From df4e0049f74db59a5ad9e788827a66007821217c Mon Sep 17 00:00:00 2001 From: Runming Wu Date: Mon, 8 Apr 2024 17:41:53 -0700 Subject: [PATCH] Clang change Change-Id: I0d82041c4bb15ea6f4898ac708797300a69fad89 --- orchagent/p4orch/acl_rule_manager.cpp | 4548 +++--- orchagent/p4orch/acl_rule_manager.h | 305 +- orchagent/p4orch/acl_table_manager.cpp | 2342 ++-- orchagent/p4orch/acl_table_manager.h | 220 +- orchagent/p4orch/acl_util.cpp | 1589 +-- orchagent/p4orch/acl_util.h | 572 +- orchagent/p4orch/ext_tables_manager.cpp | 1492 +- orchagent/p4orch/ext_tables_manager.h | 133 +- orchagent/p4orch/gre_tunnel_manager.cpp | 1125 +- orchagent/p4orch/gre_tunnel_manager.h | 183 +- orchagent/p4orch/l3_admit_manager.cpp | 789 +- orchagent/p4orch/l3_admit_manager.h | 140 +- orchagent/p4orch/mirror_session_manager.cpp | 1645 +-- orchagent/p4orch/mirror_session_manager.h | 232 +- orchagent/p4orch/neighbor_manager.cpp | 977 +- orchagent/p4orch/neighbor_manager.h | 107 +- orchagent/p4orch/next_hop_manager.cpp | 1217 +- orchagent/p4orch/next_hop_manager.h | 173 +- orchagent/p4orch/object_manager_interface.h | 31 +- orchagent/p4orch/p4oidmapper.cpp | 350 +- orchagent/p4orch/p4oidmapper.h | 155 +- orchagent/p4orch/p4orch.cpp | 441 +- orchagent/p4orch/p4orch.h | 86 +- orchagent/p4orch/p4orch_util.cpp | 365 +- orchagent/p4orch/p4orch_util.h | 502 +- orchagent/p4orch/route_manager.cpp | 2003 +-- orchagent/p4orch/route_manager.h | 245 +- orchagent/p4orch/router_interface_manager.cpp | 963 +- orchagent/p4orch/router_interface_manager.h | 112 +- .../p4orch/tables_definition_manager.cpp | 1012 +- orchagent/p4orch/tables_definition_manager.h | 91 +- orchagent/p4orch/tests/acl_manager_test.cpp | 11483 +++++++--------- .../p4orch/tests/fake_consumerstatetable.cpp | 14 +- orchagent/p4orch/tests/fake_crmorch.cpp | 82 +- orchagent/p4orch/tests/fake_dbconnector.cpp | 78 +- .../p4orch/tests/fake_flexcounterorch.cpp | 36 +- .../tests/fake_flowcounterrouteorch.cpp | 216 +- .../tests/fake_notificationconsumer.cpp | 17 +- orchagent/p4orch/tests/fake_portorch.cpp | 750 +- orchagent/p4orch/tests/fake_producertable.cpp | 27 +- .../tests/fake_subscriberstatetable.cpp | 14 +- orchagent/p4orch/tests/fake_table.cpp | 120 +- .../p4orch/tests/gre_tunnel_manager_test.cpp | 1740 ++- .../p4orch/tests/l3_admit_manager_test.cpp | 1113 +- .../tests/mirror_session_manager_test.cpp | 2404 ++-- .../p4orch/tests/mock_response_publisher.h | 27 +- orchagent/p4orch/tests/mock_sai_acl.cpp | 88 +- orchagent/p4orch/tests/mock_sai_acl.h | 156 +- orchagent/p4orch/tests/mock_sai_hostif.cpp | 93 +- orchagent/p4orch/tests/mock_sai_hostif.h | 132 +- orchagent/p4orch/tests/mock_sai_mirror.h | 69 +- orchagent/p4orch/tests/mock_sai_my_mac.h | 34 +- orchagent/p4orch/tests/mock_sai_neighbor.h | 69 +- orchagent/p4orch/tests/mock_sai_next_hop.h | 68 +- .../p4orch/tests/mock_sai_next_hop_group.h | 139 +- orchagent/p4orch/tests/mock_sai_policer.h | 80 +- orchagent/p4orch/tests/mock_sai_route.h | 193 +- .../tests/mock_sai_router_interface.cpp | 35 +- .../p4orch/tests/mock_sai_router_interface.h | 56 +- orchagent/p4orch/tests/mock_sai_serialize.cpp | 12 +- orchagent/p4orch/tests/mock_sai_serialize.h | 22 +- orchagent/p4orch/tests/mock_sai_switch.cpp | 17 +- orchagent/p4orch/tests/mock_sai_switch.h | 28 +- orchagent/p4orch/tests/mock_sai_tunnel.h | 34 +- orchagent/p4orch/tests/mock_sai_udf.cpp | 42 +- orchagent/p4orch/tests/mock_sai_udf.h | 77 +- .../p4orch/tests/mock_sai_virtual_router.h | 70 +- .../p4orch/tests/neighbor_manager_test.cpp | 1629 ++- .../p4orch/tests/next_hop_manager_test.cpp | 2179 ++- orchagent/p4orch/tests/p4oidmapper_test.cpp | 287 +- orchagent/p4orch/tests/p4orch_util_test.cpp | 237 +- orchagent/p4orch/tests/return_code_test.cpp | 342 +- orchagent/p4orch/tests/route_manager_test.cpp | 7025 +++++----- .../tests/router_interface_manager_test.cpp | 1806 ++- orchagent/p4orch/tests/test_main.cpp | 350 +- orchagent/p4orch/tests/wcmp_manager_test.cpp | 5234 ++++--- orchagent/p4orch/wcmp_manager.cpp | 1790 +-- orchagent/p4orch/wcmp_manager.h | 290 +- orchagent/response_publisher.cpp | 438 +- orchagent/response_publisher.h | 119 +- orchagent/response_publisher_interface.h | 49 +- orchagent/return_code.h | 574 +- 82 files changed, 31530 insertions(+), 34599 deletions(-) diff --git a/orchagent/p4orch/acl_rule_manager.cpp b/orchagent/p4orch/acl_rule_manager.cpp index 7c340ba34ce..5131b718ac2 100644 --- a/orchagent/p4orch/acl_rule_manager.cpp +++ b/orchagent/p4orch/acl_rule_manager.cpp @@ -18,2398 +18,2498 @@ #include "sai_serialize.h" #include "table.h" #include "tokenize.h" -extern "C" { +extern "C" +{ #include "sai.h" } using ::p4orch::kTableKeyDelimiter; extern sai_object_id_t gSwitchId; -extern sai_acl_api_t* sai_acl_api; -extern sai_policer_api_t* sai_policer_api; -extern sai_hostif_api_t* sai_hostif_api; -extern CrmOrch* gCrmOrch; -extern PortsOrch* gPortsOrch; -extern P4Orch* gP4Orch; - -namespace p4orch { -namespace { - -const std::string concatTableNameAndRuleKey(const std::string& table_name, - const std::string& rule_key) { - return table_name + kTableKeyDelimiter + rule_key; +extern sai_acl_api_t *sai_acl_api; +extern sai_policer_api_t *sai_policer_api; +extern sai_hostif_api_t *sai_hostif_api; +extern CrmOrch *gCrmOrch; +extern PortsOrch *gPortsOrch; +extern P4Orch *gP4Orch; + +namespace p4orch +{ +namespace +{ + +const std::string concatTableNameAndRuleKey(const std::string &table_name, const std::string &rule_key) +{ + return table_name + kTableKeyDelimiter + rule_key; } -std::vector getRuleSaiAttrs(const P4AclRule& acl_rule) { - std::vector acl_entry_attrs; - sai_attribute_t acl_entry_attr; - acl_entry_attr.id = SAI_ACL_ENTRY_ATTR_TABLE_ID; - acl_entry_attr.value.oid = acl_rule.acl_table_oid; - acl_entry_attrs.push_back(acl_entry_attr); - - acl_entry_attr.id = SAI_ACL_ENTRY_ATTR_PRIORITY; - acl_entry_attr.value.u32 = acl_rule.priority; - acl_entry_attrs.push_back(acl_entry_attr); - - acl_entry_attr.id = SAI_ACL_ENTRY_ATTR_ADMIN_STATE; - acl_entry_attr.value.booldata = true; - acl_entry_attrs.push_back(acl_entry_attr); - - // Add matches - for (const auto& match_fv : acl_rule.match_fvs) { - acl_entry_attr.id = fvField(match_fv); - acl_entry_attr.value = fvValue(match_fv); +std::vector getRuleSaiAttrs(const P4AclRule &acl_rule) +{ + std::vector acl_entry_attrs; + sai_attribute_t acl_entry_attr; + acl_entry_attr.id = SAI_ACL_ENTRY_ATTR_TABLE_ID; + acl_entry_attr.value.oid = acl_rule.acl_table_oid; acl_entry_attrs.push_back(acl_entry_attr); - } - // Add actions - for (const auto& action_fv : acl_rule.action_fvs) { - acl_entry_attr.id = fvField(action_fv); - acl_entry_attr.value = fvValue(action_fv); + acl_entry_attr.id = SAI_ACL_ENTRY_ATTR_PRIORITY; + acl_entry_attr.value.u32 = acl_rule.priority; acl_entry_attrs.push_back(acl_entry_attr); - } - // Add meter - if (acl_rule.meter.enabled) { - acl_entry_attr.id = SAI_ACL_ENTRY_ATTR_ACTION_SET_POLICER; - acl_entry_attr.value.aclaction.parameter.oid = acl_rule.meter.meter_oid; - acl_entry_attr.value.aclaction.enable = true; + acl_entry_attr.id = SAI_ACL_ENTRY_ATTR_ADMIN_STATE; + acl_entry_attr.value.booldata = true; acl_entry_attrs.push_back(acl_entry_attr); - } - // Add counter - if (acl_rule.counter.packets_enabled || acl_rule.counter.bytes_enabled) { - acl_entry_attr.id = SAI_ACL_ENTRY_ATTR_ACTION_COUNTER; - acl_entry_attr.value.aclaction.enable = true; - acl_entry_attr.value.aclaction.parameter.oid = acl_rule.counter.counter_oid; - acl_entry_attrs.push_back(acl_entry_attr); - } + // Add matches + for (const auto &match_fv : acl_rule.match_fvs) + { + acl_entry_attr.id = fvField(match_fv); + acl_entry_attr.value = fvValue(match_fv); + acl_entry_attrs.push_back(acl_entry_attr); + } - return acl_entry_attrs; -} + // Add actions + for (const auto &action_fv : acl_rule.action_fvs) + { + acl_entry_attr.id = fvField(action_fv); + acl_entry_attr.value = fvValue(action_fv); + acl_entry_attrs.push_back(acl_entry_attr); + } -std::vector getCounterSaiAttrs(const P4AclRule& acl_rule) { - sai_attribute_t attr; - std::vector counter_attrs; - attr.id = SAI_ACL_COUNTER_ATTR_TABLE_ID; - attr.value.oid = acl_rule.acl_table_oid; - counter_attrs.push_back(attr); + // Add meter + if (acl_rule.meter.enabled) + { + acl_entry_attr.id = SAI_ACL_ENTRY_ATTR_ACTION_SET_POLICER; + acl_entry_attr.value.aclaction.parameter.oid = acl_rule.meter.meter_oid; + acl_entry_attr.value.aclaction.enable = true; + acl_entry_attrs.push_back(acl_entry_attr); + } - if (acl_rule.counter.bytes_enabled) { - attr.id = SAI_ACL_COUNTER_ATTR_ENABLE_BYTE_COUNT; - attr.value.booldata = true; - counter_attrs.push_back(attr); - } + // Add counter + if (acl_rule.counter.packets_enabled || acl_rule.counter.bytes_enabled) + { + acl_entry_attr.id = SAI_ACL_ENTRY_ATTR_ACTION_COUNTER; + acl_entry_attr.value.aclaction.enable = true; + acl_entry_attr.value.aclaction.parameter.oid = acl_rule.counter.counter_oid; + acl_entry_attrs.push_back(acl_entry_attr); + } - if (acl_rule.counter.packets_enabled) { - attr.id = SAI_ACL_COUNTER_ATTR_ENABLE_PACKET_COUNT; - attr.value.booldata = true; + return acl_entry_attrs; +} + +std::vector getCounterSaiAttrs(const P4AclRule &acl_rule) +{ + sai_attribute_t attr; + std::vector counter_attrs; + attr.id = SAI_ACL_COUNTER_ATTR_TABLE_ID; + attr.value.oid = acl_rule.acl_table_oid; counter_attrs.push_back(attr); - } - return counter_attrs; -} + if (acl_rule.counter.bytes_enabled) + { + attr.id = SAI_ACL_COUNTER_ATTR_ENABLE_BYTE_COUNT; + attr.value.booldata = true; + counter_attrs.push_back(attr); + } -std::vector getMeterSaiAttrs(const P4AclMeter& p4_acl_meter) { - std::vector meter_attrs; - sai_attribute_t meter_attr; + if (acl_rule.counter.packets_enabled) + { + attr.id = SAI_ACL_COUNTER_ATTR_ENABLE_PACKET_COUNT; + attr.value.booldata = true; + counter_attrs.push_back(attr); + } - meter_attr.id = SAI_POLICER_ATTR_MODE; - meter_attr.value.s32 = p4_acl_meter.mode; - meter_attrs.push_back(meter_attr); + return counter_attrs; +} - if (p4_acl_meter.enabled) { - meter_attr.id = SAI_POLICER_ATTR_METER_TYPE; - meter_attr.value.s32 = p4_acl_meter.type; - meter_attrs.push_back(meter_attr); +std::vector getMeterSaiAttrs(const P4AclMeter &p4_acl_meter) +{ + std::vector meter_attrs; + sai_attribute_t meter_attr; - meter_attr.id = SAI_POLICER_ATTR_CBS; - meter_attr.value.u64 = p4_acl_meter.cburst; + meter_attr.id = SAI_POLICER_ATTR_MODE; + meter_attr.value.s32 = p4_acl_meter.mode; meter_attrs.push_back(meter_attr); - meter_attr.id = SAI_POLICER_ATTR_CIR; - meter_attr.value.u64 = p4_acl_meter.cir; - meter_attrs.push_back(meter_attr); + if (p4_acl_meter.enabled) + { + meter_attr.id = SAI_POLICER_ATTR_METER_TYPE; + meter_attr.value.s32 = p4_acl_meter.type; + meter_attrs.push_back(meter_attr); - meter_attr.id = SAI_POLICER_ATTR_PIR; - meter_attr.value.u64 = p4_acl_meter.pir; - meter_attrs.push_back(meter_attr); + meter_attr.id = SAI_POLICER_ATTR_CBS; + meter_attr.value.u64 = p4_acl_meter.cburst; + meter_attrs.push_back(meter_attr); - meter_attr.id = SAI_POLICER_ATTR_PBS; - meter_attr.value.u64 = p4_acl_meter.pburst; - meter_attrs.push_back(meter_attr); - } + meter_attr.id = SAI_POLICER_ATTR_CIR; + meter_attr.value.u64 = p4_acl_meter.cir; + meter_attrs.push_back(meter_attr); - for (const auto& packet_color_action : p4_acl_meter.packet_color_actions) { - meter_attr.id = fvField(packet_color_action); - meter_attr.value.s32 = fvValue(packet_color_action); - meter_attrs.push_back(meter_attr); - } + meter_attr.id = SAI_POLICER_ATTR_PIR; + meter_attr.value.u64 = p4_acl_meter.pir; + meter_attrs.push_back(meter_attr); - return meter_attrs; + meter_attr.id = SAI_POLICER_ATTR_PBS; + meter_attr.value.u64 = p4_acl_meter.pburst; + meter_attrs.push_back(meter_attr); + } + + for (const auto &packet_color_action : p4_acl_meter.packet_color_actions) + { + meter_attr.id = fvField(packet_color_action); + meter_attr.value.s32 = fvValue(packet_color_action); + meter_attrs.push_back(meter_attr); + } + + return meter_attrs; } -} // namespace +} // namespace -ReturnCode AclRuleManager::getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) { - return StatusCode::SWSS_RC_UNIMPLEMENTED; +ReturnCode AclRuleManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) +{ + return StatusCode::SWSS_RC_UNIMPLEMENTED; } -void AclRuleManager::enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) { - m_entries.push_back(entry); +void AclRuleManager::enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) +{ + m_entries.push_back(entry); } -void AclRuleManager::drain() { - SWSS_LOG_ENTER(); +void AclRuleManager::drain() +{ + SWSS_LOG_ENTER(); + + for (const auto &key_op_fvs_tuple : m_entries) + { + std::string table_name; + std::string db_key; + parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &db_key); + const auto &op = kfvOp(key_op_fvs_tuple); + const std::vector &attributes = kfvFieldsValues(key_op_fvs_tuple); + + SWSS_LOG_NOTICE("OP: %s, RULE_KEY: %s", op.c_str(), QuotedVar(db_key).c_str()); + + ReturnCode status; + auto app_db_entry_or = deserializeAclRuleAppDbEntry(table_name, db_key, attributes); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", + QuotedVar(table_name + ":" + db_key).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + auto &app_db_entry = *app_db_entry_or; + + status = validateAclRuleAppDbEntry(app_db_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Validation failed for ACL rule APP DB entry with key %s: %s", + QuotedVar(table_name + ":" + db_key).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } - for (const auto& key_op_fvs_tuple : m_entries) { - std::string table_name; - std::string db_key; - parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &db_key); - const auto& op = kfvOp(key_op_fvs_tuple); - const std::vector& attributes = - kfvFieldsValues(key_op_fvs_tuple); + const auto &acl_table_name = app_db_entry.acl_table_name; + const auto &acl_rule_key = + KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, std::to_string(app_db_entry.priority)); + + const auto &operation = kfvOp(key_op_fvs_tuple); + if (operation == SET_COMMAND) + { + auto *acl_rule = getAclRule(acl_table_name, acl_rule_key); + if (acl_rule == nullptr) + { + status = processAddRuleRequest(acl_rule_key, app_db_entry); + } + else + { + status = processUpdateRuleRequest(app_db_entry, *acl_rule); + } + } + else if (operation == DEL_COMMAND) + { + status = processDeleteRuleRequest(acl_table_name, acl_rule_key); + } + else + { + status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Unknown operation type " << operation; + SWSS_LOG_ERROR("%s", status.message().c_str()); + } + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), status, + /*replace=*/true); + } + m_entries.clear(); +} - SWSS_LOG_NOTICE("OP: %s, RULE_KEY: %s", op.c_str(), - QuotedVar(db_key).c_str()); +ReturnCode AclRuleManager::setUpUserDefinedTraps() +{ + SWSS_LOG_ENTER(); + + const auto trapGroupMap = m_coppOrch->getTrapGroupMap(); + const auto trapGroupHostIfMap = m_coppOrch->getTrapGroupHostIfMap(); + for (int queue_num = 1; queue_num <= P4_CPU_QUEUE_MAX_NUM; queue_num++) + { + auto trap_group_it = trapGroupMap.find(GENL_PACKET_TRAP_GROUP_NAME_PREFIX + std::to_string(queue_num)); + if (trap_group_it == trapGroupMap.end()) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Trap group was not found given trap group name: " + << GENL_PACKET_TRAP_GROUP_NAME_PREFIX << queue_num); + } + const sai_object_id_t trap_group_oid = trap_group_it->second; + auto hostif_oid_it = trapGroupHostIfMap.find(trap_group_oid); + if (hostif_oid_it == trapGroupHostIfMap.end()) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Hostif object id was not found given trap group - " << trap_group_it->first); + } + // Create user defined trap + std::vector trap_attrs; + sai_attribute_t attr; + attr.id = SAI_HOSTIF_USER_DEFINED_TRAP_ATTR_TRAP_GROUP; + attr.value.oid = trap_group_oid; + trap_attrs.push_back(attr); + attr.id = SAI_HOSTIF_USER_DEFINED_TRAP_ATTR_TYPE; + attr.value.s32 = SAI_HOSTIF_USER_DEFINED_TRAP_TYPE_ACL; + trap_attrs.push_back(attr); + P4UserDefinedTrapHostifTableEntry udt_hostif; + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_hostif_api->create_hostif_user_defined_trap(&udt_hostif.user_defined_trap, gSwitchId, + (uint32_t)trap_attrs.size(), trap_attrs.data()), + "Failed to create trap by calling " + "sai_hostif_api->create_hostif_user_defined_trap"); + std::vector sai_host_table_attr; + + attr.id = SAI_HOSTIF_TABLE_ENTRY_ATTR_TYPE; + attr.value.s32 = SAI_HOSTIF_TABLE_ENTRY_TYPE_TRAP_ID; + sai_host_table_attr.push_back(attr); + + attr.id = SAI_HOSTIF_TABLE_ENTRY_ATTR_TRAP_ID; + attr.value.oid = udt_hostif.user_defined_trap; + sai_host_table_attr.push_back(attr); + + attr.id = SAI_HOSTIF_TABLE_ENTRY_ATTR_CHANNEL_TYPE; + attr.value.s32 = SAI_HOSTIF_TABLE_ENTRY_CHANNEL_TYPE_GENETLINK; + sai_host_table_attr.push_back(attr); + + attr.id = SAI_HOSTIF_TABLE_ENTRY_ATTR_HOST_IF; + attr.value.oid = hostif_oid_it->second; + sai_host_table_attr.push_back(attr); + + auto sai_status = + sai_hostif_api->create_hostif_table_entry(&udt_hostif.hostif_table_entry, gSwitchId, + (uint32_t)sai_host_table_attr.size(), sai_host_table_attr.data()); + if (sai_status != SAI_STATUS_SUCCESS) + { + ReturnCode return_code = ReturnCode(sai_status) << "Failed to create hostif table entry by calling " + "sai_hostif_api->remove_hostif_user_defined_trap"; + sai_hostif_api->remove_hostif_user_defined_trap(udt_hostif.user_defined_trap); + SWSS_LOG_ERROR("%s SAI_STATUS: %s", return_code.message().c_str(), + sai_serialize_status(sai_status).c_str()); + return return_code; + } + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP, std::to_string(queue_num), + udt_hostif.user_defined_trap, /*ref_count=*/1); + m_userDefinedTraps.push_back(udt_hostif); + SWSS_LOG_NOTICE("Created user defined trap for QUEUE number %d: %s", queue_num, + sai_serialize_object_id(udt_hostif.user_defined_trap).c_str()); + } + return ReturnCode(); +} - ReturnCode status; - auto app_db_entry_or = - deserializeAclRuleAppDbEntry(table_name, db_key, attributes); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", - QuotedVar(table_name + ":" + db_key).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - auto& app_db_entry = *app_db_entry_or; - - status = validateAclRuleAppDbEntry(app_db_entry); - if (!status.ok()) { - SWSS_LOG_ERROR( - "Validation failed for ACL rule APP DB entry with key %s: %s", - QuotedVar(table_name + ":" + db_key).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - - const auto& acl_table_name = app_db_entry.acl_table_name; - const auto& acl_rule_key = KeyGenerator::generateAclRuleKey( - app_db_entry.match_fvs, std::to_string(app_db_entry.priority)); - - const auto& operation = kfvOp(key_op_fvs_tuple); - if (operation == SET_COMMAND) { - auto* acl_rule = getAclRule(acl_table_name, acl_rule_key); - if (acl_rule == nullptr) { - status = processAddRuleRequest(acl_rule_key, app_db_entry); - } else { - status = processUpdateRuleRequest(app_db_entry, *acl_rule); - } - } else if (operation == DEL_COMMAND) { - status = processDeleteRuleRequest(acl_table_name, acl_rule_key); - } else { - status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown operation type " << operation; - SWSS_LOG_ERROR("%s", status.message().c_str()); - } - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - } - m_entries.clear(); +ReturnCode AclRuleManager::cleanUpUserDefinedTraps() +{ + SWSS_LOG_ENTER(); + + for (size_t queue_num = 1; queue_num <= m_userDefinedTraps.size(); queue_num++) + { + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_hostif_api->remove_hostif_table_entry(m_userDefinedTraps[queue_num - 1].hostif_table_entry), + "Failed to create hostif table entry."); + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP, std::to_string(queue_num)); + sai_hostif_api->remove_hostif_user_defined_trap(m_userDefinedTraps[queue_num - 1].user_defined_trap); + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP, std::to_string(queue_num)); + } + m_userDefinedTraps.clear(); + return ReturnCode(); } -ReturnCode AclRuleManager::setUpUserDefinedTraps() { - SWSS_LOG_ENTER(); - - const auto trapGroupMap = m_coppOrch->getTrapGroupMap(); - const auto trapGroupHostIfMap = m_coppOrch->getTrapGroupHostIfMap(); - for (int queue_num = 1; queue_num <= P4_CPU_QUEUE_MAX_NUM; queue_num++) { - auto trap_group_it = trapGroupMap.find(GENL_PACKET_TRAP_GROUP_NAME_PREFIX + - std::to_string(queue_num)); - if (trap_group_it == trapGroupMap.end()) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Trap group was not found given trap group name: " - << GENL_PACKET_TRAP_GROUP_NAME_PREFIX << queue_num); - } - const sai_object_id_t trap_group_oid = trap_group_it->second; - auto hostif_oid_it = trapGroupHostIfMap.find(trap_group_oid); - if (hostif_oid_it == trapGroupHostIfMap.end()) { - LOG_ERROR_AND_RETURN( - ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Hostif object id was not found given trap group - " - << trap_group_it->first); - } - // Create user defined trap - std::vector trap_attrs; - sai_attribute_t attr; - attr.id = SAI_HOSTIF_USER_DEFINED_TRAP_ATTR_TRAP_GROUP; - attr.value.oid = trap_group_oid; - trap_attrs.push_back(attr); - attr.id = SAI_HOSTIF_USER_DEFINED_TRAP_ATTR_TYPE; - attr.value.s32 = SAI_HOSTIF_USER_DEFINED_TRAP_TYPE_ACL; - trap_attrs.push_back(attr); - P4UserDefinedTrapHostifTableEntry udt_hostif; - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_hostif_api->create_hostif_user_defined_trap( - &udt_hostif.user_defined_trap, gSwitchId, - (uint32_t)trap_attrs.size(), trap_attrs.data()), - "Failed to create trap by calling " - "sai_hostif_api->create_hostif_user_defined_trap"); - std::vector sai_host_table_attr; - - attr.id = SAI_HOSTIF_TABLE_ENTRY_ATTR_TYPE; - attr.value.s32 = SAI_HOSTIF_TABLE_ENTRY_TYPE_TRAP_ID; - sai_host_table_attr.push_back(attr); - - attr.id = SAI_HOSTIF_TABLE_ENTRY_ATTR_TRAP_ID; - attr.value.oid = udt_hostif.user_defined_trap; - sai_host_table_attr.push_back(attr); - - attr.id = SAI_HOSTIF_TABLE_ENTRY_ATTR_CHANNEL_TYPE; - attr.value.s32 = SAI_HOSTIF_TABLE_ENTRY_CHANNEL_TYPE_GENETLINK; - sai_host_table_attr.push_back(attr); - - attr.id = SAI_HOSTIF_TABLE_ENTRY_ATTR_HOST_IF; - attr.value.oid = hostif_oid_it->second; - sai_host_table_attr.push_back(attr); - - auto sai_status = sai_hostif_api->create_hostif_table_entry( - &udt_hostif.hostif_table_entry, gSwitchId, - (uint32_t)sai_host_table_attr.size(), sai_host_table_attr.data()); - if (sai_status != SAI_STATUS_SUCCESS) { - ReturnCode return_code = - ReturnCode(sai_status) - << "Failed to create hostif table entry by calling " - "sai_hostif_api->remove_hostif_user_defined_trap"; - sai_hostif_api->remove_hostif_user_defined_trap( - udt_hostif.user_defined_trap); - SWSS_LOG_ERROR("%s SAI_STATUS: %s", return_code.message().c_str(), - sai_serialize_status(sai_status).c_str()); - return return_code; - } - m_p4OidMapper->setOID(SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP, - std::to_string(queue_num), - udt_hostif.user_defined_trap, /*ref_count=*/1); - m_userDefinedTraps.push_back(udt_hostif); - SWSS_LOG_NOTICE( - "Created user defined trap for QUEUE number %d: %s", queue_num, - sai_serialize_object_id(udt_hostif.user_defined_trap).c_str()); - } - return ReturnCode(); +void AclRuleManager::doAclCounterStatsTask() +{ + SWSS_LOG_ENTER(); + + for (const auto &table_it : m_aclRuleTables) + { + const auto &table_name = fvField(table_it); + for (const auto &rule_it : fvValue(table_it)) + { + if (!fvValue(rule_it).counter.packets_enabled && !fvValue(rule_it).counter.bytes_enabled) + continue; + auto status = setAclRuleCounterStats(fvValue(rule_it)); + if (!status.ok()) + { + status.prepend("Failed to set counters stats for ACL rule " + QuotedVar(table_name) + ":" + + QuotedVar(fvField(rule_it)) + " in COUNTERS_DB: "); + SWSS_LOG_ERROR("%s", status.message().c_str()); + continue; + } + } + } } -ReturnCode AclRuleManager::cleanUpUserDefinedTraps() { - SWSS_LOG_ENTER(); +ReturnCode AclRuleManager::createAclCounter(const std::string &acl_table_name, const std::string &counter_key, + const P4AclRule &acl_rule, sai_object_id_t *counter_oid) +{ + SWSS_LOG_ENTER(); + + auto attrs = getCounterSaiAttrs(acl_rule); - for (size_t queue_num = 1; queue_num <= m_userDefinedTraps.size(); - queue_num++) { CHECK_ERROR_AND_LOG_AND_RETURN( - sai_hostif_api->remove_hostif_table_entry( - m_userDefinedTraps[queue_num - 1].hostif_table_entry), - "Failed to create hostif table entry."); - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP, - std::to_string(queue_num)); - sai_hostif_api->remove_hostif_user_defined_trap( - m_userDefinedTraps[queue_num - 1].user_defined_trap); - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP, - std::to_string(queue_num)); - } - m_userDefinedTraps.clear(); - return ReturnCode(); + sai_acl_api->create_acl_counter(counter_oid, gSwitchId, (uint32_t)attrs.size(), attrs.data()), + "Faied to create counter for the rule in table " << sai_serialize_object_id(acl_rule.acl_table_oid)); + SWSS_LOG_NOTICE("Suceeded to create ACL counter %s ", sai_serialize_object_id(*counter_oid).c_str()); + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_ACL_COUNTER, counter_key, *counter_oid); + gCrmOrch->incCrmAclTableUsedCounter(CrmResourceType::CRM_ACL_COUNTER, acl_rule.acl_table_oid); + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_ACL_TABLE, acl_table_name); + return ReturnCode(); } -void AclRuleManager::doAclCounterStatsTask() { - SWSS_LOG_ENTER(); - - for (const auto& table_it : m_aclRuleTables) { - const auto& table_name = fvField(table_it); - for (const auto& rule_it : fvValue(table_it)) { - if (!fvValue(rule_it).counter.packets_enabled && - !fvValue(rule_it).counter.bytes_enabled) - continue; - auto status = setAclRuleCounterStats(fvValue(rule_it)); - if (!status.ok()) { - status.prepend("Failed to set counters stats for ACL rule " + - QuotedVar(table_name) + ":" + - QuotedVar(fvField(rule_it)) + " in COUNTERS_DB: "); - SWSS_LOG_ERROR("%s", status.message().c_str()); - continue; - } - } - } +ReturnCode AclRuleManager::removeAclCounter(const std::string &acl_table_name, const std::string &counter_key) +{ + SWSS_LOG_ENTER(); + sai_object_id_t counter_oid; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_ACL_COUNTER, counter_key, &counter_oid)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Failed to remove ACL counter by key " << QuotedVar(counter_key) + << ": invalid counter key."); + } + sai_object_id_t table_oid; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_ACL_TABLE, acl_table_name, &table_oid)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Failed to remove ACL counter " + << sai_serialize_object_id(counter_oid) << " in table " + << QuotedVar(acl_table_name) << ": invalid table key."); + } + CHECK_ERROR_AND_LOG_AND_RETURN(sai_acl_api->remove_acl_counter(counter_oid), + "Failed to remove ACL counter " << sai_serialize_object_id(counter_oid) + << " in table " << QuotedVar(acl_table_name)); + + gCrmOrch->decCrmAclTableUsedCounter(CrmResourceType::CRM_ACL_COUNTER, table_oid); + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_ACL_COUNTER, counter_key); + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_ACL_TABLE, acl_table_name); + SWSS_LOG_NOTICE("Removing record about the counter %s from the DB", sai_serialize_object_id(counter_oid).c_str()); + return ReturnCode(); } -ReturnCode AclRuleManager::createAclCounter(const std::string& acl_table_name, - const std::string& counter_key, - const P4AclRule& acl_rule, - sai_object_id_t* counter_oid) { - SWSS_LOG_ENTER(); - - auto attrs = getCounterSaiAttrs(acl_rule); - - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_acl_api->create_acl_counter(counter_oid, gSwitchId, - (uint32_t)attrs.size(), attrs.data()), - "Faied to create counter for the rule in table " - << sai_serialize_object_id(acl_rule.acl_table_oid)); - SWSS_LOG_NOTICE("Suceeded to create ACL counter %s ", - sai_serialize_object_id(*counter_oid).c_str()); - m_p4OidMapper->setOID(SAI_OBJECT_TYPE_ACL_COUNTER, counter_key, *counter_oid); - gCrmOrch->incCrmAclTableUsedCounter(CrmResourceType::CRM_ACL_COUNTER, - acl_rule.acl_table_oid); - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_ACL_TABLE, acl_table_name); - return ReturnCode(); -} +ReturnCode AclRuleManager::createAclMeter(const P4AclMeter &p4_acl_meter, const std::string &meter_key, + sai_object_id_t *meter_oid) +{ + SWSS_LOG_ENTER(); -ReturnCode AclRuleManager::removeAclCounter(const std::string& acl_table_name, - const std::string& counter_key) { - SWSS_LOG_ENTER(); - sai_object_id_t counter_oid; - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_ACL_COUNTER, counter_key, - &counter_oid)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Failed to remove ACL counter by key " << QuotedVar(counter_key) - << ": invalid counter key."); - } - sai_object_id_t table_oid; - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_ACL_TABLE, acl_table_name, - &table_oid)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Failed to remove ACL counter " - << sai_serialize_object_id(counter_oid) << " in table " - << QuotedVar(acl_table_name) << ": invalid table key."); - } - CHECK_ERROR_AND_LOG_AND_RETURN(sai_acl_api->remove_acl_counter(counter_oid), - "Failed to remove ACL counter " - << sai_serialize_object_id(counter_oid) - << " in table " - << QuotedVar(acl_table_name)); - - gCrmOrch->decCrmAclTableUsedCounter(CrmResourceType::CRM_ACL_COUNTER, - table_oid); - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_ACL_COUNTER, counter_key); - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_ACL_TABLE, acl_table_name); - SWSS_LOG_NOTICE("Removing record about the counter %s from the DB", - sai_serialize_object_id(counter_oid).c_str()); - return ReturnCode(); -} + auto attrs = getMeterSaiAttrs(p4_acl_meter); -ReturnCode AclRuleManager::createAclMeter(const P4AclMeter& p4_acl_meter, - const std::string& meter_key, - sai_object_id_t* meter_oid) { - SWSS_LOG_ENTER(); - - auto attrs = getMeterSaiAttrs(p4_acl_meter); - - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_policer_api->create_policer(meter_oid, gSwitchId, - (uint32_t)attrs.size(), attrs.data()), - "Failed to create ACL meter"); - m_p4OidMapper->setOID(SAI_OBJECT_TYPE_POLICER, meter_key, *meter_oid); - SWSS_LOG_NOTICE("Suceeded to create ACL meter %s ", - sai_serialize_object_id(*meter_oid).c_str()); - return ReturnCode(); + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_policer_api->create_policer(meter_oid, gSwitchId, (uint32_t)attrs.size(), attrs.data()), + "Failed to create ACL meter"); + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_POLICER, meter_key, *meter_oid); + SWSS_LOG_NOTICE("Suceeded to create ACL meter %s ", sai_serialize_object_id(*meter_oid).c_str()); + return ReturnCode(); } -ReturnCode AclRuleManager::updateAclMeter(const P4AclMeter& new_acl_meter, - const P4AclMeter& old_acl_meter) { - SWSS_LOG_ENTER(); +ReturnCode AclRuleManager::updateAclMeter(const P4AclMeter &new_acl_meter, const P4AclMeter &old_acl_meter) +{ + SWSS_LOG_ENTER(); + + std::vector meter_attrs; + std::vector rollback_attrs; + sai_attribute_t meter_attr; + + if (old_acl_meter.cburst != new_acl_meter.cburst) + { + meter_attr.id = SAI_POLICER_ATTR_CBS; + meter_attr.value.u64 = new_acl_meter.cburst; + meter_attrs.push_back(meter_attr); + meter_attr.value.u64 = old_acl_meter.cburst; + rollback_attrs.push_back(meter_attr); + } + if (old_acl_meter.cir != new_acl_meter.cir) + { + meter_attr.id = SAI_POLICER_ATTR_CIR; + meter_attr.value.u64 = new_acl_meter.cir; + meter_attrs.push_back(meter_attr); + meter_attr.value.u64 = old_acl_meter.cir; + rollback_attrs.push_back(meter_attr); + } + if (old_acl_meter.pir != new_acl_meter.pir) + { + meter_attr.id = SAI_POLICER_ATTR_PIR; + meter_attr.value.u64 = new_acl_meter.pir; + meter_attrs.push_back(meter_attr); + meter_attr.value.u64 = old_acl_meter.pir; + rollback_attrs.push_back(meter_attr); + } + if (old_acl_meter.pburst != new_acl_meter.pburst) + { + meter_attr.id = SAI_POLICER_ATTR_PBS; + meter_attr.value.u64 = new_acl_meter.pburst; + meter_attrs.push_back(meter_attr); + meter_attr.value.u64 = old_acl_meter.pburst; + rollback_attrs.push_back(meter_attr); + } + + std::set colors_to_reset; + for (const auto &old_color_action : old_acl_meter.packet_color_actions) + { + colors_to_reset.insert(fvField(old_color_action)); + } + + for (const auto &packet_color_action : new_acl_meter.packet_color_actions) + { + const auto &it = old_acl_meter.packet_color_actions.find(fvField(packet_color_action)); + if (it == old_acl_meter.packet_color_actions.end() || it->second != fvValue(packet_color_action)) + { + meter_attr.id = fvField(packet_color_action); + meter_attr.value.s32 = fvValue(packet_color_action); + meter_attrs.push_back(meter_attr); + meter_attr.value.s32 = + (it == old_acl_meter.packet_color_actions.end()) ? SAI_PACKET_ACTION_FORWARD : it->second; + rollback_attrs.push_back(meter_attr); + } + if (it != old_acl_meter.packet_color_actions.end()) + { + colors_to_reset.erase(fvField(packet_color_action)); + } + } - std::vector meter_attrs; - std::vector rollback_attrs; - sai_attribute_t meter_attr; + for (const auto &packet_color : colors_to_reset) + { + meter_attr.id = packet_color; + meter_attr.value.s32 = SAI_PACKET_ACTION_FORWARD; + meter_attrs.push_back(meter_attr); + const auto &it = old_acl_meter.packet_color_actions.find(packet_color); + meter_attr.value.s32 = it->second; + rollback_attrs.push_back(meter_attr); + } - if (old_acl_meter.cburst != new_acl_meter.cburst) { - meter_attr.id = SAI_POLICER_ATTR_CBS; - meter_attr.value.u64 = new_acl_meter.cburst; - meter_attrs.push_back(meter_attr); - meter_attr.value.u64 = old_acl_meter.cburst; - rollback_attrs.push_back(meter_attr); - } - if (old_acl_meter.cir != new_acl_meter.cir) { - meter_attr.id = SAI_POLICER_ATTR_CIR; - meter_attr.value.u64 = new_acl_meter.cir; - meter_attrs.push_back(meter_attr); - meter_attr.value.u64 = old_acl_meter.cir; - rollback_attrs.push_back(meter_attr); - } - if (old_acl_meter.pir != new_acl_meter.pir) { - meter_attr.id = SAI_POLICER_ATTR_PIR; - meter_attr.value.u64 = new_acl_meter.pir; - meter_attrs.push_back(meter_attr); - meter_attr.value.u64 = old_acl_meter.pir; - rollback_attrs.push_back(meter_attr); - } - if (old_acl_meter.pburst != new_acl_meter.pburst) { - meter_attr.id = SAI_POLICER_ATTR_PBS; - meter_attr.value.u64 = new_acl_meter.pburst; - meter_attrs.push_back(meter_attr); - meter_attr.value.u64 = old_acl_meter.pburst; - rollback_attrs.push_back(meter_attr); - } - - std::set colors_to_reset; - for (const auto& old_color_action : old_acl_meter.packet_color_actions) { - colors_to_reset.insert(fvField(old_color_action)); - } - - for (const auto& packet_color_action : new_acl_meter.packet_color_actions) { - const auto& it = - old_acl_meter.packet_color_actions.find(fvField(packet_color_action)); - if (it == old_acl_meter.packet_color_actions.end() || - it->second != fvValue(packet_color_action)) { - meter_attr.id = fvField(packet_color_action); - meter_attr.value.s32 = fvValue(packet_color_action); - meter_attrs.push_back(meter_attr); - meter_attr.value.s32 = (it == old_acl_meter.packet_color_actions.end()) - ? SAI_PACKET_ACTION_FORWARD - : it->second; - rollback_attrs.push_back(meter_attr); - } - if (it != old_acl_meter.packet_color_actions.end()) { - colors_to_reset.erase(fvField(packet_color_action)); - } - } - - for (const auto& packet_color : colors_to_reset) { - meter_attr.id = packet_color; - meter_attr.value.s32 = SAI_PACKET_ACTION_FORWARD; - meter_attrs.push_back(meter_attr); - const auto& it = old_acl_meter.packet_color_actions.find(packet_color); - meter_attr.value.s32 = it->second; - rollback_attrs.push_back(meter_attr); - } - - ReturnCode status; - int i; - for (i = 0; i < static_cast(meter_attrs.size()); ++i) { - status = ReturnCode(sai_policer_api->set_policer_attribute( - old_acl_meter.meter_oid, &meter_attrs[i])); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to update ACL meter attributes: %s", - status.message().c_str()); - break; - } - } - if (!status.ok()) { - for (--i; i >= 0; --i) { - auto sai_status = sai_policer_api->set_policer_attribute( - old_acl_meter.meter_oid, &rollback_attrs[i]); - if (sai_status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to set ACL policer attribute. SAI_STATUS: %s", - sai_serialize_status(sai_status).c_str()); - SWSS_RAISE_CRITICAL_STATE( - "Failed to set ACL policer attribute in recovery."); - } + ReturnCode status; + int i; + for (i = 0; i < static_cast(meter_attrs.size()); ++i) + { + status = ReturnCode(sai_policer_api->set_policer_attribute(old_acl_meter.meter_oid, &meter_attrs[i])); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to update ACL meter attributes: %s", status.message().c_str()); + break; + } } - return status; - } - SWSS_LOG_NOTICE("Suceeded to update ACL meter %s ", - sai_serialize_object_id(old_acl_meter.meter_oid).c_str()); - return ReturnCode(); + if (!status.ok()) + { + for (--i; i >= 0; --i) + { + auto sai_status = sai_policer_api->set_policer_attribute(old_acl_meter.meter_oid, &rollback_attrs[i]); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set ACL policer attribute. SAI_STATUS: %s", + sai_serialize_status(sai_status).c_str()); + SWSS_RAISE_CRITICAL_STATE("Failed to set ACL policer attribute in recovery."); + } + } + return status; + } + SWSS_LOG_NOTICE("Suceeded to update ACL meter %s ", sai_serialize_object_id(old_acl_meter.meter_oid).c_str()); + return ReturnCode(); } -ReturnCode AclRuleManager::removeAclMeter(const std::string& meter_key) { - SWSS_LOG_ENTER(); - sai_object_id_t meter_oid; - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_POLICER, meter_key, &meter_oid)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Failed to get ACL meter object id for ACL rule " - << QuotedVar(meter_key)); - } - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_policer_api->remove_policer(meter_oid), - "Failed to remove ACL meter for ACL rule " << QuotedVar(meter_key)); - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_POLICER, meter_key); - SWSS_LOG_NOTICE("Suceeded to remove ACL meter %s: %s ", - QuotedVar(meter_key).c_str(), - sai_serialize_object_id(meter_oid).c_str()); - return ReturnCode(); +ReturnCode AclRuleManager::removeAclMeter(const std::string &meter_key) +{ + SWSS_LOG_ENTER(); + sai_object_id_t meter_oid; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_POLICER, meter_key, &meter_oid)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Failed to get ACL meter object id for ACL rule " + << QuotedVar(meter_key)); + } + CHECK_ERROR_AND_LOG_AND_RETURN(sai_policer_api->remove_policer(meter_oid), + "Failed to remove ACL meter for ACL rule " << QuotedVar(meter_key)); + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_POLICER, meter_key); + SWSS_LOG_NOTICE("Suceeded to remove ACL meter %s: %s ", QuotedVar(meter_key).c_str(), + sai_serialize_object_id(meter_oid).c_str()); + return ReturnCode(); } ReturnCodeOr AclRuleManager::deserializeAclRuleAppDbEntry( - const std::string& acl_table_name, const std::string& key, - const std::vector& attributes) { - sai_object_id_t table_oid; - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_ACL_TABLE, acl_table_name, - &table_oid)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "ACL table " << QuotedVar(acl_table_name) << " is not found"; - } - P4AclRuleAppDbEntry app_db_entry = {}; - app_db_entry.acl_table_name = acl_table_name; - app_db_entry.db_key = concatTableNameAndRuleKey(acl_table_name, key); - // Parse rule key : match fields and priority - try { - const auto& rule_key_json = nlohmann::json::parse(key); - if (!rule_key_json.is_object()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid ACL rule key: should be a JSON object."; - } - for (auto rule_key_it = rule_key_json.begin(); - rule_key_it != rule_key_json.end(); ++rule_key_it) { - if (rule_key_it.key() == kPriority) { - if (!rule_key_it.value().is_number_unsigned()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid ACL rule priority type: should be uint32_t"; - } - app_db_entry.priority = rule_key_it.value(); - continue; - } else { - const auto& tokenized_match_field = - tokenize(rule_key_it.key(), kFieldDelimiter); - if (tokenized_match_field.size() <= 1 || - tokenized_match_field[0] != kMatchPrefix) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown ACL match field string " - << QuotedVar(rule_key_it.key()); - } - app_db_entry.match_fvs[tokenized_match_field[1]] = rule_key_it.value(); - } - } - } catch (std::exception& e) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to deserialize ACL rule match key"; - } - - for (const auto& it : attributes) { - const auto& field = fvField(it); - const auto& value = fvValue(it); - if (field == kControllerMetadata) continue; - if (field == kAction) { - app_db_entry.action = value; - continue; - } - const auto& tokenized_field = tokenize(field, kFieldDelimiter); - if (tokenized_field.size() <= 1) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown ACL rule field " << QuotedVar(field); - } - const auto& prefix = tokenized_field[0]; - if (prefix == kActionParamPrefix) { - const auto& param_name = tokenized_field[1]; - app_db_entry.action_param_fvs[param_name] = value; - } else if (prefix == kMeterPrefix) { - const auto& meter_attr_name = tokenized_field[1]; - if (std::stoi(value) < 0) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid ACL meter field value " << QuotedVar(field) << ": " - << QuotedVar(value); - } - if (meter_attr_name == kMeterCir) { - app_db_entry.meter.cir = std::stoi(value); - } else if (meter_attr_name == kMeterCburst) { - app_db_entry.meter.cburst = std::stoi(value); - } else if (meter_attr_name == kMeterPir) { - app_db_entry.meter.pir = std::stoi(value); - } else if (meter_attr_name == kMeterPburst) { - app_db_entry.meter.pburst = std::stoi(value); - } else { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown ACL meter field " << QuotedVar(field); - } - app_db_entry.meter.enabled = true; - } else { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown ACL rule field " << QuotedVar(field); - } - } - return app_db_entry; + const std::string &acl_table_name, const std::string &key, const std::vector &attributes) +{ + sai_object_id_t table_oid; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_ACL_TABLE, acl_table_name, &table_oid)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "ACL table " << QuotedVar(acl_table_name) << " is not found"; + } + P4AclRuleAppDbEntry app_db_entry = {}; + app_db_entry.acl_table_name = acl_table_name; + app_db_entry.db_key = concatTableNameAndRuleKey(acl_table_name, key); + // Parse rule key : match fields and priority + try + { + const auto &rule_key_json = nlohmann::json::parse(key); + if (!rule_key_json.is_object()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Invalid ACL rule key: should be a JSON object."; + } + for (auto rule_key_it = rule_key_json.begin(); rule_key_it != rule_key_json.end(); ++rule_key_it) + { + if (rule_key_it.key() == kPriority) + { + if (!rule_key_it.value().is_number_unsigned()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid ACL rule priority type: should be uint32_t"; + } + app_db_entry.priority = rule_key_it.value(); + continue; + } + else + { + const auto &tokenized_match_field = tokenize(rule_key_it.key(), kFieldDelimiter); + if (tokenized_match_field.size() <= 1 || tokenized_match_field[0] != kMatchPrefix) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unknown ACL match field string " << QuotedVar(rule_key_it.key()); + } + app_db_entry.match_fvs[tokenized_match_field[1]] = rule_key_it.value(); + } + } + } + catch (std::exception &e) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Failed to deserialize ACL rule match key"; + } + + for (const auto &it : attributes) + { + const auto &field = fvField(it); + const auto &value = fvValue(it); + if (field == kControllerMetadata) + continue; + if (field == kAction) + { + app_db_entry.action = value; + continue; + } + const auto &tokenized_field = tokenize(field, kFieldDelimiter); + if (tokenized_field.size() <= 1) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Unknown ACL rule field " << QuotedVar(field); + } + const auto &prefix = tokenized_field[0]; + if (prefix == kActionParamPrefix) + { + const auto ¶m_name = tokenized_field[1]; + app_db_entry.action_param_fvs[param_name] = value; + } + else if (prefix == kMeterPrefix) + { + const auto &meter_attr_name = tokenized_field[1]; + if (std::stoi(value) < 0) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid ACL meter field value " << QuotedVar(field) << ": " << QuotedVar(value); + } + if (meter_attr_name == kMeterCir) + { + app_db_entry.meter.cir = std::stoi(value); + } + else if (meter_attr_name == kMeterCburst) + { + app_db_entry.meter.cburst = std::stoi(value); + } + else if (meter_attr_name == kMeterPir) + { + app_db_entry.meter.pir = std::stoi(value); + } + else if (meter_attr_name == kMeterPburst) + { + app_db_entry.meter.pburst = std::stoi(value); + } + else + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Unknown ACL meter field " << QuotedVar(field); + } + app_db_entry.meter.enabled = true; + } + else + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Unknown ACL rule field " << QuotedVar(field); + } + } + return app_db_entry; } -ReturnCode AclRuleManager::validateAclRuleAppDbEntry( - const P4AclRuleAppDbEntry& app_db_entry) { - if (app_db_entry.priority == 0) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL rule in table " << QuotedVar(app_db_entry.acl_table_name) - << " is missing priority"; - } - return ReturnCode(); +ReturnCode AclRuleManager::validateAclRuleAppDbEntry(const P4AclRuleAppDbEntry &app_db_entry) +{ + if (app_db_entry.priority == 0) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL rule in table " << QuotedVar(app_db_entry.acl_table_name) << " is missing priority"; + } + return ReturnCode(); } -P4AclRule* AclRuleManager::getAclRule(const std::string& acl_table_name, - const std::string& acl_rule_key) { - if (m_aclRuleTables[acl_table_name].find(acl_rule_key) == - m_aclRuleTables[acl_table_name].end()) { - return nullptr; - } - return &m_aclRuleTables[acl_table_name][acl_rule_key]; +P4AclRule *AclRuleManager::getAclRule(const std::string &acl_table_name, const std::string &acl_rule_key) +{ + if (m_aclRuleTables[acl_table_name].find(acl_rule_key) == m_aclRuleTables[acl_table_name].end()) + { + return nullptr; + } + return &m_aclRuleTables[acl_table_name][acl_rule_key]; } -ReturnCode AclRuleManager::setAclRuleCounterStats(const P4AclRule& acl_rule) { - SWSS_LOG_ENTER(); - - std::vector counter_stats_values; - // Query colored packets/bytes stats by ACL meter object id if packet color is - // defined - if (!acl_rule.meter.packet_color_actions.empty()) { - std::vector counter_stats_ids; - const auto& packet_colors = acl_rule.meter.packet_color_actions; - for (const auto& pc : packet_colors) { - if (acl_rule.counter.packets_enabled) { - const auto& pkt_stats_id_it = - aclCounterColoredPacketsStatsIdMap.find(fvField(pc)); - if (pkt_stats_id_it == aclCounterColoredPacketsStatsIdMap.end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid meter attribute " << pkt_stats_id_it->first - << " for packet color in ACL rule " - << QuotedVar(acl_rule.db_key); - } - counter_stats_ids.push_back(pkt_stats_id_it->second); - } - if (acl_rule.counter.bytes_enabled) { - const auto& byte_stats_id_it = - aclCounterColoredBytesStatsIdMap.find(fvField(pc)); - if (byte_stats_id_it == aclCounterColoredBytesStatsIdMap.end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid meter attribute " << byte_stats_id_it->first - << " for packet color in ACL rule " - << QuotedVar(acl_rule.db_key); - } - counter_stats_ids.push_back(byte_stats_id_it->second); - } - } - std::vector meter_stats(counter_stats_ids.size()); - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_policer_api->get_policer_stats( - acl_rule.meter.meter_oid, - static_cast(counter_stats_ids.size()), - counter_stats_ids.data(), meter_stats.data()), - "Failed to get meter stats for ACL rule " - << QuotedVar(acl_rule.db_key)); - for (size_t i = 0; i < counter_stats_ids.size(); i++) { - counter_stats_values.push_back(swss::FieldValueTuple{ - aclCounterStatsIdNameMap.at(counter_stats_ids[i]), - std::to_string(meter_stats[i])}); - } - } - // Query general packets/bytes stats by ACL counter object id. - std::vector counter_attrs; - sai_attribute_t counter_attr; - if (acl_rule.counter.packets_enabled) { - counter_attr.id = SAI_ACL_COUNTER_ATTR_PACKETS; - counter_attrs.push_back(counter_attr); - } - if (acl_rule.counter.bytes_enabled) { - counter_attr.id = SAI_ACL_COUNTER_ATTR_BYTES; - counter_attrs.push_back(counter_attr); - } - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_acl_api->get_acl_counter_attribute( - acl_rule.counter.counter_oid, - static_cast(counter_attrs.size()), counter_attrs.data()), - "Failed to get counters stats for " - << QuotedVar(acl_rule.acl_table_name)); - for (const auto& counter_attr : counter_attrs) { - if (counter_attr.id == SAI_ACL_COUNTER_ATTR_PACKETS) { - counter_stats_values.push_back(swss::FieldValueTuple{ - P4_COUNTER_STATS_PACKETS, std::to_string(counter_attr.value.u64)}); - } - if (counter_attr.id == SAI_ACL_COUNTER_ATTR_BYTES) { - counter_stats_values.push_back(swss::FieldValueTuple{ - P4_COUNTER_STATS_BYTES, std::to_string(counter_attr.value.u64)}); - } - } - - // Set field value tuples for counters stats in COUNTERS_DB - m_countersTable->set(acl_rule.db_key, counter_stats_values); - return ReturnCode(); +ReturnCode AclRuleManager::setAclRuleCounterStats(const P4AclRule &acl_rule) +{ + SWSS_LOG_ENTER(); + + std::vector counter_stats_values; + // Query colored packets/bytes stats by ACL meter object id if packet color is + // defined + if (!acl_rule.meter.packet_color_actions.empty()) + { + std::vector counter_stats_ids; + const auto &packet_colors = acl_rule.meter.packet_color_actions; + for (const auto &pc : packet_colors) + { + if (acl_rule.counter.packets_enabled) + { + const auto &pkt_stats_id_it = aclCounterColoredPacketsStatsIdMap.find(fvField(pc)); + if (pkt_stats_id_it == aclCounterColoredPacketsStatsIdMap.end()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid meter attribute " << pkt_stats_id_it->first << " for packet color in ACL rule " + << QuotedVar(acl_rule.db_key); + } + counter_stats_ids.push_back(pkt_stats_id_it->second); + } + if (acl_rule.counter.bytes_enabled) + { + const auto &byte_stats_id_it = aclCounterColoredBytesStatsIdMap.find(fvField(pc)); + if (byte_stats_id_it == aclCounterColoredBytesStatsIdMap.end()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid meter attribute " << byte_stats_id_it->first << " for packet color in ACL rule " + << QuotedVar(acl_rule.db_key); + } + counter_stats_ids.push_back(byte_stats_id_it->second); + } + } + std::vector meter_stats(counter_stats_ids.size()); + CHECK_ERROR_AND_LOG_AND_RETURN(sai_policer_api->get_policer_stats( + acl_rule.meter.meter_oid, static_cast(counter_stats_ids.size()), + counter_stats_ids.data(), meter_stats.data()), + "Failed to get meter stats for ACL rule " << QuotedVar(acl_rule.db_key)); + for (size_t i = 0; i < counter_stats_ids.size(); i++) + { + counter_stats_values.push_back(swss::FieldValueTuple{aclCounterStatsIdNameMap.at(counter_stats_ids[i]), + std::to_string(meter_stats[i])}); + } + } + // Query general packets/bytes stats by ACL counter object id. + std::vector counter_attrs; + sai_attribute_t counter_attr; + if (acl_rule.counter.packets_enabled) + { + counter_attr.id = SAI_ACL_COUNTER_ATTR_PACKETS; + counter_attrs.push_back(counter_attr); + } + if (acl_rule.counter.bytes_enabled) + { + counter_attr.id = SAI_ACL_COUNTER_ATTR_BYTES; + counter_attrs.push_back(counter_attr); + } + CHECK_ERROR_AND_LOG_AND_RETURN(sai_acl_api->get_acl_counter_attribute(acl_rule.counter.counter_oid, + static_cast(counter_attrs.size()), + counter_attrs.data()), + "Failed to get counters stats for " << QuotedVar(acl_rule.acl_table_name)); + for (const auto &counter_attr : counter_attrs) + { + if (counter_attr.id == SAI_ACL_COUNTER_ATTR_PACKETS) + { + counter_stats_values.push_back( + swss::FieldValueTuple{P4_COUNTER_STATS_PACKETS, std::to_string(counter_attr.value.u64)}); + } + if (counter_attr.id == SAI_ACL_COUNTER_ATTR_BYTES) + { + counter_stats_values.push_back( + swss::FieldValueTuple{P4_COUNTER_STATS_BYTES, std::to_string(counter_attr.value.u64)}); + } + } + + // Set field value tuples for counters stats in COUNTERS_DB + m_countersTable->set(acl_rule.db_key, counter_stats_values); + return ReturnCode(); } -ReturnCode AclRuleManager::setMatchValue(const acl_entry_attr_union_t attr_name, - const std::string& attr_value, - sai_attribute_value_t* value, - P4AclRule* acl_rule, - const std::string& ip_type_bit_type) { - try { - switch (attr_name) { - case SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS: { - const auto& ports = tokenize(attr_value, kPortsDelimiter); - if (ports.empty()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "IN_PORTS are emtpy."; - } - for (const auto& alias : ports) { - Port port; - if (!gPortsOrch->getPort(alias, port)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Failed to locate port " << QuotedVar(alias); - } - acl_rule->in_ports.push_back(alias); - acl_rule->in_ports_oids.push_back(port.m_port_id); - } - value->aclfield.data.objlist.count = - static_cast(acl_rule->in_ports_oids.size()); - value->aclfield.data.objlist.list = acl_rule->in_ports_oids.data(); - break; - } - case SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS: { - const auto& ports = tokenize(attr_value, kPortsDelimiter); - if (ports.empty()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "OUT_PORTS are emtpy."; - } - for (const auto& alias : ports) { - Port port; - if (!gPortsOrch->getPort(alias, port)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Failed to locate port " << QuotedVar(alias); - } - acl_rule->out_ports.push_back(alias); - acl_rule->out_ports_oids.push_back(port.m_port_id); - } - value->aclfield.data.objlist.count = - static_cast(acl_rule->out_ports_oids.size()); - value->aclfield.data.objlist.list = acl_rule->out_ports_oids.data(); - break; - } - case SAI_ACL_ENTRY_ATTR_FIELD_IN_PORT: { - Port port; - if (!gPortsOrch->getPort(attr_value, port)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Failed to locate port " << QuotedVar(attr_value); - } - value->aclfield.data.oid = port.m_port_id; - acl_rule->in_ports.push_back(attr_value); - break; - } - case SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORT: { - Port port; - if (!gPortsOrch->getPort(attr_value, port)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Failed to locate port " << QuotedVar(attr_value); - } - value->aclfield.data.oid = port.m_port_id; - acl_rule->out_ports.push_back(attr_value); - break; - } - case SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE: { - if (!setMatchFieldIpType(attr_value, value, ip_type_bit_type)) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to set IP_TYPE with value " - << QuotedVar(attr_value); +ReturnCode AclRuleManager::setMatchValue(const acl_entry_attr_union_t attr_name, const std::string &attr_value, + sai_attribute_value_t *value, P4AclRule *acl_rule, + const std::string &ip_type_bit_type) +{ + try + { + switch (attr_name) + { + case SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS: { + const auto &ports = tokenize(attr_value, kPortsDelimiter); + if (ports.empty()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "IN_PORTS are emtpy."; + } + for (const auto &alias : ports) + { + Port port; + if (!gPortsOrch->getPort(alias, port)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) << "Failed to locate port " << QuotedVar(alias); + } + acl_rule->in_ports.push_back(alias); + acl_rule->in_ports_oids.push_back(port.m_port_id); + } + value->aclfield.data.objlist.count = static_cast(acl_rule->in_ports_oids.size()); + value->aclfield.data.objlist.list = acl_rule->in_ports_oids.data(); + break; } - break; - } - case SAI_ACL_ENTRY_ATTR_FIELD_TCP_FLAGS: - case SAI_ACL_ENTRY_ATTR_FIELD_IP_FLAGS: - case SAI_ACL_ENTRY_ATTR_FIELD_DSCP: { - // Support both exact value match and value/mask match - const auto& flag_data = tokenize(attr_value, kDataMaskDelimiter); - value->aclfield.data.u8 = to_uint(trim(flag_data[0]), 0, 0x3F); - - if (flag_data.size() == 2) { - value->aclfield.mask.u8 = - to_uint(trim(flag_data[1]), 0, 0x3F); - } else { - value->aclfield.mask.u8 = 0x3F; + case SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS: { + const auto &ports = tokenize(attr_value, kPortsDelimiter); + if (ports.empty()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "OUT_PORTS are emtpy."; + } + for (const auto &alias : ports) + { + Port port; + if (!gPortsOrch->getPort(alias, port)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) << "Failed to locate port " << QuotedVar(alias); + } + acl_rule->out_ports.push_back(alias); + acl_rule->out_ports_oids.push_back(port.m_port_id); + } + value->aclfield.data.objlist.count = static_cast(acl_rule->out_ports_oids.size()); + value->aclfield.data.objlist.list = acl_rule->out_ports_oids.data(); + break; } - break; - } - case SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE: - case SAI_ACL_ENTRY_ATTR_FIELD_L4_SRC_PORT: - case SAI_ACL_ENTRY_ATTR_FIELD_L4_DST_PORT: - case SAI_ACL_ENTRY_ATTR_FIELD_IP_IDENTIFICATION: - case SAI_ACL_ENTRY_ATTR_FIELD_OUTER_VLAN_ID: - case SAI_ACL_ENTRY_ATTR_FIELD_INNER_VLAN_ID: - case SAI_ACL_ENTRY_ATTR_FIELD_INNER_ETHER_TYPE: - case SAI_ACL_ENTRY_ATTR_FIELD_INNER_L4_SRC_PORT: - case SAI_ACL_ENTRY_ATTR_FIELD_INNER_L4_DST_PORT: { - const std::vector& value_and_mask = - tokenize(attr_value, kDataMaskDelimiter); - value->aclfield.data.u16 = to_uint(trim(value_and_mask[0])); - if (value_and_mask.size() > 1) { - value->aclfield.mask.u16 = to_uint(trim(value_and_mask[1])); - } else { - value->aclfield.mask.u16 = 0xFFFF; + case SAI_ACL_ENTRY_ATTR_FIELD_IN_PORT: { + Port port; + if (!gPortsOrch->getPort(attr_value, port)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) << "Failed to locate port " << QuotedVar(attr_value); + } + value->aclfield.data.oid = port.m_port_id; + acl_rule->in_ports.push_back(attr_value); + break; } - break; - } - case SAI_ACL_ENTRY_ATTR_FIELD_INNER_SRC_IP: - case SAI_ACL_ENTRY_ATTR_FIELD_INNER_DST_IP: - case SAI_ACL_ENTRY_ATTR_FIELD_SRC_IP: - case SAI_ACL_ENTRY_ATTR_FIELD_DST_IP: { - const auto& tokenized_ip = tokenize(attr_value, kDataMaskDelimiter); - if (tokenized_ip.size() == 2) { - // data & mask - swss::IpAddress ip_data(trim(tokenized_ip[0])); - if (!ip_data.isV4()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "IP data type should be v4 type: " - << QuotedVar(attr_value); - } - swss::IpAddress ip_mask(trim(tokenized_ip[1])); - if (!ip_mask.isV4()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "IP mask type should be v4 type: " - << QuotedVar(attr_value); - } - value->aclfield.data.ip4 = ip_data.getV4Addr(); - value->aclfield.mask.ip4 = ip_mask.getV4Addr(); - } else { - // LPM annotated value - swss::IpPrefix ip_prefix(trim(attr_value)); - if (!ip_prefix.isV4()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "IP type should be v6 type: " << QuotedVar(attr_value); - } - value->aclfield.data.ip4 = ip_prefix.getIp().getV4Addr(); - value->aclfield.mask.ip4 = ip_prefix.getMask().getV4Addr(); + case SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORT: { + Port port; + if (!gPortsOrch->getPort(attr_value, port)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) << "Failed to locate port " << QuotedVar(attr_value); + } + value->aclfield.data.oid = port.m_port_id; + acl_rule->out_ports.push_back(attr_value); + break; } - break; - } - case SAI_ACL_ENTRY_ATTR_FIELD_INNER_SRC_IPV6: - case SAI_ACL_ENTRY_ATTR_FIELD_INNER_DST_IPV6: - case SAI_ACL_ENTRY_ATTR_FIELD_SRC_IPV6: - case SAI_ACL_ENTRY_ATTR_FIELD_DST_IPV6: { - const auto& tokenized_ip = tokenize(attr_value, kDataMaskDelimiter); - if (tokenized_ip.size() == 2) { - // data & mask - swss::IpAddress ip_data(trim(tokenized_ip[0])); - if (ip_data.isV4()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "IP data type should be v6 type: " - << QuotedVar(attr_value); - } - swss::IpAddress ip_mask(trim(tokenized_ip[1])); - if (ip_mask.isV4()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "IP mask type should be v6 type: " - << QuotedVar(attr_value); - } - memcpy(value->aclfield.data.ip6, ip_data.getV6Addr(), - sizeof(sai_ip6_t)); - memcpy(value->aclfield.mask.ip6, ip_mask.getV6Addr(), - sizeof(sai_ip6_t)); - } else { - // LPM annotated value - swss::IpPrefix ip_prefix(trim(attr_value)); - if (ip_prefix.isV4()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "IP type should be v6 type: " << QuotedVar(attr_value); - } - memcpy(value->aclfield.data.ip6, ip_prefix.getIp().getV6Addr(), - sizeof(sai_ip6_t)); - memcpy(value->aclfield.mask.ip6, ip_prefix.getMask().getV6Addr(), - sizeof(sai_ip6_t)); + case SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE: { + if (!setMatchFieldIpType(attr_value, value, ip_type_bit_type)) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Failed to set IP_TYPE with value " << QuotedVar(attr_value); + } + break; } - break; - } - case SAI_ACL_ENTRY_ATTR_FIELD_SRC_MAC: - case SAI_ACL_ENTRY_ATTR_FIELD_DST_MAC: { - const std::vector mask_and_value = - tokenize(attr_value, kDataMaskDelimiter); - swss::MacAddress mac(trim(mask_and_value[0])); - memcpy(value->aclfield.data.mac, mac.getMac(), sizeof(sai_mac_t)); - if (mask_and_value.size() > 1) { - swss::MacAddress mask(trim(mask_and_value[1])); - memcpy(value->aclfield.mask.mac, mask.getMac(), sizeof(sai_mac_t)); - } else { - const sai_mac_t mac_mask = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - memcpy(value->aclfield.mask.mac, mac_mask, sizeof(sai_mac_t)); + case SAI_ACL_ENTRY_ATTR_FIELD_TCP_FLAGS: + case SAI_ACL_ENTRY_ATTR_FIELD_IP_FLAGS: + case SAI_ACL_ENTRY_ATTR_FIELD_DSCP: { + // Support both exact value match and value/mask match + const auto &flag_data = tokenize(attr_value, kDataMaskDelimiter); + value->aclfield.data.u8 = to_uint(trim(flag_data[0]), 0, 0x3F); + + if (flag_data.size() == 2) + { + value->aclfield.mask.u8 = to_uint(trim(flag_data[1]), 0, 0x3F); + } + else + { + value->aclfield.mask.u8 = 0x3F; + } + break; } - break; - } - case SAI_ACL_ENTRY_ATTR_FIELD_TC: - case SAI_ACL_ENTRY_ATTR_FIELD_ICMP_TYPE: - case SAI_ACL_ENTRY_ATTR_FIELD_ICMP_CODE: - case SAI_ACL_ENTRY_ATTR_FIELD_ICMPV6_TYPE: - case SAI_ACL_ENTRY_ATTR_FIELD_ICMPV6_CODE: - case SAI_ACL_ENTRY_ATTR_FIELD_OUTER_VLAN_PRI: - case SAI_ACL_ENTRY_ATTR_FIELD_OUTER_VLAN_CFI: - case SAI_ACL_ENTRY_ATTR_FIELD_INNER_VLAN_PRI: - case SAI_ACL_ENTRY_ATTR_FIELD_INNER_VLAN_CFI: - case SAI_ACL_ENTRY_ATTR_FIELD_INNER_IP_PROTOCOL: - case SAI_ACL_ENTRY_ATTR_FIELD_IP_PROTOCOL: - case SAI_ACL_ENTRY_ATTR_FIELD_ECN: - case SAI_ACL_ENTRY_ATTR_FIELD_TTL: - case SAI_ACL_ENTRY_ATTR_FIELD_TOS: - case SAI_ACL_ENTRY_ATTR_FIELD_IPV6_NEXT_HEADER: { - const std::vector& value_and_mask = - tokenize(attr_value, kDataMaskDelimiter); - value->aclfield.data.u8 = to_uint(trim(value_and_mask[0])); - if (value_and_mask.size() > 1) { - value->aclfield.mask.u8 = to_uint(trim(value_and_mask[1])); - } else { - value->aclfield.mask.u8 = 0xFF; + case SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE: + case SAI_ACL_ENTRY_ATTR_FIELD_L4_SRC_PORT: + case SAI_ACL_ENTRY_ATTR_FIELD_L4_DST_PORT: + case SAI_ACL_ENTRY_ATTR_FIELD_IP_IDENTIFICATION: + case SAI_ACL_ENTRY_ATTR_FIELD_OUTER_VLAN_ID: + case SAI_ACL_ENTRY_ATTR_FIELD_INNER_VLAN_ID: + case SAI_ACL_ENTRY_ATTR_FIELD_INNER_ETHER_TYPE: + case SAI_ACL_ENTRY_ATTR_FIELD_INNER_L4_SRC_PORT: + case SAI_ACL_ENTRY_ATTR_FIELD_INNER_L4_DST_PORT: { + const std::vector &value_and_mask = tokenize(attr_value, kDataMaskDelimiter); + value->aclfield.data.u16 = to_uint(trim(value_and_mask[0])); + if (value_and_mask.size() > 1) + { + value->aclfield.mask.u16 = to_uint(trim(value_and_mask[1])); + } + else + { + value->aclfield.mask.u16 = 0xFFFF; + } + break; } - break; - } - case SAI_ACL_ENTRY_ATTR_FIELD_TUNNEL_VNI: - case SAI_ACL_ENTRY_ATTR_FIELD_ROUTE_DST_USER_META: - case SAI_ACL_ENTRY_ATTR_FIELD_IPV6_FLOW_LABEL: { - const std::vector& value_and_mask = - tokenize(attr_value, kDataMaskDelimiter); - value->aclfield.data.u32 = to_uint(trim(value_and_mask[0])); - if (value_and_mask.size() > 1) { - value->aclfield.mask.u32 = to_uint(trim(value_and_mask[1])); - } else { - value->aclfield.mask.u32 = 0xFFFFFFFF; + case SAI_ACL_ENTRY_ATTR_FIELD_INNER_SRC_IP: + case SAI_ACL_ENTRY_ATTR_FIELD_INNER_DST_IP: + case SAI_ACL_ENTRY_ATTR_FIELD_SRC_IP: + case SAI_ACL_ENTRY_ATTR_FIELD_DST_IP: { + const auto &tokenized_ip = tokenize(attr_value, kDataMaskDelimiter); + if (tokenized_ip.size() == 2) + { + // data & mask + swss::IpAddress ip_data(trim(tokenized_ip[0])); + if (!ip_data.isV4()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "IP data type should be v4 type: " << QuotedVar(attr_value); + } + swss::IpAddress ip_mask(trim(tokenized_ip[1])); + if (!ip_mask.isV4()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "IP mask type should be v4 type: " << QuotedVar(attr_value); + } + value->aclfield.data.ip4 = ip_data.getV4Addr(); + value->aclfield.mask.ip4 = ip_mask.getV4Addr(); + } + else + { + // LPM annotated value + swss::IpPrefix ip_prefix(trim(attr_value)); + if (!ip_prefix.isV4()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "IP type should be v6 type: " << QuotedVar(attr_value); + } + value->aclfield.data.ip4 = ip_prefix.getIp().getV4Addr(); + value->aclfield.mask.ip4 = ip_prefix.getMask().getV4Addr(); + } + break; } - break; - } - case SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_FRAG: { - const auto& ip_frag_it = aclIpFragLookup.find(attr_value); - if (ip_frag_it == aclIpFragLookup.end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid IP frag " << QuotedVar(attr_value); - } - value->aclfield.data.u32 = ip_frag_it->second; - value->aclfield.mask.u32 = 0xFFFFFFFF; - break; - } - case SAI_ACL_ENTRY_ATTR_FIELD_PACKET_VLAN: { - const auto& packet_vlan_it = aclPacketVlanLookup.find(attr_value); - if (packet_vlan_it == aclPacketVlanLookup.end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid Packet VLAN " << QuotedVar(attr_value); - } - value->aclfield.data.u32 = packet_vlan_it->second; - value->aclfield.mask.u32 = 0xFFFFFFFF; - break; - } - default: { + case SAI_ACL_ENTRY_ATTR_FIELD_INNER_SRC_IPV6: + case SAI_ACL_ENTRY_ATTR_FIELD_INNER_DST_IPV6: + case SAI_ACL_ENTRY_ATTR_FIELD_SRC_IPV6: + case SAI_ACL_ENTRY_ATTR_FIELD_DST_IPV6: { + const auto &tokenized_ip = tokenize(attr_value, kDataMaskDelimiter); + if (tokenized_ip.size() == 2) + { + // data & mask + swss::IpAddress ip_data(trim(tokenized_ip[0])); + if (ip_data.isV4()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "IP data type should be v6 type: " << QuotedVar(attr_value); + } + swss::IpAddress ip_mask(trim(tokenized_ip[1])); + if (ip_mask.isV4()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "IP mask type should be v6 type: " << QuotedVar(attr_value); + } + memcpy(value->aclfield.data.ip6, ip_data.getV6Addr(), sizeof(sai_ip6_t)); + memcpy(value->aclfield.mask.ip6, ip_mask.getV6Addr(), sizeof(sai_ip6_t)); + } + else + { + // LPM annotated value + swss::IpPrefix ip_prefix(trim(attr_value)); + if (ip_prefix.isV4()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "IP type should be v6 type: " << QuotedVar(attr_value); + } + memcpy(value->aclfield.data.ip6, ip_prefix.getIp().getV6Addr(), sizeof(sai_ip6_t)); + memcpy(value->aclfield.mask.ip6, ip_prefix.getMask().getV6Addr(), sizeof(sai_ip6_t)); + } + break; + } + case SAI_ACL_ENTRY_ATTR_FIELD_SRC_MAC: + case SAI_ACL_ENTRY_ATTR_FIELD_DST_MAC: { + const std::vector mask_and_value = tokenize(attr_value, kDataMaskDelimiter); + swss::MacAddress mac(trim(mask_and_value[0])); + memcpy(value->aclfield.data.mac, mac.getMac(), sizeof(sai_mac_t)); + if (mask_and_value.size() > 1) + { + swss::MacAddress mask(trim(mask_and_value[1])); + memcpy(value->aclfield.mask.mac, mask.getMac(), sizeof(sai_mac_t)); + } + else + { + const sai_mac_t mac_mask = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + memcpy(value->aclfield.mask.mac, mac_mask, sizeof(sai_mac_t)); + } + break; + } + case SAI_ACL_ENTRY_ATTR_FIELD_TC: + case SAI_ACL_ENTRY_ATTR_FIELD_ICMP_TYPE: + case SAI_ACL_ENTRY_ATTR_FIELD_ICMP_CODE: + case SAI_ACL_ENTRY_ATTR_FIELD_ICMPV6_TYPE: + case SAI_ACL_ENTRY_ATTR_FIELD_ICMPV6_CODE: + case SAI_ACL_ENTRY_ATTR_FIELD_OUTER_VLAN_PRI: + case SAI_ACL_ENTRY_ATTR_FIELD_OUTER_VLAN_CFI: + case SAI_ACL_ENTRY_ATTR_FIELD_INNER_VLAN_PRI: + case SAI_ACL_ENTRY_ATTR_FIELD_INNER_VLAN_CFI: + case SAI_ACL_ENTRY_ATTR_FIELD_INNER_IP_PROTOCOL: + case SAI_ACL_ENTRY_ATTR_FIELD_IP_PROTOCOL: + case SAI_ACL_ENTRY_ATTR_FIELD_ECN: + case SAI_ACL_ENTRY_ATTR_FIELD_TTL: + case SAI_ACL_ENTRY_ATTR_FIELD_TOS: + case SAI_ACL_ENTRY_ATTR_FIELD_IPV6_NEXT_HEADER: { + const std::vector &value_and_mask = tokenize(attr_value, kDataMaskDelimiter); + value->aclfield.data.u8 = to_uint(trim(value_and_mask[0])); + if (value_and_mask.size() > 1) + { + value->aclfield.mask.u8 = to_uint(trim(value_and_mask[1])); + } + else + { + value->aclfield.mask.u8 = 0xFF; + } + break; + } + case SAI_ACL_ENTRY_ATTR_FIELD_TUNNEL_VNI: + case SAI_ACL_ENTRY_ATTR_FIELD_ROUTE_DST_USER_META: + case SAI_ACL_ENTRY_ATTR_FIELD_IPV6_FLOW_LABEL: { + const std::vector &value_and_mask = tokenize(attr_value, kDataMaskDelimiter); + value->aclfield.data.u32 = to_uint(trim(value_and_mask[0])); + if (value_and_mask.size() > 1) + { + value->aclfield.mask.u32 = to_uint(trim(value_and_mask[1])); + } + else + { + value->aclfield.mask.u32 = 0xFFFFFFFF; + } + break; + } + case SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_FRAG: { + const auto &ip_frag_it = aclIpFragLookup.find(attr_value); + if (ip_frag_it == aclIpFragLookup.end()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Invalid IP frag " << QuotedVar(attr_value); + } + value->aclfield.data.u32 = ip_frag_it->second; + value->aclfield.mask.u32 = 0xFFFFFFFF; + break; + } + case SAI_ACL_ENTRY_ATTR_FIELD_PACKET_VLAN: { + const auto &packet_vlan_it = aclPacketVlanLookup.find(attr_value); + if (packet_vlan_it == aclPacketVlanLookup.end()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Invalid Packet VLAN " << QuotedVar(attr_value); + } + value->aclfield.data.u32 = packet_vlan_it->second; + value->aclfield.mask.u32 = 0xFFFFFFFF; + break; + } + default: { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL match field " << attr_name << " is not supported."; + } + } + } + catch (std::exception &e) + { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL match field " << attr_name << " is not supported."; - } - } - } catch (std::exception& e) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to parse match attribute " << attr_name - << " value: " << QuotedVar(attr_value); - } - value->aclfield.enable = true; - return ReturnCode(); + << "Failed to parse match attribute " << attr_name << " value: " << QuotedVar(attr_value); + } + value->aclfield.enable = true; + return ReturnCode(); } -ReturnCode AclRuleManager::getRedirectActionPortOid( - const std::string& target, sai_object_id_t* rediect_oid) { - // Try to parse physical port and LAG first - Port port; - if (gPortsOrch->getPort(target, port)) { - if (port.m_type == Port::PHY) { - *rediect_oid = port.m_port_id; - return ReturnCode(); - } else if (port.m_type == Port::LAG) { - *rediect_oid = port.m_lag_id; - return ReturnCode(); - } else { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Wrong port type for REDIRECT action. Only " - "physical ports and LAG ports are supported"); - } - } - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Port " << QuotedVar(target) << " not found."; +ReturnCode AclRuleManager::getRedirectActionPortOid(const std::string &target, sai_object_id_t *rediect_oid) +{ + // Try to parse physical port and LAG first + Port port; + if (gPortsOrch->getPort(target, port)) + { + if (port.m_type == Port::PHY) + { + *rediect_oid = port.m_port_id; + return ReturnCode(); + } + else if (port.m_type == Port::LAG) + { + *rediect_oid = port.m_lag_id; + return ReturnCode(); + } + else + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Wrong port type for REDIRECT action. Only " + "physical ports and LAG ports are supported"); + } + } + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) << "Port " << QuotedVar(target) << " not found."; } -ReturnCode AclRuleManager::getRedirectActionNextHopOid( - const std::string& target, sai_object_id_t* rediect_oid) { - // Try to get nexthop object id - const auto& next_hop_key = KeyGenerator::generateNextHopKey(target); - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key, - rediect_oid)) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL Redirect action target next hop ip: " - << QuotedVar(target) - << " doesn't exist on the switch"); - } - return ReturnCode(); +ReturnCode AclRuleManager::getRedirectActionNextHopOid(const std::string &target, sai_object_id_t *rediect_oid) +{ + // Try to get nexthop object id + const auto &next_hop_key = KeyGenerator::generateNextHopKey(target); + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key, rediect_oid)) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL Redirect action target next hop ip: " << QuotedVar(target) + << " doesn't exist on the switch"); + } + return ReturnCode(); } -ReturnCode AclRuleManager::setAllMatchFieldValues( - const P4AclRuleAppDbEntry& app_db_entry, - const P4AclTableDefinition* acl_table, P4AclRule& acl_rule) { - for (const auto& match_fv : app_db_entry.match_fvs) { - const auto& match_field = fvField(match_fv); - const auto& match_value = fvValue(match_fv); - ReturnCode set_match_rc; - // Set UDF fields - auto udf_fields_it = acl_table->udf_fields_lookup.find(match_field); - if (udf_fields_it != acl_table->udf_fields_lookup.end()) { - // Bytes Offset to extract Hex value from match_value string - uint16_t bytes_offset = 0; - for (const auto& udf_field : udf_fields_it->second) { - auto udf_group_index_it = - acl_table->udf_group_attr_index_lookup.find(udf_field.group_id); - if (udf_group_index_it == - acl_table->udf_group_attr_index_lookup.end()) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "No UDF group found in ACL table definition with id:" - << QuotedVar(udf_field.group_id)); - } - set_match_rc = setUdfMatchValue( - udf_field, match_value, - &acl_rule - .match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN + - udf_group_index_it->second], - &acl_rule.udf_data_masks - [SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN + - udf_group_index_it->second], - bytes_offset); - if (!set_match_rc.ok()) { - set_match_rc.prepend("Invalid ACL rule match field " + - QuotedVar(match_field) + ": " + - QuotedVar(match_value) + " to add: "); - return set_match_rc; - } - bytes_offset = (uint16_t)(bytes_offset + udf_field.length); - } - continue; - } - // Set Composite SAI fields - auto composite_sai_match_field_it = - acl_table->composite_sai_match_fields_lookup.find(match_field); - if (composite_sai_match_field_it != - acl_table->composite_sai_match_fields_lookup.end()) { - // Handle composite SAI match fields - for (const auto& sai_match_field : composite_sai_match_field_it->second) { - set_match_rc = setCompositeSaiMatchValue( - sai_match_field.entry_attr, match_value, - &acl_rule.match_fvs[sai_match_field.entry_attr]); - if (!set_match_rc.ok()) { - set_match_rc.prepend("Invalid ACL rule match field " + - QuotedVar(match_field) + ": " + - QuotedVar(match_value) + " to add: "); - return set_match_rc; - } - } - continue; - } - auto sai_match_field_it = - acl_table->sai_match_field_lookup.find(match_field); - if (sai_match_field_it == acl_table->sai_match_field_lookup.end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL rule match field " << QuotedVar(match_field) << ": " - << QuotedVar(match_value) << " is an invalid ACL rule attribute"; - } - auto& sai_match_field = sai_match_field_it->second; - if (sai_match_field.entry_attr == SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE && - acl_table->ip_type_bit_type_lookup.find(sai_match_field_it->first) != - acl_table->ip_type_bit_type_lookup.end()) { - set_match_rc = setMatchValue( - sai_match_field.entry_attr, match_value, - &acl_rule.match_fvs[sai_match_field.entry_attr], &acl_rule, - acl_table->ip_type_bit_type_lookup.at(sai_match_field_it->first)); - } else { - set_match_rc = setMatchValue( - sai_match_field.entry_attr, match_value, - &acl_rule.match_fvs[sai_match_field.entry_attr], &acl_rule); - } - if (!set_match_rc.ok()) { - set_match_rc.prepend("Invalid ACL rule match field " + - QuotedVar(match_field) + ": " + - QuotedVar(match_value) + " to add: "); - return set_match_rc; - } - } - if (!acl_table->ip_type_bit_type_lookup.empty() && - acl_rule.match_fvs.find(SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE) == - acl_rule.match_fvs.end()) { - // Wildcard match on ip type bits - sai_attribute_value_t ip_type_attr; - ip_type_attr.aclfield.data.u32 = SAI_ACL_IP_TYPE_ANY; - ip_type_attr.aclfield.mask.u32 = 0xFFFFFFFF; - ip_type_attr.aclfield.enable = true; - acl_rule.match_fvs.insert( - {SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE, ip_type_attr}); - } - return ReturnCode(); +ReturnCode AclRuleManager::setAllMatchFieldValues(const P4AclRuleAppDbEntry &app_db_entry, + const P4AclTableDefinition *acl_table, P4AclRule &acl_rule) +{ + for (const auto &match_fv : app_db_entry.match_fvs) + { + const auto &match_field = fvField(match_fv); + const auto &match_value = fvValue(match_fv); + ReturnCode set_match_rc; + // Set UDF fields + auto udf_fields_it = acl_table->udf_fields_lookup.find(match_field); + if (udf_fields_it != acl_table->udf_fields_lookup.end()) + { + // Bytes Offset to extract Hex value from match_value string + uint16_t bytes_offset = 0; + for (const auto &udf_field : udf_fields_it->second) + { + auto udf_group_index_it = acl_table->udf_group_attr_index_lookup.find(udf_field.group_id); + if (udf_group_index_it == acl_table->udf_group_attr_index_lookup.end()) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( + "No UDF group found in ACL table definition with id:" << QuotedVar(udf_field.group_id)); + } + set_match_rc = setUdfMatchValue( + udf_field, match_value, + &acl_rule.match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN + udf_group_index_it->second], + &acl_rule + .udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN + udf_group_index_it->second], + bytes_offset); + if (!set_match_rc.ok()) + { + set_match_rc.prepend("Invalid ACL rule match field " + QuotedVar(match_field) + ": " + + QuotedVar(match_value) + " to add: "); + return set_match_rc; + } + bytes_offset = (uint16_t)(bytes_offset + udf_field.length); + } + continue; + } + // Set Composite SAI fields + auto composite_sai_match_field_it = acl_table->composite_sai_match_fields_lookup.find(match_field); + if (composite_sai_match_field_it != acl_table->composite_sai_match_fields_lookup.end()) + { + // Handle composite SAI match fields + for (const auto &sai_match_field : composite_sai_match_field_it->second) + { + set_match_rc = setCompositeSaiMatchValue(sai_match_field.entry_attr, match_value, + &acl_rule.match_fvs[sai_match_field.entry_attr]); + if (!set_match_rc.ok()) + { + set_match_rc.prepend("Invalid ACL rule match field " + QuotedVar(match_field) + ": " + + QuotedVar(match_value) + " to add: "); + return set_match_rc; + } + } + continue; + } + auto sai_match_field_it = acl_table->sai_match_field_lookup.find(match_field); + if (sai_match_field_it == acl_table->sai_match_field_lookup.end()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL rule match field " << QuotedVar(match_field) << ": " << QuotedVar(match_value) + << " is an invalid ACL rule attribute"; + } + auto &sai_match_field = sai_match_field_it->second; + if (sai_match_field.entry_attr == SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE && + acl_table->ip_type_bit_type_lookup.find(sai_match_field_it->first) != + acl_table->ip_type_bit_type_lookup.end()) + { + set_match_rc = + setMatchValue(sai_match_field.entry_attr, match_value, &acl_rule.match_fvs[sai_match_field.entry_attr], + &acl_rule, acl_table->ip_type_bit_type_lookup.at(sai_match_field_it->first)); + } + else + { + set_match_rc = setMatchValue(sai_match_field.entry_attr, match_value, + &acl_rule.match_fvs[sai_match_field.entry_attr], &acl_rule); + } + if (!set_match_rc.ok()) + { + set_match_rc.prepend("Invalid ACL rule match field " + QuotedVar(match_field) + ": " + + QuotedVar(match_value) + " to add: "); + return set_match_rc; + } + } + if (!acl_table->ip_type_bit_type_lookup.empty() && + acl_rule.match_fvs.find(SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE) == acl_rule.match_fvs.end()) + { + // Wildcard match on ip type bits + sai_attribute_value_t ip_type_attr; + ip_type_attr.aclfield.data.u32 = SAI_ACL_IP_TYPE_ANY; + ip_type_attr.aclfield.mask.u32 = 0xFFFFFFFF; + ip_type_attr.aclfield.enable = true; + acl_rule.match_fvs.insert({SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE, ip_type_attr}); + } + return ReturnCode(); } -ReturnCode AclRuleManager::setAllActionFieldValues( - const P4AclRuleAppDbEntry& app_db_entry, - const P4AclTableDefinition* acl_table, P4AclRule& acl_rule) { - const auto& action_param_list_it = - acl_table->rule_action_field_lookup.find(app_db_entry.action); - if (action_param_list_it == acl_table->rule_action_field_lookup.end()) { - ReturnCode status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid P4 ACL action " - << QuotedVar(app_db_entry.action); - return status; - } - SaiActionWithParam sai_action_param; - for (const auto& action_param : action_param_list_it->second) { - sai_action_param.action = action_param.action; - sai_action_param.param_name = action_param.param_name; - sai_action_param.param_value = action_param.param_value; - if (!action_param.param_name.empty()) { - const auto& param_value_it = - app_db_entry.action_param_fvs.find(action_param.param_name); - if (param_value_it == app_db_entry.action_param_fvs.end()) { +ReturnCode AclRuleManager::setAllActionFieldValues(const P4AclRuleAppDbEntry &app_db_entry, + const P4AclTableDefinition *acl_table, P4AclRule &acl_rule) +{ + const auto &action_param_list_it = acl_table->rule_action_field_lookup.find(app_db_entry.action); + if (action_param_list_it == acl_table->rule_action_field_lookup.end()) + { ReturnCode status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "No action param found for action " - << action_param.action; + << "Invalid P4 ACL action " << QuotedVar(app_db_entry.action); return status; - } - if (!param_value_it->second.empty()) { - sai_action_param.param_value = param_value_it->second; - } - } - auto set_action_rc = setActionValue( - sai_action_param.action, sai_action_param.param_value, - &acl_rule.action_fvs[sai_action_param.action], &acl_rule); - if (!set_action_rc.ok()) { - return set_action_rc; - } - } - return ReturnCode(); + } + SaiActionWithParam sai_action_param; + for (const auto &action_param : action_param_list_it->second) + { + sai_action_param.action = action_param.action; + sai_action_param.param_name = action_param.param_name; + sai_action_param.param_value = action_param.param_value; + if (!action_param.param_name.empty()) + { + const auto ¶m_value_it = app_db_entry.action_param_fvs.find(action_param.param_name); + if (param_value_it == app_db_entry.action_param_fvs.end()) + { + ReturnCode status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "No action param found for action " << action_param.action; + return status; + } + if (!param_value_it->second.empty()) + { + sai_action_param.param_value = param_value_it->second; + } + } + auto set_action_rc = setActionValue(sai_action_param.action, sai_action_param.param_value, + &acl_rule.action_fvs[sai_action_param.action], &acl_rule); + if (!set_action_rc.ok()) + { + return set_action_rc; + } + } + return ReturnCode(); } -ReturnCode AclRuleManager::setActionValue( - const acl_entry_attr_union_t attr_name, const std::string& attr_value, - sai_attribute_value_t* value, P4AclRule* acl_rule) { - switch (attr_name) { +ReturnCode AclRuleManager::setActionValue(const acl_entry_attr_union_t attr_name, const std::string &attr_value, + sai_attribute_value_t *value, P4AclRule *acl_rule) +{ + switch (attr_name) + { case SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION: { - const auto it = aclPacketActionLookup.find(attr_value); - if (it != aclPacketActionLookup.end()) { - value->aclaction.parameter.s32 = it->second; - } else { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid ACL packet action " << QuotedVar(attr_value) - << " for " << QuotedVar(acl_rule->acl_table_name); - } - break; + const auto it = aclPacketActionLookup.find(attr_value); + if (it != aclPacketActionLookup.end()) + { + value->aclaction.parameter.s32 = it->second; + } + else + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid ACL packet action " << QuotedVar(attr_value) << " for " + << QuotedVar(acl_rule->acl_table_name); + } + break; } case SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT: { - sai_object_id_t redirect_oid; - if (getRedirectActionPortOid(attr_value, &redirect_oid).ok()) { + sai_object_id_t redirect_oid; + if (getRedirectActionPortOid(attr_value, &redirect_oid).ok()) + { + value->aclaction.parameter.oid = redirect_oid; + break; + } + RETURN_IF_ERROR(getRedirectActionNextHopOid(attr_value, &redirect_oid)); value->aclaction.parameter.oid = redirect_oid; + acl_rule->action_redirect_nexthop_key = KeyGenerator::generateNextHopKey(attr_value); break; - } - RETURN_IF_ERROR(getRedirectActionNextHopOid(attr_value, &redirect_oid)); - value->aclaction.parameter.oid = redirect_oid; - acl_rule->action_redirect_nexthop_key = - KeyGenerator::generateNextHopKey(attr_value); - break; } case SAI_ACL_ENTRY_ATTR_ACTION_ENDPOINT_IP: { - try { - swss::IpAddress ip(attr_value); - if (ip.isV4()) { - value->aclaction.parameter.ip4 = ip.getV4Addr(); - } else { - memcpy(value->aclaction.parameter.ip6, ip.getV6Addr(), - sizeof(sai_ip6_t)); - } - } catch (std::exception& e) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Action attribute " << QuotedVar(std::to_string(attr_name)) - << " is invalid for " << QuotedVar(acl_rule->acl_table_name) - << ": Expect IP address but got " << QuotedVar(attr_value); - } - break; + try + { + swss::IpAddress ip(attr_value); + if (ip.isV4()) + { + value->aclaction.parameter.ip4 = ip.getV4Addr(); + } + else + { + memcpy(value->aclaction.parameter.ip6, ip.getV6Addr(), sizeof(sai_ip6_t)); + } + } + catch (std::exception &e) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Action attribute " << QuotedVar(std::to_string(attr_name)) << " is invalid for " + << QuotedVar(acl_rule->acl_table_name) << ": Expect IP address but got " << QuotedVar(attr_value); + } + break; } case SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS: case SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS: { - sai_object_id_t mirror_session_oid; - std::string key = KeyGenerator::generateMirrorSessionKey(attr_value); - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_MIRROR_SESSION, key, - &mirror_session_oid)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Mirror session " << QuotedVar(attr_value) - << " does not exist for " << QuotedVar(acl_rule->acl_table_name); - } - auto& mirror_session = acl_rule->action_mirror_sessions[attr_name]; - mirror_session.name = attr_value; - mirror_session.key = key; - mirror_session.oid = mirror_session_oid; - value->aclaction.parameter.objlist.list = &mirror_session.oid; - value->aclaction.parameter.objlist.count = 1; - break; + sai_object_id_t mirror_session_oid; + std::string key = KeyGenerator::generateMirrorSessionKey(attr_value); + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_MIRROR_SESSION, key, &mirror_session_oid)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Mirror session " << QuotedVar(attr_value) << " does not exist for " + << QuotedVar(acl_rule->acl_table_name); + } + auto &mirror_session = acl_rule->action_mirror_sessions[attr_name]; + mirror_session.name = attr_value; + mirror_session.key = key; + mirror_session.oid = mirror_session_oid; + value->aclaction.parameter.objlist.list = &mirror_session.oid; + value->aclaction.parameter.objlist.count = 1; + break; } case SAI_ACL_ENTRY_ATTR_ACTION_SET_PACKET_COLOR: { - const auto& it = aclPacketColorLookup.find(attr_value); - if (it == aclPacketColorLookup.end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid ACL packet color " << QuotedVar(attr_value) - << " in action for " << QuotedVar(acl_rule->acl_table_name); - } - value->aclaction.parameter.s32 = it->second; - break; + const auto &it = aclPacketColorLookup.find(attr_value); + if (it == aclPacketColorLookup.end()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid ACL packet color " << QuotedVar(attr_value) << " in action for " + << QuotedVar(acl_rule->acl_table_name); + } + value->aclaction.parameter.s32 = it->second; + break; } case SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_MAC: case SAI_ACL_ENTRY_ATTR_ACTION_SET_DST_MAC: { - try { - swss::MacAddress mac(attr_value); - memcpy(value->aclaction.parameter.mac, mac.getMac(), sizeof(sai_mac_t)); - } catch (std::exception& e) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Action attribute " << QuotedVar(std::to_string(attr_name)) - << " is invalid for " << QuotedVar(acl_rule->acl_table_name) - << ": Expect MAC address but got " << QuotedVar(attr_value); - } - break; + try + { + swss::MacAddress mac(attr_value); + memcpy(value->aclaction.parameter.mac, mac.getMac(), sizeof(sai_mac_t)); + } + catch (std::exception &e) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Action attribute " << QuotedVar(std::to_string(attr_name)) << " is invalid for " + << QuotedVar(acl_rule->acl_table_name) << ": Expect MAC address but got " << QuotedVar(attr_value); + } + break; } case SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_IP: case SAI_ACL_ENTRY_ATTR_ACTION_SET_DST_IP: { - try { - swss::IpAddress ip(attr_value); - if (!ip.isV4()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Action attribute " << QuotedVar(std::to_string(attr_name)) - << " is invalid for " << QuotedVar(acl_rule->acl_table_name) - << ": Expect IPv4 address but got " << QuotedVar(attr_value); - } - value->aclaction.parameter.ip4 = ip.getV4Addr(); - } catch (std::exception& e) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Action attribute " << QuotedVar(std::to_string(attr_name)) - << " is invalid for " << QuotedVar(acl_rule->acl_table_name) - << ": Expect IP address but got " << QuotedVar(attr_value); - } - break; + try + { + swss::IpAddress ip(attr_value); + if (!ip.isV4()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Action attribute " << QuotedVar(std::to_string(attr_name)) << " is invalid for " + << QuotedVar(acl_rule->acl_table_name) << ": Expect IPv4 address but got " + << QuotedVar(attr_value); + } + value->aclaction.parameter.ip4 = ip.getV4Addr(); + } + catch (std::exception &e) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Action attribute " << QuotedVar(std::to_string(attr_name)) << " is invalid for " + << QuotedVar(acl_rule->acl_table_name) << ": Expect IP address but got " << QuotedVar(attr_value); + } + break; } case SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_IPV6: case SAI_ACL_ENTRY_ATTR_ACTION_SET_DST_IPV6: { - try { - swss::IpAddress ip(attr_value); - if (ip.isV4()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Action attribute " << QuotedVar(std::to_string(attr_name)) - << " is invalid for " << QuotedVar(acl_rule->acl_table_name) - << ": Expect IPv6 address but got " << QuotedVar(attr_value); - } - memcpy(value->aclaction.parameter.ip6, ip.getV6Addr(), - sizeof(sai_ip6_t)); - } catch (std::exception& e) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Action attribute " << QuotedVar(std::to_string(attr_name)) - << " is invalid for " << QuotedVar(acl_rule->acl_table_name) - << ": Expect IP address but got " << QuotedVar(attr_value); - } - break; + try + { + swss::IpAddress ip(attr_value); + if (ip.isV4()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Action attribute " << QuotedVar(std::to_string(attr_name)) << " is invalid for " + << QuotedVar(acl_rule->acl_table_name) << ": Expect IPv6 address but got " + << QuotedVar(attr_value); + } + memcpy(value->aclaction.parameter.ip6, ip.getV6Addr(), sizeof(sai_ip6_t)); + } + catch (std::exception &e) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Action attribute " << QuotedVar(std::to_string(attr_name)) << " is invalid for " + << QuotedVar(acl_rule->acl_table_name) << ": Expect IP address but got " << QuotedVar(attr_value); + } + break; } case SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID: { - try { - uint32_t queue_num = to_uint(attr_value); - if (queue_num < 1 || queue_num > m_userDefinedTraps.size()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid CPU queue number " << QuotedVar(attr_value) - << " for " << QuotedVar(acl_rule->acl_table_name) - << ". Queue number should >= 1 and <= " - << m_userDefinedTraps.size(); - } - value->aclaction.parameter.oid = - m_userDefinedTraps[queue_num - 1].user_defined_trap; - acl_rule->action_qos_queue_num = queue_num; - } catch (std::exception& e) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Action attribute " << QuotedVar(std::to_string(attr_name)) - << " is invalid for " << QuotedVar(acl_rule->acl_table_name) - << ": Expect integer but got " << QuotedVar(attr_value); - } - break; + try + { + uint32_t queue_num = to_uint(attr_value); + if (queue_num < 1 || queue_num > m_userDefinedTraps.size()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid CPU queue number " << QuotedVar(attr_value) << " for " + << QuotedVar(acl_rule->acl_table_name) + << ". Queue number should >= 1 and <= " << m_userDefinedTraps.size(); + } + value->aclaction.parameter.oid = m_userDefinedTraps[queue_num - 1].user_defined_trap; + acl_rule->action_qos_queue_num = queue_num; + } + catch (std::exception &e) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Action attribute " << QuotedVar(std::to_string(attr_name)) << " is invalid for " + << QuotedVar(acl_rule->acl_table_name) << ": Expect integer but got " << QuotedVar(attr_value); + } + break; } case SAI_ACL_ENTRY_ATTR_ACTION_SET_TC: case SAI_ACL_ENTRY_ATTR_ACTION_SET_DSCP: case SAI_ACL_ENTRY_ATTR_ACTION_SET_ECN: case SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_PRI: case SAI_ACL_ENTRY_ATTR_ACTION_SET_OUTER_VLAN_PRI: { - try { - value->aclaction.parameter.u8 = to_uint(attr_value); - } catch (std::exception& e) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Action attribute " << QuotedVar(std::to_string(attr_name)) - << " is invalid for " << QuotedVar(acl_rule->acl_table_name) - << ": Expect integer but got " << QuotedVar(attr_value); - } - break; + try + { + value->aclaction.parameter.u8 = to_uint(attr_value); + } + catch (std::exception &e) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Action attribute " << QuotedVar(std::to_string(attr_name)) << " is invalid for " + << QuotedVar(acl_rule->acl_table_name) << ": Expect integer but got " << QuotedVar(attr_value); + } + break; } case SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_ID: { - try { - value->aclaction.parameter.u32 = to_uint(attr_value); - } catch (std::exception& e) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Action attribute " << QuotedVar(std::to_string(attr_name)) - << " is invalid for " << QuotedVar(acl_rule->acl_table_name) - << ": Expect integer but got " << QuotedVar(attr_value); - } - break; + try + { + value->aclaction.parameter.u32 = to_uint(attr_value); + } + catch (std::exception &e) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Action attribute " << QuotedVar(std::to_string(attr_name)) << " is invalid for " + << QuotedVar(acl_rule->acl_table_name) << ": Expect integer but got " << QuotedVar(attr_value); + } + break; } case SAI_ACL_ENTRY_ATTR_ACTION_SET_OUTER_VLAN_ID: case SAI_ACL_ENTRY_ATTR_ACTION_SET_L4_SRC_PORT: case SAI_ACL_ENTRY_ATTR_ACTION_SET_L4_DST_PORT: { - try { - value->aclaction.parameter.u16 = to_uint(attr_value); - } catch (std::exception& e) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Action attribute " << QuotedVar(std::to_string(attr_name)) - << " is invalid for " << QuotedVar(acl_rule->acl_table_name) - << ": Expect integer but got " << QuotedVar(attr_value); - } - break; + try + { + value->aclaction.parameter.u16 = to_uint(attr_value); + } + catch (std::exception &e) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Action attribute " << QuotedVar(std::to_string(attr_name)) << " is invalid for " + << QuotedVar(acl_rule->acl_table_name) << ": Expect integer but got " << QuotedVar(attr_value); + } + break; } case SAI_ACL_ENTRY_ATTR_ACTION_FLOOD: case SAI_ACL_ENTRY_ATTR_ACTION_DECREMENT_TTL: case SAI_ACL_ENTRY_ATTR_ACTION_SET_DO_NOT_LEARN: { - // parameter is not needed - break; + // parameter is not needed + break; } case SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF: { - if (!attr_value.empty() && !m_vrfOrch->isVRFexists(attr_value)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "No VRF found with name " << QuotedVar(attr_value) << " for " - << QuotedVar(acl_rule->acl_table_name); - } - value->aclaction.parameter.oid = m_vrfOrch->getVRFid(attr_value); - break; + if (!attr_value.empty() && !m_vrfOrch->isVRFexists(attr_value)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) << "No VRF found with name " << QuotedVar(attr_value) + << " for " << QuotedVar(acl_rule->acl_table_name); + } + value->aclaction.parameter.oid = m_vrfOrch->getVRFid(attr_value); + break; } default: { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid ACL action " << attr_name << " for " - << QuotedVar(acl_rule->acl_table_name); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid ACL action " << attr_name << " for " << QuotedVar(acl_rule->acl_table_name); } - } - value->aclaction.enable = true; - return ReturnCode(); + } + value->aclaction.enable = true; + return ReturnCode(); } -ReturnCode AclRuleManager::setMeterValue( - const P4AclTableDefinition* acl_table, - const P4AclRuleAppDbEntry& app_db_entry, P4AclMeter& acl_meter) { - if (app_db_entry.meter.enabled) { - acl_meter.cir = app_db_entry.meter.cir; - acl_meter.cburst = app_db_entry.meter.cburst; - acl_meter.pir = app_db_entry.meter.pir; - acl_meter.pburst = app_db_entry.meter.pburst; - acl_meter.mode = SAI_POLICER_MODE_TR_TCM; - if (acl_table->meter_unit == P4_METER_UNIT_PACKETS) { - acl_meter.type = SAI_METER_TYPE_PACKETS; - } else if (acl_table->meter_unit == P4_METER_UNIT_BYTES) { - acl_meter.type = SAI_METER_TYPE_BYTES; - } else { - ReturnCode status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid ACL meter type " - << QuotedVar(acl_table->meter_unit); - return status; - } - acl_meter.enabled = true; - } - const auto& action_color_it = - acl_table->rule_packet_action_color_lookup.find(app_db_entry.action); - if (action_color_it != acl_table->rule_packet_action_color_lookup.end() && - !action_color_it->second.empty()) { - acl_meter.packet_color_actions = action_color_it->second; - } - - // SAI_POLICER_MODE_TR_TCM mode is used by default. - // Meter rate limit config is not present for the ACL rule - // Mark the packet as GREEN by setting rate limit to max. - if (!acl_meter.packet_color_actions.empty() && !acl_meter.enabled) { - acl_meter.enabled = true; - acl_meter.type = SAI_METER_TYPE_PACKETS; - acl_meter.cburst = 0x7fffffff; - acl_meter.cir = 0x7fffffff; - acl_meter.pir = 0x7fffffff; - acl_meter.pburst = 0x7fffffff; - } - - return ReturnCode(); +ReturnCode AclRuleManager::setMeterValue(const P4AclTableDefinition *acl_table, const P4AclRuleAppDbEntry &app_db_entry, + P4AclMeter &acl_meter) +{ + if (app_db_entry.meter.enabled) + { + acl_meter.cir = app_db_entry.meter.cir; + acl_meter.cburst = app_db_entry.meter.cburst; + acl_meter.pir = app_db_entry.meter.pir; + acl_meter.pburst = app_db_entry.meter.pburst; + acl_meter.mode = SAI_POLICER_MODE_TR_TCM; + if (acl_table->meter_unit == P4_METER_UNIT_PACKETS) + { + acl_meter.type = SAI_METER_TYPE_PACKETS; + } + else if (acl_table->meter_unit == P4_METER_UNIT_BYTES) + { + acl_meter.type = SAI_METER_TYPE_BYTES; + } + else + { + ReturnCode status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid ACL meter type " << QuotedVar(acl_table->meter_unit); + return status; + } + acl_meter.enabled = true; + } + const auto &action_color_it = acl_table->rule_packet_action_color_lookup.find(app_db_entry.action); + if (action_color_it != acl_table->rule_packet_action_color_lookup.end() && !action_color_it->second.empty()) + { + acl_meter.packet_color_actions = action_color_it->second; + } + + // SAI_POLICER_MODE_TR_TCM mode is used by default. + // Meter rate limit config is not present for the ACL rule + // Mark the packet as GREEN by setting rate limit to max. + if (!acl_meter.packet_color_actions.empty() && !acl_meter.enabled) + { + acl_meter.enabled = true; + acl_meter.type = SAI_METER_TYPE_PACKETS; + acl_meter.cburst = 0x7fffffff; + acl_meter.cir = 0x7fffffff; + acl_meter.pir = 0x7fffffff; + acl_meter.pburst = 0x7fffffff; + } + + return ReturnCode(); } -ReturnCode AclRuleManager::createAclRule(P4AclRule& acl_rule) { - SWSS_LOG_ENTER(); - - // Track if the entry creats a new counter or meter - bool created_meter = false; - bool created_counter = false; - const auto& table_name_and_rule_key = - concatTableNameAndRuleKey(acl_rule.acl_table_name, acl_rule.acl_rule_key); - - // Add meter - if (acl_rule.meter.enabled) { - if (acl_rule.meter.meter_oid == SAI_NULL_OBJECT_ID) { - auto status = createAclMeter(acl_rule.meter, table_name_and_rule_key, - &acl_rule.meter.meter_oid); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to create ACL meter for rule %s", - QuotedVar(acl_rule.acl_rule_key).c_str()); - return status; - } - created_meter = true; - } - } - - // Add counter - if (acl_rule.counter.packets_enabled || acl_rule.counter.bytes_enabled) { - if (acl_rule.counter.counter_oid == SAI_NULL_OBJECT_ID) { - auto status = - createAclCounter(acl_rule.acl_table_name, table_name_and_rule_key, - acl_rule, &acl_rule.counter.counter_oid); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to create ACL counter for rule %s", - QuotedVar(acl_rule.acl_rule_key).c_str()); - if (created_meter) { - auto rc = removeAclMeter(table_name_and_rule_key); - if (!rc.ok()) { - SWSS_RAISE_CRITICAL_STATE( - "Failed to remove ACL meter in recovery."); - } +ReturnCode AclRuleManager::createAclRule(P4AclRule &acl_rule) +{ + SWSS_LOG_ENTER(); + + // Track if the entry creats a new counter or meter + bool created_meter = false; + bool created_counter = false; + const auto &table_name_and_rule_key = concatTableNameAndRuleKey(acl_rule.acl_table_name, acl_rule.acl_rule_key); + + // Add meter + if (acl_rule.meter.enabled) + { + if (acl_rule.meter.meter_oid == SAI_NULL_OBJECT_ID) + { + auto status = createAclMeter(acl_rule.meter, table_name_and_rule_key, &acl_rule.meter.meter_oid); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to create ACL meter for rule %s", QuotedVar(acl_rule.acl_rule_key).c_str()); + return status; + } + created_meter = true; + } + } + + // Add counter + if (acl_rule.counter.packets_enabled || acl_rule.counter.bytes_enabled) + { + if (acl_rule.counter.counter_oid == SAI_NULL_OBJECT_ID) + { + auto status = createAclCounter(acl_rule.acl_table_name, table_name_and_rule_key, acl_rule, + &acl_rule.counter.counter_oid); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to create ACL counter for rule %s", QuotedVar(acl_rule.acl_rule_key).c_str()); + if (created_meter) + { + auto rc = removeAclMeter(table_name_and_rule_key); + if (!rc.ok()) + { + SWSS_RAISE_CRITICAL_STATE("Failed to remove ACL meter in recovery."); + } + } + return status; + } + created_counter = true; + } + } + + auto attrs = getRuleSaiAttrs(acl_rule); + + auto sai_status = + sai_acl_api->create_acl_entry(&acl_rule.acl_entry_oid, gSwitchId, (uint32_t)attrs.size(), attrs.data()); + if (sai_status != SAI_STATUS_SUCCESS) + { + ReturnCode status = ReturnCode(sai_status) + << "Failed to create ACL entry in table " << QuotedVar(acl_rule.acl_table_name); + SWSS_LOG_ERROR("%s SAI_STATUS: %s", status.message().c_str(), sai_serialize_status(sai_status).c_str()); + if (created_meter) + { + auto rc = removeAclMeter(table_name_and_rule_key); + if (!rc.ok()) + { + SWSS_RAISE_CRITICAL_STATE("Failed to remove ACL meter in recovery."); + } + } + if (created_counter) + { + auto rc = removeAclCounter(acl_rule.acl_table_name, table_name_and_rule_key); + if (!rc.ok()) + { + SWSS_RAISE_CRITICAL_STATE("Failed to remove ACL counter in recovery."); + } } return status; - } - created_counter = true; - } - } - - auto attrs = getRuleSaiAttrs(acl_rule); - - auto sai_status = sai_acl_api->create_acl_entry( - &acl_rule.acl_entry_oid, gSwitchId, (uint32_t)attrs.size(), attrs.data()); - if (sai_status != SAI_STATUS_SUCCESS) { - ReturnCode status = ReturnCode(sai_status) - << "Failed to create ACL entry in table " - << QuotedVar(acl_rule.acl_table_name); - SWSS_LOG_ERROR("%s SAI_STATUS: %s", status.message().c_str(), - sai_serialize_status(sai_status).c_str()); - if (created_meter) { - auto rc = removeAclMeter(table_name_and_rule_key); - if (!rc.ok()) { - SWSS_RAISE_CRITICAL_STATE("Failed to remove ACL meter in recovery."); - } - } - if (created_counter) { - auto rc = - removeAclCounter(acl_rule.acl_table_name, table_name_and_rule_key); - if (!rc.ok()) { - SWSS_RAISE_CRITICAL_STATE("Failed to remove ACL counter in recovery."); - } } - return status; - } - return ReturnCode(); + return ReturnCode(); } -ReturnCode AclRuleManager::updateAclRule( - const P4AclRule& acl_rule, const P4AclRule& old_acl_rule, - std::vector& acl_entry_attrs, - std::vector& rollback_attrs) { - SWSS_LOG_ENTER(); - - sai_attribute_t acl_entry_attr; - std::set actions_to_reset; - for (const auto& old_action_fv : old_acl_rule.action_fvs) { - actions_to_reset.insert(fvField(old_action_fv)); - } - - for (const auto& action_fv : acl_rule.action_fvs) { - const auto& it = old_acl_rule.action_fvs.find(fvField(action_fv)); - if (it == old_acl_rule.action_fvs.end()) { - acl_entry_attr.id = fvField(action_fv); - acl_entry_attr.value = fvValue(action_fv); - acl_entry_attr.value.aclaction.enable = true; - acl_entry_attrs.push_back(acl_entry_attr); - acl_entry_attr.value.aclaction.enable = false; - rollback_attrs.push_back(acl_entry_attr); - } else if (isDiffActionFieldValue(fvField(action_fv), fvValue(action_fv), - it->second, acl_rule, old_acl_rule)) { - acl_entry_attr.id = fvField(action_fv); - acl_entry_attr.value = fvValue(action_fv); - acl_entry_attr.value.aclaction.enable = true; - acl_entry_attrs.push_back(acl_entry_attr); - acl_entry_attr.value = it->second; - rollback_attrs.push_back(acl_entry_attr); - } - if (it != old_acl_rule.action_fvs.end()) { - actions_to_reset.erase(fvField(action_fv)); - } - } - - for (const auto& action : actions_to_reset) { - acl_entry_attr.id = action; - acl_entry_attr.value = old_acl_rule.action_fvs.at(action); - acl_entry_attr.value.aclaction.enable = false; - acl_entry_attrs.push_back(acl_entry_attr); - acl_entry_attr.value.aclaction.enable = true; - rollback_attrs.push_back(acl_entry_attr); - } - - ReturnCode status; - int i; - for (i = 0; i < static_cast(acl_entry_attrs.size()); ++i) { - status = ReturnCode(sai_acl_api->set_acl_entry_attribute( - old_acl_rule.acl_entry_oid, &acl_entry_attrs[i])); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to update ACL rule attributes: %s", - status.message().c_str()); - break; - } - } - if (!status.ok()) { - for (--i; i >= 0; --i) { - auto sai_status = sai_acl_api->set_acl_entry_attribute( - old_acl_rule.acl_entry_oid, &rollback_attrs[i]); - if (sai_status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to set ACL rule attribute. SAI_STATUS: %s", - sai_serialize_status(sai_status).c_str()); - SWSS_RAISE_CRITICAL_STATE( - "Failed to set ACL rule attribute in recovery."); - } +ReturnCode AclRuleManager::updateAclRule(const P4AclRule &acl_rule, const P4AclRule &old_acl_rule, + std::vector &acl_entry_attrs, + std::vector &rollback_attrs) +{ + SWSS_LOG_ENTER(); + + sai_attribute_t acl_entry_attr; + std::set actions_to_reset; + for (const auto &old_action_fv : old_acl_rule.action_fvs) + { + actions_to_reset.insert(fvField(old_action_fv)); + } + + for (const auto &action_fv : acl_rule.action_fvs) + { + const auto &it = old_acl_rule.action_fvs.find(fvField(action_fv)); + if (it == old_acl_rule.action_fvs.end()) + { + acl_entry_attr.id = fvField(action_fv); + acl_entry_attr.value = fvValue(action_fv); + acl_entry_attr.value.aclaction.enable = true; + acl_entry_attrs.push_back(acl_entry_attr); + acl_entry_attr.value.aclaction.enable = false; + rollback_attrs.push_back(acl_entry_attr); + } + else if (isDiffActionFieldValue(fvField(action_fv), fvValue(action_fv), it->second, acl_rule, old_acl_rule)) + { + acl_entry_attr.id = fvField(action_fv); + acl_entry_attr.value = fvValue(action_fv); + acl_entry_attr.value.aclaction.enable = true; + acl_entry_attrs.push_back(acl_entry_attr); + acl_entry_attr.value = it->second; + rollback_attrs.push_back(acl_entry_attr); + } + if (it != old_acl_rule.action_fvs.end()) + { + actions_to_reset.erase(fvField(action_fv)); + } } - return status; - } - - // Clear old ACL rule dependent refcount and update refcount in new rule - if (!old_acl_rule.action_redirect_nexthop_key.empty()) { - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - old_acl_rule.action_redirect_nexthop_key); - } - if (!acl_rule.action_redirect_nexthop_key.empty()) { - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - acl_rule.action_redirect_nexthop_key); - } - for (const auto& mirror_session : old_acl_rule.action_mirror_sessions) { - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_MIRROR_SESSION, - fvValue(mirror_session).key); - } - for (const auto& mirror_session : acl_rule.action_mirror_sessions) { - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_MIRROR_SESSION, - fvValue(mirror_session).key); - } - auto old_set_vrf_action_it = - old_acl_rule.action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF); - if (old_set_vrf_action_it != old_acl_rule.action_fvs.end()) { - m_vrfOrch->decreaseVrfRefCount( - old_set_vrf_action_it->second.aclaction.parameter.oid); - } - auto set_vrf_action_it = - acl_rule.action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF); - if (set_vrf_action_it != acl_rule.action_fvs.end()) { - m_vrfOrch->increaseVrfRefCount( - set_vrf_action_it->second.aclaction.parameter.oid); - } - auto set_user_trap_it = - acl_rule.action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID); - if (set_user_trap_it != acl_rule.action_fvs.end()) { - m_p4OidMapper->increaseRefCount( - SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP, - std::to_string(acl_rule.action_qos_queue_num)); - } - auto old_set_user_trap_it = - old_acl_rule.action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID); - if (old_set_user_trap_it != old_acl_rule.action_fvs.end()) { - m_p4OidMapper->decreaseRefCount( - SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP, - std::to_string(old_acl_rule.action_qos_queue_num)); - } - return ReturnCode(); + + for (const auto &action : actions_to_reset) + { + acl_entry_attr.id = action; + acl_entry_attr.value = old_acl_rule.action_fvs.at(action); + acl_entry_attr.value.aclaction.enable = false; + acl_entry_attrs.push_back(acl_entry_attr); + acl_entry_attr.value.aclaction.enable = true; + rollback_attrs.push_back(acl_entry_attr); + } + + ReturnCode status; + int i; + for (i = 0; i < static_cast(acl_entry_attrs.size()); ++i) + { + status = ReturnCode(sai_acl_api->set_acl_entry_attribute(old_acl_rule.acl_entry_oid, &acl_entry_attrs[i])); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to update ACL rule attributes: %s", status.message().c_str()); + break; + } + } + if (!status.ok()) + { + for (--i; i >= 0; --i) + { + auto sai_status = sai_acl_api->set_acl_entry_attribute(old_acl_rule.acl_entry_oid, &rollback_attrs[i]); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set ACL rule attribute. SAI_STATUS: %s", + sai_serialize_status(sai_status).c_str()); + SWSS_RAISE_CRITICAL_STATE("Failed to set ACL rule attribute in recovery."); + } + } + return status; + } + + // Clear old ACL rule dependent refcount and update refcount in new rule + if (!old_acl_rule.action_redirect_nexthop_key.empty()) + { + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, old_acl_rule.action_redirect_nexthop_key); + } + if (!acl_rule.action_redirect_nexthop_key.empty()) + { + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, acl_rule.action_redirect_nexthop_key); + } + for (const auto &mirror_session : old_acl_rule.action_mirror_sessions) + { + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_MIRROR_SESSION, fvValue(mirror_session).key); + } + for (const auto &mirror_session : acl_rule.action_mirror_sessions) + { + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_MIRROR_SESSION, fvValue(mirror_session).key); + } + auto old_set_vrf_action_it = old_acl_rule.action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF); + if (old_set_vrf_action_it != old_acl_rule.action_fvs.end()) + { + m_vrfOrch->decreaseVrfRefCount(old_set_vrf_action_it->second.aclaction.parameter.oid); + } + auto set_vrf_action_it = acl_rule.action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF); + if (set_vrf_action_it != acl_rule.action_fvs.end()) + { + m_vrfOrch->increaseVrfRefCount(set_vrf_action_it->second.aclaction.parameter.oid); + } + auto set_user_trap_it = acl_rule.action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID); + if (set_user_trap_it != acl_rule.action_fvs.end()) + { + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP, + std::to_string(acl_rule.action_qos_queue_num)); + } + auto old_set_user_trap_it = old_acl_rule.action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID); + if (old_set_user_trap_it != old_acl_rule.action_fvs.end()) + { + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP, + std::to_string(old_acl_rule.action_qos_queue_num)); + } + return ReturnCode(); } -ReturnCode AclRuleManager::removeAclRule(const std::string& acl_table_name, - const std::string& acl_rule_key) { - auto* acl_rule = getAclRule(acl_table_name, acl_rule_key); - if (acl_rule == nullptr) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "ACL rule with key " << QuotedVar(acl_rule_key) - << " in table " << QuotedVar(acl_table_name) - << " does not exist"); - } - const auto& table_name_and_rule_key = - concatTableNameAndRuleKey(acl_table_name, acl_rule_key); - // Check if there is anything referring to the next hop before deletion. - uint32_t ref_count; - if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_ACL_ENTRY, - table_name_and_rule_key, &ref_count)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Failed to get reference count for ACL rule " - << QuotedVar(table_name_and_rule_key)); - } - if (ref_count > 0) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL rule " << QuotedVar(acl_rule_key) - << " referenced by other objects (ref_count = " - << ref_count << ")"); - } - - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_acl_api->remove_acl_entry(acl_rule->acl_entry_oid), - "Failed to remove ACL rule with key " - << sai_serialize_object_id(acl_rule->acl_entry_oid) << " in table " - << QuotedVar(acl_table_name)); - bool deleted_meter = false; - if (acl_rule->meter.enabled) { - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key); - auto status = removeAclMeter(table_name_and_rule_key); - if (!status.ok()) { - SWSS_LOG_ERROR( - "Failed to remove ACL meter for rule with key %s in table %s.", - QuotedVar(acl_rule_key).c_str(), QuotedVar(acl_table_name).c_str()); - auto rc = createAclRule(*acl_rule); - if (!rc.ok()) { - SWSS_RAISE_CRITICAL_STATE("Failed to create ACL rule in recovery."); - } - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key); - return status; - } - acl_rule->meter.meter_oid = SAI_NULL_OBJECT_ID; - deleted_meter = true; - } - if (acl_rule->counter.packets_enabled || acl_rule->counter.bytes_enabled) { - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_ACL_COUNTER, - table_name_and_rule_key); - auto status = removeAclCounter(acl_table_name, table_name_and_rule_key); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to remove ACL counter for rule with key %s.", - QuotedVar(table_name_and_rule_key).c_str()); - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_ACL_COUNTER, - table_name_and_rule_key); - if (deleted_meter) { - auto rc = createAclMeter(acl_rule->meter, table_name_and_rule_key, - &acl_rule->meter.meter_oid); - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key); - if (!rc.ok()) { - SWSS_RAISE_CRITICAL_STATE("Failed to create ACL rule in recovery."); - return status; - } - } - auto rc = createAclRule(*acl_rule); - if (!rc.ok()) { - SWSS_RAISE_CRITICAL_STATE("Failed to create ACL rule in recovery."); - } - return status; - } - // Remove counter stats - m_countersTable->del(acl_rule->db_key); - } - gCrmOrch->decCrmAclTableUsedCounter(CrmResourceType::CRM_ACL_ENTRY, - acl_rule->acl_table_oid); - if (!acl_rule->action_redirect_nexthop_key.empty()) { - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - acl_rule->action_redirect_nexthop_key); - } - for (const auto& mirror_session : acl_rule->action_mirror_sessions) { - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_MIRROR_SESSION, - fvValue(mirror_session).key); - } - auto set_vrf_action_it = - acl_rule->action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF); - if (set_vrf_action_it != acl_rule->action_fvs.end()) { - m_vrfOrch->decreaseVrfRefCount( - set_vrf_action_it->second.aclaction.parameter.oid); - } - auto set_user_trap_it = - acl_rule->action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID); - if (set_user_trap_it != acl_rule->action_fvs.end()) { - m_p4OidMapper->decreaseRefCount( - SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP, - std::to_string(acl_rule->action_qos_queue_num)); - } - for (const auto& port_alias : acl_rule->in_ports) { - gPortsOrch->decreasePortRefCount(port_alias); - } - for (const auto& port_alias : acl_rule->out_ports) { - gPortsOrch->decreasePortRefCount(port_alias); - } - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_ACL_TABLE, acl_table_name); - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_ACL_ENTRY, table_name_and_rule_key); - m_aclRuleTables[acl_table_name].erase(acl_rule_key); - return ReturnCode(); +ReturnCode AclRuleManager::removeAclRule(const std::string &acl_table_name, const std::string &acl_rule_key) +{ + auto *acl_rule = getAclRule(acl_table_name, acl_rule_key); + if (acl_rule == nullptr) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "ACL rule with key " << QuotedVar(acl_rule_key) << " in table " + << QuotedVar(acl_table_name) << " does not exist"); + } + const auto &table_name_and_rule_key = concatTableNameAndRuleKey(acl_table_name, acl_rule_key); + // Check if there is anything referring to the next hop before deletion. + uint32_t ref_count; + if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_ACL_ENTRY, table_name_and_rule_key, &ref_count)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Failed to get reference count for ACL rule " + << QuotedVar(table_name_and_rule_key)); + } + if (ref_count > 0) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL rule " << QuotedVar(acl_rule_key) + << " referenced by other objects (ref_count = " << ref_count << ")"); + } + + CHECK_ERROR_AND_LOG_AND_RETURN(sai_acl_api->remove_acl_entry(acl_rule->acl_entry_oid), + "Failed to remove ACL rule with key " + << sai_serialize_object_id(acl_rule->acl_entry_oid) << " in table " + << QuotedVar(acl_table_name)); + bool deleted_meter = false; + if (acl_rule->meter.enabled) + { + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key); + auto status = removeAclMeter(table_name_and_rule_key); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to remove ACL meter for rule with key %s in table %s.", + QuotedVar(acl_rule_key).c_str(), QuotedVar(acl_table_name).c_str()); + auto rc = createAclRule(*acl_rule); + if (!rc.ok()) + { + SWSS_RAISE_CRITICAL_STATE("Failed to create ACL rule in recovery."); + } + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key); + return status; + } + acl_rule->meter.meter_oid = SAI_NULL_OBJECT_ID; + deleted_meter = true; + } + if (acl_rule->counter.packets_enabled || acl_rule->counter.bytes_enabled) + { + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_ACL_COUNTER, table_name_and_rule_key); + auto status = removeAclCounter(acl_table_name, table_name_and_rule_key); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to remove ACL counter for rule with key %s.", + QuotedVar(table_name_and_rule_key).c_str()); + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_ACL_COUNTER, table_name_and_rule_key); + if (deleted_meter) + { + auto rc = createAclMeter(acl_rule->meter, table_name_and_rule_key, &acl_rule->meter.meter_oid); + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key); + if (!rc.ok()) + { + SWSS_RAISE_CRITICAL_STATE("Failed to create ACL rule in recovery."); + return status; + } + } + auto rc = createAclRule(*acl_rule); + if (!rc.ok()) + { + SWSS_RAISE_CRITICAL_STATE("Failed to create ACL rule in recovery."); + } + return status; + } + // Remove counter stats + m_countersTable->del(acl_rule->db_key); + } + gCrmOrch->decCrmAclTableUsedCounter(CrmResourceType::CRM_ACL_ENTRY, acl_rule->acl_table_oid); + if (!acl_rule->action_redirect_nexthop_key.empty()) + { + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, acl_rule->action_redirect_nexthop_key); + } + for (const auto &mirror_session : acl_rule->action_mirror_sessions) + { + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_MIRROR_SESSION, fvValue(mirror_session).key); + } + auto set_vrf_action_it = acl_rule->action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF); + if (set_vrf_action_it != acl_rule->action_fvs.end()) + { + m_vrfOrch->decreaseVrfRefCount(set_vrf_action_it->second.aclaction.parameter.oid); + } + auto set_user_trap_it = acl_rule->action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID); + if (set_user_trap_it != acl_rule->action_fvs.end()) + { + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP, + std::to_string(acl_rule->action_qos_queue_num)); + } + for (const auto &port_alias : acl_rule->in_ports) + { + gPortsOrch->decreasePortRefCount(port_alias); + } + for (const auto &port_alias : acl_rule->out_ports) + { + gPortsOrch->decreasePortRefCount(port_alias); + } + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_ACL_TABLE, acl_table_name); + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_ACL_ENTRY, table_name_and_rule_key); + m_aclRuleTables[acl_table_name].erase(acl_rule_key); + return ReturnCode(); } -ReturnCode AclRuleManager::processAddRuleRequest( - const std::string& acl_rule_key, const P4AclRuleAppDbEntry& app_db_entry) { - P4AclRule acl_rule{}; - acl_rule.priority = app_db_entry.priority; - acl_rule.acl_rule_key = acl_rule_key; - acl_rule.p4_action = app_db_entry.action; - acl_rule.db_key = app_db_entry.db_key; - const auto* acl_table = - gP4Orch->getAclTableManager()->getAclTable(app_db_entry.acl_table_name); - acl_rule.acl_table_oid = acl_table->table_oid; - acl_rule.acl_table_name = acl_table->acl_table_name; - - // Add match field values - LOG_AND_RETURN_IF_ERROR( - setAllMatchFieldValues(app_db_entry, acl_table, acl_rule)); - - // Add action field values - auto status = setAllActionFieldValues(app_db_entry, acl_table, acl_rule); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to add action field values for ACL rule %s: %s", - QuotedVar(acl_rule.acl_rule_key).c_str(), - status.message().c_str()); - return status; - } - - // Add meter - LOG_AND_RETURN_IF_ERROR( - setMeterValue(acl_table, app_db_entry, acl_rule.meter)); - - // Add counter - if (!acl_table->counter_unit.empty()) { - if (acl_table->counter_unit == P4_COUNTER_UNIT_PACKETS) { - acl_rule.counter.packets_enabled = true; - } else if (acl_table->counter_unit == P4_COUNTER_UNIT_BYTES) { - acl_rule.counter.bytes_enabled = true; - } else if (acl_table->counter_unit == P4_COUNTER_UNIT_BOTH) { - acl_rule.counter.bytes_enabled = true; - acl_rule.counter.packets_enabled = true; - } else { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid ACL counter type " - << QuotedVar(acl_table->counter_unit)); - } - } - status = createAclRule(acl_rule); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to create ACL rule with key %s in table %s", - QuotedVar(acl_rule.acl_rule_key).c_str(), - QuotedVar(app_db_entry.acl_table_name).c_str()); +ReturnCode AclRuleManager::processAddRuleRequest(const std::string &acl_rule_key, + const P4AclRuleAppDbEntry &app_db_entry) +{ + P4AclRule acl_rule{}; + acl_rule.priority = app_db_entry.priority; + acl_rule.acl_rule_key = acl_rule_key; + acl_rule.p4_action = app_db_entry.action; + acl_rule.db_key = app_db_entry.db_key; + const auto *acl_table = gP4Orch->getAclTableManager()->getAclTable(app_db_entry.acl_table_name); + acl_rule.acl_table_oid = acl_table->table_oid; + acl_rule.acl_table_name = acl_table->acl_table_name; + + // Add match field values + LOG_AND_RETURN_IF_ERROR(setAllMatchFieldValues(app_db_entry, acl_table, acl_rule)); + + // Add action field values + auto status = setAllActionFieldValues(app_db_entry, acl_table, acl_rule); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to add action field values for ACL rule %s: %s", + QuotedVar(acl_rule.acl_rule_key).c_str(), status.message().c_str()); + return status; + } + + // Add meter + LOG_AND_RETURN_IF_ERROR(setMeterValue(acl_table, app_db_entry, acl_rule.meter)); + + // Add counter + if (!acl_table->counter_unit.empty()) + { + if (acl_table->counter_unit == P4_COUNTER_UNIT_PACKETS) + { + acl_rule.counter.packets_enabled = true; + } + else if (acl_table->counter_unit == P4_COUNTER_UNIT_BYTES) + { + acl_rule.counter.bytes_enabled = true; + } + else if (acl_table->counter_unit == P4_COUNTER_UNIT_BOTH) + { + acl_rule.counter.bytes_enabled = true; + acl_rule.counter.packets_enabled = true; + } + else + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid ACL counter type " << QuotedVar(acl_table->counter_unit)); + } + } + status = createAclRule(acl_rule); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to create ACL rule with key %s in table %s", QuotedVar(acl_rule.acl_rule_key).c_str(), + QuotedVar(app_db_entry.acl_table_name).c_str()); + return status; + } + // ACL entry created in HW, update refcount + if (!acl_rule.action_redirect_nexthop_key.empty()) + { + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, acl_rule.action_redirect_nexthop_key); + } + for (const auto &mirror_session : acl_rule.action_mirror_sessions) + { + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_MIRROR_SESSION, fvValue(mirror_session).key); + } + auto set_vrf_action_it = acl_rule.action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF); + if (set_vrf_action_it != acl_rule.action_fvs.end()) + { + m_vrfOrch->increaseVrfRefCount(set_vrf_action_it->second.aclaction.parameter.oid); + } + auto set_user_trap_it = acl_rule.action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID); + if (set_user_trap_it != acl_rule.action_fvs.end()) + { + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP, + std::to_string(acl_rule.action_qos_queue_num)); + } + for (const auto &port_alias : acl_rule.in_ports) + { + gPortsOrch->increasePortRefCount(port_alias); + } + for (const auto &port_alias : acl_rule.out_ports) + { + gPortsOrch->increasePortRefCount(port_alias); + } + gCrmOrch->incCrmAclTableUsedCounter(CrmResourceType::CRM_ACL_ENTRY, acl_rule.acl_table_oid); + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_ACL_TABLE, acl_rule.acl_table_name); + const auto &table_name_and_rule_key = concatTableNameAndRuleKey(acl_rule.acl_table_name, acl_rule.acl_rule_key); + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_ACL_ENTRY, table_name_and_rule_key, acl_rule.acl_entry_oid); + if (acl_rule.counter.packets_enabled || acl_rule.counter.bytes_enabled) + { + // Counter was created, increase ACL rule ref count + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_ACL_COUNTER, table_name_and_rule_key); + } + if (acl_rule.meter.enabled) + { + // Meter was created, increase ACL rule ref count + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key); + } + m_aclRuleTables[acl_table->acl_table_name][acl_rule_key] = std::move(acl_rule); + SWSS_LOG_NOTICE( + "Suceeded to create ACL rule %s : %s", QuotedVar(acl_rule_key).c_str(), + sai_serialize_object_id(m_aclRuleTables[acl_table->acl_table_name][acl_rule_key].acl_entry_oid).c_str()); return status; - } - // ACL entry created in HW, update refcount - if (!acl_rule.action_redirect_nexthop_key.empty()) { - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - acl_rule.action_redirect_nexthop_key); - } - for (const auto& mirror_session : acl_rule.action_mirror_sessions) { - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_MIRROR_SESSION, - fvValue(mirror_session).key); - } - auto set_vrf_action_it = - acl_rule.action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF); - if (set_vrf_action_it != acl_rule.action_fvs.end()) { - m_vrfOrch->increaseVrfRefCount( - set_vrf_action_it->second.aclaction.parameter.oid); - } - auto set_user_trap_it = - acl_rule.action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID); - if (set_user_trap_it != acl_rule.action_fvs.end()) { - m_p4OidMapper->increaseRefCount( - SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP, - std::to_string(acl_rule.action_qos_queue_num)); - } - for (const auto& port_alias : acl_rule.in_ports) { - gPortsOrch->increasePortRefCount(port_alias); - } - for (const auto& port_alias : acl_rule.out_ports) { - gPortsOrch->increasePortRefCount(port_alias); - } - gCrmOrch->incCrmAclTableUsedCounter(CrmResourceType::CRM_ACL_ENTRY, - acl_rule.acl_table_oid); - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_ACL_TABLE, - acl_rule.acl_table_name); - const auto& table_name_and_rule_key = - concatTableNameAndRuleKey(acl_rule.acl_table_name, acl_rule.acl_rule_key); - m_p4OidMapper->setOID(SAI_OBJECT_TYPE_ACL_ENTRY, table_name_and_rule_key, - acl_rule.acl_entry_oid); - if (acl_rule.counter.packets_enabled || acl_rule.counter.bytes_enabled) { - // Counter was created, increase ACL rule ref count - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_ACL_COUNTER, - table_name_and_rule_key); - } - if (acl_rule.meter.enabled) { - // Meter was created, increase ACL rule ref count - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key); - } - m_aclRuleTables[acl_table->acl_table_name][acl_rule_key] = - std::move(acl_rule); - SWSS_LOG_NOTICE("Suceeded to create ACL rule %s : %s", - QuotedVar(acl_rule_key).c_str(), - sai_serialize_object_id( - m_aclRuleTables[acl_table->acl_table_name][acl_rule_key] - .acl_entry_oid) - .c_str()); - return status; } -ReturnCode AclRuleManager::processDeleteRuleRequest( - const std::string& acl_table_name, const std::string& acl_rule_key) { - SWSS_LOG_ENTER(); - auto status = removeAclRule(acl_table_name, acl_rule_key); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to remove ACL rule with key %s in table %s", - QuotedVar(acl_rule_key).c_str(), - QuotedVar(acl_table_name).c_str()); - } - return status; +ReturnCode AclRuleManager::processDeleteRuleRequest(const std::string &acl_table_name, const std::string &acl_rule_key) +{ + SWSS_LOG_ENTER(); + auto status = removeAclRule(acl_table_name, acl_rule_key); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to remove ACL rule with key %s in table %s", QuotedVar(acl_rule_key).c_str(), + QuotedVar(acl_table_name).c_str()); + } + return status; } -ReturnCode AclRuleManager::processUpdateRuleRequest( - const P4AclRuleAppDbEntry& app_db_entry, const P4AclRule& old_acl_rule) { - SWSS_LOG_ENTER(); - - P4AclRule acl_rule{}; - const auto* acl_table = - gP4Orch->getAclTableManager()->getAclTable(app_db_entry.acl_table_name); - acl_rule.acl_table_oid = acl_table->table_oid; - acl_rule.acl_table_name = acl_table->acl_table_name; - acl_rule.db_key = app_db_entry.db_key; - - // Skip match field comparison because the acl_rule_key including match - // field value and priority should be the same with old one. - acl_rule.priority = app_db_entry.priority; - acl_rule.acl_rule_key = old_acl_rule.acl_rule_key; - // Skip Counter comparison since the counter unit is defined in table - // definition - acl_rule.counter = old_acl_rule.counter; - - std::vector acl_entry_attrs; - std::vector rollback_attrs; - sai_attribute_t acl_entry_attr; - const auto& table_name_and_rule_key = - concatTableNameAndRuleKey(acl_rule.acl_table_name, acl_rule.acl_rule_key); - - // Update action field - acl_rule.p4_action = app_db_entry.action; - acl_rule.acl_entry_oid = old_acl_rule.acl_entry_oid; - auto set_actions_rc = - setAllActionFieldValues(app_db_entry, acl_table, acl_rule); - if (!set_actions_rc.ok()) { - SWSS_LOG_ERROR("Failed to add action field values for ACL rule %s: %s", - QuotedVar(acl_rule.acl_rule_key).c_str(), - set_actions_rc.message().c_str()); - return set_actions_rc; - } - - // Update meter - bool remove_meter = false; - bool created_meter = false; - bool updated_meter = false; - LOG_AND_RETURN_IF_ERROR( - setMeterValue(acl_table, app_db_entry, acl_rule.meter)); - if (old_acl_rule.meter.meter_oid == SAI_NULL_OBJECT_ID && - acl_rule.meter.enabled) { - // Create new meter - auto status = createAclMeter(acl_rule.meter, table_name_and_rule_key, - &acl_rule.meter.meter_oid); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to create ACL meter for rule %s", - QuotedVar(acl_rule.acl_rule_key).c_str()); - return status; - } - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key); - created_meter = true; - acl_entry_attr.id = SAI_ACL_ENTRY_ATTR_ACTION_SET_POLICER; - acl_entry_attr.value.aclaction.enable = true; - acl_entry_attr.value.aclaction.parameter.oid = acl_rule.meter.meter_oid; - acl_entry_attrs.push_back(acl_entry_attr); - acl_entry_attr.value.aclaction.enable = false; - acl_entry_attr.value.aclaction.parameter.oid = SAI_NULL_OBJECT_ID; - rollback_attrs.push_back(acl_entry_attr); - } else if (old_acl_rule.meter.meter_oid != SAI_NULL_OBJECT_ID && - !acl_rule.meter.enabled) { - // Remove old meter - remove_meter = true; - acl_entry_attr.id = SAI_ACL_ENTRY_ATTR_ACTION_SET_POLICER; - acl_entry_attr.value.aclaction.enable = false; - acl_entry_attr.value.aclaction.parameter.oid = SAI_NULL_OBJECT_ID; - acl_entry_attrs.push_back(acl_entry_attr); - acl_entry_attr.value.aclaction.enable = true; - acl_entry_attr.value.aclaction.parameter.oid = old_acl_rule.meter.meter_oid; - rollback_attrs.push_back(acl_entry_attr); - } else if (old_acl_rule.meter.meter_oid != SAI_NULL_OBJECT_ID) { - // Update meter attributes - auto status = updateAclMeter(acl_rule.meter, old_acl_rule.meter); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to update ACL meter for rule %s", - QuotedVar(acl_rule.acl_rule_key).c_str()); - return status; - } - updated_meter = true; - acl_rule.meter.meter_oid = old_acl_rule.meter.meter_oid; - } - - auto status = - updateAclRule(acl_rule, old_acl_rule, acl_entry_attrs, rollback_attrs); - if (status.ok()) { - // Remove old meter. - if (remove_meter) { - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key); - auto rc = removeAclMeter(table_name_and_rule_key); - if (!rc.ok()) { - SWSS_LOG_ERROR("Failed to remove ACL meter for rule %s", - QuotedVar(acl_rule.acl_rule_key).c_str()); - for (const auto& entry_attr : rollback_attrs) { - auto sai_status = sai_acl_api->set_acl_entry_attribute( - old_acl_rule.acl_entry_oid, &entry_attr); - if (sai_status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to set ACL rule attribute. SAI_STATUS: %s", - sai_serialize_status(sai_status).c_str()); - SWSS_RAISE_CRITICAL_STATE( - "Failed to set ACL rule attribute in recovery."); - } - } - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key); - return rc; - } - } - } else { - SWSS_LOG_ERROR("Failed to update ACL rule %s", - QuotedVar(acl_rule.acl_rule_key).c_str()); - // Clean up - if (created_meter) { - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key); - auto rc = removeAclMeter(table_name_and_rule_key); - if (!rc.ok()) { - SWSS_RAISE_CRITICAL_STATE("Failed to remove ACL meter in recovery."); - } - } - if (updated_meter) { - auto rc = updateAclMeter(old_acl_rule.meter, acl_rule.meter); - if (!rc.ok()) { - SWSS_RAISE_CRITICAL_STATE("Failed to update ACL meter in recovery."); - } +ReturnCode AclRuleManager::processUpdateRuleRequest(const P4AclRuleAppDbEntry &app_db_entry, + const P4AclRule &old_acl_rule) +{ + SWSS_LOG_ENTER(); + + P4AclRule acl_rule{}; + const auto *acl_table = gP4Orch->getAclTableManager()->getAclTable(app_db_entry.acl_table_name); + acl_rule.acl_table_oid = acl_table->table_oid; + acl_rule.acl_table_name = acl_table->acl_table_name; + acl_rule.db_key = app_db_entry.db_key; + + // Skip match field comparison because the acl_rule_key including match + // field value and priority should be the same with old one. + acl_rule.priority = app_db_entry.priority; + acl_rule.acl_rule_key = old_acl_rule.acl_rule_key; + // Skip Counter comparison since the counter unit is defined in table + // definition + acl_rule.counter = old_acl_rule.counter; + + std::vector acl_entry_attrs; + std::vector rollback_attrs; + sai_attribute_t acl_entry_attr; + const auto &table_name_and_rule_key = concatTableNameAndRuleKey(acl_rule.acl_table_name, acl_rule.acl_rule_key); + + // Update action field + acl_rule.p4_action = app_db_entry.action; + acl_rule.acl_entry_oid = old_acl_rule.acl_entry_oid; + auto set_actions_rc = setAllActionFieldValues(app_db_entry, acl_table, acl_rule); + if (!set_actions_rc.ok()) + { + SWSS_LOG_ERROR("Failed to add action field values for ACL rule %s: %s", + QuotedVar(acl_rule.acl_rule_key).c_str(), set_actions_rc.message().c_str()); + return set_actions_rc; + } + + // Update meter + bool remove_meter = false; + bool created_meter = false; + bool updated_meter = false; + LOG_AND_RETURN_IF_ERROR(setMeterValue(acl_table, app_db_entry, acl_rule.meter)); + if (old_acl_rule.meter.meter_oid == SAI_NULL_OBJECT_ID && acl_rule.meter.enabled) + { + // Create new meter + auto status = createAclMeter(acl_rule.meter, table_name_and_rule_key, &acl_rule.meter.meter_oid); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to create ACL meter for rule %s", QuotedVar(acl_rule.acl_rule_key).c_str()); + return status; + } + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key); + created_meter = true; + acl_entry_attr.id = SAI_ACL_ENTRY_ATTR_ACTION_SET_POLICER; + acl_entry_attr.value.aclaction.enable = true; + acl_entry_attr.value.aclaction.parameter.oid = acl_rule.meter.meter_oid; + acl_entry_attrs.push_back(acl_entry_attr); + acl_entry_attr.value.aclaction.enable = false; + acl_entry_attr.value.aclaction.parameter.oid = SAI_NULL_OBJECT_ID; + rollback_attrs.push_back(acl_entry_attr); + } + else if (old_acl_rule.meter.meter_oid != SAI_NULL_OBJECT_ID && !acl_rule.meter.enabled) + { + // Remove old meter + remove_meter = true; + acl_entry_attr.id = SAI_ACL_ENTRY_ATTR_ACTION_SET_POLICER; + acl_entry_attr.value.aclaction.enable = false; + acl_entry_attr.value.aclaction.parameter.oid = SAI_NULL_OBJECT_ID; + acl_entry_attrs.push_back(acl_entry_attr); + acl_entry_attr.value.aclaction.enable = true; + acl_entry_attr.value.aclaction.parameter.oid = old_acl_rule.meter.meter_oid; + rollback_attrs.push_back(acl_entry_attr); + } + else if (old_acl_rule.meter.meter_oid != SAI_NULL_OBJECT_ID) + { + // Update meter attributes + auto status = updateAclMeter(acl_rule.meter, old_acl_rule.meter); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to update ACL meter for rule %s", QuotedVar(acl_rule.acl_rule_key).c_str()); + return status; + } + updated_meter = true; + acl_rule.meter.meter_oid = old_acl_rule.meter.meter_oid; + } + + auto status = updateAclRule(acl_rule, old_acl_rule, acl_entry_attrs, rollback_attrs); + if (status.ok()) + { + // Remove old meter. + if (remove_meter) + { + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key); + auto rc = removeAclMeter(table_name_and_rule_key); + if (!rc.ok()) + { + SWSS_LOG_ERROR("Failed to remove ACL meter for rule %s", QuotedVar(acl_rule.acl_rule_key).c_str()); + for (const auto &entry_attr : rollback_attrs) + { + auto sai_status = sai_acl_api->set_acl_entry_attribute(old_acl_rule.acl_entry_oid, &entry_attr); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set ACL rule attribute. SAI_STATUS: %s", + sai_serialize_status(sai_status).c_str()); + SWSS_RAISE_CRITICAL_STATE("Failed to set ACL rule attribute in recovery."); + } + } + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key); + return rc; + } + } } - return status; - } - // Move match_fvs and referred pointers from old rule to new rule - acl_rule.in_ports = std::move(old_acl_rule.in_ports); - acl_rule.out_ports = std::move(old_acl_rule.out_ports); - acl_rule.in_ports_oids = std::move(old_acl_rule.in_ports_oids); - acl_rule.out_ports_oids = std::move(old_acl_rule.out_ports_oids); - acl_rule.udf_data_masks = std::move(old_acl_rule.udf_data_masks); - acl_rule.match_fvs = std::move(old_acl_rule.match_fvs); - m_aclRuleTables[acl_rule.acl_table_name][acl_rule.acl_rule_key] = - std::move(acl_rule); - return ReturnCode(); + else + { + SWSS_LOG_ERROR("Failed to update ACL rule %s", QuotedVar(acl_rule.acl_rule_key).c_str()); + // Clean up + if (created_meter) + { + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key); + auto rc = removeAclMeter(table_name_and_rule_key); + if (!rc.ok()) + { + SWSS_RAISE_CRITICAL_STATE("Failed to remove ACL meter in recovery."); + } + } + if (updated_meter) + { + auto rc = updateAclMeter(old_acl_rule.meter, acl_rule.meter); + if (!rc.ok()) + { + SWSS_RAISE_CRITICAL_STATE("Failed to update ACL meter in recovery."); + } + } + return status; + } + // Move match_fvs and referred pointers from old rule to new rule + acl_rule.in_ports = std::move(old_acl_rule.in_ports); + acl_rule.out_ports = std::move(old_acl_rule.out_ports); + acl_rule.in_ports_oids = std::move(old_acl_rule.in_ports_oids); + acl_rule.out_ports_oids = std::move(old_acl_rule.out_ports_oids); + acl_rule.udf_data_masks = std::move(old_acl_rule.udf_data_masks); + acl_rule.match_fvs = std::move(old_acl_rule.match_fvs); + m_aclRuleTables[acl_rule.acl_table_name][acl_rule.acl_rule_key] = std::move(acl_rule); + return ReturnCode(); } -std::string AclRuleManager::verifyState( - const std::string& key, const std::vector& tuple) { - SWSS_LOG_ENTER(); - - auto pos = key.find_first_of(kTableKeyDelimiter); - if (pos == std::string::npos) { - return std::string("Invalid key: ") + key; - } - std::string p4rt_table = key.substr(0, pos); - std::string p4rt_key = key.substr(pos + 1); - if (p4rt_table != APP_P4RT_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - std::string table_name; - std::string key_content; - parseP4RTKey(p4rt_key, &table_name, &key_content); - - ReturnCode status; - auto app_db_entry_or = - deserializeAclRuleAppDbEntry(table_name, key_content, tuple); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - std::stringstream msg; - msg << "Unable to deserialize key " << QuotedVar(key) << ": " - << status.message(); - return msg.str(); - } - auto& app_db_entry = *app_db_entry_or; - - const auto& acl_table_name = app_db_entry.acl_table_name; - const auto& acl_rule_key = KeyGenerator::generateAclRuleKey( - app_db_entry.match_fvs, std::to_string(app_db_entry.priority)); - auto* acl_rule = getAclRule(acl_table_name, acl_rule_key); - if (acl_rule == nullptr) { - std::stringstream msg; - msg << "No entry found with key " << QuotedVar(key); - return msg.str(); - } - - std::string cache_result = verifyStateCache(app_db_entry, acl_rule); - std::string asic_db_result = verifyStateAsicDb(acl_rule); - if (cache_result.empty()) { - return asic_db_result; - } - if (asic_db_result.empty()) { - return cache_result; - } - return cache_result + "; " + asic_db_result; +std::string AclRuleManager::verifyState(const std::string &key, const std::vector &tuple) +{ + SWSS_LOG_ENTER(); + + auto pos = key.find_first_of(kTableKeyDelimiter); + if (pos == std::string::npos) + { + return std::string("Invalid key: ") + key; + } + std::string p4rt_table = key.substr(0, pos); + std::string p4rt_key = key.substr(pos + 1); + if (p4rt_table != APP_P4RT_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } + std::string table_name; + std::string key_content; + parseP4RTKey(p4rt_key, &table_name, &key_content); + + ReturnCode status; + auto app_db_entry_or = deserializeAclRuleAppDbEntry(table_name, key_content, tuple); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + std::stringstream msg; + msg << "Unable to deserialize key " << QuotedVar(key) << ": " << status.message(); + return msg.str(); + } + auto &app_db_entry = *app_db_entry_or; + + const auto &acl_table_name = app_db_entry.acl_table_name; + const auto &acl_rule_key = + KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, std::to_string(app_db_entry.priority)); + auto *acl_rule = getAclRule(acl_table_name, acl_rule_key); + if (acl_rule == nullptr) + { + std::stringstream msg; + msg << "No entry found with key " << QuotedVar(key); + return msg.str(); + } + + std::string cache_result = verifyStateCache(app_db_entry, acl_rule); + std::string asic_db_result = verifyStateAsicDb(acl_rule); + if (cache_result.empty()) + { + return asic_db_result; + } + if (asic_db_result.empty()) + { + return cache_result; + } + return cache_result + "; " + asic_db_result; } -std::string AclRuleManager::verifyStateCache( - const P4AclRuleAppDbEntry& app_db_entry, const P4AclRule* acl_rule) { - ReturnCode status = validateAclRuleAppDbEntry(app_db_entry); - if (!status.ok()) { - std::stringstream msg; - msg << "Validation failed for ACL rule DB entry with key " - << QuotedVar(acl_rule->acl_rule_key) << ": " << status.message(); - return msg.str(); - } - - const auto& acl_rule_key = KeyGenerator::generateAclRuleKey( - app_db_entry.match_fvs, std::to_string(app_db_entry.priority)); - if (acl_rule->acl_rule_key != acl_rule_key) { - std::stringstream msg; - msg << "ACL rule " << QuotedVar(acl_rule_key) - << " does not match internal cache " - << QuotedVar(acl_rule->acl_rule_key) << " in ACL rule manager."; - return msg.str(); - } - if (acl_rule->acl_table_name != app_db_entry.acl_table_name) { - std::stringstream msg; - msg << "ACL rule " << QuotedVar(acl_rule_key) << " with table name " - << QuotedVar(app_db_entry.acl_table_name) - << " does not match internal cache " - << QuotedVar(acl_rule->acl_table_name) << " in ACL rule manager."; - return msg.str(); - } - if (acl_rule->db_key != app_db_entry.db_key) { - std::stringstream msg; - msg << "ACL rule " << QuotedVar(acl_rule_key) << " with DB key " - << QuotedVar(app_db_entry.db_key) << " does not match internal cache " - << QuotedVar(acl_rule->db_key) << " in ACL rule manager."; - return msg.str(); - } - if (acl_rule->p4_action != app_db_entry.action) { - std::stringstream msg; - msg << "ACL rule " << QuotedVar(acl_rule_key) << " with action " - << QuotedVar(app_db_entry.action) << " does not match internal cache " - << QuotedVar(acl_rule->p4_action) << " in ACL rule manager."; - return msg.str(); - } - if (acl_rule->priority != app_db_entry.priority) { - std::stringstream msg; - msg << "ACL rule " << QuotedVar(acl_rule_key) << " with priority " - << app_db_entry.priority << " does not match internal cache " - << acl_rule->priority << " in ACL rule manager."; - return msg.str(); - } - - auto* acl_table = - gP4Orch->getAclTableManager()->getAclTable(app_db_entry.acl_table_name); - if (acl_table == nullptr) { - std::stringstream msg; - msg << "ACL table " << QuotedVar(app_db_entry.acl_table_name) - << " not found in ACL rule " << QuotedVar(acl_rule_key); - return msg.str(); - } - if (acl_rule->acl_table_name != acl_table->acl_table_name) { - std::stringstream msg; - msg << "ACL rule " << QuotedVar(acl_rule_key) << " with ACL table name " - << QuotedVar(acl_rule->acl_table_name) << " mismatch with ACl table " - << QuotedVar(acl_table->acl_table_name) << " in ACl rule manager."; - return msg.str(); - } - if (acl_rule->acl_table_oid != acl_table->table_oid) { - std::stringstream msg; - msg << "ACL rule " << QuotedVar(acl_rule_key) << " with ACL table OID " - << acl_rule->acl_table_oid << " mismatch with ACl table " - << acl_table->table_oid << " in ACl rule manager."; - return msg.str(); - } - - P4AclRule acl_rule_entry{}; - acl_rule_entry.priority = app_db_entry.priority; - acl_rule_entry.acl_rule_key = acl_rule_key; - acl_rule_entry.p4_action = app_db_entry.action; - acl_rule_entry.db_key = app_db_entry.db_key; - status = setAllMatchFieldValues(app_db_entry, acl_table, acl_rule_entry); - if (!status.ok()) { - std::stringstream msg; - msg << "Failed to set match field values for ACL rule " - << QuotedVar(acl_rule_key); - return msg.str(); - } - status = setAllActionFieldValues(app_db_entry, acl_table, acl_rule_entry); - if (!status.ok()) { - std::stringstream msg; - msg << "Failed to set action field values for ACL rule " - << QuotedVar(acl_rule_key); - return msg.str(); - } - status = setMeterValue(acl_table, app_db_entry, acl_rule_entry.meter); - if (!status.ok()) { - std::stringstream msg; - msg << "Failed to set meter value for ACL rule " << QuotedVar(acl_rule_key); - return msg.str(); - } - if (!acl_table->counter_unit.empty()) { - if (acl_table->counter_unit == P4_COUNTER_UNIT_PACKETS) { - acl_rule_entry.counter.packets_enabled = true; - } else if (acl_table->counter_unit == P4_COUNTER_UNIT_BYTES) { - acl_rule_entry.counter.bytes_enabled = true; - } else if (acl_table->counter_unit == P4_COUNTER_UNIT_BOTH) { - acl_rule_entry.counter.bytes_enabled = true; - acl_rule_entry.counter.packets_enabled = true; - } - } - - if (acl_rule->match_fvs.size() != acl_rule_entry.match_fvs.size()) { - std::stringstream msg; - msg << "ACL rule " << QuotedVar(acl_rule_key) << " with match fvs size " - << acl_rule_entry.match_fvs.size() << " does not match internal cache " - << acl_rule->match_fvs.size() << " in ACl rule manager."; - return msg.str(); - } - for (const auto& match_fv : acl_rule_entry.match_fvs) { - const auto& it = acl_rule->match_fvs.find(fvField(match_fv)); - if (it == acl_rule->match_fvs.end()) { - std::stringstream msg; - msg << "ACL match field " << fvField(match_fv) - << " not found in internal cache in ACL rule " - << QuotedVar(acl_rule_key); - return msg.str(); - } else if (isDiffMatchFieldValue(fvField(match_fv), fvValue(match_fv), - it->second, acl_rule_entry, *acl_rule)) { - std::stringstream msg; - msg << "ACL match field " << fvField(match_fv) - << " mismatch in internal cache in ACL rule " - << QuotedVar(acl_rule_key); - return msg.str(); - } - } - - if (acl_rule->action_fvs.size() != acl_rule_entry.action_fvs.size()) { - std::stringstream msg; - msg << "ACL rule " << QuotedVar(acl_rule_key) << " with action fvs size " - << acl_rule_entry.action_fvs.size() << " does not match internal cache " - << acl_rule->action_fvs.size() << " in ACl rule manager."; - return msg.str(); - } - for (const auto& action_fv : acl_rule_entry.action_fvs) { - const auto& it = acl_rule->action_fvs.find(fvField(action_fv)); - if (it == acl_rule->action_fvs.end()) { - std::stringstream msg; - msg << "ACL action field " << fvField(action_fv) - << " not found in internal cache in ACL rule " - << QuotedVar(acl_rule_key); - return msg.str(); - } else if (isDiffActionFieldValue(fvField(action_fv), fvValue(action_fv), - it->second, acl_rule_entry, *acl_rule)) { - std::stringstream msg; - msg << "ACL action field " << fvField(action_fv) - << " mismatch in internal cache in ACL rule " - << QuotedVar(acl_rule_key); - return msg.str(); - } - } - - if (acl_rule->meter != acl_rule_entry.meter) { - std::stringstream msg; - msg << "Meter mismatch on ACL rule " << QuotedVar(acl_rule_key); - return msg.str(); - } - if (acl_rule->counter != acl_rule_entry.counter) { - std::stringstream msg; - msg << "Counter mismatch on ACL rule " << QuotedVar(acl_rule_key); - return msg.str(); - } - if (acl_rule->action_qos_queue_num != acl_rule_entry.action_qos_queue_num) { - std::stringstream msg; - msg << "ACL rule " << QuotedVar(acl_rule_key) << " with qos queue number " - << acl_rule_entry.action_qos_queue_num - << " mismatch with internal cache " << acl_rule->action_qos_queue_num - << " in ACl rule manager."; - return msg.str(); - } - if (acl_rule->action_redirect_nexthop_key != - acl_rule_entry.action_redirect_nexthop_key) { - std::stringstream msg; - msg << "ACL rule " << QuotedVar(acl_rule_key) - << " with redirect nexthop key " - << QuotedVar(acl_rule_entry.action_redirect_nexthop_key) - << " mismatch with internal cache " - << QuotedVar(acl_rule->action_redirect_nexthop_key) - << " in ACl rule manager."; - return msg.str(); - } - if (acl_rule->action_mirror_sessions != - acl_rule_entry.action_mirror_sessions) { - std::stringstream msg; - msg << "Mirror sessions mismatch on ACL rule " << QuotedVar(acl_rule_key); - return msg.str(); - } - if (!acl_rule->action_mirror_sessions.empty()) { - for (const auto& fv : acl_rule->action_mirror_sessions) { - if (acl_rule->action_fvs.find(fvField(fv)) == - acl_rule->action_fvs.end() || - acl_rule->action_fvs.at(fvField(fv)) - .aclaction.parameter.objlist.list != &fvValue(fv).oid) { +std::string AclRuleManager::verifyStateCache(const P4AclRuleAppDbEntry &app_db_entry, const P4AclRule *acl_rule) +{ + ReturnCode status = validateAclRuleAppDbEntry(app_db_entry); + if (!status.ok()) + { std::stringstream msg; - msg << "Mirror session " << QuotedVar(std::to_string(fvField(fv))) - << " mismatch on internal cache ACL rule " - << QuotedVar(acl_rule_key); + msg << "Validation failed for ACL rule DB entry with key " << QuotedVar(acl_rule->acl_rule_key) << ": " + << status.message(); + return msg.str(); + } + + const auto &acl_rule_key = + KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, std::to_string(app_db_entry.priority)); + if (acl_rule->acl_rule_key != acl_rule_key) + { + std::stringstream msg; + msg << "ACL rule " << QuotedVar(acl_rule_key) << " does not match internal cache " + << QuotedVar(acl_rule->acl_rule_key) << " in ACL rule manager."; + return msg.str(); + } + if (acl_rule->acl_table_name != app_db_entry.acl_table_name) + { + std::stringstream msg; + msg << "ACL rule " << QuotedVar(acl_rule_key) << " with table name " << QuotedVar(app_db_entry.acl_table_name) + << " does not match internal cache " << QuotedVar(acl_rule->acl_table_name) << " in ACL rule manager."; + return msg.str(); + } + if (acl_rule->db_key != app_db_entry.db_key) + { + std::stringstream msg; + msg << "ACL rule " << QuotedVar(acl_rule_key) << " with DB key " << QuotedVar(app_db_entry.db_key) + << " does not match internal cache " << QuotedVar(acl_rule->db_key) << " in ACL rule manager."; + return msg.str(); + } + if (acl_rule->p4_action != app_db_entry.action) + { + std::stringstream msg; + msg << "ACL rule " << QuotedVar(acl_rule_key) << " with action " << QuotedVar(app_db_entry.action) + << " does not match internal cache " << QuotedVar(acl_rule->p4_action) << " in ACL rule manager."; + return msg.str(); + } + if (acl_rule->priority != app_db_entry.priority) + { + std::stringstream msg; + msg << "ACL rule " << QuotedVar(acl_rule_key) << " with priority " << app_db_entry.priority + << " does not match internal cache " << acl_rule->priority << " in ACL rule manager."; return msg.str(); - } - } - } - - if (acl_rule->udf_data_masks != acl_rule_entry.udf_data_masks) { - std::stringstream msg; - msg << "UDF data masks mismatch on ACL rule " << QuotedVar(acl_rule_key); - return msg.str(); - } - if (!acl_rule->udf_data_masks.empty()) { - std::stringstream msg; - for (const auto& fv : acl_rule->udf_data_masks) { - if (acl_rule->match_fvs.find(fvField(fv)) == acl_rule->match_fvs.end()) { - msg << "UDF group " << QuotedVar(std::to_string(fvField(fv))) - << " are missing in in internal cache in ACL rule match_fvs" + } + + auto *acl_table = gP4Orch->getAclTableManager()->getAclTable(app_db_entry.acl_table_name); + if (acl_table == nullptr) + { + std::stringstream msg; + msg << "ACL table " << QuotedVar(app_db_entry.acl_table_name) << " not found in ACL rule " << QuotedVar(acl_rule_key); return msg.str(); - } - if (acl_rule->match_fvs.at(fvField(fv)).aclfield.data.u8list.list != - fvValue(fv).data.data()) { - msg << "UDF data for field " << QuotedVar(std::to_string(fvField(fv))) - << " mismatches between match_fvs and " - "udf_data_masks in internal cache in ACL rule" + } + if (acl_rule->acl_table_name != acl_table->acl_table_name) + { + std::stringstream msg; + msg << "ACL rule " << QuotedVar(acl_rule_key) << " with ACL table name " << QuotedVar(acl_rule->acl_table_name) + << " mismatch with ACl table " << QuotedVar(acl_table->acl_table_name) << " in ACl rule manager."; + return msg.str(); + } + if (acl_rule->acl_table_oid != acl_table->table_oid) + { + std::stringstream msg; + msg << "ACL rule " << QuotedVar(acl_rule_key) << " with ACL table OID " << acl_rule->acl_table_oid + << " mismatch with ACl table " << acl_table->table_oid << " in ACl rule manager."; + return msg.str(); + } + + P4AclRule acl_rule_entry{}; + acl_rule_entry.priority = app_db_entry.priority; + acl_rule_entry.acl_rule_key = acl_rule_key; + acl_rule_entry.p4_action = app_db_entry.action; + acl_rule_entry.db_key = app_db_entry.db_key; + status = setAllMatchFieldValues(app_db_entry, acl_table, acl_rule_entry); + if (!status.ok()) + { + std::stringstream msg; + msg << "Failed to set match field values for ACL rule " << QuotedVar(acl_rule_key); + return msg.str(); + } + status = setAllActionFieldValues(app_db_entry, acl_table, acl_rule_entry); + if (!status.ok()) + { + std::stringstream msg; + msg << "Failed to set action field values for ACL rule " << QuotedVar(acl_rule_key); + return msg.str(); + } + status = setMeterValue(acl_table, app_db_entry, acl_rule_entry.meter); + if (!status.ok()) + { + std::stringstream msg; + msg << "Failed to set meter value for ACL rule " << QuotedVar(acl_rule_key); + return msg.str(); + } + if (!acl_table->counter_unit.empty()) + { + if (acl_table->counter_unit == P4_COUNTER_UNIT_PACKETS) + { + acl_rule_entry.counter.packets_enabled = true; + } + else if (acl_table->counter_unit == P4_COUNTER_UNIT_BYTES) + { + acl_rule_entry.counter.bytes_enabled = true; + } + else if (acl_table->counter_unit == P4_COUNTER_UNIT_BOTH) + { + acl_rule_entry.counter.bytes_enabled = true; + acl_rule_entry.counter.packets_enabled = true; + } + } + + if (acl_rule->match_fvs.size() != acl_rule_entry.match_fvs.size()) + { + std::stringstream msg; + msg << "ACL rule " << QuotedVar(acl_rule_key) << " with match fvs size " << acl_rule_entry.match_fvs.size() + << " does not match internal cache " << acl_rule->match_fvs.size() << " in ACl rule manager."; + return msg.str(); + } + for (const auto &match_fv : acl_rule_entry.match_fvs) + { + const auto &it = acl_rule->match_fvs.find(fvField(match_fv)); + if (it == acl_rule->match_fvs.end()) + { + std::stringstream msg; + msg << "ACL match field " << fvField(match_fv) << " not found in internal cache in ACL rule " + << QuotedVar(acl_rule_key); + return msg.str(); + } + else if (isDiffMatchFieldValue(fvField(match_fv), fvValue(match_fv), it->second, acl_rule_entry, *acl_rule)) + { + std::stringstream msg; + msg << "ACL match field " << fvField(match_fv) << " mismatch in internal cache in ACL rule " + << QuotedVar(acl_rule_key); + return msg.str(); + } + } + + if (acl_rule->action_fvs.size() != acl_rule_entry.action_fvs.size()) + { + std::stringstream msg; + msg << "ACL rule " << QuotedVar(acl_rule_key) << " with action fvs size " << acl_rule_entry.action_fvs.size() + << " does not match internal cache " << acl_rule->action_fvs.size() << " in ACl rule manager."; + return msg.str(); + } + for (const auto &action_fv : acl_rule_entry.action_fvs) + { + const auto &it = acl_rule->action_fvs.find(fvField(action_fv)); + if (it == acl_rule->action_fvs.end()) + { + std::stringstream msg; + msg << "ACL action field " << fvField(action_fv) << " not found in internal cache in ACL rule " + << QuotedVar(acl_rule_key); + return msg.str(); + } + else if (isDiffActionFieldValue(fvField(action_fv), fvValue(action_fv), it->second, acl_rule_entry, *acl_rule)) + { + std::stringstream msg; + msg << "ACL action field " << fvField(action_fv) << " mismatch in internal cache in ACL rule " + << QuotedVar(acl_rule_key); + return msg.str(); + } + } + + if (acl_rule->meter != acl_rule_entry.meter) + { + std::stringstream msg; + msg << "Meter mismatch on ACL rule " << QuotedVar(acl_rule_key); + return msg.str(); + } + if (acl_rule->counter != acl_rule_entry.counter) + { + std::stringstream msg; + msg << "Counter mismatch on ACL rule " << QuotedVar(acl_rule_key); + return msg.str(); + } + if (acl_rule->action_qos_queue_num != acl_rule_entry.action_qos_queue_num) + { + std::stringstream msg; + msg << "ACL rule " << QuotedVar(acl_rule_key) << " with qos queue number " + << acl_rule_entry.action_qos_queue_num << " mismatch with internal cache " << acl_rule->action_qos_queue_num + << " in ACl rule manager."; + return msg.str(); + } + if (acl_rule->action_redirect_nexthop_key != acl_rule_entry.action_redirect_nexthop_key) + { + std::stringstream msg; + msg << "ACL rule " << QuotedVar(acl_rule_key) << " with redirect nexthop key " + << QuotedVar(acl_rule_entry.action_redirect_nexthop_key) << " mismatch with internal cache " + << QuotedVar(acl_rule->action_redirect_nexthop_key) << " in ACl rule manager."; + return msg.str(); + } + if (acl_rule->action_mirror_sessions != acl_rule_entry.action_mirror_sessions) + { + std::stringstream msg; + msg << "Mirror sessions mismatch on ACL rule " << QuotedVar(acl_rule_key); + return msg.str(); + } + if (!acl_rule->action_mirror_sessions.empty()) + { + for (const auto &fv : acl_rule->action_mirror_sessions) + { + if (acl_rule->action_fvs.find(fvField(fv)) == acl_rule->action_fvs.end() || + acl_rule->action_fvs.at(fvField(fv)).aclaction.parameter.objlist.list != &fvValue(fv).oid) + { + std::stringstream msg; + msg << "Mirror session " << QuotedVar(std::to_string(fvField(fv))) + << " mismatch on internal cache ACL rule " << QuotedVar(acl_rule_key); + return msg.str(); + } + } + } + + if (acl_rule->udf_data_masks != acl_rule_entry.udf_data_masks) + { + std::stringstream msg; + msg << "UDF data masks mismatch on ACL rule " << QuotedVar(acl_rule_key); + return msg.str(); + } + if (!acl_rule->udf_data_masks.empty()) + { + std::stringstream msg; + for (const auto &fv : acl_rule->udf_data_masks) + { + if (acl_rule->match_fvs.find(fvField(fv)) == acl_rule->match_fvs.end()) + { + msg << "UDF group " << QuotedVar(std::to_string(fvField(fv))) + << " are missing in in internal cache in ACL rule match_fvs" << QuotedVar(acl_rule_key); + return msg.str(); + } + if (acl_rule->match_fvs.at(fvField(fv)).aclfield.data.u8list.list != fvValue(fv).data.data()) + { + msg << "UDF data for field " << QuotedVar(std::to_string(fvField(fv))) + << " mismatches between match_fvs and " + "udf_data_masks in internal cache in ACL rule" + << QuotedVar(acl_rule_key); + return msg.str(); + } + if (acl_rule->match_fvs.at(fvField(fv)).aclfield.mask.u8list.list != fvValue(fv).mask.data()) + { + msg << "UDF mask for field " << QuotedVar(std::to_string(fvField(fv))) + << " mismatches between match_fvs and " + "udf_data_masks in internal cache in ACL rule" + << QuotedVar(acl_rule_key); + return msg.str(); + } + } + } + if (acl_rule->in_ports != acl_rule_entry.in_ports) + { + std::stringstream msg; + msg << "In ports mismatch on ACL rule " << QuotedVar(acl_rule_key); + return msg.str(); + } + if (acl_rule->out_ports != acl_rule_entry.out_ports) + { + std::stringstream msg; + msg << "Out ports mismatch on ACL rule " << QuotedVar(acl_rule_key); + return msg.str(); + } + if (acl_rule->in_ports_oids != acl_rule_entry.in_ports_oids) + { + std::stringstream msg; + msg << "In port OIDs mismatch on ACL rule " << QuotedVar(acl_rule_key); + return msg.str(); + } + if (!acl_rule->in_ports_oids.empty() && + (acl_rule->match_fvs.find(SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS) == acl_rule->match_fvs.end() || + acl_rule->match_fvs.at(SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS).aclfield.data.objlist.list != + acl_rule->in_ports_oids.data())) + { + std::stringstream msg; + msg << "In port OIDs mismatch between match_fvs and " + "in_ports_oids in internal cache in ACL rule" << QuotedVar(acl_rule_key); return msg.str(); - } - if (acl_rule->match_fvs.at(fvField(fv)).aclfield.mask.u8list.list != - fvValue(fv).mask.data()) { - msg << "UDF mask for field " << QuotedVar(std::to_string(fvField(fv))) - << " mismatches between match_fvs and " - "udf_data_masks in internal cache in ACL rule" + } + + if (acl_rule->out_ports_oids != acl_rule_entry.out_ports_oids) + { + std::stringstream msg; + msg << "Out port OIDs mismatch on ACL rule " << QuotedVar(acl_rule_key); + return msg.str(); + } + if (!acl_rule->out_ports_oids.empty() && + (acl_rule->match_fvs.find(SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS) == acl_rule->match_fvs.end() || + acl_rule->match_fvs.at(SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS).aclfield.data.objlist.list != + acl_rule->out_ports_oids.data())) + { + std::stringstream msg; + msg << "Out port OIDs mismatch between match_fvs and " + "out_ports_oids in internal cache in ACL rule" << QuotedVar(acl_rule_key); return msg.str(); - } - } - } - if (acl_rule->in_ports != acl_rule_entry.in_ports) { - std::stringstream msg; - msg << "In ports mismatch on ACL rule " << QuotedVar(acl_rule_key); - return msg.str(); - } - if (acl_rule->out_ports != acl_rule_entry.out_ports) { - std::stringstream msg; - msg << "Out ports mismatch on ACL rule " << QuotedVar(acl_rule_key); - return msg.str(); - } - if (acl_rule->in_ports_oids != acl_rule_entry.in_ports_oids) { - std::stringstream msg; - msg << "In port OIDs mismatch on ACL rule " << QuotedVar(acl_rule_key); - return msg.str(); - } - if (!acl_rule->in_ports_oids.empty() && - (acl_rule->match_fvs.find(SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS) == - acl_rule->match_fvs.end() || - acl_rule->match_fvs.at(SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS) - .aclfield.data.objlist.list != acl_rule->in_ports_oids.data())) { - std::stringstream msg; - msg << "In port OIDs mismatch between match_fvs and " - "in_ports_oids in internal cache in ACL rule" - << QuotedVar(acl_rule_key); - return msg.str(); - } - - if (acl_rule->out_ports_oids != acl_rule_entry.out_ports_oids) { - std::stringstream msg; - msg << "Out port OIDs mismatch on ACL rule " << QuotedVar(acl_rule_key); - return msg.str(); - } - if (!acl_rule->out_ports_oids.empty() && - (acl_rule->match_fvs.find(SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS) == - acl_rule->match_fvs.end() || - acl_rule->match_fvs.at(SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS) - .aclfield.data.objlist.list != - acl_rule->out_ports_oids.data())) { - std::stringstream msg; - msg << "Out port OIDs mismatch between match_fvs and " - "out_ports_oids in internal cache in ACL rule" - << QuotedVar(acl_rule_key); - return msg.str(); - } - - const auto& table_name_and_rule_key = concatTableNameAndRuleKey( - acl_rule->acl_table_name, acl_rule->acl_rule_key); - std::string err_msg = m_p4OidMapper->verifyOIDMapping( - SAI_OBJECT_TYPE_ACL_ENTRY, table_name_and_rule_key, - acl_rule->acl_entry_oid); - if (!err_msg.empty()) { - return err_msg; - } - if (!acl_table->counter_unit.empty()) { - err_msg = m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_ACL_COUNTER, - table_name_and_rule_key, - acl_rule->counter.counter_oid); - if (!err_msg.empty()) { - return err_msg; - } - } - if (acl_rule_entry.meter.enabled) { - err_msg = m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, - acl_rule->meter.meter_oid); - if (!err_msg.empty()) { - return err_msg; - } - } - - return ""; + } + + const auto &table_name_and_rule_key = concatTableNameAndRuleKey(acl_rule->acl_table_name, acl_rule->acl_rule_key); + std::string err_msg = + m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_ACL_ENTRY, table_name_and_rule_key, acl_rule->acl_entry_oid); + if (!err_msg.empty()) + { + return err_msg; + } + if (!acl_table->counter_unit.empty()) + { + err_msg = m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_ACL_COUNTER, table_name_and_rule_key, + acl_rule->counter.counter_oid); + if (!err_msg.empty()) + { + return err_msg; + } + } + if (acl_rule_entry.meter.enabled) + { + err_msg = m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, + acl_rule->meter.meter_oid); + if (!err_msg.empty()) + { + return err_msg; + } + } + + return ""; } -std::string AclRuleManager::verifyStateAsicDb(const P4AclRule* acl_rule) { - swss::DBConnector db("ASIC_DB", 0); - swss::Table table(&db, "ASIC_STATE"); - - // Verify rule. - auto attrs = getRuleSaiAttrs(*acl_rule); - std::vector exp = - saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_ACL_ENTRY, (uint32_t)attrs.size(), attrs.data(), - /*countOnly=*/false); - std::string key = sai_serialize_object_type(SAI_OBJECT_TYPE_ACL_ENTRY) + ":" + - sai_serialize_object_id(acl_rule->acl_entry_oid); - std::vector values; - if (!table.get(key, values)) { - return std::string("ASIC DB key not found ") + key; - } - std::string err_msg = - verifyAttrs(values, exp, std::vector{}, - /*allow_unknown=*/true); - if (!err_msg.empty()) { - return err_msg; - } - - // Verify counter. - if (acl_rule->counter.packets_enabled || acl_rule->counter.bytes_enabled) { - attrs = getCounterSaiAttrs(*acl_rule); - exp = saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_ACL_COUNTER, (uint32_t)attrs.size(), attrs.data(), - /*countOnly=*/false); - key = sai_serialize_object_type(SAI_OBJECT_TYPE_ACL_COUNTER) + ":" + - sai_serialize_object_id(acl_rule->counter.counter_oid); - values.clear(); - if (!table.get(key, values)) { - return std::string("ASIC DB key not found ") + key; - } - err_msg = verifyAttrs(values, exp, std::vector{}, - /*allow_unknown=*/true); - if (!err_msg.empty()) { - return err_msg; - } - } - - // Verify meter. - if (acl_rule->meter.enabled) { - attrs = getMeterSaiAttrs(acl_rule->meter); - exp = saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_POLICER, (uint32_t)attrs.size(), attrs.data(), - /*countOnly=*/false); - key = sai_serialize_object_type(SAI_OBJECT_TYPE_POLICER) + ":" + - sai_serialize_object_id(acl_rule->meter.meter_oid); - values.clear(); - if (!table.get(key, values)) { - return std::string("ASIC DB key not found ") + key; - } - err_msg = verifyAttrs(values, exp, std::vector{}, - /*allow_unknown=*/true); - if (!err_msg.empty()) { - return err_msg; - } - } - - return ""; +std::string AclRuleManager::verifyStateAsicDb(const P4AclRule *acl_rule) +{ + swss::DBConnector db("ASIC_DB", 0); + swss::Table table(&db, "ASIC_STATE"); + + // Verify rule. + auto attrs = getRuleSaiAttrs(*acl_rule); + std::vector exp = + saimeta::SaiAttributeList::serialize_attr_list(SAI_OBJECT_TYPE_ACL_ENTRY, (uint32_t)attrs.size(), attrs.data(), + /*countOnly=*/false); + std::string key = + sai_serialize_object_type(SAI_OBJECT_TYPE_ACL_ENTRY) + ":" + sai_serialize_object_id(acl_rule->acl_entry_oid); + std::vector values; + if (!table.get(key, values)) + { + return std::string("ASIC DB key not found ") + key; + } + std::string err_msg = verifyAttrs(values, exp, std::vector{}, + /*allow_unknown=*/true); + if (!err_msg.empty()) + { + return err_msg; + } + + // Verify counter. + if (acl_rule->counter.packets_enabled || acl_rule->counter.bytes_enabled) + { + attrs = getCounterSaiAttrs(*acl_rule); + exp = saimeta::SaiAttributeList::serialize_attr_list(SAI_OBJECT_TYPE_ACL_COUNTER, (uint32_t)attrs.size(), + attrs.data(), + /*countOnly=*/false); + key = sai_serialize_object_type(SAI_OBJECT_TYPE_ACL_COUNTER) + ":" + + sai_serialize_object_id(acl_rule->counter.counter_oid); + values.clear(); + if (!table.get(key, values)) + { + return std::string("ASIC DB key not found ") + key; + } + err_msg = verifyAttrs(values, exp, std::vector{}, + /*allow_unknown=*/true); + if (!err_msg.empty()) + { + return err_msg; + } + } + + // Verify meter. + if (acl_rule->meter.enabled) + { + attrs = getMeterSaiAttrs(acl_rule->meter); + exp = saimeta::SaiAttributeList::serialize_attr_list(SAI_OBJECT_TYPE_POLICER, (uint32_t)attrs.size(), + attrs.data(), + /*countOnly=*/false); + key = sai_serialize_object_type(SAI_OBJECT_TYPE_POLICER) + ":" + + sai_serialize_object_id(acl_rule->meter.meter_oid); + values.clear(); + if (!table.get(key, values)) + { + return std::string("ASIC DB key not found ") + key; + } + err_msg = verifyAttrs(values, exp, std::vector{}, + /*allow_unknown=*/true); + if (!err_msg.empty()) + { + return err_msg; + } + } + + return ""; } -} // namespace p4orch +} // namespace p4orch diff --git a/orchagent/p4orch/acl_rule_manager.h b/orchagent/p4orch/acl_rule_manager.h index e211e507674..1e65ef7c8d7 100644 --- a/orchagent/p4orch/acl_rule_manager.h +++ b/orchagent/p4orch/acl_rule_manager.h @@ -14,174 +14,149 @@ #include "return_code.h" #include "vrforch.h" -extern "C" { +extern "C" +{ #include "sai.h" } -namespace p4orch { -namespace test { +namespace p4orch +{ +namespace test +{ class AclManagerTest; -} // namespace test - -class AclRuleManager : public ObjectManagerInterface { - public: - explicit AclRuleManager(P4OidMapper* p4oidMapper, VRFOrch* vrfOrch, - CoppOrch* coppOrch, - ResponsePublisherInterface* publisher) - : m_p4OidMapper(p4oidMapper), - m_vrfOrch(vrfOrch), - m_publisher(publisher), - m_coppOrch(coppOrch), - m_countersDb(std::make_unique("COUNTERS_DB", 0)), - m_countersTable(std::make_unique( - m_countersDb.get(), std::string(COUNTERS_TABLE) + - DEFAULT_KEY_SEPARATOR + - APP_P4RT_TABLE_NAME)) { - SWSS_LOG_ENTER(); - assert(m_p4OidMapper != nullptr); - } - virtual ~AclRuleManager() = default; - - void enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) override; - void drain() override; - std::string verifyState( - const std::string& key, - const std::vector& tuple) override; - ReturnCode getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) override; - - // Update counters stats for every rule in each ACL table in COUNTERS_DB, if - // counters are enabled in rules. - void doAclCounterStatsTask(); - - private: - // Deserializes an entry in a dynamically created ACL table. - ReturnCodeOr deserializeAclRuleAppDbEntry( - const std::string& acl_table_name, const std::string& key, - const std::vector& attributes); - - // Validate an ACL rule APP_DB entry. - ReturnCode validateAclRuleAppDbEntry(const P4AclRuleAppDbEntry& app_db_entry); - - // Get ACL rule by table name and rule key. Return nullptr if not found. - P4AclRule* getAclRule(const std::string& acl_table_name, - const std::string& acl_rule_key); - - // Processes add operation for an ACL rule. - ReturnCode processAddRuleRequest(const std::string& acl_rule_key, - const P4AclRuleAppDbEntry& app_db_entry); - - // Processes delete operation for an ACL rule. - ReturnCode processDeleteRuleRequest(const std::string& acl_table_name, - const std::string& acl_rule_key); - - // Processes update operation for an ACL rule. - ReturnCode processUpdateRuleRequest(const P4AclRuleAppDbEntry& app_db_entry, - const P4AclRule& old_acl_rule); - - // Set counters stats for an ACL rule in COUNTERS_DB. - ReturnCode setAclRuleCounterStats(const P4AclRule& acl_rule); - - // Create an ACL rule. - ReturnCode createAclRule(P4AclRule& acl_rule); - - // Create an ACL counter. - ReturnCode createAclCounter(const std::string& acl_table_name, - const std::string& counter_key, - const P4AclRule& acl_rule, - sai_object_id_t* counter_oid); - - // Create an ACL meter. - ReturnCode createAclMeter(const P4AclMeter& p4_acl_meter, - const std::string& meter_key, - sai_object_id_t* meter_oid); - - // Remove an ACL counter. - ReturnCode removeAclCounter(const std::string& acl_table_name, - const std::string& counter_key); - - // Update ACL meter. - ReturnCode updateAclMeter(const P4AclMeter& new_acl_meter, - const P4AclMeter& old_acl_meter); - - // Update ACL rule. - ReturnCode updateAclRule(const P4AclRule& new_acl_rule, - const P4AclRule& old_acl_rule, - std::vector& acl_entry_attrs, - std::vector& rollback_attrs); - - // Remove an ACL meter. - ReturnCode removeAclMeter(const std::string& meter_key); - - // Remove the ACL rule by key in the given ACL table. - ReturnCode removeAclRule(const std::string& acl_table_name, - const std::string& acl_rule_key); - - // Set Meter value in ACL rule. - ReturnCode setMeterValue(const P4AclTableDefinition* acl_table, - const P4AclRuleAppDbEntry& app_db_entry, - P4AclMeter& acl_meter); - - // Validate and set all match attributes in an ACL rule. - ReturnCode setAllMatchFieldValues(const P4AclRuleAppDbEntry& app_db_entry, - const P4AclTableDefinition* acl_table, - P4AclRule& acl_rules); - - // Validate and set all action attributes in an ACL rule. - ReturnCode setAllActionFieldValues(const P4AclRuleAppDbEntry& app_db_entry, - const P4AclTableDefinition* acl_table, - P4AclRule& acl_rule); - - // Validate and set a match attribute in an ACL rule. - ReturnCode setMatchValue(const acl_entry_attr_union_t attr_name, - const std::string& attr_value, - sai_attribute_value_t* value, P4AclRule* acl_rule, - const std::string& ip_type_bit_type = EMPTY_STRING); - - // Validate and set an action attribute in an ACL rule. - ReturnCode setActionValue(const acl_entry_attr_union_t attr_name, - const std::string& attr_value, - sai_attribute_value_t* value, P4AclRule* acl_rule); - - // Get port object id by name for redirect action. - ReturnCode getRedirectActionPortOid(const std::string& target, - sai_object_id_t* rediect_oid); - - // Get next hop object id by name for redirect action. - ReturnCode getRedirectActionNextHopOid(const std::string& target, - sai_object_id_t* rediect_oid); - - // Create user defined trap for each cpu queue/trap group and program user - // defined traps in hostif. Save the user defined trap oids in m_p4OidMapper - // and default ref count is 1. - ReturnCode setUpUserDefinedTraps(); - - // Clean up user defined traps created for cpu queues. Callers need to make - // sure ref count on user defined traps in m_userDefinedTraps are ones before - // clean up. - ReturnCode cleanUpUserDefinedTraps(); - - // Verifies internal cache for an entry. - std::string verifyStateCache(const P4AclRuleAppDbEntry& app_db_entry, - const P4AclRule* acl_rule); - - // Verifies ASIC DB for an entry. - std::string verifyStateAsicDb(const P4AclRule* acl_rule); - - P4OidMapper* m_p4OidMapper; - ResponsePublisherInterface* m_publisher; - P4AclRuleTables m_aclRuleTables; - VRFOrch* m_vrfOrch; - CoppOrch* m_coppOrch; - std::deque m_entries; - std::unique_ptr m_countersDb; - std::unique_ptr m_countersTable; - std::vector m_userDefinedTraps; - - friend class AclTableManager; - friend class p4orch::test::AclManagerTest; +} // namespace test + +class AclRuleManager : public ObjectManagerInterface +{ + public: + explicit AclRuleManager(P4OidMapper *p4oidMapper, VRFOrch *vrfOrch, CoppOrch *coppOrch, + ResponsePublisherInterface *publisher) + : m_p4OidMapper(p4oidMapper), m_vrfOrch(vrfOrch), m_publisher(publisher), m_coppOrch(coppOrch), + m_countersDb(std::make_unique("COUNTERS_DB", 0)), + m_countersTable(std::make_unique( + m_countersDb.get(), std::string(COUNTERS_TABLE) + DEFAULT_KEY_SEPARATOR + APP_P4RT_TABLE_NAME)) + { + SWSS_LOG_ENTER(); + assert(m_p4OidMapper != nullptr); + } + virtual ~AclRuleManager() = default; + + void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; + void drain() override; + std::string verifyState(const std::string &key, const std::vector &tuple) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; + + // Update counters stats for every rule in each ACL table in COUNTERS_DB, if + // counters are enabled in rules. + void doAclCounterStatsTask(); + + private: + // Deserializes an entry in a dynamically created ACL table. + ReturnCodeOr deserializeAclRuleAppDbEntry( + const std::string &acl_table_name, const std::string &key, + const std::vector &attributes); + + // Validate an ACL rule APP_DB entry. + ReturnCode validateAclRuleAppDbEntry(const P4AclRuleAppDbEntry &app_db_entry); + + // Get ACL rule by table name and rule key. Return nullptr if not found. + P4AclRule *getAclRule(const std::string &acl_table_name, const std::string &acl_rule_key); + + // Processes add operation for an ACL rule. + ReturnCode processAddRuleRequest(const std::string &acl_rule_key, const P4AclRuleAppDbEntry &app_db_entry); + + // Processes delete operation for an ACL rule. + ReturnCode processDeleteRuleRequest(const std::string &acl_table_name, const std::string &acl_rule_key); + + // Processes update operation for an ACL rule. + ReturnCode processUpdateRuleRequest(const P4AclRuleAppDbEntry &app_db_entry, const P4AclRule &old_acl_rule); + + // Set counters stats for an ACL rule in COUNTERS_DB. + ReturnCode setAclRuleCounterStats(const P4AclRule &acl_rule); + + // Create an ACL rule. + ReturnCode createAclRule(P4AclRule &acl_rule); + + // Create an ACL counter. + ReturnCode createAclCounter(const std::string &acl_table_name, const std::string &counter_key, + const P4AclRule &acl_rule, sai_object_id_t *counter_oid); + + // Create an ACL meter. + ReturnCode createAclMeter(const P4AclMeter &p4_acl_meter, const std::string &meter_key, sai_object_id_t *meter_oid); + + // Remove an ACL counter. + ReturnCode removeAclCounter(const std::string &acl_table_name, const std::string &counter_key); + + // Update ACL meter. + ReturnCode updateAclMeter(const P4AclMeter &new_acl_meter, const P4AclMeter &old_acl_meter); + + // Update ACL rule. + ReturnCode updateAclRule(const P4AclRule &new_acl_rule, const P4AclRule &old_acl_rule, + std::vector &acl_entry_attrs, + std::vector &rollback_attrs); + + // Remove an ACL meter. + ReturnCode removeAclMeter(const std::string &meter_key); + + // Remove the ACL rule by key in the given ACL table. + ReturnCode removeAclRule(const std::string &acl_table_name, const std::string &acl_rule_key); + + // Set Meter value in ACL rule. + ReturnCode setMeterValue(const P4AclTableDefinition *acl_table, const P4AclRuleAppDbEntry &app_db_entry, + P4AclMeter &acl_meter); + + // Validate and set all match attributes in an ACL rule. + ReturnCode setAllMatchFieldValues(const P4AclRuleAppDbEntry &app_db_entry, const P4AclTableDefinition *acl_table, + P4AclRule &acl_rules); + + // Validate and set all action attributes in an ACL rule. + ReturnCode setAllActionFieldValues(const P4AclRuleAppDbEntry &app_db_entry, const P4AclTableDefinition *acl_table, + P4AclRule &acl_rule); + + // Validate and set a match attribute in an ACL rule. + ReturnCode setMatchValue(const acl_entry_attr_union_t attr_name, const std::string &attr_value, + sai_attribute_value_t *value, P4AclRule *acl_rule, + const std::string &ip_type_bit_type = EMPTY_STRING); + + // Validate and set an action attribute in an ACL rule. + ReturnCode setActionValue(const acl_entry_attr_union_t attr_name, const std::string &attr_value, + sai_attribute_value_t *value, P4AclRule *acl_rule); + + // Get port object id by name for redirect action. + ReturnCode getRedirectActionPortOid(const std::string &target, sai_object_id_t *rediect_oid); + + // Get next hop object id by name for redirect action. + ReturnCode getRedirectActionNextHopOid(const std::string &target, sai_object_id_t *rediect_oid); + + // Create user defined trap for each cpu queue/trap group and program user + // defined traps in hostif. Save the user defined trap oids in m_p4OidMapper + // and default ref count is 1. + ReturnCode setUpUserDefinedTraps(); + + // Clean up user defined traps created for cpu queues. Callers need to make + // sure ref count on user defined traps in m_userDefinedTraps are ones before + // clean up. + ReturnCode cleanUpUserDefinedTraps(); + + // Verifies internal cache for an entry. + std::string verifyStateCache(const P4AclRuleAppDbEntry &app_db_entry, const P4AclRule *acl_rule); + + // Verifies ASIC DB for an entry. + std::string verifyStateAsicDb(const P4AclRule *acl_rule); + + P4OidMapper *m_p4OidMapper; + ResponsePublisherInterface *m_publisher; + P4AclRuleTables m_aclRuleTables; + VRFOrch *m_vrfOrch; + CoppOrch *m_coppOrch; + std::deque m_entries; + std::unique_ptr m_countersDb; + std::unique_ptr m_countersTable; + std::vector m_userDefinedTraps; + + friend class AclTableManager; + friend class p4orch::test::AclManagerTest; }; -} // namespace p4orch +} // namespace p4orch diff --git a/orchagent/p4orch/acl_table_manager.cpp b/orchagent/p4orch/acl_table_manager.cpp index c8a5eca112f..4a3910992ee 100644 --- a/orchagent/p4orch/acl_table_manager.cpp +++ b/orchagent/p4orch/acl_table_manager.cpp @@ -16,1268 +16,1266 @@ #include "switchorch.h" #include "table.h" #include "tokenize.h" -extern "C" { +extern "C" +{ #include "sai.h" } using ::p4orch::kTableKeyDelimiter; extern sai_object_id_t gSwitchId; -extern sai_acl_api_t* sai_acl_api; -extern sai_udf_api_t* sai_udf_api; -extern sai_switch_api_t* sai_switch_api; -extern CrmOrch* gCrmOrch; -extern P4Orch* gP4Orch; -extern SwitchOrch* gSwitchOrch; +extern sai_acl_api_t *sai_acl_api; +extern sai_udf_api_t *sai_udf_api; +extern sai_switch_api_t *sai_switch_api; +extern CrmOrch *gCrmOrch; +extern P4Orch *gP4Orch; +extern SwitchOrch *gSwitchOrch; extern int gBatchSize; -namespace p4orch { -namespace { +namespace p4orch +{ +namespace +{ -std::vector getGroupMemSaiAttrs( - const P4AclTableDefinition& acl_table) { - std::vector acl_mem_attrs; - sai_attribute_t acl_mem_attr; - acl_mem_attr.id = SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_GROUP_ID; - acl_mem_attr.value.oid = acl_table.group_oid; - acl_mem_attrs.push_back(acl_mem_attr); +std::vector getGroupMemSaiAttrs(const P4AclTableDefinition &acl_table) +{ + std::vector acl_mem_attrs; + sai_attribute_t acl_mem_attr; + acl_mem_attr.id = SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_GROUP_ID; + acl_mem_attr.value.oid = acl_table.group_oid; + acl_mem_attrs.push_back(acl_mem_attr); - acl_mem_attr.id = SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_ID; - acl_mem_attr.value.oid = acl_table.table_oid; - acl_mem_attrs.push_back(acl_mem_attr); + acl_mem_attr.id = SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_ID; + acl_mem_attr.value.oid = acl_table.table_oid; + acl_mem_attrs.push_back(acl_mem_attr); - acl_mem_attr.id = SAI_ACL_TABLE_GROUP_MEMBER_ATTR_PRIORITY; - acl_mem_attr.value.u32 = acl_table.priority; - acl_mem_attrs.push_back(acl_mem_attr); + acl_mem_attr.id = SAI_ACL_TABLE_GROUP_MEMBER_ATTR_PRIORITY; + acl_mem_attr.value.u32 = acl_table.priority; + acl_mem_attrs.push_back(acl_mem_attr); - return acl_mem_attrs; + return acl_mem_attrs; } -std::vector getUdfGroupSaiAttrs(const P4UdfField& udf_field) { - std::vector udf_group_attrs; - sai_attribute_t udf_group_attr; - udf_group_attr.id = SAI_UDF_GROUP_ATTR_TYPE; - udf_group_attr.value.s32 = SAI_UDF_GROUP_TYPE_GENERIC; - udf_group_attrs.push_back(udf_group_attr); +std::vector getUdfGroupSaiAttrs(const P4UdfField &udf_field) +{ + std::vector udf_group_attrs; + sai_attribute_t udf_group_attr; + udf_group_attr.id = SAI_UDF_GROUP_ATTR_TYPE; + udf_group_attr.value.s32 = SAI_UDF_GROUP_TYPE_GENERIC; + udf_group_attrs.push_back(udf_group_attr); - udf_group_attr.id = SAI_UDF_GROUP_ATTR_LENGTH; - udf_group_attr.value.u16 = udf_field.length; - udf_group_attrs.push_back(udf_group_attr); + udf_group_attr.id = SAI_UDF_GROUP_ATTR_LENGTH; + udf_group_attr.value.u16 = udf_field.length; + udf_group_attrs.push_back(udf_group_attr); - return udf_group_attrs; + return udf_group_attrs; } -} // namespace +} // namespace -AclTableManager::AclTableManager(P4OidMapper* p4oidMapper, - ResponsePublisherInterface* publisher) - : m_p4OidMapper(p4oidMapper), m_publisher(publisher) { - SWSS_LOG_ENTER(); +AclTableManager::AclTableManager(P4OidMapper *p4oidMapper, ResponsePublisherInterface *publisher) + : m_p4OidMapper(p4oidMapper), m_publisher(publisher) +{ + SWSS_LOG_ENTER(); - assert(p4oidMapper != nullptr); + assert(p4oidMapper != nullptr); } -AclTableManager::~AclTableManager() { - sai_object_id_t udf_match_oid; - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF_MATCH, P4_UDF_MATCH_DEFAULT, - &udf_match_oid)) { - return; - } - auto status = removeDefaultUdfMatch(); - if (!status.ok()) { - status.prepend("Failed to remove default UDF match: "); - SWSS_LOG_ERROR("%s", status.message().c_str()); - } +AclTableManager::~AclTableManager() +{ + sai_object_id_t udf_match_oid; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF_MATCH, P4_UDF_MATCH_DEFAULT, &udf_match_oid)) + { + return; + } + auto status = removeDefaultUdfMatch(); + if (!status.ok()) + { + status.prepend("Failed to remove default UDF match: "); + SWSS_LOG_ERROR("%s", status.message().c_str()); + } } -ReturnCodeOr> AclTableManager::getTableSaiAttrs( - const P4AclTableDefinition& acl_table) { - std::vector acl_attr_list; - sai_attribute_t acl_attr; - acl_attr.id = SAI_ACL_TABLE_ATTR_ACL_STAGE; - acl_attr.value.s32 = acl_table.stage; - acl_attr_list.push_back(acl_attr); - - if (acl_table.size > 0) { - acl_attr.id = SAI_ACL_TABLE_ATTR_SIZE; - acl_attr.value.u32 = acl_table.size; +ReturnCodeOr> AclTableManager::getTableSaiAttrs(const P4AclTableDefinition &acl_table) +{ + std::vector acl_attr_list; + sai_attribute_t acl_attr; + acl_attr.id = SAI_ACL_TABLE_ATTR_ACL_STAGE; + acl_attr.value.s32 = acl_table.stage; acl_attr_list.push_back(acl_attr); - } - std::set table_match_fields_to_add; - if (!acl_table.ip_type_bit_type_lookup.empty()) { - acl_attr.id = SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE; - acl_attr.value.booldata = true; - acl_attr_list.push_back(acl_attr); - table_match_fields_to_add.insert(SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE); - } - - for (const auto& match_field : acl_table.sai_match_field_lookup) { - const auto& sai_match_field = fvValue(match_field); - // Avoid duplicate match attribute to add - if (table_match_fields_to_add.find(sai_match_field.table_attr) != - table_match_fields_to_add.end()) - continue; - acl_attr.id = sai_match_field.table_attr; - acl_attr.value.booldata = true; - acl_attr_list.push_back(acl_attr); - table_match_fields_to_add.insert(sai_match_field.table_attr); - } - - for (const auto& match_fields : acl_table.composite_sai_match_fields_lookup) { - const auto& sai_match_fields = fvValue(match_fields); - for (const auto& sai_match_field : sai_match_fields) { - // Avoid duplicate match attribute to add - if (table_match_fields_to_add.find(sai_match_field.table_attr) != - table_match_fields_to_add.end()) - continue; - acl_attr.id = sai_match_field.table_attr; - acl_attr.value.booldata = true; - acl_attr_list.push_back(acl_attr); - table_match_fields_to_add.insert(sai_match_field.table_attr); - } - } - - // Add UDF group attributes - for (const auto& udf_group_idx : acl_table.udf_group_attr_index_lookup) { - acl_attr.id = SAI_ACL_TABLE_ATTR_USER_DEFINED_FIELD_GROUP_MIN + - fvValue(udf_group_idx); - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF_GROUP, - fvField(udf_group_idx), &acl_attr.value.oid)) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "THe UDF group with id " - << QuotedVar(fvField(udf_group_idx)) - << " was not found."); + if (acl_table.size > 0) + { + acl_attr.id = SAI_ACL_TABLE_ATTR_SIZE; + acl_attr.value.u32 = acl_table.size; + acl_attr_list.push_back(acl_attr); } - acl_attr_list.push_back(acl_attr); - } - m_acl_action_list[0] = SAI_ACL_ACTION_TYPE_COUNTER; - acl_attr.id = SAI_ACL_TABLE_ATTR_ACL_ACTION_TYPE_LIST; - acl_attr.value.s32list.count = 1; - acl_attr.value.s32list.list = m_acl_action_list; - acl_attr_list.push_back(acl_attr); + std::set table_match_fields_to_add; + if (!acl_table.ip_type_bit_type_lookup.empty()) + { + acl_attr.id = SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE; + acl_attr.value.booldata = true; + acl_attr_list.push_back(acl_attr); + table_match_fields_to_add.insert(SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE); + } - return acl_attr_list; -} + for (const auto &match_field : acl_table.sai_match_field_lookup) + { + const auto &sai_match_field = fvValue(match_field); + // Avoid duplicate match attribute to add + if (table_match_fields_to_add.find(sai_match_field.table_attr) != table_match_fields_to_add.end()) + continue; + acl_attr.id = sai_match_field.table_attr; + acl_attr.value.booldata = true; + acl_attr_list.push_back(acl_attr); + table_match_fields_to_add.insert(sai_match_field.table_attr); + } -ReturnCodeOr> AclTableManager::getUdfSaiAttrs( - const P4UdfField& udf_field) { - sai_object_id_t udf_group_oid; - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF_GROUP, udf_field.group_id, - &udf_group_oid)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "UDF group " << QuotedVar(udf_field.group_id) - << " does not exist"; - } - sai_object_id_t udf_match_oid; - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF_MATCH, P4_UDF_MATCH_DEFAULT, - &udf_match_oid)) { - // Create the default UDF match - LOG_AND_RETURN_IF_ERROR(createDefaultUdfMatch() - << "Failed to create ACL UDF default match " - << QuotedVar(P4_UDF_MATCH_DEFAULT)); - m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF_MATCH, P4_UDF_MATCH_DEFAULT, - &udf_match_oid); - } - std::vector udf_attrs; - sai_attribute_t udf_attr; - udf_attr.id = SAI_UDF_ATTR_GROUP_ID; - udf_attr.value.oid = udf_group_oid; - udf_attrs.push_back(udf_attr); - - udf_attr.id = SAI_UDF_ATTR_MATCH_ID; - udf_attr.value.oid = udf_match_oid; - udf_attrs.push_back(udf_attr); - - udf_attr.id = SAI_UDF_ATTR_BASE; - udf_attr.value.s32 = udf_field.base; - udf_attrs.push_back(udf_attr); - - udf_attr.id = SAI_UDF_ATTR_OFFSET; - udf_attr.value.u16 = udf_field.offset; - udf_attrs.push_back(udf_attr); - - return udf_attrs; -} + for (const auto &match_fields : acl_table.composite_sai_match_fields_lookup) + { + const auto &sai_match_fields = fvValue(match_fields); + for (const auto &sai_match_field : sai_match_fields) + { + // Avoid duplicate match attribute to add + if (table_match_fields_to_add.find(sai_match_field.table_attr) != table_match_fields_to_add.end()) + continue; + acl_attr.id = sai_match_field.table_attr; + acl_attr.value.booldata = true; + acl_attr_list.push_back(acl_attr); + table_match_fields_to_add.insert(sai_match_field.table_attr); + } + } -ReturnCode AclTableManager::getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) { - return StatusCode::SWSS_RC_UNIMPLEMENTED; + // Add UDF group attributes + for (const auto &udf_group_idx : acl_table.udf_group_attr_index_lookup) + { + acl_attr.id = SAI_ACL_TABLE_ATTR_USER_DEFINED_FIELD_GROUP_MIN + fvValue(udf_group_idx); + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF_GROUP, fvField(udf_group_idx), &acl_attr.value.oid)) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "THe UDF group with id " << QuotedVar(fvField(udf_group_idx)) << " was not found."); + } + acl_attr_list.push_back(acl_attr); + } + + m_acl_action_list[0] = SAI_ACL_ACTION_TYPE_COUNTER; + acl_attr.id = SAI_ACL_TABLE_ATTR_ACL_ACTION_TYPE_LIST; + acl_attr.value.s32list.count = 1; + acl_attr.value.s32list.list = m_acl_action_list; + acl_attr_list.push_back(acl_attr); + + return acl_attr_list; } -void AclTableManager::enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) { - m_entries.push_back(entry); +ReturnCodeOr> AclTableManager::getUdfSaiAttrs(const P4UdfField &udf_field) +{ + sai_object_id_t udf_group_oid; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF_GROUP, udf_field.group_id, &udf_group_oid)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "UDF group " << QuotedVar(udf_field.group_id) << " does not exist"; + } + sai_object_id_t udf_match_oid; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF_MATCH, P4_UDF_MATCH_DEFAULT, &udf_match_oid)) + { + // Create the default UDF match + LOG_AND_RETURN_IF_ERROR(createDefaultUdfMatch() + << "Failed to create ACL UDF default match " << QuotedVar(P4_UDF_MATCH_DEFAULT)); + m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF_MATCH, P4_UDF_MATCH_DEFAULT, &udf_match_oid); + } + std::vector udf_attrs; + sai_attribute_t udf_attr; + udf_attr.id = SAI_UDF_ATTR_GROUP_ID; + udf_attr.value.oid = udf_group_oid; + udf_attrs.push_back(udf_attr); + + udf_attr.id = SAI_UDF_ATTR_MATCH_ID; + udf_attr.value.oid = udf_match_oid; + udf_attrs.push_back(udf_attr); + + udf_attr.id = SAI_UDF_ATTR_BASE; + udf_attr.value.s32 = udf_field.base; + udf_attrs.push_back(udf_attr); + + udf_attr.id = SAI_UDF_ATTR_OFFSET; + udf_attr.value.u16 = udf_field.offset; + udf_attrs.push_back(udf_attr); + + return udf_attrs; } -void AclTableManager::drain() { - SWSS_LOG_ENTER(); +ReturnCode AclTableManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) +{ + return StatusCode::SWSS_RC_UNIMPLEMENTED; +} - for (const auto& key_op_fvs_tuple : m_entries) { - std::string table_name; - std::string db_key; - parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &db_key); - SWSS_LOG_NOTICE("P4AclTableManager drain tuple for table %s", - QuotedVar(table_name).c_str()); - if (table_name != APP_P4RT_ACL_TABLE_DEFINITION_NAME) { - ReturnCode status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid table " << QuotedVar(table_name); - SWSS_LOG_ERROR("%s", status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - const std::vector& attributes = - kfvFieldsValues(key_op_fvs_tuple); +void AclTableManager::enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) +{ + m_entries.push_back(entry); +} - ReturnCode status; - const std::string& operation = kfvOp(key_op_fvs_tuple); - if (operation == SET_COMMAND) { - auto app_db_entry_or = - deserializeAclTableDefinitionAppDbEntry(db_key, attributes); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", - QuotedVar(table_name + ":" + db_key).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - auto& app_db_entry = *app_db_entry_or; - - status = validateAclTableDefinitionAppDbEntry(app_db_entry); - if (!status.ok()) { - SWSS_LOG_ERROR( - "Validation failed for ACL definition APP DB entry with key %s: %s", - QuotedVar(table_name + ":" + db_key).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, +void AclTableManager::drain() +{ + SWSS_LOG_ENTER(); + + for (const auto &key_op_fvs_tuple : m_entries) + { + std::string table_name; + std::string db_key; + parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &db_key); + SWSS_LOG_NOTICE("P4AclTableManager drain tuple for table %s", QuotedVar(table_name).c_str()); + if (table_name != APP_P4RT_ACL_TABLE_DEFINITION_NAME) + { + ReturnCode status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid table " << QuotedVar(table_name); + SWSS_LOG_ERROR("%s", status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + const std::vector &attributes = kfvFieldsValues(key_op_fvs_tuple); + + ReturnCode status; + const std::string &operation = kfvOp(key_op_fvs_tuple); + if (operation == SET_COMMAND) + { + auto app_db_entry_or = deserializeAclTableDefinitionAppDbEntry(db_key, attributes); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", + QuotedVar(table_name + ":" + db_key).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + auto &app_db_entry = *app_db_entry_or; + + status = validateAclTableDefinitionAppDbEntry(app_db_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Validation failed for ACL definition APP DB entry with key %s: %s", + QuotedVar(table_name + ":" + db_key).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + auto *acl_table_definition = getAclTable(app_db_entry.acl_table_name); + if (acl_table_definition == nullptr) + { + SWSS_LOG_NOTICE("ACL table SET %s", app_db_entry.acl_table_name.c_str()); + status = processAddTableRequest(app_db_entry); + } + else + { + // All attributes in sai_acl_table_attr_t are CREATE_ONLY. + status = ReturnCode(StatusCode::SWSS_RC_UNIMPLEMENTED) + << "Unable to update ACL table definition in APP DB entry with key " + << QuotedVar(table_name + ":" + db_key) + << " : All attributes in sai_acl_table_attr_t are CREATE_ONLY."; + } + } + else if (operation == DEL_COMMAND) + { + status = processDeleteTableRequest(db_key); + } + else + { + status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Unknown operation type " << QuotedVar(operation); + } + if (!status.ok()) + { + SWSS_LOG_ERROR("Processed DEFINITION entry status: %s", status.message().c_str()); + } + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), status, /*replace=*/true); - continue; - } - auto* acl_table_definition = getAclTable(app_db_entry.acl_table_name); - if (acl_table_definition == nullptr) { - SWSS_LOG_NOTICE("ACL table SET %s", - app_db_entry.acl_table_name.c_str()); - status = processAddTableRequest(app_db_entry); - } else { - // All attributes in sai_acl_table_attr_t are CREATE_ONLY. - status = - ReturnCode(StatusCode::SWSS_RC_UNIMPLEMENTED) - << "Unable to update ACL table definition in APP DB entry with key " - << QuotedVar(table_name + ":" + db_key) - << " : All attributes in sai_acl_table_attr_t are CREATE_ONLY."; - } - } else if (operation == DEL_COMMAND) { - status = processDeleteTableRequest(db_key); - } else { - status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown operation type " << QuotedVar(operation); - } - if (!status.ok()) { - SWSS_LOG_ERROR("Processed DEFINITION entry status: %s", - status.message().c_str()); - } - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - } - m_entries.clear(); + } + m_entries.clear(); } -ReturnCodeOr -AclTableManager::deserializeAclTableDefinitionAppDbEntry( - const std::string& key, - const std::vector& attributes) { - SWSS_LOG_ENTER(); - - P4AclTableDefinitionAppDbEntry app_db_entry = {}; - app_db_entry.acl_table_name = key; - - for (const auto& it : attributes) { - const auto& field = fvField(it); - const auto& value = fvValue(it); - SWSS_LOG_INFO("ACL table definition attr string %s : %s\n", - QuotedVar(field).c_str(), QuotedVar(value).c_str()); - if (field == kStage) { - app_db_entry.stage = value; - continue; - } else if (field == kPriority) { - int priority = std::stoi(value); - if (priority < 0) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid ACL table priority " << QuotedVar(value); - } - app_db_entry.priority = static_cast(priority); - continue; - } else if (field == kSize) { - int size = std::stoi(value); - if (size < 0) { +ReturnCodeOr AclTableManager::deserializeAclTableDefinitionAppDbEntry( + const std::string &key, const std::vector &attributes) +{ + SWSS_LOG_ENTER(); + + P4AclTableDefinitionAppDbEntry app_db_entry = {}; + app_db_entry.acl_table_name = key; + + for (const auto &it : attributes) + { + const auto &field = fvField(it); + const auto &value = fvValue(it); + SWSS_LOG_INFO("ACL table definition attr string %s : %s\n", QuotedVar(field).c_str(), QuotedVar(value).c_str()); + if (field == kStage) + { + app_db_entry.stage = value; + continue; + } + else if (field == kPriority) + { + int priority = std::stoi(value); + if (priority < 0) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid ACL table priority " << QuotedVar(value); + } + app_db_entry.priority = static_cast(priority); + continue; + } + else if (field == kSize) + { + int size = std::stoi(value); + if (size < 0) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Invalid ACL table size " << QuotedVar(value); + } + app_db_entry.size = static_cast(size); + continue; + } + else if (field == kMeterUnit) + { + app_db_entry.meter_unit = value; + continue; + } + else if (field == kCounterUnit) + { + app_db_entry.counter_unit = value; + continue; + } + std::vector tokenized_field = swss::tokenize(field, kFieldDelimiter); + if (tokenized_field.size() <= 1) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unknown ACL table definition field string " << QuotedVar(field); + } + const auto &p4_field = tokenized_field[1]; + if (tokenized_field[0] == kMatchPrefix) + { + app_db_entry.match_field_lookup[p4_field] = value; + } + else if (tokenized_field[0] == kAction) + { + if (!parseAclTableAppDbActionField(value, &app_db_entry.action_field_lookup[p4_field], + &app_db_entry.packet_action_color_lookup[p4_field])) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Error parsing ACL table definition action " << QuotedVar(field) << ":" << QuotedVar(value); + } + } + else + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unknown ACL table definition field string " << QuotedVar(field); + } + } + return app_db_entry; +} + +ReturnCode AclTableManager::validateAclTableDefinitionAppDbEntry(const P4AclTableDefinitionAppDbEntry &app_db_entry) +{ + // Perform generic APP DB entry validations. Operation specific + // validations will be done by the respective request process methods. + if (!app_db_entry.meter_unit.empty() && app_db_entry.meter_unit != P4_METER_UNIT_BYTES && + app_db_entry.meter_unit != P4_METER_UNIT_PACKETS) + { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid ACL table size " << QuotedVar(value); - } - app_db_entry.size = static_cast(size); - continue; - } else if (field == kMeterUnit) { - app_db_entry.meter_unit = value; - continue; - } else if (field == kCounterUnit) { - app_db_entry.counter_unit = value; - continue; - } - std::vector tokenized_field = - swss::tokenize(field, kFieldDelimiter); - if (tokenized_field.size() <= 1) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown ACL table definition field string " - << QuotedVar(field); - } - const auto& p4_field = tokenized_field[1]; - if (tokenized_field[0] == kMatchPrefix) { - app_db_entry.match_field_lookup[p4_field] = value; - } else if (tokenized_field[0] == kAction) { - if (!parseAclTableAppDbActionField( - value, &app_db_entry.action_field_lookup[p4_field], - &app_db_entry.packet_action_color_lookup[p4_field])) { + << "ACL table meter unit " << QuotedVar(app_db_entry.meter_unit) << " is invalid"; + } + if (!app_db_entry.counter_unit.empty() && app_db_entry.counter_unit != P4_COUNTER_UNIT_BYTES && + app_db_entry.counter_unit != P4_COUNTER_UNIT_PACKETS && app_db_entry.counter_unit != P4_COUNTER_UNIT_BOTH) + { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Error parsing ACL table definition action " - << QuotedVar(field) << ":" << QuotedVar(value); - } - } else { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown ACL table definition field string " - << QuotedVar(field); - } - } - return app_db_entry; + << "ACL table counter unit " << QuotedVar(app_db_entry.counter_unit) << " is invalid"; + } + return ReturnCode(); } -ReturnCode AclTableManager::validateAclTableDefinitionAppDbEntry( - const P4AclTableDefinitionAppDbEntry& app_db_entry) { - // Perform generic APP DB entry validations. Operation specific - // validations will be done by the respective request process methods. - if (!app_db_entry.meter_unit.empty() && - app_db_entry.meter_unit != P4_METER_UNIT_BYTES && - app_db_entry.meter_unit != P4_METER_UNIT_PACKETS) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table meter unit " << QuotedVar(app_db_entry.meter_unit) - << " is invalid"; - } - if (!app_db_entry.counter_unit.empty() && - app_db_entry.counter_unit != P4_COUNTER_UNIT_BYTES && - app_db_entry.counter_unit != P4_COUNTER_UNIT_PACKETS && - app_db_entry.counter_unit != P4_COUNTER_UNIT_BOTH) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table counter unit " << QuotedVar(app_db_entry.counter_unit) - << " is invalid"; - } - return ReturnCode(); +P4AclTableDefinition *AclTableManager::getAclTable(const std::string &acl_table_name) +{ + SWSS_LOG_ENTER(); + if (m_aclTableDefinitions.find(acl_table_name) == m_aclTableDefinitions.end()) + return nullptr; + return &m_aclTableDefinitions[acl_table_name]; } -P4AclTableDefinition* AclTableManager::getAclTable( - const std::string& acl_table_name) { - SWSS_LOG_ENTER(); - if (m_aclTableDefinitions.find(acl_table_name) == m_aclTableDefinitions.end()) - return nullptr; - return &m_aclTableDefinitions[acl_table_name]; -} +ReturnCode AclTableManager::processAddTableRequest(const P4AclTableDefinitionAppDbEntry &app_db_entry) +{ + SWSS_LOG_ENTER(); + + auto stage_it = aclStageLookup.find(app_db_entry.stage); + sai_acl_stage_t stage; + if (stage_it != aclStageLookup.end()) + { + stage = stage_it->second; + } + else + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table stage " << QuotedVar(app_db_entry.stage) << " is invalid"); + } + + if (gSwitchOrch->getAclGroupsBindingToSwitch().empty()) + { + // Create default ACL groups binding to switch + gSwitchOrch->initAclGroupsBindToSwitch(); + } + + P4AclTableDefinition acl_table_definition(app_db_entry.acl_table_name, stage, app_db_entry.priority, + app_db_entry.size, app_db_entry.meter_unit, app_db_entry.counter_unit); + + auto &group_map = gSwitchOrch->getAclGroupsBindingToSwitch(); + auto group_it = group_map.find(acl_table_definition.stage); + if (group_it == group_map.end()) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Failed to find ACL group binding to switch at stage " + << acl_table_definition.stage); + } + acl_table_definition.group_oid = group_it->second.m_saiObjectId; + + auto build_match_rc = + buildAclTableDefinitionMatchFieldValues(app_db_entry.match_field_lookup, &acl_table_definition); -ReturnCode AclTableManager::processAddTableRequest( - const P4AclTableDefinitionAppDbEntry& app_db_entry) { - SWSS_LOG_ENTER(); - - auto stage_it = aclStageLookup.find(app_db_entry.stage); - sai_acl_stage_t stage; - if (stage_it != aclStageLookup.end()) { - stage = stage_it->second; - } else { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table stage " << QuotedVar(app_db_entry.stage) - << " is invalid"); - } - - if (gSwitchOrch->getAclGroupsBindingToSwitch().empty()) { - // Create default ACL groups binding to switch - gSwitchOrch->initAclGroupsBindToSwitch(); - } - - P4AclTableDefinition acl_table_definition( - app_db_entry.acl_table_name, stage, app_db_entry.priority, - app_db_entry.size, app_db_entry.meter_unit, app_db_entry.counter_unit); - - auto& group_map = gSwitchOrch->getAclGroupsBindingToSwitch(); - auto group_it = group_map.find(acl_table_definition.stage); - if (group_it == group_map.end()) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Failed to find ACL group binding to switch at stage " - << acl_table_definition.stage); - } - acl_table_definition.group_oid = group_it->second.m_saiObjectId; - - auto build_match_rc = buildAclTableDefinitionMatchFieldValues( - app_db_entry.match_field_lookup, &acl_table_definition); - - LOG_AND_RETURN_IF_ERROR(build_match_rc.prepend( - "Failed to build ACL table definition match fields with table name " + - QuotedVar(app_db_entry.acl_table_name) + ": ")); - - auto build_action_rc = buildAclTableDefinitionActionFieldValues( - app_db_entry.action_field_lookup, - &acl_table_definition.rule_action_field_lookup); - - LOG_AND_RETURN_IF_ERROR(build_action_rc.prepend( - "Failed to build ACL table definition action fields with table name " + - QuotedVar(app_db_entry.acl_table_name) + ": ")); - - if (gP4Orch->getAclRuleManager()->m_userDefinedTraps.empty() && - isSetUserTrapActionInAclTableDefinition( - acl_table_definition.rule_action_field_lookup)) { - // Set up User Defined Traps for QOS_QUEUE action - auto status = gP4Orch->getAclRuleManager()->setUpUserDefinedTraps(); - if (!status.ok()) { - gP4Orch->getAclRuleManager()->cleanUpUserDefinedTraps(); - LOG_ERROR_AND_RETURN(status); - } - } - - auto build_action_color_rc = buildAclTableDefinitionActionColorFieldValues( - app_db_entry.packet_action_color_lookup, - &acl_table_definition.rule_action_field_lookup, - &acl_table_definition.rule_packet_action_color_lookup); - LOG_AND_RETURN_IF_ERROR(build_action_color_rc.prepend( - "Failed to build ACL table definition " - "action color fields with table name " + - QuotedVar(app_db_entry.acl_table_name) + ": ")); - - if (!acl_table_definition.udf_fields_lookup.empty()) { LOG_AND_RETURN_IF_ERROR( - createUdfGroupsAndUdfsForAclTable(acl_table_definition)); - } - - auto status = - createAclTable(acl_table_definition, &acl_table_definition.table_oid, - &acl_table_definition.group_member_oid); - if (!status.ok()) { - // Clean up newly created UDFs and UDF groups - for (auto& udf_fields : acl_table_definition.udf_fields_lookup) { - for (auto& udf_field : fvValue(udf_fields)) { - auto rc = removeUdf(udf_field.udf_id, udf_field.group_id); - if (!rc.ok()) { - SWSS_LOG_ERROR("Failed to remove UDF %s: %s", - QuotedVar(udf_field.udf_id).c_str(), - rc.message().c_str()); - SWSS_RAISE_CRITICAL_STATE("Failed to remove UDF in recovery."); + build_match_rc.prepend("Failed to build ACL table definition match fields with table name " + + QuotedVar(app_db_entry.acl_table_name) + ": ")); + + auto build_action_rc = buildAclTableDefinitionActionFieldValues(app_db_entry.action_field_lookup, + &acl_table_definition.rule_action_field_lookup); + + LOG_AND_RETURN_IF_ERROR( + build_action_rc.prepend("Failed to build ACL table definition action fields with table name " + + QuotedVar(app_db_entry.acl_table_name) + ": ")); + + if (gP4Orch->getAclRuleManager()->m_userDefinedTraps.empty() && + isSetUserTrapActionInAclTableDefinition(acl_table_definition.rule_action_field_lookup)) + { + // Set up User Defined Traps for QOS_QUEUE action + auto status = gP4Orch->getAclRuleManager()->setUpUserDefinedTraps(); + if (!status.ok()) + { + gP4Orch->getAclRuleManager()->cleanUpUserDefinedTraps(); + LOG_ERROR_AND_RETURN(status); } - rc = removeUdfGroup(udf_field.group_id); - if (!rc.ok()) { - SWSS_LOG_ERROR("Failed to remove UDF group %s: %s", - QuotedVar(udf_field.group_id).c_str(), - rc.message().c_str()); - SWSS_RAISE_CRITICAL_STATE("Failed to remove UDF group in recovery."); + } + + auto build_action_color_rc = buildAclTableDefinitionActionColorFieldValues( + app_db_entry.packet_action_color_lookup, &acl_table_definition.rule_action_field_lookup, + &acl_table_definition.rule_packet_action_color_lookup); + LOG_AND_RETURN_IF_ERROR(build_action_color_rc.prepend("Failed to build ACL table definition " + "action color fields with table name " + + QuotedVar(app_db_entry.acl_table_name) + ": ")); + + if (!acl_table_definition.udf_fields_lookup.empty()) + { + LOG_AND_RETURN_IF_ERROR(createUdfGroupsAndUdfsForAclTable(acl_table_definition)); + } + + auto status = + createAclTable(acl_table_definition, &acl_table_definition.table_oid, &acl_table_definition.group_member_oid); + if (!status.ok()) + { + // Clean up newly created UDFs and UDF groups + for (auto &udf_fields : acl_table_definition.udf_fields_lookup) + { + for (auto &udf_field : fvValue(udf_fields)) + { + auto rc = removeUdf(udf_field.udf_id, udf_field.group_id); + if (!rc.ok()) + { + SWSS_LOG_ERROR("Failed to remove UDF %s: %s", QuotedVar(udf_field.udf_id).c_str(), + rc.message().c_str()); + SWSS_RAISE_CRITICAL_STATE("Failed to remove UDF in recovery."); + } + rc = removeUdfGroup(udf_field.group_id); + if (!rc.ok()) + { + SWSS_LOG_ERROR("Failed to remove UDF group %s: %s", QuotedVar(udf_field.group_id).c_str(), + rc.message().c_str()); + SWSS_RAISE_CRITICAL_STATE("Failed to remove UDF group in recovery."); + } + } } - } + LOG_ERROR_AND_RETURN( + status.prepend("Failed to create ACL table with key " + QuotedVar(app_db_entry.acl_table_name))); } - LOG_ERROR_AND_RETURN( - status.prepend("Failed to create ACL table with key " + - QuotedVar(app_db_entry.acl_table_name))); - } - return status; + return status; } -ReturnCode AclTableManager::createDefaultUdfMatch() { - SWSS_LOG_ENTER(); - sai_object_id_t udf_match_oid; - std::vector udf_match_attrs; - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_udf_api->create_udf_match(&udf_match_oid, gSwitchId, 0, - udf_match_attrs.data()), - "Failed to create default UDF match from SAI call " - "sai_udf_api->create_udf_match"); - m_p4OidMapper->setOID(SAI_OBJECT_TYPE_UDF_MATCH, P4_UDF_MATCH_DEFAULT, - udf_match_oid); - SWSS_LOG_INFO("Suceeded to create default UDF match %s with object ID %s ", - QuotedVar(P4_UDF_MATCH_DEFAULT).c_str(), - sai_serialize_object_id(udf_match_oid).c_str()); - return ReturnCode(); +ReturnCode AclTableManager::createDefaultUdfMatch() +{ + SWSS_LOG_ENTER(); + sai_object_id_t udf_match_oid; + std::vector udf_match_attrs; + CHECK_ERROR_AND_LOG_AND_RETURN(sai_udf_api->create_udf_match(&udf_match_oid, gSwitchId, 0, udf_match_attrs.data()), + "Failed to create default UDF match from SAI call " + "sai_udf_api->create_udf_match"); + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_UDF_MATCH, P4_UDF_MATCH_DEFAULT, udf_match_oid); + SWSS_LOG_INFO("Suceeded to create default UDF match %s with object ID %s ", QuotedVar(P4_UDF_MATCH_DEFAULT).c_str(), + sai_serialize_object_id(udf_match_oid).c_str()); + return ReturnCode(); } -ReturnCode AclTableManager::removeDefaultUdfMatch() { - SWSS_LOG_ENTER(); - sai_object_id_t udf_match_oid; - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF_MATCH, P4_UDF_MATCH_DEFAULT, - &udf_match_oid)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Default UDF match " << QuotedVar(P4_UDF_MATCH_DEFAULT) - << " was not found"; - } - - // Check if there is anything referring to the UDF match before deletion. - uint32_t ref_count; - if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_UDF_MATCH, - P4_UDF_MATCH_DEFAULT, &ref_count)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Default UDF match " << QuotedVar(P4_UDF_MATCH_DEFAULT) - << " reference count was not found"; - } - if (ref_count > 0) { - return ReturnCode(StatusCode::SWSS_RC_IN_USE) - << "Default UDF match " << QuotedVar(P4_UDF_MATCH_DEFAULT) - << " is referenced by other objects (ref_count = " << ref_count - << ")"; - } - - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_udf_api->remove_udf_match(udf_match_oid), - "Failed to remove default UDF match with id " << udf_match_oid); - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_UDF_MATCH, P4_UDF_MATCH_DEFAULT); - - SWSS_LOG_INFO("Suceeded to remove UDF match %s : %s", - QuotedVar(P4_UDF_MATCH_DEFAULT).c_str(), - sai_serialize_object_id(udf_match_oid).c_str()); - return ReturnCode(); +ReturnCode AclTableManager::removeDefaultUdfMatch() +{ + SWSS_LOG_ENTER(); + sai_object_id_t udf_match_oid; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF_MATCH, P4_UDF_MATCH_DEFAULT, &udf_match_oid)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Default UDF match " << QuotedVar(P4_UDF_MATCH_DEFAULT) << " was not found"; + } + + // Check if there is anything referring to the UDF match before deletion. + uint32_t ref_count; + if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_UDF_MATCH, P4_UDF_MATCH_DEFAULT, &ref_count)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Default UDF match " << QuotedVar(P4_UDF_MATCH_DEFAULT) << " reference count was not found"; + } + if (ref_count > 0) + { + return ReturnCode(StatusCode::SWSS_RC_IN_USE) + << "Default UDF match " << QuotedVar(P4_UDF_MATCH_DEFAULT) + << " is referenced by other objects (ref_count = " << ref_count << ")"; + } + + CHECK_ERROR_AND_LOG_AND_RETURN(sai_udf_api->remove_udf_match(udf_match_oid), + "Failed to remove default UDF match with id " << udf_match_oid); + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_UDF_MATCH, P4_UDF_MATCH_DEFAULT); + + SWSS_LOG_INFO("Suceeded to remove UDF match %s : %s", QuotedVar(P4_UDF_MATCH_DEFAULT).c_str(), + sai_serialize_object_id(udf_match_oid).c_str()); + return ReturnCode(); } -ReturnCode AclTableManager::createUdfGroup(const P4UdfField& udf_field) { - SWSS_LOG_ENTER(); - sai_object_id_t udf_group_oid; - auto attrs = getUdfGroupSaiAttrs(udf_field); - - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_udf_api->create_udf_group(&udf_group_oid, gSwitchId, - (uint32_t)attrs.size(), attrs.data()), - "Failed to create UDF group " - << QuotedVar(udf_field.group_id) - << " from SAI call sai_udf_api->create_udf_group"); - m_p4OidMapper->setOID(SAI_OBJECT_TYPE_UDF_GROUP, udf_field.group_id, - udf_group_oid); - SWSS_LOG_INFO("Suceeded to create UDF group %s with object ID %s ", - QuotedVar(udf_field.group_id).c_str(), - sai_serialize_object_id(udf_group_oid).c_str()); - return ReturnCode(); +ReturnCode AclTableManager::createUdfGroup(const P4UdfField &udf_field) +{ + SWSS_LOG_ENTER(); + sai_object_id_t udf_group_oid; + auto attrs = getUdfGroupSaiAttrs(udf_field); + + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_udf_api->create_udf_group(&udf_group_oid, gSwitchId, (uint32_t)attrs.size(), attrs.data()), + "Failed to create UDF group " << QuotedVar(udf_field.group_id) + << " from SAI call sai_udf_api->create_udf_group"); + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_UDF_GROUP, udf_field.group_id, udf_group_oid); + SWSS_LOG_INFO("Suceeded to create UDF group %s with object ID %s ", QuotedVar(udf_field.group_id).c_str(), + sai_serialize_object_id(udf_group_oid).c_str()); + return ReturnCode(); } -ReturnCode AclTableManager::removeUdfGroup(const std::string& udf_group_id) { - SWSS_LOG_ENTER(); - sai_object_id_t group_oid; - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF_GROUP, udf_group_id, - &group_oid)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "UDF group " << QuotedVar(udf_group_id) << " was not found"; - } - - // Check if there is anything referring to the UDF group before deletion. - uint32_t ref_count; - if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_UDF_GROUP, udf_group_id, - &ref_count)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "UDF group " << QuotedVar(udf_group_id) - << " reference count was not found"; - } - if (ref_count > 0) { - return ReturnCode(StatusCode::SWSS_RC_IN_USE) - << "UDF group " << QuotedVar(udf_group_id) - << " referenced by other objects (ref_count = " << ref_count << ")"; - } - - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_udf_api->remove_udf_group(group_oid), - "Failed to remove UDF group with id " << QuotedVar(udf_group_id)); - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_UDF_GROUP, udf_group_id); - - SWSS_LOG_NOTICE("Suceeded to remove UDF group %s: %s", - QuotedVar(udf_group_id).c_str(), - sai_serialize_object_id(group_oid).c_str()); - return ReturnCode(); +ReturnCode AclTableManager::removeUdfGroup(const std::string &udf_group_id) +{ + SWSS_LOG_ENTER(); + sai_object_id_t group_oid; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF_GROUP, udf_group_id, &group_oid)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) << "UDF group " << QuotedVar(udf_group_id) << " was not found"; + } + + // Check if there is anything referring to the UDF group before deletion. + uint32_t ref_count; + if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_UDF_GROUP, udf_group_id, &ref_count)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "UDF group " << QuotedVar(udf_group_id) << " reference count was not found"; + } + if (ref_count > 0) + { + return ReturnCode(StatusCode::SWSS_RC_IN_USE) + << "UDF group " << QuotedVar(udf_group_id) << " referenced by other objects (ref_count = " << ref_count + << ")"; + } + + CHECK_ERROR_AND_LOG_AND_RETURN(sai_udf_api->remove_udf_group(group_oid), + "Failed to remove UDF group with id " << QuotedVar(udf_group_id)); + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_UDF_GROUP, udf_group_id); + + SWSS_LOG_NOTICE("Suceeded to remove UDF group %s: %s", QuotedVar(udf_group_id).c_str(), + sai_serialize_object_id(group_oid).c_str()); + return ReturnCode(); } -ReturnCode AclTableManager::createUdf(const P4UdfField& udf_field) { - SWSS_LOG_ENTER(); - const auto& udf_id = udf_field.udf_id; - - ASSIGN_OR_RETURN(auto attrs, getUdfSaiAttrs(udf_field)); - - sai_object_id_t udf_oid; - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_udf_api->create_udf(&udf_oid, gSwitchId, (uint32_t)attrs.size(), - attrs.data()), - "Failed to create UDF " << QuotedVar(udf_id) - << " from SAI call sai_udf_api->create_udf"); - m_p4OidMapper->setOID(SAI_OBJECT_TYPE_UDF, udf_id, udf_oid); - // Increase UDF group and match reference count - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_UDF_MATCH, - P4_UDF_MATCH_DEFAULT); - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_UDF_GROUP, - udf_field.group_id); - SWSS_LOG_NOTICE("Suceeded to create UDF %s with object ID %s ", - QuotedVar(udf_id).c_str(), - sai_serialize_object_id(udf_oid).c_str()); - return ReturnCode(); +ReturnCode AclTableManager::createUdf(const P4UdfField &udf_field) +{ + SWSS_LOG_ENTER(); + const auto &udf_id = udf_field.udf_id; + + ASSIGN_OR_RETURN(auto attrs, getUdfSaiAttrs(udf_field)); + + sai_object_id_t udf_oid; + CHECK_ERROR_AND_LOG_AND_RETURN(sai_udf_api->create_udf(&udf_oid, gSwitchId, (uint32_t)attrs.size(), attrs.data()), + "Failed to create UDF " << QuotedVar(udf_id) + << " from SAI call sai_udf_api->create_udf"); + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_UDF, udf_id, udf_oid); + // Increase UDF group and match reference count + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_UDF_MATCH, P4_UDF_MATCH_DEFAULT); + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_UDF_GROUP, udf_field.group_id); + SWSS_LOG_NOTICE("Suceeded to create UDF %s with object ID %s ", QuotedVar(udf_id).c_str(), + sai_serialize_object_id(udf_oid).c_str()); + return ReturnCode(); } -ReturnCode AclTableManager::removeUdf(const std::string& udf_id, - const std::string& udf_group_id) { - SWSS_LOG_ENTER(); - sai_object_id_t udf_oid; - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF, udf_id, &udf_oid)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "UDF " << QuotedVar(udf_id) << " was not found"; - } - // Check if there is anything referring to the UDF before deletion. - uint32_t ref_count; - if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_UDF, udf_id, &ref_count)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "UDF " << QuotedVar(udf_id) << " reference count was not found"; - } - if (ref_count > 0) { - return ReturnCode(StatusCode::SWSS_RC_IN_USE) - << "UDF " << QuotedVar(udf_id) - << " referenced by other objects (ref_count = " << ref_count << ")"; - } - - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_udf_api->remove_udf(udf_oid), - "Failed to remove UDF with id " - << udf_oid << " from SAI call sai_udf_api->remove_udf"); - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_UDF, udf_id); - // Decrease UDF group and match reference count - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_UDF_MATCH, - P4_UDF_MATCH_DEFAULT); - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_UDF_GROUP, udf_group_id); - SWSS_LOG_NOTICE("Suceeded to remove UDF %s: %s", QuotedVar(udf_id).c_str(), - sai_serialize_object_id(udf_oid).c_str()); - return ReturnCode(); +ReturnCode AclTableManager::removeUdf(const std::string &udf_id, const std::string &udf_group_id) +{ + SWSS_LOG_ENTER(); + sai_object_id_t udf_oid; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF, udf_id, &udf_oid)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) << "UDF " << QuotedVar(udf_id) << " was not found"; + } + // Check if there is anything referring to the UDF before deletion. + uint32_t ref_count; + if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_UDF, udf_id, &ref_count)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "UDF " << QuotedVar(udf_id) << " reference count was not found"; + } + if (ref_count > 0) + { + return ReturnCode(StatusCode::SWSS_RC_IN_USE) + << "UDF " << QuotedVar(udf_id) << " referenced by other objects (ref_count = " << ref_count << ")"; + } + + CHECK_ERROR_AND_LOG_AND_RETURN(sai_udf_api->remove_udf(udf_oid), "Failed to remove UDF with id " + << udf_oid + << " from SAI call sai_udf_api->remove_udf"); + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_UDF, udf_id); + // Decrease UDF group and match reference count + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_UDF_MATCH, P4_UDF_MATCH_DEFAULT); + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_UDF_GROUP, udf_group_id); + SWSS_LOG_NOTICE("Suceeded to remove UDF %s: %s", QuotedVar(udf_id).c_str(), + sai_serialize_object_id(udf_oid).c_str()); + return ReturnCode(); } -ReturnCode AclTableManager::createUdfGroupsAndUdfsForAclTable( - const P4AclTableDefinition& acl_table_definition) { - ReturnCode status; - // Cache newly created UDFs - std::vector created_udf_fields; - // Cache newly created UDF groups, - std::vector created_udf_group_ids; - // Create UDF groups and UDFs - for (auto& udf_fields : acl_table_definition.udf_fields_lookup) { - for (auto& udf_field : fvValue(udf_fields)) { - status = createUdfGroup(udf_field); - if (!status.ok()) { - status.prepend("Failed to create ACL UDF group with group id " + - QuotedVar(udf_field.group_id) + " : "); - break; - } - created_udf_group_ids.push_back(udf_field.group_id); - status = createUdf(udf_field); - if (!status.ok()) { - status.prepend("Failed to create ACL UDF with id " + - QuotedVar(udf_field.udf_id) + ": "); - break; - } - created_udf_fields.push_back(udf_field); - } - if (!status.ok()) break; - } - // Clean up created UDFs and UDF groups if fails to create all. - if (!status.ok()) { - for (const auto& udf_field : created_udf_fields) { - auto rc = removeUdf(udf_field.udf_id, udf_field.group_id); - if (!rc.ok()) { - SWSS_LOG_ERROR("Failed to remove UDF %s: %s", - QuotedVar(udf_field.udf_id).c_str(), - rc.message().c_str()); - SWSS_RAISE_CRITICAL_STATE("Failed to remove UDF in recovery."); - } - } - for (const auto& udf_group_id : created_udf_group_ids) { - auto rc = removeUdfGroup(udf_group_id); - if (!rc.ok()) { - SWSS_LOG_ERROR("Failed to remove UDF group %s: %s", - QuotedVar(udf_group_id).c_str(), rc.message().c_str()); - SWSS_RAISE_CRITICAL_STATE("Failed to remove UDF group in recovery."); - } - } - LOG_ERROR_AND_RETURN(status); - } - return ReturnCode(); +ReturnCode AclTableManager::createUdfGroupsAndUdfsForAclTable(const P4AclTableDefinition &acl_table_definition) +{ + ReturnCode status; + // Cache newly created UDFs + std::vector created_udf_fields; + // Cache newly created UDF groups, + std::vector created_udf_group_ids; + // Create UDF groups and UDFs + for (auto &udf_fields : acl_table_definition.udf_fields_lookup) + { + for (auto &udf_field : fvValue(udf_fields)) + { + status = createUdfGroup(udf_field); + if (!status.ok()) + { + status.prepend("Failed to create ACL UDF group with group id " + QuotedVar(udf_field.group_id) + " : "); + break; + } + created_udf_group_ids.push_back(udf_field.group_id); + status = createUdf(udf_field); + if (!status.ok()) + { + status.prepend("Failed to create ACL UDF with id " + QuotedVar(udf_field.udf_id) + ": "); + break; + } + created_udf_fields.push_back(udf_field); + } + if (!status.ok()) + break; + } + // Clean up created UDFs and UDF groups if fails to create all. + if (!status.ok()) + { + for (const auto &udf_field : created_udf_fields) + { + auto rc = removeUdf(udf_field.udf_id, udf_field.group_id); + if (!rc.ok()) + { + SWSS_LOG_ERROR("Failed to remove UDF %s: %s", QuotedVar(udf_field.udf_id).c_str(), + rc.message().c_str()); + SWSS_RAISE_CRITICAL_STATE("Failed to remove UDF in recovery."); + } + } + for (const auto &udf_group_id : created_udf_group_ids) + { + auto rc = removeUdfGroup(udf_group_id); + if (!rc.ok()) + { + SWSS_LOG_ERROR("Failed to remove UDF group %s: %s", QuotedVar(udf_group_id).c_str(), + rc.message().c_str()); + SWSS_RAISE_CRITICAL_STATE("Failed to remove UDF group in recovery."); + } + } + LOG_ERROR_AND_RETURN(status); + } + return ReturnCode(); } -ReturnCode AclTableManager::createAclTable( - P4AclTableDefinition& acl_table, sai_object_id_t* acl_table_oid, - sai_object_id_t* acl_group_member_oid) { - // Prepare SAI ACL attributes list to create ACL table - ASSIGN_OR_RETURN(auto attrs, getTableSaiAttrs(acl_table)); - - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_acl_api->create_acl_table(acl_table_oid, gSwitchId, - (uint32_t)attrs.size(), attrs.data()), - "Failed to create ACL table " << QuotedVar(acl_table.acl_table_name)); - SWSS_LOG_NOTICE("Called SAI API to create ACL table %s ", - sai_serialize_object_id(*acl_table_oid).c_str()); - auto status = createAclGroupMember(acl_table, acl_group_member_oid); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to create ACL group member for table %s", - QuotedVar(acl_table.acl_table_name).c_str()); - auto sai_status = sai_acl_api->remove_acl_table(*acl_table_oid); - if (sai_status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to remove ACL table %s SAI_STATUS: %s", - QuotedVar(acl_table.acl_table_name).c_str(), - sai_serialize_status(sai_status).c_str()); - SWSS_RAISE_CRITICAL_STATE("Failed to remove ACL table in recovery."); +ReturnCode AclTableManager::createAclTable(P4AclTableDefinition &acl_table, sai_object_id_t *acl_table_oid, + sai_object_id_t *acl_group_member_oid) +{ + // Prepare SAI ACL attributes list to create ACL table + ASSIGN_OR_RETURN(auto attrs, getTableSaiAttrs(acl_table)); + + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_acl_api->create_acl_table(acl_table_oid, gSwitchId, (uint32_t)attrs.size(), attrs.data()), + "Failed to create ACL table " << QuotedVar(acl_table.acl_table_name)); + SWSS_LOG_NOTICE("Called SAI API to create ACL table %s ", sai_serialize_object_id(*acl_table_oid).c_str()); + auto status = createAclGroupMember(acl_table, acl_group_member_oid); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to create ACL group member for table %s", QuotedVar(acl_table.acl_table_name).c_str()); + auto sai_status = sai_acl_api->remove_acl_table(*acl_table_oid); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove ACL table %s SAI_STATUS: %s", QuotedVar(acl_table.acl_table_name).c_str(), + sai_serialize_status(sai_status).c_str()); + SWSS_RAISE_CRITICAL_STATE("Failed to remove ACL table in recovery."); + } + return status; } - return status; - } - m_p4OidMapper->setOID(SAI_OBJECT_TYPE_ACL_TABLE, acl_table.acl_table_name, - *acl_table_oid); - gCrmOrch->incCrmAclUsedCounter(CrmResourceType::CRM_ACL_TABLE, - (sai_acl_stage_t)acl_table.stage, - SAI_ACL_BIND_POINT_TYPE_SWITCH); - m_aclTablesByStage[acl_table.stage].push_back(acl_table.acl_table_name); - m_aclTableDefinitions[acl_table.acl_table_name] = acl_table; - // Add ACL table name to AclRuleManager mapping in p4orch - if (!gP4Orch->addAclTableToManagerMapping(acl_table.acl_table_name)) { - SWSS_LOG_NOTICE("ACL table %s to AclRuleManager mapping already exists", - QuotedVar(acl_table.acl_table_name).c_str()); - } - for (const auto& udf_group_idx : acl_table.udf_group_attr_index_lookup) { - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_UDF_GROUP, - fvField(udf_group_idx)); - } - - SWSS_LOG_NOTICE("ACL table %s was created successfully : %s", - QuotedVar(acl_table.acl_table_name).c_str(), - sai_serialize_object_id(acl_table.table_oid).c_str()); - return ReturnCode(); + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_ACL_TABLE, acl_table.acl_table_name, *acl_table_oid); + gCrmOrch->incCrmAclUsedCounter(CrmResourceType::CRM_ACL_TABLE, (sai_acl_stage_t)acl_table.stage, + SAI_ACL_BIND_POINT_TYPE_SWITCH); + m_aclTablesByStage[acl_table.stage].push_back(acl_table.acl_table_name); + m_aclTableDefinitions[acl_table.acl_table_name] = acl_table; + // Add ACL table name to AclRuleManager mapping in p4orch + if (!gP4Orch->addAclTableToManagerMapping(acl_table.acl_table_name)) + { + SWSS_LOG_NOTICE("ACL table %s to AclRuleManager mapping already exists", + QuotedVar(acl_table.acl_table_name).c_str()); + } + for (const auto &udf_group_idx : acl_table.udf_group_attr_index_lookup) + { + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_UDF_GROUP, fvField(udf_group_idx)); + } + + SWSS_LOG_NOTICE("ACL table %s was created successfully : %s", QuotedVar(acl_table.acl_table_name).c_str(), + sai_serialize_object_id(acl_table.table_oid).c_str()); + return ReturnCode(); } -ReturnCode AclTableManager::removeAclTable(P4AclTableDefinition& acl_table) { - SWSS_LOG_ENTER(); +ReturnCode AclTableManager::removeAclTable(P4AclTableDefinition &acl_table) +{ + SWSS_LOG_ENTER(); + + auto status = removeAclGroupMember(acl_table); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to remove ACL table with key %s : failed to delete group " + "member %s.", + QuotedVar(acl_table.acl_table_name).c_str(), + sai_serialize_object_id(acl_table.group_member_oid).c_str()); + return status; + } + auto sai_status = sai_acl_api->remove_acl_table(acl_table.table_oid); + if (sai_status != SAI_STATUS_SUCCESS) + { + status = ReturnCode(sai_status) << "Failed to remove ACL table with key " << QuotedVar(acl_table.acl_table_name) + << " by calling sai_acl_api->remove_acl_table"; + SWSS_LOG_ERROR("%s", status.message().c_str()); + auto rc = createAclGroupMember(acl_table, &acl_table.group_member_oid); + if (!rc.ok()) + { + SWSS_LOG_ERROR("%s", rc.message().c_str()); + SWSS_RAISE_CRITICAL_STATE("Failed to create ACL group member in recovery."); + } + return status; + } + for (const auto &udf_group_idx : acl_table.udf_group_attr_index_lookup) + { + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_UDF_GROUP, fvField(udf_group_idx)); + } - auto status = removeAclGroupMember(acl_table); - if (!status.ok()) { - SWSS_LOG_ERROR( - "Failed to remove ACL table with key %s : failed to delete group " - "member %s.", - QuotedVar(acl_table.acl_table_name).c_str(), - sai_serialize_object_id(acl_table.group_member_oid).c_str()); - return status; - } - auto sai_status = sai_acl_api->remove_acl_table(acl_table.table_oid); - if (sai_status != SAI_STATUS_SUCCESS) { - status = ReturnCode(sai_status) - << "Failed to remove ACL table with key " - << QuotedVar(acl_table.acl_table_name) - << " by calling sai_acl_api->remove_acl_table"; - SWSS_LOG_ERROR("%s", status.message().c_str()); - auto rc = createAclGroupMember(acl_table, &acl_table.group_member_oid); - if (!rc.ok()) { - SWSS_LOG_ERROR("%s", rc.message().c_str()); - SWSS_RAISE_CRITICAL_STATE( - "Failed to create ACL group member in recovery."); + // Remove UDFs and UDF groups after ACL table deletion + std::vector removed_udf_fields; + std::vector removed_udf_group_ids; + for (const auto &udf_fields : acl_table.udf_fields_lookup) + { + for (const auto &udf_field : fvValue(udf_fields)) + { + status = removeUdf(udf_field.udf_id, udf_field.group_id); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to remove ACL UDF with id %s : %s", QuotedVar(udf_field.udf_id).c_str(), + status.message().c_str()); + break; + } + removed_udf_fields.push_back(udf_field); + status = removeUdfGroup(udf_field.group_id); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to remove ACL UDF group with group id %s : %s", + QuotedVar(udf_field.group_id).c_str(), status.message().c_str()); + break; + } + removed_udf_group_ids.push_back(udf_field); + } + if (!status.ok()) + { + break; + } } - return status; - } - for (const auto& udf_group_idx : acl_table.udf_group_attr_index_lookup) { - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_UDF_GROUP, - fvField(udf_group_idx)); - } - - // Remove UDFs and UDF groups after ACL table deletion - std::vector removed_udf_fields; - std::vector removed_udf_group_ids; - for (const auto& udf_fields : acl_table.udf_fields_lookup) { - for (const auto& udf_field : fvValue(udf_fields)) { - status = removeUdf(udf_field.udf_id, udf_field.group_id); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to remove ACL UDF with id %s : %s", - QuotedVar(udf_field.udf_id).c_str(), - status.message().c_str()); - break; - } - removed_udf_fields.push_back(udf_field); - status = removeUdfGroup(udf_field.group_id); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to remove ACL UDF group with group id %s : %s", - QuotedVar(udf_field.group_id).c_str(), - status.message().c_str()); - break; - } - removed_udf_group_ids.push_back(udf_field); - } - if (!status.ok()) { - break; - } - } - if (!status.ok()) { - for (const auto& udf_field : removed_udf_group_ids) { - auto rc = createUdfGroup(udf_field); - if (!rc.ok()) { - SWSS_LOG_ERROR("Failed to create UDF group %s: %s", - QuotedVar(udf_field.group_id).c_str(), - rc.message().c_str()); - SWSS_RAISE_CRITICAL_STATE("Failed to create UDF group in recovery."); - } - } - for (const auto& udf_field : removed_udf_fields) { - auto rc = createUdf(udf_field); - if (!rc.ok()) { - SWSS_LOG_ERROR("Failed to create UDF %s: %s", - QuotedVar(udf_field.udf_id).c_str(), - rc.message().c_str()); - SWSS_RAISE_CRITICAL_STATE("Failed to create UDF in recovery."); - } - } - } - - gCrmOrch->decCrmAclUsedCounter( - CrmResourceType::CRM_ACL_TABLE, (sai_acl_stage_t)acl_table.stage, - SAI_ACL_BIND_POINT_TYPE_SWITCH, acl_table.table_oid); - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_ACL_TABLE, acl_table.acl_table_name); - // Remove ACL table name to AclRuleManager mapping in p4orch - if (!gP4Orch->removeAclTableToManagerMapping(acl_table.acl_table_name)) { - SWSS_LOG_NOTICE("ACL table %s to AclRuleManager mapping does not exist", - QuotedVar(acl_table.acl_table_name).c_str()); - } - auto& table_keys = m_aclTablesByStage[acl_table.stage]; - auto position = - std::find(table_keys.begin(), table_keys.end(), acl_table.acl_table_name); - if (position != table_keys.end()) { - table_keys.erase(position); - } - P4AclTableDefinition rollback_acl_table = acl_table; - m_aclTableDefinitions.erase(acl_table.acl_table_name); - - if (!status.ok()) { - auto rc = createAclTable(rollback_acl_table, &rollback_acl_table.table_oid, - &rollback_acl_table.group_member_oid); - if (!rc.ok()) { - SWSS_LOG_ERROR("Failed to create ACL table: %s", rc.message().c_str()); - SWSS_RAISE_CRITICAL_STATE("Failed to create ACL table in recovery."); + if (!status.ok()) + { + for (const auto &udf_field : removed_udf_group_ids) + { + auto rc = createUdfGroup(udf_field); + if (!rc.ok()) + { + SWSS_LOG_ERROR("Failed to create UDF group %s: %s", QuotedVar(udf_field.group_id).c_str(), + rc.message().c_str()); + SWSS_RAISE_CRITICAL_STATE("Failed to create UDF group in recovery."); + } + } + for (const auto &udf_field : removed_udf_fields) + { + auto rc = createUdf(udf_field); + if (!rc.ok()) + { + SWSS_LOG_ERROR("Failed to create UDF %s: %s", QuotedVar(udf_field.udf_id).c_str(), + rc.message().c_str()); + SWSS_RAISE_CRITICAL_STATE("Failed to create UDF in recovery."); + } + } } - return status; - } - SWSS_LOG_NOTICE( - "ACL table %s(%s) was removed successfully.", - QuotedVar(rollback_acl_table.acl_table_name).c_str(), - sai_serialize_object_id(rollback_acl_table.table_oid).c_str()); - return ReturnCode(); + + gCrmOrch->decCrmAclUsedCounter(CrmResourceType::CRM_ACL_TABLE, (sai_acl_stage_t)acl_table.stage, + SAI_ACL_BIND_POINT_TYPE_SWITCH, acl_table.table_oid); + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_ACL_TABLE, acl_table.acl_table_name); + // Remove ACL table name to AclRuleManager mapping in p4orch + if (!gP4Orch->removeAclTableToManagerMapping(acl_table.acl_table_name)) + { + SWSS_LOG_NOTICE("ACL table %s to AclRuleManager mapping does not exist", + QuotedVar(acl_table.acl_table_name).c_str()); + } + auto &table_keys = m_aclTablesByStage[acl_table.stage]; + auto position = std::find(table_keys.begin(), table_keys.end(), acl_table.acl_table_name); + if (position != table_keys.end()) + { + table_keys.erase(position); + } + P4AclTableDefinition rollback_acl_table = acl_table; + m_aclTableDefinitions.erase(acl_table.acl_table_name); + + if (!status.ok()) + { + auto rc = + createAclTable(rollback_acl_table, &rollback_acl_table.table_oid, &rollback_acl_table.group_member_oid); + if (!rc.ok()) + { + SWSS_LOG_ERROR("Failed to create ACL table: %s", rc.message().c_str()); + SWSS_RAISE_CRITICAL_STATE("Failed to create ACL table in recovery."); + } + return status; + } + SWSS_LOG_NOTICE("ACL table %s(%s) was removed successfully.", QuotedVar(rollback_acl_table.acl_table_name).c_str(), + sai_serialize_object_id(rollback_acl_table.table_oid).c_str()); + return ReturnCode(); } -ReturnCode AclTableManager::processDeleteTableRequest( - const std::string& acl_table_name) { - SWSS_LOG_ENTER(); - - auto* acl_table = getAclTable(acl_table_name); - if (acl_table == nullptr) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "ACL table with key " << QuotedVar(acl_table_name) - << " does not exist"); - } - // Check if there is anything referring to the ACL table before deletion. - uint32_t ref_count; - if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_ACL_TABLE, - acl_table->acl_table_name, &ref_count)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Failed to get reference count of ACL table " - << QuotedVar(acl_table->acl_table_name)); - } - if (ref_count > 0) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table " << QuotedVar(acl_table->acl_table_name) - << " referenced by other objects (ref_count = " - << ref_count << ")"); - } - return removeAclTable(*acl_table); +ReturnCode AclTableManager::processDeleteTableRequest(const std::string &acl_table_name) +{ + SWSS_LOG_ENTER(); + + auto *acl_table = getAclTable(acl_table_name); + if (acl_table == nullptr) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "ACL table with key " << QuotedVar(acl_table_name) << " does not exist"); + } + // Check if there is anything referring to the ACL table before deletion. + uint32_t ref_count; + if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_ACL_TABLE, acl_table->acl_table_name, &ref_count)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Failed to get reference count of ACL table " + << QuotedVar(acl_table->acl_table_name)); + } + if (ref_count > 0) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table " << QuotedVar(acl_table->acl_table_name) + << " referenced by other objects (ref_count = " << ref_count << ")"); + } + return removeAclTable(*acl_table); } -ReturnCode AclTableManager::createAclGroupMember( - const P4AclTableDefinition& acl_table, sai_object_id_t* acl_grp_mem_oid) { - SWSS_LOG_ENTER(); - - auto attrs = getGroupMemSaiAttrs(acl_table); - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_acl_api->create_acl_table_group_member( - acl_grp_mem_oid, gSwitchId, (uint32_t)attrs.size(), attrs.data()), - "Failed to create ACL group member in group " - << sai_serialize_object_id(acl_table.group_oid)); - m_p4OidMapper->setOID(SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER, - acl_table.acl_table_name, *acl_grp_mem_oid); - // Add reference on the ACL group - auto& group_map = gSwitchOrch->getAclGroupsBindingToSwitch(); - auto group_it = group_map.find(acl_table.stage); - if (group_it == group_map.end()) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Failed to find ACL group binding to switch at stage " - << acl_table.stage); - } - auto* referenced_group = &group_it->second; - referenced_group->m_objsDependingOnMe.insert( - sai_serialize_object_id(*acl_grp_mem_oid)); - SWSS_LOG_NOTICE("ACL group member for table %s was created successfully: %s", - QuotedVar(acl_table.acl_table_name).c_str(), - sai_serialize_object_id(*acl_grp_mem_oid).c_str()); - return ReturnCode(); +ReturnCode AclTableManager::createAclGroupMember(const P4AclTableDefinition &acl_table, + sai_object_id_t *acl_grp_mem_oid) +{ + SWSS_LOG_ENTER(); + + auto attrs = getGroupMemSaiAttrs(acl_table); + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_acl_api->create_acl_table_group_member(acl_grp_mem_oid, gSwitchId, (uint32_t)attrs.size(), attrs.data()), + "Failed to create ACL group member in group " << sai_serialize_object_id(acl_table.group_oid)); + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER, acl_table.acl_table_name, *acl_grp_mem_oid); + // Add reference on the ACL group + auto &group_map = gSwitchOrch->getAclGroupsBindingToSwitch(); + auto group_it = group_map.find(acl_table.stage); + if (group_it == group_map.end()) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Failed to find ACL group binding to switch at stage " + << acl_table.stage); + } + auto *referenced_group = &group_it->second; + referenced_group->m_objsDependingOnMe.insert(sai_serialize_object_id(*acl_grp_mem_oid)); + SWSS_LOG_NOTICE("ACL group member for table %s was created successfully: %s", + QuotedVar(acl_table.acl_table_name).c_str(), sai_serialize_object_id(*acl_grp_mem_oid).c_str()); + return ReturnCode(); } -ReturnCode AclTableManager::removeAclGroupMember( - P4AclTableDefinition& acl_table) { - SWSS_LOG_ENTER(); - - sai_object_id_t grp_mem_oid; - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER, - acl_table.acl_table_name, &grp_mem_oid)) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to remove ACL group member " - << sai_serialize_object_id(grp_mem_oid) - << " for table " << QuotedVar(acl_table.acl_table_name) - << ": invalid table key."); - } - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_acl_api->remove_acl_table_group_member(grp_mem_oid), - "Failed to remove ACL group member " - << sai_serialize_object_id(grp_mem_oid) << " for table " - << QuotedVar(acl_table.acl_table_name)); - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER, - acl_table.acl_table_name); - // Remove reference on the ACL group - auto& group_map = gSwitchOrch->getAclGroupsBindingToSwitch(); - auto group_it = group_map.find(acl_table.stage); - if (group_it == group_map.end()) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Failed to find ACL group binding to switch at stage " - << acl_table.stage); - } - auto* referenced_group = &group_it->second; - referenced_group->m_objsDependingOnMe.erase( - sai_serialize_object_id(grp_mem_oid)); - SWSS_LOG_NOTICE("ACL table member %s for table %s was removed successfully.", - sai_serialize_object_id(grp_mem_oid).c_str(), - QuotedVar(acl_table.acl_table_name).c_str()); - return ReturnCode(); +ReturnCode AclTableManager::removeAclGroupMember(P4AclTableDefinition &acl_table) +{ + SWSS_LOG_ENTER(); + + sai_object_id_t grp_mem_oid; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER, acl_table.acl_table_name, &grp_mem_oid)) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Failed to remove ACL group member " << sai_serialize_object_id(grp_mem_oid) + << " for table " << QuotedVar(acl_table.acl_table_name) << ": invalid table key."); + } + CHECK_ERROR_AND_LOG_AND_RETURN(sai_acl_api->remove_acl_table_group_member(grp_mem_oid), + "Failed to remove ACL group member " << sai_serialize_object_id(grp_mem_oid) + << " for table " + << QuotedVar(acl_table.acl_table_name)); + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER, acl_table.acl_table_name); + // Remove reference on the ACL group + auto &group_map = gSwitchOrch->getAclGroupsBindingToSwitch(); + auto group_it = group_map.find(acl_table.stage); + if (group_it == group_map.end()) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Failed to find ACL group binding to switch at stage " + << acl_table.stage); + } + auto *referenced_group = &group_it->second; + referenced_group->m_objsDependingOnMe.erase(sai_serialize_object_id(grp_mem_oid)); + SWSS_LOG_NOTICE("ACL table member %s for table %s was removed successfully.", + sai_serialize_object_id(grp_mem_oid).c_str(), QuotedVar(acl_table.acl_table_name).c_str()); + return ReturnCode(); } -std::string AclTableManager::verifyState( - const std::string& key, const std::vector& tuple) { - SWSS_LOG_ENTER(); - - auto pos = key.find_first_of(kTableKeyDelimiter); - if (pos == std::string::npos) { - return std::string("Invalid key: ") + key; - } - std::string p4rt_table = key.substr(0, pos); - std::string p4rt_key = key.substr(pos + 1); - if (p4rt_table != APP_P4RT_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - std::string table_name; - std::string key_content; - parseP4RTKey(p4rt_key, &table_name, &key_content); - if (table_name != APP_P4RT_ACL_TABLE_DEFINITION_NAME) { - return std::string("Invalid key: ") + key; - } - - ReturnCode status; - auto app_db_entry_or = - deserializeAclTableDefinitionAppDbEntry(key_content, tuple); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - std::stringstream msg; - msg << "Unable to deserialize key " << QuotedVar(key) << ": " - << status.message(); - return msg.str(); - } - auto& app_db_entry = *app_db_entry_or; - - auto* acl_table_definition = getAclTable(app_db_entry.acl_table_name); - if (acl_table_definition == nullptr) { - std::stringstream msg; - msg << "No entry found with key " << QuotedVar(key); - return msg.str(); - } - - std::string cache_result = - verifyStateCache(app_db_entry, acl_table_definition); - std::string asic_db_result = verifyStateAsicDb(acl_table_definition); - if (cache_result.empty()) { - return asic_db_result; - } - if (asic_db_result.empty()) { - return cache_result; - } - return cache_result + "; " + asic_db_result; +std::string AclTableManager::verifyState(const std::string &key, const std::vector &tuple) +{ + SWSS_LOG_ENTER(); + + auto pos = key.find_first_of(kTableKeyDelimiter); + if (pos == std::string::npos) + { + return std::string("Invalid key: ") + key; + } + std::string p4rt_table = key.substr(0, pos); + std::string p4rt_key = key.substr(pos + 1); + if (p4rt_table != APP_P4RT_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } + std::string table_name; + std::string key_content; + parseP4RTKey(p4rt_key, &table_name, &key_content); + if (table_name != APP_P4RT_ACL_TABLE_DEFINITION_NAME) + { + return std::string("Invalid key: ") + key; + } + + ReturnCode status; + auto app_db_entry_or = deserializeAclTableDefinitionAppDbEntry(key_content, tuple); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + std::stringstream msg; + msg << "Unable to deserialize key " << QuotedVar(key) << ": " << status.message(); + return msg.str(); + } + auto &app_db_entry = *app_db_entry_or; + + auto *acl_table_definition = getAclTable(app_db_entry.acl_table_name); + if (acl_table_definition == nullptr) + { + std::stringstream msg; + msg << "No entry found with key " << QuotedVar(key); + return msg.str(); + } + + std::string cache_result = verifyStateCache(app_db_entry, acl_table_definition); + std::string asic_db_result = verifyStateAsicDb(acl_table_definition); + if (cache_result.empty()) + { + return asic_db_result; + } + if (asic_db_result.empty()) + { + return cache_result; + } + return cache_result + "; " + asic_db_result; } -std::string AclTableManager::verifyStateCache( - const P4AclTableDefinitionAppDbEntry& app_db_entry, - const P4AclTableDefinition* acl_table) { - ReturnCode status = validateAclTableDefinitionAppDbEntry(app_db_entry); - if (!status.ok()) { - std::stringstream msg; - msg << "Validation failed for ACL table DB entry " - << QuotedVar(app_db_entry.acl_table_name) << ": " << status.message(); - return msg.str(); - } - - auto stage_it = aclStageLookup.find(app_db_entry.stage); - sai_acl_stage_t stage; - if (stage_it != aclStageLookup.end()) { - stage = stage_it->second; - } else { - std::stringstream msg; - msg << "Invalid stage " << QuotedVar(app_db_entry.stage) - << " in ACL table manager."; - return msg.str(); - } - P4AclTableDefinition acl_table_definition_entry( - app_db_entry.acl_table_name, stage, app_db_entry.priority, - app_db_entry.size, app_db_entry.meter_unit, app_db_entry.counter_unit); - - if (acl_table->acl_table_name != app_db_entry.acl_table_name) { - std::stringstream msg; - msg << "ACL table " << QuotedVar(app_db_entry.acl_table_name) - << " does not match internal cache " - << QuotedVar(acl_table->acl_table_name) << " in ACL table manager."; - return msg.str(); - } - if (acl_table->stage != stage) { - std::stringstream msg; - msg << "ACL table " << QuotedVar(app_db_entry.acl_table_name) - << " with stage " << stage << " does not match internal cache " - << acl_table->stage << " in ACL table manager."; - return msg.str(); - } - if (acl_table->size != app_db_entry.size) { - std::stringstream msg; - msg << "ACL table " << QuotedVar(app_db_entry.acl_table_name) - << " with size " << app_db_entry.size - << " does not match internal cache " << acl_table->size - << " in ACL table manager."; - return msg.str(); - } - if (acl_table->priority != app_db_entry.priority) { - std::stringstream msg; - msg << "ACL table " << QuotedVar(app_db_entry.acl_table_name) - << " with priority " << app_db_entry.priority - << " does not match internal cache " << acl_table->priority - << " in ACL table manager."; - return msg.str(); - } - if (acl_table->meter_unit != app_db_entry.meter_unit) { - std::stringstream msg; - msg << "ACL table " << QuotedVar(app_db_entry.acl_table_name) - << " with meter unit " << QuotedVar(app_db_entry.meter_unit) - << " does not match internal cache " << QuotedVar(acl_table->meter_unit) - << " in ACL table manager."; - return msg.str(); - } - if (acl_table->counter_unit != app_db_entry.counter_unit) { - std::stringstream msg; - msg << "ACL table " << QuotedVar(app_db_entry.acl_table_name) - << " with counter unit " << QuotedVar(app_db_entry.counter_unit) - << " does not match internal cache " - << QuotedVar(acl_table->counter_unit) << " in ACL table manager."; - return msg.str(); - } - - status = buildAclTableDefinitionMatchFieldValues( - app_db_entry.match_field_lookup, &acl_table_definition_entry); - if (!status.ok()) { - std::stringstream msg; - msg << "Failed to build ACL table match field values for table " - << QuotedVar(app_db_entry.acl_table_name); - return msg.str(); - } - status = buildAclTableDefinitionActionFieldValues( - app_db_entry.action_field_lookup, - &acl_table_definition_entry.rule_action_field_lookup); - if (!status.ok()) { - std::stringstream msg; - msg << "Failed to build ACL table action field values for table " - << QuotedVar(app_db_entry.acl_table_name); - return msg.str(); - } - status = buildAclTableDefinitionActionColorFieldValues( - app_db_entry.packet_action_color_lookup, - &acl_table_definition_entry.rule_action_field_lookup, - &acl_table_definition_entry.rule_packet_action_color_lookup); - if (!status.ok()) { - std::stringstream msg; - msg << "Failed to build ACL table action color field values for table " - << QuotedVar(app_db_entry.acl_table_name); - return msg.str(); - } - - if (acl_table->composite_sai_match_fields_lookup != - acl_table_definition_entry.composite_sai_match_fields_lookup) { - std::stringstream msg; - msg << "Composite SAI match fields mismatch on ACL table " - << QuotedVar(app_db_entry.acl_table_name); - return msg.str(); - } - if (acl_table->udf_fields_lookup != - acl_table_definition_entry.udf_fields_lookup) { - std::stringstream msg; - msg << "UDF fields lookup mismatch on ACL table " - << QuotedVar(app_db_entry.acl_table_name); - return msg.str(); - } - if (acl_table->udf_group_attr_index_lookup != - acl_table_definition_entry.udf_group_attr_index_lookup) { - std::stringstream msg; - msg << "UDF group attr index lookup mismatch on ACL table " - << QuotedVar(app_db_entry.acl_table_name); - return msg.str(); - } - if (acl_table->sai_match_field_lookup != - acl_table_definition_entry.sai_match_field_lookup) { - std::stringstream msg; - msg << "SAI match field lookup mismatch on ACL table " - << QuotedVar(app_db_entry.acl_table_name); - return msg.str(); - } - if (acl_table->ip_type_bit_type_lookup != - acl_table_definition_entry.ip_type_bit_type_lookup) { - std::stringstream msg; - msg << "IP type bit type lookup mismatch on ACL table " - << QuotedVar(app_db_entry.acl_table_name); - return msg.str(); - } - if (acl_table->rule_action_field_lookup != - acl_table_definition_entry.rule_action_field_lookup) { - std::stringstream msg; - msg << "Rule action field lookup mismatch on ACL table " - << QuotedVar(app_db_entry.acl_table_name); - return msg.str(); - } - if (acl_table->rule_packet_action_color_lookup != - acl_table_definition_entry.rule_packet_action_color_lookup) { - std::stringstream msg; - msg << "Rule packet action color lookup mismatch on ACL table " - << QuotedVar(app_db_entry.acl_table_name); - return msg.str(); - } - - std::string err_msg = m_p4OidMapper->verifyOIDMapping( - SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER, app_db_entry.acl_table_name, - acl_table->group_member_oid); - if (!err_msg.empty()) { - return err_msg; - } - err_msg = m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_ACL_TABLE, - app_db_entry.acl_table_name, - acl_table->table_oid); - if (!err_msg.empty()) { - return err_msg; - } - - return ""; +std::string AclTableManager::verifyStateCache(const P4AclTableDefinitionAppDbEntry &app_db_entry, + const P4AclTableDefinition *acl_table) +{ + ReturnCode status = validateAclTableDefinitionAppDbEntry(app_db_entry); + if (!status.ok()) + { + std::stringstream msg; + msg << "Validation failed for ACL table DB entry " << QuotedVar(app_db_entry.acl_table_name) << ": " + << status.message(); + return msg.str(); + } + + auto stage_it = aclStageLookup.find(app_db_entry.stage); + sai_acl_stage_t stage; + if (stage_it != aclStageLookup.end()) + { + stage = stage_it->second; + } + else + { + std::stringstream msg; + msg << "Invalid stage " << QuotedVar(app_db_entry.stage) << " in ACL table manager."; + return msg.str(); + } + P4AclTableDefinition acl_table_definition_entry(app_db_entry.acl_table_name, stage, app_db_entry.priority, + app_db_entry.size, app_db_entry.meter_unit, + app_db_entry.counter_unit); + + if (acl_table->acl_table_name != app_db_entry.acl_table_name) + { + std::stringstream msg; + msg << "ACL table " << QuotedVar(app_db_entry.acl_table_name) << " does not match internal cache " + << QuotedVar(acl_table->acl_table_name) << " in ACL table manager."; + return msg.str(); + } + if (acl_table->stage != stage) + { + std::stringstream msg; + msg << "ACL table " << QuotedVar(app_db_entry.acl_table_name) << " with stage " << stage + << " does not match internal cache " << acl_table->stage << " in ACL table manager."; + return msg.str(); + } + if (acl_table->size != app_db_entry.size) + { + std::stringstream msg; + msg << "ACL table " << QuotedVar(app_db_entry.acl_table_name) << " with size " << app_db_entry.size + << " does not match internal cache " << acl_table->size << " in ACL table manager."; + return msg.str(); + } + if (acl_table->priority != app_db_entry.priority) + { + std::stringstream msg; + msg << "ACL table " << QuotedVar(app_db_entry.acl_table_name) << " with priority " << app_db_entry.priority + << " does not match internal cache " << acl_table->priority << " in ACL table manager."; + return msg.str(); + } + if (acl_table->meter_unit != app_db_entry.meter_unit) + { + std::stringstream msg; + msg << "ACL table " << QuotedVar(app_db_entry.acl_table_name) << " with meter unit " + << QuotedVar(app_db_entry.meter_unit) << " does not match internal cache " + << QuotedVar(acl_table->meter_unit) << " in ACL table manager."; + return msg.str(); + } + if (acl_table->counter_unit != app_db_entry.counter_unit) + { + std::stringstream msg; + msg << "ACL table " << QuotedVar(app_db_entry.acl_table_name) << " with counter unit " + << QuotedVar(app_db_entry.counter_unit) << " does not match internal cache " + << QuotedVar(acl_table->counter_unit) << " in ACL table manager."; + return msg.str(); + } + + status = buildAclTableDefinitionMatchFieldValues(app_db_entry.match_field_lookup, &acl_table_definition_entry); + if (!status.ok()) + { + std::stringstream msg; + msg << "Failed to build ACL table match field values for table " << QuotedVar(app_db_entry.acl_table_name); + return msg.str(); + } + status = buildAclTableDefinitionActionFieldValues(app_db_entry.action_field_lookup, + &acl_table_definition_entry.rule_action_field_lookup); + if (!status.ok()) + { + std::stringstream msg; + msg << "Failed to build ACL table action field values for table " << QuotedVar(app_db_entry.acl_table_name); + return msg.str(); + } + status = buildAclTableDefinitionActionColorFieldValues(app_db_entry.packet_action_color_lookup, + &acl_table_definition_entry.rule_action_field_lookup, + &acl_table_definition_entry.rule_packet_action_color_lookup); + if (!status.ok()) + { + std::stringstream msg; + msg << "Failed to build ACL table action color field values for table " + << QuotedVar(app_db_entry.acl_table_name); + return msg.str(); + } + + if (acl_table->composite_sai_match_fields_lookup != acl_table_definition_entry.composite_sai_match_fields_lookup) + { + std::stringstream msg; + msg << "Composite SAI match fields mismatch on ACL table " << QuotedVar(app_db_entry.acl_table_name); + return msg.str(); + } + if (acl_table->udf_fields_lookup != acl_table_definition_entry.udf_fields_lookup) + { + std::stringstream msg; + msg << "UDF fields lookup mismatch on ACL table " << QuotedVar(app_db_entry.acl_table_name); + return msg.str(); + } + if (acl_table->udf_group_attr_index_lookup != acl_table_definition_entry.udf_group_attr_index_lookup) + { + std::stringstream msg; + msg << "UDF group attr index lookup mismatch on ACL table " << QuotedVar(app_db_entry.acl_table_name); + return msg.str(); + } + if (acl_table->sai_match_field_lookup != acl_table_definition_entry.sai_match_field_lookup) + { + std::stringstream msg; + msg << "SAI match field lookup mismatch on ACL table " << QuotedVar(app_db_entry.acl_table_name); + return msg.str(); + } + if (acl_table->ip_type_bit_type_lookup != acl_table_definition_entry.ip_type_bit_type_lookup) + { + std::stringstream msg; + msg << "IP type bit type lookup mismatch on ACL table " << QuotedVar(app_db_entry.acl_table_name); + return msg.str(); + } + if (acl_table->rule_action_field_lookup != acl_table_definition_entry.rule_action_field_lookup) + { + std::stringstream msg; + msg << "Rule action field lookup mismatch on ACL table " << QuotedVar(app_db_entry.acl_table_name); + return msg.str(); + } + if (acl_table->rule_packet_action_color_lookup != acl_table_definition_entry.rule_packet_action_color_lookup) + { + std::stringstream msg; + msg << "Rule packet action color lookup mismatch on ACL table " << QuotedVar(app_db_entry.acl_table_name); + return msg.str(); + } + + std::string err_msg = m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER, + app_db_entry.acl_table_name, acl_table->group_member_oid); + if (!err_msg.empty()) + { + return err_msg; + } + err_msg = + m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_ACL_TABLE, app_db_entry.acl_table_name, acl_table->table_oid); + if (!err_msg.empty()) + { + return err_msg; + } + + return ""; } -std::string AclTableManager::verifyStateAsicDb( - const P4AclTableDefinition* acl_table) { - swss::DBConnector db("ASIC_DB", 0); - swss::Table table(&db, "ASIC_STATE"); - - // Verify table. - auto attrs_or = getTableSaiAttrs(*acl_table); - if (!attrs_or.ok()) { - return std::string("Failed to get SAI attrs: ") + - attrs_or.status().message(); - } - std::vector attrs = *attrs_or; - std::vector exp = - saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_ACL_TABLE, (uint32_t)attrs.size(), attrs.data(), - /*countOnly=*/false); - std::string key = sai_serialize_object_type(SAI_OBJECT_TYPE_ACL_TABLE) + ":" + - sai_serialize_object_id(acl_table->table_oid); - std::vector values; - if (!table.get(key, values)) { - return std::string("ASIC DB key not found ") + key; - } - std::string err_msg = - verifyAttrs(values, exp, std::vector{}, - /*allow_unknown=*/false); - if (!err_msg.empty()) { - return err_msg; - } - - // Verify group member. - attrs = getGroupMemSaiAttrs(*acl_table); - exp = saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER, (uint32_t)attrs.size(), - attrs.data(), /*countOnly=*/false); - key = sai_serialize_object_type(SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER) + - ":" + sai_serialize_object_id(acl_table->group_member_oid); - values.clear(); - if (!table.get(key, values)) { - return std::string("ASIC DB key not found ") + key; - } - err_msg = verifyAttrs(values, exp, std::vector{}, - /*allow_unknown=*/false); - if (!err_msg.empty()) { - return err_msg; - } - - for (auto& udf_fields : acl_table->udf_fields_lookup) { - for (auto& udf_field : fvValue(udf_fields)) { - sai_object_id_t udf_group_oid; - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF_GROUP, udf_field.group_id, - &udf_group_oid)) { - return std::string("UDF group ") + udf_field.group_id + - " does not exist"; - } - sai_object_id_t udf_oid; - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF, udf_field.udf_id, - &udf_oid)) { - return std::string("UDF ") + udf_field.udf_id + " does not exist"; - } - - // Verify UDF group. - attrs = getUdfGroupSaiAttrs(udf_field); - exp = saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_UDF_GROUP, (uint32_t)attrs.size(), attrs.data(), - /*countOnly=*/false); - key = sai_serialize_object_type(SAI_OBJECT_TYPE_UDF_GROUP) + ":" + - sai_serialize_object_id(udf_group_oid); - values.clear(); - if (!table.get(key, values)) { +std::string AclTableManager::verifyStateAsicDb(const P4AclTableDefinition *acl_table) +{ + swss::DBConnector db("ASIC_DB", 0); + swss::Table table(&db, "ASIC_STATE"); + + // Verify table. + auto attrs_or = getTableSaiAttrs(*acl_table); + if (!attrs_or.ok()) + { + return std::string("Failed to get SAI attrs: ") + attrs_or.status().message(); + } + std::vector attrs = *attrs_or; + std::vector exp = + saimeta::SaiAttributeList::serialize_attr_list(SAI_OBJECT_TYPE_ACL_TABLE, (uint32_t)attrs.size(), attrs.data(), + /*countOnly=*/false); + std::string key = + sai_serialize_object_type(SAI_OBJECT_TYPE_ACL_TABLE) + ":" + sai_serialize_object_id(acl_table->table_oid); + std::vector values; + if (!table.get(key, values)) + { return std::string("ASIC DB key not found ") + key; - } - err_msg = verifyAttrs(values, exp, std::vector{}, - /*allow_unknown=*/false); - if (!err_msg.empty()) { + } + std::string err_msg = verifyAttrs(values, exp, std::vector{}, + /*allow_unknown=*/false); + if (!err_msg.empty()) + { return err_msg; - } - - // Verify UDF. - attrs_or = getUdfSaiAttrs(udf_field); - if (!attrs_or.ok()) { - return std::string("Failed to get SAI attrs: ") + - attrs_or.status().message(); - } - attrs = *attrs_or; - exp = saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_UDF, (uint32_t)attrs.size(), attrs.data(), - /*countOnly=*/false); - key = sai_serialize_object_type(SAI_OBJECT_TYPE_UDF) + ":" + - sai_serialize_object_id(udf_oid); - values.clear(); - if (!table.get(key, values)) { + } + + // Verify group member. + attrs = getGroupMemSaiAttrs(*acl_table); + exp = saimeta::SaiAttributeList::serialize_attr_list(SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER, (uint32_t)attrs.size(), + attrs.data(), /*countOnly=*/false); + key = sai_serialize_object_type(SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER) + ":" + + sai_serialize_object_id(acl_table->group_member_oid); + values.clear(); + if (!table.get(key, values)) + { return std::string("ASIC DB key not found ") + key; - } - err_msg = verifyAttrs(values, exp, std::vector{}, - /*allow_unknown=*/false); - if (!err_msg.empty()) { + } + err_msg = verifyAttrs(values, exp, std::vector{}, + /*allow_unknown=*/false); + if (!err_msg.empty()) + { return err_msg; - } } - } - return ""; + for (auto &udf_fields : acl_table->udf_fields_lookup) + { + for (auto &udf_field : fvValue(udf_fields)) + { + sai_object_id_t udf_group_oid; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF_GROUP, udf_field.group_id, &udf_group_oid)) + { + return std::string("UDF group ") + udf_field.group_id + " does not exist"; + } + sai_object_id_t udf_oid; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_UDF, udf_field.udf_id, &udf_oid)) + { + return std::string("UDF ") + udf_field.udf_id + " does not exist"; + } + + // Verify UDF group. + attrs = getUdfGroupSaiAttrs(udf_field); + exp = saimeta::SaiAttributeList::serialize_attr_list(SAI_OBJECT_TYPE_UDF_GROUP, (uint32_t)attrs.size(), + attrs.data(), + /*countOnly=*/false); + key = sai_serialize_object_type(SAI_OBJECT_TYPE_UDF_GROUP) + ":" + sai_serialize_object_id(udf_group_oid); + values.clear(); + if (!table.get(key, values)) + { + return std::string("ASIC DB key not found ") + key; + } + err_msg = verifyAttrs(values, exp, std::vector{}, + /*allow_unknown=*/false); + if (!err_msg.empty()) + { + return err_msg; + } + + // Verify UDF. + attrs_or = getUdfSaiAttrs(udf_field); + if (!attrs_or.ok()) + { + return std::string("Failed to get SAI attrs: ") + attrs_or.status().message(); + } + attrs = *attrs_or; + exp = saimeta::SaiAttributeList::serialize_attr_list(SAI_OBJECT_TYPE_UDF, (uint32_t)attrs.size(), + attrs.data(), + /*countOnly=*/false); + key = sai_serialize_object_type(SAI_OBJECT_TYPE_UDF) + ":" + sai_serialize_object_id(udf_oid); + values.clear(); + if (!table.get(key, values)) + { + return std::string("ASIC DB key not found ") + key; + } + err_msg = verifyAttrs(values, exp, std::vector{}, + /*allow_unknown=*/false); + if (!err_msg.empty()) + { + return err_msg; + } + } + } + + return ""; } -} // namespace p4orch +} // namespace p4orch diff --git a/orchagent/p4orch/acl_table_manager.h b/orchagent/p4orch/acl_table_manager.h index 9c62a2522dd..68cc1c99208 100644 --- a/orchagent/p4orch/acl_table_manager.h +++ b/orchagent/p4orch/acl_table_manager.h @@ -13,125 +13,113 @@ #include "response_publisher_interface.h" #include "return_code.h" -extern "C" { +extern "C" +{ #include "sai.h" } -namespace p4orch { -namespace test { +namespace p4orch +{ +namespace test +{ class AclManagerTest; -} // namespace test - -class AclTableManager : public ObjectManagerInterface { - public: - explicit AclTableManager(P4OidMapper* p4oidMapper, - ResponsePublisherInterface* publisher); - virtual ~AclTableManager(); - - void enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) override; - void drain() override; - std::string verifyState( - const std::string& key, - const std::vector& tuple) override; - ReturnCode getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) override; - - // Get ACL table definition by table name in cache. Return nullptr if not - // found. - P4AclTableDefinition* getAclTable(const std::string& acl_table_name); - - private: - // Validate ACL table definition APP_DB entry. - ReturnCode validateAclTableDefinitionAppDbEntry( - const P4AclTableDefinitionAppDbEntry& app_db_entry); - - // Deserializes an entry from table APP_P4RT_ACL_TABLE_DEFINITION_NAME. - ReturnCodeOr - deserializeAclTableDefinitionAppDbEntry( - const std::string& key, - const std::vector& attributes); - - // Create new ACL table definition. - ReturnCode createAclTable(P4AclTableDefinition& acl_table, - sai_object_id_t* acl_table_oid, - sai_object_id_t* acl_group_member_oid); - - // Remove ACL table by table name. Caller should verify reference count is - // zero before calling the method. - ReturnCode removeAclTable(P4AclTableDefinition& acl_table); - - // Create UDF groups and UDFs for the ACL table. If any of the UDF and UDF - // group fails to create, then clean up all created ones - ReturnCode createUdfGroupsAndUdfsForAclTable( - const P4AclTableDefinition& acl_table); - - // Create new ACL UDF group based on the UdfField. Callers should verify no - // UDF group with the same name exists - ReturnCode createUdfGroup(const P4UdfField& udf_field); - - // Remove ACL UDF group by group id, - ReturnCode removeUdfGroup(const std::string& udf_group_id); - - // Create the default UDF match with name P4_UDF_MATCH_DEFAULT. - // The attributes values for the UDF match are all wildcard matches. - ReturnCode createDefaultUdfMatch(); - - // Remove the default UDF match if no UDFs depend on it. - ReturnCode removeDefaultUdfMatch(); - - // Create UDF with group_oid, base and offset defined in udf_field and the - // default udf_match_oid. Callers should verify no UDF with the same name - // exists - ReturnCode createUdf(const P4UdfField& udf_fields); - - // Remove UDF by id string and group id string if no ACL rules depends on it - ReturnCode removeUdf(const std::string& udf_id, - const std::string& udf_group_id); - - // Process add request on ACL table definition. If the table is - // created successfully, a new consumer will be added in - // p4orch to process requests for ACL rules for the table. - ReturnCode processAddTableRequest( - const P4AclTableDefinitionAppDbEntry& app_db_entry); - - // Process delete request on ACL table definition. - ReturnCode processDeleteTableRequest(const std::string& acl_table_name); - - // Create ACL group member for given ACL table. - ReturnCode createAclGroupMember(const P4AclTableDefinition& acl_table, - sai_object_id_t* acl_grp_mem_oid); - - // Remove ACL group member for given ACL table. - ReturnCode removeAclGroupMember(P4AclTableDefinition& acl_table); - - // Verifies internal cache for an entry. - std::string verifyStateCache( - const P4AclTableDefinitionAppDbEntry& app_db_entry, - const P4AclTableDefinition* acl_table); - - // Verifies ASIC DB for an entry. - std::string verifyStateAsicDb(const P4AclTableDefinition* acl_table); - - // Returns ACl table SAI attributes. - ReturnCodeOr> getTableSaiAttrs( - const P4AclTableDefinition& acl_table); - - // Returns UDF SAI attributes. - ReturnCodeOr> getUdfSaiAttrs( - const P4UdfField& udf_field); - - P4OidMapper* m_p4OidMapper; - ResponsePublisherInterface* m_publisher; - P4AclTableDefinitions m_aclTableDefinitions; - std::deque m_entries; - std::map> m_aclTablesByStage; - - // Always add counter action in ACL table action list during creation - int32_t m_acl_action_list[1]; - - friend class p4orch::test::AclManagerTest; +} // namespace test + +class AclTableManager : public ObjectManagerInterface +{ + public: + explicit AclTableManager(P4OidMapper *p4oidMapper, ResponsePublisherInterface *publisher); + virtual ~AclTableManager(); + + void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; + void drain() override; + std::string verifyState(const std::string &key, const std::vector &tuple) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; + + // Get ACL table definition by table name in cache. Return nullptr if not + // found. + P4AclTableDefinition *getAclTable(const std::string &acl_table_name); + + private: + // Validate ACL table definition APP_DB entry. + ReturnCode validateAclTableDefinitionAppDbEntry(const P4AclTableDefinitionAppDbEntry &app_db_entry); + + // Deserializes an entry from table APP_P4RT_ACL_TABLE_DEFINITION_NAME. + ReturnCodeOr deserializeAclTableDefinitionAppDbEntry( + const std::string &key, const std::vector &attributes); + + // Create new ACL table definition. + ReturnCode createAclTable(P4AclTableDefinition &acl_table, sai_object_id_t *acl_table_oid, + sai_object_id_t *acl_group_member_oid); + + // Remove ACL table by table name. Caller should verify reference count is + // zero before calling the method. + ReturnCode removeAclTable(P4AclTableDefinition &acl_table); + + // Create UDF groups and UDFs for the ACL table. If any of the UDF and UDF + // group fails to create, then clean up all created ones + ReturnCode createUdfGroupsAndUdfsForAclTable(const P4AclTableDefinition &acl_table); + + // Create new ACL UDF group based on the UdfField. Callers should verify no + // UDF group with the same name exists + ReturnCode createUdfGroup(const P4UdfField &udf_field); + + // Remove ACL UDF group by group id, + ReturnCode removeUdfGroup(const std::string &udf_group_id); + + // Create the default UDF match with name P4_UDF_MATCH_DEFAULT. + // The attributes values for the UDF match are all wildcard matches. + ReturnCode createDefaultUdfMatch(); + + // Remove the default UDF match if no UDFs depend on it. + ReturnCode removeDefaultUdfMatch(); + + // Create UDF with group_oid, base and offset defined in udf_field and the + // default udf_match_oid. Callers should verify no UDF with the same name + // exists + ReturnCode createUdf(const P4UdfField &udf_fields); + + // Remove UDF by id string and group id string if no ACL rules depends on it + ReturnCode removeUdf(const std::string &udf_id, const std::string &udf_group_id); + + // Process add request on ACL table definition. If the table is + // created successfully, a new consumer will be added in + // p4orch to process requests for ACL rules for the table. + ReturnCode processAddTableRequest(const P4AclTableDefinitionAppDbEntry &app_db_entry); + + // Process delete request on ACL table definition. + ReturnCode processDeleteTableRequest(const std::string &acl_table_name); + + // Create ACL group member for given ACL table. + ReturnCode createAclGroupMember(const P4AclTableDefinition &acl_table, sai_object_id_t *acl_grp_mem_oid); + + // Remove ACL group member for given ACL table. + ReturnCode removeAclGroupMember(P4AclTableDefinition &acl_table); + + // Verifies internal cache for an entry. + std::string verifyStateCache(const P4AclTableDefinitionAppDbEntry &app_db_entry, + const P4AclTableDefinition *acl_table); + + // Verifies ASIC DB for an entry. + std::string verifyStateAsicDb(const P4AclTableDefinition *acl_table); + + // Returns ACl table SAI attributes. + ReturnCodeOr> getTableSaiAttrs(const P4AclTableDefinition &acl_table); + + // Returns UDF SAI attributes. + ReturnCodeOr> getUdfSaiAttrs(const P4UdfField &udf_field); + + P4OidMapper *m_p4OidMapper; + ResponsePublisherInterface *m_publisher; + P4AclTableDefinitions m_aclTableDefinitions; + std::deque m_entries; + std::map> m_aclTablesByStage; + + // Always add counter action in ACL table action list during creation + int32_t m_acl_action_list[1]; + + friend class p4orch::test::AclManagerTest; }; -} // namespace p4orch +} // namespace p4orch diff --git a/orchagent/p4orch/acl_util.cpp b/orchagent/p4orch/acl_util.cpp index 28234873388..5ab2276b4db 100644 --- a/orchagent/p4orch/acl_util.cpp +++ b/orchagent/p4orch/acl_util.cpp @@ -8,809 +8,830 @@ #include "table.h" #include "tokenize.h" -namespace p4orch { +namespace p4orch +{ -bool parseAclTableAppDbActionField( - const std::string& aggr_actions_str, - std::vector* action_list, - std::vector* action_color_list) { - try { - const auto& j = nlohmann::json::parse(aggr_actions_str); - if (!j.is_array()) { - SWSS_LOG_ERROR( - "Invalid ACL table definition action %s, expecting an array.\n", - aggr_actions_str.c_str()); - return false; - } - P4ActionParamName action_with_param; - for (auto& action_item : j) { - auto sai_action_it = action_item.find(kAction); - if (sai_action_it == action_item.end()) { - SWSS_LOG_ERROR( - "Invalid ACL table definition action %s, missing 'action':\n", - aggr_actions_str.c_str()); +bool parseAclTableAppDbActionField(const std::string &aggr_actions_str, std::vector *action_list, + std::vector *action_color_list) +{ + try + { + const auto &j = nlohmann::json::parse(aggr_actions_str); + if (!j.is_array()) + { + SWSS_LOG_ERROR("Invalid ACL table definition action %s, expecting an array.\n", aggr_actions_str.c_str()); + return false; + } + P4ActionParamName action_with_param; + for (auto &action_item : j) + { + auto sai_action_it = action_item.find(kAction); + if (sai_action_it == action_item.end()) + { + SWSS_LOG_ERROR("Invalid ACL table definition action %s, missing 'action':\n", aggr_actions_str.c_str()); + return false; + } + if (aclPacketActionLookup.find(sai_action_it.value()) == aclPacketActionLookup.end()) + { + action_with_param.sai_action = sai_action_it.value(); + auto action_param_it = action_item.find(kActionParamPrefix); + if (action_param_it != action_item.end() && !action_param_it.value().is_null()) + { + action_with_param.p4_param_name = action_param_it.value(); + } + action_list->push_back(action_with_param); + } + else + { + auto packet_color_it = action_item.find(kPacketColor); + P4PacketActionWithColor packet_action_with_color; + packet_action_with_color.packet_action = sai_action_it.value(); + if (packet_color_it != action_item.end() && !packet_color_it.value().is_null()) + { + packet_action_with_color.packet_color = packet_color_it.value(); + } + action_color_list->push_back(packet_action_with_color); + } + } + return true; + } + catch (std::exception &ex) + { + SWSS_LOG_ERROR("Failed to deserialize ACL table definition action fields: %s (%s)", aggr_actions_str.c_str(), + ex.what()); return false; - } - if (aclPacketActionLookup.find(sai_action_it.value()) == - aclPacketActionLookup.end()) { - action_with_param.sai_action = sai_action_it.value(); - auto action_param_it = action_item.find(kActionParamPrefix); - if (action_param_it != action_item.end() && - !action_param_it.value().is_null()) { - action_with_param.p4_param_name = action_param_it.value(); - } - action_list->push_back(action_with_param); - } else { - auto packet_color_it = action_item.find(kPacketColor); - P4PacketActionWithColor packet_action_with_color; - packet_action_with_color.packet_action = sai_action_it.value(); - if (packet_color_it != action_item.end() && - !packet_color_it.value().is_null()) { - packet_action_with_color.packet_color = packet_color_it.value(); - } - action_color_list->push_back(packet_action_with_color); - } } - return true; - } catch (std::exception& ex) { - SWSS_LOG_ERROR( - "Failed to deserialize ACL table definition action fields: %s (%s)", - aggr_actions_str.c_str(), ex.what()); - return false; - } } -ReturnCode validateAndSetSaiMatchFieldJson( - const nlohmann::json& match_json, const std::string& p4_match, - const std::string& aggr_match_str, - std::map* sai_match_field_lookup, - std::map* ip_type_bit_type_lookup) { - SaiMatchField sai_match_field; - auto format_str_it = match_json.find(kAclMatchFieldFormat); - if (format_str_it == match_json.end() || format_str_it.value().is_null() || - !format_str_it.value().is_string()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: " << kAclMatchFieldFormat - << " value is required and should be a string"; - } - auto format_it = formatLookup.find(format_str_it.value()); - if (format_it == formatLookup.end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: " << kAclMatchFieldFormat - << " value is invalid, should be one of {" << P4_FORMAT_HEX_STRING - << ", " << P4_FORMAT_MAC << ", " << P4_FORMAT_IPV4 << ", " - << P4_FORMAT_IPV6 << ", " << P4_FORMAT_STRING << "}"; - } - sai_match_field.format = format_it->second; - if (sai_match_field.format != Format::STRING) { - // bitwidth is required if the format is not "STRING" - auto bitwidth_it = match_json.find(kAclMatchFieldBitwidth); - if (bitwidth_it == match_json.end() || bitwidth_it.value().is_null() || - !bitwidth_it.value().is_number()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: " - << kAclMatchFieldBitwidth - << " value is required and should be a number"; +ReturnCode validateAndSetSaiMatchFieldJson(const nlohmann::json &match_json, const std::string &p4_match, + const std::string &aggr_match_str, + std::map *sai_match_field_lookup, + std::map *ip_type_bit_type_lookup) +{ + SaiMatchField sai_match_field; + auto format_str_it = match_json.find(kAclMatchFieldFormat); + if (format_str_it == match_json.end() || format_str_it.value().is_null() || !format_str_it.value().is_string()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: " << kAclMatchFieldFormat + << " value is required and should be a string"; + } + auto format_it = formatLookup.find(format_str_it.value()); + if (format_it == formatLookup.end()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: " << kAclMatchFieldFormat + << " value is invalid, should be one of {" << P4_FORMAT_HEX_STRING << ", " << P4_FORMAT_MAC << ", " + << P4_FORMAT_IPV4 << ", " << P4_FORMAT_IPV6 << ", " << P4_FORMAT_STRING << "}"; + } + sai_match_field.format = format_it->second; + if (sai_match_field.format != Format::STRING) + { + // bitwidth is required if the format is not "STRING" + auto bitwidth_it = match_json.find(kAclMatchFieldBitwidth); + if (bitwidth_it == match_json.end() || bitwidth_it.value().is_null() || !bitwidth_it.value().is_number()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: " << kAclMatchFieldBitwidth + << " value is required and should be a number"; + } + sai_match_field.bitwidth = bitwidth_it.value(); } - sai_match_field.bitwidth = bitwidth_it.value(); - } - auto match_field_it = match_json.find(kAclMatchFieldSaiField); - if (match_field_it == match_json.end() || match_field_it.value().is_null() || - !match_field_it.value().is_string()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: " << kAclMatchFieldSaiField - << " value is required and should be a string"; - } + auto match_field_it = match_json.find(kAclMatchFieldSaiField); + if (match_field_it == match_json.end() || match_field_it.value().is_null() || !match_field_it.value().is_string()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: " << kAclMatchFieldSaiField + << " value is required and should be a string"; + } - std::vector tokenized_field = - swss::tokenize(match_field_it.value(), kFieldDelimiter); - const auto& sai_match_field_str = tokenized_field[0]; - auto table_attr_it = aclMatchTableAttrLookup.find(sai_match_field_str); - auto rule_attr_it = aclMatchEntryAttrLookup.find(sai_match_field_str); - if (table_attr_it == aclMatchTableAttrLookup.end() || - rule_attr_it == aclMatchEntryAttrLookup.end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: " << match_field_it.value() - << " is not supported in P4Orch "; - } - const auto& expected_format_it = - aclMatchTableAttrFormatLookup.find(table_attr_it->second); - if (expected_format_it == aclMatchTableAttrFormatLookup.end() || - sai_match_field.format != expected_format_it->second) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: format for field " - << match_field_it.value() << " is expected to be " - << expected_format_it->second << ", but got " << format_it->first; - } - sai_match_field.table_attr = table_attr_it->second; - sai_match_field.entry_attr = rule_attr_it->second; - (*sai_match_field_lookup)[p4_match] = sai_match_field; + std::vector tokenized_field = swss::tokenize(match_field_it.value(), kFieldDelimiter); + const auto &sai_match_field_str = tokenized_field[0]; + auto table_attr_it = aclMatchTableAttrLookup.find(sai_match_field_str); + auto rule_attr_it = aclMatchEntryAttrLookup.find(sai_match_field_str); + if (table_attr_it == aclMatchTableAttrLookup.end() || rule_attr_it == aclMatchEntryAttrLookup.end()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: " << match_field_it.value() << " is not supported in P4Orch "; + } + const auto &expected_format_it = aclMatchTableAttrFormatLookup.find(table_attr_it->second); + if (expected_format_it == aclMatchTableAttrFormatLookup.end() || + sai_match_field.format != expected_format_it->second) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: format for field " << match_field_it.value() + << " is expected to be " << expected_format_it->second << ", but got " << format_it->first; + } + sai_match_field.table_attr = table_attr_it->second; + sai_match_field.entry_attr = rule_attr_it->second; + (*sai_match_field_lookup)[p4_match] = sai_match_field; - if (rule_attr_it->second == SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE && - tokenized_field.size() == 2) { - // Get IP_TYPE suffix and save the bit mapping. - if (aclIpTypeBitSet.find(tokenized_field[1]) == aclIpTypeBitSet.end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} has invalid IP_TYPE encode bit."; - } - (*ip_type_bit_type_lookup)[p4_match] = tokenized_field[1]; - } - SWSS_LOG_INFO("ACL table built match field %s with kind:sai_field", - sai_match_field_str.c_str()); + if (rule_attr_it->second == SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE && tokenized_field.size() == 2) + { + // Get IP_TYPE suffix and save the bit mapping. + if (aclIpTypeBitSet.find(tokenized_field[1]) == aclIpTypeBitSet.end()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} has invalid IP_TYPE encode bit."; + } + (*ip_type_bit_type_lookup)[p4_match] = tokenized_field[1]; + } + SWSS_LOG_INFO("ACL table built match field %s with kind:sai_field", sai_match_field_str.c_str()); - return ReturnCode(); + return ReturnCode(); } ReturnCode validateAndSetCompositeElementSaiFieldJson( - const nlohmann::json& element_match_json, const std::string& p4_match, - std::map>* - composite_sai_match_fields_lookup, - const std::string& format_str) { - SaiMatchField sai_match_field; - const auto& element_str = element_match_json.dump(); - if (format_str != P4_FORMAT_IPV6) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field " << p4_match - << " element: " << element_str - << " is an invalid ACL table attribute: '" << kAclMatchFieldFormat - << "' should be " << P4_FORMAT_IPV6; - } - sai_match_field.format = Format::IPV6; + const nlohmann::json &element_match_json, const std::string &p4_match, + std::map> *composite_sai_match_fields_lookup, const std::string &format_str) +{ + SaiMatchField sai_match_field; + const auto &element_str = element_match_json.dump(); + if (format_str != P4_FORMAT_IPV6) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field " << p4_match << " element: " << element_str + << " is an invalid ACL table attribute: '" << kAclMatchFieldFormat << "' should be " << P4_FORMAT_IPV6; + } + sai_match_field.format = Format::IPV6; - auto bitwidth_it = element_match_json.find(kAclMatchFieldBitwidth); - if (bitwidth_it == element_match_json.end() || - bitwidth_it.value().is_null() || !bitwidth_it.value().is_number()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field " << p4_match << "element: " << element_str - << " is an invalid ACL table attribute: " << kAclMatchFieldBitwidth - << " value is required and should be a number"; - } - sai_match_field.bitwidth = bitwidth_it.value(); + auto bitwidth_it = element_match_json.find(kAclMatchFieldBitwidth); + if (bitwidth_it == element_match_json.end() || bitwidth_it.value().is_null() || !bitwidth_it.value().is_number()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field " << p4_match << "element: " << element_str + << " is an invalid ACL table attribute: " << kAclMatchFieldBitwidth + << " value is required and should be a number"; + } + sai_match_field.bitwidth = bitwidth_it.value(); - auto match_field_it = element_match_json.find(kAclMatchFieldSaiField); - if (match_field_it == element_match_json.end() || - match_field_it.value().is_null() || !match_field_it.value().is_string()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field " << p4_match - << " element: " << element_str - << " is an invalid ACL table attribute: " << kAclMatchFieldSaiField - << " value is required in composite elements and should be a string"; - } - const std::string& match_field_str = match_field_it.value(); - auto table_attr_it = aclCompositeMatchTableAttrLookup.find(match_field_str); - auto rule_attr_it = aclCompositeMatchEntryAttrLookup.find(match_field_str); - if (table_attr_it == aclCompositeMatchTableAttrLookup.end() || - rule_attr_it == aclCompositeMatchEntryAttrLookup.end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field " << p4_match - << " element: " << element_str - << " is an invalid ACL table attribute: not supported in P4Orch " - "as an element in composite match fields"; - } - const uint32_t expected_bitwidth = - BYTE_BITWIDTH * IPV6_SINGLE_WORD_BYTES_LENGTH; - if (sai_match_field.bitwidth != expected_bitwidth) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field " << p4_match - << " element: " << element_str - << " is an invalid ACL table attribute: element.bitwidth is " - "expected to be " - << expected_bitwidth << " but got " << sai_match_field.bitwidth; - } - sai_match_field.table_attr = table_attr_it->second; - sai_match_field.entry_attr = rule_attr_it->second; - (*composite_sai_match_fields_lookup)[p4_match].push_back(sai_match_field); - SWSS_LOG_INFO( - "ACL table built composite match field element %s with kind:sai_field", - match_field_str.c_str()); - return ReturnCode(); + auto match_field_it = element_match_json.find(kAclMatchFieldSaiField); + if (match_field_it == element_match_json.end() || match_field_it.value().is_null() || + !match_field_it.value().is_string()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field " << p4_match << " element: " << element_str + << " is an invalid ACL table attribute: " << kAclMatchFieldSaiField + << " value is required in composite elements and should be a string"; + } + const std::string &match_field_str = match_field_it.value(); + auto table_attr_it = aclCompositeMatchTableAttrLookup.find(match_field_str); + auto rule_attr_it = aclCompositeMatchEntryAttrLookup.find(match_field_str); + if (table_attr_it == aclCompositeMatchTableAttrLookup.end() || + rule_attr_it == aclCompositeMatchEntryAttrLookup.end()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field " << p4_match << " element: " << element_str + << " is an invalid ACL table attribute: not supported in P4Orch " + "as an element in composite match fields"; + } + const uint32_t expected_bitwidth = BYTE_BITWIDTH * IPV6_SINGLE_WORD_BYTES_LENGTH; + if (sai_match_field.bitwidth != expected_bitwidth) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field " << p4_match << " element: " << element_str + << " is an invalid ACL table attribute: element.bitwidth is " + "expected to be " + << expected_bitwidth << " but got " << sai_match_field.bitwidth; + } + sai_match_field.table_attr = table_attr_it->second; + sai_match_field.entry_attr = rule_attr_it->second; + (*composite_sai_match_fields_lookup)[p4_match].push_back(sai_match_field); + SWSS_LOG_INFO("ACL table built composite match field element %s with kind:sai_field", match_field_str.c_str()); + return ReturnCode(); } -ReturnCode validateAndSetUdfFieldJson( - const nlohmann::json& match_json, const std::string& p4_match, - const std::string& aggr_match_str, const std::string& acl_table_name, - std::map>* udf_fields_lookup, - std::map* udf_group_attr_index_lookup) { - P4UdfField udf_field; - // Parse UDF bitwitdth - auto bitwidth_json_it = match_json.find(kAclMatchFieldBitwidth); - if (bitwidth_json_it == match_json.end() || - bitwidth_json_it.value().is_null() || - !bitwidth_json_it.value().is_number()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match composite UDF field {" << p4_match << ": " - << aggr_match_str - << "} is an invalid ACL table attribute: " << kAclMatchFieldBitwidth - << " value is required and should be a number"; - } - uint32_t bitwidth = bitwidth_json_it.value(); - if (bitwidth % BYTE_BITWIDTH != 0) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match composite UDF field {" << p4_match << ": " - << aggr_match_str - << "} is an invalid ACL table attribute: " << kAclMatchFieldBitwidth - << " value should be a multiple of 8."; - } - udf_field.length = (uint16_t)(bitwidth / BYTE_BITWIDTH); +ReturnCode validateAndSetUdfFieldJson(const nlohmann::json &match_json, const std::string &p4_match, + const std::string &aggr_match_str, const std::string &acl_table_name, + std::map> *udf_fields_lookup, + std::map *udf_group_attr_index_lookup) +{ + P4UdfField udf_field; + // Parse UDF bitwitdth + auto bitwidth_json_it = match_json.find(kAclMatchFieldBitwidth); + if (bitwidth_json_it == match_json.end() || bitwidth_json_it.value().is_null() || + !bitwidth_json_it.value().is_number()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match composite UDF field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: " << kAclMatchFieldBitwidth + << " value is required and should be a number"; + } + uint32_t bitwidth = bitwidth_json_it.value(); + if (bitwidth % BYTE_BITWIDTH != 0) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match composite UDF field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: " << kAclMatchFieldBitwidth + << " value should be a multiple of 8."; + } + udf_field.length = (uint16_t)(bitwidth / BYTE_BITWIDTH); - // Parse UDF offset - auto udf_offset_it = match_json.find(kAclUdfOffset); - if (udf_offset_it == match_json.end() || udf_offset_it.value().is_null() || - !udf_offset_it.value().is_number()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match composite UDF field {" << p4_match << ": " - << aggr_match_str - << "} is an invalid ACL table attribute: " << kAclUdfOffset - << " value is required in composite elements and should be a number"; - } - udf_field.offset = udf_offset_it.value(); + // Parse UDF offset + auto udf_offset_it = match_json.find(kAclUdfOffset); + if (udf_offset_it == match_json.end() || udf_offset_it.value().is_null() || !udf_offset_it.value().is_number()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match composite UDF field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: " << kAclUdfOffset + << " value is required in composite elements and should be a number"; + } + udf_field.offset = udf_offset_it.value(); - // Parse UDF base - auto udf_base_json_it = match_json.find(kAclUdfBase); - if (udf_base_json_it == match_json.end() || - udf_base_json_it.value().is_null() || - !udf_base_json_it.value().is_string()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match composite UDF field {" << p4_match << ": " - << aggr_match_str - << "} is an invalid ACL table attribute: " << kAclUdfBase - << " value is required in composite elements and should be a string"; - } - const auto& udf_base_it = udfBaseLookup.find(udf_base_json_it.value()); - if (udf_base_it == udfBaseLookup.end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match composite UDF field {" << p4_match << ": " - << aggr_match_str << "} is an invalid ACL table attribute: " - << udf_base_json_it.value() - << " is not supported in P4Orch " - "as a valid UDF base. Supported UDF bases are: " - << P4_UDF_BASE_L2 << ", " << P4_UDF_BASE_L3 << " and " - << P4_UDF_BASE_L4; - } - udf_field.base = udf_base_it->second; - // Set UDF group id - udf_field.group_id = acl_table_name + "-" + p4_match + "-" + - std::to_string((*udf_fields_lookup)[p4_match].size()); - udf_field.udf_id = udf_field.group_id + "-base" + - std::to_string(udf_field.base) + "-offset" + - std::to_string(udf_field.offset); - (*udf_fields_lookup)[p4_match].push_back(udf_field); - // Assign UDF group to a new ACL entry attr index if it is a new group - uint16_t index = 0; - auto udf_group_attr_index_it = - udf_group_attr_index_lookup->find(udf_field.group_id); - if (udf_group_attr_index_it != udf_group_attr_index_lookup->end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Error when building UDF field for ACL talbe: duplicated UDF " - "groups found for the same index."; - } - index = (uint16_t)udf_group_attr_index_lookup->size(); - (*udf_group_attr_index_lookup)[udf_field.group_id] = index; - SWSS_LOG_INFO( - "ACL table built composite match field elelment %s with kind:udf", - udf_field.group_id.c_str()); - return ReturnCode(); + // Parse UDF base + auto udf_base_json_it = match_json.find(kAclUdfBase); + if (udf_base_json_it == match_json.end() || udf_base_json_it.value().is_null() || + !udf_base_json_it.value().is_string()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match composite UDF field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: " << kAclUdfBase + << " value is required in composite elements and should be a string"; + } + const auto &udf_base_it = udfBaseLookup.find(udf_base_json_it.value()); + if (udf_base_it == udfBaseLookup.end()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match composite UDF field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: " << udf_base_json_it.value() + << " is not supported in P4Orch " + "as a valid UDF base. Supported UDF bases are: " + << P4_UDF_BASE_L2 << ", " << P4_UDF_BASE_L3 << " and " << P4_UDF_BASE_L4; + } + udf_field.base = udf_base_it->second; + // Set UDF group id + udf_field.group_id = acl_table_name + "-" + p4_match + "-" + std::to_string((*udf_fields_lookup)[p4_match].size()); + udf_field.udf_id = + udf_field.group_id + "-base" + std::to_string(udf_field.base) + "-offset" + std::to_string(udf_field.offset); + (*udf_fields_lookup)[p4_match].push_back(udf_field); + // Assign UDF group to a new ACL entry attr index if it is a new group + uint16_t index = 0; + auto udf_group_attr_index_it = udf_group_attr_index_lookup->find(udf_field.group_id); + if (udf_group_attr_index_it != udf_group_attr_index_lookup->end()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Error when building UDF field for ACL talbe: duplicated UDF " + "groups found for the same index."; + } + index = (uint16_t)udf_group_attr_index_lookup->size(); + (*udf_group_attr_index_lookup)[udf_field.group_id] = index; + SWSS_LOG_INFO("ACL table built composite match field elelment %s with kind:udf", udf_field.group_id.c_str()); + return ReturnCode(); } ReturnCode validateAndSetCompositeMatchFieldJson( - const nlohmann::json& aggr_match_json, const std::string& p4_match, - const std::string& aggr_match_str, const std::string& acl_table_name, - std::map>* - composite_sai_match_fields_lookup, - std::map>* udf_fields_lookup, - std::map* udf_group_attr_index_lookups) { - auto format_str_it = aggr_match_json.find(kAclMatchFieldFormat); - if (format_str_it == aggr_match_json.end() || - format_str_it.value().is_null() || !format_str_it.value().is_string()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: " << kAclMatchFieldFormat - << " value is required and should be a string"; - } - auto format_it = formatLookup.find(format_str_it.value()); - if (format_it == formatLookup.end() || format_it->second == Format::STRING) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: " << kAclMatchFieldFormat - << " value is invalid, should be one of {" << P4_FORMAT_HEX_STRING - << ", " << P4_FORMAT_IPV6 << "}"; - } - auto bitwidth_it = aggr_match_json.find(kAclMatchFieldBitwidth); - if (bitwidth_it == aggr_match_json.end() || bitwidth_it.value().is_null() || - !bitwidth_it.value().is_number()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: " << kAclMatchFieldBitwidth - << " value is required and should be a number"; - } - uint32_t composite_bitwidth = bitwidth_it.value(); - - auto elements_it = aggr_match_json.find(kAclMatchFieldElements); - // TODO: temp disable verification on composite elements field until p4rt - // implementation is added. - if (elements_it == aggr_match_json.end()) { - (*udf_fields_lookup)[p4_match]; - return ReturnCode(); - } - if (elements_it.value().is_null() || !elements_it.value().is_array()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: 'elements' value is " - "required and should be an array"; - } - for (const auto& element : elements_it.value()) { - if (element.is_null() || !element.is_object()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: 'elements' member " - "should be an json"; - } - const auto& element_kind_it = element.find(kAclMatchFieldKind); - if (element_kind_it == element.end() || element_kind_it.value().is_null() || - !element_kind_it.value().is_string()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: composite element " - "'kind' value is required and should be a string"; - } - ReturnCode rc; - if (element_kind_it.value() == kAclMatchFieldSaiField) { - rc = validateAndSetCompositeElementSaiFieldJson( - element, p4_match, composite_sai_match_fields_lookup, - format_str_it.value()); - } else if (element_kind_it.value() == kAclMatchFieldKindUdf) { - if (format_str_it.value() != P4_FORMAT_HEX_STRING) { + const nlohmann::json &aggr_match_json, const std::string &p4_match, const std::string &aggr_match_str, + const std::string &acl_table_name, + std::map> *composite_sai_match_fields_lookup, + std::map> *udf_fields_lookup, + std::map *udf_group_attr_index_lookups) +{ + auto format_str_it = aggr_match_json.find(kAclMatchFieldFormat); + if (format_str_it == aggr_match_json.end() || format_str_it.value().is_null() || !format_str_it.value().is_string()) + { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " - << aggr_match_str << "} is an invalid ACL table attribute: " - << kAclMatchFieldFormat - << " value should be HEX_STRING for UDF field"; - } - rc = validateAndSetUdfFieldJson(element, p4_match, aggr_match_str, - acl_table_name, udf_fields_lookup, - udf_group_attr_index_lookups); - } else { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: composite element " - "'kind' should be either " - << kAclMatchFieldKindUdf << " or " << kAclMatchFieldSaiField; - } - if (!rc.ok()) return rc; - } - // elements kind should be all sai_field or all udf. - auto sai_field_it = composite_sai_match_fields_lookup->find(p4_match); - auto udf_field_it = udf_fields_lookup->find(p4_match); - if (sai_field_it != composite_sai_match_fields_lookup->end() && - udf_field_it != udf_fields_lookup->end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: composite element " - "'kind' should be consistent within all elements."; - } - // The sum of bitwidth of elements should equals overall bitwidth defined - // in composite fields - uint32_t total_bitwidth = 0; - if (sai_field_it != composite_sai_match_fields_lookup->end()) { - // IPV6_64bit(IPV6_WORD3 and IPV6_WORD2 in elements, kind:sai_field, - // format:IPV6) - if (sai_field_it->second.size() != 2) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: composite match field " - "with sai_field in element kind should have 2 elements."; - } - if (!((sai_field_it->second[0].table_attr == - SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6_WORD3 && - sai_field_it->second[1].table_attr == - SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6_WORD2) || - (sai_field_it->second[0].table_attr == - SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD3 && - sai_field_it->second[1].table_attr == - SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2))) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: For composite match " - "field " - "with element.kind == sai_field, the SAI match field " - "in elements list should be either pair {" - << P4_MATCH_DST_IPV6_WORD3 << ", " << P4_MATCH_DST_IPV6_WORD2 - << "} or pair {" << P4_MATCH_SRC_IPV6_WORD3 << ", " - << P4_MATCH_SRC_IPV6_WORD2 << "} with the correct sequence"; - } - total_bitwidth = - sai_field_it->second[0].bitwidth + sai_field_it->second[1].bitwidth; - } - if (udf_field_it != udf_fields_lookup->end()) { - for (const auto& udf_field : udf_field_it->second) { - total_bitwidth += (uint32_t)udf_field.length * BYTE_BITWIDTH; - } - } - if (total_bitwidth != composite_bitwidth) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: composite bitwidth " - "does not equal with the sum of elements bitwidth."; - } - return ReturnCode(); -} - -ReturnCode buildAclTableDefinitionMatchFieldValues( - const std::map& match_field_lookup, - P4AclTableDefinition* acl_table) { - for (const auto& raw_match_field : match_field_lookup) { - const auto& p4_match = fvField(raw_match_field); - const auto& aggr_match_str = fvValue(raw_match_field); - try { - const auto& aggr_match_json = nlohmann::json::parse(aggr_match_str); - if (!aggr_match_json.is_object()) { + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: " << kAclMatchFieldFormat + << " value is required and should be a string"; + } + auto format_it = formatLookup.find(format_str_it.value()); + if (format_it == formatLookup.end() || format_it->second == Format::STRING) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: " << kAclMatchFieldFormat + << " value is invalid, should be one of {" << P4_FORMAT_HEX_STRING << ", " << P4_FORMAT_IPV6 << "}"; + } + auto bitwidth_it = aggr_match_json.find(kAclMatchFieldBitwidth); + if (bitwidth_it == aggr_match_json.end() || bitwidth_it.value().is_null() || !bitwidth_it.value().is_number()) + { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " - << aggr_match_str - << "} is an invalid ACL table attribute: expecting an json"; - } + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: " << kAclMatchFieldBitwidth + << " value is required and should be a number"; + } + uint32_t composite_bitwidth = bitwidth_it.value(); - const auto& kind_it = aggr_match_json.find(kAclMatchFieldKind); - if (kind_it == aggr_match_json.end() || kind_it.value().is_null() || - !kind_it.value().is_string()) { + auto elements_it = aggr_match_json.find(kAclMatchFieldElements); + // TODO: temp disable verification on composite elements field until p4rt + // implementation is added. + if (elements_it == aggr_match_json.end()) + { + (*udf_fields_lookup)[p4_match]; + return ReturnCode(); + } + if (elements_it.value().is_null() || !elements_it.value().is_array()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: 'elements' value is " + "required and should be an array"; + } + for (const auto &element : elements_it.value()) + { + if (element.is_null() || !element.is_object()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: 'elements' member " + "should be an json"; + } + const auto &element_kind_it = element.find(kAclMatchFieldKind); + if (element_kind_it == element.end() || element_kind_it.value().is_null() || + !element_kind_it.value().is_string()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: composite element " + "'kind' value is required and should be a string"; + } + ReturnCode rc; + if (element_kind_it.value() == kAclMatchFieldSaiField) + { + rc = validateAndSetCompositeElementSaiFieldJson(element, p4_match, composite_sai_match_fields_lookup, + format_str_it.value()); + } + else if (element_kind_it.value() == kAclMatchFieldKindUdf) + { + if (format_str_it.value() != P4_FORMAT_HEX_STRING) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: " << kAclMatchFieldFormat + << " value should be HEX_STRING for UDF field"; + } + rc = validateAndSetUdfFieldJson(element, p4_match, aggr_match_str, acl_table_name, udf_fields_lookup, + udf_group_attr_index_lookups); + } + else + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: composite element " + "'kind' should be either " + << kAclMatchFieldKindUdf << " or " << kAclMatchFieldSaiField; + } + if (!rc.ok()) + return rc; + } + // elements kind should be all sai_field or all udf. + auto sai_field_it = composite_sai_match_fields_lookup->find(p4_match); + auto udf_field_it = udf_fields_lookup->find(p4_match); + if (sai_field_it != composite_sai_match_fields_lookup->end() && udf_field_it != udf_fields_lookup->end()) + { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " - << aggr_match_str - << "} is an invalid ACL table attribute: 'kind' value is " - "required and should be a string"; - } - ReturnCode rc; - if (kind_it.value() == kAclMatchFieldSaiField) { - rc = validateAndSetSaiMatchFieldJson( - aggr_match_json, p4_match, aggr_match_str, - &acl_table->sai_match_field_lookup, - &acl_table->ip_type_bit_type_lookup); - } else if (kind_it.value() == kAclMatchFieldKindComposite) { - rc = validateAndSetCompositeMatchFieldJson( - aggr_match_json, p4_match, aggr_match_str, - acl_table->acl_table_name, - &acl_table->composite_sai_match_fields_lookup, - &acl_table->udf_fields_lookup, - &acl_table->udf_group_attr_index_lookup); - } else if (kind_it.value() == kAclMatchFieldKindUdf) { - auto format_str_it = aggr_match_json.find(kAclMatchFieldFormat); - if (format_str_it == aggr_match_json.end() || - format_str_it.value().is_null() || - !format_str_it.value().is_string()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " - << aggr_match_str << "} is an invalid ACL table attribute: " - << kAclMatchFieldFormat - << " value is required and should be a string"; - } - if (format_str_it.value() != P4_FORMAT_HEX_STRING) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " - << aggr_match_str << "} is an invalid ACL table attribute: " - << kAclMatchFieldFormat - << " value should be HEX_STRING for UDF field"; - } - rc = validateAndSetUdfFieldJson( - aggr_match_json, p4_match, aggr_match_str, - acl_table->acl_table_name, &acl_table->udf_fields_lookup, - &acl_table->udf_group_attr_index_lookup); - } else { + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: composite element " + "'kind' should be consistent within all elements."; + } + // The sum of bitwidth of elements should equals overall bitwidth defined + // in composite fields + uint32_t total_bitwidth = 0; + if (sai_field_it != composite_sai_match_fields_lookup->end()) + { + // IPV6_64bit(IPV6_WORD3 and IPV6_WORD2 in elements, kind:sai_field, + // format:IPV6) + if (sai_field_it->second.size() != 2) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: composite match field " + "with sai_field in element kind should have 2 elements."; + } + if (!((sai_field_it->second[0].table_attr == SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6_WORD3 && + sai_field_it->second[1].table_attr == SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6_WORD2) || + (sai_field_it->second[0].table_attr == SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD3 && + sai_field_it->second[1].table_attr == SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2))) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: For composite match " + "field " + "with element.kind == sai_field, the SAI match field " + "in elements list should be either pair {" + << P4_MATCH_DST_IPV6_WORD3 << ", " << P4_MATCH_DST_IPV6_WORD2 << "} or pair {" + << P4_MATCH_SRC_IPV6_WORD3 << ", " << P4_MATCH_SRC_IPV6_WORD2 << "} with the correct sequence"; + } + total_bitwidth = sai_field_it->second[0].bitwidth + sai_field_it->second[1].bitwidth; + } + if (udf_field_it != udf_fields_lookup->end()) + { + for (const auto &udf_field : udf_field_it->second) + { + total_bitwidth += (uint32_t)udf_field.length * BYTE_BITWIDTH; + } + } + if (total_bitwidth != composite_bitwidth) + { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " - << aggr_match_str - << "} is an invalid ACL table attribute: 'kind' is expecting " - "one of {" - << kAclMatchFieldKindComposite << ", " << kAclMatchFieldSaiField - << ", " << kAclMatchFieldKindUdf << "}."; - } - if (!rc.ok()) return rc; - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table match field {" << p4_match << ": " << aggr_match_str - << "} is an invalid ACL table attribute: ex" << ex.what(); - } - } - return ReturnCode(); + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: composite bitwidth " + "does not equal with the sum of elements bitwidth."; + } + return ReturnCode(); +} + +ReturnCode buildAclTableDefinitionMatchFieldValues(const std::map &match_field_lookup, + P4AclTableDefinition *acl_table) +{ + for (const auto &raw_match_field : match_field_lookup) + { + const auto &p4_match = fvField(raw_match_field); + const auto &aggr_match_str = fvValue(raw_match_field); + try + { + const auto &aggr_match_json = nlohmann::json::parse(aggr_match_str); + if (!aggr_match_json.is_object()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: expecting an json"; + } + + const auto &kind_it = aggr_match_json.find(kAclMatchFieldKind); + if (kind_it == aggr_match_json.end() || kind_it.value().is_null() || !kind_it.value().is_string()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: 'kind' value is " + "required and should be a string"; + } + ReturnCode rc; + if (kind_it.value() == kAclMatchFieldSaiField) + { + rc = validateAndSetSaiMatchFieldJson(aggr_match_json, p4_match, aggr_match_str, + &acl_table->sai_match_field_lookup, + &acl_table->ip_type_bit_type_lookup); + } + else if (kind_it.value() == kAclMatchFieldKindComposite) + { + rc = validateAndSetCompositeMatchFieldJson( + aggr_match_json, p4_match, aggr_match_str, acl_table->acl_table_name, + &acl_table->composite_sai_match_fields_lookup, &acl_table->udf_fields_lookup, + &acl_table->udf_group_attr_index_lookup); + } + else if (kind_it.value() == kAclMatchFieldKindUdf) + { + auto format_str_it = aggr_match_json.find(kAclMatchFieldFormat); + if (format_str_it == aggr_match_json.end() || format_str_it.value().is_null() || + !format_str_it.value().is_string()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: " << kAclMatchFieldFormat + << " value is required and should be a string"; + } + if (format_str_it.value() != P4_FORMAT_HEX_STRING) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: " << kAclMatchFieldFormat + << " value should be HEX_STRING for UDF field"; + } + rc = validateAndSetUdfFieldJson(aggr_match_json, p4_match, aggr_match_str, acl_table->acl_table_name, + &acl_table->udf_fields_lookup, &acl_table->udf_group_attr_index_lookup); + } + else + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: 'kind' is expecting " + "one of {" + << kAclMatchFieldKindComposite << ", " << kAclMatchFieldSaiField << ", " << kAclMatchFieldKindUdf + << "}."; + } + if (!rc.ok()) + return rc; + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table match field {" << p4_match << ": " << aggr_match_str + << "} is an invalid ACL table attribute: ex" << ex.what(); + } + } + return ReturnCode(); } ReturnCode buildAclTableDefinitionActionFieldValues( - const std::map>& - action_field_lookup, - std::map>* - aggr_sai_actions_lookup) { - SaiActionWithParam action_with_param; - for (const auto& aggr_action_field : action_field_lookup) { - auto& aggr_sai_actions = - (*aggr_sai_actions_lookup)[fvField(aggr_action_field)]; - for (const auto& single_action : fvValue(aggr_action_field)) { - auto rule_action_it = aclActionLookup.find(single_action.sai_action); - if (rule_action_it == aclActionLookup.end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table action is invalid: " << single_action.sai_action; - } - action_with_param.action = rule_action_it->second; - action_with_param.param_name = single_action.p4_param_name; - aggr_sai_actions.push_back(action_with_param); - } - } - return ReturnCode(); + const std::map> &action_field_lookup, + std::map> *aggr_sai_actions_lookup) +{ + SaiActionWithParam action_with_param; + for (const auto &aggr_action_field : action_field_lookup) + { + auto &aggr_sai_actions = (*aggr_sai_actions_lookup)[fvField(aggr_action_field)]; + for (const auto &single_action : fvValue(aggr_action_field)) + { + auto rule_action_it = aclActionLookup.find(single_action.sai_action); + if (rule_action_it == aclActionLookup.end()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table action is invalid: " << single_action.sai_action; + } + action_with_param.action = rule_action_it->second; + action_with_param.param_name = single_action.p4_param_name; + aggr_sai_actions.push_back(action_with_param); + } + } + return ReturnCode(); } ReturnCode buildAclTableDefinitionActionColorFieldValues( - const std::map>& - action_color_lookup, - std::map>* - aggr_sai_actions_lookup, - std::map>* - aggr_sai_action_color_lookup) { - for (const auto& aggr_action_color : action_color_lookup) { - auto& aggr_sai_actions = - (*aggr_sai_actions_lookup)[fvField(aggr_action_color)]; - auto& aggr_sai_action_color = - (*aggr_sai_action_color_lookup)[fvField(aggr_action_color)]; - for (const auto& action_color : fvValue(aggr_action_color)) { - auto packet_action_it = - aclPacketActionLookup.find(action_color.packet_action); - if (packet_action_it == aclPacketActionLookup.end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table packet action is invalid: " - << action_color.packet_action; - } + const std::map> &action_color_lookup, + std::map> *aggr_sai_actions_lookup, + std::map> *aggr_sai_action_color_lookup) +{ + for (const auto &aggr_action_color : action_color_lookup) + { + auto &aggr_sai_actions = (*aggr_sai_actions_lookup)[fvField(aggr_action_color)]; + auto &aggr_sai_action_color = (*aggr_sai_action_color_lookup)[fvField(aggr_action_color)]; + for (const auto &action_color : fvValue(aggr_action_color)) + { + auto packet_action_it = aclPacketActionLookup.find(action_color.packet_action); + if (packet_action_it == aclPacketActionLookup.end()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table packet action is invalid: " << action_color.packet_action; + } - if (action_color.packet_color.empty()) { - // Handle packet action without packet color, set ACL entry attribute - SaiActionWithParam action_with_param; - action_with_param.action = SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION; - action_with_param.param_name = EMPTY_STRING; - action_with_param.param_value = action_color.packet_action; - aggr_sai_actions.push_back(action_with_param); - continue; - } + if (action_color.packet_color.empty()) + { + // Handle packet action without packet color, set ACL entry attribute + SaiActionWithParam action_with_param; + action_with_param.action = SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION; + action_with_param.param_name = EMPTY_STRING; + action_with_param.param_value = action_color.packet_action; + aggr_sai_actions.push_back(action_with_param); + continue; + } - // Handle packet action with packet color, set ACL policer attribute - auto packet_color_it = - aclPacketColorPolicerAttrLookup.find(action_color.packet_color); - if (packet_color_it == aclPacketColorPolicerAttrLookup.end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL table packet color is invalid: " - << action_color.packet_color; - } - aggr_sai_action_color[packet_color_it->second] = packet_action_it->second; + // Handle packet action with packet color, set ACL policer attribute + auto packet_color_it = aclPacketColorPolicerAttrLookup.find(action_color.packet_color); + if (packet_color_it == aclPacketColorPolicerAttrLookup.end()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL table packet color is invalid: " << action_color.packet_color; + } + aggr_sai_action_color[packet_color_it->second] = packet_action_it->second; + } } - } - return ReturnCode(); + return ReturnCode(); } bool isSetUserTrapActionInAclTableDefinition( - const std::map>& - aggr_sai_actions_lookup) { - for (const auto& aggr_action : aggr_sai_actions_lookup) { - for (const auto& sai_action : fvValue(aggr_action)) { - if (sai_action.action == SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID) - return true; + const std::map> &aggr_sai_actions_lookup) +{ + for (const auto &aggr_action : aggr_sai_actions_lookup) + { + for (const auto &sai_action : fvValue(aggr_action)) + { + if (sai_action.action == SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID) + return true; + } } - } - return false; + return false; } -bool setMatchFieldIpType(const std::string& attr_value, - sai_attribute_value_t* value, - const std::string& ip_type_bit_type) { - SWSS_LOG_ENTER(); - if (ip_type_bit_type == EMPTY_STRING) { - SWSS_LOG_ERROR("Invalid IP type %s, bit type is not defined.", - attr_value.c_str()); - return false; - } - // go/p4-ip-type - const auto& ip_type_bit_data_mask = - swss::tokenize(attr_value, kDataMaskDelimiter); - if (ip_type_bit_data_mask.size() == 2 && - swss::to_uint(trim(ip_type_bit_data_mask[1])) == 0) { - SWSS_LOG_ERROR( - "Invalid IP_TYPE mask %s for bit type %s: ip type bit mask " - "should not be zero.", - attr_value.c_str(), ip_type_bit_type.c_str()); - return false; - } - int ip_type_bit_data = std::stoi(ip_type_bit_data_mask[0], nullptr, 0); - value->aclfield.mask.u32 = 0xFFFFFFFF; - if (ip_type_bit_type == P4_IP_TYPE_BIT_IP) { - if (ip_type_bit_data) { - value->aclfield.data.u32 = SAI_ACL_IP_TYPE_IP; - } else { - value->aclfield.data.u32 = SAI_ACL_IP_TYPE_NON_IP; - } - } else if (ip_type_bit_type == P4_IP_TYPE_BIT_IPV4ANY) { - if (ip_type_bit_data) { - value->aclfield.data.u32 = SAI_ACL_IP_TYPE_IPV4ANY; - } else { - value->aclfield.data.u32 = SAI_ACL_IP_TYPE_NON_IPV4; - } - } else if (ip_type_bit_type == P4_IP_TYPE_BIT_IPV6ANY) { - if (ip_type_bit_data) { - value->aclfield.data.u32 = SAI_ACL_IP_TYPE_IPV6ANY; - } else { - value->aclfield.data.u32 = SAI_ACL_IP_TYPE_NON_IPV6; - } - } else if (ip_type_bit_type == P4_IP_TYPE_BIT_ARP && ip_type_bit_data) { - value->aclfield.data.u32 = SAI_ACL_IP_TYPE_ARP; - } else if (ip_type_bit_type == P4_IP_TYPE_BIT_ARP_REQUEST && - ip_type_bit_data) { - value->aclfield.data.u32 = SAI_ACL_IP_TYPE_ARP_REQUEST; - } else if (ip_type_bit_type == P4_IP_TYPE_BIT_ARP_REPLY && ip_type_bit_data) { - value->aclfield.data.u32 = SAI_ACL_IP_TYPE_ARP_REPLY; - } else { - SWSS_LOG_ERROR("Invalid IP_TYPE bit data %s for ip type %s", - attr_value.c_str(), ip_type_bit_type.c_str()); - return false; - } - return true; +bool setMatchFieldIpType(const std::string &attr_value, sai_attribute_value_t *value, + const std::string &ip_type_bit_type) +{ + SWSS_LOG_ENTER(); + if (ip_type_bit_type == EMPTY_STRING) + { + SWSS_LOG_ERROR("Invalid IP type %s, bit type is not defined.", attr_value.c_str()); + return false; + } + // go/p4-ip-type + const auto &ip_type_bit_data_mask = swss::tokenize(attr_value, kDataMaskDelimiter); + if (ip_type_bit_data_mask.size() == 2 && swss::to_uint(trim(ip_type_bit_data_mask[1])) == 0) + { + SWSS_LOG_ERROR("Invalid IP_TYPE mask %s for bit type %s: ip type bit mask " + "should not be zero.", + attr_value.c_str(), ip_type_bit_type.c_str()); + return false; + } + int ip_type_bit_data = std::stoi(ip_type_bit_data_mask[0], nullptr, 0); + value->aclfield.mask.u32 = 0xFFFFFFFF; + if (ip_type_bit_type == P4_IP_TYPE_BIT_IP) + { + if (ip_type_bit_data) + { + value->aclfield.data.u32 = SAI_ACL_IP_TYPE_IP; + } + else + { + value->aclfield.data.u32 = SAI_ACL_IP_TYPE_NON_IP; + } + } + else if (ip_type_bit_type == P4_IP_TYPE_BIT_IPV4ANY) + { + if (ip_type_bit_data) + { + value->aclfield.data.u32 = SAI_ACL_IP_TYPE_IPV4ANY; + } + else + { + value->aclfield.data.u32 = SAI_ACL_IP_TYPE_NON_IPV4; + } + } + else if (ip_type_bit_type == P4_IP_TYPE_BIT_IPV6ANY) + { + if (ip_type_bit_data) + { + value->aclfield.data.u32 = SAI_ACL_IP_TYPE_IPV6ANY; + } + else + { + value->aclfield.data.u32 = SAI_ACL_IP_TYPE_NON_IPV6; + } + } + else if (ip_type_bit_type == P4_IP_TYPE_BIT_ARP && ip_type_bit_data) + { + value->aclfield.data.u32 = SAI_ACL_IP_TYPE_ARP; + } + else if (ip_type_bit_type == P4_IP_TYPE_BIT_ARP_REQUEST && ip_type_bit_data) + { + value->aclfield.data.u32 = SAI_ACL_IP_TYPE_ARP_REQUEST; + } + else if (ip_type_bit_type == P4_IP_TYPE_BIT_ARP_REPLY && ip_type_bit_data) + { + value->aclfield.data.u32 = SAI_ACL_IP_TYPE_ARP_REPLY; + } + else + { + SWSS_LOG_ERROR("Invalid IP_TYPE bit data %s for ip type %s", attr_value.c_str(), ip_type_bit_type.c_str()); + return false; + } + return true; } -ReturnCode setCompositeSaiMatchValue(const acl_entry_attr_union_t attr_name, - const std::string& attr_value, - sai_attribute_value_t* value) { - try { - const auto& tokenized_ip = swss::tokenize(attr_value, kDataMaskDelimiter); - swss::IpAddress ip_data; - swss::IpAddress ip_mask; - if (tokenized_ip.size() == 2) { - // data & mask - ip_data = swss::IpAddress(trim(tokenized_ip[0])); - if (ip_data.isV4()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "IP data type should be v6 type: " << attr_value; - } - ip_mask = swss::IpAddress(trim(tokenized_ip[1])); - if (ip_mask.isV4()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "IP mask type should be v6 type: " << attr_value; - } - } else { - // LPM annotated value - swss::IpPrefix ip_prefix(trim(attr_value)); - if (ip_prefix.isV4()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "IP type should be v6 type: " << attr_value; - } - ip_data = ip_prefix.getIp(); - ip_mask = ip_prefix.getMask(); - } - switch (attr_name) { - case SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6_WORD3: - case SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD3: { - // IPv6 Address 127:96 32 bits - memcpy(&value->aclfield.data.ip6[0], &ip_data.getV6Addr()[0], - IPV6_SINGLE_WORD_BYTES_LENGTH); - memcpy(&value->aclfield.mask.ip6[0], &ip_mask.getV6Addr()[0], - IPV6_SINGLE_WORD_BYTES_LENGTH); - break; - } - case SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6_WORD2: - case SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2: { - // IPv6 Address 95:64 32 bits - memcpy(&value->aclfield.data.ip6[IPV6_SINGLE_WORD_BYTES_LENGTH], - &ip_data.getV6Addr()[IPV6_SINGLE_WORD_BYTES_LENGTH], - IPV6_SINGLE_WORD_BYTES_LENGTH); - memcpy(&value->aclfield.mask.ip6[IPV6_SINGLE_WORD_BYTES_LENGTH], - &ip_mask.getV6Addr()[IPV6_SINGLE_WORD_BYTES_LENGTH], - IPV6_SINGLE_WORD_BYTES_LENGTH); - break; - } - default: { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "ACL match field " << attr_name - << " is not supported in composite match field sai_field type."; - } - } - } catch (std::exception& e) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to parse match attribute " << attr_name - << " (value: " << attr_value << "). Error:" << e.what(); - } - value->aclfield.enable = true; - return ReturnCode(); +ReturnCode setCompositeSaiMatchValue(const acl_entry_attr_union_t attr_name, const std::string &attr_value, + sai_attribute_value_t *value) +{ + try + { + const auto &tokenized_ip = swss::tokenize(attr_value, kDataMaskDelimiter); + swss::IpAddress ip_data; + swss::IpAddress ip_mask; + if (tokenized_ip.size() == 2) + { + // data & mask + ip_data = swss::IpAddress(trim(tokenized_ip[0])); + if (ip_data.isV4()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "IP data type should be v6 type: " << attr_value; + } + ip_mask = swss::IpAddress(trim(tokenized_ip[1])); + if (ip_mask.isV4()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "IP mask type should be v6 type: " << attr_value; + } + } + else + { + // LPM annotated value + swss::IpPrefix ip_prefix(trim(attr_value)); + if (ip_prefix.isV4()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "IP type should be v6 type: " << attr_value; + } + ip_data = ip_prefix.getIp(); + ip_mask = ip_prefix.getMask(); + } + switch (attr_name) + { + case SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6_WORD3: + case SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD3: { + // IPv6 Address 127:96 32 bits + memcpy(&value->aclfield.data.ip6[0], &ip_data.getV6Addr()[0], IPV6_SINGLE_WORD_BYTES_LENGTH); + memcpy(&value->aclfield.mask.ip6[0], &ip_mask.getV6Addr()[0], IPV6_SINGLE_WORD_BYTES_LENGTH); + break; + } + case SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6_WORD2: + case SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2: { + // IPv6 Address 95:64 32 bits + memcpy(&value->aclfield.data.ip6[IPV6_SINGLE_WORD_BYTES_LENGTH], + &ip_data.getV6Addr()[IPV6_SINGLE_WORD_BYTES_LENGTH], IPV6_SINGLE_WORD_BYTES_LENGTH); + memcpy(&value->aclfield.mask.ip6[IPV6_SINGLE_WORD_BYTES_LENGTH], + &ip_mask.getV6Addr()[IPV6_SINGLE_WORD_BYTES_LENGTH], IPV6_SINGLE_WORD_BYTES_LENGTH); + break; + } + default: { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "ACL match field " << attr_name << " is not supported in composite match field sai_field type."; + } + } + } + catch (std::exception &e) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Failed to parse match attribute " << attr_name + << " (value: " << attr_value << "). Error:" << e.what(); + } + value->aclfield.enable = true; + return ReturnCode(); } -ReturnCode setUdfMatchValue(const P4UdfField& udf_field, - const std::string& attr_value, - sai_attribute_value_t* value, - P4UdfDataMask* udf_data_mask, - uint16_t bytes_offset) { - if (!udf_data_mask->data.empty() || !udf_data_mask->mask.empty()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to set UDF match field " << udf_field.udf_id - << " with value " << attr_value - << " in ACL rule: the UDF: duplicated UDF value found for the same " - "UDF field."; - } - try { - // Extract UDF field values by length(in bytes) and offset(in bytes) - const std::vector& value_and_mask = - swss::tokenize(attr_value, kDataMaskDelimiter); - uint32_t data_str_offset = bytes_offset * 2, - mask_str_offset = bytes_offset * 2; - const auto& data = trim(value_and_mask[0]); - if (data.size() > 2 && data[0] == '0' && - (data[1] == 'x' || data[1] == 'X')) { - data_str_offset += 2; - } - std::string mask = EMPTY_STRING; - if (value_and_mask.size() > 1) { - mask = trim(value_and_mask[1]); - if (mask.size() > 2 && mask[0] == '0' && - (mask[1] == 'x' || mask[1] == 'X')) { - mask_str_offset += 2; - } - } - for (uint16_t i = 0; i < udf_field.length; i++) { - // Add to udf_data uint8_t list - udf_data_mask->data.push_back( - std::stoul(data.substr(data_str_offset, 2), nullptr, 16) & 0xFF); - data_str_offset += 2; - if (value_and_mask.size() > 1) { - // Add to udf_mask uint8_t list - udf_data_mask->mask.push_back( - (std::stoul(mask.substr(mask_str_offset, 2), nullptr, 16)) & 0xFF); - mask_str_offset += 2; - } else { - udf_data_mask->mask.push_back(0xFF); - } - } - value->aclfield.data.u8list.count = udf_field.length; - value->aclfield.data.u8list.list = udf_data_mask->data.data(); - value->aclfield.mask.u8list.count = udf_field.length; - value->aclfield.mask.u8list.list = udf_data_mask->mask.data(); - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to set UDF match field " << udf_field.udf_id - << " with value " << attr_value << " in ACL rule: " << ex.what(); - } - value->aclfield.enable = true; - return ReturnCode(); +ReturnCode setUdfMatchValue(const P4UdfField &udf_field, const std::string &attr_value, sai_attribute_value_t *value, + P4UdfDataMask *udf_data_mask, uint16_t bytes_offset) +{ + if (!udf_data_mask->data.empty() || !udf_data_mask->mask.empty()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Failed to set UDF match field " << udf_field.udf_id << " with value " << attr_value + << " in ACL rule: the UDF: duplicated UDF value found for the same " + "UDF field."; + } + try + { + // Extract UDF field values by length(in bytes) and offset(in bytes) + const std::vector &value_and_mask = swss::tokenize(attr_value, kDataMaskDelimiter); + uint32_t data_str_offset = bytes_offset * 2, mask_str_offset = bytes_offset * 2; + const auto &data = trim(value_and_mask[0]); + if (data.size() > 2 && data[0] == '0' && (data[1] == 'x' || data[1] == 'X')) + { + data_str_offset += 2; + } + std::string mask = EMPTY_STRING; + if (value_and_mask.size() > 1) + { + mask = trim(value_and_mask[1]); + if (mask.size() > 2 && mask[0] == '0' && (mask[1] == 'x' || mask[1] == 'X')) + { + mask_str_offset += 2; + } + } + for (uint16_t i = 0; i < udf_field.length; i++) + { + // Add to udf_data uint8_t list + udf_data_mask->data.push_back(std::stoul(data.substr(data_str_offset, 2), nullptr, 16) & 0xFF); + data_str_offset += 2; + if (value_and_mask.size() > 1) + { + // Add to udf_mask uint8_t list + udf_data_mask->mask.push_back((std::stoul(mask.substr(mask_str_offset, 2), nullptr, 16)) & 0xFF); + mask_str_offset += 2; + } + else + { + udf_data_mask->mask.push_back(0xFF); + } + } + value->aclfield.data.u8list.count = udf_field.length; + value->aclfield.data.u8list.list = udf_data_mask->data.data(); + value->aclfield.mask.u8list.count = udf_field.length; + value->aclfield.mask.u8list.list = udf_data_mask->mask.data(); + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Failed to set UDF match field " << udf_field.udf_id << " with value " << attr_value + << " in ACL rule: " << ex.what(); + } + value->aclfield.enable = true; + return ReturnCode(); } -bool isDiffActionFieldValue(const acl_entry_attr_union_t attr_name, - const sai_attribute_value_t& value, - const sai_attribute_value_t& old_value, - const P4AclRule& acl_rule, - const P4AclRule& old_acl_rule) { - switch (attr_name) { +bool isDiffActionFieldValue(const acl_entry_attr_union_t attr_name, const sai_attribute_value_t &value, + const sai_attribute_value_t &old_value, const P4AclRule &acl_rule, + const P4AclRule &old_acl_rule) +{ + switch (attr_name) + { case SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION: case SAI_ACL_ENTRY_ATTR_ACTION_SET_PACKET_COLOR: { - return value.aclaction.parameter.s32 != old_value.aclaction.parameter.s32; + return value.aclaction.parameter.s32 != old_value.aclaction.parameter.s32; } case SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT: { - return value.aclaction.parameter.oid != old_value.aclaction.parameter.oid; + return value.aclaction.parameter.oid != old_value.aclaction.parameter.oid; } case SAI_ACL_ENTRY_ATTR_ACTION_ENDPOINT_IP: case SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_IP: case SAI_ACL_ENTRY_ATTR_ACTION_SET_DST_IP: { - return value.aclaction.parameter.ip4 != old_value.aclaction.parameter.ip4; + return value.aclaction.parameter.ip4 != old_value.aclaction.parameter.ip4; } case SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS: case SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS: { - return acl_rule.action_mirror_sessions.at(attr_name).oid != - old_acl_rule.action_mirror_sessions.at(attr_name).oid; + return acl_rule.action_mirror_sessions.at(attr_name).oid != + old_acl_rule.action_mirror_sessions.at(attr_name).oid; } case SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_MAC: case SAI_ACL_ENTRY_ATTR_ACTION_SET_DST_MAC: { - return memcmp(value.aclaction.parameter.mac, - old_value.aclaction.parameter.mac, sizeof(sai_mac_t)); + return memcmp(value.aclaction.parameter.mac, old_value.aclaction.parameter.mac, sizeof(sai_mac_t)); } case SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_IPV6: case SAI_ACL_ENTRY_ATTR_ACTION_SET_DST_IPV6: { - return memcmp(value.aclaction.parameter.ip6, - old_value.aclaction.parameter.ip6, sizeof(sai_ip6_t)); + return memcmp(value.aclaction.parameter.ip6, old_value.aclaction.parameter.ip6, sizeof(sai_ip6_t)); } case SAI_ACL_ENTRY_ATTR_ACTION_SET_TC: @@ -818,60 +839,58 @@ bool isDiffActionFieldValue(const acl_entry_attr_union_t attr_name, case SAI_ACL_ENTRY_ATTR_ACTION_SET_ECN: case SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_PRI: case SAI_ACL_ENTRY_ATTR_ACTION_SET_OUTER_VLAN_PRI: { - return value.aclaction.parameter.u8 != old_value.aclaction.parameter.u8; + return value.aclaction.parameter.u8 != old_value.aclaction.parameter.u8; } case SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_ID: { - return value.aclaction.parameter.u32 != old_value.aclaction.parameter.u32; + return value.aclaction.parameter.u32 != old_value.aclaction.parameter.u32; } case SAI_ACL_ENTRY_ATTR_ACTION_SET_OUTER_VLAN_ID: case SAI_ACL_ENTRY_ATTR_ACTION_SET_L4_SRC_PORT: case SAI_ACL_ENTRY_ATTR_ACTION_SET_L4_DST_PORT: { - return value.aclaction.parameter.u16 != old_value.aclaction.parameter.u16; + return value.aclaction.parameter.u16 != old_value.aclaction.parameter.u16; } case SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF: case SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID: { - return value.aclaction.parameter.oid != old_value.aclaction.parameter.oid; + return value.aclaction.parameter.oid != old_value.aclaction.parameter.oid; } case SAI_ACL_ENTRY_ATTR_ACTION_FLOOD: case SAI_ACL_ENTRY_ATTR_ACTION_DECREMENT_TTL: case SAI_ACL_ENTRY_ATTR_ACTION_SET_DO_NOT_LEARN: { - // parameter is not needed - return false; + // parameter is not needed + return false; } default: { - return false; + return false; + } } - } } -bool isDiffMatchFieldValue(const acl_entry_attr_union_t attr_name, - const sai_attribute_value_t& value, - const sai_attribute_value_t& old_value, - const P4AclRule& acl_rule, - const P4AclRule& old_acl_rule) { - if (attr_name >= SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN && - attr_name <= SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MAX) { - // We compare the size here only. The list is explicitly verified in the - // ACL rule. - return value.aclfield.data.u8list.count != - old_value.aclfield.data.u8list.count; - } - switch (attr_name) { +bool isDiffMatchFieldValue(const acl_entry_attr_union_t attr_name, const sai_attribute_value_t &value, + const sai_attribute_value_t &old_value, const P4AclRule &acl_rule, + const P4AclRule &old_acl_rule) +{ + if (attr_name >= SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN && + attr_name <= SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MAX) + { + // We compare the size here only. The list is explicitly verified in the + // ACL rule. + return value.aclfield.data.u8list.count != old_value.aclfield.data.u8list.count; + } + switch (attr_name) + { case SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS: { - // We compare the size here only. The list is explicitly verified in the - // ACL rule. - return value.aclfield.data.objlist.count != - old_value.aclfield.data.objlist.count; + // We compare the size here only. The list is explicitly verified in the + // ACL rule. + return value.aclfield.data.objlist.count != old_value.aclfield.data.objlist.count; } case SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS: { - // We compare the size here only. The list is explicitly verified in the - // ACL rule. - return value.aclfield.data.objlist.count != - old_value.aclfield.data.objlist.count; + // We compare the size here only. The list is explicitly verified in the + // ACL rule. + return value.aclfield.data.objlist.count != old_value.aclfield.data.objlist.count; } case SAI_ACL_ENTRY_ATTR_FIELD_IN_PORT: case SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORT: { - return value.aclfield.data.oid != old_value.aclfield.data.oid; + return value.aclfield.data.oid != old_value.aclfield.data.oid; } case SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE: case SAI_ACL_ENTRY_ATTR_FIELD_TUNNEL_VNI: @@ -879,8 +898,8 @@ bool isDiffMatchFieldValue(const acl_entry_attr_union_t attr_name, case SAI_ACL_ENTRY_ATTR_FIELD_IPV6_FLOW_LABEL: case SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_FRAG: case SAI_ACL_ENTRY_ATTR_FIELD_PACKET_VLAN: { - return value.aclfield.data.u32 != old_value.aclfield.data.u32 || - value.aclfield.mask.u32 != old_value.aclfield.mask.u32; + return value.aclfield.data.u32 != old_value.aclfield.data.u32 || + value.aclfield.mask.u32 != old_value.aclfield.mask.u32; } case SAI_ACL_ENTRY_ATTR_FIELD_TCP_FLAGS: case SAI_ACL_ENTRY_ATTR_FIELD_IP_FLAGS: @@ -900,8 +919,8 @@ bool isDiffMatchFieldValue(const acl_entry_attr_union_t attr_name, case SAI_ACL_ENTRY_ATTR_FIELD_TTL: case SAI_ACL_ENTRY_ATTR_FIELD_TOS: case SAI_ACL_ENTRY_ATTR_FIELD_IPV6_NEXT_HEADER: { - return value.aclfield.data.u8 != old_value.aclfield.data.u8 || - value.aclfield.mask.u8 != old_value.aclfield.mask.u8; + return value.aclfield.data.u8 != old_value.aclfield.data.u8 || + value.aclfield.mask.u8 != old_value.aclfield.mask.u8; } case SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE: case SAI_ACL_ENTRY_ATTR_FIELD_L4_SRC_PORT: @@ -912,36 +931,32 @@ bool isDiffMatchFieldValue(const acl_entry_attr_union_t attr_name, case SAI_ACL_ENTRY_ATTR_FIELD_INNER_ETHER_TYPE: case SAI_ACL_ENTRY_ATTR_FIELD_INNER_L4_SRC_PORT: case SAI_ACL_ENTRY_ATTR_FIELD_INNER_L4_DST_PORT: { - return value.aclfield.data.u16 != old_value.aclfield.data.u16 || - value.aclfield.mask.u16 != old_value.aclfield.mask.u16; + return value.aclfield.data.u16 != old_value.aclfield.data.u16 || + value.aclfield.mask.u16 != old_value.aclfield.mask.u16; } case SAI_ACL_ENTRY_ATTR_FIELD_INNER_SRC_IP: case SAI_ACL_ENTRY_ATTR_FIELD_INNER_DST_IP: case SAI_ACL_ENTRY_ATTR_FIELD_SRC_IP: case SAI_ACL_ENTRY_ATTR_FIELD_DST_IP: { - return value.aclfield.data.ip4 != old_value.aclfield.data.ip4 || - value.aclfield.mask.ip4 != old_value.aclfield.mask.ip4; + return value.aclfield.data.ip4 != old_value.aclfield.data.ip4 || + value.aclfield.mask.ip4 != old_value.aclfield.mask.ip4; } case SAI_ACL_ENTRY_ATTR_FIELD_INNER_SRC_IPV6: case SAI_ACL_ENTRY_ATTR_FIELD_INNER_DST_IPV6: case SAI_ACL_ENTRY_ATTR_FIELD_SRC_IPV6: case SAI_ACL_ENTRY_ATTR_FIELD_DST_IPV6: { - return memcmp(value.aclfield.data.ip6, old_value.aclfield.data.ip6, - sizeof(sai_ip6_t)) || - memcmp(value.aclfield.mask.ip6, old_value.aclfield.mask.ip6, - sizeof(sai_ip6_t)); + return memcmp(value.aclfield.data.ip6, old_value.aclfield.data.ip6, sizeof(sai_ip6_t)) || + memcmp(value.aclfield.mask.ip6, old_value.aclfield.mask.ip6, sizeof(sai_ip6_t)); } case SAI_ACL_ENTRY_ATTR_FIELD_SRC_MAC: case SAI_ACL_ENTRY_ATTR_FIELD_DST_MAC: { - return memcmp(value.aclfield.data.mac, old_value.aclfield.data.mac, - sizeof(sai_mac_t)) || - memcmp(value.aclfield.mask.mac, old_value.aclfield.mask.mac, - sizeof(sai_mac_t)); + return memcmp(value.aclfield.data.mac, old_value.aclfield.data.mac, sizeof(sai_mac_t)) || + memcmp(value.aclfield.mask.mac, old_value.aclfield.mask.mac, sizeof(sai_mac_t)); } default: { - return false; + return false; + } } - } } -} // namespace p4orch +} // namespace p4orch diff --git a/orchagent/p4orch/acl_util.h b/orchagent/p4orch/acl_util.h index 38718aacb3b..b4123d07542 100644 --- a/orchagent/p4orch/acl_util.h +++ b/orchagent/p4orch/acl_util.h @@ -8,12 +8,14 @@ #include "p4orch/p4orch_util.h" #include "return_code.h" -extern "C" { +extern "C" +{ #include "sai.h" #include "saiextensions.h" } -namespace p4orch { +namespace p4orch +{ // sai_acl_entry_attr_t or sai_acl_entry_attr_extensions_t using acl_entry_attr_union_t = int32_t; @@ -21,223 +23,235 @@ using acl_entry_attr_union_t = int32_t; using acl_table_attr_union_t = int32_t; // Describes the format of a value. -enum Format { - // Hex string, e.g. 0x0a8b. All lowercase, and always of length - // ceil(num_bits/4)+2 (1 character for every 4 bits, zero-padded to be - // divisible by 4, and 2 characters for the '0x' prefix). - HEX_STRING = 0, - // MAC address, e.g. 00:11:ab:cd:ef:22. All lowercase, and always 17 - // characters long. - MAC = 1, - // IPv4 address, e.g. 10.0.0.2. - IPV4 = 2, - // IPv6 address, e.g. fe80::21a:11ff:fe17:5f80. All lowercase, formatted - // according to RFC5952. This can be used for any bitwidth of 128 or less. If - // the bitwidth n is less than 128, then by convention only the upper n bits - // can be set. - IPV6 = 3, - // String format, only printable characters. - STRING = 4, +enum Format +{ + // Hex string, e.g. 0x0a8b. All lowercase, and always of length + // ceil(num_bits/4)+2 (1 character for every 4 bits, zero-padded to be + // divisible by 4, and 2 characters for the '0x' prefix). + HEX_STRING = 0, + // MAC address, e.g. 00:11:ab:cd:ef:22. All lowercase, and always 17 + // characters long. + MAC = 1, + // IPv4 address, e.g. 10.0.0.2. + IPV4 = 2, + // IPv6 address, e.g. fe80::21a:11ff:fe17:5f80. All lowercase, formatted + // according to RFC5952. This can be used for any bitwidth of 128 or less. If + // the bitwidth n is less than 128, then by convention only the upper n bits + // can be set. + IPV6 = 3, + // String format, only printable characters. + STRING = 4, }; -struct P4AclCounter { - sai_object_id_t counter_oid; - bool bytes_enabled; - bool packets_enabled; - P4AclCounter() - : bytes_enabled(false), - packets_enabled(false), - counter_oid(SAI_NULL_OBJECT_ID) {} - - bool operator==(const P4AclCounter& entry) const { - return bytes_enabled == entry.bytes_enabled && - packets_enabled == entry.packets_enabled; - } - - bool operator!=(const P4AclCounter& entry) const { return !(*this == entry); } +struct P4AclCounter +{ + sai_object_id_t counter_oid; + bool bytes_enabled; + bool packets_enabled; + P4AclCounter() : bytes_enabled(false), packets_enabled(false), counter_oid(SAI_NULL_OBJECT_ID) + { + } + + bool operator==(const P4AclCounter &entry) const + { + return bytes_enabled == entry.bytes_enabled && packets_enabled == entry.packets_enabled; + } + + bool operator!=(const P4AclCounter &entry) const + { + return !(*this == entry); + } }; -struct P4AclMeter { - sai_object_id_t meter_oid; - bool enabled; - sai_meter_type_t type; - sai_policer_mode_t mode; - sai_uint64_t cir; - sai_uint64_t cburst; - sai_uint64_t pir; - sai_uint64_t pburst; - - std::map packet_color_actions; - - P4AclMeter() - : enabled(false), - meter_oid(SAI_NULL_OBJECT_ID), - cir(0), - cburst(0), - pir(0), - pburst(0), - type(SAI_METER_TYPE_PACKETS), - mode(SAI_POLICER_MODE_TR_TCM) {} - - bool operator==(const P4AclMeter& entry) const { - return enabled == entry.enabled && type == entry.type && - mode == entry.mode && cir == entry.cir && cburst == entry.cburst && - pir == entry.pir && pburst == entry.pburst && - packet_color_actions == entry.packet_color_actions; - } - - bool operator!=(const P4AclMeter& entry) const { return !(*this == entry); } +struct P4AclMeter +{ + sai_object_id_t meter_oid; + bool enabled; + sai_meter_type_t type; + sai_policer_mode_t mode; + sai_uint64_t cir; + sai_uint64_t cburst; + sai_uint64_t pir; + sai_uint64_t pburst; + + std::map packet_color_actions; + + P4AclMeter() + : enabled(false), meter_oid(SAI_NULL_OBJECT_ID), cir(0), cburst(0), pir(0), pburst(0), + type(SAI_METER_TYPE_PACKETS), mode(SAI_POLICER_MODE_TR_TCM) + { + } + + bool operator==(const P4AclMeter &entry) const + { + return enabled == entry.enabled && type == entry.type && mode == entry.mode && cir == entry.cir && + cburst == entry.cburst && pir == entry.pir && pburst == entry.pburst && + packet_color_actions == entry.packet_color_actions; + } + + bool operator!=(const P4AclMeter &entry) const + { + return !(*this == entry); + } }; -struct P4AclMirrorSession { - std::string name; - std::string key; // KeyGenerator::generateMirrorSessionKey(name) - sai_object_id_t oid; - - bool operator==(const P4AclMirrorSession& entry) const { - return name == entry.name && key == entry.key && oid == entry.oid; - } - - bool operator!=(const P4AclMirrorSession& entry) const { - return !(*this == entry); - } +struct P4AclMirrorSession +{ + std::string name; + std::string key; // KeyGenerator::generateMirrorSessionKey(name) + sai_object_id_t oid; + + bool operator==(const P4AclMirrorSession &entry) const + { + return name == entry.name && key == entry.key && oid == entry.oid; + } + + bool operator!=(const P4AclMirrorSession &entry) const + { + return !(*this == entry); + } }; -struct P4UdfDataMask { - std::vector data; - std::vector mask; +struct P4UdfDataMask +{ + std::vector data; + std::vector mask; - bool operator==(const P4UdfDataMask& entry) const { - return data == entry.data && mask == entry.mask; - } + bool operator==(const P4UdfDataMask &entry) const + { + return data == entry.data && mask == entry.mask; + } - bool operator!=(const P4UdfDataMask& entry) const { - return !(*this == entry); - } + bool operator!=(const P4UdfDataMask &entry) const + { + return !(*this == entry); + } }; -struct P4AclRule { - sai_object_id_t acl_table_oid; - sai_object_id_t acl_entry_oid; - std::string acl_table_name; - std::string acl_rule_key; - std::string db_key; - - sai_uint32_t priority; - std::string p4_action; - std::map match_fvs; - std::map action_fvs; - P4AclMeter meter; - P4AclCounter counter; - - sai_uint32_t action_qos_queue_num; - std::string action_redirect_nexthop_key; - // SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS and - // SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS are allowed as key - std::map action_mirror_sessions; - // Stores mapping from SAI_ACL_TABLE_ATTR_USER_DEFINED_FIELD_GROUP_{number} to - // udf data and masks pairs in two uin8_t list - std::map udf_data_masks; - std::vector in_ports; - std::vector out_ports; - std::vector in_ports_oids; - std::vector out_ports_oids; +struct P4AclRule +{ + sai_object_id_t acl_table_oid; + sai_object_id_t acl_entry_oid; + std::string acl_table_name; + std::string acl_rule_key; + std::string db_key; + + sai_uint32_t priority; + std::string p4_action; + std::map match_fvs; + std::map action_fvs; + P4AclMeter meter; + P4AclCounter counter; + + sai_uint32_t action_qos_queue_num; + std::string action_redirect_nexthop_key; + // SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS and + // SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS are allowed as key + std::map action_mirror_sessions; + // Stores mapping from SAI_ACL_TABLE_ATTR_USER_DEFINED_FIELD_GROUP_{number} to + // udf data and masks pairs in two uin8_t list + std::map udf_data_masks; + std::vector in_ports; + std::vector out_ports; + std::vector in_ports_oids; + std::vector out_ports_oids; }; -struct SaiActionWithParam { - acl_entry_attr_union_t action; - std::string param_name; - std::string param_value; - - bool operator==(const SaiActionWithParam& entry) const { - return action == entry.action && param_name == entry.param_name && - param_value == entry.param_value; - } - - bool operator!=(const SaiActionWithParam& entry) const { - return !(*this == entry); - } +struct SaiActionWithParam +{ + acl_entry_attr_union_t action; + std::string param_name; + std::string param_value; + + bool operator==(const SaiActionWithParam &entry) const + { + return action == entry.action && param_name == entry.param_name && param_value == entry.param_value; + } + + bool operator!=(const SaiActionWithParam &entry) const + { + return !(*this == entry); + } }; -struct SaiMatchField { - acl_entry_attr_union_t entry_attr; - acl_table_attr_union_t table_attr; - uint32_t bitwidth; - Format format; - - bool operator==(const SaiMatchField& entry) const { - return entry_attr == entry.entry_attr && table_attr == entry.table_attr && - bitwidth == entry.bitwidth && format == entry.format; - } - - bool operator!=(const SaiMatchField& entry) const { - return !(*this == entry); - } +struct SaiMatchField +{ + acl_entry_attr_union_t entry_attr; + acl_table_attr_union_t table_attr; + uint32_t bitwidth; + Format format; + + bool operator==(const SaiMatchField &entry) const + { + return entry_attr == entry.entry_attr && table_attr == entry.table_attr && bitwidth == entry.bitwidth && + format == entry.format; + } + + bool operator!=(const SaiMatchField &entry) const + { + return !(*this == entry); + } }; -struct P4UdfField { - uint16_t length; // in Bytes - std::string group_id; // {ACL_TABLE_NAME}-{P4_MATCH_FIELD}-{INDEX} - std::string udf_id; // {group_id}-base{base}-offset{offset} - uint16_t offset; // in Bytes - sai_udf_base_t base; - - bool operator==(const P4UdfField& entry) const { - return length == entry.length && group_id == entry.group_id && - udf_id == entry.udf_id && offset == entry.offset && - base == entry.base; - } - - bool operator!=(const P4UdfField& entry) const { return !(*this == entry); } +struct P4UdfField +{ + uint16_t length; // in Bytes + std::string group_id; // {ACL_TABLE_NAME}-{P4_MATCH_FIELD}-{INDEX} + std::string udf_id; // {group_id}-base{base}-offset{offset} + uint16_t offset; // in Bytes + sai_udf_base_t base; + + bool operator==(const P4UdfField &entry) const + { + return length == entry.length && group_id == entry.group_id && udf_id == entry.udf_id && + offset == entry.offset && base == entry.base; + } + + bool operator!=(const P4UdfField &entry) const + { + return !(*this == entry); + } }; -struct P4AclTableDefinition { - std::string acl_table_name; - sai_object_id_t table_oid; - sai_object_id_t group_oid; - sai_object_id_t group_member_oid; - - sai_acl_stage_t stage; - sai_uint32_t size; - sai_uint32_t priority; - std::string meter_unit; - std::string counter_unit; - // go/p4-composite-fields - // Only SAI attributes for IPv6-64bit(IPV6_WORDn) are supported as - // sai_field elements in composite field - std::map> - composite_sai_match_fields_lookup; - // go/gpins-acl-udf - // p4_match string to a list of P4UdfFields mapping - std::map> udf_fields_lookup; - // UDF group id to ACL entry attribute index mapping - std::map udf_group_attr_index_lookup; - std::map sai_match_field_lookup; - std::map ip_type_bit_type_lookup; - std::map> - rule_action_field_lookup; - std::map> - rule_packet_action_color_lookup; - - P4AclTableDefinition() = default; - P4AclTableDefinition(const std::string& acl_table_name, - const sai_acl_stage_t stage, const uint32_t priority, - const uint32_t size, const std::string& meter_unit, - const std::string& counter_unit) - : acl_table_name(acl_table_name), - stage(stage), - priority(priority), - size(size), - meter_unit(meter_unit), - counter_unit(counter_unit) {}; +struct P4AclTableDefinition +{ + std::string acl_table_name; + sai_object_id_t table_oid; + sai_object_id_t group_oid; + sai_object_id_t group_member_oid; + + sai_acl_stage_t stage; + sai_uint32_t size; + sai_uint32_t priority; + std::string meter_unit; + std::string counter_unit; + // go/p4-composite-fields + // Only SAI attributes for IPv6-64bit(IPV6_WORDn) are supported as + // sai_field elements in composite field + std::map> composite_sai_match_fields_lookup; + // go/gpins-acl-udf + // p4_match string to a list of P4UdfFields mapping + std::map> udf_fields_lookup; + // UDF group id to ACL entry attribute index mapping + std::map udf_group_attr_index_lookup; + std::map sai_match_field_lookup; + std::map ip_type_bit_type_lookup; + std::map> rule_action_field_lookup; + std::map> rule_packet_action_color_lookup; + + P4AclTableDefinition() = default; + P4AclTableDefinition(const std::string &acl_table_name, const sai_acl_stage_t stage, const uint32_t priority, + const uint32_t size, const std::string &meter_unit, const std::string &counter_unit) + : acl_table_name(acl_table_name), stage(stage), priority(priority), size(size), meter_unit(meter_unit), + counter_unit(counter_unit) {}; }; -struct P4UserDefinedTrapHostifTableEntry { - sai_object_id_t user_defined_trap; - sai_object_id_t hostif_table_entry; - P4UserDefinedTrapHostifTableEntry() - : user_defined_trap(SAI_NULL_OBJECT_ID), - hostif_table_entry(SAI_NULL_OBJECT_ID) {}; +struct P4UserDefinedTrapHostifTableEntry +{ + sai_object_id_t user_defined_trap; + sai_object_id_t hostif_table_entry; + P4UserDefinedTrapHostifTableEntry() + : user_defined_trap(SAI_NULL_OBJECT_ID), hostif_table_entry(SAI_NULL_OBJECT_ID) {}; }; using acl_rule_attr_lookup_t = std::map; @@ -245,8 +259,7 @@ using acl_table_attr_lookup_t = std::map; using acl_table_attr_format_lookup_t = std::map; using acl_packet_action_lookup_t = std::map; using acl_packet_color_lookup_t = std::map; -using acl_packet_color_policer_attr_lookup_t = - std::map; +using acl_packet_color_policer_attr_lookup_t = std::map; using acl_ip_type_lookup_t = std::map; using acl_ip_frag_lookup_t = std::map; using udf_base_lookup_t = std::map; @@ -310,8 +323,7 @@ using P4AclRuleTables = std::map>; #define P4_MATCH_DST_IPV6_WORD2 "SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6_WORD2" #define P4_MATCH_SRC_IPV6_WORD3 "SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD3" #define P4_MATCH_SRC_IPV6_WORD2 "SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2" -#define P4_MATCH_ROUTE_DST_USER_META \ - "SAI_ACL_TABLE_ATTR_FIELD_ROUTE_DST_USER_META" +#define P4_MATCH_ROUTE_DST_USER_META "SAI_ACL_TABLE_ATTR_FIELD_ROUTE_DST_USER_META" #define P4_ACTION_PACKET_ACTION "SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION" #define P4_ACTION_REDIRECT "SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT" @@ -324,14 +336,10 @@ using P4AclRuleTables = std::map>; #define P4_ACTION_DECREMENT_TTL "SAI_ACL_ENTRY_ATTR_ACTION_DECREMENT_TTL" #define P4_ACTION_SET_TRAFFIC_CLASS "SAI_ACL_ENTRY_ATTR_ACTION_SET_TC" #define P4_ACTION_SET_PACKET_COLOR "SAI_ACL_ENTRY_ATTR_ACTION_SET_PACKET_COLOR" -#define P4_ACTION_SET_INNER_VLAN_ID \ - "SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_ID" -#define P4_ACTION_SET_INNER_VLAN_PRIORITY \ - "SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_PRI" -#define P4_ACTION_SET_OUTER_VLAN_ID \ - "SAI_ACL_ENTRY_ATTR_ACTION_SET_OUTER_VLAN_ID" -#define P4_ACTION_SET_OUTER_VLAN_PRIORITY \ - "SAI_ACL_ENTRY_ATTR_ACTION_SET_OUTER_VLAN_PRI" +#define P4_ACTION_SET_INNER_VLAN_ID "SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_ID" +#define P4_ACTION_SET_INNER_VLAN_PRIORITY "SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_PRI" +#define P4_ACTION_SET_OUTER_VLAN_ID "SAI_ACL_ENTRY_ATTR_ACTION_SET_OUTER_VLAN_ID" +#define P4_ACTION_SET_OUTER_VLAN_PRIORITY "SAI_ACL_ENTRY_ATTR_ACTION_SET_OUTER_VLAN_PRI" #define P4_ACTION_SET_SRC_MAC "SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_MAC" #define P4_ACTION_SET_DST_MAC "SAI_ACL_ENTRY_ATTR_ACTION_SET_DST_MAC" #define P4_ACTION_SET_SRC_IP "SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_IP" @@ -475,8 +483,7 @@ static const acl_table_attr_lookup_t aclMatchTableAttrLookup = { {P4_MATCH_PACKET_VLAN, SAI_ACL_TABLE_ATTR_FIELD_PACKET_VLAN}, {P4_MATCH_TUNNEL_VNI, SAI_ACL_TABLE_ATTR_FIELD_TUNNEL_VNI}, {P4_MATCH_IPV6_NEXT_HEADER, SAI_ACL_TABLE_ATTR_FIELD_IPV6_NEXT_HEADER}, - {P4_MATCH_ROUTE_DST_USER_META, - SAI_ACL_TABLE_ATTR_FIELD_ROUTE_DST_USER_META}, + {P4_MATCH_ROUTE_DST_USER_META, SAI_ACL_TABLE_ATTR_FIELD_ROUTE_DST_USER_META}, }; static const acl_table_attr_format_lookup_t aclMatchTableAttrFormatLookup = { @@ -581,8 +588,7 @@ static const acl_rule_attr_lookup_t aclMatchEntryAttrLookup = { {P4_MATCH_PACKET_VLAN, SAI_ACL_ENTRY_ATTR_FIELD_PACKET_VLAN}, {P4_MATCH_TUNNEL_VNI, SAI_ACL_ENTRY_ATTR_FIELD_TUNNEL_VNI}, {P4_MATCH_IPV6_NEXT_HEADER, SAI_ACL_ENTRY_ATTR_FIELD_IPV6_NEXT_HEADER}, - {P4_MATCH_ROUTE_DST_USER_META, - SAI_ACL_ENTRY_ATTR_FIELD_ROUTE_DST_USER_META}, + {P4_MATCH_ROUTE_DST_USER_META, SAI_ACL_ENTRY_ATTR_FIELD_ROUTE_DST_USER_META}, }; static const acl_rule_attr_lookup_t aclCompositeMatchEntryAttrLookup = { @@ -593,10 +599,8 @@ static const acl_rule_attr_lookup_t aclCompositeMatchEntryAttrLookup = { }; static const acl_packet_action_lookup_t aclPacketActionLookup = { - {P4_PACKET_ACTION_FORWARD, SAI_PACKET_ACTION_FORWARD}, - {P4_PACKET_ACTION_DROP, SAI_PACKET_ACTION_DROP}, - {P4_PACKET_ACTION_COPY, SAI_PACKET_ACTION_COPY}, - {P4_PACKET_ACTION_PUNT, SAI_PACKET_ACTION_TRAP}, + {P4_PACKET_ACTION_FORWARD, SAI_PACKET_ACTION_FORWARD}, {P4_PACKET_ACTION_DROP, SAI_PACKET_ACTION_DROP}, + {P4_PACKET_ACTION_COPY, SAI_PACKET_ACTION_COPY}, {P4_PACKET_ACTION_PUNT, SAI_PACKET_ACTION_TRAP}, {P4_PACKET_ACTION_LOG, SAI_PACKET_ACTION_LOG}, }; @@ -611,11 +615,9 @@ static const acl_rule_attr_lookup_t aclActionLookup = { {P4_ACTION_SET_TRAFFIC_CLASS, SAI_ACL_ENTRY_ATTR_ACTION_SET_TC}, {P4_ACTION_SET_PACKET_COLOR, SAI_ACL_ENTRY_ATTR_ACTION_SET_PACKET_COLOR}, {P4_ACTION_SET_INNER_VLAN_ID, SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_ID}, - {P4_ACTION_SET_INNER_VLAN_PRIORITY, - SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_PRI}, + {P4_ACTION_SET_INNER_VLAN_PRIORITY, SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_PRI}, {P4_ACTION_SET_OUTER_VLAN_ID, SAI_ACL_ENTRY_ATTR_ACTION_SET_OUTER_VLAN_ID}, - {P4_ACTION_SET_OUTER_VLAN_PRIORITY, - SAI_ACL_ENTRY_ATTR_ACTION_SET_OUTER_VLAN_PRI}, + {P4_ACTION_SET_OUTER_VLAN_PRIORITY, SAI_ACL_ENTRY_ATTR_ACTION_SET_OUTER_VLAN_PRI}, {P4_ACTION_SET_SRC_MAC, SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_MAC}, {P4_ACTION_SET_DST_MAC, SAI_ACL_ENTRY_ATTR_ACTION_SET_DST_MAC}, {P4_ACTION_SET_SRC_IP, SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_IP}, @@ -631,11 +633,10 @@ static const acl_rule_attr_lookup_t aclActionLookup = { {P4_ACTION_SET_VRF, SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF}, }; -static const acl_packet_color_policer_attr_lookup_t - aclPacketColorPolicerAttrLookup = { - {P4_PACKET_COLOR_GREEN, SAI_POLICER_ATTR_GREEN_PACKET_ACTION}, - {P4_PACKET_COLOR_YELLOW, SAI_POLICER_ATTR_YELLOW_PACKET_ACTION}, - {P4_PACKET_COLOR_RED, SAI_POLICER_ATTR_RED_PACKET_ACTION}, +static const acl_packet_color_policer_attr_lookup_t aclPacketColorPolicerAttrLookup = { + {P4_PACKET_COLOR_GREEN, SAI_POLICER_ATTR_GREEN_PACKET_ACTION}, + {P4_PACKET_COLOR_YELLOW, SAI_POLICER_ATTR_YELLOW_PACKET_ACTION}, + {P4_PACKET_COLOR_RED, SAI_POLICER_ATTR_RED_PACKET_ACTION}, }; static const acl_packet_color_lookup_t aclPacketColorLookup = { @@ -682,19 +683,16 @@ static const udf_base_lookup_t udfBaseLookup = { {P4_UDF_BASE_L4, SAI_UDF_BASE_L4}, }; -static std::map - aclCounterColoredPacketsStatsIdMap = { - {SAI_POLICER_ATTR_GREEN_PACKET_ACTION, SAI_POLICER_STAT_GREEN_PACKETS}, - {SAI_POLICER_ATTR_YELLOW_PACKET_ACTION, - SAI_POLICER_STAT_YELLOW_PACKETS}, - {SAI_POLICER_ATTR_RED_PACKET_ACTION, SAI_POLICER_STAT_RED_PACKETS}, +static std::map aclCounterColoredPacketsStatsIdMap = { + {SAI_POLICER_ATTR_GREEN_PACKET_ACTION, SAI_POLICER_STAT_GREEN_PACKETS}, + {SAI_POLICER_ATTR_YELLOW_PACKET_ACTION, SAI_POLICER_STAT_YELLOW_PACKETS}, + {SAI_POLICER_ATTR_RED_PACKET_ACTION, SAI_POLICER_STAT_RED_PACKETS}, }; -static std::map - aclCounterColoredBytesStatsIdMap = { - {SAI_POLICER_ATTR_GREEN_PACKET_ACTION, SAI_POLICER_STAT_GREEN_BYTES}, - {SAI_POLICER_ATTR_YELLOW_PACKET_ACTION, SAI_POLICER_STAT_YELLOW_BYTES}, - {SAI_POLICER_ATTR_RED_PACKET_ACTION, SAI_POLICER_STAT_RED_BYTES}, +static std::map aclCounterColoredBytesStatsIdMap = { + {SAI_POLICER_ATTR_GREEN_PACKET_ACTION, SAI_POLICER_STAT_GREEN_BYTES}, + {SAI_POLICER_ATTR_YELLOW_PACKET_ACTION, SAI_POLICER_STAT_YELLOW_BYTES}, + {SAI_POLICER_ATTR_RED_PACKET_ACTION, SAI_POLICER_STAT_RED_BYTES}, }; static std::map aclCounterStatsIdNameMap = { @@ -708,108 +706,86 @@ static std::map aclCounterStatsIdNameMap = { // Parse ACL table definition APP DB entry action field to P4ActionParamName // action_list and P4PacketActionWithColor action_color_list -bool parseAclTableAppDbActionField( - const std::string& aggr_actions_str, - std::vector* action_list, - std::vector* action_color_list); +bool parseAclTableAppDbActionField(const std::string &aggr_actions_str, std::vector *action_list, + std::vector *action_color_list); // Validate and set match field with kind:sai_field. Caller methods are // responsible to verify the kind before calling this method -ReturnCode validateAndSetSaiMatchFieldJson( - const nlohmann::json& match_json, const std::string& p4_match, - const std::string& aggr_match_str, - std::map* sai_match_field_lookup, - std::map* ip_type_bit_type_lookup); +ReturnCode validateAndSetSaiMatchFieldJson(const nlohmann::json &match_json, const std::string &p4_match, + const std::string &aggr_match_str, + std::map *sai_match_field_lookup, + std::map *ip_type_bit_type_lookup); // Validate and set composite match field element with kind:sai_field. // Composite SAI field only support IPv6-64bit now (IPV6_WORDn) ReturnCode validateAndSetCompositeElementSaiFieldJson( - const nlohmann::json& element_match_json, const std::string& p4_match, - std::map>* - composite_sai_match_fields_lookup, - const std::string& format_str = EMPTY_STRING); + const nlohmann::json &element_match_json, const std::string &p4_match, + std::map> *composite_sai_match_fields_lookup, + const std::string &format_str = EMPTY_STRING); // Validate and set UDF match field with kind:udf. Caller methods are // responsible for verifying the kind and format before calling this method -ReturnCode validateAndSetUdfFieldJson( - const nlohmann::json& match_json, const std::string& p4_match, - const std::string& aggr_match_str, const std::string& acl_table_name, - std::map>* udf_fields_lookup, - std::map* udf_group_attr_index_lookup); +ReturnCode validateAndSetUdfFieldJson(const nlohmann::json &match_json, const std::string &p4_match, + const std::string &aggr_match_str, const std::string &acl_table_name, + std::map> *udf_fields_lookup, + std::map *udf_group_attr_index_lookup); // Only two cases are allowed in composite fields: // 1. IPV6_64bit(IPV6_WORD3 and IPV6_WORD2 in elements, kind:sai_field, // format:IPV6) // 2. Generic UDF(UDF in elements, kind:udf, format:HEX_STRING) ReturnCode validateAndSetCompositeMatchFieldJson( - const nlohmann::json& aggr_match_json, const std::string& p4_match, - const std::string& aggr_match_str, const std::string& acl_table_name, - std::map>* - composite_sai_match_fields_lookup, - std::map>* udf_fields_lookup, - std::map* udf_group_attr_index_lookup); + const nlohmann::json &aggr_match_json, const std::string &p4_match, const std::string &aggr_match_str, + const std::string &acl_table_name, + std::map> *composite_sai_match_fields_lookup, + std::map> *udf_fields_lookup, + std::map *udf_group_attr_index_lookup); -ReturnCode buildAclTableDefinitionMatchFieldValues( - const std::map& match_field_lookup, - P4AclTableDefinition* acl_table); +ReturnCode buildAclTableDefinitionMatchFieldValues(const std::map &match_field_lookup, + P4AclTableDefinition *acl_table); // Build SaiActionWithParam action map for ACL table definition // by P4ActionParamName action map ReturnCode buildAclTableDefinitionActionFieldValues( - const std::map>& - action_field_lookup, - std::map>* - aggr_sai_actions_lookup); + const std::map> &action_field_lookup, + std::map> *aggr_sai_actions_lookup); bool isSetUserTrapActionInAclTableDefinition( - const std::map>& - aggr_sai_actions_lookup); + const std::map> &aggr_sai_actions_lookup); // Build packet color(sai_policer_attr_t) to packet // action(sai_packet_action_t) map for ACL table definition by // P4PacketActionWithColor action map. If packet color is empty, then the // packet action should add as a SaiActionWithParam ReturnCode buildAclTableDefinitionActionColorFieldValues( - const std::map>& - action_color_lookup, - std::map>* - aggr_sai_actions_lookup, - std::map>* - aggr_sai_action_color_lookup); + const std::map> &action_color_lookup, + std::map> *aggr_sai_actions_lookup, + std::map> *aggr_sai_action_color_lookup); // Set IP_TYPE in match field -bool setMatchFieldIpType(const std::string& attr_value, - sai_attribute_value_t* value, - const std::string& ip_type_bit_type); +bool setMatchFieldIpType(const std::string &attr_value, sai_attribute_value_t *value, + const std::string &ip_type_bit_type); // Set composite match field with sai_field type. Currently only ACL entry // attributes listed in aclCompositeMatchTableAttrLookup are supported -ReturnCode setCompositeSaiMatchValue(const acl_entry_attr_union_t attr_name, - const std::string& attr_value, - sai_attribute_value_t* value); +ReturnCode setCompositeSaiMatchValue(const acl_entry_attr_union_t attr_name, const std::string &attr_value, + sai_attribute_value_t *value); // Set composite match field with sai_field type. -ReturnCode setUdfMatchValue(const P4UdfField& udf_field, - const std::string& attr_value, - sai_attribute_value_t* value, - P4UdfDataMask* udf_data_mask, - uint16_t bytes_offset); +ReturnCode setUdfMatchValue(const P4UdfField &udf_field, const std::string &attr_value, sai_attribute_value_t *value, + P4UdfDataMask *udf_data_mask, uint16_t bytes_offset); // Compares the action value difference if the action field is present in // both new and old ACL rules. Returns true if action values are different. -bool isDiffActionFieldValue(const acl_entry_attr_union_t attr_name, - const sai_attribute_value_t& value, - const sai_attribute_value_t& old_value, - const P4AclRule& acl_rule, - const P4AclRule& old_acl_rule); +bool isDiffActionFieldValue(const acl_entry_attr_union_t attr_name, const sai_attribute_value_t &value, + const sai_attribute_value_t &old_value, const P4AclRule &acl_rule, + const P4AclRule &old_acl_rule); // Compares the match value difference if the match field is present in // both new and old ACL rules. Returns true if match values are different. // This method is used in state verification only. -bool isDiffMatchFieldValue(const acl_entry_attr_union_t attr_name, - const sai_attribute_value_t& value, - const sai_attribute_value_t& old_value, - const P4AclRule& acl_rule, - const P4AclRule& old_acl_rule); +bool isDiffMatchFieldValue(const acl_entry_attr_union_t attr_name, const sai_attribute_value_t &value, + const sai_attribute_value_t &old_value, const P4AclRule &acl_rule, + const P4AclRule &old_acl_rule); -} // namespace p4orch +} // namespace p4orch diff --git a/orchagent/p4orch/ext_tables_manager.cpp b/orchagent/p4orch/ext_tables_manager.cpp index 41af2747108..ae091fcd775 100644 --- a/orchagent/p4orch/ext_tables_manager.cpp +++ b/orchagent/p4orch/ext_tables_manager.cpp @@ -16,845 +16,849 @@ #include "p4orch/p4orch_util.h" #include "tokenize.h" -extern sai_counter_api_t* sai_counter_api; -extern sai_generic_programmable_api_t* sai_generic_programmable_api; +extern sai_counter_api_t *sai_counter_api; +extern sai_generic_programmable_api_t *sai_generic_programmable_api; -extern Directory gDirectory; +extern Directory gDirectory; extern sai_object_id_t gSwitchId; -extern P4Orch* gP4Orch; -extern CrmOrch* gCrmOrch; +extern P4Orch *gP4Orch; +extern CrmOrch *gCrmOrch; -P4ExtTableEntry* ExtTablesManager::getP4ExtTableEntry( - const std::string& table_name, const std::string& key) { - SWSS_LOG_ENTER(); +P4ExtTableEntry *ExtTablesManager::getP4ExtTableEntry(const std::string &table_name, const std::string &key) +{ + SWSS_LOG_ENTER(); - auto it = m_extTables.find(table_name); - if (it == m_extTables.end()) return nullptr; + auto it = m_extTables.find(table_name); + if (it == m_extTables.end()) + return nullptr; - if (it->second.find(key) == it->second.end()) return nullptr; + if (it->second.find(key) == it->second.end()) + return nullptr; - return &it->second[key]; + return &it->second[key]; } -std::string getCrossRefTableName(const std::string table_name) { - auto it = FixedTablesMap.find(table_name); - if (it != FixedTablesMap.end()) { - return (it->second); - } +std::string getCrossRefTableName(const std::string table_name) +{ + auto it = FixedTablesMap.find(table_name); + if (it != FixedTablesMap.end()) + { + return (it->second); + } - return (table_name); + return (table_name); } -ReturnCode ExtTablesManager::validateActionParamsCrossRef( - P4ExtTableAppDbEntry& app_db_entry, ActionInfo* action) { - const std::string action_name = action->name; - std::unordered_map cross_ref_key_j; - ReturnCode status; +ReturnCode ExtTablesManager::validateActionParamsCrossRef(P4ExtTableAppDbEntry &app_db_entry, ActionInfo *action) +{ + const std::string action_name = action->name; + std::unordered_map cross_ref_key_j; + ReturnCode status; + + for (auto param_defn_it = action->params.begin(); param_defn_it != action->params.end(); param_defn_it++) + { + ActionParamInfo action_param_defn = param_defn_it->second; + if (action_param_defn.table_reference_map.empty()) + { + continue; + } - for (auto param_defn_it = action->params.begin(); - param_defn_it != action->params.end(); param_defn_it++) { - ActionParamInfo action_param_defn = param_defn_it->second; - if (action_param_defn.table_reference_map.empty()) { - continue; - } + std::string param_name = param_defn_it->first; - std::string param_name = param_defn_it->first; + auto app_db_param_it = app_db_entry.action_params[action_name].find(param_name); + if (app_db_param_it == app_db_entry.action_params[action_name].end()) + { + SWSS_LOG_ERROR("Required param not specified for action %s\n", action_name.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Required param not specified for action %s " << action_name.c_str(); + } - auto app_db_param_it = - app_db_entry.action_params[action_name].find(param_name); - if (app_db_param_it == app_db_entry.action_params[action_name].end()) { - SWSS_LOG_ERROR("Required param not specified for action %s\n", - action_name.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Required param not specified for action %s " - << action_name.c_str(); + for (auto cross_ref_it = action_param_defn.table_reference_map.begin(); + cross_ref_it != action_param_defn.table_reference_map.end(); cross_ref_it++) + { + cross_ref_key_j[cross_ref_it->first].push_back( + nlohmann::json::object_t::value_type(prependMatchField(cross_ref_it->second), app_db_param_it->second)); + } } - for (auto cross_ref_it = action_param_defn.table_reference_map.begin(); - cross_ref_it != action_param_defn.table_reference_map.end(); - cross_ref_it++) { - cross_ref_key_j[cross_ref_it->first].push_back( - nlohmann::json::object_t::value_type( - prependMatchField(cross_ref_it->second), - app_db_param_it->second)); - } - } + for (auto it = cross_ref_key_j.begin(); it != cross_ref_key_j.end(); it++) + { + const std::string table_name = getCrossRefTableName(it->first); + const std::string table_key = it->second.dump(); + std::string key; + sai_object_type_t object_type; + sai_object_id_t oid; + DepObject dep_object = {}; + + if (gP4Orch->m_p4TableToManagerMap.find(table_name) != gP4Orch->m_p4TableToManagerMap.end()) + { + status = gP4Orch->m_p4TableToManagerMap[table_name]->getSaiObject(table_key, object_type, key); + if (!status.ok()) + { + SWSS_LOG_ERROR("Cross-table reference validation failed from fixed-table %s", table_name.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Cross-table reference valdiation failed from fixed-table"; + } + } + else + { + if (getTableInfo(table_name)) + { + auto ext_table_key = KeyGenerator::generateExtTableKey(table_name, table_key); + status = getSaiObject(ext_table_key, object_type, key); + if (!status.ok()) + { + SWSS_LOG_ERROR("Cross-table reference validation failed from extension-table %s", + table_name.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Cross-table reference valdiation failed from extension " + "table"; + } + } + else + { + SWSS_LOG_ERROR("Cross-table reference validation failed due to non-existent table " + "%s", + table_name.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Cross-table reference valdiation failed due to non-existent " + "table"; + } + } - for (auto it = cross_ref_key_j.begin(); it != cross_ref_key_j.end(); it++) { - const std::string table_name = getCrossRefTableName(it->first); - const std::string table_key = it->second.dump(); - std::string key; - sai_object_type_t object_type; - sai_object_id_t oid; - DepObject dep_object = {}; - - if (gP4Orch->m_p4TableToManagerMap.find(table_name) != - gP4Orch->m_p4TableToManagerMap.end()) { - status = gP4Orch->m_p4TableToManagerMap[table_name]->getSaiObject( - table_key, object_type, key); - if (!status.ok()) { - SWSS_LOG_ERROR( - "Cross-table reference validation failed from fixed-table %s", - table_name.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Cross-table reference valdiation failed from fixed-table"; - } - } else { - if (getTableInfo(table_name)) { - auto ext_table_key = - KeyGenerator::generateExtTableKey(table_name, table_key); - status = getSaiObject(ext_table_key, object_type, key); - if (!status.ok()) { - SWSS_LOG_ERROR( - "Cross-table reference validation failed from extension-table %s", - table_name.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Cross-table reference valdiation failed from extension " - "table"; + if (!m_p4OidMapper->getOID(object_type, key, &oid)) + { + SWSS_LOG_ERROR("Cross-table reference validation failed, no OID found from table %s", table_name.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Cross-table reference valdiation failed, no OID found"; } - } else { - SWSS_LOG_ERROR( - "Cross-table reference validation failed due to non-existent table " - "%s", - table_name.c_str()); + + if (oid == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_ERROR("Cross-table reference validation failed, null OID expected from " + "table %s", + table_name.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Cross-table reference valdiation failed, null OID"; + } + + dep_object.sai_object = object_type; + dep_object.key = key; + dep_object.oid = oid; + app_db_entry.action_dep_objects[action_name] = dep_object; + } + + return ReturnCode(); +} + +ReturnCode ExtTablesManager::validateP4ExtTableAppDbEntry(P4ExtTableAppDbEntry &app_db_entry) +{ + // Perform generic APP DB entry validations. Operation specific validations + // will be done by the respective request process methods. + ReturnCode status; + + TableInfo *table; + table = getTableInfo(app_db_entry.table_name); + if (table == nullptr) + { + SWSS_LOG_ERROR("Not a valid extension table %s", app_db_entry.table_name.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Cross-table reference valdiation failed due to non-existent " - "table"; - } + << "Not a valid extension table " << app_db_entry.table_name.c_str(); } - if (!m_p4OidMapper->getOID(object_type, key, &oid)) { - SWSS_LOG_ERROR( - "Cross-table reference validation failed, no OID found from table %s", - table_name.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Cross-table reference valdiation failed, no OID found"; + if (table->action_ref_tables.empty()) + { + return ReturnCode(); } - if (oid == SAI_NULL_OBJECT_ID) { - SWSS_LOG_ERROR( - "Cross-table reference validation failed, null OID expected from " - "table %s", - table_name.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Cross-table reference valdiation failed, null OID"; + ActionInfo *action; + for (auto app_db_action_it = app_db_entry.action_params.begin(); + app_db_action_it != app_db_entry.action_params.end(); app_db_action_it++) + { + auto action_name = app_db_action_it->first; + action = getTableActionInfo(table, action_name); + if (action == nullptr) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Not a valid action " << action_name.c_str() << " in extension table " + << app_db_entry.table_name.c_str(); + } + + if (!action->refers_to) + { + continue; + } + + status = validateActionParamsCrossRef(app_db_entry, action); + if (!status.ok()) + { + return status; + } } - dep_object.sai_object = object_type; - dep_object.key = key; - dep_object.oid = oid; - app_db_entry.action_dep_objects[action_name] = dep_object; - } + return ReturnCode(); +} + +ReturnCodeOr ExtTablesManager::deserializeP4ExtTableEntry( + const std::string &table_name, const std::string &key, const std::vector &attributes) +{ + std::string action_name; + + SWSS_LOG_ENTER(); + + P4ExtTableAppDbEntry app_db_entry_or = {}; + app_db_entry_or.table_name = table_name; + app_db_entry_or.table_key = key; + + action_name = ""; + for (const auto &it : attributes) + { + auto field = fvField(it); + auto value = fvValue(it); + + if (field == p4orch::kAction) + { + action_name = value; + continue; + } + + const auto &tokenized_fields = tokenize(field, p4orch::kFieldDelimiter); + if (tokenized_fields.size() <= 1) + { + SWSS_LOG_ERROR("Unknown extension entry field"); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unknown extension entry field " << QuotedVar(field); + } + + const auto &prefix = tokenized_fields[0]; + if (prefix == p4orch::kActionParamPrefix) + { + const auto ¶m_name = tokenized_fields[1]; + app_db_entry_or.action_params[action_name][param_name] = value; + continue; + } + else + { + SWSS_LOG_ERROR("Unexpected extension entry field"); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unexpected extension entry field " << QuotedVar(field); + } + } - return ReturnCode(); + return app_db_entry_or; } -ReturnCode ExtTablesManager::validateP4ExtTableAppDbEntry( - P4ExtTableAppDbEntry& app_db_entry) { - // Perform generic APP DB entry validations. Operation specific validations - // will be done by the respective request process methods. - ReturnCode status; - - TableInfo* table; - table = getTableInfo(app_db_entry.table_name); - if (table == nullptr) { - SWSS_LOG_ERROR("Not a valid extension table %s", - app_db_entry.table_name.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Not a valid extension table " << app_db_entry.table_name.c_str(); - } - - if (table->action_ref_tables.empty()) { - return ReturnCode(); - } +ReturnCode ExtTablesManager::prepareP4SaiExtAPIParams(const P4ExtTableAppDbEntry &app_db_entry, + std::string &ext_table_entry_attr) +{ + nlohmann::json sai_j, sai_metadata_j, sai_array_j = {}, sai_entry_j; + + SWSS_LOG_ENTER(); + + try + { + TableInfo *table; + table = getTableInfo(app_db_entry.table_name); + if (!table) + { + SWSS_LOG_ERROR("extension entry for invalid table %s", app_db_entry.table_name.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "extension entry for invalid table " << app_db_entry.table_name.c_str(); + } + + nlohmann::json j = nlohmann::json::parse(app_db_entry.table_key); + for (auto it = j.begin(); it != j.end(); ++it) + { + std::string match, value, prefix; + std::size_t pos; + + match = it.key(); + value = it.value(); + + prefix = p4orch::kMatchPrefix; + pos = match.rfind(prefix); + if (pos != std::string::npos) + { + match.erase(0, prefix.length()); + } + else + { + SWSS_LOG_ERROR("Failed to encode match fields for sai call"); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Failed to encode match fields for sai call"; + } + + prefix = p4orch::kFieldDelimiter; + pos = match.rfind(prefix); + if (pos != std::string::npos) + { + match.erase(0, prefix.length()); + } + else + { + SWSS_LOG_ERROR("Failed to encode match fields for sai call"); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Failed to encode match fields for sai call"; + } + + auto match_defn_it = table->match_fields.find(match); + if (match_defn_it == table->match_fields.end()) + { + SWSS_LOG_ERROR("extension entry for invalid match field %s", match.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "extension entry for invalid match field " << match.c_str(); + } + + sai_metadata_j = nlohmann::json::object({}); + sai_metadata_j["sai_attr_value_type"] = match_defn_it->second.datatype; + + sai_j = nlohmann::json::object({}); + sai_j[match]["value"] = value; + sai_j[match]["sai_metadata"] = sai_metadata_j; + + sai_array_j.push_back(sai_j); + } - ActionInfo* action; - for (auto app_db_action_it = app_db_entry.action_params.begin(); - app_db_action_it != app_db_entry.action_params.end(); - app_db_action_it++) { - auto action_name = app_db_action_it->first; - action = getTableActionInfo(table, action_name); - if (action == nullptr) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Not a valid action " << action_name.c_str() - << " in extension table " << app_db_entry.table_name.c_str(); + for (auto app_db_action_it = app_db_entry.action_params.begin(); + app_db_action_it != app_db_entry.action_params.end(); app_db_action_it++) + { + sai_j = nlohmann::json::object({}); + auto action_dep_object_it = app_db_entry.action_dep_objects.find(app_db_action_it->first); + if (action_dep_object_it == app_db_entry.action_dep_objects.end()) + { + auto action_defn_it = table->action_fields.find(app_db_action_it->first); + for (auto app_db_param_it = app_db_action_it->second.begin(); + app_db_param_it != app_db_action_it->second.end(); app_db_param_it++) + { + nlohmann::json params_j = nlohmann::json::object({}); + if (action_defn_it != table->action_fields.end()) + { + auto param_defn_it = action_defn_it->second.params.find(app_db_param_it->first); + if (param_defn_it != action_defn_it->second.params.end()) + { + sai_metadata_j = nlohmann::json::object({}); + sai_metadata_j["sai_attr_value_type"] = param_defn_it->second.datatype; + + params_j[app_db_param_it->first]["sai_metadata"] = sai_metadata_j; + } + } + params_j[app_db_param_it->first]["value"] = app_db_param_it->second; + sai_j[app_db_action_it->first].push_back(params_j); + } + } + else + { + auto action_dep_object = action_dep_object_it->second; + + sai_metadata_j = nlohmann::json::object({}); + sai_metadata_j["sai_attr_value_type"] = "SAI_ATTR_VALUE_TYPE_OBJECT_ID"; + + sai_j[app_db_action_it->first]["sai_metadata"] = sai_metadata_j; + sai_j[app_db_action_it->first]["value"] = action_dep_object.oid; + } + + sai_array_j.push_back(sai_j); + } + } + catch (std::exception &ex) + { + SWSS_LOG_ERROR("Failed to encode table %s entry for sai call", app_db_entry.table_name.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Failed to encode table entry for sai call"; } - if (!action->refers_to) { - continue; + sai_entry_j = nlohmann::json::object({}); + sai_entry_j.push_back(nlohmann::json::object_t::value_type("attributes", sai_array_j)); + SWSS_LOG_ERROR("table: %s, sai entry: %s", app_db_entry.table_name.c_str(), sai_entry_j.dump().c_str()); + ext_table_entry_attr = sai_entry_j.dump(); + + return ReturnCode(); +} + +bool removeGenericCounter(sai_object_id_t counter_id) +{ + sai_status_t sai_status = sai_counter_api->remove_counter(counter_id); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to remove generic counter: %" PRId64 "", counter_id); + return false; } - status = validateActionParamsCrossRef(app_db_entry, action); - if (!status.ok()) { - return status; + return true; +} + +bool createGenericCounter(sai_object_id_t &counter_id) +{ + sai_attribute_t counter_attr; + counter_attr.id = SAI_COUNTER_ATTR_TYPE; + counter_attr.value.s32 = SAI_COUNTER_TYPE_REGULAR; + sai_status_t sai_status = sai_counter_api->create_counter(&counter_id, gSwitchId, 1, &counter_attr); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_WARN("Failed to create generic counter"); + return false; } - } - return ReturnCode(); + return true; } -ReturnCodeOr ExtTablesManager::deserializeP4ExtTableEntry( - const std::string& table_name, const std::string& key, - const std::vector& attributes) { - std::string action_name; +ReturnCode ExtTablesManager::createP4ExtTableEntry(const P4ExtTableAppDbEntry &app_db_entry, + P4ExtTableEntry &ext_table_entry) +{ + ReturnCode status; + sai_object_type_t object_type; + std::string key; + std::string ext_table_entry_attr; + sai_object_id_t counter_id; + + SWSS_LOG_ENTER(); - SWSS_LOG_ENTER(); + status = prepareP4SaiExtAPIParams(app_db_entry, ext_table_entry_attr); + if (!status.ok()) + { + return status; + } - P4ExtTableAppDbEntry app_db_entry_or = {}; - app_db_entry_or.table_name = table_name; - app_db_entry_or.table_key = key; + // Prepare attributes for the SAI create call. + std::vector generic_programmable_attrs; + sai_attribute_t generic_programmable_attr; - action_name = ""; - for (const auto& it : attributes) { - auto field = fvField(it); - auto value = fvValue(it); + generic_programmable_attr.id = SAI_GENERIC_PROGRAMMABLE_ATTR_OBJECT_NAME; + generic_programmable_attr.value.s8list.count = (uint32_t)app_db_entry.table_name.size(); + generic_programmable_attr.value.s8list.list = (int8_t *)const_cast(app_db_entry.table_name.c_str()); + generic_programmable_attrs.push_back(generic_programmable_attr); - if (field == p4orch::kAction) { - action_name = value; - continue; + generic_programmable_attr.id = SAI_GENERIC_PROGRAMMABLE_ATTR_ENTRY; + generic_programmable_attr.value.json.json.count = (uint32_t)ext_table_entry_attr.size(); + generic_programmable_attr.value.json.json.list = (int8_t *)const_cast(ext_table_entry_attr.c_str()); + generic_programmable_attrs.push_back(generic_programmable_attr); + + auto *table = getTableInfo(app_db_entry.table_name); + if (!table) + { + SWSS_LOG_ERROR("extension entry for invalid table %s", app_db_entry.table_name.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "extension entry for invalid table " << app_db_entry.table_name.c_str(); } - const auto& tokenized_fields = tokenize(field, p4orch::kFieldDelimiter); - if (tokenized_fields.size() <= 1) { - SWSS_LOG_ERROR("Unknown extension entry field"); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown extension entry field " << QuotedVar(field); + if (table->counter_bytes_enabled || table->counter_packets_enabled) + { + if (!createGenericCounter(counter_id)) + { + SWSS_LOG_WARN("Failed to create counter for table %s, key %s\n", app_db_entry.table_name.c_str(), + app_db_entry.table_key.c_str()); + } + else + { + ext_table_entry.sai_counter_oid = counter_id; + } + + generic_programmable_attr.id = SAI_GENERIC_PROGRAMMABLE_ATTR_COUNTER_ID; + generic_programmable_attr.value.oid = counter_id; + generic_programmable_attrs.push_back(generic_programmable_attr); } - const auto& prefix = tokenized_fields[0]; - if (prefix == p4orch::kActionParamPrefix) { - const auto& param_name = tokenized_fields[1]; - app_db_entry_or.action_params[action_name][param_name] = value; - continue; - } else { - SWSS_LOG_ERROR("Unexpected extension entry field"); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unexpected extension entry field " << QuotedVar(field); + sai_object_id_t sai_generic_programmable_oid = SAI_NULL_OBJECT_ID; + sai_status_t sai_status = sai_generic_programmable_api->create_generic_programmable( + &sai_generic_programmable_oid, gSwitchId, (uint32_t)generic_programmable_attrs.size(), + generic_programmable_attrs.data()); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("create sai api call failed for extension entry table %s, entry %s", + app_db_entry.table_name.c_str(), app_db_entry.table_key.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "create sai api call failed for extension entry table " << app_db_entry.table_name.c_str() + << " , entry " << app_db_entry.table_key.c_str(); + } + std::string crm_table_name = "EXT_" + app_db_entry.table_name; + boost::algorithm::to_upper(crm_table_name); + gCrmOrch->incCrmExtTableUsedCounter(CrmResourceType::CRM_EXT_TABLE, crm_table_name); + + ext_table_entry.sai_entry_oid = sai_generic_programmable_oid; + for (auto action_dep_object_it = app_db_entry.action_dep_objects.begin(); + action_dep_object_it != app_db_entry.action_dep_objects.end(); action_dep_object_it++) + { + auto action_dep_object = action_dep_object_it->second; + m_p4OidMapper->increaseRefCount(action_dep_object.sai_object, action_dep_object.key); + ext_table_entry.action_dep_objects[action_dep_object_it->first] = action_dep_object; } - } - return app_db_entry_or; + auto ext_table_key = KeyGenerator::generateExtTableKey(app_db_entry.table_name, app_db_entry.table_key); + status = getSaiObject(ext_table_key, object_type, key); + if (!status.ok()) + { + SWSS_LOG_ERROR("Invalid formation of a key %s", ext_table_key.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Invalid formation of a key"; + } + + m_p4OidMapper->setOID(object_type, key, ext_table_entry.sai_entry_oid); + m_extTables[app_db_entry.table_name][app_db_entry.table_key] = ext_table_entry; + return ReturnCode(); } -ReturnCode ExtTablesManager::prepareP4SaiExtAPIParams( - const P4ExtTableAppDbEntry& app_db_entry, - std::string& ext_table_entry_attr) { - nlohmann::json sai_j, sai_metadata_j, sai_array_j = {}, sai_entry_j; +ReturnCode ExtTablesManager::updateP4ExtTableEntry(const P4ExtTableAppDbEntry &app_db_entry, + P4ExtTableEntry *ext_table_entry) +{ + ReturnCode status; + std::string ext_table_entry_attr; + std::unordered_map old_action_dep_objects; - SWSS_LOG_ENTER(); + SWSS_LOG_ENTER(); - try { - TableInfo* table; - table = getTableInfo(app_db_entry.table_name); - if (!table) { - SWSS_LOG_ERROR("extension entry for invalid table %s", - app_db_entry.table_name.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "extension entry for invalid table " - << app_db_entry.table_name.c_str(); - } - - nlohmann::json j = nlohmann::json::parse(app_db_entry.table_key); - for (auto it = j.begin(); it != j.end(); ++it) { - std::string match, value, prefix; - std::size_t pos; - - match = it.key(); - value = it.value(); - - prefix = p4orch::kMatchPrefix; - pos = match.rfind(prefix); - if (pos != std::string::npos) { - match.erase(0, prefix.length()); - } else { - SWSS_LOG_ERROR("Failed to encode match fields for sai call"); + if (ext_table_entry->sai_entry_oid == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_ERROR("update sai api call for NULL extension entry table %s, entry %s", + app_db_entry.table_name.c_str(), ext_table_entry->table_key.c_str()); return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to encode match fields for sai call"; - } - - prefix = p4orch::kFieldDelimiter; - pos = match.rfind(prefix); - if (pos != std::string::npos) { - match.erase(0, prefix.length()); - } else { - SWSS_LOG_ERROR("Failed to encode match fields for sai call"); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to encode match fields for sai call"; - } + << "update sai api call for NULL extension entry table " << app_db_entry.table_name.c_str() + << " , entry " << ext_table_entry->table_key.c_str(); + } - auto match_defn_it = table->match_fields.find(match); - if (match_defn_it == table->match_fields.end()) { - SWSS_LOG_ERROR("extension entry for invalid match field %s", - match.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "extension entry for invalid match field " << match.c_str(); - } + status = prepareP4SaiExtAPIParams(app_db_entry, ext_table_entry_attr); + if (!status.ok()) + { + return status; + } - sai_metadata_j = nlohmann::json::object({}); - sai_metadata_j["sai_attr_value_type"] = match_defn_it->second.datatype; + // Prepare attribute for the SAI update call. + sai_attribute_t generic_programmable_attr; - sai_j = nlohmann::json::object({}); - sai_j[match]["value"] = value; - sai_j[match]["sai_metadata"] = sai_metadata_j; + generic_programmable_attr.id = SAI_GENERIC_PROGRAMMABLE_ATTR_ENTRY; + generic_programmable_attr.value.json.json.count = (uint32_t)ext_table_entry_attr.length(); + generic_programmable_attr.value.json.json.list = (int8_t *)const_cast(ext_table_entry_attr.c_str()); - sai_array_j.push_back(sai_j); + sai_status_t sai_status = sai_generic_programmable_api->set_generic_programmable_attribute( + ext_table_entry->sai_entry_oid, &generic_programmable_attr); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("update sai api call failed for extension entry table %s, entry %s", + app_db_entry.table_name.c_str(), ext_table_entry->table_key.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "update sai api call failed for extension entry table " << app_db_entry.table_name.c_str() + << " , entry " << ext_table_entry->table_key.c_str(); } - for (auto app_db_action_it = app_db_entry.action_params.begin(); - app_db_action_it != app_db_entry.action_params.end(); - app_db_action_it++) { - sai_j = nlohmann::json::object({}); - auto action_dep_object_it = - app_db_entry.action_dep_objects.find(app_db_action_it->first); - if (action_dep_object_it == app_db_entry.action_dep_objects.end()) { - auto action_defn_it = - table->action_fields.find(app_db_action_it->first); - for (auto app_db_param_it = app_db_action_it->second.begin(); - app_db_param_it != app_db_action_it->second.end(); - app_db_param_it++) { - nlohmann::json params_j = nlohmann::json::object({}); - if (action_defn_it != table->action_fields.end()) { - auto param_defn_it = - action_defn_it->second.params.find(app_db_param_it->first); - if (param_defn_it != action_defn_it->second.params.end()) { - sai_metadata_j = nlohmann::json::object({}); - sai_metadata_j["sai_attr_value_type"] = - param_defn_it->second.datatype; - - params_j[app_db_param_it->first]["sai_metadata"] = sai_metadata_j; - } - } - params_j[app_db_param_it->first]["value"] = app_db_param_it->second; - sai_j[app_db_action_it->first].push_back(params_j); - } - } else { + old_action_dep_objects = ext_table_entry->action_dep_objects; + ext_table_entry->action_dep_objects.clear(); + + for (auto action_dep_object_it = app_db_entry.action_dep_objects.begin(); + action_dep_object_it != app_db_entry.action_dep_objects.end(); action_dep_object_it++) + { auto action_dep_object = action_dep_object_it->second; + m_p4OidMapper->increaseRefCount(action_dep_object.sai_object, action_dep_object.key); + ext_table_entry->action_dep_objects[action_dep_object_it->first] = action_dep_object; + } + + for (auto old_action_dep_object_it = old_action_dep_objects.begin(); + old_action_dep_object_it != old_action_dep_objects.end(); old_action_dep_object_it++) + { + auto old_action_dep_object = old_action_dep_object_it->second; + m_p4OidMapper->decreaseRefCount(old_action_dep_object.sai_object, old_action_dep_object.key); + } - sai_metadata_j = nlohmann::json::object({}); - sai_metadata_j["sai_attr_value_type"] = "SAI_ATTR_VALUE_TYPE_OBJECT_ID"; + return ReturnCode(); +} - sai_j[app_db_action_it->first]["sai_metadata"] = sai_metadata_j; - sai_j[app_db_action_it->first]["value"] = action_dep_object.oid; - } +ReturnCode ExtTablesManager::removeP4ExtTableEntry(const std::string &table_name, const std::string &table_key) +{ + ReturnCode status; + sai_object_type_t object_type; + std::string key; - sai_array_j.push_back(sai_j); + SWSS_LOG_ENTER(); + + auto *ext_table_entry = getP4ExtTableEntry(table_name, table_key); + if (!ext_table_entry) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "extension entry with key " << QuotedVar(table_key) << " does not exist for table " + << QuotedVar(table_name)); } - } catch (std::exception& ex) { - SWSS_LOG_ERROR("Failed to encode table %s entry for sai call", - app_db_entry.table_name.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to encode table entry for sai call"; - } - sai_entry_j = nlohmann::json::object({}); - sai_entry_j.push_back( - nlohmann::json::object_t::value_type("attributes", sai_array_j)); - SWSS_LOG_ERROR("table: %s, sai entry: %s", app_db_entry.table_name.c_str(), - sai_entry_j.dump().c_str()); - ext_table_entry_attr = sai_entry_j.dump(); + if (ext_table_entry->sai_entry_oid == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_ERROR("remove sai api call for NULL extension entry table %s, entry %s", table_name.c_str(), + table_key.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "remove sai api call for NULL extension entry table " + << table_name.c_str() << " , entry " << table_key.c_str(); + } - return ReturnCode(); -} + SWSS_LOG_ERROR("table: %s, key: %s", ext_table_entry->table_name.c_str(), ext_table_entry->table_key.c_str()); + sai_status_t sai_status = sai_generic_programmable_api->remove_generic_programmable(ext_table_entry->sai_entry_oid); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("remove sai api call failed for extension entry table %s, entry %s", table_name.c_str(), + table_key.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "remove sai api call failed for extension entry table " + << table_name.c_str() << " , entry " << table_key.c_str(); + } + std::string crm_table_name = "EXT_" + table_name; + boost::algorithm::to_upper(crm_table_name); + gCrmOrch->decCrmExtTableUsedCounter(CrmResourceType::CRM_EXT_TABLE, crm_table_name); + + auto ext_table_key = KeyGenerator::generateExtTableKey(table_name, table_key); + status = getSaiObject(ext_table_key, object_type, key); + if (!status.ok()) + { + SWSS_LOG_ERROR("Invalid formation of a key %s", ext_table_key.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Invalid formation of a key"; + } -bool removeGenericCounter(sai_object_id_t counter_id) { - sai_status_t sai_status = sai_counter_api->remove_counter(counter_id); - if (sai_status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to remove generic counter: %" PRId64 "", counter_id); - return false; - } + uint32_t ref_count; + if (!m_p4OidMapper->getRefCount(object_type, key, &ref_count)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Failed to get reference count for " << QuotedVar(key)); + } + if (ref_count > 0) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "extension entry " << QuotedVar(key) + << " referenced by other objects (ref_count = " << ref_count); + } + m_p4OidMapper->eraseOID(object_type, key); - return true; -} + for (auto action_dep_object_it = ext_table_entry->action_dep_objects.begin(); + action_dep_object_it != ext_table_entry->action_dep_objects.end(); action_dep_object_it++) + { + auto action_dep_object = action_dep_object_it->second; + m_p4OidMapper->decreaseRefCount(action_dep_object.sai_object, action_dep_object.key); + } -bool createGenericCounter(sai_object_id_t& counter_id) { - sai_attribute_t counter_attr; - counter_attr.id = SAI_COUNTER_ATTR_TYPE; - counter_attr.value.s32 = SAI_COUNTER_TYPE_REGULAR; - sai_status_t sai_status = - sai_counter_api->create_counter(&counter_id, gSwitchId, 1, &counter_attr); - if (sai_status != SAI_STATUS_SUCCESS) { - SWSS_LOG_WARN("Failed to create generic counter"); - return false; - } - - return true; -} + if (ext_table_entry->sai_counter_oid != SAI_NULL_OBJECT_ID) + { + m_countersTable->del(ext_table_entry->db_key); + removeGenericCounter(ext_table_entry->sai_counter_oid); + } -ReturnCode ExtTablesManager::createP4ExtTableEntry( - const P4ExtTableAppDbEntry& app_db_entry, - P4ExtTableEntry& ext_table_entry) { - ReturnCode status; - sai_object_type_t object_type; - std::string key; - std::string ext_table_entry_attr; - sai_object_id_t counter_id; - - SWSS_LOG_ENTER(); - - status = prepareP4SaiExtAPIParams(app_db_entry, ext_table_entry_attr); - if (!status.ok()) { - return status; - } - - // Prepare attributes for the SAI create call. - std::vector generic_programmable_attrs; - sai_attribute_t generic_programmable_attr; - - generic_programmable_attr.id = SAI_GENERIC_PROGRAMMABLE_ATTR_OBJECT_NAME; - generic_programmable_attr.value.s8list.count = - (uint32_t)app_db_entry.table_name.size(); - generic_programmable_attr.value.s8list.list = - (int8_t*)const_cast(app_db_entry.table_name.c_str()); - generic_programmable_attrs.push_back(generic_programmable_attr); - - generic_programmable_attr.id = SAI_GENERIC_PROGRAMMABLE_ATTR_ENTRY; - generic_programmable_attr.value.json.json.count = - (uint32_t)ext_table_entry_attr.size(); - generic_programmable_attr.value.json.json.list = - (int8_t*)const_cast(ext_table_entry_attr.c_str()); - generic_programmable_attrs.push_back(generic_programmable_attr); - - auto* table = getTableInfo(app_db_entry.table_name); - if (!table) { - SWSS_LOG_ERROR("extension entry for invalid table %s", - app_db_entry.table_name.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "extension entry for invalid table " - << app_db_entry.table_name.c_str(); - } - - if (table->counter_bytes_enabled || table->counter_packets_enabled) { - if (!createGenericCounter(counter_id)) { - SWSS_LOG_WARN("Failed to create counter for table %s, key %s\n", - app_db_entry.table_name.c_str(), - app_db_entry.table_key.c_str()); - } else { - ext_table_entry.sai_counter_oid = counter_id; - } - - generic_programmable_attr.id = SAI_GENERIC_PROGRAMMABLE_ATTR_COUNTER_ID; - generic_programmable_attr.value.oid = counter_id; - generic_programmable_attrs.push_back(generic_programmable_attr); - } - - sai_object_id_t sai_generic_programmable_oid = SAI_NULL_OBJECT_ID; - sai_status_t sai_status = - sai_generic_programmable_api->create_generic_programmable( - &sai_generic_programmable_oid, gSwitchId, - (uint32_t)generic_programmable_attrs.size(), - generic_programmable_attrs.data()); - if (sai_status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR( - "create sai api call failed for extension entry table %s, entry %s", - app_db_entry.table_name.c_str(), app_db_entry.table_key.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "create sai api call failed for extension entry table " - << app_db_entry.table_name.c_str() << " , entry " - << app_db_entry.table_key.c_str(); - } - std::string crm_table_name = "EXT_" + app_db_entry.table_name; - boost::algorithm::to_upper(crm_table_name); - gCrmOrch->incCrmExtTableUsedCounter(CrmResourceType::CRM_EXT_TABLE, - crm_table_name); - - ext_table_entry.sai_entry_oid = sai_generic_programmable_oid; - for (auto action_dep_object_it = app_db_entry.action_dep_objects.begin(); - action_dep_object_it != app_db_entry.action_dep_objects.end(); - action_dep_object_it++) { - auto action_dep_object = action_dep_object_it->second; - m_p4OidMapper->increaseRefCount(action_dep_object.sai_object, - action_dep_object.key); - ext_table_entry.action_dep_objects[action_dep_object_it->first] = - action_dep_object; - } - - auto ext_table_key = KeyGenerator::generateExtTableKey( - app_db_entry.table_name, app_db_entry.table_key); - status = getSaiObject(ext_table_key, object_type, key); - if (!status.ok()) { - SWSS_LOG_ERROR("Invalid formation of a key %s", ext_table_key.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid formation of a key"; - } - - m_p4OidMapper->setOID(object_type, key, ext_table_entry.sai_entry_oid); - m_extTables[app_db_entry.table_name][app_db_entry.table_key] = - ext_table_entry; - return ReturnCode(); -} + m_extTables[table_name].erase(table_key); -ReturnCode ExtTablesManager::updateP4ExtTableEntry( - const P4ExtTableAppDbEntry& app_db_entry, - P4ExtTableEntry* ext_table_entry) { - ReturnCode status; - std::string ext_table_entry_attr; - std::unordered_map old_action_dep_objects; - - SWSS_LOG_ENTER(); - - if (ext_table_entry->sai_entry_oid == SAI_NULL_OBJECT_ID) { - SWSS_LOG_ERROR( - "update sai api call for NULL extension entry table %s, entry %s", - app_db_entry.table_name.c_str(), ext_table_entry->table_key.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "update sai api call for NULL extension entry table " - << app_db_entry.table_name.c_str() << " , entry " - << ext_table_entry->table_key.c_str(); - } - - status = prepareP4SaiExtAPIParams(app_db_entry, ext_table_entry_attr); - if (!status.ok()) { - return status; - } - - // Prepare attribute for the SAI update call. - sai_attribute_t generic_programmable_attr; - - generic_programmable_attr.id = SAI_GENERIC_PROGRAMMABLE_ATTR_ENTRY; - generic_programmable_attr.value.json.json.count = - (uint32_t)ext_table_entry_attr.length(); - generic_programmable_attr.value.json.json.list = - (int8_t*)const_cast(ext_table_entry_attr.c_str()); - - sai_status_t sai_status = - sai_generic_programmable_api->set_generic_programmable_attribute( - ext_table_entry->sai_entry_oid, &generic_programmable_attr); - if (sai_status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR( - "update sai api call failed for extension entry table %s, entry %s", - app_db_entry.table_name.c_str(), ext_table_entry->table_key.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "update sai api call failed for extension entry table " - << app_db_entry.table_name.c_str() << " , entry " - << ext_table_entry->table_key.c_str(); - } - - old_action_dep_objects = ext_table_entry->action_dep_objects; - ext_table_entry->action_dep_objects.clear(); - - for (auto action_dep_object_it = app_db_entry.action_dep_objects.begin(); - action_dep_object_it != app_db_entry.action_dep_objects.end(); - action_dep_object_it++) { - auto action_dep_object = action_dep_object_it->second; - m_p4OidMapper->increaseRefCount(action_dep_object.sai_object, - action_dep_object.key); - ext_table_entry->action_dep_objects[action_dep_object_it->first] = - action_dep_object; - } - - for (auto old_action_dep_object_it = old_action_dep_objects.begin(); - old_action_dep_object_it != old_action_dep_objects.end(); - old_action_dep_object_it++) { - auto old_action_dep_object = old_action_dep_object_it->second; - m_p4OidMapper->decreaseRefCount(old_action_dep_object.sai_object, - old_action_dep_object.key); - } - - return ReturnCode(); + return ReturnCode(); } -ReturnCode ExtTablesManager::removeP4ExtTableEntry( - const std::string& table_name, const std::string& table_key) { - ReturnCode status; - sai_object_type_t object_type; - std::string key; - - SWSS_LOG_ENTER(); - - auto* ext_table_entry = getP4ExtTableEntry(table_name, table_key); - if (!ext_table_entry) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "extension entry with key " << QuotedVar(table_key) - << " does not exist for table " - << QuotedVar(table_name)); - } - - if (ext_table_entry->sai_entry_oid == SAI_NULL_OBJECT_ID) { - SWSS_LOG_ERROR( - "remove sai api call for NULL extension entry table %s, entry %s", - table_name.c_str(), table_key.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "remove sai api call for NULL extension entry table " - << table_name.c_str() << " , entry " << table_key.c_str(); - } - - SWSS_LOG_ERROR("table: %s, key: %s", ext_table_entry->table_name.c_str(), - ext_table_entry->table_key.c_str()); - sai_status_t sai_status = - sai_generic_programmable_api->remove_generic_programmable( - ext_table_entry->sai_entry_oid); - if (sai_status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR( - "remove sai api call failed for extension entry table %s, entry %s", - table_name.c_str(), table_key.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "remove sai api call failed for extension entry table " - << table_name.c_str() << " , entry " << table_key.c_str(); - } - std::string crm_table_name = "EXT_" + table_name; - boost::algorithm::to_upper(crm_table_name); - gCrmOrch->decCrmExtTableUsedCounter(CrmResourceType::CRM_EXT_TABLE, - crm_table_name); - - auto ext_table_key = KeyGenerator::generateExtTableKey(table_name, table_key); - status = getSaiObject(ext_table_key, object_type, key); - if (!status.ok()) { - SWSS_LOG_ERROR("Invalid formation of a key %s", ext_table_key.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid formation of a key"; - } - - uint32_t ref_count; - if (!m_p4OidMapper->getRefCount(object_type, key, &ref_count)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Failed to get reference count for " << QuotedVar(key)); - } - if (ref_count > 0) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "extension entry " << QuotedVar(key) - << " referenced by other objects (ref_count = " - << ref_count); - } - m_p4OidMapper->eraseOID(object_type, key); - - for (auto action_dep_object_it = ext_table_entry->action_dep_objects.begin(); - action_dep_object_it != ext_table_entry->action_dep_objects.end(); - action_dep_object_it++) { - auto action_dep_object = action_dep_object_it->second; - m_p4OidMapper->decreaseRefCount(action_dep_object.sai_object, - action_dep_object.key); - } - - if (ext_table_entry->sai_counter_oid != SAI_NULL_OBJECT_ID) { - m_countersTable->del(ext_table_entry->db_key); - removeGenericCounter(ext_table_entry->sai_counter_oid); - } - - m_extTables[table_name].erase(table_key); - - return ReturnCode(); -} +ReturnCode ExtTablesManager::processAddRequest(const P4ExtTableAppDbEntry &app_db_entry) +{ + SWSS_LOG_ENTER(); -ReturnCode ExtTablesManager::processAddRequest( - const P4ExtTableAppDbEntry& app_db_entry) { - SWSS_LOG_ENTER(); - - P4ExtTableEntry ext_table_entry(app_db_entry.db_key, app_db_entry.table_name, - app_db_entry.table_key); - auto status = createP4ExtTableEntry(app_db_entry, ext_table_entry); - if (!status.ok()) { - return status; - } - return ReturnCode(); + P4ExtTableEntry ext_table_entry(app_db_entry.db_key, app_db_entry.table_name, app_db_entry.table_key); + auto status = createP4ExtTableEntry(app_db_entry, ext_table_entry); + if (!status.ok()) + { + return status; + } + return ReturnCode(); } -ReturnCode ExtTablesManager::processUpdateRequest( - const P4ExtTableAppDbEntry& app_db_entry, - P4ExtTableEntry* ext_table_entry) { - SWSS_LOG_ENTER(); - - auto status = updateP4ExtTableEntry(app_db_entry, ext_table_entry); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to update extension entry with key %s", - app_db_entry.table_key.c_str()); - } - return ReturnCode(); +ReturnCode ExtTablesManager::processUpdateRequest(const P4ExtTableAppDbEntry &app_db_entry, + P4ExtTableEntry *ext_table_entry) +{ + SWSS_LOG_ENTER(); + + auto status = updateP4ExtTableEntry(app_db_entry, ext_table_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to update extension entry with key %s", app_db_entry.table_key.c_str()); + } + return ReturnCode(); } -ReturnCode ExtTablesManager::processDeleteRequest( - const P4ExtTableAppDbEntry& app_db_entry) { - SWSS_LOG_ENTER(); - - auto status = - removeP4ExtTableEntry(app_db_entry.table_name, app_db_entry.table_key); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to remove extension entry with key %s", - app_db_entry.table_key.c_str()); - } - return ReturnCode(); +ReturnCode ExtTablesManager::processDeleteRequest(const P4ExtTableAppDbEntry &app_db_entry) +{ + SWSS_LOG_ENTER(); + + auto status = removeP4ExtTableEntry(app_db_entry.table_name, app_db_entry.table_key); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to remove extension entry with key %s", app_db_entry.table_key.c_str()); + } + return ReturnCode(); } -ReturnCode ExtTablesManager::getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) { - object_type = SAI_OBJECT_TYPE_GENERIC_PROGRAMMABLE; - object_key = json_key; +ReturnCode ExtTablesManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) +{ + object_type = SAI_OBJECT_TYPE_GENERIC_PROGRAMMABLE; + object_key = json_key; - return ReturnCode(); + return ReturnCode(); } -void ExtTablesManager::enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) { - m_entriesTables[table_name].push_back(entry); +void ExtTablesManager::enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) +{ + m_entriesTables[table_name].push_back(entry); } -void ExtTablesManager::drain() { - SWSS_LOG_ENTER(); - std::string table_prefix = "EXT_"; - - if (gP4Orch->tablesinfo) { - for (auto table_it = gP4Orch->tablesinfo->m_tablePrecedenceMap.begin(); - table_it != gP4Orch->tablesinfo->m_tablePrecedenceMap.end(); - ++table_it) { - auto table_name = table_prefix + table_it->second; - boost::algorithm::to_upper(table_name); - auto it_m = m_entriesTables.find(table_name); - if (it_m == m_entriesTables.end()) { - continue; - } - - for (const auto& key_op_fvs_tuple : it_m->second) { - std::string table_name; - std::string table_key; - - parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &table_key); - const std::vector& attributes = - kfvFieldsValues(key_op_fvs_tuple); - - if (table_name.rfind(table_prefix, 0) == std::string::npos) { - SWSS_LOG_ERROR("Table %s is without prefix %s", table_name.c_str(), - table_prefix.c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), - StatusCode::SWSS_RC_INVALID_PARAM, - /*replace=*/true); - continue; - } - table_name = table_name.substr(table_prefix.length()); - boost::algorithm::to_lower(table_name); - - ReturnCode status; - auto app_db_entry_or = - deserializeP4ExtTableEntry(table_name, table_key, attributes); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", - QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } +void ExtTablesManager::drain() +{ + SWSS_LOG_ENTER(); + std::string table_prefix = "EXT_"; + + if (gP4Orch->tablesinfo) + { + for (auto table_it = gP4Orch->tablesinfo->m_tablePrecedenceMap.begin(); + table_it != gP4Orch->tablesinfo->m_tablePrecedenceMap.end(); ++table_it) + { + auto table_name = table_prefix + table_it->second; + boost::algorithm::to_upper(table_name); + auto it_m = m_entriesTables.find(table_name); + if (it_m == m_entriesTables.end()) + { + continue; + } - auto& app_db_entry = *app_db_entry_or; - status = validateP4ExtTableAppDbEntry(app_db_entry); - if (!status.ok()) { - SWSS_LOG_ERROR( - "Validation failed for extension APP DB entry with key %s: %s", - QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } + for (const auto &key_op_fvs_tuple : it_m->second) + { + std::string table_name; + std::string table_key; + + parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &table_key); + const std::vector &attributes = kfvFieldsValues(key_op_fvs_tuple); + + if (table_name.rfind(table_prefix, 0) == std::string::npos) + { + SWSS_LOG_ERROR("Table %s is without prefix %s", table_name.c_str(), table_prefix.c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), + kfvFieldsValues(key_op_fvs_tuple), StatusCode::SWSS_RC_INVALID_PARAM, + /*replace=*/true); + continue; + } + table_name = table_name.substr(table_prefix.length()); + boost::algorithm::to_lower(table_name); + + ReturnCode status; + auto app_db_entry_or = deserializeP4ExtTableEntry(table_name, table_key, attributes); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", + QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), + kfvFieldsValues(key_op_fvs_tuple), status, + /*replace=*/true); + continue; + } + + auto &app_db_entry = *app_db_entry_or; + status = validateP4ExtTableAppDbEntry(app_db_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Validation failed for extension APP DB entry with key %s: %s", + QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), + kfvFieldsValues(key_op_fvs_tuple), status, + /*replace=*/true); + continue; + } + + const std::string &operation = kfvOp(key_op_fvs_tuple); + if (operation == SET_COMMAND) + { + auto *ext_table_entry = getP4ExtTableEntry(app_db_entry.table_name, app_db_entry.table_key); + if (ext_table_entry == nullptr) + { + // Create extension entry + app_db_entry.db_key = kfvKey(key_op_fvs_tuple); + status = processAddRequest(app_db_entry); + } + else + { + // Modify existing extension entry + status = processUpdateRequest(app_db_entry, ext_table_entry); + } + } + else if (operation == DEL_COMMAND) + { + // Delete extension entry + status = processDeleteRequest(app_db_entry); + } + else + { + status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unknown operation type " << QuotedVar(operation); + SWSS_LOG_ERROR("%s", status.message().c_str()); + } + if (!status.ok()) + { + SWSS_LOG_ERROR("Processing failed for extension APP_DB entry with key %s: %s", + QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), status.message().c_str()); + } + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + } - const std::string& operation = kfvOp(key_op_fvs_tuple); - if (operation == SET_COMMAND) { - auto* ext_table_entry = getP4ExtTableEntry(app_db_entry.table_name, - app_db_entry.table_key); - if (ext_table_entry == nullptr) { - // Create extension entry - app_db_entry.db_key = kfvKey(key_op_fvs_tuple); - status = processAddRequest(app_db_entry); - } else { - // Modify existing extension entry - status = processUpdateRequest(app_db_entry, ext_table_entry); - } - } else if (operation == DEL_COMMAND) { - // Delete extension entry - status = processDeleteRequest(app_db_entry); - } else { - status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown operation type " << QuotedVar(operation); - SWSS_LOG_ERROR("%s", status.message().c_str()); + it_m->second.clear(); } - if (!status.ok()) { - SWSS_LOG_ERROR( - "Processing failed for extension APP_DB entry with key %s: %s", - QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), - status.message().c_str()); + } + + // Now report error for all remaining un-processed entries + for (auto it_m = m_entriesTables.begin(); it_m != m_entriesTables.end(); it_m++) + { + for (const auto &key_op_fvs_tuple : it_m->second) + { + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + StatusCode::SWSS_RC_INVALID_PARAM, /*replace=*/true); } - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - } - it_m->second.clear(); + it_m->second.clear(); } - } +} - // Now report error for all remaining un-processed entries - for (auto it_m = m_entriesTables.begin(); it_m != m_entriesTables.end(); - it_m++) { - for (const auto& key_op_fvs_tuple : it_m->second) { - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), - StatusCode::SWSS_RC_INVALID_PARAM, /*replace=*/true); +void ExtTablesManager::doExtCounterStatsTask() +{ + SWSS_LOG_ENTER(); + + if (!gP4Orch->tablesinfo) + { + return; } - it_m->second.clear(); - } -} + sai_stat_id_t stat_ids[] = {SAI_COUNTER_STAT_PACKETS, SAI_COUNTER_STAT_BYTES}; + uint64_t stats[2]; + std::vector counter_stats_values; + + for (auto table_it = gP4Orch->tablesinfo->m_tableInfoMap.begin(); + table_it != gP4Orch->tablesinfo->m_tableInfoMap.end(); ++table_it) + { + if (!table_it->second.counter_bytes_enabled && !table_it->second.counter_packets_enabled) + { + continue; + } -void ExtTablesManager::doExtCounterStatsTask() { - SWSS_LOG_ENTER(); - - if (!gP4Orch->tablesinfo) { - return; - } - - sai_stat_id_t stat_ids[] = {SAI_COUNTER_STAT_PACKETS, SAI_COUNTER_STAT_BYTES}; - uint64_t stats[2]; - std::vector counter_stats_values; - - for (auto table_it = gP4Orch->tablesinfo->m_tableInfoMap.begin(); - table_it != gP4Orch->tablesinfo->m_tableInfoMap.end(); ++table_it) { - if (!table_it->second.counter_bytes_enabled && - !table_it->second.counter_packets_enabled) { - continue; - } - - auto table_name = table_it->second.name; - auto ext_table_it = m_extTables.find(table_name); - if (ext_table_it == m_extTables.end()) { - continue; - } - - for (auto ext_table_entry_it = ext_table_it->second.begin(); - ext_table_entry_it != ext_table_it->second.end(); - ++ext_table_entry_it) { - auto* ext_table_entry = &ext_table_entry_it->second; - if (ext_table_entry->sai_counter_oid == SAI_NULL_OBJECT_ID) { - continue; - } - - sai_status_t sai_status = sai_counter_api->get_counter_stats( - ext_table_entry->sai_counter_oid, 2, stat_ids, stats); - if (sai_status != SAI_STATUS_SUCCESS) { - SWSS_LOG_WARN( - "Failed to set counters stats for extension entry %s:%s in " - "COUNTERS_DB: ", - table_name.c_str(), ext_table_entry->table_key.c_str()); - continue; - } - - counter_stats_values.push_back(swss::FieldValueTuple{ - P4_COUNTER_STATS_PACKETS, std::to_string(stats[0])}); - counter_stats_values.push_back(swss::FieldValueTuple{ - P4_COUNTER_STATS_BYTES, std::to_string(stats[1])}); - - // Set field value tuples for counters stats in COUNTERS_DB - m_countersTable->set(ext_table_entry->db_key, counter_stats_values); - } - } + auto table_name = table_it->second.name; + auto ext_table_it = m_extTables.find(table_name); + if (ext_table_it == m_extTables.end()) + { + continue; + } + + for (auto ext_table_entry_it = ext_table_it->second.begin(); ext_table_entry_it != ext_table_it->second.end(); + ++ext_table_entry_it) + { + auto *ext_table_entry = &ext_table_entry_it->second; + if (ext_table_entry->sai_counter_oid == SAI_NULL_OBJECT_ID) + { + continue; + } + + sai_status_t sai_status = + sai_counter_api->get_counter_stats(ext_table_entry->sai_counter_oid, 2, stat_ids, stats); + if (sai_status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_WARN("Failed to set counters stats for extension entry %s:%s in " + "COUNTERS_DB: ", + table_name.c_str(), ext_table_entry->table_key.c_str()); + continue; + } + + counter_stats_values.push_back(swss::FieldValueTuple{P4_COUNTER_STATS_PACKETS, std::to_string(stats[0])}); + counter_stats_values.push_back(swss::FieldValueTuple{P4_COUNTER_STATS_BYTES, std::to_string(stats[1])}); + + // Set field value tuples for counters stats in COUNTERS_DB + m_countersTable->set(ext_table_entry->db_key, counter_stats_values); + } + } } -std::string ExtTablesManager::verifyState( - const std::string& key, const std::vector& tuple) { - std::string result = ""; - SWSS_LOG_ENTER(); +std::string ExtTablesManager::verifyState(const std::string &key, const std::vector &tuple) +{ + std::string result = ""; + SWSS_LOG_ENTER(); - return result; + return result; } diff --git a/orchagent/p4orch/ext_tables_manager.h b/orchagent/p4orch/ext_tables_manager.h index ea85402de95..82256f72ba1 100644 --- a/orchagent/p4orch/ext_tables_manager.h +++ b/orchagent/p4orch/ext_tables_manager.h @@ -15,93 +15,80 @@ #include "response_publisher_interface.h" #include "return_code.h" #include "vrforch.h" -extern "C" { +extern "C" +{ #include "sai.h" } -struct P4ExtTableEntry { - std::string db_key; - std::string table_name; - std::string table_key; - sai_object_id_t sai_entry_oid = SAI_NULL_OBJECT_ID; - sai_object_id_t sai_counter_oid = SAI_NULL_OBJECT_ID; - std::unordered_map action_dep_objects; +struct P4ExtTableEntry +{ + std::string db_key; + std::string table_name; + std::string table_key; + sai_object_id_t sai_entry_oid = SAI_NULL_OBJECT_ID; + sai_object_id_t sai_counter_oid = SAI_NULL_OBJECT_ID; + std::unordered_map action_dep_objects; - P4ExtTableEntry() {}; - P4ExtTableEntry(const std::string& db_key, const std::string& table_name, - const std::string& table_key) - : db_key(db_key), table_name(table_name), table_key(table_key) {} + P4ExtTableEntry() {}; + P4ExtTableEntry(const std::string &db_key, const std::string &table_name, const std::string &table_key) + : db_key(db_key), table_name(table_name), table_key(table_key) + { + } }; typedef std::unordered_map P4ExtTableEntryMap; typedef std::unordered_map P4ExtTableMap; -typedef std::unordered_map> - m_entriesTableMap; +typedef std::unordered_map> m_entriesTableMap; -class ExtTablesManager : public ObjectManagerInterface { - public: - ExtTablesManager(P4OidMapper* p4oidMapper, VRFOrch* vrfOrch, - ResponsePublisherInterface* publisher) - : m_vrfOrch(vrfOrch), - m_countersDb(std::make_unique("COUNTERS_DB", 0)), - m_countersTable(std::make_unique( - m_countersDb.get(), std::string(COUNTERS_TABLE) + - DEFAULT_KEY_SEPARATOR + - APP_P4RT_TABLE_NAME)) { - SWSS_LOG_ENTER(); +class ExtTablesManager : public ObjectManagerInterface +{ + public: + ExtTablesManager(P4OidMapper *p4oidMapper, VRFOrch *vrfOrch, ResponsePublisherInterface *publisher) + : m_vrfOrch(vrfOrch), m_countersDb(std::make_unique("COUNTERS_DB", 0)), + m_countersTable(std::make_unique( + m_countersDb.get(), std::string(COUNTERS_TABLE) + DEFAULT_KEY_SEPARATOR + APP_P4RT_TABLE_NAME)) + { + SWSS_LOG_ENTER(); - assert(p4oidMapper != nullptr); - m_p4OidMapper = p4oidMapper; - assert(publisher != nullptr); - m_publisher = publisher; - } - virtual ~ExtTablesManager() = default; + assert(p4oidMapper != nullptr); + m_p4OidMapper = p4oidMapper; + assert(publisher != nullptr); + m_publisher = publisher; + } + virtual ~ExtTablesManager() = default; - void enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) override; - void drain() override; - std::string verifyState( - const std::string& key, - const std::vector& tuple) override; - ReturnCode getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) override; + void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; + void drain() override; + std::string verifyState(const std::string &key, const std::vector &tuple) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; - // For every extension entry, update counters stats in COUNTERS_DB, if - // counters are enabled for those entries - void doExtCounterStatsTask(); + // For every extension entry, update counters stats in COUNTERS_DB, if + // counters are enabled for those entries + void doExtCounterStatsTask(); - private: - ReturnCodeOr deserializeP4ExtTableEntry( - const std::string& table_name, const std::string& key, - const std::vector& attributes); - ReturnCode validateActionParamsCrossRef(P4ExtTableAppDbEntry& app_db_entry, - ActionInfo* action); - ReturnCode validateP4ExtTableAppDbEntry(P4ExtTableAppDbEntry& app_db_entry); - P4ExtTableEntry* getP4ExtTableEntry(const std::string& table_name, - const std::string& table_key); - ReturnCode prepareP4SaiExtAPIParams(const P4ExtTableAppDbEntry& app_db_entry, - std::string& ext_table_entry_attr); - ReturnCode createP4ExtTableEntry(const P4ExtTableAppDbEntry& app_db_entry, - P4ExtTableEntry& ext_table_entry); - ReturnCode updateP4ExtTableEntry(const P4ExtTableAppDbEntry& app_db_entry, - P4ExtTableEntry* ext_table_entry); - ReturnCode removeP4ExtTableEntry(const std::string& table_name, - const std::string& table_key); - ReturnCode processAddRequest(const P4ExtTableAppDbEntry& app_db_entry); - ReturnCode processUpdateRequest(const P4ExtTableAppDbEntry& app_db_entry, - P4ExtTableEntry* ext_table_entry); - ReturnCode processDeleteRequest(const P4ExtTableAppDbEntry& app_db_entry); + private: + ReturnCodeOr deserializeP4ExtTableEntry(const std::string &table_name, const std::string &key, + const std::vector &attributes); + ReturnCode validateActionParamsCrossRef(P4ExtTableAppDbEntry &app_db_entry, ActionInfo *action); + ReturnCode validateP4ExtTableAppDbEntry(P4ExtTableAppDbEntry &app_db_entry); + P4ExtTableEntry *getP4ExtTableEntry(const std::string &table_name, const std::string &table_key); + ReturnCode prepareP4SaiExtAPIParams(const P4ExtTableAppDbEntry &app_db_entry, std::string &ext_table_entry_attr); + ReturnCode createP4ExtTableEntry(const P4ExtTableAppDbEntry &app_db_entry, P4ExtTableEntry &ext_table_entry); + ReturnCode updateP4ExtTableEntry(const P4ExtTableAppDbEntry &app_db_entry, P4ExtTableEntry *ext_table_entry); + ReturnCode removeP4ExtTableEntry(const std::string &table_name, const std::string &table_key); + ReturnCode processAddRequest(const P4ExtTableAppDbEntry &app_db_entry); + ReturnCode processUpdateRequest(const P4ExtTableAppDbEntry &app_db_entry, P4ExtTableEntry *ext_table_entry); + ReturnCode processDeleteRequest(const P4ExtTableAppDbEntry &app_db_entry); - ReturnCode setExtTableCounterStats(P4ExtTableEntry* ext_table_entry); + ReturnCode setExtTableCounterStats(P4ExtTableEntry *ext_table_entry); - P4ExtTableMap m_extTables; - P4OidMapper* m_p4OidMapper; - VRFOrch* m_vrfOrch; - ResponsePublisherInterface* m_publisher; - m_entriesTableMap m_entriesTables; + P4ExtTableMap m_extTables; + P4OidMapper *m_p4OidMapper; + VRFOrch *m_vrfOrch; + ResponsePublisherInterface *m_publisher; + m_entriesTableMap m_entriesTables; - std::unique_ptr m_countersDb; - std::unique_ptr m_countersTable; + std::unique_ptr m_countersDb; + std::unique_ptr m_countersTable; }; diff --git a/orchagent/p4orch/gre_tunnel_manager.cpp b/orchagent/p4orch/gre_tunnel_manager.cpp index 3a430692d9d..c3bfd7d6d7a 100644 --- a/orchagent/p4orch/gre_tunnel_manager.cpp +++ b/orchagent/p4orch/gre_tunnel_manager.cpp @@ -15,628 +15,621 @@ #include "sai_serialize.h" #include "swssnet.h" #include "table.h" -extern "C" { +extern "C" +{ #include "sai.h" } using ::p4orch::kTableKeyDelimiter; extern sai_object_id_t gSwitchId; -extern sai_tunnel_api_t* sai_tunnel_api; -extern sai_router_interface_api_t* sai_router_intfs_api; -extern CrmOrch* gCrmOrch; +extern sai_tunnel_api_t *sai_tunnel_api; +extern sai_router_interface_api_t *sai_router_intfs_api; +extern CrmOrch *gCrmOrch; extern sai_object_id_t gVirtualRouterId; -namespace { - -ReturnCode validateGreTunnelAppDbEntry( - const P4GreTunnelAppDbEntry& app_db_entry) { - if (app_db_entry.action_str != p4orch::kTunnelAction) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid action " << QuotedVar(app_db_entry.action_str) - << " of GRE Tunnel App DB entry"; - } - if (app_db_entry.router_interface_id.empty()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << QuotedVar(prependParamField(p4orch::kTunnelId)) - << " field is missing in table entry"; - } - if (app_db_entry.encap_src_ip.isZero()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << QuotedVar(prependParamField(p4orch::kEncapSrcIp)) - << " field is missing in table entry"; - } - if (app_db_entry.encap_dst_ip.isZero()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << QuotedVar(prependParamField(p4orch::kEncapDstIp)) - << " field is missing in table entry"; - } - return ReturnCode(); -} +namespace +{ -std::vector getSaiAttrs( - const P4GreTunnelEntry& gre_tunnel_entry) { - std::vector tunnel_attrs; - sai_attribute_t tunnel_attr; - tunnel_attr.id = SAI_TUNNEL_ATTR_TYPE; - tunnel_attr.value.s32 = SAI_TUNNEL_TYPE_IPINIP_GRE; - tunnel_attrs.push_back(tunnel_attr); - - tunnel_attr.id = SAI_TUNNEL_ATTR_PEER_MODE; - tunnel_attr.value.s32 = SAI_TUNNEL_PEER_MODE_P2P; - tunnel_attrs.push_back(tunnel_attr); - - tunnel_attr.id = SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE; - tunnel_attr.value.oid = gre_tunnel_entry.underlay_if_oid; - tunnel_attrs.push_back(tunnel_attr); - - tunnel_attr.id = SAI_TUNNEL_ATTR_OVERLAY_INTERFACE; - tunnel_attr.value.oid = gre_tunnel_entry.overlay_if_oid; - tunnel_attrs.push_back(tunnel_attr); - - tunnel_attr.id = SAI_TUNNEL_ATTR_ENCAP_SRC_IP; - swss::copy(tunnel_attr.value.ipaddr, gre_tunnel_entry.encap_src_ip); - tunnel_attrs.push_back(tunnel_attr); - - tunnel_attr.id = SAI_TUNNEL_ATTR_ENCAP_DST_IP; - swss::copy(tunnel_attr.value.ipaddr, gre_tunnel_entry.encap_dst_ip); - tunnel_attrs.push_back(tunnel_attr); - return tunnel_attrs; +ReturnCode validateGreTunnelAppDbEntry(const P4GreTunnelAppDbEntry &app_db_entry) +{ + if (app_db_entry.action_str != p4orch::kTunnelAction) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid action " << QuotedVar(app_db_entry.action_str) << " of GRE Tunnel App DB entry"; + } + if (app_db_entry.router_interface_id.empty()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << QuotedVar(prependParamField(p4orch::kTunnelId)) << " field is missing in table entry"; + } + if (app_db_entry.encap_src_ip.isZero()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << QuotedVar(prependParamField(p4orch::kEncapSrcIp)) << " field is missing in table entry"; + } + if (app_db_entry.encap_dst_ip.isZero()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << QuotedVar(prependParamField(p4orch::kEncapDstIp)) << " field is missing in table entry"; + } + return ReturnCode(); } -} // namespace - -P4GreTunnelEntry::P4GreTunnelEntry(const std::string& tunnel_id, - const std::string& router_interface_id, - const swss::IpAddress& encap_src_ip, - const swss::IpAddress& encap_dst_ip, - const swss::IpAddress& neighbor_id) - : tunnel_id(tunnel_id), - router_interface_id(router_interface_id), - encap_src_ip(encap_src_ip), - encap_dst_ip(encap_dst_ip), - neighbor_id(neighbor_id) { - SWSS_LOG_ENTER(); - tunnel_key = KeyGenerator::generateTunnelKey(tunnel_id); +std::vector getSaiAttrs(const P4GreTunnelEntry &gre_tunnel_entry) +{ + std::vector tunnel_attrs; + sai_attribute_t tunnel_attr; + tunnel_attr.id = SAI_TUNNEL_ATTR_TYPE; + tunnel_attr.value.s32 = SAI_TUNNEL_TYPE_IPINIP_GRE; + tunnel_attrs.push_back(tunnel_attr); + + tunnel_attr.id = SAI_TUNNEL_ATTR_PEER_MODE; + tunnel_attr.value.s32 = SAI_TUNNEL_PEER_MODE_P2P; + tunnel_attrs.push_back(tunnel_attr); + + tunnel_attr.id = SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE; + tunnel_attr.value.oid = gre_tunnel_entry.underlay_if_oid; + tunnel_attrs.push_back(tunnel_attr); + + tunnel_attr.id = SAI_TUNNEL_ATTR_OVERLAY_INTERFACE; + tunnel_attr.value.oid = gre_tunnel_entry.overlay_if_oid; + tunnel_attrs.push_back(tunnel_attr); + + tunnel_attr.id = SAI_TUNNEL_ATTR_ENCAP_SRC_IP; + swss::copy(tunnel_attr.value.ipaddr, gre_tunnel_entry.encap_src_ip); + tunnel_attrs.push_back(tunnel_attr); + + tunnel_attr.id = SAI_TUNNEL_ATTR_ENCAP_DST_IP; + swss::copy(tunnel_attr.value.ipaddr, gre_tunnel_entry.encap_dst_ip); + tunnel_attrs.push_back(tunnel_attr); + return tunnel_attrs; } -ReturnCode GreTunnelManager::getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) { - return StatusCode::SWSS_RC_UNIMPLEMENTED; -} +} // namespace -void GreTunnelManager::enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) { - m_entries.push_back(entry); +P4GreTunnelEntry::P4GreTunnelEntry(const std::string &tunnel_id, const std::string &router_interface_id, + const swss::IpAddress &encap_src_ip, const swss::IpAddress &encap_dst_ip, + const swss::IpAddress &neighbor_id) + : tunnel_id(tunnel_id), router_interface_id(router_interface_id), encap_src_ip(encap_src_ip), + encap_dst_ip(encap_dst_ip), neighbor_id(neighbor_id) +{ + SWSS_LOG_ENTER(); + tunnel_key = KeyGenerator::generateTunnelKey(tunnel_id); } -void GreTunnelManager::drain() { - SWSS_LOG_ENTER(); - - for (const auto& key_op_fvs_tuple : m_entries) { - std::string table_name; - std::string key; - parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &key); - const std::vector& attributes = - kfvFieldsValues(key_op_fvs_tuple); +ReturnCode GreTunnelManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) +{ + return StatusCode::SWSS_RC_UNIMPLEMENTED; +} - const std::string& operation = kfvOp(key_op_fvs_tuple); +void GreTunnelManager::enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) +{ + m_entries.push_back(entry); +} - ReturnCode status; - auto app_db_entry_or = deserializeP4GreTunnelAppDbEntry(key, attributes); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - SWSS_LOG_ERROR( - "Unable to deserialize GRE Tunnel APP DB entry with key %s: %s", - QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - auto& app_db_entry = *app_db_entry_or; - - const std::string tunnel_key = - KeyGenerator::generateTunnelKey(app_db_entry.tunnel_id); - - // Fulfill the operation. - if (operation == SET_COMMAND) { - status = validateGreTunnelAppDbEntry(app_db_entry); - if (!status.ok()) { - SWSS_LOG_ERROR( - "Validation failed for GRE Tunnel APP DB entry with key %s: %s", - QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, +void GreTunnelManager::drain() +{ + SWSS_LOG_ENTER(); + + for (const auto &key_op_fvs_tuple : m_entries) + { + std::string table_name; + std::string key; + parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &key); + const std::vector &attributes = kfvFieldsValues(key_op_fvs_tuple); + + const std::string &operation = kfvOp(key_op_fvs_tuple); + + ReturnCode status; + auto app_db_entry_or = deserializeP4GreTunnelAppDbEntry(key, attributes); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + SWSS_LOG_ERROR("Unable to deserialize GRE Tunnel APP DB entry with key %s: %s", + QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + auto &app_db_entry = *app_db_entry_or; + + const std::string tunnel_key = KeyGenerator::generateTunnelKey(app_db_entry.tunnel_id); + + // Fulfill the operation. + if (operation == SET_COMMAND) + { + status = validateGreTunnelAppDbEntry(app_db_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Validation failed for GRE Tunnel APP DB entry with key %s: %s", + QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + auto *gre_tunnel_entry = getGreTunnelEntry(tunnel_key); + if (gre_tunnel_entry == nullptr) + { + // Create new GRE tunnel. + status = processAddRequest(app_db_entry); + } + else + { + // Modify existing GRE tunnel. + status = processUpdateRequest(app_db_entry, gre_tunnel_entry); + } + } + else if (operation == DEL_COMMAND) + { + // Delete GRE tunnel. + status = processDeleteRequest(tunnel_key); + } + else + { + status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Unknown operation type " << QuotedVar(operation); + SWSS_LOG_ERROR("%s", status.message().c_str()); + } + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), status, /*replace=*/true); - continue; - } - auto* gre_tunnel_entry = getGreTunnelEntry(tunnel_key); - if (gre_tunnel_entry == nullptr) { - // Create new GRE tunnel. - status = processAddRequest(app_db_entry); - } else { - // Modify existing GRE tunnel. - status = processUpdateRequest(app_db_entry, gre_tunnel_entry); - } - } else if (operation == DEL_COMMAND) { - // Delete GRE tunnel. - status = processDeleteRequest(tunnel_key); - } else { - status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown operation type " << QuotedVar(operation); - SWSS_LOG_ERROR("%s", status.message().c_str()); - } - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - } - m_entries.clear(); + } + m_entries.clear(); } -P4GreTunnelEntry* GreTunnelManager::getGreTunnelEntry( - const std::string& tunnel_key) { - SWSS_LOG_ENTER(); +P4GreTunnelEntry *GreTunnelManager::getGreTunnelEntry(const std::string &tunnel_key) +{ + SWSS_LOG_ENTER(); - auto it = m_greTunnelTable.find(tunnel_key); + auto it = m_greTunnelTable.find(tunnel_key); - if (it == m_greTunnelTable.end()) { - return nullptr; - } else { - return &it->second; - } + if (it == m_greTunnelTable.end()) + { + return nullptr; + } + else + { + return &it->second; + } }; -ReturnCodeOr GreTunnelManager::getConstGreTunnelEntry( - const std::string& tunnel_key) { - SWSS_LOG_ENTER(); - - auto* tunnel = getGreTunnelEntry(tunnel_key); - if (tunnel == nullptr) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "GRE Tunnel with key " << QuotedVar(tunnel_key) - << " was not found."; - } else { - return *tunnel; - } -} +ReturnCodeOr GreTunnelManager::getConstGreTunnelEntry(const std::string &tunnel_key) +{ + SWSS_LOG_ENTER(); -ReturnCodeOr -GreTunnelManager::deserializeP4GreTunnelAppDbEntry( - const std::string& key, - const std::vector& attributes) { - SWSS_LOG_ENTER(); - - P4GreTunnelAppDbEntry app_db_entry = {}; - app_db_entry.encap_src_ip = swss::IpAddress("0.0.0.0"); - app_db_entry.encap_dst_ip = swss::IpAddress("0.0.0.0"); - - try { - nlohmann::json j = nlohmann::json::parse(key); - app_db_entry.tunnel_id = j[prependMatchField(p4orch::kTunnelId)]; - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to deserialize GRE tunnel id"; - } - - for (const auto& it : attributes) { - const auto& field = fvField(it); - const auto& value = fvValue(it); - if (field == prependParamField(p4orch::kRouterInterfaceId)) { - app_db_entry.router_interface_id = value; - } else if (field == prependParamField(p4orch::kEncapSrcIp)) { - try { - app_db_entry.encap_src_ip = swss::IpAddress(value); - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid IP address " << QuotedVar(value) << " of field " - << QuotedVar(field); - } - } else if (field == prependParamField(p4orch::kEncapDstIp)) { - try { - app_db_entry.encap_dst_ip = swss::IpAddress(value); - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid IP address " << QuotedVar(value) << " of field " - << QuotedVar(field); - } - } else if (field == p4orch::kAction) { - app_db_entry.action_str = value; - } else if (field != p4orch::kControllerMetadata) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unexpected field " << QuotedVar(field) << " in table entry"; - } - } - - return app_db_entry; + auto *tunnel = getGreTunnelEntry(tunnel_key); + if (tunnel == nullptr) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "GRE Tunnel with key " << QuotedVar(tunnel_key) << " was not found."; + } + else + { + return *tunnel; + } } -ReturnCode GreTunnelManager::processAddRequest( - const P4GreTunnelAppDbEntry& app_db_entry) { - SWSS_LOG_ENTER(); - - P4GreTunnelEntry gre_tunnel_entry( - app_db_entry.tunnel_id, app_db_entry.router_interface_id, - app_db_entry.encap_src_ip, app_db_entry.encap_dst_ip, - app_db_entry.encap_dst_ip); - auto status = createGreTunnel(gre_tunnel_entry); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to create GRE tunnel with key %s", - QuotedVar(gre_tunnel_entry.tunnel_key).c_str()); - } - return status; +ReturnCodeOr GreTunnelManager::deserializeP4GreTunnelAppDbEntry( + const std::string &key, const std::vector &attributes) +{ + SWSS_LOG_ENTER(); + + P4GreTunnelAppDbEntry app_db_entry = {}; + app_db_entry.encap_src_ip = swss::IpAddress("0.0.0.0"); + app_db_entry.encap_dst_ip = swss::IpAddress("0.0.0.0"); + + try + { + nlohmann::json j = nlohmann::json::parse(key); + app_db_entry.tunnel_id = j[prependMatchField(p4orch::kTunnelId)]; + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Failed to deserialize GRE tunnel id"; + } + + for (const auto &it : attributes) + { + const auto &field = fvField(it); + const auto &value = fvValue(it); + if (field == prependParamField(p4orch::kRouterInterfaceId)) + { + app_db_entry.router_interface_id = value; + } + else if (field == prependParamField(p4orch::kEncapSrcIp)) + { + try + { + app_db_entry.encap_src_ip = swss::IpAddress(value); + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid IP address " << QuotedVar(value) << " of field " << QuotedVar(field); + } + } + else if (field == prependParamField(p4orch::kEncapDstIp)) + { + try + { + app_db_entry.encap_dst_ip = swss::IpAddress(value); + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid IP address " << QuotedVar(value) << " of field " << QuotedVar(field); + } + } + else if (field == p4orch::kAction) + { + app_db_entry.action_str = value; + } + else if (field != p4orch::kControllerMetadata) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unexpected field " << QuotedVar(field) << " in table entry"; + } + } + + return app_db_entry; } -ReturnCode GreTunnelManager::createGreTunnel( - P4GreTunnelEntry& gre_tunnel_entry) { - SWSS_LOG_ENTER(); - - // Check the existence of the GRE tunnel in GRE tunnel manager and centralized - // mapper. - if (getGreTunnelEntry(gre_tunnel_entry.tunnel_key) != nullptr) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_EXISTS) - << "GRE tunnel with key " - << QuotedVar(gre_tunnel_entry.tunnel_key) - << " already exists in GRE tunnel manager"); - } - if (m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_TUNNEL, - gre_tunnel_entry.tunnel_key)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "GRE tunnel with key " << QuotedVar(gre_tunnel_entry.tunnel_key) - << " already exists in centralized mapper"); - } - - // From centralized mapper, get OID of router interface that GRE tunnel - // depends on. - const auto router_interface_key = KeyGenerator::generateRouterInterfaceKey( - gre_tunnel_entry.router_interface_id); - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - router_interface_key, - &gre_tunnel_entry.underlay_if_oid)) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Router intf " - << QuotedVar(gre_tunnel_entry.router_interface_id) - << " does not exist"); - } - - std::vector overlay_intf_attrs; - - sai_attribute_t overlay_intf_attr; - overlay_intf_attr.id = SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID; - overlay_intf_attr.value.oid = gVirtualRouterId; - overlay_intf_attrs.push_back(overlay_intf_attr); - - overlay_intf_attr.id = SAI_ROUTER_INTERFACE_ATTR_TYPE; - overlay_intf_attr.value.s32 = SAI_ROUTER_INTERFACE_TYPE_LOOPBACK; - overlay_intf_attrs.push_back(overlay_intf_attr); - - // Call SAI API. - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_router_intfs_api->create_router_interface( - &gre_tunnel_entry.overlay_if_oid, gSwitchId, - (uint32_t)overlay_intf_attrs.size(), overlay_intf_attrs.data()), - "Failed to create the Loopback router interface for GRE tunnel " - "SAI_TUNNEL_ATTR_OVERLAY_INTERFACE attribute" - << QuotedVar(gre_tunnel_entry.tunnel_key)); - - // Prepare attributes for the SAI creation call. - std::vector tunnel_attrs = getSaiAttrs(gre_tunnel_entry); - - // Call SAI API. - auto sai_status = sai_tunnel_api->create_tunnel( - &gre_tunnel_entry.tunnel_oid, gSwitchId, (uint32_t)tunnel_attrs.size(), - tunnel_attrs.data()); - if (sai_status != SAI_STATUS_SUCCESS) { - auto status = ReturnCode(sai_status) - << "Failed to create GRE tunnel " - << QuotedVar(gre_tunnel_entry.tunnel_key) << " on rif " - << QuotedVar(gre_tunnel_entry.router_interface_id); - SWSS_LOG_ERROR("%s", status.message().c_str()); - auto recovery_status = sai_router_intfs_api->remove_router_interface( - gre_tunnel_entry.overlay_if_oid); - if (recovery_status != SAI_STATUS_SUCCESS) { - auto rc = - ReturnCode(recovery_status) - << "Failed to recover overlay router interface due to SAI call " - "failure: Failed to remove loopback router interface " - << QuotedVar(sai_serialize_object_id(gre_tunnel_entry.overlay_if_oid)) - << " while clean up dependencies."; - SWSS_LOG_ERROR("%s", rc.message().c_str()); - SWSS_RAISE_CRITICAL_STATE(rc.message()); +ReturnCode GreTunnelManager::processAddRequest(const P4GreTunnelAppDbEntry &app_db_entry) +{ + SWSS_LOG_ENTER(); + + P4GreTunnelEntry gre_tunnel_entry(app_db_entry.tunnel_id, app_db_entry.router_interface_id, + app_db_entry.encap_src_ip, app_db_entry.encap_dst_ip, app_db_entry.encap_dst_ip); + auto status = createGreTunnel(gre_tunnel_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to create GRE tunnel with key %s", QuotedVar(gre_tunnel_entry.tunnel_key).c_str()); } return status; - } +} + +ReturnCode GreTunnelManager::createGreTunnel(P4GreTunnelEntry &gre_tunnel_entry) +{ + SWSS_LOG_ENTER(); + + // Check the existence of the GRE tunnel in GRE tunnel manager and centralized + // mapper. + if (getGreTunnelEntry(gre_tunnel_entry.tunnel_key) != nullptr) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_EXISTS) + << "GRE tunnel with key " << QuotedVar(gre_tunnel_entry.tunnel_key) + << " already exists in GRE tunnel manager"); + } + if (m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_entry.tunnel_key)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("GRE tunnel with key " << QuotedVar(gre_tunnel_entry.tunnel_key) + << " already exists in centralized mapper"); + } + + // From centralized mapper, get OID of router interface that GRE tunnel + // depends on. + const auto router_interface_key = KeyGenerator::generateRouterInterfaceKey(gre_tunnel_entry.router_interface_id); + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_interface_key, + &gre_tunnel_entry.underlay_if_oid)) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Router intf " << QuotedVar(gre_tunnel_entry.router_interface_id) << " does not exist"); + } + + std::vector overlay_intf_attrs; + + sai_attribute_t overlay_intf_attr; + overlay_intf_attr.id = SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID; + overlay_intf_attr.value.oid = gVirtualRouterId; + overlay_intf_attrs.push_back(overlay_intf_attr); + + overlay_intf_attr.id = SAI_ROUTER_INTERFACE_ATTR_TYPE; + overlay_intf_attr.value.s32 = SAI_ROUTER_INTERFACE_TYPE_LOOPBACK; + overlay_intf_attrs.push_back(overlay_intf_attr); + + // Call SAI API. + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_router_intfs_api->create_router_interface(&gre_tunnel_entry.overlay_if_oid, gSwitchId, + (uint32_t)overlay_intf_attrs.size(), overlay_intf_attrs.data()), + "Failed to create the Loopback router interface for GRE tunnel " + "SAI_TUNNEL_ATTR_OVERLAY_INTERFACE attribute" + << QuotedVar(gre_tunnel_entry.tunnel_key)); + + // Prepare attributes for the SAI creation call. + std::vector tunnel_attrs = getSaiAttrs(gre_tunnel_entry); + + // Call SAI API. + auto sai_status = sai_tunnel_api->create_tunnel(&gre_tunnel_entry.tunnel_oid, gSwitchId, + (uint32_t)tunnel_attrs.size(), tunnel_attrs.data()); + if (sai_status != SAI_STATUS_SUCCESS) + { + auto status = ReturnCode(sai_status) << "Failed to create GRE tunnel " << QuotedVar(gre_tunnel_entry.tunnel_key) + << " on rif " << QuotedVar(gre_tunnel_entry.router_interface_id); + SWSS_LOG_ERROR("%s", status.message().c_str()); + auto recovery_status = sai_router_intfs_api->remove_router_interface(gre_tunnel_entry.overlay_if_oid); + if (recovery_status != SAI_STATUS_SUCCESS) + { + auto rc = ReturnCode(recovery_status) << "Failed to recover overlay router interface due to SAI call " + "failure: Failed to remove loopback router interface " + << QuotedVar(sai_serialize_object_id(gre_tunnel_entry.overlay_if_oid)) + << " while clean up dependencies."; + SWSS_LOG_ERROR("%s", rc.message().c_str()); + SWSS_RAISE_CRITICAL_STATE(rc.message()); + } + return status; + } - // On successful creation, increment ref count. - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - router_interface_key); + // On successful creation, increment ref count. + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_interface_key); - // Add created entry to internal table. - m_greTunnelTable.emplace(gre_tunnel_entry.tunnel_key, gre_tunnel_entry); + // Add created entry to internal table. + m_greTunnelTable.emplace(gre_tunnel_entry.tunnel_key, gre_tunnel_entry); - // Add the key to OID map to centralized mapper. - m_p4OidMapper->setOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_entry.tunnel_key, - gre_tunnel_entry.tunnel_oid); + // Add the key to OID map to centralized mapper. + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_entry.tunnel_key, gre_tunnel_entry.tunnel_oid); - return ReturnCode(); + return ReturnCode(); } -ReturnCode GreTunnelManager::processUpdateRequest( - const P4GreTunnelAppDbEntry& app_db_entry, - P4GreTunnelEntry* gre_tunnel_entry) { - SWSS_LOG_ENTER(); - - ReturnCode status = - ReturnCode(StatusCode::SWSS_RC_UNIMPLEMENTED) - << "Currently GRE tunnel doesn't support update by SAI. GRE tunnel key " - << QuotedVar(gre_tunnel_entry->tunnel_key); - SWSS_LOG_ERROR("%s", status.message().c_str()); - return status; +ReturnCode GreTunnelManager::processUpdateRequest(const P4GreTunnelAppDbEntry &app_db_entry, + P4GreTunnelEntry *gre_tunnel_entry) +{ + SWSS_LOG_ENTER(); + + ReturnCode status = ReturnCode(StatusCode::SWSS_RC_UNIMPLEMENTED) + << "Currently GRE tunnel doesn't support update by SAI. GRE tunnel key " + << QuotedVar(gre_tunnel_entry->tunnel_key); + SWSS_LOG_ERROR("%s", status.message().c_str()); + return status; } -ReturnCode GreTunnelManager::processDeleteRequest( - const std::string& tunnel_key) { - SWSS_LOG_ENTER(); +ReturnCode GreTunnelManager::processDeleteRequest(const std::string &tunnel_key) +{ + SWSS_LOG_ENTER(); - auto status = removeGreTunnel(tunnel_key); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to remove GRE tunnel with key %s", - QuotedVar(tunnel_key).c_str()); - } + auto status = removeGreTunnel(tunnel_key); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to remove GRE tunnel with key %s", QuotedVar(tunnel_key).c_str()); + } - return status; + return status; } -ReturnCode GreTunnelManager::removeGreTunnel(const std::string& tunnel_key) { - SWSS_LOG_ENTER(); - - // Check the existence of the GRE tunnel in GRE tunnel manager and centralized - // mapper. - auto* gre_tunnel_entry = getGreTunnelEntry(tunnel_key); - if (gre_tunnel_entry == nullptr) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "GRE tunnel with key " << QuotedVar(tunnel_key) - << " does not exist in GRE tunnel manager"); - } - - // Check if there is anything referring to the GRE tunnel before deletion. - uint32_t ref_count; - if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_TUNNEL, tunnel_key, - &ref_count)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Failed to get reference count for GRE tunnel " - << QuotedVar(tunnel_key)); - } - if (ref_count > 0) { - LOG_ERROR_AND_RETURN( - ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "GRE tunnel " << QuotedVar(gre_tunnel_entry->tunnel_key) - << " referenced by other objects (ref_count = " << ref_count); - } - - // Call SAI API. - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_tunnel_api->remove_tunnel(gre_tunnel_entry->tunnel_oid), - "Failed to remove GRE tunnel " - << QuotedVar(gre_tunnel_entry->tunnel_key)); - - auto sai_status = sai_router_intfs_api->remove_router_interface( - gre_tunnel_entry->overlay_if_oid); - if (sai_status != SAI_STATUS_SUCCESS) { - auto status = - ReturnCode(sai_status) - << "Failed to remove loopback router interface " - << QuotedVar(sai_serialize_object_id(gre_tunnel_entry->overlay_if_oid)) - << " when removing GRE tunnel " - << QuotedVar(gre_tunnel_entry->tunnel_key); - SWSS_LOG_ERROR("%s", status.message().c_str()); +ReturnCode GreTunnelManager::removeGreTunnel(const std::string &tunnel_key) +{ + SWSS_LOG_ENTER(); + + // Check the existence of the GRE tunnel in GRE tunnel manager and centralized + // mapper. + auto *gre_tunnel_entry = getGreTunnelEntry(tunnel_key); + if (gre_tunnel_entry == nullptr) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "GRE tunnel with key " << QuotedVar(tunnel_key) + << " does not exist in GRE tunnel manager"); + } - // Try to recreate the GRE tunnel - std::vector tunnel_attrs = getSaiAttrs(*gre_tunnel_entry); + // Check if there is anything referring to the GRE tunnel before deletion. + uint32_t ref_count; + if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_TUNNEL, tunnel_key, &ref_count)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Failed to get reference count for GRE tunnel " + << QuotedVar(tunnel_key)); + } + if (ref_count > 0) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "GRE tunnel " << QuotedVar(gre_tunnel_entry->tunnel_key) + << " referenced by other objects (ref_count = " << ref_count); + } // Call SAI API. - auto recovery_status = sai_tunnel_api->create_tunnel( - &gre_tunnel_entry->tunnel_oid, gSwitchId, (uint32_t)tunnel_attrs.size(), - tunnel_attrs.data()); - if (recovery_status != SAI_STATUS_SUCCESS) { - auto rc = ReturnCode(recovery_status) - << "Failed to recover the GRE tunnel due to SAI call failure : " - "Failed to create GRE tunnel " - << QuotedVar(gre_tunnel_entry->tunnel_key) << " on rif " - << QuotedVar(gre_tunnel_entry->router_interface_id); - SWSS_LOG_ERROR("%s", rc.message().c_str()); - SWSS_RAISE_CRITICAL_STATE(rc.message()); + CHECK_ERROR_AND_LOG_AND_RETURN(sai_tunnel_api->remove_tunnel(gre_tunnel_entry->tunnel_oid), + "Failed to remove GRE tunnel " << QuotedVar(gre_tunnel_entry->tunnel_key)); + + auto sai_status = sai_router_intfs_api->remove_router_interface(gre_tunnel_entry->overlay_if_oid); + if (sai_status != SAI_STATUS_SUCCESS) + { + auto status = ReturnCode(sai_status) << "Failed to remove loopback router interface " + << QuotedVar(sai_serialize_object_id(gre_tunnel_entry->overlay_if_oid)) + << " when removing GRE tunnel " << QuotedVar(gre_tunnel_entry->tunnel_key); + SWSS_LOG_ERROR("%s", status.message().c_str()); + + // Try to recreate the GRE tunnel + std::vector tunnel_attrs = getSaiAttrs(*gre_tunnel_entry); + + // Call SAI API. + auto recovery_status = sai_tunnel_api->create_tunnel(&gre_tunnel_entry->tunnel_oid, gSwitchId, + (uint32_t)tunnel_attrs.size(), tunnel_attrs.data()); + if (recovery_status != SAI_STATUS_SUCCESS) + { + auto rc = ReturnCode(recovery_status) << "Failed to recover the GRE tunnel due to SAI call failure : " + "Failed to create GRE tunnel " + << QuotedVar(gre_tunnel_entry->tunnel_key) << " on rif " + << QuotedVar(gre_tunnel_entry->router_interface_id); + SWSS_LOG_ERROR("%s", rc.message().c_str()); + SWSS_RAISE_CRITICAL_STATE(rc.message()); + } + return status; } - return status; - } - // On successful deletion, decrement ref count. - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey( - gre_tunnel_entry->router_interface_id)); + // On successful deletion, decrement ref count. + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(gre_tunnel_entry->router_interface_id)); - // Remove the key to OID map to centralized mapper. - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_TUNNEL, tunnel_key); + // Remove the key to OID map to centralized mapper. + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_TUNNEL, tunnel_key); - // Remove the entry from internal table. - m_greTunnelTable.erase(tunnel_key); + // Remove the entry from internal table. + m_greTunnelTable.erase(tunnel_key); - return ReturnCode(); + return ReturnCode(); } -std::string GreTunnelManager::verifyState( - const std::string& key, const std::vector& tuple) { - SWSS_LOG_ENTER(); - - auto pos = key.find_first_of(kTableKeyDelimiter); - if (pos == std::string::npos) { - return std::string("Invalid key: ") + key; - } - std::string p4rt_table = key.substr(0, pos); - std::string p4rt_key = key.substr(pos + 1); - if (p4rt_table != APP_P4RT_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - std::string table_name; - std::string key_content; - parseP4RTKey(p4rt_key, &table_name, &key_content); - if (table_name != APP_P4RT_TUNNEL_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - - ReturnCode status; - auto app_db_entry_or = deserializeP4GreTunnelAppDbEntry(key_content, tuple); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - std::stringstream msg; - msg << "Unable to deserialize key " << QuotedVar(key) << ": " - << status.message(); - return msg.str(); - } - auto& app_db_entry = *app_db_entry_or; - const std::string tunnel_key = - KeyGenerator::generateTunnelKey(app_db_entry.tunnel_id); - auto* gre_tunnel_entry = getGreTunnelEntry(tunnel_key); - if (gre_tunnel_entry == nullptr) { - std::stringstream msg; - msg << "No entry found with key " << QuotedVar(key); - return msg.str(); - } - - std::string cache_result = verifyStateCache(app_db_entry, gre_tunnel_entry); - std::string asic_db_result = verifyStateAsicDb(gre_tunnel_entry); - if (cache_result.empty()) { - return asic_db_result; - } - if (asic_db_result.empty()) { - return cache_result; - } - return cache_result + "; " + asic_db_result; +std::string GreTunnelManager::verifyState(const std::string &key, const std::vector &tuple) +{ + SWSS_LOG_ENTER(); + + auto pos = key.find_first_of(kTableKeyDelimiter); + if (pos == std::string::npos) + { + return std::string("Invalid key: ") + key; + } + std::string p4rt_table = key.substr(0, pos); + std::string p4rt_key = key.substr(pos + 1); + if (p4rt_table != APP_P4RT_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } + std::string table_name; + std::string key_content; + parseP4RTKey(p4rt_key, &table_name, &key_content); + if (table_name != APP_P4RT_TUNNEL_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } + + ReturnCode status; + auto app_db_entry_or = deserializeP4GreTunnelAppDbEntry(key_content, tuple); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + std::stringstream msg; + msg << "Unable to deserialize key " << QuotedVar(key) << ": " << status.message(); + return msg.str(); + } + auto &app_db_entry = *app_db_entry_or; + const std::string tunnel_key = KeyGenerator::generateTunnelKey(app_db_entry.tunnel_id); + auto *gre_tunnel_entry = getGreTunnelEntry(tunnel_key); + if (gre_tunnel_entry == nullptr) + { + std::stringstream msg; + msg << "No entry found with key " << QuotedVar(key); + return msg.str(); + } + + std::string cache_result = verifyStateCache(app_db_entry, gre_tunnel_entry); + std::string asic_db_result = verifyStateAsicDb(gre_tunnel_entry); + if (cache_result.empty()) + { + return asic_db_result; + } + if (asic_db_result.empty()) + { + return cache_result; + } + return cache_result + "; " + asic_db_result; } -std::string GreTunnelManager::verifyStateCache( - const P4GreTunnelAppDbEntry& app_db_entry, - const P4GreTunnelEntry* gre_tunnel_entry) { - const std::string tunnel_key = - KeyGenerator::generateTunnelKey(app_db_entry.tunnel_id); - ReturnCode status = validateGreTunnelAppDbEntry(app_db_entry); - if (!status.ok()) { - std::stringstream msg; - msg << "Validation failed for GRE Tunnel DB entry with key " - << QuotedVar(tunnel_key) << ": " << status.message(); - return msg.str(); - } - - if (gre_tunnel_entry->tunnel_key != tunnel_key) { - std::stringstream msg; - msg << "GreTunnel with key " << QuotedVar(tunnel_key) - << " does not match internal cache " - << QuotedVar(gre_tunnel_entry->tunnel_key) << " in Gre Tunnel manager."; - return msg.str(); - } - if (gre_tunnel_entry->tunnel_id != app_db_entry.tunnel_id) { - std::stringstream msg; - msg << "GreTunnel " << QuotedVar(app_db_entry.tunnel_id) - << " does not match internal cache " - << QuotedVar(gre_tunnel_entry->tunnel_id) << " in GreTunnel manager."; - return msg.str(); - } - if (gre_tunnel_entry->router_interface_id != - app_db_entry.router_interface_id) { - std::stringstream msg; - msg << "GreTunnel " << QuotedVar(app_db_entry.tunnel_id) << " with ritf ID " - << QuotedVar(app_db_entry.router_interface_id) - << " does not match internal cache " - << QuotedVar(gre_tunnel_entry->router_interface_id) - << " in GreTunnel manager."; - return msg.str(); - } - if (gre_tunnel_entry->encap_src_ip.to_string() != - app_db_entry.encap_src_ip.to_string()) { - std::stringstream msg; - msg << "GreTunnel " << QuotedVar(app_db_entry.tunnel_id) - << " with source IP " - << QuotedVar(app_db_entry.encap_src_ip.to_string()) - << " does not match internal cache " - << QuotedVar(gre_tunnel_entry->encap_src_ip.to_string()) - << " in GreTunnel manager."; - return msg.str(); - } - - if (gre_tunnel_entry->encap_dst_ip.to_string() != - app_db_entry.encap_dst_ip.to_string()) { - std::stringstream msg; - msg << "GreTunnel " << QuotedVar(app_db_entry.tunnel_id) - << " with destination IP " - << QuotedVar(app_db_entry.encap_dst_ip.to_string()) - << " does not match internal cache " - << QuotedVar(gre_tunnel_entry->encap_dst_ip.to_string()) - << " in GreTunnel manager."; - return msg.str(); - } - - if (gre_tunnel_entry->neighbor_id.to_string() != - app_db_entry.encap_dst_ip.to_string()) { - std::stringstream msg; - msg << "GreTunnel " << QuotedVar(app_db_entry.tunnel_id) - << " with destination IP " - << QuotedVar(app_db_entry.encap_dst_ip.to_string()) - << " does not match internal cache " - << QuotedVar(gre_tunnel_entry->neighbor_id.to_string()) - << " fo neighbor_id in GreTunnel manager."; - return msg.str(); - } - - return m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_TUNNEL, - gre_tunnel_entry->tunnel_key, - gre_tunnel_entry->tunnel_oid); +std::string GreTunnelManager::verifyStateCache(const P4GreTunnelAppDbEntry &app_db_entry, + const P4GreTunnelEntry *gre_tunnel_entry) +{ + const std::string tunnel_key = KeyGenerator::generateTunnelKey(app_db_entry.tunnel_id); + ReturnCode status = validateGreTunnelAppDbEntry(app_db_entry); + if (!status.ok()) + { + std::stringstream msg; + msg << "Validation failed for GRE Tunnel DB entry with key " << QuotedVar(tunnel_key) << ": " + << status.message(); + return msg.str(); + } + + if (gre_tunnel_entry->tunnel_key != tunnel_key) + { + std::stringstream msg; + msg << "GreTunnel with key " << QuotedVar(tunnel_key) << " does not match internal cache " + << QuotedVar(gre_tunnel_entry->tunnel_key) << " in Gre Tunnel manager."; + return msg.str(); + } + if (gre_tunnel_entry->tunnel_id != app_db_entry.tunnel_id) + { + std::stringstream msg; + msg << "GreTunnel " << QuotedVar(app_db_entry.tunnel_id) << " does not match internal cache " + << QuotedVar(gre_tunnel_entry->tunnel_id) << " in GreTunnel manager."; + return msg.str(); + } + if (gre_tunnel_entry->router_interface_id != app_db_entry.router_interface_id) + { + std::stringstream msg; + msg << "GreTunnel " << QuotedVar(app_db_entry.tunnel_id) << " with ritf ID " + << QuotedVar(app_db_entry.router_interface_id) << " does not match internal cache " + << QuotedVar(gre_tunnel_entry->router_interface_id) << " in GreTunnel manager."; + return msg.str(); + } + if (gre_tunnel_entry->encap_src_ip.to_string() != app_db_entry.encap_src_ip.to_string()) + { + std::stringstream msg; + msg << "GreTunnel " << QuotedVar(app_db_entry.tunnel_id) << " with source IP " + << QuotedVar(app_db_entry.encap_src_ip.to_string()) << " does not match internal cache " + << QuotedVar(gre_tunnel_entry->encap_src_ip.to_string()) << " in GreTunnel manager."; + return msg.str(); + } + + if (gre_tunnel_entry->encap_dst_ip.to_string() != app_db_entry.encap_dst_ip.to_string()) + { + std::stringstream msg; + msg << "GreTunnel " << QuotedVar(app_db_entry.tunnel_id) << " with destination IP " + << QuotedVar(app_db_entry.encap_dst_ip.to_string()) << " does not match internal cache " + << QuotedVar(gre_tunnel_entry->encap_dst_ip.to_string()) << " in GreTunnel manager."; + return msg.str(); + } + + if (gre_tunnel_entry->neighbor_id.to_string() != app_db_entry.encap_dst_ip.to_string()) + { + std::stringstream msg; + msg << "GreTunnel " << QuotedVar(app_db_entry.tunnel_id) << " with destination IP " + << QuotedVar(app_db_entry.encap_dst_ip.to_string()) << " does not match internal cache " + << QuotedVar(gre_tunnel_entry->neighbor_id.to_string()) << " fo neighbor_id in GreTunnel manager."; + return msg.str(); + } + + return m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_entry->tunnel_key, + gre_tunnel_entry->tunnel_oid); } -std::string GreTunnelManager::verifyStateAsicDb( - const P4GreTunnelEntry* gre_tunnel_entry) { - swss::DBConnector db("ASIC_DB", 0); - swss::Table table(&db, "ASIC_STATE"); - - // Verify Overlay router interface ASIC DB attributes - std::string key = - sai_serialize_object_type(SAI_OBJECT_TYPE_ROUTER_INTERFACE) + ":" + - sai_serialize_object_id(gre_tunnel_entry->overlay_if_oid); - std::vector values; - if (!table.get(key, values)) { - return std::string("ASIC DB key not found ") + key; - } - - std::vector overlay_intf_attrs; - sai_attribute_t overlay_intf_attr; - overlay_intf_attr.id = SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID; - overlay_intf_attr.value.oid = gVirtualRouterId; - overlay_intf_attrs.push_back(overlay_intf_attr); - overlay_intf_attr.id = SAI_ROUTER_INTERFACE_ATTR_TYPE; - overlay_intf_attr.value.s32 = SAI_ROUTER_INTERFACE_TYPE_LOOPBACK; - overlay_intf_attrs.push_back(overlay_intf_attr); - std::vector exp = - saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, (uint32_t)overlay_intf_attrs.size(), - overlay_intf_attrs.data(), - /*countOnly=*/false); - verifyAttrs(values, exp, std::vector{}, - /*allow_unknown=*/false); - - // Verify Tunnel ASIC DB attributes - std::vector attrs = getSaiAttrs(*gre_tunnel_entry); - exp = saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_TUNNEL, (uint32_t)attrs.size(), attrs.data(), - /*countOnly=*/false); - key = sai_serialize_object_type(SAI_OBJECT_TYPE_TUNNEL) + ":" + - sai_serialize_object_id(gre_tunnel_entry->tunnel_oid); - values.clear(); - if (!table.get(key, values)) { - return std::string("ASIC DB key not found ") + key; - } - - return verifyAttrs(values, exp, std::vector{}, - /*allow_unknown=*/false); +std::string GreTunnelManager::verifyStateAsicDb(const P4GreTunnelEntry *gre_tunnel_entry) +{ + swss::DBConnector db("ASIC_DB", 0); + swss::Table table(&db, "ASIC_STATE"); + + // Verify Overlay router interface ASIC DB attributes + std::string key = sai_serialize_object_type(SAI_OBJECT_TYPE_ROUTER_INTERFACE) + ":" + + sai_serialize_object_id(gre_tunnel_entry->overlay_if_oid); + std::vector values; + if (!table.get(key, values)) + { + return std::string("ASIC DB key not found ") + key; + } + + std::vector overlay_intf_attrs; + sai_attribute_t overlay_intf_attr; + overlay_intf_attr.id = SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID; + overlay_intf_attr.value.oid = gVirtualRouterId; + overlay_intf_attrs.push_back(overlay_intf_attr); + overlay_intf_attr.id = SAI_ROUTER_INTERFACE_ATTR_TYPE; + overlay_intf_attr.value.s32 = SAI_ROUTER_INTERFACE_TYPE_LOOPBACK; + overlay_intf_attrs.push_back(overlay_intf_attr); + std::vector exp = saimeta::SaiAttributeList::serialize_attr_list( + SAI_OBJECT_TYPE_ROUTER_INTERFACE, (uint32_t)overlay_intf_attrs.size(), overlay_intf_attrs.data(), + /*countOnly=*/false); + verifyAttrs(values, exp, std::vector{}, + /*allow_unknown=*/false); + + // Verify Tunnel ASIC DB attributes + std::vector attrs = getSaiAttrs(*gre_tunnel_entry); + exp = saimeta::SaiAttributeList::serialize_attr_list(SAI_OBJECT_TYPE_TUNNEL, (uint32_t)attrs.size(), attrs.data(), + /*countOnly=*/false); + key = + sai_serialize_object_type(SAI_OBJECT_TYPE_TUNNEL) + ":" + sai_serialize_object_id(gre_tunnel_entry->tunnel_oid); + values.clear(); + if (!table.get(key, values)) + { + return std::string("ASIC DB key not found ") + key; + } + + return verifyAttrs(values, exp, std::vector{}, + /*allow_unknown=*/false); } diff --git a/orchagent/p4orch/gre_tunnel_manager.h b/orchagent/p4orch/gre_tunnel_manager.h index c12eb50e5ae..2eee9b18c4f 100644 --- a/orchagent/p4orch/gre_tunnel_manager.h +++ b/orchagent/p4orch/gre_tunnel_manager.h @@ -12,7 +12,8 @@ #include "p4orch/router_interface_manager.h" #include "response_publisher_interface.h" #include "return_code.h" -extern "C" { +extern "C" +{ #include "sai.h" } @@ -23,102 +24,94 @@ extern "C" { // "param/encap_src_ip" = "2607:f8b0:8096:3110::1", // "param/encap_dst_ip" = "2607:f8b0:8096:311a::2", // "controller_metadata" = "..." -struct P4GreTunnelEntry { - // Key of this entry, built from tunnel_id. - std::string tunnel_key; - - // Fields from P4 table. - // Match - std::string tunnel_id; - // Action - std::string router_interface_id; - swss::IpAddress encap_src_ip; - swss::IpAddress encap_dst_ip; - // neighbor_id is required to be equal to encap_dst_ip by BRCM. And the - // neighbor entry needs to be created before GRE tunnel object - swss::IpAddress neighbor_id; - - // SAI OID associated with this entry. - sai_object_id_t tunnel_oid = SAI_NULL_OBJECT_ID; - // SAI OID of a loopback rif for SAI_TUNNEL_ATTR_OVERLAY_INTERFACE - sai_object_id_t overlay_if_oid = SAI_NULL_OBJECT_ID; - // SAI OID of the router_interface_id for SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE - sai_object_id_t underlay_if_oid = SAI_NULL_OBJECT_ID; - - P4GreTunnelEntry(const std::string& tunnel_id, - const std::string& router_interface_id, - const swss::IpAddress& encap_src_ip, - const swss::IpAddress& encap_dst_ip, - const swss::IpAddress& neighbor_id); +struct P4GreTunnelEntry +{ + // Key of this entry, built from tunnel_id. + std::string tunnel_key; + + // Fields from P4 table. + // Match + std::string tunnel_id; + // Action + std::string router_interface_id; + swss::IpAddress encap_src_ip; + swss::IpAddress encap_dst_ip; + // neighbor_id is required to be equal to encap_dst_ip by BRCM. And the + // neighbor entry needs to be created before GRE tunnel object + swss::IpAddress neighbor_id; + + // SAI OID associated with this entry. + sai_object_id_t tunnel_oid = SAI_NULL_OBJECT_ID; + // SAI OID of a loopback rif for SAI_TUNNEL_ATTR_OVERLAY_INTERFACE + sai_object_id_t overlay_if_oid = SAI_NULL_OBJECT_ID; + // SAI OID of the router_interface_id for SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE + sai_object_id_t underlay_if_oid = SAI_NULL_OBJECT_ID; + + P4GreTunnelEntry(const std::string &tunnel_id, const std::string &router_interface_id, + const swss::IpAddress &encap_src_ip, const swss::IpAddress &encap_dst_ip, + const swss::IpAddress &neighbor_id); }; // GreTunnelManager listens to changes in table APP_P4RT_TUNNEL_TABLE_NAME and // creates/updates/deletes tunnel SAI object accordingly. -class GreTunnelManager : public ObjectManagerInterface { - public: - GreTunnelManager(P4OidMapper* p4oidMapper, - ResponsePublisherInterface* publisher) { - SWSS_LOG_ENTER(); - - assert(p4oidMapper != nullptr); - m_p4OidMapper = p4oidMapper; - assert(publisher != nullptr); - m_publisher = publisher; - } - - virtual ~GreTunnelManager() = default; - - void enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) override; - void drain() override; - std::string verifyState( - const std::string& key, - const std::vector& tuple) override; - ReturnCode getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) override; - - ReturnCodeOr getConstGreTunnelEntry( - const std::string& gre_tunnel_key); - - private: - // Gets the internal cached GRE tunnel entry by its key. - // Return nullptr if corresponding GRE tunnel entry is not cached. - P4GreTunnelEntry* getGreTunnelEntry(const std::string& gre_tunnel_key); - - // Deserializes an entry from table APP_P4RT_TUNNEL_TABLE_NAME. - ReturnCodeOr deserializeP4GreTunnelAppDbEntry( - const std::string& key, - const std::vector& attributes); - - // Processes add operation for an entry. - ReturnCode processAddRequest(const P4GreTunnelAppDbEntry& app_db_entry); - - // Creates an GRE tunnel in the GRE tunnel table. Return true on success. - ReturnCode createGreTunnel(P4GreTunnelEntry& gre_tunnel_entry); - - // Processes update operation for an entry. - ReturnCode processUpdateRequest(const P4GreTunnelAppDbEntry& app_db_entry, - P4GreTunnelEntry* gre_tunnel_entry); - - // Processes delete operation for an entry. - ReturnCode processDeleteRequest(const std::string& gre_tunnel_key); - - // Deletes a GRE tunnel in the GRE tunnel table. Return true on success. - ReturnCode removeGreTunnel(const std::string& gre_tunnel_key); - - std::string verifyStateCache(const P4GreTunnelAppDbEntry& app_db_entry, - const P4GreTunnelEntry* gre_tunnel_entry); - std::string verifyStateAsicDb(const P4GreTunnelEntry* gre_tunnel_entry); - - // m_greTunnelTable: gre_tunnel_key, P4GreTunnelEntry - std::unordered_map m_greTunnelTable; - - // Owners of pointers below must outlive this class's instance. - P4OidMapper* m_p4OidMapper; - ResponsePublisherInterface* m_publisher; - std::deque m_entries; - - friend class GreTunnelManagerTest; - friend class NextHopManagerTest; +class GreTunnelManager : public ObjectManagerInterface +{ + public: + GreTunnelManager(P4OidMapper *p4oidMapper, ResponsePublisherInterface *publisher) + { + SWSS_LOG_ENTER(); + + assert(p4oidMapper != nullptr); + m_p4OidMapper = p4oidMapper; + assert(publisher != nullptr); + m_publisher = publisher; + } + + virtual ~GreTunnelManager() = default; + + void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; + void drain() override; + std::string verifyState(const std::string &key, const std::vector &tuple) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; + + ReturnCodeOr getConstGreTunnelEntry(const std::string &gre_tunnel_key); + + private: + // Gets the internal cached GRE tunnel entry by its key. + // Return nullptr if corresponding GRE tunnel entry is not cached. + P4GreTunnelEntry *getGreTunnelEntry(const std::string &gre_tunnel_key); + + // Deserializes an entry from table APP_P4RT_TUNNEL_TABLE_NAME. + ReturnCodeOr deserializeP4GreTunnelAppDbEntry( + const std::string &key, const std::vector &attributes); + + // Processes add operation for an entry. + ReturnCode processAddRequest(const P4GreTunnelAppDbEntry &app_db_entry); + + // Creates an GRE tunnel in the GRE tunnel table. Return true on success. + ReturnCode createGreTunnel(P4GreTunnelEntry &gre_tunnel_entry); + + // Processes update operation for an entry. + ReturnCode processUpdateRequest(const P4GreTunnelAppDbEntry &app_db_entry, P4GreTunnelEntry *gre_tunnel_entry); + + // Processes delete operation for an entry. + ReturnCode processDeleteRequest(const std::string &gre_tunnel_key); + + // Deletes a GRE tunnel in the GRE tunnel table. Return true on success. + ReturnCode removeGreTunnel(const std::string &gre_tunnel_key); + + std::string verifyStateCache(const P4GreTunnelAppDbEntry &app_db_entry, const P4GreTunnelEntry *gre_tunnel_entry); + std::string verifyStateAsicDb(const P4GreTunnelEntry *gre_tunnel_entry); + + // m_greTunnelTable: gre_tunnel_key, P4GreTunnelEntry + std::unordered_map m_greTunnelTable; + + // Owners of pointers below must outlive this class's instance. + P4OidMapper *m_p4OidMapper; + ResponsePublisherInterface *m_publisher; + std::deque m_entries; + + friend class GreTunnelManagerTest; + friend class NextHopManagerTest; }; diff --git a/orchagent/p4orch/l3_admit_manager.cpp b/orchagent/p4orch/l3_admit_manager.cpp index 6fe7abef7c9..da5b955dbaf 100644 --- a/orchagent/p4orch/l3_admit_manager.cpp +++ b/orchagent/p4orch/l3_admit_manager.cpp @@ -15,437 +15,452 @@ #include "sai_serialize.h" #include "table.h" #include "tokenize.h" -extern "C" { +extern "C" +{ #include "sai.h" } using ::p4orch::kTableKeyDelimiter; -extern PortsOrch* gPortsOrch; +extern PortsOrch *gPortsOrch; extern sai_object_id_t gSwitchId; -extern sai_my_mac_api_t* sai_my_mac_api; - -namespace { - -ReturnCodeOr> getSaiAttrs( - const P4L3AdmitEntry& l3_admit_entry) { - std::vector l3_admit_attrs; - sai_attribute_t l3_admit_attr; - - l3_admit_attr.id = SAI_MY_MAC_ATTR_MAC_ADDRESS; - memcpy(l3_admit_attr.value.mac, l3_admit_entry.mac_address_data.getMac(), - sizeof(sai_mac_t)); - l3_admit_attrs.push_back(l3_admit_attr); - - l3_admit_attr.id = SAI_MY_MAC_ATTR_MAC_ADDRESS_MASK; - memcpy(l3_admit_attr.value.mac, l3_admit_entry.mac_address_mask.getMac(), - sizeof(sai_mac_t)); - l3_admit_attrs.push_back(l3_admit_attr); - - l3_admit_attr.id = SAI_MY_MAC_ATTR_PRIORITY; - l3_admit_attr.value.u32 = l3_admit_entry.priority; - l3_admit_attrs.push_back(l3_admit_attr); - - if (!l3_admit_entry.port_name.empty()) { - Port port; - if (!gPortsOrch->getPort(l3_admit_entry.port_name, port)) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Failed to get port info for port " - << QuotedVar(l3_admit_entry.port_name)); - } - l3_admit_attr.id = SAI_MY_MAC_ATTR_PORT_ID; - l3_admit_attr.value.oid = port.m_port_id; +extern sai_my_mac_api_t *sai_my_mac_api; + +namespace +{ + +ReturnCodeOr> getSaiAttrs(const P4L3AdmitEntry &l3_admit_entry) +{ + std::vector l3_admit_attrs; + sai_attribute_t l3_admit_attr; + + l3_admit_attr.id = SAI_MY_MAC_ATTR_MAC_ADDRESS; + memcpy(l3_admit_attr.value.mac, l3_admit_entry.mac_address_data.getMac(), sizeof(sai_mac_t)); l3_admit_attrs.push_back(l3_admit_attr); - } - return l3_admit_attrs; -} + l3_admit_attr.id = SAI_MY_MAC_ATTR_MAC_ADDRESS_MASK; + memcpy(l3_admit_attr.value.mac, l3_admit_entry.mac_address_mask.getMac(), sizeof(sai_mac_t)); + l3_admit_attrs.push_back(l3_admit_attr); -} // namespace + l3_admit_attr.id = SAI_MY_MAC_ATTR_PRIORITY; + l3_admit_attr.value.u32 = l3_admit_entry.priority; + l3_admit_attrs.push_back(l3_admit_attr); -ReturnCode L3AdmitManager::getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) { - return StatusCode::SWSS_RC_UNIMPLEMENTED; -} + if (!l3_admit_entry.port_name.empty()) + { + Port port; + if (!gPortsOrch->getPort(l3_admit_entry.port_name, port)) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Failed to get port info for port " << QuotedVar(l3_admit_entry.port_name)); + } + l3_admit_attr.id = SAI_MY_MAC_ATTR_PORT_ID; + l3_admit_attr.value.oid = port.m_port_id; + l3_admit_attrs.push_back(l3_admit_attr); + } -void L3AdmitManager::enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) { - m_entries.push_back(entry); + return l3_admit_attrs; } -void L3AdmitManager::drain() { - SWSS_LOG_ENTER(); +} // namespace - for (const auto& key_op_fvs_tuple : m_entries) { - std::string table_name; - std::string key; - parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &key); - const std::vector& attributes = - kfvFieldsValues(key_op_fvs_tuple); +ReturnCode L3AdmitManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) +{ + return StatusCode::SWSS_RC_UNIMPLEMENTED; +} - ReturnCode status; - auto app_db_entry_or = deserializeP4L3AdmitAppDbEntry(key, attributes); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", - QuotedVar(table_name + ":" + key).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - auto& app_db_entry = *app_db_entry_or; +void L3AdmitManager::enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) +{ + m_entries.push_back(entry); +} - const std::string l3_admit_key = KeyGenerator::generateL3AdmitKey( - app_db_entry.mac_address_data, app_db_entry.mac_address_mask, - app_db_entry.port_name, app_db_entry.priority); - - // Fulfill the operation. - const std::string& operation = kfvOp(key_op_fvs_tuple); - if (operation == SET_COMMAND) { - auto* l3_admit_entry = getL3AdmitEntry(l3_admit_key); - if (l3_admit_entry == nullptr) { - // Create new l3 admit. - status = processAddRequest(app_db_entry, l3_admit_key); - } else { - // Duplicate l3 admit entry, no-op - status = ReturnCode(StatusCode::SWSS_RC_SUCCESS) - << "L3 Admit entry with the same key received: " - << QuotedVar(l3_admit_key); - } - } else if (operation == DEL_COMMAND) { - // Delete l3 admit. - status = processDeleteRequest(l3_admit_key); - } else { - status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown operation type " << QuotedVar(operation); - SWSS_LOG_ERROR("%s", status.message().c_str()); +void L3AdmitManager::drain() +{ + SWSS_LOG_ENTER(); + + for (const auto &key_op_fvs_tuple : m_entries) + { + std::string table_name; + std::string key; + parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &key); + const std::vector &attributes = kfvFieldsValues(key_op_fvs_tuple); + + ReturnCode status; + auto app_db_entry_or = deserializeP4L3AdmitAppDbEntry(key, attributes); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", + QuotedVar(table_name + ":" + key).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + auto &app_db_entry = *app_db_entry_or; + + const std::string l3_admit_key = + KeyGenerator::generateL3AdmitKey(app_db_entry.mac_address_data, app_db_entry.mac_address_mask, + app_db_entry.port_name, app_db_entry.priority); + + // Fulfill the operation. + const std::string &operation = kfvOp(key_op_fvs_tuple); + if (operation == SET_COMMAND) + { + auto *l3_admit_entry = getL3AdmitEntry(l3_admit_key); + if (l3_admit_entry == nullptr) + { + // Create new l3 admit. + status = processAddRequest(app_db_entry, l3_admit_key); + } + else + { + // Duplicate l3 admit entry, no-op + status = ReturnCode(StatusCode::SWSS_RC_SUCCESS) + << "L3 Admit entry with the same key received: " << QuotedVar(l3_admit_key); + } + } + else if (operation == DEL_COMMAND) + { + // Delete l3 admit. + status = processDeleteRequest(l3_admit_key); + } + else + { + status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Unknown operation type " << QuotedVar(operation); + SWSS_LOG_ERROR("%s", status.message().c_str()); + } + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), status, + /*replace=*/true); } - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - } - m_entries.clear(); + m_entries.clear(); } -P4L3AdmitEntry* L3AdmitManager::getL3AdmitEntry( - const std::string& l3_admit_key) { - SWSS_LOG_ENTER(); +P4L3AdmitEntry *L3AdmitManager::getL3AdmitEntry(const std::string &l3_admit_key) +{ + SWSS_LOG_ENTER(); - auto it = m_l3AdmitTable.find(l3_admit_key); + auto it = m_l3AdmitTable.find(l3_admit_key); - if (it == m_l3AdmitTable.end()) { - return nullptr; - } else { - return &it->second; - } + if (it == m_l3AdmitTable.end()) + { + return nullptr; + } + else + { + return &it->second; + } } -ReturnCodeOr -L3AdmitManager::deserializeP4L3AdmitAppDbEntry( - const std::string& key, - const std::vector& attributes) { - SWSS_LOG_ENTER(); - - P4L3AdmitAppDbEntry app_db_entry = {}; - - try { - nlohmann::json j = nlohmann::json::parse(key); - // "match/dst_mac":"00:02:03:04:00:00&ff:ff:ff:ff:00:00" - if (j.find(prependMatchField(p4orch::kDstMac)) != j.end()) { - std::string dst_mac_data_and_mask = j[prependMatchField(p4orch::kDstMac)]; - const auto& data_and_mask = - swss::tokenize(dst_mac_data_and_mask, p4orch::kDataMaskDelimiter); - app_db_entry.mac_address_data = swss::MacAddress(trim(data_and_mask[0])); - if (data_and_mask.size() > 1) { - app_db_entry.mac_address_mask = - swss::MacAddress(trim(data_and_mask[1])); - } else { - app_db_entry.mac_address_mask = swss::MacAddress("ff:ff:ff:ff:ff:ff"); - } - } else { - // P4RT set "don't care" value for dst_mac - mask should be all 0 - app_db_entry.mac_address_data = swss::MacAddress("00:00:00:00:00:00"); - app_db_entry.mac_address_mask = swss::MacAddress("00:00:00:00:00:00"); +ReturnCodeOr L3AdmitManager::deserializeP4L3AdmitAppDbEntry( + const std::string &key, const std::vector &attributes) +{ + SWSS_LOG_ENTER(); + + P4L3AdmitAppDbEntry app_db_entry = {}; + + try + { + nlohmann::json j = nlohmann::json::parse(key); + // "match/dst_mac":"00:02:03:04:00:00&ff:ff:ff:ff:00:00" + if (j.find(prependMatchField(p4orch::kDstMac)) != j.end()) + { + std::string dst_mac_data_and_mask = j[prependMatchField(p4orch::kDstMac)]; + const auto &data_and_mask = swss::tokenize(dst_mac_data_and_mask, p4orch::kDataMaskDelimiter); + app_db_entry.mac_address_data = swss::MacAddress(trim(data_and_mask[0])); + if (data_and_mask.size() > 1) + { + app_db_entry.mac_address_mask = swss::MacAddress(trim(data_and_mask[1])); + } + else + { + app_db_entry.mac_address_mask = swss::MacAddress("ff:ff:ff:ff:ff:ff"); + } + } + else + { + // P4RT set "don't care" value for dst_mac - mask should be all 0 + app_db_entry.mac_address_data = swss::MacAddress("00:00:00:00:00:00"); + app_db_entry.mac_address_mask = swss::MacAddress("00:00:00:00:00:00"); + } + + // "priority":2030 + auto priority_j = j[p4orch::kPriority]; + if (!priority_j.is_number_unsigned()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid l3 admit entry priority type: should be uint32_t"; + } + app_db_entry.priority = static_cast(priority_j); + + // "match/in_port":"Ethernet0" + if (j.find(prependMatchField(p4orch::kInPort)) != j.end()) + { + app_db_entry.port_name = j[prependMatchField(p4orch::kInPort)]; + } } - - // "priority":2030 - auto priority_j = j[p4orch::kPriority]; - if (!priority_j.is_number_unsigned()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid l3 admit entry priority type: should be uint32_t"; + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Failed to deserialize l3 admit key"; } - app_db_entry.priority = static_cast(priority_j); - // "match/in_port":"Ethernet0" - if (j.find(prependMatchField(p4orch::kInPort)) != j.end()) { - app_db_entry.port_name = j[prependMatchField(p4orch::kInPort)]; + for (const auto &it : attributes) + { + const auto &field = fvField(it); + const auto &value = fvValue(it); + // "action": "admit_to_l3" + if (field == p4orch::kAction) + { + if (value != p4orch::kL3AdmitAction) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unexpected action " << QuotedVar(value) << " in L3 Admit table entry"; + } + } + else if (field != p4orch::kControllerMetadata) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unexpected field " << QuotedVar(field) << " in L3 Admit table entry"; + } } - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to deserialize l3 admit key"; - } - - for (const auto& it : attributes) { - const auto& field = fvField(it); - const auto& value = fvValue(it); - // "action": "admit_to_l3" - if (field == p4orch::kAction) { - if (value != p4orch::kL3AdmitAction) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unexpected action " << QuotedVar(value) - << " in L3 Admit table entry"; - } - } else if (field != p4orch::kControllerMetadata) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unexpected field " << QuotedVar(field) - << " in L3 Admit table entry"; - } - } - return app_db_entry; + return app_db_entry; } -ReturnCode L3AdmitManager::processAddRequest( - const P4L3AdmitAppDbEntry& app_db_entry, const std::string& l3_admit_key) { - SWSS_LOG_ENTER(); - - // Check the existence of the l3 admit in l3 admit manager and centralized - // mapper. - if (getL3AdmitEntry(l3_admit_key) != nullptr) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_EXISTS) - << "l3 admit with key " << QuotedVar(l3_admit_key) - << " already exists in l3 admit manager"); - } - if (m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_MY_MAC, l3_admit_key)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "l3 admit with key " << QuotedVar(l3_admit_key) - << " already exists in centralized mapper"); - } - // Create L3 admit entry - P4L3AdmitEntry l3_admit_entry(app_db_entry.mac_address_data, - app_db_entry.mac_address_mask, - app_db_entry.priority, app_db_entry.port_name); - auto status = createL3Admit(l3_admit_entry); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to create l3 admit with key %s", - QuotedVar(l3_admit_key).c_str()); +ReturnCode L3AdmitManager::processAddRequest(const P4L3AdmitAppDbEntry &app_db_entry, const std::string &l3_admit_key) +{ + SWSS_LOG_ENTER(); + + // Check the existence of the l3 admit in l3 admit manager and centralized + // mapper. + if (getL3AdmitEntry(l3_admit_key) != nullptr) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_EXISTS) << "l3 admit with key " << QuotedVar(l3_admit_key) + << " already exists in l3 admit manager"); + } + if (m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_MY_MAC, l3_admit_key)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("l3 admit with key " << QuotedVar(l3_admit_key) + << " already exists in centralized mapper"); + } + // Create L3 admit entry + P4L3AdmitEntry l3_admit_entry(app_db_entry.mac_address_data, app_db_entry.mac_address_mask, app_db_entry.priority, + app_db_entry.port_name); + auto status = createL3Admit(l3_admit_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to create l3 admit with key %s", QuotedVar(l3_admit_key).c_str()); + return status; + } + // Increase reference count to port + if (!l3_admit_entry.port_name.empty()) + { + gPortsOrch->increasePortRefCount(l3_admit_entry.port_name); + } + // Add created entry to internal table. + m_l3AdmitTable.emplace(l3_admit_key, l3_admit_entry); + + // Add the key to OID map to centralized mapper. + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_MY_MAC, l3_admit_key, l3_admit_entry.l3_admit_oid); return status; - } - // Increase reference count to port - if (!l3_admit_entry.port_name.empty()) { - gPortsOrch->increasePortRefCount(l3_admit_entry.port_name); - } - // Add created entry to internal table. - m_l3AdmitTable.emplace(l3_admit_key, l3_admit_entry); - - // Add the key to OID map to centralized mapper. - m_p4OidMapper->setOID(SAI_OBJECT_TYPE_MY_MAC, l3_admit_key, - l3_admit_entry.l3_admit_oid); - return status; } -ReturnCode L3AdmitManager::createL3Admit(P4L3AdmitEntry& l3_admit_entry) { - SWSS_LOG_ENTER(); - - ASSIGN_OR_RETURN(std::vector l3_admit_attrs, - getSaiAttrs(l3_admit_entry)); - // Call SAI API. - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_my_mac_api->create_my_mac(&l3_admit_entry.l3_admit_oid, gSwitchId, - (uint32_t)l3_admit_attrs.size(), - l3_admit_attrs.data()), - "Failed to create l3 admit with mac:" - << QuotedVar(l3_admit_entry.mac_address_data.to_string()) - << "; mac_mask:" - << QuotedVar(l3_admit_entry.mac_address_mask.to_string()) - << "; priority:" << QuotedVar(std::to_string(l3_admit_entry.priority)) - << "; in_port:" << QuotedVar(l3_admit_entry.port_name)); - - return ReturnCode(); +ReturnCode L3AdmitManager::createL3Admit(P4L3AdmitEntry &l3_admit_entry) +{ + SWSS_LOG_ENTER(); + + ASSIGN_OR_RETURN(std::vector l3_admit_attrs, getSaiAttrs(l3_admit_entry)); + // Call SAI API. + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_my_mac_api->create_my_mac(&l3_admit_entry.l3_admit_oid, gSwitchId, (uint32_t)l3_admit_attrs.size(), + l3_admit_attrs.data()), + "Failed to create l3 admit with mac:" << QuotedVar(l3_admit_entry.mac_address_data.to_string()) + << "; mac_mask:" << QuotedVar(l3_admit_entry.mac_address_mask.to_string()) + << "; priority:" << QuotedVar(std::to_string(l3_admit_entry.priority)) + << "; in_port:" << QuotedVar(l3_admit_entry.port_name)); + + return ReturnCode(); } -ReturnCode L3AdmitManager::processDeleteRequest( - const std::string& l3_admit_key) { - SWSS_LOG_ENTER(); - - // Check the existence of the l3 admit in l3 admit manager and centralized - // mapper. - auto* l3_admit_entry = getL3AdmitEntry(l3_admit_key); - if (l3_admit_entry == nullptr) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "l3 admit with key " << QuotedVar(l3_admit_key) - << " does not exist in l3 admit manager"); - } - - // Check if there is anything referring to the l3 admit before deletion. - uint32_t ref_count; - if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_MY_MAC, l3_admit_key, - &ref_count)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Failed to get reference count for l3 admit " - << QuotedVar(l3_admit_key)); - } - if (ref_count > 0) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "l3 admit " << QuotedVar(l3_admit_key) - << " referenced by other objects (ref_count = " - << ref_count); - } - - // Call SAI API - auto status = removeL3Admit(l3_admit_key); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to remove l3 admit with key %s", - QuotedVar(l3_admit_key).c_str()); +ReturnCode L3AdmitManager::processDeleteRequest(const std::string &l3_admit_key) +{ + SWSS_LOG_ENTER(); + + // Check the existence of the l3 admit in l3 admit manager and centralized + // mapper. + auto *l3_admit_entry = getL3AdmitEntry(l3_admit_key); + if (l3_admit_entry == nullptr) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "l3 admit with key " << QuotedVar(l3_admit_key) + << " does not exist in l3 admit manager"); + } + + // Check if there is anything referring to the l3 admit before deletion. + uint32_t ref_count; + if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_MY_MAC, l3_admit_key, &ref_count)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Failed to get reference count for l3 admit " + << QuotedVar(l3_admit_key)); + } + if (ref_count > 0) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "l3 admit " << QuotedVar(l3_admit_key) + << " referenced by other objects (ref_count = " << ref_count); + } + + // Call SAI API + auto status = removeL3Admit(l3_admit_key); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to remove l3 admit with key %s", QuotedVar(l3_admit_key).c_str()); + return status; + } + + // Decrease reference count to port + if (!l3_admit_entry->port_name.empty()) + { + gPortsOrch->decreasePortRefCount(l3_admit_entry->port_name); + } + // Remove the key to OID map to centralized mapper. + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_MY_MAC, l3_admit_key); + + // Remove the entry from internal table. + m_l3AdmitTable.erase(l3_admit_key); return status; - } - - // Decrease reference count to port - if (!l3_admit_entry->port_name.empty()) { - gPortsOrch->decreasePortRefCount(l3_admit_entry->port_name); - } - // Remove the key to OID map to centralized mapper. - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_MY_MAC, l3_admit_key); - - // Remove the entry from internal table. - m_l3AdmitTable.erase(l3_admit_key); - return status; } -ReturnCode L3AdmitManager::removeL3Admit(const std::string& l3_admit_key) { - SWSS_LOG_ENTER(); +ReturnCode L3AdmitManager::removeL3Admit(const std::string &l3_admit_key) +{ + SWSS_LOG_ENTER(); - auto* l3_admit_entry = getL3AdmitEntry(l3_admit_key); - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_my_mac_api->remove_my_mac(l3_admit_entry->l3_admit_oid), - "Failed to remove l3 admit " << QuotedVar(l3_admit_key)); + auto *l3_admit_entry = getL3AdmitEntry(l3_admit_key); + CHECK_ERROR_AND_LOG_AND_RETURN(sai_my_mac_api->remove_my_mac(l3_admit_entry->l3_admit_oid), + "Failed to remove l3 admit " << QuotedVar(l3_admit_key)); - return ReturnCode(); + return ReturnCode(); } -std::string L3AdmitManager::verifyState( - const std::string& key, const std::vector& tuple) { - SWSS_LOG_ENTER(); - - auto pos = key.find_first_of(kTableKeyDelimiter); - if (pos == std::string::npos) { - return std::string("Invalid key: ") + key; - } - std::string p4rt_table = key.substr(0, pos); - std::string p4rt_key = key.substr(pos + 1); - if (p4rt_table != APP_P4RT_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - std::string table_name; - std::string key_content; - parseP4RTKey(p4rt_key, &table_name, &key_content); - if (table_name != APP_P4RT_L3_ADMIT_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - - ReturnCode status; - auto app_db_entry_or = deserializeP4L3AdmitAppDbEntry(key_content, tuple); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - std::stringstream msg; - msg << "Unable to deserialize key " << QuotedVar(key) << ": " - << status.message(); - return msg.str(); - } - auto& app_db_entry = *app_db_entry_or; - const std::string l3_admit_key = KeyGenerator::generateL3AdmitKey( - app_db_entry.mac_address_data, app_db_entry.mac_address_mask, - app_db_entry.port_name, app_db_entry.priority); - auto* l3_admit_entry = getL3AdmitEntry(l3_admit_key); - if (l3_admit_entry == nullptr) { - std::stringstream msg; - msg << "No entry found with key " << QuotedVar(key); - return msg.str(); - } - - std::string cache_result = verifyStateCache(app_db_entry, l3_admit_entry); - std::string asic_db_result = verifyStateAsicDb(l3_admit_entry); - if (cache_result.empty()) { - return asic_db_result; - } - if (asic_db_result.empty()) { - return cache_result; - } - return cache_result + "; " + asic_db_result; +std::string L3AdmitManager::verifyState(const std::string &key, const std::vector &tuple) +{ + SWSS_LOG_ENTER(); + + auto pos = key.find_first_of(kTableKeyDelimiter); + if (pos == std::string::npos) + { + return std::string("Invalid key: ") + key; + } + std::string p4rt_table = key.substr(0, pos); + std::string p4rt_key = key.substr(pos + 1); + if (p4rt_table != APP_P4RT_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } + std::string table_name; + std::string key_content; + parseP4RTKey(p4rt_key, &table_name, &key_content); + if (table_name != APP_P4RT_L3_ADMIT_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } + + ReturnCode status; + auto app_db_entry_or = deserializeP4L3AdmitAppDbEntry(key_content, tuple); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + std::stringstream msg; + msg << "Unable to deserialize key " << QuotedVar(key) << ": " << status.message(); + return msg.str(); + } + auto &app_db_entry = *app_db_entry_or; + const std::string l3_admit_key = KeyGenerator::generateL3AdmitKey( + app_db_entry.mac_address_data, app_db_entry.mac_address_mask, app_db_entry.port_name, app_db_entry.priority); + auto *l3_admit_entry = getL3AdmitEntry(l3_admit_key); + if (l3_admit_entry == nullptr) + { + std::stringstream msg; + msg << "No entry found with key " << QuotedVar(key); + return msg.str(); + } + + std::string cache_result = verifyStateCache(app_db_entry, l3_admit_entry); + std::string asic_db_result = verifyStateAsicDb(l3_admit_entry); + if (cache_result.empty()) + { + return asic_db_result; + } + if (asic_db_result.empty()) + { + return cache_result; + } + return cache_result + "; " + asic_db_result; } -std::string L3AdmitManager::verifyStateCache( - const P4L3AdmitAppDbEntry& app_db_entry, - const P4L3AdmitEntry* l3_admit_entry) { - const std::string l3_admit_key = KeyGenerator::generateL3AdmitKey( - app_db_entry.mac_address_data, app_db_entry.mac_address_mask, - app_db_entry.port_name, app_db_entry.priority); - - if (l3_admit_entry->port_name != app_db_entry.port_name) { - std::stringstream msg; - msg << "L3 admit " << QuotedVar(l3_admit_key) << " with port " - << QuotedVar(app_db_entry.port_name) - << " does not match internal cache " - << QuotedVar(l3_admit_entry->port_name) << " in L3 admit manager."; - return msg.str(); - } - if (l3_admit_entry->mac_address_data.to_string() != - app_db_entry.mac_address_data.to_string()) { - std::stringstream msg; - msg << "L3 admit " << QuotedVar(l3_admit_key) << " with MAC addr " - << app_db_entry.mac_address_data.to_string() - << " does not match internal cache " - << l3_admit_entry->mac_address_data.to_string() - << " in L3 admit manager."; - return msg.str(); - } - if (l3_admit_entry->mac_address_mask.to_string() != - app_db_entry.mac_address_mask.to_string()) { - std::stringstream msg; - msg << "L3 admit " << QuotedVar(l3_admit_key) << " with MAC mask " - << app_db_entry.mac_address_mask.to_string() - << " does not match internal cache " - << l3_admit_entry->mac_address_mask.to_string() - << " in L3 admit manager."; - return msg.str(); - } - if (l3_admit_entry->priority != app_db_entry.priority) { - std::stringstream msg; - msg << "L3 admit " << QuotedVar(l3_admit_key) << " with priority " - << app_db_entry.priority << " does not match internal cache " - << l3_admit_entry->priority << " in L3 admit manager."; - return msg.str(); - } - - return m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_MY_MAC, l3_admit_key, - l3_admit_entry->l3_admit_oid); +std::string L3AdmitManager::verifyStateCache(const P4L3AdmitAppDbEntry &app_db_entry, + const P4L3AdmitEntry *l3_admit_entry) +{ + const std::string l3_admit_key = KeyGenerator::generateL3AdmitKey( + app_db_entry.mac_address_data, app_db_entry.mac_address_mask, app_db_entry.port_name, app_db_entry.priority); + + if (l3_admit_entry->port_name != app_db_entry.port_name) + { + std::stringstream msg; + msg << "L3 admit " << QuotedVar(l3_admit_key) << " with port " << QuotedVar(app_db_entry.port_name) + << " does not match internal cache " << QuotedVar(l3_admit_entry->port_name) << " in L3 admit manager."; + return msg.str(); + } + if (l3_admit_entry->mac_address_data.to_string() != app_db_entry.mac_address_data.to_string()) + { + std::stringstream msg; + msg << "L3 admit " << QuotedVar(l3_admit_key) << " with MAC addr " << app_db_entry.mac_address_data.to_string() + << " does not match internal cache " << l3_admit_entry->mac_address_data.to_string() + << " in L3 admit manager."; + return msg.str(); + } + if (l3_admit_entry->mac_address_mask.to_string() != app_db_entry.mac_address_mask.to_string()) + { + std::stringstream msg; + msg << "L3 admit " << QuotedVar(l3_admit_key) << " with MAC mask " << app_db_entry.mac_address_mask.to_string() + << " does not match internal cache " << l3_admit_entry->mac_address_mask.to_string() + << " in L3 admit manager."; + return msg.str(); + } + if (l3_admit_entry->priority != app_db_entry.priority) + { + std::stringstream msg; + msg << "L3 admit " << QuotedVar(l3_admit_key) << " with priority " << app_db_entry.priority + << " does not match internal cache " << l3_admit_entry->priority << " in L3 admit manager."; + return msg.str(); + } + + return m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_MY_MAC, l3_admit_key, l3_admit_entry->l3_admit_oid); } -std::string L3AdmitManager::verifyStateAsicDb( - const P4L3AdmitEntry* l3_admit_entry) { - auto attrs_or = getSaiAttrs(*l3_admit_entry); - if (!attrs_or.ok()) { - return std::string("Failed to get SAI attrs: ") + - attrs_or.status().message(); - } - std::vector attrs = *attrs_or; - std::vector exp = - saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_MY_MAC, (uint32_t)attrs.size(), attrs.data(), - /*countOnly=*/false); - - swss::DBConnector db("ASIC_DB", 0); - swss::Table table(&db, "ASIC_STATE"); - std::string key = sai_serialize_object_type(SAI_OBJECT_TYPE_MY_MAC) + ":" + - sai_serialize_object_id(l3_admit_entry->l3_admit_oid); - std::vector values; - if (!table.get(key, values)) { - return std::string("ASIC DB key not found ") + key; - } - - return verifyAttrs(values, exp, std::vector{}, - /*allow_unknown=*/false); +std::string L3AdmitManager::verifyStateAsicDb(const P4L3AdmitEntry *l3_admit_entry) +{ + auto attrs_or = getSaiAttrs(*l3_admit_entry); + if (!attrs_or.ok()) + { + return std::string("Failed to get SAI attrs: ") + attrs_or.status().message(); + } + std::vector attrs = *attrs_or; + std::vector exp = + saimeta::SaiAttributeList::serialize_attr_list(SAI_OBJECT_TYPE_MY_MAC, (uint32_t)attrs.size(), attrs.data(), + /*countOnly=*/false); + + swss::DBConnector db("ASIC_DB", 0); + swss::Table table(&db, "ASIC_STATE"); + std::string key = + sai_serialize_object_type(SAI_OBJECT_TYPE_MY_MAC) + ":" + sai_serialize_object_id(l3_admit_entry->l3_admit_oid); + std::vector values; + if (!table.get(key, values)) + { + return std::string("ASIC DB key not found ") + key; + } + + return verifyAttrs(values, exp, std::vector{}, + /*allow_unknown=*/false); } diff --git a/orchagent/p4orch/l3_admit_manager.h b/orchagent/p4orch/l3_admit_manager.h index 087e873c9a2..5f0af69b713 100644 --- a/orchagent/p4orch/l3_admit_manager.h +++ b/orchagent/p4orch/l3_admit_manager.h @@ -11,21 +11,21 @@ #define EMPTY_STRING "" -struct P4L3AdmitEntry { - std::string port_name; // Optional - swss::MacAddress mac_address_data; - swss::MacAddress mac_address_mask; - sai_uint32_t priority; - sai_object_id_t l3_admit_oid = SAI_NULL_OBJECT_ID; - - P4L3AdmitEntry() = default; - P4L3AdmitEntry(const swss::MacAddress& mac_address_data, - const swss::MacAddress& mac_address_mask, - const sai_uint32_t& priority, const std::string& port_name) - : port_name(port_name), - mac_address_data(mac_address_data), - mac_address_mask(mac_address_mask), - priority(priority) {} +struct P4L3AdmitEntry +{ + std::string port_name; // Optional + swss::MacAddress mac_address_data; + swss::MacAddress mac_address_mask; + sai_uint32_t priority; + sai_object_id_t l3_admit_oid = SAI_NULL_OBJECT_ID; + + P4L3AdmitEntry() = default; + P4L3AdmitEntry(const swss::MacAddress &mac_address_data, const swss::MacAddress &mac_address_mask, + const sai_uint32_t &priority, const std::string &port_name) + : port_name(port_name), mac_address_data(mac_address_data), mac_address_mask(mac_address_mask), + priority(priority) + { + } }; // L3Admit manager is responsible for subscribing to APPL_DB FIXED_L3_ADMIT @@ -45,62 +45,56 @@ struct P4L3AdmitEntry { // P4RT:FIXED_L3_ADMIT_TABLE:{\"priority\":2030} // "action": "admit_to_l3" // "controller_metadata": "..." -class L3AdmitManager : public ObjectManagerInterface { - public: - L3AdmitManager(P4OidMapper* p4oidMapper, - ResponsePublisherInterface* publisher) { - SWSS_LOG_ENTER(); - - assert(p4oidMapper != nullptr); - m_p4OidMapper = p4oidMapper; - assert(publisher != nullptr); - m_publisher = publisher; - } - - virtual ~L3AdmitManager() = default; - - void enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) override; - void drain() override; - std::string verifyState( - const std::string& key, - const std::vector& tuple) override; - ReturnCode getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) override; - - private: - // Gets the internal cached next hop entry by its key. - // Return nullptr if corresponding next hop entry is not cached. - P4L3AdmitEntry* getL3AdmitEntry(const std::string& l3_admit_key); - - // Deserializes an entry from table APP_P4RT_L3_ADMIT_TABLE_NAME. - ReturnCodeOr deserializeP4L3AdmitAppDbEntry( - const std::string& key, - const std::vector& attributes); - - ReturnCode processAddRequest(const P4L3AdmitAppDbEntry& app_db_entry, - const std::string& l3_admit_key); - - // Creates a L3 Admit entry. Return true on success. - ReturnCode createL3Admit(P4L3AdmitEntry& l3_admit_entry); - - ReturnCode processDeleteRequest(const std::string& l3_admit_key); - - // Deletes a L3 Admit entry. Return true on success. - ReturnCode removeL3Admit(const std::string& l3_admit_key); - - // state verification DB helper functions. Return err string or empty string. - std::string verifyStateCache(const P4L3AdmitAppDbEntry& app_db_entry, - const P4L3AdmitEntry* l3_admit_entry); - std::string verifyStateAsicDb(const P4L3AdmitEntry* l3_admit_entry); - - // m_l3AdmitTable: l3_admit_key, P4L3AdmitEntry - std::unordered_map m_l3AdmitTable; - - ResponsePublisherInterface* m_publisher; - std::deque m_entries; - P4OidMapper* m_p4OidMapper; - - friend class L3AdmitManagerTest; +class L3AdmitManager : public ObjectManagerInterface +{ + public: + L3AdmitManager(P4OidMapper *p4oidMapper, ResponsePublisherInterface *publisher) + { + SWSS_LOG_ENTER(); + + assert(p4oidMapper != nullptr); + m_p4OidMapper = p4oidMapper; + assert(publisher != nullptr); + m_publisher = publisher; + } + + virtual ~L3AdmitManager() = default; + + void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; + void drain() override; + std::string verifyState(const std::string &key, const std::vector &tuple) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; + + private: + // Gets the internal cached next hop entry by its key. + // Return nullptr if corresponding next hop entry is not cached. + P4L3AdmitEntry *getL3AdmitEntry(const std::string &l3_admit_key); + + // Deserializes an entry from table APP_P4RT_L3_ADMIT_TABLE_NAME. + ReturnCodeOr deserializeP4L3AdmitAppDbEntry( + const std::string &key, const std::vector &attributes); + + ReturnCode processAddRequest(const P4L3AdmitAppDbEntry &app_db_entry, const std::string &l3_admit_key); + + // Creates a L3 Admit entry. Return true on success. + ReturnCode createL3Admit(P4L3AdmitEntry &l3_admit_entry); + + ReturnCode processDeleteRequest(const std::string &l3_admit_key); + + // Deletes a L3 Admit entry. Return true on success. + ReturnCode removeL3Admit(const std::string &l3_admit_key); + + // state verification DB helper functions. Return err string or empty string. + std::string verifyStateCache(const P4L3AdmitAppDbEntry &app_db_entry, const P4L3AdmitEntry *l3_admit_entry); + std::string verifyStateAsicDb(const P4L3AdmitEntry *l3_admit_entry); + + // m_l3AdmitTable: l3_admit_key, P4L3AdmitEntry + std::unordered_map m_l3AdmitTable; + + ResponsePublisherInterface *m_publisher; + std::deque m_entries; + P4OidMapper *m_p4OidMapper; + + friend class L3AdmitManagerTest; }; diff --git a/orchagent/p4orch/mirror_session_manager.cpp b/orchagent/p4orch/mirror_session_manager.cpp index 83a174176a4..e562b87ff57 100644 --- a/orchagent/p4orch/mirror_session_manager.cpp +++ b/orchagent/p4orch/mirror_session_manager.cpp @@ -14,893 +14,914 @@ using ::p4orch::kTableKeyDelimiter; -extern PortsOrch* gPortsOrch; -extern sai_mirror_api_t* sai_mirror_api; +extern PortsOrch *gPortsOrch; +extern sai_mirror_api_t *sai_mirror_api; extern sai_object_id_t gSwitchId; -namespace p4orch { - -ReturnCode MirrorSessionManager::getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) { - std::string value; - - try { - nlohmann::json j = nlohmann::json::parse(json_key); - if (j.find(prependMatchField(p4orch::kMirrorSessionId)) != j.end()) { - value = - j.at(prependMatchField(p4orch::kMirrorSessionId)).get(); - object_key = KeyGenerator::generateMirrorSessionKey(value); - object_type = SAI_OBJECT_TYPE_MIRROR_SESSION; - return ReturnCode(); - } else { - SWSS_LOG_ERROR( - "%s match parameter absent: required for dependent object query", - p4orch::kMirrorSessionId); - } - } catch (std::exception& ex) { - SWSS_LOG_ERROR("json_key parse error"); - } - - return StatusCode::SWSS_RC_INVALID_PARAM; +namespace p4orch +{ + +ReturnCode MirrorSessionManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) +{ + std::string value; + + try + { + nlohmann::json j = nlohmann::json::parse(json_key); + if (j.find(prependMatchField(p4orch::kMirrorSessionId)) != j.end()) + { + value = j.at(prependMatchField(p4orch::kMirrorSessionId)).get(); + object_key = KeyGenerator::generateMirrorSessionKey(value); + object_type = SAI_OBJECT_TYPE_MIRROR_SESSION; + return ReturnCode(); + } + else + { + SWSS_LOG_ERROR("%s match parameter absent: required for dependent object query", p4orch::kMirrorSessionId); + } + } + catch (std::exception &ex) + { + SWSS_LOG_ERROR("json_key parse error"); + } + + return StatusCode::SWSS_RC_INVALID_PARAM; } -void MirrorSessionManager::enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) { - SWSS_LOG_ENTER(); - m_entries.push_back(entry); +void MirrorSessionManager::enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) +{ + SWSS_LOG_ENTER(); + m_entries.push_back(entry); } -void MirrorSessionManager::drain() { - SWSS_LOG_ENTER(); +void MirrorSessionManager::drain() +{ + SWSS_LOG_ENTER(); + + for (const auto &key_op_fvs_tuple : m_entries) + { + std::string table_name; + std::string key; + parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &key); + const std::vector &attributes = kfvFieldsValues(key_op_fvs_tuple); + + ReturnCode status; + auto app_db_entry_or = deserializeP4MirrorSessionAppDbEntry(key, attributes); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", + QuotedVar(table_name + ":" + key).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + auto &app_db_entry = *app_db_entry_or; + + const std::string mirror_session_key = KeyGenerator::generateMirrorSessionKey(app_db_entry.mirror_session_id); + + // Fulfill the operation. + const std::string &operation = kfvOp(key_op_fvs_tuple); + if (operation == SET_COMMAND) + { + auto *mirror_session_entry = getMirrorSessionEntry(mirror_session_key); + if (mirror_session_entry == nullptr) + { + // Create new mirror session. + status = processAddRequest(app_db_entry); + } + else + { + // Modify existing mirror session. + status = processUpdateRequest(app_db_entry, mirror_session_entry); + } + } + else if (operation == DEL_COMMAND) + { + // Delete mirror session. + status = processDeleteRequest(mirror_session_key); + } + else + { + status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Unknown operation type " << QuotedVar(operation); + SWSS_LOG_ERROR("%s", status.message().c_str()); + } + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), status, + /*replace=*/true); + } + m_entries.clear(); +} - for (const auto& key_op_fvs_tuple : m_entries) { - std::string table_name; - std::string key; - parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &key); - const std::vector& attributes = - kfvFieldsValues(key_op_fvs_tuple); +ReturnCodeOr> getSaiAttrs(const P4MirrorSessionEntry &mirror_session_entry) +{ + swss::Port port; + if (!gPortsOrch->getPort(mirror_session_entry.port, port)) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Failed to get port info for port " << QuotedVar(mirror_session_entry.port)); + } + if (port.m_type != Port::Type::PHY) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Port " << QuotedVar(mirror_session_entry.port) << "'s type " << port.m_type + << " is not physical and is invalid as destination " + "port for mirror packet."); + } - ReturnCode status; - auto app_db_entry_or = - deserializeP4MirrorSessionAppDbEntry(key, attributes); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", - QuotedVar(table_name + ":" + key).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - auto& app_db_entry = *app_db_entry_or; - - const std::string mirror_session_key = - KeyGenerator::generateMirrorSessionKey(app_db_entry.mirror_session_id); - - // Fulfill the operation. - const std::string& operation = kfvOp(key_op_fvs_tuple); - if (operation == SET_COMMAND) { - auto* mirror_session_entry = getMirrorSessionEntry(mirror_session_key); - if (mirror_session_entry == nullptr) { - // Create new mirror session. - status = processAddRequest(app_db_entry); - } else { - // Modify existing mirror session. - status = processUpdateRequest(app_db_entry, mirror_session_entry); - } - } else if (operation == DEL_COMMAND) { - // Delete mirror session. - status = processDeleteRequest(mirror_session_key); - } else { - status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown operation type " << QuotedVar(operation); - SWSS_LOG_ERROR("%s", status.message().c_str()); - } - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - } - m_entries.clear(); -} + std::vector attrs; + sai_attribute_t attr; + + attr.id = SAI_MIRROR_SESSION_ATTR_MONITOR_PORT; + attr.value.oid = port.m_port_id; + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_TYPE; + attr.value.s32 = SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE; + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE; + attr.value.s32 = SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL; + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION; + attr.value.u8 = MIRROR_SESSION_DEFAULT_IP_HDR_VER; + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_TOS; + attr.value.u8 = mirror_session_entry.tos; + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_TTL; + attr.value.u8 = mirror_session_entry.ttl; + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS; + swss::copy(attr.value.ipaddr, mirror_session_entry.src_ip); + attrs.push_back(attr); -ReturnCodeOr> getSaiAttrs( - const P4MirrorSessionEntry& mirror_session_entry) { - swss::Port port; - if (!gPortsOrch->getPort(mirror_session_entry.port, port)) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Failed to get port info for port " - << QuotedVar(mirror_session_entry.port)); - } - if (port.m_type != Port::Type::PHY) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Port " << QuotedVar(mirror_session_entry.port) - << "'s type " << port.m_type - << " is not physical and is invalid as destination " - "port for mirror packet."); - } - - std::vector attrs; - sai_attribute_t attr; - - attr.id = SAI_MIRROR_SESSION_ATTR_MONITOR_PORT; - attr.value.oid = port.m_port_id; - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_TYPE; - attr.value.s32 = SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE; - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE; - attr.value.s32 = SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL; - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION; - attr.value.u8 = MIRROR_SESSION_DEFAULT_IP_HDR_VER; - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_TOS; - attr.value.u8 = mirror_session_entry.tos; - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_TTL; - attr.value.u8 = mirror_session_entry.ttl; - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS; - swss::copy(attr.value.ipaddr, mirror_session_entry.src_ip); - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS; - swss::copy(attr.value.ipaddr, mirror_session_entry.dst_ip); - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS; - memcpy(attr.value.mac, mirror_session_entry.src_mac.getMac(), - sizeof(sai_mac_t)); - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS; - memcpy(attr.value.mac, mirror_session_entry.dst_mac.getMac(), - sizeof(sai_mac_t)); - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE; - attr.value.u16 = GRE_PROTOCOL_ERSPAN; - attrs.push_back(attr); - - return attrs; + attr.id = SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS; + swss::copy(attr.value.ipaddr, mirror_session_entry.dst_ip); + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS; + memcpy(attr.value.mac, mirror_session_entry.src_mac.getMac(), sizeof(sai_mac_t)); + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS; + memcpy(attr.value.mac, mirror_session_entry.dst_mac.getMac(), sizeof(sai_mac_t)); + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE; + attr.value.u16 = GRE_PROTOCOL_ERSPAN; + attrs.push_back(attr); + + return attrs; } -ReturnCodeOr -MirrorSessionManager::deserializeP4MirrorSessionAppDbEntry( - const std::string& key, - const std::vector& attributes) { - SWSS_LOG_ENTER(); - - P4MirrorSessionAppDbEntry app_db_entry = {}; - - try { - nlohmann::json j = nlohmann::json::parse(key); - app_db_entry.mirror_session_id = - j[prependMatchField(p4orch::kMirrorSessionId)]; - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to deserialize mirror session id"; - } - - for (const auto& it : attributes) { - const auto& field = fvField(it); - const auto& value = fvValue(it); - if (field == prependParamField(p4orch::kPort)) { - swss::Port port; - if (!gPortsOrch->getPort(value, port)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Failed to get port info for port " << QuotedVar(value); - } - if (port.m_type != Port::Type::PHY) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Port " << QuotedVar(value) << "'s type " << port.m_type - << " is not physical and is invalid as destination port for " - "mirror packet."; - } - app_db_entry.port = value; - app_db_entry.has_port = true; - } else if (field == prependParamField(p4orch::kSrcIp)) { - try { - app_db_entry.src_ip = swss::IpAddress(value); - app_db_entry.has_src_ip = true; - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid IP address " << QuotedVar(value) << " of field " - << QuotedVar(field); - } - } else if (field == prependParamField(p4orch::kDstIp)) { - try { - app_db_entry.dst_ip = swss::IpAddress(value); - app_db_entry.has_dst_ip = true; - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid IP address " << QuotedVar(value) << " of field " - << QuotedVar(field); - } - } else if (field == prependParamField(p4orch::kSrcMac)) { - try { - app_db_entry.src_mac = swss::MacAddress(value); - app_db_entry.has_src_mac = true; - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid MAC address " << QuotedVar(value) << " of field " - << QuotedVar(field); - } - } else if (field == prependParamField(p4orch::kDstMac)) { - try { - app_db_entry.dst_mac = swss::MacAddress(value); - app_db_entry.has_dst_mac = true; - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid MAC address " << QuotedVar(value) << " of field " - << QuotedVar(field); - } - } else if (field == prependParamField(p4orch::kTtl)) { - try { - app_db_entry.ttl = - static_cast(std::stoul(value, 0, /*base=*/16)); - app_db_entry.has_ttl = true; - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid TTL " << QuotedVar(value) << " of field " - << QuotedVar(field); - } - } else if (field == prependParamField(p4orch::kTos)) { - try { - app_db_entry.tos = - static_cast(std::stoul(value, 0, /*base=*/16)); - app_db_entry.has_tos = true; - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid TOS " << QuotedVar(value) << " of field " - << QuotedVar(field); - } - } else if (field == p4orch::kAction) { - if (value != p4orch::kMirrorAsIpv4Erspan) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Action value " << QuotedVar(value) - << " is not mirror_as_ipv4_erspan."; - } - } else if (field != p4orch::kControllerMetadata) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unexpected field " << QuotedVar(field) << " in table entry"; - } - } - - return app_db_entry; +ReturnCodeOr MirrorSessionManager::deserializeP4MirrorSessionAppDbEntry( + const std::string &key, const std::vector &attributes) +{ + SWSS_LOG_ENTER(); + + P4MirrorSessionAppDbEntry app_db_entry = {}; + + try + { + nlohmann::json j = nlohmann::json::parse(key); + app_db_entry.mirror_session_id = j[prependMatchField(p4orch::kMirrorSessionId)]; + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Failed to deserialize mirror session id"; + } + + for (const auto &it : attributes) + { + const auto &field = fvField(it); + const auto &value = fvValue(it); + if (field == prependParamField(p4orch::kPort)) + { + swss::Port port; + if (!gPortsOrch->getPort(value, port)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Failed to get port info for port " << QuotedVar(value); + } + if (port.m_type != Port::Type::PHY) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Port " << QuotedVar(value) << "'s type " << port.m_type + << " is not physical and is invalid as destination port for " + "mirror packet."; + } + app_db_entry.port = value; + app_db_entry.has_port = true; + } + else if (field == prependParamField(p4orch::kSrcIp)) + { + try + { + app_db_entry.src_ip = swss::IpAddress(value); + app_db_entry.has_src_ip = true; + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid IP address " << QuotedVar(value) << " of field " << QuotedVar(field); + } + } + else if (field == prependParamField(p4orch::kDstIp)) + { + try + { + app_db_entry.dst_ip = swss::IpAddress(value); + app_db_entry.has_dst_ip = true; + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid IP address " << QuotedVar(value) << " of field " << QuotedVar(field); + } + } + else if (field == prependParamField(p4orch::kSrcMac)) + { + try + { + app_db_entry.src_mac = swss::MacAddress(value); + app_db_entry.has_src_mac = true; + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid MAC address " << QuotedVar(value) << " of field " << QuotedVar(field); + } + } + else if (field == prependParamField(p4orch::kDstMac)) + { + try + { + app_db_entry.dst_mac = swss::MacAddress(value); + app_db_entry.has_dst_mac = true; + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid MAC address " << QuotedVar(value) << " of field " << QuotedVar(field); + } + } + else if (field == prependParamField(p4orch::kTtl)) + { + try + { + app_db_entry.ttl = static_cast(std::stoul(value, 0, /*base=*/16)); + app_db_entry.has_ttl = true; + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid TTL " << QuotedVar(value) << " of field " << QuotedVar(field); + } + } + else if (field == prependParamField(p4orch::kTos)) + { + try + { + app_db_entry.tos = static_cast(std::stoul(value, 0, /*base=*/16)); + app_db_entry.has_tos = true; + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid TOS " << QuotedVar(value) << " of field " << QuotedVar(field); + } + } + else if (field == p4orch::kAction) + { + if (value != p4orch::kMirrorAsIpv4Erspan) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Action value " << QuotedVar(value) << " is not mirror_as_ipv4_erspan."; + } + } + else if (field != p4orch::kControllerMetadata) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unexpected field " << QuotedVar(field) << " in table entry"; + } + } + + return app_db_entry; } -P4MirrorSessionEntry* MirrorSessionManager::getMirrorSessionEntry( - const std::string& mirror_session_key) { - auto it = m_mirrorSessionTable.find(mirror_session_key); +P4MirrorSessionEntry *MirrorSessionManager::getMirrorSessionEntry(const std::string &mirror_session_key) +{ + auto it = m_mirrorSessionTable.find(mirror_session_key); - if (it == m_mirrorSessionTable.end()) { - return nullptr; - } else { - return &it->second; - } + if (it == m_mirrorSessionTable.end()) + { + return nullptr; + } + else + { + return &it->second; + } } -ReturnCode MirrorSessionManager::processAddRequest( - const P4MirrorSessionAppDbEntry& app_db_entry) { - SWSS_LOG_ENTER(); - - ReturnCode status; - // Check if all required fields for add operation are given in APP DB entry. - if (app_db_entry.has_port && app_db_entry.has_src_ip && - app_db_entry.has_dst_ip && app_db_entry.has_src_mac && - app_db_entry.has_dst_mac && app_db_entry.has_ttl && - app_db_entry.has_tos) { - P4MirrorSessionEntry mirror_session_entry( - KeyGenerator::generateMirrorSessionKey(app_db_entry.mirror_session_id), - /*mirror_session_oid=*/0, app_db_entry.mirror_session_id, - app_db_entry.port, app_db_entry.src_ip, app_db_entry.dst_ip, - app_db_entry.src_mac, app_db_entry.dst_mac, app_db_entry.ttl, - app_db_entry.tos); - status = createMirrorSession(std::move(mirror_session_entry)); - } else { - status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Mirror session entry with mirror_session_id " - << QuotedVar(app_db_entry.mirror_session_id) - << " doesn't specify all required fields for ADD operation."; - SWSS_LOG_ERROR("%s", status.message().c_str()); - } - - return status; +ReturnCode MirrorSessionManager::processAddRequest(const P4MirrorSessionAppDbEntry &app_db_entry) +{ + SWSS_LOG_ENTER(); + + ReturnCode status; + // Check if all required fields for add operation are given in APP DB entry. + if (app_db_entry.has_port && app_db_entry.has_src_ip && app_db_entry.has_dst_ip && app_db_entry.has_src_mac && + app_db_entry.has_dst_mac && app_db_entry.has_ttl && app_db_entry.has_tos) + { + P4MirrorSessionEntry mirror_session_entry( + KeyGenerator::generateMirrorSessionKey(app_db_entry.mirror_session_id), + /*mirror_session_oid=*/0, app_db_entry.mirror_session_id, app_db_entry.port, app_db_entry.src_ip, + app_db_entry.dst_ip, app_db_entry.src_mac, app_db_entry.dst_mac, app_db_entry.ttl, app_db_entry.tos); + status = createMirrorSession(std::move(mirror_session_entry)); + } + else + { + status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Mirror session entry with mirror_session_id " << QuotedVar(app_db_entry.mirror_session_id) + << " doesn't specify all required fields for ADD operation."; + SWSS_LOG_ERROR("%s", status.message().c_str()); + } + + return status; } -ReturnCode MirrorSessionManager::createMirrorSession( - P4MirrorSessionEntry mirror_session_entry) { - SWSS_LOG_ENTER(); - - // Check the existence of the mirror session in centralized mapper. - if (m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_MIRROR_SESSION, - mirror_session_entry.mirror_session_key)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Mirror session with key " - << QuotedVar(mirror_session_entry.mirror_session_key) - << " already exists in centralized mapper"); - } - // Prepare attributes for the SAI creation call. - ASSIGN_OR_RETURN(std::vector attrs, - getSaiAttrs(mirror_session_entry)); - - // Call SAI API. - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_mirror_api->create_mirror_session( - &mirror_session_entry.mirror_session_oid, gSwitchId, - (uint32_t)attrs.size(), attrs.data()), - "Failed to create mirror session " - << QuotedVar(mirror_session_entry.mirror_session_key)); - - // On successful creation, increment ref count. - gPortsOrch->increasePortRefCount(mirror_session_entry.port); - - // Add the key to OID map to centralized mapper. - m_p4OidMapper->setOID(SAI_OBJECT_TYPE_MIRROR_SESSION, - mirror_session_entry.mirror_session_key, - mirror_session_entry.mirror_session_oid); - - // Add created entry to internal table. - m_mirrorSessionTable.emplace(mirror_session_entry.mirror_session_key, - mirror_session_entry); - - return ReturnCode(); +ReturnCode MirrorSessionManager::createMirrorSession(P4MirrorSessionEntry mirror_session_entry) +{ + SWSS_LOG_ENTER(); + + // Check the existence of the mirror session in centralized mapper. + if (m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_MIRROR_SESSION, mirror_session_entry.mirror_session_key)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Mirror session with key " + << QuotedVar(mirror_session_entry.mirror_session_key) + << " already exists in centralized mapper"); + } + // Prepare attributes for the SAI creation call. + ASSIGN_OR_RETURN(std::vector attrs, getSaiAttrs(mirror_session_entry)); + + // Call SAI API. + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_mirror_api->create_mirror_session(&mirror_session_entry.mirror_session_oid, gSwitchId, + (uint32_t)attrs.size(), attrs.data()), + "Failed to create mirror session " << QuotedVar(mirror_session_entry.mirror_session_key)); + + // On successful creation, increment ref count. + gPortsOrch->increasePortRefCount(mirror_session_entry.port); + + // Add the key to OID map to centralized mapper. + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_MIRROR_SESSION, mirror_session_entry.mirror_session_key, + mirror_session_entry.mirror_session_oid); + + // Add created entry to internal table. + m_mirrorSessionTable.emplace(mirror_session_entry.mirror_session_key, mirror_session_entry); + + return ReturnCode(); } -ReturnCode MirrorSessionManager::processUpdateRequest( - const P4MirrorSessionAppDbEntry& app_db_entry, - P4MirrorSessionEntry* existing_mirror_session_entry) { - SWSS_LOG_ENTER(); - - // Check the existence of the mirror session in mirror manager and centralized - // mapper. - if (existing_mirror_session_entry == nullptr) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "existing_mirror_session_entry is nullptr"); - } - if (!m_p4OidMapper->existsOID( - SAI_OBJECT_TYPE_MIRROR_SESSION, - existing_mirror_session_entry->mirror_session_key)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Mirror session with key " - << QuotedVar(existing_mirror_session_entry->mirror_session_key) - << " doesn't exist in centralized mapper"); - } - - P4MirrorSessionEntry mirror_session_entry_before_update( - *existing_mirror_session_entry); - - // Because SAI mirror set API sets attr one at a time, it is possible attr - // updates fail in the middle. Up on failure, all successful operations need - // to be undone. - ReturnCode ret; - bool update_fail_in_middle = false; - if (!update_fail_in_middle && app_db_entry.has_port) { - ret = setPort(app_db_entry.port, existing_mirror_session_entry); - if (!ret.ok()) update_fail_in_middle = true; - } - if (!update_fail_in_middle && app_db_entry.has_src_ip) { - ret = setSrcIp(app_db_entry.src_ip, existing_mirror_session_entry); - if (!ret.ok()) update_fail_in_middle = true; - } - if (!update_fail_in_middle && app_db_entry.has_dst_ip) { - ret = setDstIp(app_db_entry.dst_ip, existing_mirror_session_entry); - if (!ret.ok()) update_fail_in_middle = true; - } - if (!update_fail_in_middle && app_db_entry.has_src_mac) { - ret = setSrcMac(app_db_entry.src_mac, existing_mirror_session_entry); - if (!ret.ok()) update_fail_in_middle = true; - } - if (!update_fail_in_middle && app_db_entry.has_dst_mac) { - ret = setDstMac(app_db_entry.dst_mac, existing_mirror_session_entry); - if (!ret.ok()) update_fail_in_middle = true; - } - if (!update_fail_in_middle && app_db_entry.has_ttl) { - ret = setTtl(app_db_entry.ttl, existing_mirror_session_entry); - if (!ret.ok()) update_fail_in_middle = true; - } - if (!update_fail_in_middle && app_db_entry.has_tos) { - ret = setTos(app_db_entry.tos, existing_mirror_session_entry); - if (!ret.ok()) update_fail_in_middle = true; - } - - if (update_fail_in_middle) { - ReturnCode status = setMirrorSessionEntry( - mirror_session_entry_before_update, existing_mirror_session_entry); - if (!status.ok()) { - ret << "Failed to recover mirror session entry to the state before " - "update operation."; - SWSS_RAISE_CRITICAL_STATE( - "Failed to recover mirror session entry to the state before update " - "operation."); - } - } - - return ret; +ReturnCode MirrorSessionManager::processUpdateRequest(const P4MirrorSessionAppDbEntry &app_db_entry, + P4MirrorSessionEntry *existing_mirror_session_entry) +{ + SWSS_LOG_ENTER(); + + // Check the existence of the mirror session in mirror manager and centralized + // mapper. + if (existing_mirror_session_entry == nullptr) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("existing_mirror_session_entry is nullptr"); + } + if (!m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_MIRROR_SESSION, existing_mirror_session_entry->mirror_session_key)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Mirror session with key " + << QuotedVar(existing_mirror_session_entry->mirror_session_key) + << " doesn't exist in centralized mapper"); + } + + P4MirrorSessionEntry mirror_session_entry_before_update(*existing_mirror_session_entry); + + // Because SAI mirror set API sets attr one at a time, it is possible attr + // updates fail in the middle. Up on failure, all successful operations need + // to be undone. + ReturnCode ret; + bool update_fail_in_middle = false; + if (!update_fail_in_middle && app_db_entry.has_port) + { + ret = setPort(app_db_entry.port, existing_mirror_session_entry); + if (!ret.ok()) + update_fail_in_middle = true; + } + if (!update_fail_in_middle && app_db_entry.has_src_ip) + { + ret = setSrcIp(app_db_entry.src_ip, existing_mirror_session_entry); + if (!ret.ok()) + update_fail_in_middle = true; + } + if (!update_fail_in_middle && app_db_entry.has_dst_ip) + { + ret = setDstIp(app_db_entry.dst_ip, existing_mirror_session_entry); + if (!ret.ok()) + update_fail_in_middle = true; + } + if (!update_fail_in_middle && app_db_entry.has_src_mac) + { + ret = setSrcMac(app_db_entry.src_mac, existing_mirror_session_entry); + if (!ret.ok()) + update_fail_in_middle = true; + } + if (!update_fail_in_middle && app_db_entry.has_dst_mac) + { + ret = setDstMac(app_db_entry.dst_mac, existing_mirror_session_entry); + if (!ret.ok()) + update_fail_in_middle = true; + } + if (!update_fail_in_middle && app_db_entry.has_ttl) + { + ret = setTtl(app_db_entry.ttl, existing_mirror_session_entry); + if (!ret.ok()) + update_fail_in_middle = true; + } + if (!update_fail_in_middle && app_db_entry.has_tos) + { + ret = setTos(app_db_entry.tos, existing_mirror_session_entry); + if (!ret.ok()) + update_fail_in_middle = true; + } + + if (update_fail_in_middle) + { + ReturnCode status = setMirrorSessionEntry(mirror_session_entry_before_update, existing_mirror_session_entry); + if (!status.ok()) + { + ret << "Failed to recover mirror session entry to the state before " + "update operation."; + SWSS_RAISE_CRITICAL_STATE("Failed to recover mirror session entry to the state before update " + "operation."); + } + } + + return ret; } -ReturnCode MirrorSessionManager::setPort( - const std::string& new_port_name, - P4MirrorSessionEntry* existing_mirror_session_entry) { - SWSS_LOG_ENTER(); +ReturnCode MirrorSessionManager::setPort(const std::string &new_port_name, + P4MirrorSessionEntry *existing_mirror_session_entry) +{ + SWSS_LOG_ENTER(); + + if (new_port_name == existing_mirror_session_entry->port) + { + return ReturnCode(); + } + + swss::Port new_port; + if (!gPortsOrch->getPort(new_port_name, new_port)) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Failed to get port info for port " << QuotedVar(new_port_name)); + } + if (new_port.m_type != Port::Type::PHY) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Port " << QuotedVar(new_port.m_alias) << "'s type " << new_port.m_type + << " is not physical and is invalid as destination " + "port for mirror packet."); + } + + sai_attribute_t attr; + attr.id = SAI_MIRROR_SESSION_ATTR_MONITOR_PORT; + attr.value.oid = new_port.m_port_id; + + // Call SAI API. + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_mirror_api->set_mirror_session_attribute(existing_mirror_session_entry->mirror_session_oid, &attr), + "Failed to set new port " << QuotedVar(new_port.m_alias) << " for mirror session " + << QuotedVar(existing_mirror_session_entry->mirror_session_key)); + + // Update ref count. + gPortsOrch->decreasePortRefCount(existing_mirror_session_entry->port); + gPortsOrch->increasePortRefCount(new_port.m_alias); + + // Update the entry in table + existing_mirror_session_entry->port = new_port_name; - if (new_port_name == existing_mirror_session_entry->port) { return ReturnCode(); - } - - swss::Port new_port; - if (!gPortsOrch->getPort(new_port_name, new_port)) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Failed to get port info for port " - << QuotedVar(new_port_name)); - } - if (new_port.m_type != Port::Type::PHY) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Port " << QuotedVar(new_port.m_alias) << "'s type " - << new_port.m_type - << " is not physical and is invalid as destination " - "port for mirror packet."); - } - - sai_attribute_t attr; - attr.id = SAI_MIRROR_SESSION_ATTR_MONITOR_PORT; - attr.value.oid = new_port.m_port_id; - - // Call SAI API. - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_mirror_api->set_mirror_session_attribute( - existing_mirror_session_entry->mirror_session_oid, &attr), - "Failed to set new port " - << QuotedVar(new_port.m_alias) << " for mirror session " - << QuotedVar(existing_mirror_session_entry->mirror_session_key)); - - // Update ref count. - gPortsOrch->decreasePortRefCount(existing_mirror_session_entry->port); - gPortsOrch->increasePortRefCount(new_port.m_alias); - - // Update the entry in table - existing_mirror_session_entry->port = new_port_name; - - return ReturnCode(); } -ReturnCode MirrorSessionManager::setSrcIp( - const swss::IpAddress& new_src_ip, - P4MirrorSessionEntry* existing_mirror_session_entry) { - SWSS_LOG_ENTER(); +ReturnCode MirrorSessionManager::setSrcIp(const swss::IpAddress &new_src_ip, + P4MirrorSessionEntry *existing_mirror_session_entry) +{ + SWSS_LOG_ENTER(); - if (new_src_ip == existing_mirror_session_entry->src_ip) { - return ReturnCode(); - } + if (new_src_ip == existing_mirror_session_entry->src_ip) + { + return ReturnCode(); + } - sai_attribute_t attr; - attr.id = SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS; - swss::copy(attr.value.ipaddr, new_src_ip); + sai_attribute_t attr; + attr.id = SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS; + swss::copy(attr.value.ipaddr, new_src_ip); - // Call SAI API. - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_mirror_api->set_mirror_session_attribute( - existing_mirror_session_entry->mirror_session_oid, &attr), - "Failed to set new src_ip " - << QuotedVar(new_src_ip.to_string()) << " for mirror session " - << QuotedVar(existing_mirror_session_entry->mirror_session_key)); + // Call SAI API. + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_mirror_api->set_mirror_session_attribute(existing_mirror_session_entry->mirror_session_oid, &attr), + "Failed to set new src_ip " << QuotedVar(new_src_ip.to_string()) << " for mirror session " + << QuotedVar(existing_mirror_session_entry->mirror_session_key)); - // Update the entry in table - existing_mirror_session_entry->src_ip = new_src_ip; + // Update the entry in table + existing_mirror_session_entry->src_ip = new_src_ip; - return ReturnCode(); + return ReturnCode(); } -ReturnCode MirrorSessionManager::setDstIp( - const swss::IpAddress& new_dst_ip, - P4MirrorSessionEntry* existing_mirror_session_entry) { - SWSS_LOG_ENTER(); +ReturnCode MirrorSessionManager::setDstIp(const swss::IpAddress &new_dst_ip, + P4MirrorSessionEntry *existing_mirror_session_entry) +{ + SWSS_LOG_ENTER(); - if (new_dst_ip == existing_mirror_session_entry->dst_ip) { - return ReturnCode(); - } + if (new_dst_ip == existing_mirror_session_entry->dst_ip) + { + return ReturnCode(); + } - sai_attribute_t attr; - attr.id = SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS; - swss::copy(attr.value.ipaddr, new_dst_ip); + sai_attribute_t attr; + attr.id = SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS; + swss::copy(attr.value.ipaddr, new_dst_ip); - // Call SAI API. - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_mirror_api->set_mirror_session_attribute( - existing_mirror_session_entry->mirror_session_oid, &attr), - "Failed to set new dst_ip " - << QuotedVar(new_dst_ip.to_string()) << " for mirror session " - << QuotedVar(existing_mirror_session_entry->mirror_session_key)); + // Call SAI API. + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_mirror_api->set_mirror_session_attribute(existing_mirror_session_entry->mirror_session_oid, &attr), + "Failed to set new dst_ip " << QuotedVar(new_dst_ip.to_string()) << " for mirror session " + << QuotedVar(existing_mirror_session_entry->mirror_session_key)); - // Update the entry in table - existing_mirror_session_entry->dst_ip = new_dst_ip; + // Update the entry in table + existing_mirror_session_entry->dst_ip = new_dst_ip; - return ReturnCode(); + return ReturnCode(); } -ReturnCode MirrorSessionManager::setSrcMac( - const swss::MacAddress& new_src_mac, - P4MirrorSessionEntry* existing_mirror_session_entry) { - SWSS_LOG_ENTER(); +ReturnCode MirrorSessionManager::setSrcMac(const swss::MacAddress &new_src_mac, + P4MirrorSessionEntry *existing_mirror_session_entry) +{ + SWSS_LOG_ENTER(); - if (new_src_mac == existing_mirror_session_entry->src_mac) { - return ReturnCode(); - } + if (new_src_mac == existing_mirror_session_entry->src_mac) + { + return ReturnCode(); + } - sai_attribute_t attr; - attr.id = SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS; - memcpy(attr.value.mac, new_src_mac.getMac(), sizeof(sai_mac_t)); + sai_attribute_t attr; + attr.id = SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS; + memcpy(attr.value.mac, new_src_mac.getMac(), sizeof(sai_mac_t)); - // Call SAI API. - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_mirror_api->set_mirror_session_attribute( - existing_mirror_session_entry->mirror_session_oid, &attr), - "Failed to set new src_mac " - << QuotedVar(new_src_mac.to_string()) << " for mirror session " - << QuotedVar(existing_mirror_session_entry->mirror_session_key)); + // Call SAI API. + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_mirror_api->set_mirror_session_attribute(existing_mirror_session_entry->mirror_session_oid, &attr), + "Failed to set new src_mac " << QuotedVar(new_src_mac.to_string()) << " for mirror session " + << QuotedVar(existing_mirror_session_entry->mirror_session_key)); - // Update the entry in table - existing_mirror_session_entry->src_mac = new_src_mac; + // Update the entry in table + existing_mirror_session_entry->src_mac = new_src_mac; - return ReturnCode(); + return ReturnCode(); } -ReturnCode MirrorSessionManager::setDstMac( - const swss::MacAddress& new_dst_mac, - P4MirrorSessionEntry* existing_mirror_session_entry) { - SWSS_LOG_ENTER(); +ReturnCode MirrorSessionManager::setDstMac(const swss::MacAddress &new_dst_mac, + P4MirrorSessionEntry *existing_mirror_session_entry) +{ + SWSS_LOG_ENTER(); - if (new_dst_mac == existing_mirror_session_entry->dst_mac) { - return ReturnCode(); - } + if (new_dst_mac == existing_mirror_session_entry->dst_mac) + { + return ReturnCode(); + } - sai_attribute_t attr; - attr.id = SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS; - memcpy(attr.value.mac, new_dst_mac.getMac(), sizeof(sai_mac_t)); + sai_attribute_t attr; + attr.id = SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS; + memcpy(attr.value.mac, new_dst_mac.getMac(), sizeof(sai_mac_t)); - // Call SAI API. - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_mirror_api->set_mirror_session_attribute( - existing_mirror_session_entry->mirror_session_oid, &attr), - "Failed to set new dst_mac " - << QuotedVar(new_dst_mac.to_string()) << " for mirror session " - << QuotedVar(existing_mirror_session_entry->mirror_session_key)); + // Call SAI API. + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_mirror_api->set_mirror_session_attribute(existing_mirror_session_entry->mirror_session_oid, &attr), + "Failed to set new dst_mac " << QuotedVar(new_dst_mac.to_string()) << " for mirror session " + << QuotedVar(existing_mirror_session_entry->mirror_session_key)); - // Update the entry in table - existing_mirror_session_entry->dst_mac = new_dst_mac; + // Update the entry in table + existing_mirror_session_entry->dst_mac = new_dst_mac; - return ReturnCode(); + return ReturnCode(); } -ReturnCode MirrorSessionManager::setTtl( - uint8_t new_ttl, P4MirrorSessionEntry* existing_mirror_session_entry) { - SWSS_LOG_ENTER(); +ReturnCode MirrorSessionManager::setTtl(uint8_t new_ttl, P4MirrorSessionEntry *existing_mirror_session_entry) +{ + SWSS_LOG_ENTER(); - if (new_ttl == existing_mirror_session_entry->ttl) { - return ReturnCode(); - } + if (new_ttl == existing_mirror_session_entry->ttl) + { + return ReturnCode(); + } - sai_attribute_t attr; - attr.id = SAI_MIRROR_SESSION_ATTR_TTL; - attr.value.u8 = new_ttl; + sai_attribute_t attr; + attr.id = SAI_MIRROR_SESSION_ATTR_TTL; + attr.value.u8 = new_ttl; - // Call SAI API. - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_mirror_api->set_mirror_session_attribute( - existing_mirror_session_entry->mirror_session_oid, &attr), - "Failed to set new ttl " - << new_ttl << " for mirror session " - << QuotedVar(existing_mirror_session_entry->mirror_session_key)); + // Call SAI API. + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_mirror_api->set_mirror_session_attribute(existing_mirror_session_entry->mirror_session_oid, &attr), + "Failed to set new ttl " << new_ttl << " for mirror session " + << QuotedVar(existing_mirror_session_entry->mirror_session_key)); - // Update the entry in table - existing_mirror_session_entry->ttl = new_ttl; + // Update the entry in table + existing_mirror_session_entry->ttl = new_ttl; - return ReturnCode(); + return ReturnCode(); } -ReturnCode MirrorSessionManager::setTos( - uint8_t new_tos, P4MirrorSessionEntry* existing_mirror_session_entry) { - SWSS_LOG_ENTER(); +ReturnCode MirrorSessionManager::setTos(uint8_t new_tos, P4MirrorSessionEntry *existing_mirror_session_entry) +{ + SWSS_LOG_ENTER(); - if (new_tos == existing_mirror_session_entry->tos) { - return ReturnCode(); - } + if (new_tos == existing_mirror_session_entry->tos) + { + return ReturnCode(); + } - sai_attribute_t attr; - attr.id = SAI_MIRROR_SESSION_ATTR_TOS; - attr.value.u8 = new_tos; + sai_attribute_t attr; + attr.id = SAI_MIRROR_SESSION_ATTR_TOS; + attr.value.u8 = new_tos; - // Call SAI API. - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_mirror_api->set_mirror_session_attribute( - existing_mirror_session_entry->mirror_session_oid, &attr), - "Failed to set new tos " - << new_tos << " for mirror session " - << QuotedVar(existing_mirror_session_entry->mirror_session_key)); + // Call SAI API. + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_mirror_api->set_mirror_session_attribute(existing_mirror_session_entry->mirror_session_oid, &attr), + "Failed to set new tos " << new_tos << " for mirror session " + << QuotedVar(existing_mirror_session_entry->mirror_session_key)); - // Update the entry in table - existing_mirror_session_entry->tos = new_tos; + // Update the entry in table + existing_mirror_session_entry->tos = new_tos; - return ReturnCode(); + return ReturnCode(); } -ReturnCode MirrorSessionManager::setMirrorSessionEntry( - const P4MirrorSessionEntry& intent_mirror_session_entry, - P4MirrorSessionEntry* existing_mirror_session_entry) { - SWSS_LOG_ENTER(); - - ReturnCode status; - - if (intent_mirror_session_entry.port != existing_mirror_session_entry->port) { - status = setPort(intent_mirror_session_entry.port, - existing_mirror_session_entry); - if (!status.ok()) return status; - } - if (intent_mirror_session_entry.src_ip != - existing_mirror_session_entry->src_ip) { - status = setSrcIp(intent_mirror_session_entry.src_ip, - existing_mirror_session_entry); - if (!status.ok()) return status; - } - if (intent_mirror_session_entry.dst_ip != - existing_mirror_session_entry->dst_ip) { - status = setDstIp(intent_mirror_session_entry.dst_ip, - existing_mirror_session_entry); - if (!status.ok()) return status; - } - if (intent_mirror_session_entry.src_mac != - existing_mirror_session_entry->src_mac) { - status = setSrcMac(intent_mirror_session_entry.src_mac, - existing_mirror_session_entry); - if (!status.ok()) return status; - } - if (intent_mirror_session_entry.dst_mac != - existing_mirror_session_entry->dst_mac) { - status = setDstMac(intent_mirror_session_entry.dst_mac, - existing_mirror_session_entry); - if (!status.ok()) return status; - } - if (intent_mirror_session_entry.ttl != existing_mirror_session_entry->ttl) { - status = - setTtl(intent_mirror_session_entry.ttl, existing_mirror_session_entry); - if (!status.ok()) return status; - } - if (intent_mirror_session_entry.tos != existing_mirror_session_entry->tos) { - status = - setTos(intent_mirror_session_entry.tos, existing_mirror_session_entry); - if (!status.ok()) return status; - } - - return status; +ReturnCode MirrorSessionManager::setMirrorSessionEntry(const P4MirrorSessionEntry &intent_mirror_session_entry, + P4MirrorSessionEntry *existing_mirror_session_entry) +{ + SWSS_LOG_ENTER(); + + ReturnCode status; + + if (intent_mirror_session_entry.port != existing_mirror_session_entry->port) + { + status = setPort(intent_mirror_session_entry.port, existing_mirror_session_entry); + if (!status.ok()) + return status; + } + if (intent_mirror_session_entry.src_ip != existing_mirror_session_entry->src_ip) + { + status = setSrcIp(intent_mirror_session_entry.src_ip, existing_mirror_session_entry); + if (!status.ok()) + return status; + } + if (intent_mirror_session_entry.dst_ip != existing_mirror_session_entry->dst_ip) + { + status = setDstIp(intent_mirror_session_entry.dst_ip, existing_mirror_session_entry); + if (!status.ok()) + return status; + } + if (intent_mirror_session_entry.src_mac != existing_mirror_session_entry->src_mac) + { + status = setSrcMac(intent_mirror_session_entry.src_mac, existing_mirror_session_entry); + if (!status.ok()) + return status; + } + if (intent_mirror_session_entry.dst_mac != existing_mirror_session_entry->dst_mac) + { + status = setDstMac(intent_mirror_session_entry.dst_mac, existing_mirror_session_entry); + if (!status.ok()) + return status; + } + if (intent_mirror_session_entry.ttl != existing_mirror_session_entry->ttl) + { + status = setTtl(intent_mirror_session_entry.ttl, existing_mirror_session_entry); + if (!status.ok()) + return status; + } + if (intent_mirror_session_entry.tos != existing_mirror_session_entry->tos) + { + status = setTos(intent_mirror_session_entry.tos, existing_mirror_session_entry); + if (!status.ok()) + return status; + } + + return status; } -ReturnCode MirrorSessionManager::processDeleteRequest( - const std::string& mirror_session_key) { - SWSS_LOG_ENTER(); - - const P4MirrorSessionEntry* mirror_session_entry = - getMirrorSessionEntry(mirror_session_key); - if (mirror_session_entry == nullptr) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Mirror session with key " - << QuotedVar(mirror_session_key) - << " does not exist in mirror session manager"); - } - - // Check if there is anything referring to the mirror session before deletion. - uint32_t ref_count; - if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_MIRROR_SESSION, - mirror_session_key, &ref_count)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Failed to get reference count for mirror session " - << QuotedVar(mirror_session_key)); - } - if (ref_count > 0) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_IN_USE) - << "Mirror session " - << QuotedVar(mirror_session_entry->mirror_session_key) - << " referenced by other objects (ref_count = " - << ref_count); - } - - // Call SAI API. - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_mirror_api->remove_mirror_session( - mirror_session_entry->mirror_session_oid), - "Failed to remove mirror session " - << QuotedVar(mirror_session_entry->mirror_session_key)); - - // On successful deletion, decrement ref count. - gPortsOrch->decreasePortRefCount(mirror_session_entry->port); - - // Delete the key to OID map from centralized mapper. - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_MIRROR_SESSION, - mirror_session_entry->mirror_session_key); - - // Delete entry from internal table. - m_mirrorSessionTable.erase(mirror_session_entry->mirror_session_key); - - return ReturnCode(); +ReturnCode MirrorSessionManager::processDeleteRequest(const std::string &mirror_session_key) +{ + SWSS_LOG_ENTER(); + + const P4MirrorSessionEntry *mirror_session_entry = getMirrorSessionEntry(mirror_session_key); + if (mirror_session_entry == nullptr) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Mirror session with key " << QuotedVar(mirror_session_key) + << " does not exist in mirror session manager"); + } + + // Check if there is anything referring to the mirror session before deletion. + uint32_t ref_count; + if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_MIRROR_SESSION, mirror_session_key, &ref_count)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Failed to get reference count for mirror session " + << QuotedVar(mirror_session_key)); + } + if (ref_count > 0) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_IN_USE) + << "Mirror session " << QuotedVar(mirror_session_entry->mirror_session_key) + << " referenced by other objects (ref_count = " << ref_count); + } + + // Call SAI API. + CHECK_ERROR_AND_LOG_AND_RETURN(sai_mirror_api->remove_mirror_session(mirror_session_entry->mirror_session_oid), + "Failed to remove mirror session " + << QuotedVar(mirror_session_entry->mirror_session_key)); + + // On successful deletion, decrement ref count. + gPortsOrch->decreasePortRefCount(mirror_session_entry->port); + + // Delete the key to OID map from centralized mapper. + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_MIRROR_SESSION, mirror_session_entry->mirror_session_key); + + // Delete entry from internal table. + m_mirrorSessionTable.erase(mirror_session_entry->mirror_session_key); + + return ReturnCode(); } -std::string MirrorSessionManager::verifyState( - const std::string& key, const std::vector& tuple) { - SWSS_LOG_ENTER(); - - auto pos = key.find_first_of(kTableKeyDelimiter); - if (pos == std::string::npos) { - return std::string("Invalid key: ") + key; - } - std::string p4rt_table = key.substr(0, pos); - std::string p4rt_key = key.substr(pos + 1); - if (p4rt_table != APP_P4RT_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - std::string table_name; - std::string key_content; - parseP4RTKey(p4rt_key, &table_name, &key_content); - if (table_name != APP_P4RT_MIRROR_SESSION_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - - ReturnCode status; - auto app_db_entry_or = - deserializeP4MirrorSessionAppDbEntry(key_content, tuple); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - std::stringstream msg; - msg << "Unable to deserialize key " << QuotedVar(key) << ": " - << status.message(); - return msg.str(); - } - auto& app_db_entry = *app_db_entry_or; - const std::string mirror_session_key = - KeyGenerator::generateMirrorSessionKey(app_db_entry.mirror_session_id); - auto* mirror_session_entry = getMirrorSessionEntry(mirror_session_key); - if (mirror_session_entry == nullptr) { - std::stringstream msg; - msg << "No entry found with key " << QuotedVar(key); - return msg.str(); - } - - std::string cache_result = - verifyStateCache(app_db_entry, mirror_session_entry); - std::string asic_db_result = verifyStateAsicDb(mirror_session_entry); - if (cache_result.empty()) { - return asic_db_result; - } - if (asic_db_result.empty()) { - return cache_result; - } - return cache_result + "; " + asic_db_result; +std::string MirrorSessionManager::verifyState(const std::string &key, const std::vector &tuple) +{ + SWSS_LOG_ENTER(); + + auto pos = key.find_first_of(kTableKeyDelimiter); + if (pos == std::string::npos) + { + return std::string("Invalid key: ") + key; + } + std::string p4rt_table = key.substr(0, pos); + std::string p4rt_key = key.substr(pos + 1); + if (p4rt_table != APP_P4RT_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } + std::string table_name; + std::string key_content; + parseP4RTKey(p4rt_key, &table_name, &key_content); + if (table_name != APP_P4RT_MIRROR_SESSION_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } + + ReturnCode status; + auto app_db_entry_or = deserializeP4MirrorSessionAppDbEntry(key_content, tuple); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + std::stringstream msg; + msg << "Unable to deserialize key " << QuotedVar(key) << ": " << status.message(); + return msg.str(); + } + auto &app_db_entry = *app_db_entry_or; + const std::string mirror_session_key = KeyGenerator::generateMirrorSessionKey(app_db_entry.mirror_session_id); + auto *mirror_session_entry = getMirrorSessionEntry(mirror_session_key); + if (mirror_session_entry == nullptr) + { + std::stringstream msg; + msg << "No entry found with key " << QuotedVar(key); + return msg.str(); + } + + std::string cache_result = verifyStateCache(app_db_entry, mirror_session_entry); + std::string asic_db_result = verifyStateAsicDb(mirror_session_entry); + if (cache_result.empty()) + { + return asic_db_result; + } + if (asic_db_result.empty()) + { + return cache_result; + } + return cache_result + "; " + asic_db_result; } -std::string MirrorSessionManager::verifyStateCache( - const P4MirrorSessionAppDbEntry& app_db_entry, - const P4MirrorSessionEntry* mirror_session_entry) { - const std::string mirror_session_key = - KeyGenerator::generateMirrorSessionKey(app_db_entry.mirror_session_id); - - if (mirror_session_entry->mirror_session_key != mirror_session_key) { - std::stringstream msg; - msg << "Mirror section with key " << QuotedVar(mirror_session_key) - << " does not match internal cache " - << QuotedVar(mirror_session_entry->mirror_session_key) - << " in mirror section manager."; - return msg.str(); - } - if (mirror_session_entry->mirror_session_id != - app_db_entry.mirror_session_id) { - std::stringstream msg; - msg << "Mirror section " << QuotedVar(app_db_entry.mirror_session_id) - << " does not match internal cache " - << QuotedVar(mirror_session_entry->mirror_session_id) - << " in mirror section manager."; - return msg.str(); - } - if (mirror_session_entry->port != app_db_entry.port) { - std::stringstream msg; - msg << "Mirror section " << QuotedVar(app_db_entry.mirror_session_id) - << " with port " << QuotedVar(app_db_entry.port) - << " does not match internal cache " - << QuotedVar(mirror_session_entry->port) - << " in mirror section manager."; - return msg.str(); - } - if (mirror_session_entry->src_ip.to_string() != - app_db_entry.src_ip.to_string()) { - std::stringstream msg; - msg << "Mirror section " << QuotedVar(app_db_entry.mirror_session_id) - << " with source IP " << app_db_entry.src_ip.to_string() - << " does not match internal cache " - << mirror_session_entry->src_ip.to_string() - << " in mirror section manager."; - return msg.str(); - } - if (mirror_session_entry->dst_ip.to_string() != - app_db_entry.dst_ip.to_string()) { - std::stringstream msg; - msg << "Mirror section " << QuotedVar(app_db_entry.mirror_session_id) - << " with dest IP " << app_db_entry.dst_ip.to_string() - << " does not match internal cache " - << mirror_session_entry->dst_ip.to_string() - << " in mirror section manager."; - return msg.str(); - } - if (mirror_session_entry->src_mac.to_string() != - app_db_entry.src_mac.to_string()) { - std::stringstream msg; - msg << "Mirror section " << QuotedVar(app_db_entry.mirror_session_id) - << " with source MAC " << app_db_entry.src_mac.to_string() - << " does not match internal cache " - << mirror_session_entry->src_mac.to_string() - << " in mirror section manager."; - return msg.str(); - } - if (mirror_session_entry->dst_mac.to_string() != - app_db_entry.dst_mac.to_string()) { - std::stringstream msg; - msg << "Mirror section " << QuotedVar(app_db_entry.mirror_session_id) - << " with dest MAC " << app_db_entry.dst_mac.to_string() - << " does not match internal cache " - << mirror_session_entry->dst_mac.to_string() - << " in mirror section manager."; - return msg.str(); - } - if (mirror_session_entry->ttl != app_db_entry.ttl) { - std::stringstream msg; - msg << "Mirror section " << QuotedVar(app_db_entry.mirror_session_id) - << " with ttl " << app_db_entry.ttl << " does not match internal cache " - << mirror_session_entry->ttl << " in mirror section manager."; - return msg.str(); - } - if (mirror_session_entry->tos != app_db_entry.tos) { - std::stringstream msg; - msg << "Mirror section " << QuotedVar(app_db_entry.mirror_session_id) - << " with tos " << app_db_entry.tos << " does not match internal cache " - << mirror_session_entry->tos << " in mirror section manager."; - return msg.str(); - } - - return m_p4OidMapper->verifyOIDMapping( - SAI_OBJECT_TYPE_MIRROR_SESSION, mirror_session_entry->mirror_session_key, - mirror_session_entry->mirror_session_oid); +std::string MirrorSessionManager::verifyStateCache(const P4MirrorSessionAppDbEntry &app_db_entry, + const P4MirrorSessionEntry *mirror_session_entry) +{ + const std::string mirror_session_key = KeyGenerator::generateMirrorSessionKey(app_db_entry.mirror_session_id); + + if (mirror_session_entry->mirror_session_key != mirror_session_key) + { + std::stringstream msg; + msg << "Mirror section with key " << QuotedVar(mirror_session_key) << " does not match internal cache " + << QuotedVar(mirror_session_entry->mirror_session_key) << " in mirror section manager."; + return msg.str(); + } + if (mirror_session_entry->mirror_session_id != app_db_entry.mirror_session_id) + { + std::stringstream msg; + msg << "Mirror section " << QuotedVar(app_db_entry.mirror_session_id) << " does not match internal cache " + << QuotedVar(mirror_session_entry->mirror_session_id) << " in mirror section manager."; + return msg.str(); + } + if (mirror_session_entry->port != app_db_entry.port) + { + std::stringstream msg; + msg << "Mirror section " << QuotedVar(app_db_entry.mirror_session_id) << " with port " + << QuotedVar(app_db_entry.port) << " does not match internal cache " + << QuotedVar(mirror_session_entry->port) << " in mirror section manager."; + return msg.str(); + } + if (mirror_session_entry->src_ip.to_string() != app_db_entry.src_ip.to_string()) + { + std::stringstream msg; + msg << "Mirror section " << QuotedVar(app_db_entry.mirror_session_id) << " with source IP " + << app_db_entry.src_ip.to_string() << " does not match internal cache " + << mirror_session_entry->src_ip.to_string() << " in mirror section manager."; + return msg.str(); + } + if (mirror_session_entry->dst_ip.to_string() != app_db_entry.dst_ip.to_string()) + { + std::stringstream msg; + msg << "Mirror section " << QuotedVar(app_db_entry.mirror_session_id) << " with dest IP " + << app_db_entry.dst_ip.to_string() << " does not match internal cache " + << mirror_session_entry->dst_ip.to_string() << " in mirror section manager."; + return msg.str(); + } + if (mirror_session_entry->src_mac.to_string() != app_db_entry.src_mac.to_string()) + { + std::stringstream msg; + msg << "Mirror section " << QuotedVar(app_db_entry.mirror_session_id) << " with source MAC " + << app_db_entry.src_mac.to_string() << " does not match internal cache " + << mirror_session_entry->src_mac.to_string() << " in mirror section manager."; + return msg.str(); + } + if (mirror_session_entry->dst_mac.to_string() != app_db_entry.dst_mac.to_string()) + { + std::stringstream msg; + msg << "Mirror section " << QuotedVar(app_db_entry.mirror_session_id) << " with dest MAC " + << app_db_entry.dst_mac.to_string() << " does not match internal cache " + << mirror_session_entry->dst_mac.to_string() << " in mirror section manager."; + return msg.str(); + } + if (mirror_session_entry->ttl != app_db_entry.ttl) + { + std::stringstream msg; + msg << "Mirror section " << QuotedVar(app_db_entry.mirror_session_id) << " with ttl " << app_db_entry.ttl + << " does not match internal cache " << mirror_session_entry->ttl << " in mirror section manager."; + return msg.str(); + } + if (mirror_session_entry->tos != app_db_entry.tos) + { + std::stringstream msg; + msg << "Mirror section " << QuotedVar(app_db_entry.mirror_session_id) << " with tos " << app_db_entry.tos + << " does not match internal cache " << mirror_session_entry->tos << " in mirror section manager."; + return msg.str(); + } + + return m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_MIRROR_SESSION, mirror_session_entry->mirror_session_key, + mirror_session_entry->mirror_session_oid); } -std::string MirrorSessionManager::verifyStateAsicDb( - const P4MirrorSessionEntry* mirror_session_entry) { - auto attrs_or = getSaiAttrs(*mirror_session_entry); - if (!attrs_or.ok()) { - return std::string("Failed to get SAI attrs: ") + - attrs_or.status().message(); - } - std::vector attrs = *attrs_or; - std::vector exp = - saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_MIRROR_SESSION, (uint32_t)attrs.size(), attrs.data(), - /*countOnly=*/false); - - swss::DBConnector db("ASIC_DB", 0); - swss::Table table(&db, "ASIC_STATE"); - std::string key = - sai_serialize_object_type(SAI_OBJECT_TYPE_MIRROR_SESSION) + ":" + - sai_serialize_object_id(mirror_session_entry->mirror_session_oid); - std::vector values; - if (!table.get(key, values)) { - return std::string("ASIC DB key not found ") + key; - } - - return verifyAttrs(values, exp, std::vector{}, - /*allow_unknown=*/false); +std::string MirrorSessionManager::verifyStateAsicDb(const P4MirrorSessionEntry *mirror_session_entry) +{ + auto attrs_or = getSaiAttrs(*mirror_session_entry); + if (!attrs_or.ok()) + { + return std::string("Failed to get SAI attrs: ") + attrs_or.status().message(); + } + std::vector attrs = *attrs_or; + std::vector exp = saimeta::SaiAttributeList::serialize_attr_list( + SAI_OBJECT_TYPE_MIRROR_SESSION, (uint32_t)attrs.size(), attrs.data(), + /*countOnly=*/false); + + swss::DBConnector db("ASIC_DB", 0); + swss::Table table(&db, "ASIC_STATE"); + std::string key = sai_serialize_object_type(SAI_OBJECT_TYPE_MIRROR_SESSION) + ":" + + sai_serialize_object_id(mirror_session_entry->mirror_session_oid); + std::vector values; + if (!table.get(key, values)) + { + return std::string("ASIC DB key not found ") + key; + } + + return verifyAttrs(values, exp, std::vector{}, + /*allow_unknown=*/false); } -} // namespace p4orch +} // namespace p4orch diff --git a/orchagent/p4orch/mirror_session_manager.h b/orchagent/p4orch/mirror_session_manager.h index e02f67372e5..7c2bf3b3b1a 100644 --- a/orchagent/p4orch/mirror_session_manager.h +++ b/orchagent/p4orch/mirror_session_manager.h @@ -12,143 +12,121 @@ #include "swss/ipaddress.h" #include "swss/macaddress.h" #include "swss/rediscommand.h" -extern "C" { +extern "C" +{ #include "sai.h" } #define MIRROR_SESSION_DEFAULT_IP_HDR_VER 4 #define GRE_PROTOCOL_ERSPAN 0x88be -namespace p4orch { -namespace test { +namespace p4orch +{ +namespace test +{ class MirrorSessionManagerTest; -} // namespace test - -struct P4MirrorSessionEntry { - P4MirrorSessionEntry(const std::string& mirror_session_key, - sai_object_id_t mirror_session_oid, - const std::string& mirror_session_id, - const std::string& port, const swss::IpAddress& src_ip, - const swss::IpAddress& dst_ip, - const swss::MacAddress& src_mac, - const swss::MacAddress& dst_mac, uint8_t ttl, - uint8_t tos) - : mirror_session_key(mirror_session_key), - mirror_session_oid(mirror_session_oid), - mirror_session_id(mirror_session_id), - port(port), - src_ip(src_ip), - dst_ip(dst_ip), - src_mac(src_mac), - dst_mac(dst_mac), - ttl(ttl), - tos(tos) {} - - P4MirrorSessionEntry(const P4MirrorSessionEntry&) = default; - - bool operator==(const P4MirrorSessionEntry& entry) const { - return mirror_session_key == entry.mirror_session_key && - mirror_session_oid == entry.mirror_session_oid && - mirror_session_id == entry.mirror_session_id && port == entry.port && - src_ip == entry.src_ip && dst_ip == entry.dst_ip && - src_mac == entry.src_mac && dst_mac == entry.dst_mac && - ttl == entry.ttl && tos == entry.tos; - } - - std::string mirror_session_key; - - // SAI OID associated with this entry. - sai_object_id_t mirror_session_oid = 0; - - // Match field in table - std::string mirror_session_id; - // Action parameters - std::string port; - swss::IpAddress src_ip; - swss::IpAddress dst_ip; - swss::MacAddress src_mac; - swss::MacAddress dst_mac; - uint8_t ttl = 0; - uint8_t tos = 0; +} // namespace test + +struct P4MirrorSessionEntry +{ + P4MirrorSessionEntry(const std::string &mirror_session_key, sai_object_id_t mirror_session_oid, + const std::string &mirror_session_id, const std::string &port, const swss::IpAddress &src_ip, + const swss::IpAddress &dst_ip, const swss::MacAddress &src_mac, + const swss::MacAddress &dst_mac, uint8_t ttl, uint8_t tos) + : mirror_session_key(mirror_session_key), mirror_session_oid(mirror_session_oid), + mirror_session_id(mirror_session_id), port(port), src_ip(src_ip), dst_ip(dst_ip), src_mac(src_mac), + dst_mac(dst_mac), ttl(ttl), tos(tos) + { + } + + P4MirrorSessionEntry(const P4MirrorSessionEntry &) = default; + + bool operator==(const P4MirrorSessionEntry &entry) const + { + return mirror_session_key == entry.mirror_session_key && mirror_session_oid == entry.mirror_session_oid && + mirror_session_id == entry.mirror_session_id && port == entry.port && src_ip == entry.src_ip && + dst_ip == entry.dst_ip && src_mac == entry.src_mac && dst_mac == entry.dst_mac && ttl == entry.ttl && + tos == entry.tos; + } + + std::string mirror_session_key; + + // SAI OID associated with this entry. + sai_object_id_t mirror_session_oid = 0; + + // Match field in table + std::string mirror_session_id; + // Action parameters + std::string port; + swss::IpAddress src_ip; + swss::IpAddress dst_ip; + swss::MacAddress src_mac; + swss::MacAddress dst_mac; + uint8_t ttl = 0; + uint8_t tos = 0; }; // MirrorSessionManager is responsible for programming mirror session intents in // APPL_DB:FIXED_MIRROR_SESSION_TABLE to ASIC_DB. -class MirrorSessionManager : public ObjectManagerInterface { - public: - MirrorSessionManager(P4OidMapper* p4oidMapper, - ResponsePublisherInterface* publisher) { - SWSS_LOG_ENTER(); - - assert(p4oidMapper != nullptr); - m_p4OidMapper = p4oidMapper; - assert(publisher != nullptr); - m_publisher = publisher; - } - - void enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) override; - - void drain() override; - - std::string verifyState( - const std::string& key, - const std::vector& tuple) override; - - ReturnCode getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) override; - - private: - ReturnCodeOr deserializeP4MirrorSessionAppDbEntry( - const std::string& key, - const std::vector& attributes); - - P4MirrorSessionEntry* getMirrorSessionEntry( - const std::string& mirror_session_key); - - ReturnCode processAddRequest(const P4MirrorSessionAppDbEntry& app_db_entry); - ReturnCode createMirrorSession(P4MirrorSessionEntry mirror_session_entry); - - ReturnCode processUpdateRequest( - const P4MirrorSessionAppDbEntry& app_db_entry, - P4MirrorSessionEntry* existing_mirror_session_entry); - ReturnCode setPort(const std::string& new_port, - P4MirrorSessionEntry* existing_mirror_session_entry); - ReturnCode setSrcIp(const swss::IpAddress& new_src_ip, - P4MirrorSessionEntry* existing_mirror_session_entry); - ReturnCode setDstIp(const swss::IpAddress& new_dst_ip, - P4MirrorSessionEntry* existing_mirror_session_entry); - ReturnCode setSrcMac(const swss::MacAddress& new_src_mac, - P4MirrorSessionEntry* existing_mirror_session_entry); - ReturnCode setDstMac(const swss::MacAddress& new_dst_mac, - P4MirrorSessionEntry* existing_mirror_session_entry); - ReturnCode setTtl(uint8_t new_ttl, - P4MirrorSessionEntry* existing_mirror_session_entry); - ReturnCode setTos(uint8_t new_tos, - P4MirrorSessionEntry* existing_mirror_session_entry); - ReturnCode setMirrorSessionEntry( - const P4MirrorSessionEntry& intent_mirror_session_entry, - P4MirrorSessionEntry* existing_mirror_session_entry); - - ReturnCode processDeleteRequest(const std::string& mirror_session_key); - - // state verification DB helper functions. Return err string or empty string. - std::string verifyStateCache( - const P4MirrorSessionAppDbEntry& app_db_entry, - const P4MirrorSessionEntry* mirror_session_entry); - std::string verifyStateAsicDb( - const P4MirrorSessionEntry* mirror_session_entry); - - std::unordered_map m_mirrorSessionTable; - - // Owners of pointers below must outlive this class's instance. - P4OidMapper* m_p4OidMapper; - ResponsePublisherInterface* m_publisher; - std::deque m_entries; - - // For test purpose only - friend class p4orch::test::MirrorSessionManagerTest; +class MirrorSessionManager : public ObjectManagerInterface +{ + public: + MirrorSessionManager(P4OidMapper *p4oidMapper, ResponsePublisherInterface *publisher) + { + SWSS_LOG_ENTER(); + + assert(p4oidMapper != nullptr); + m_p4OidMapper = p4oidMapper; + assert(publisher != nullptr); + m_publisher = publisher; + } + + void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; + + void drain() override; + + std::string verifyState(const std::string &key, const std::vector &tuple) override; + + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; + + private: + ReturnCodeOr deserializeP4MirrorSessionAppDbEntry( + const std::string &key, const std::vector &attributes); + + P4MirrorSessionEntry *getMirrorSessionEntry(const std::string &mirror_session_key); + + ReturnCode processAddRequest(const P4MirrorSessionAppDbEntry &app_db_entry); + ReturnCode createMirrorSession(P4MirrorSessionEntry mirror_session_entry); + + ReturnCode processUpdateRequest(const P4MirrorSessionAppDbEntry &app_db_entry, + P4MirrorSessionEntry *existing_mirror_session_entry); + ReturnCode setPort(const std::string &new_port, P4MirrorSessionEntry *existing_mirror_session_entry); + ReturnCode setSrcIp(const swss::IpAddress &new_src_ip, P4MirrorSessionEntry *existing_mirror_session_entry); + ReturnCode setDstIp(const swss::IpAddress &new_dst_ip, P4MirrorSessionEntry *existing_mirror_session_entry); + ReturnCode setSrcMac(const swss::MacAddress &new_src_mac, P4MirrorSessionEntry *existing_mirror_session_entry); + ReturnCode setDstMac(const swss::MacAddress &new_dst_mac, P4MirrorSessionEntry *existing_mirror_session_entry); + ReturnCode setTtl(uint8_t new_ttl, P4MirrorSessionEntry *existing_mirror_session_entry); + ReturnCode setTos(uint8_t new_tos, P4MirrorSessionEntry *existing_mirror_session_entry); + ReturnCode setMirrorSessionEntry(const P4MirrorSessionEntry &intent_mirror_session_entry, + P4MirrorSessionEntry *existing_mirror_session_entry); + + ReturnCode processDeleteRequest(const std::string &mirror_session_key); + + // state verification DB helper functions. Return err string or empty string. + std::string verifyStateCache(const P4MirrorSessionAppDbEntry &app_db_entry, + const P4MirrorSessionEntry *mirror_session_entry); + std::string verifyStateAsicDb(const P4MirrorSessionEntry *mirror_session_entry); + + std::unordered_map m_mirrorSessionTable; + + // Owners of pointers below must outlive this class's instance. + P4OidMapper *m_p4OidMapper; + ResponsePublisherInterface *m_publisher; + std::deque m_entries; + + // For test purpose only + friend class p4orch::test::MirrorSessionManagerTest; }; -} // namespace p4orch +} // namespace p4orch diff --git a/orchagent/p4orch/neighbor_manager.cpp b/orchagent/p4orch/neighbor_manager.cpp index 71729933a6f..f68f22a5450 100644 --- a/orchagent/p4orch/neighbor_manager.cpp +++ b/orchagent/p4orch/neighbor_manager.cpp @@ -14,7 +14,8 @@ #include "sai_serialize.h" #include "swssnet.h" #include "table.h" -extern "C" { +extern "C" +{ #include "sai.h" } @@ -22,539 +23,555 @@ using ::p4orch::kTableKeyDelimiter; extern sai_object_id_t gSwitchId; -extern sai_neighbor_api_t* sai_neighbor_api; +extern sai_neighbor_api_t *sai_neighbor_api; -extern CrmOrch* gCrmOrch; +extern CrmOrch *gCrmOrch; -namespace { +namespace +{ -std::vector getSaiAttrs( - const P4NeighborEntry& neighbor_entry) { - std::vector attrs; - sai_attribute_t attr; - attr.id = SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS; - memcpy(attr.value.mac, neighbor_entry.dst_mac_address.getMac(), - sizeof(sai_mac_t)); - attrs.push_back(attr); +std::vector getSaiAttrs(const P4NeighborEntry &neighbor_entry) +{ + std::vector attrs; + sai_attribute_t attr; + attr.id = SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS; + memcpy(attr.value.mac, neighbor_entry.dst_mac_address.getMac(), sizeof(sai_mac_t)); + attrs.push_back(attr); - // Do not program host route. - // This is mainly for neighbor with IPv6 link-local addresses. - attr.id = SAI_NEIGHBOR_ENTRY_ATTR_NO_HOST_ROUTE; - attr.value.booldata = true; - attrs.push_back(attr); + // Do not program host route. + // This is mainly for neighbor with IPv6 link-local addresses. + attr.id = SAI_NEIGHBOR_ENTRY_ATTR_NO_HOST_ROUTE; + attr.value.booldata = true; + attrs.push_back(attr); - return attrs; + return attrs; } -} // namespace +} // namespace -P4NeighborEntry::P4NeighborEntry(const std::string& router_interface_id, - const swss::IpAddress& ip_address, - const swss::MacAddress& mac_address) { - SWSS_LOG_ENTER(); +P4NeighborEntry::P4NeighborEntry(const std::string &router_interface_id, const swss::IpAddress &ip_address, + const swss::MacAddress &mac_address) +{ + SWSS_LOG_ENTER(); - router_intf_id = router_interface_id; - neighbor_id = ip_address; - dst_mac_address = mac_address; + router_intf_id = router_interface_id; + neighbor_id = ip_address; + dst_mac_address = mac_address; - router_intf_key = KeyGenerator::generateRouterInterfaceKey(router_intf_id); - neighbor_key = KeyGenerator::generateNeighborKey(router_intf_id, neighbor_id); + router_intf_key = KeyGenerator::generateRouterInterfaceKey(router_intf_id); + neighbor_key = KeyGenerator::generateNeighborKey(router_intf_id, neighbor_id); } -ReturnCodeOr NeighborManager::getSaiEntry( - const P4NeighborEntry& neighbor_entry) { - const std::string& router_intf_key = neighbor_entry.router_intf_key; - sai_object_id_t router_intf_oid; - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key, - &router_intf_oid)) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Router intf key " << QuotedVar(router_intf_key) - << " does not exist in certralized map"); - } - - sai_neighbor_entry_t neigh_entry; - neigh_entry.switch_id = gSwitchId; - copy(neigh_entry.ip_address, neighbor_entry.neighbor_id); - neigh_entry.rif_id = router_intf_oid; - - return neigh_entry; +ReturnCodeOr NeighborManager::getSaiEntry(const P4NeighborEntry &neighbor_entry) +{ + const std::string &router_intf_key = neighbor_entry.router_intf_key; + sai_object_id_t router_intf_oid; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key, &router_intf_oid)) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Router intf key " << QuotedVar(router_intf_key) + << " does not exist in certralized map"); + } + + sai_neighbor_entry_t neigh_entry; + neigh_entry.switch_id = gSwitchId; + copy(neigh_entry.ip_address, neighbor_entry.neighbor_id); + neigh_entry.rif_id = router_intf_oid; + + return neigh_entry; } ReturnCodeOr NeighborManager::deserializeNeighborEntry( - const std::string& key, - const std::vector& attributes) { - SWSS_LOG_ENTER(); - - P4NeighborAppDbEntry app_db_entry = {}; - std::string ip_address; - try { - nlohmann::json j = nlohmann::json::parse(key); - app_db_entry.router_intf_id = - j[prependMatchField(p4orch::kRouterInterfaceId)]; - ip_address = j[prependMatchField(p4orch::kNeighborId)]; - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to deserialize key"; - } - try { - app_db_entry.neighbor_id = swss::IpAddress(ip_address); - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid IP address " << QuotedVar(ip_address) << " of field " - << QuotedVar(prependMatchField(p4orch::kNeighborId)); - } - - for (const auto& it : attributes) { - const auto& field = fvField(it); - const auto& value = fvValue(it); - if (field == prependParamField(p4orch::kDstMac)) { - try { - app_db_entry.dst_mac_address = swss::MacAddress(value); - } catch (std::exception& ex) { + const std::string &key, const std::vector &attributes) +{ + SWSS_LOG_ENTER(); + + P4NeighborAppDbEntry app_db_entry = {}; + std::string ip_address; + try + { + nlohmann::json j = nlohmann::json::parse(key); + app_db_entry.router_intf_id = j[prependMatchField(p4orch::kRouterInterfaceId)]; + ip_address = j[prependMatchField(p4orch::kNeighborId)]; + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Failed to deserialize key"; + } + try + { + app_db_entry.neighbor_id = swss::IpAddress(ip_address); + } + catch (std::exception &ex) + { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid MAC address " << QuotedVar(value) << " of field " - << QuotedVar(field); - } - app_db_entry.is_set_dst_mac = true; - } else if (field != p4orch::kAction && - field != p4orch::kControllerMetadata) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unexpected field " << QuotedVar(field) << " in table entry"; - } - } - - return app_db_entry; -} + << "Invalid IP address " << QuotedVar(ip_address) << " of field " + << QuotedVar(prependMatchField(p4orch::kNeighborId)); + } -ReturnCode NeighborManager::validateNeighborAppDbEntry( - const P4NeighborAppDbEntry& app_db_entry) { - SWSS_LOG_ENTER(); - // Perform generic APP DB entry validations. Operation specific validations - // will be done by the respective request process methods. - - const std::string router_intf_key = - KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_intf_id); - if (!m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - router_intf_key)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Router interface id " << QuotedVar(app_db_entry.router_intf_id) - << " does not exist"; - } - - if ((app_db_entry.is_set_dst_mac) && - (app_db_entry.dst_mac_address.to_string() == "00:00:00:00:00:00")) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid dst mac address " - << QuotedVar(app_db_entry.dst_mac_address.to_string()); - } - - return ReturnCode(); + for (const auto &it : attributes) + { + const auto &field = fvField(it); + const auto &value = fvValue(it); + if (field == prependParamField(p4orch::kDstMac)) + { + try + { + app_db_entry.dst_mac_address = swss::MacAddress(value); + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid MAC address " << QuotedVar(value) << " of field " << QuotedVar(field); + } + app_db_entry.is_set_dst_mac = true; + } + else if (field != p4orch::kAction && field != p4orch::kControllerMetadata) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unexpected field " << QuotedVar(field) << " in table entry"; + } + } + + return app_db_entry; } -P4NeighborEntry* NeighborManager::getNeighborEntry( - const std::string& neighbor_key) { - SWSS_LOG_ENTER(); +ReturnCode NeighborManager::validateNeighborAppDbEntry(const P4NeighborAppDbEntry &app_db_entry) +{ + SWSS_LOG_ENTER(); + // Perform generic APP DB entry validations. Operation specific validations + // will be done by the respective request process methods. + + const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_intf_id); + if (!m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Router interface id " << QuotedVar(app_db_entry.router_intf_id) << " does not exist"; + } - if (m_neighborTable.find(neighbor_key) == m_neighborTable.end()) - return nullptr; + if ((app_db_entry.is_set_dst_mac) && (app_db_entry.dst_mac_address.to_string() == "00:00:00:00:00:00")) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid dst mac address " << QuotedVar(app_db_entry.dst_mac_address.to_string()); + } - return &m_neighborTable[neighbor_key]; + return ReturnCode(); } -ReturnCode NeighborManager::createNeighbor(P4NeighborEntry& neighbor_entry) { - SWSS_LOG_ENTER(); - - const std::string& neighbor_key = neighbor_entry.neighbor_key; - if (getNeighborEntry(neighbor_key) != nullptr) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_EXISTS) - << "Neighbor entry with key " - << QuotedVar(neighbor_key) << " already exists"); - } - - if (m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Neighbor entry with key " << QuotedVar(neighbor_key) - << " already exists in centralized map"); - } - - ASSIGN_OR_RETURN(neighbor_entry.neigh_entry, getSaiEntry(neighbor_entry)); - auto attrs = getSaiAttrs(neighbor_entry); - - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_neighbor_api->create_neighbor_entry( - &neighbor_entry.neigh_entry, static_cast(attrs.size()), - attrs.data()), - "Failed to create neighbor with key " << QuotedVar(neighbor_key)); - - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - neighbor_entry.router_intf_key); - if (neighbor_entry.neighbor_id.isV4()) { - gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV4_NEIGHBOR); - } else { - gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV6_NEIGHBOR); - } - - m_neighborTable[neighbor_key] = neighbor_entry; - m_p4OidMapper->setDummyOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key); - return ReturnCode(); +P4NeighborEntry *NeighborManager::getNeighborEntry(const std::string &neighbor_key) +{ + SWSS_LOG_ENTER(); + + if (m_neighborTable.find(neighbor_key) == m_neighborTable.end()) + return nullptr; + + return &m_neighborTable[neighbor_key]; } -ReturnCode NeighborManager::removeNeighbor(const std::string& neighbor_key) { - SWSS_LOG_ENTER(); - - auto* neighbor_entry = getNeighborEntry(neighbor_key); - if (neighbor_entry == nullptr) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Neighbor with key " << QuotedVar(neighbor_key) - << " does not exist"); - } - - uint32_t ref_count; - if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, - &ref_count)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Failed to get reference count of neighbor with key " - << QuotedVar(neighbor_key)); - } - if (ref_count > 0) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Neighbor with key " << QuotedVar(neighbor_key) - << " referenced by other objects (ref_count = " - << ref_count << ")"); - } - - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_neighbor_api->remove_neighbor_entry(&neighbor_entry->neigh_entry), - "Failed to remove neighbor with key " << QuotedVar(neighbor_key)); - - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - neighbor_entry->router_intf_key); - if (neighbor_entry->neighbor_id.isV4()) { - gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV4_NEIGHBOR); - } else { - gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV6_NEIGHBOR); - } - - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key); - m_neighborTable.erase(neighbor_key); - return ReturnCode(); +ReturnCode NeighborManager::createNeighbor(P4NeighborEntry &neighbor_entry) +{ + SWSS_LOG_ENTER(); + + const std::string &neighbor_key = neighbor_entry.neighbor_key; + if (getNeighborEntry(neighbor_key) != nullptr) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_EXISTS) + << "Neighbor entry with key " << QuotedVar(neighbor_key) << " already exists"); + } + + if (m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Neighbor entry with key " << QuotedVar(neighbor_key) + << " already exists in centralized map"); + } + + ASSIGN_OR_RETURN(neighbor_entry.neigh_entry, getSaiEntry(neighbor_entry)); + auto attrs = getSaiAttrs(neighbor_entry); + + CHECK_ERROR_AND_LOG_AND_RETURN(sai_neighbor_api->create_neighbor_entry( + &neighbor_entry.neigh_entry, static_cast(attrs.size()), attrs.data()), + "Failed to create neighbor with key " << QuotedVar(neighbor_key)); + + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, neighbor_entry.router_intf_key); + if (neighbor_entry.neighbor_id.isV4()) + { + gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV4_NEIGHBOR); + } + else + { + gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV6_NEIGHBOR); + } + + m_neighborTable[neighbor_key] = neighbor_entry; + m_p4OidMapper->setDummyOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key); + return ReturnCode(); } -ReturnCode NeighborManager::setDstMacAddress( - P4NeighborEntry* neighbor_entry, const swss::MacAddress& mac_address) { - SWSS_LOG_ENTER(); +ReturnCode NeighborManager::removeNeighbor(const std::string &neighbor_key) +{ + SWSS_LOG_ENTER(); - if (neighbor_entry->dst_mac_address == mac_address) return ReturnCode(); + auto *neighbor_entry = getNeighborEntry(neighbor_key); + if (neighbor_entry == nullptr) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Neighbor with key " << QuotedVar(neighbor_key) << " does not exist"); + } - sai_attribute_t neigh_attr; - neigh_attr.id = SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS; - memcpy(neigh_attr.value.mac, mac_address.getMac(), sizeof(sai_mac_t)); - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_neighbor_api->set_neighbor_entry_attribute( - &neighbor_entry->neigh_entry, &neigh_attr), - "Failed to set mac address " << QuotedVar(mac_address.to_string()) - << " for neighbor with key " - << QuotedVar(neighbor_entry->neighbor_key)); + uint32_t ref_count; + if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, &ref_count)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Failed to get reference count of neighbor with key " + << QuotedVar(neighbor_key)); + } + if (ref_count > 0) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Neighbor with key " << QuotedVar(neighbor_key) + << " referenced by other objects (ref_count = " << ref_count << ")"); + } + + CHECK_ERROR_AND_LOG_AND_RETURN(sai_neighbor_api->remove_neighbor_entry(&neighbor_entry->neigh_entry), + "Failed to remove neighbor with key " << QuotedVar(neighbor_key)); + + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, neighbor_entry->router_intf_key); + if (neighbor_entry->neighbor_id.isV4()) + { + gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV4_NEIGHBOR); + } + else + { + gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV6_NEIGHBOR); + } - neighbor_entry->dst_mac_address = mac_address; - return ReturnCode(); + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key); + m_neighborTable.erase(neighbor_key); + return ReturnCode(); } -ReturnCode NeighborManager::processAddRequest( - const P4NeighborAppDbEntry& app_db_entry, const std::string& neighbor_key) { - SWSS_LOG_ENTER(); - - // Perform operation specific validations. - if (!app_db_entry.is_set_dst_mac) { - LOG_ERROR_AND_RETURN( - ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << p4orch::kDstMac - << " is mandatory to create neighbor entry. Failed to create " - "neighbor with key " - << QuotedVar(neighbor_key)); - } - - P4NeighborEntry neighbor_entry(app_db_entry.router_intf_id, - app_db_entry.neighbor_id, - app_db_entry.dst_mac_address); - auto status = createNeighbor(neighbor_entry); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to create neighbor with key %s", - QuotedVar(neighbor_key).c_str()); - } - - return status; +ReturnCode NeighborManager::setDstMacAddress(P4NeighborEntry *neighbor_entry, const swss::MacAddress &mac_address) +{ + SWSS_LOG_ENTER(); + + if (neighbor_entry->dst_mac_address == mac_address) + return ReturnCode(); + + sai_attribute_t neigh_attr; + neigh_attr.id = SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS; + memcpy(neigh_attr.value.mac, mac_address.getMac(), sizeof(sai_mac_t)); + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_neighbor_api->set_neighbor_entry_attribute(&neighbor_entry->neigh_entry, &neigh_attr), + "Failed to set mac address " << QuotedVar(mac_address.to_string()) << " for neighbor with key " + << QuotedVar(neighbor_entry->neighbor_key)); + + neighbor_entry->dst_mac_address = mac_address; + return ReturnCode(); } -ReturnCode NeighborManager::processUpdateRequest( - const P4NeighborAppDbEntry& app_db_entry, P4NeighborEntry* neighbor_entry) { - SWSS_LOG_ENTER(); +ReturnCode NeighborManager::processAddRequest(const P4NeighborAppDbEntry &app_db_entry, const std::string &neighbor_key) +{ + SWSS_LOG_ENTER(); + + // Perform operation specific validations. + if (!app_db_entry.is_set_dst_mac) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << p4orch::kDstMac + << " is mandatory to create neighbor entry. Failed to create " + "neighbor with key " + << QuotedVar(neighbor_key)); + } - if (app_db_entry.is_set_dst_mac) { - auto status = - setDstMacAddress(neighbor_entry, app_db_entry.dst_mac_address); - if (!status.ok()) { - SWSS_LOG_ERROR( - "Failed to set destination mac address for neighbor with key %s", - QuotedVar(neighbor_entry->neighbor_key).c_str()); - return status; + P4NeighborEntry neighbor_entry(app_db_entry.router_intf_id, app_db_entry.neighbor_id, app_db_entry.dst_mac_address); + auto status = createNeighbor(neighbor_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to create neighbor with key %s", QuotedVar(neighbor_key).c_str()); } - } - return ReturnCode(); + return status; } -ReturnCode NeighborManager::processDeleteRequest( - const std::string& neighbor_key) { - SWSS_LOG_ENTER(); +ReturnCode NeighborManager::processUpdateRequest(const P4NeighborAppDbEntry &app_db_entry, + P4NeighborEntry *neighbor_entry) +{ + SWSS_LOG_ENTER(); + + if (app_db_entry.is_set_dst_mac) + { + auto status = setDstMacAddress(neighbor_entry, app_db_entry.dst_mac_address); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to set destination mac address for neighbor with key %s", + QuotedVar(neighbor_entry->neighbor_key).c_str()); + return status; + } + } - auto status = removeNeighbor(neighbor_key); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to remove neighbor with key %s", - QuotedVar(neighbor_key).c_str()); - } + return ReturnCode(); +} - return status; +ReturnCode NeighborManager::processDeleteRequest(const std::string &neighbor_key) +{ + SWSS_LOG_ENTER(); + + auto status = removeNeighbor(neighbor_key); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to remove neighbor with key %s", QuotedVar(neighbor_key).c_str()); + } + + return status; } -ReturnCode NeighborManager::getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) { - std::string router_intf_id, neighbor_id; - swss::IpAddress neighbor; - - try { - nlohmann::json j = nlohmann::json::parse(json_key); - if (j.find(prependMatchField(p4orch::kRouterInterfaceId)) != j.end()) { - router_intf_id = j.at(prependMatchField(p4orch::kRouterInterfaceId)) - .get(); - if (j.find(prependMatchField(p4orch::kNeighborId)) != j.end()) { - neighbor_id = - j.at(prependMatchField(p4orch::kNeighborId)).get(); - neighbor = swss::IpAddress(neighbor_id); - object_key = - KeyGenerator::generateNeighborKey(router_intf_id, neighbor); - object_type = SAI_OBJECT_TYPE_NEIGHBOR_ENTRY; - return ReturnCode(); - } else { - SWSS_LOG_ERROR( - "%s match parameter absent: required for dependent object query", - p4orch::kNeighborId); - } - } else { - SWSS_LOG_ERROR( - "%s match parameter absent: required for dependent object query", - p4orch::kRouterInterfaceId); - } - } catch (std::exception& ex) { - SWSS_LOG_ERROR("json_key parse error"); - } - - return StatusCode::SWSS_RC_INVALID_PARAM; +ReturnCode NeighborManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) +{ + std::string router_intf_id, neighbor_id; + swss::IpAddress neighbor; + + try + { + nlohmann::json j = nlohmann::json::parse(json_key); + if (j.find(prependMatchField(p4orch::kRouterInterfaceId)) != j.end()) + { + router_intf_id = j.at(prependMatchField(p4orch::kRouterInterfaceId)).get(); + if (j.find(prependMatchField(p4orch::kNeighborId)) != j.end()) + { + neighbor_id = j.at(prependMatchField(p4orch::kNeighborId)).get(); + neighbor = swss::IpAddress(neighbor_id); + object_key = KeyGenerator::generateNeighborKey(router_intf_id, neighbor); + object_type = SAI_OBJECT_TYPE_NEIGHBOR_ENTRY; + return ReturnCode(); + } + else + { + SWSS_LOG_ERROR("%s match parameter absent: required for dependent object query", p4orch::kNeighborId); + } + } + else + { + SWSS_LOG_ERROR("%s match parameter absent: required for dependent object query", + p4orch::kRouterInterfaceId); + } + } + catch (std::exception &ex) + { + SWSS_LOG_ERROR("json_key parse error"); + } + + return StatusCode::SWSS_RC_INVALID_PARAM; +} + +void NeighborManager::enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) +{ + m_entries.push_back(entry); } -void NeighborManager::enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) { - m_entries.push_back(entry); +void NeighborManager::drain() +{ + SWSS_LOG_ENTER(); + + for (const auto &key_op_fvs_tuple : m_entries) + { + std::string table_name; + std::string db_key; + parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &db_key); + const std::vector &attributes = kfvFieldsValues(key_op_fvs_tuple); + + ReturnCode status; + auto app_db_entry_or = deserializeNeighborEntry(db_key, attributes); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", + QuotedVar(table_name + ":" + db_key).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + auto &app_db_entry = *app_db_entry_or; + + status = validateNeighborAppDbEntry(app_db_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Validation failed for Neighbor APP DB entry with key %s: %s", + QuotedVar(table_name + ":" + db_key).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(app_db_entry.router_intf_id, app_db_entry.neighbor_id); + + const std::string &operation = kfvOp(key_op_fvs_tuple); + if (operation == SET_COMMAND) + { + auto *neighbor_entry = getNeighborEntry(neighbor_key); + if (neighbor_entry == nullptr) + { + // Create neighbor + status = processAddRequest(app_db_entry, neighbor_key); + } + else + { + // Modify existing neighbor + status = processUpdateRequest(app_db_entry, neighbor_entry); + } + } + else if (operation == DEL_COMMAND) + { + // Delete neighbor + status = processDeleteRequest(neighbor_key); + } + else + { + status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Unknown operation type " << QuotedVar(operation); + SWSS_LOG_ERROR("%s", status.message().c_str()); + } + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), status, + /*replace=*/true); + } + m_entries.clear(); } -void NeighborManager::drain() { - SWSS_LOG_ENTER(); +std::string NeighborManager::verifyState(const std::string &key, const std::vector &tuple) +{ + SWSS_LOG_ENTER(); - for (const auto& key_op_fvs_tuple : m_entries) { + auto pos = key.find_first_of(kTableKeyDelimiter); + if (pos == std::string::npos) + { + return std::string("Invalid key: ") + key; + } + std::string p4rt_table = key.substr(0, pos); + std::string p4rt_key = key.substr(pos + 1); + if (p4rt_table != APP_P4RT_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } std::string table_name; - std::string db_key; - parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &db_key); - const std::vector& attributes = - kfvFieldsValues(key_op_fvs_tuple); + std::string key_content; + parseP4RTKey(p4rt_key, &table_name, &key_content); + if (table_name != APP_P4RT_NEIGHBOR_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } ReturnCode status; - auto app_db_entry_or = deserializeNeighborEntry(db_key, attributes); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", - QuotedVar(table_name + ":" + db_key).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - auto& app_db_entry = *app_db_entry_or; - - status = validateNeighborAppDbEntry(app_db_entry); - if (!status.ok()) { - SWSS_LOG_ERROR( - "Validation failed for Neighbor APP DB entry with key %s: %s", - QuotedVar(table_name + ":" + db_key).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - app_db_entry.router_intf_id, app_db_entry.neighbor_id); - - const std::string& operation = kfvOp(key_op_fvs_tuple); - if (operation == SET_COMMAND) { - auto* neighbor_entry = getNeighborEntry(neighbor_key); - if (neighbor_entry == nullptr) { - // Create neighbor - status = processAddRequest(app_db_entry, neighbor_key); - } else { - // Modify existing neighbor - status = processUpdateRequest(app_db_entry, neighbor_entry); - } - } else if (operation == DEL_COMMAND) { - // Delete neighbor - status = processDeleteRequest(neighbor_key); - } else { - status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown operation type " << QuotedVar(operation); - SWSS_LOG_ERROR("%s", status.message().c_str()); - } - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - } - m_entries.clear(); -} + auto app_db_entry_or = deserializeNeighborEntry(key_content, tuple); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + std::stringstream msg; + msg << "Unable to deserialize key " << QuotedVar(key) << ": " << status.message(); + return msg.str(); + } + auto &app_db_entry = *app_db_entry_or; + + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(app_db_entry.router_intf_id, app_db_entry.neighbor_id); + auto *neighbor_entry = getNeighborEntry(neighbor_key); + if (neighbor_entry == nullptr) + { + std::stringstream msg; + msg << "No entry found with key " << QuotedVar(key); + return msg.str(); + } -std::string NeighborManager::verifyState( - const std::string& key, const std::vector& tuple) { - SWSS_LOG_ENTER(); - - auto pos = key.find_first_of(kTableKeyDelimiter); - if (pos == std::string::npos) { - return std::string("Invalid key: ") + key; - } - std::string p4rt_table = key.substr(0, pos); - std::string p4rt_key = key.substr(pos + 1); - if (p4rt_table != APP_P4RT_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - std::string table_name; - std::string key_content; - parseP4RTKey(p4rt_key, &table_name, &key_content); - if (table_name != APP_P4RT_NEIGHBOR_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - - ReturnCode status; - auto app_db_entry_or = deserializeNeighborEntry(key_content, tuple); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - std::stringstream msg; - msg << "Unable to deserialize key " << QuotedVar(key) << ": " - << status.message(); - return msg.str(); - } - auto& app_db_entry = *app_db_entry_or; - - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - app_db_entry.router_intf_id, app_db_entry.neighbor_id); - auto* neighbor_entry = getNeighborEntry(neighbor_key); - if (neighbor_entry == nullptr) { - std::stringstream msg; - msg << "No entry found with key " << QuotedVar(key); - return msg.str(); - } - - std::string cache_result = verifyStateCache(app_db_entry, neighbor_entry); - std::string asic_db_result = verifyStateAsicDb(neighbor_entry); - if (cache_result.empty()) { - return asic_db_result; - } - if (asic_db_result.empty()) { - return cache_result; - } - return cache_result + "; " + asic_db_result; + std::string cache_result = verifyStateCache(app_db_entry, neighbor_entry); + std::string asic_db_result = verifyStateAsicDb(neighbor_entry); + if (cache_result.empty()) + { + return asic_db_result; + } + if (asic_db_result.empty()) + { + return cache_result; + } + return cache_result + "; " + asic_db_result; } -std::string NeighborManager::verifyStateCache( - const P4NeighborAppDbEntry& app_db_entry, - const P4NeighborEntry* neighbor_entry) { - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - app_db_entry.router_intf_id, app_db_entry.neighbor_id); - ReturnCode status = validateNeighborAppDbEntry(app_db_entry); - if (!status.ok()) { - std::stringstream msg; - msg << "Validation failed for neighbor DB entry with key " - << QuotedVar(neighbor_key) << ": " << status.message(); - return msg.str(); - } - - if (neighbor_entry->router_intf_id != app_db_entry.router_intf_id) { - std::stringstream msg; - msg << "Neighbor " << QuotedVar(neighbor_key) << " with ritf ID " - << QuotedVar(app_db_entry.router_intf_id) - << " does not match internal cache " - << QuotedVar(neighbor_entry->router_intf_id) << " in neighbor manager."; - return msg.str(); - } - if (neighbor_entry->neighbor_id.to_string() != - app_db_entry.neighbor_id.to_string()) { - std::stringstream msg; - msg << "Neighbor " << QuotedVar(neighbor_key) << " with neighbor ID " - << app_db_entry.neighbor_id.to_string() - << " does not match internal cache " - << neighbor_entry->neighbor_id.to_string() << " in neighbor manager."; - return msg.str(); - } - if (neighbor_entry->dst_mac_address.to_string() != - app_db_entry.dst_mac_address.to_string()) { - std::stringstream msg; - msg << "Neighbor " << QuotedVar(neighbor_key) << " with dest MAC " - << app_db_entry.dst_mac_address.to_string() - << " does not match internal cache " - << neighbor_entry->dst_mac_address.to_string() - << " in neighbor manager."; - return msg.str(); - } - if (neighbor_entry->router_intf_key != - KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_intf_id)) { - std::stringstream msg; - msg << "Neighbor " << QuotedVar(neighbor_key) - << " does not match internal cache on ritf key " - << QuotedVar(neighbor_entry->router_intf_key) - << " in neighbor manager."; - return msg.str(); - } - if (neighbor_entry->neighbor_key != neighbor_key) { - std::stringstream msg; - msg << "Neighbor " << QuotedVar(neighbor_key) - << " does not match internal cache on neighbor key " - << QuotedVar(neighbor_entry->neighbor_key) << " in neighbor manager."; - return msg.str(); - } - return ""; +std::string NeighborManager::verifyStateCache(const P4NeighborAppDbEntry &app_db_entry, + const P4NeighborEntry *neighbor_entry) +{ + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(app_db_entry.router_intf_id, app_db_entry.neighbor_id); + ReturnCode status = validateNeighborAppDbEntry(app_db_entry); + if (!status.ok()) + { + std::stringstream msg; + msg << "Validation failed for neighbor DB entry with key " << QuotedVar(neighbor_key) << ": " + << status.message(); + return msg.str(); + } + + if (neighbor_entry->router_intf_id != app_db_entry.router_intf_id) + { + std::stringstream msg; + msg << "Neighbor " << QuotedVar(neighbor_key) << " with ritf ID " << QuotedVar(app_db_entry.router_intf_id) + << " does not match internal cache " << QuotedVar(neighbor_entry->router_intf_id) + << " in neighbor manager."; + return msg.str(); + } + if (neighbor_entry->neighbor_id.to_string() != app_db_entry.neighbor_id.to_string()) + { + std::stringstream msg; + msg << "Neighbor " << QuotedVar(neighbor_key) << " with neighbor ID " << app_db_entry.neighbor_id.to_string() + << " does not match internal cache " << neighbor_entry->neighbor_id.to_string() << " in neighbor manager."; + return msg.str(); + } + if (neighbor_entry->dst_mac_address.to_string() != app_db_entry.dst_mac_address.to_string()) + { + std::stringstream msg; + msg << "Neighbor " << QuotedVar(neighbor_key) << " with dest MAC " << app_db_entry.dst_mac_address.to_string() + << " does not match internal cache " << neighbor_entry->dst_mac_address.to_string() + << " in neighbor manager."; + return msg.str(); + } + if (neighbor_entry->router_intf_key != KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_intf_id)) + { + std::stringstream msg; + msg << "Neighbor " << QuotedVar(neighbor_key) << " does not match internal cache on ritf key " + << QuotedVar(neighbor_entry->router_intf_key) << " in neighbor manager."; + return msg.str(); + } + if (neighbor_entry->neighbor_key != neighbor_key) + { + std::stringstream msg; + msg << "Neighbor " << QuotedVar(neighbor_key) << " does not match internal cache on neighbor key " + << QuotedVar(neighbor_entry->neighbor_key) << " in neighbor manager."; + return msg.str(); + } + return ""; } -std::string NeighborManager::verifyStateAsicDb( - const P4NeighborEntry* neighbor_entry) { - auto sai_entry_or = getSaiEntry(*neighbor_entry); - if (!sai_entry_or.ok()) { - return std::string("Failed to get SAI entry: ") + - sai_entry_or.status().message(); - } - sai_neighbor_entry_t sai_entry = *sai_entry_or; - auto attrs = getSaiAttrs(*neighbor_entry); - std::vector exp = - saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, (uint32_t)attrs.size(), attrs.data(), - /*countOnly=*/false); - - swss::DBConnector db("ASIC_DB", 0); - swss::Table table(&db, "ASIC_STATE"); - std::string key = sai_serialize_object_type(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY) + - ":" + sai_serialize_neighbor_entry(sai_entry); - std::vector values; - if (!table.get(key, values)) { - return std::string("ASIC DB key not found ") + key; - } - - return verifyAttrs(values, exp, std::vector{}, - /*allow_unknown=*/false); +std::string NeighborManager::verifyStateAsicDb(const P4NeighborEntry *neighbor_entry) +{ + auto sai_entry_or = getSaiEntry(*neighbor_entry); + if (!sai_entry_or.ok()) + { + return std::string("Failed to get SAI entry: ") + sai_entry_or.status().message(); + } + sai_neighbor_entry_t sai_entry = *sai_entry_or; + auto attrs = getSaiAttrs(*neighbor_entry); + std::vector exp = saimeta::SaiAttributeList::serialize_attr_list( + SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, (uint32_t)attrs.size(), attrs.data(), + /*countOnly=*/false); + + swss::DBConnector db("ASIC_DB", 0); + swss::Table table(&db, "ASIC_STATE"); + std::string key = + sai_serialize_object_type(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY) + ":" + sai_serialize_neighbor_entry(sai_entry); + std::vector values; + if (!table.get(key, values)) + { + return std::string("ASIC DB key not found ") + key; + } + + return verifyAttrs(values, exp, std::vector{}, + /*allow_unknown=*/false); } diff --git a/orchagent/p4orch/neighbor_manager.h b/orchagent/p4orch/neighbor_manager.h index d04f97f7400..229dcc41d11 100644 --- a/orchagent/p4orch/neighbor_manager.h +++ b/orchagent/p4orch/neighbor_manager.h @@ -13,76 +13,67 @@ #include "p4orch/router_interface_manager.h" #include "response_publisher_interface.h" #include "return_code.h" -extern "C" { +extern "C" +{ #include "sai.h" } -struct P4NeighborEntry { - std::string router_intf_id; - swss::IpAddress neighbor_id; - swss::MacAddress dst_mac_address; - std::string router_intf_key; - std::string neighbor_key; - sai_neighbor_entry_t neigh_entry; +struct P4NeighborEntry +{ + std::string router_intf_id; + swss::IpAddress neighbor_id; + swss::MacAddress dst_mac_address; + std::string router_intf_key; + std::string neighbor_key; + sai_neighbor_entry_t neigh_entry; - P4NeighborEntry() = default; - P4NeighborEntry(const std::string& router_interface_id, - const swss::IpAddress& ip_address, - const swss::MacAddress& mac_address); + P4NeighborEntry() = default; + P4NeighborEntry(const std::string &router_interface_id, const swss::IpAddress &ip_address, + const swss::MacAddress &mac_address); }; // P4NeighborTable: Neighbor key string, P4NeighborEntry typedef std::unordered_map P4NeighborTable; -class NeighborManager : public ObjectManagerInterface { - public: - NeighborManager(P4OidMapper* p4oidMapper, - ResponsePublisherInterface* publisher) { - SWSS_LOG_ENTER(); +class NeighborManager : public ObjectManagerInterface +{ + public: + NeighborManager(P4OidMapper *p4oidMapper, ResponsePublisherInterface *publisher) + { + SWSS_LOG_ENTER(); - assert(p4oidMapper != nullptr); - m_p4OidMapper = p4oidMapper; - assert(publisher != nullptr); - m_publisher = publisher; - } - virtual ~NeighborManager() = default; + assert(p4oidMapper != nullptr); + m_p4OidMapper = p4oidMapper; + assert(publisher != nullptr); + m_publisher = publisher; + } + virtual ~NeighborManager() = default; - void enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) override; - void drain() override; - std::string verifyState( - const std::string& key, - const std::vector& tuple) override; - ReturnCode getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) override; + void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; + void drain() override; + std::string verifyState(const std::string &key, const std::vector &tuple) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; - private: - ReturnCodeOr deserializeNeighborEntry( - const std::string& key, - const std::vector& attributes); - ReturnCode validateNeighborAppDbEntry( - const P4NeighborAppDbEntry& app_db_entry); - P4NeighborEntry* getNeighborEntry(const std::string& neighbor_key); - ReturnCode createNeighbor(P4NeighborEntry& neighbor_entry); - ReturnCode removeNeighbor(const std::string& neighbor_key); - ReturnCode setDstMacAddress(P4NeighborEntry* neighbor_entry, - const swss::MacAddress& mac_address); - ReturnCode processAddRequest(const P4NeighborAppDbEntry& app_db_entry, - const std::string& neighbor_key); - ReturnCode processUpdateRequest(const P4NeighborAppDbEntry& app_db_entry, - P4NeighborEntry* neighbor_entry); - ReturnCode processDeleteRequest(const std::string& neighbor_key); - std::string verifyStateCache(const P4NeighborAppDbEntry& app_db_entry, - const P4NeighborEntry* neighbor_entry); - std::string verifyStateAsicDb(const P4NeighborEntry* neighbor_entry); - ReturnCodeOr getSaiEntry( - const P4NeighborEntry& neighbor_entry); + private: + ReturnCodeOr deserializeNeighborEntry(const std::string &key, + const std::vector &attributes); + ReturnCode validateNeighborAppDbEntry(const P4NeighborAppDbEntry &app_db_entry); + P4NeighborEntry *getNeighborEntry(const std::string &neighbor_key); + ReturnCode createNeighbor(P4NeighborEntry &neighbor_entry); + ReturnCode removeNeighbor(const std::string &neighbor_key); + ReturnCode setDstMacAddress(P4NeighborEntry *neighbor_entry, const swss::MacAddress &mac_address); + ReturnCode processAddRequest(const P4NeighborAppDbEntry &app_db_entry, const std::string &neighbor_key); + ReturnCode processUpdateRequest(const P4NeighborAppDbEntry &app_db_entry, P4NeighborEntry *neighbor_entry); + ReturnCode processDeleteRequest(const std::string &neighbor_key); + std::string verifyStateCache(const P4NeighborAppDbEntry &app_db_entry, const P4NeighborEntry *neighbor_entry); + std::string verifyStateAsicDb(const P4NeighborEntry *neighbor_entry); + ReturnCodeOr getSaiEntry(const P4NeighborEntry &neighbor_entry); - P4OidMapper* m_p4OidMapper; - P4NeighborTable m_neighborTable; - ResponsePublisherInterface* m_publisher; - std::deque m_entries; + P4OidMapper *m_p4OidMapper; + P4NeighborTable m_neighborTable; + ResponsePublisherInterface *m_publisher; + std::deque m_entries; - friend class NeighborManagerTest; + friend class NeighborManagerTest; }; diff --git a/orchagent/p4orch/next_hop_manager.cpp b/orchagent/p4orch/next_hop_manager.cpp index a8f72807819..f55c83534ae 100644 --- a/orchagent/p4orch/next_hop_manager.cpp +++ b/orchagent/p4orch/next_hop_manager.cpp @@ -15,649 +15,672 @@ #include "sai_serialize.h" #include "swssnet.h" #include "table.h" -extern "C" { +extern "C" +{ #include "sai.h" } using ::p4orch::kTableKeyDelimiter; extern sai_object_id_t gSwitchId; -extern sai_next_hop_api_t* sai_next_hop_api; -extern CrmOrch* gCrmOrch; -extern P4Orch* gP4Orch; - -P4NextHopEntry::P4NextHopEntry(const std::string& next_hop_id, - const std::string& router_interface_id, - const std::string& gre_tunnel_id, - const swss::IpAddress& neighbor_id) - : next_hop_id(next_hop_id), - router_interface_id(router_interface_id), - gre_tunnel_id(gre_tunnel_id), - neighbor_id(neighbor_id) { - SWSS_LOG_ENTER(); - next_hop_key = KeyGenerator::generateNextHopKey(next_hop_id); +extern sai_next_hop_api_t *sai_next_hop_api; +extern CrmOrch *gCrmOrch; +extern P4Orch *gP4Orch; + +P4NextHopEntry::P4NextHopEntry(const std::string &next_hop_id, const std::string &router_interface_id, + const std::string &gre_tunnel_id, const swss::IpAddress &neighbor_id) + : next_hop_id(next_hop_id), router_interface_id(router_interface_id), gre_tunnel_id(gre_tunnel_id), + neighbor_id(neighbor_id) +{ + SWSS_LOG_ENTER(); + next_hop_key = KeyGenerator::generateNextHopKey(next_hop_id); } -namespace { - -ReturnCode validateAppDbEntry(const P4NextHopAppDbEntry& app_db_entry) { - // TODO(b/225242372): remove kSetNexthop action after P4RT and Orion update - // naming - if (app_db_entry.action_str != p4orch::kSetIpNexthop && - app_db_entry.action_str != p4orch::kSetNexthop && - app_db_entry.action_str != p4orch::kSetTunnelNexthop) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid action " << QuotedVar(app_db_entry.action_str) - << " of Nexthop App DB entry"; - } - if (app_db_entry.action_str == p4orch::kSetIpNexthop && - app_db_entry.neighbor_id.isZero()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Missing field " - << QuotedVar(prependParamField(p4orch::kNeighborId)) - << " for action " << QuotedVar(p4orch::kSetIpNexthop) - << " in table entry"; - } - // TODO(b/225242372): remove kSetNexthop action after P4RT and Orion update - // naming - if (app_db_entry.action_str == p4orch::kSetIpNexthop || - app_db_entry.action_str == p4orch::kSetNexthop) { - if (!app_db_entry.gre_tunnel_id.empty()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unexpected field " - << QuotedVar(prependParamField(p4orch::kTunnelId)) - << " for action " << QuotedVar(p4orch::kSetIpNexthop) - << " in table entry"; - } - if (app_db_entry.router_interface_id.empty()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Missing field " - << QuotedVar(prependParamField(p4orch::kRouterInterfaceId)) - << " for action " << QuotedVar(p4orch::kSetIpNexthop) - << " in table entry"; - } - } - - if (app_db_entry.action_str == p4orch::kSetTunnelNexthop) { - if (!app_db_entry.router_interface_id.empty()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unexpected field " - << QuotedVar(prependParamField(p4orch::kRouterInterfaceId)) - << " for action " << QuotedVar(p4orch::kSetTunnelNexthop) - << " in table entry"; - } - if (app_db_entry.gre_tunnel_id.empty()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Missing field " - << QuotedVar(prependParamField(p4orch::kTunnelId)) - << " for action " << QuotedVar(p4orch::kSetTunnelNexthop) - << " in table entry"; - } - } - return ReturnCode(); +namespace +{ + +ReturnCode validateAppDbEntry(const P4NextHopAppDbEntry &app_db_entry) +{ + // TODO(b/225242372): remove kSetNexthop action after P4RT and Orion update + // naming + if (app_db_entry.action_str != p4orch::kSetIpNexthop && app_db_entry.action_str != p4orch::kSetNexthop && + app_db_entry.action_str != p4orch::kSetTunnelNexthop) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid action " << QuotedVar(app_db_entry.action_str) << " of Nexthop App DB entry"; + } + if (app_db_entry.action_str == p4orch::kSetIpNexthop && app_db_entry.neighbor_id.isZero()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Missing field " << QuotedVar(prependParamField(p4orch::kNeighborId)) << " for action " + << QuotedVar(p4orch::kSetIpNexthop) << " in table entry"; + } + // TODO(b/225242372): remove kSetNexthop action after P4RT and Orion update + // naming + if (app_db_entry.action_str == p4orch::kSetIpNexthop || app_db_entry.action_str == p4orch::kSetNexthop) + { + if (!app_db_entry.gre_tunnel_id.empty()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unexpected field " << QuotedVar(prependParamField(p4orch::kTunnelId)) << " for action " + << QuotedVar(p4orch::kSetIpNexthop) << " in table entry"; + } + if (app_db_entry.router_interface_id.empty()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Missing field " << QuotedVar(prependParamField(p4orch::kRouterInterfaceId)) << " for action " + << QuotedVar(p4orch::kSetIpNexthop) << " in table entry"; + } + } + + if (app_db_entry.action_str == p4orch::kSetTunnelNexthop) + { + if (!app_db_entry.router_interface_id.empty()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unexpected field " << QuotedVar(prependParamField(p4orch::kRouterInterfaceId)) << " for action " + << QuotedVar(p4orch::kSetTunnelNexthop) << " in table entry"; + } + if (app_db_entry.gre_tunnel_id.empty()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Missing field " << QuotedVar(prependParamField(p4orch::kTunnelId)) << " for action " + << QuotedVar(p4orch::kSetTunnelNexthop) << " in table entry"; + } + } + return ReturnCode(); } -} // namespace - -ReturnCodeOr> NextHopManager::getSaiAttrs( - const P4NextHopEntry& next_hop_entry) { - std::vector next_hop_attrs; - sai_attribute_t next_hop_attr; - - if (!next_hop_entry.gre_tunnel_id.empty()) { - // From centralized mapper and, get gre tunnel that next hop depends on. Get - // underlay router interface from gre tunnel manager, - sai_object_id_t tunnel_oid; - if (!m_p4OidMapper->getOID( - SAI_OBJECT_TYPE_TUNNEL, - KeyGenerator::generateTunnelKey(next_hop_entry.gre_tunnel_id), - &tunnel_oid)) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "GRE Tunnel " - << QuotedVar(next_hop_entry.gre_tunnel_id) - << " does not exist"); - } - - next_hop_attr.id = SAI_NEXT_HOP_ATTR_TYPE; - next_hop_attr.value.s32 = SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP; - next_hop_attrs.push_back(next_hop_attr); +} // namespace + +ReturnCodeOr> NextHopManager::getSaiAttrs(const P4NextHopEntry &next_hop_entry) +{ + std::vector next_hop_attrs; + sai_attribute_t next_hop_attr; + + if (!next_hop_entry.gre_tunnel_id.empty()) + { + // From centralized mapper and, get gre tunnel that next hop depends on. Get + // underlay router interface from gre tunnel manager, + sai_object_id_t tunnel_oid; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_TUNNEL, + KeyGenerator::generateTunnelKey(next_hop_entry.gre_tunnel_id), &tunnel_oid)) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "GRE Tunnel " << QuotedVar(next_hop_entry.gre_tunnel_id) << " does not exist"); + } + + next_hop_attr.id = SAI_NEXT_HOP_ATTR_TYPE; + next_hop_attr.value.s32 = SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP; + next_hop_attrs.push_back(next_hop_attr); + + next_hop_attr.id = SAI_NEXT_HOP_ATTR_TUNNEL_ID; + next_hop_attr.value.oid = tunnel_oid; + next_hop_attrs.push_back(next_hop_attr); + } + else + { + // From centralized mapper, get OID of router interface that next hop + // depends on. + sai_object_id_t rif_oid; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(next_hop_entry.router_interface_id), + &rif_oid)) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Router intf " << QuotedVar(next_hop_entry.router_interface_id) + << " does not exist"); + } + next_hop_attr.id = SAI_NEXT_HOP_ATTR_TYPE; + next_hop_attr.value.s32 = SAI_NEXT_HOP_TYPE_IP; + next_hop_attrs.push_back(next_hop_attr); + + next_hop_attr.id = SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID; + next_hop_attr.value.oid = rif_oid; + next_hop_attrs.push_back(next_hop_attr); + } - next_hop_attr.id = SAI_NEXT_HOP_ATTR_TUNNEL_ID; - next_hop_attr.value.oid = tunnel_oid; - next_hop_attrs.push_back(next_hop_attr); - } else { - // From centralized mapper, get OID of router interface that next hop - // depends on. - sai_object_id_t rif_oid; - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey( - next_hop_entry.router_interface_id), - &rif_oid)) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Router intf " - << QuotedVar(next_hop_entry.router_interface_id) - << " does not exist"); - } - next_hop_attr.id = SAI_NEXT_HOP_ATTR_TYPE; - next_hop_attr.value.s32 = SAI_NEXT_HOP_TYPE_IP; + next_hop_attr.id = SAI_NEXT_HOP_ATTR_IP; + swss::copy(next_hop_attr.value.ipaddr, next_hop_entry.neighbor_id); next_hop_attrs.push_back(next_hop_attr); - next_hop_attr.id = SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID; - next_hop_attr.value.oid = rif_oid; - next_hop_attrs.push_back(next_hop_attr); - } + return next_hop_attrs; +} - next_hop_attr.id = SAI_NEXT_HOP_ATTR_IP; - swss::copy(next_hop_attr.value.ipaddr, next_hop_entry.neighbor_id); - next_hop_attrs.push_back(next_hop_attr); +ReturnCode NextHopManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) +{ + std::string value; + + try + { + nlohmann::json j = nlohmann::json::parse(json_key); + if (j.find(prependMatchField(p4orch::kNexthopId)) != j.end()) + { + value = j.at(prependMatchField(p4orch::kNexthopId)).get(); + object_key = KeyGenerator::generateNextHopKey(value); + object_type = SAI_OBJECT_TYPE_NEXT_HOP; + return ReturnCode(); + } + else + { + SWSS_LOG_ERROR("%s match parameter absent: required for dependent object query", p4orch::kNexthopId); + } + } + catch (std::exception &ex) + { + SWSS_LOG_ERROR("json_key parse error"); + } - return next_hop_attrs; + return StatusCode::SWSS_RC_INVALID_PARAM; } -ReturnCode NextHopManager::getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) { - std::string value; - - try { - nlohmann::json j = nlohmann::json::parse(json_key); - if (j.find(prependMatchField(p4orch::kNexthopId)) != j.end()) { - value = j.at(prependMatchField(p4orch::kNexthopId)).get(); - object_key = KeyGenerator::generateNextHopKey(value); - object_type = SAI_OBJECT_TYPE_NEXT_HOP; - return ReturnCode(); - } else { - SWSS_LOG_ERROR( - "%s match parameter absent: required for dependent object query", - p4orch::kNexthopId); - } - } catch (std::exception& ex) { - SWSS_LOG_ERROR("json_key parse error"); - } - - return StatusCode::SWSS_RC_INVALID_PARAM; +void NextHopManager::enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) +{ + m_entries.push_back(entry); } -void NextHopManager::enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) { - m_entries.push_back(entry); +void NextHopManager::drain() +{ + SWSS_LOG_ENTER(); + + for (const auto &key_op_fvs_tuple : m_entries) + { + std::string table_name; + std::string key; + parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &key); + const std::vector &attributes = kfvFieldsValues(key_op_fvs_tuple); + + ReturnCode status; + auto app_db_entry_or = deserializeP4NextHopAppDbEntry(key, attributes); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", + QuotedVar(table_name + ":" + key).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + auto &app_db_entry = *app_db_entry_or; + + const std::string next_hop_key = KeyGenerator::generateNextHopKey(app_db_entry.next_hop_id); + + // Fulfill the operation. + const std::string &operation = kfvOp(key_op_fvs_tuple); + if (operation == SET_COMMAND) + { + status = validateAppDbEntry(app_db_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Validation failed for Nexthop APP DB entry with key %s: %s", + QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + auto *next_hop_entry = getNextHopEntry(next_hop_key); + if (next_hop_entry == nullptr) + { + // Create new next hop. + status = processAddRequest(app_db_entry); + } + else + { + // Modify existing next hop. + status = processUpdateRequest(app_db_entry, next_hop_entry); + } + } + else if (operation == DEL_COMMAND) + { + // Delete next hop. + status = processDeleteRequest(next_hop_key); + } + else + { + status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Unknown operation type " << QuotedVar(operation); + SWSS_LOG_ERROR("%s", status.message().c_str()); + } + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), status, + /*replace=*/true); + } + m_entries.clear(); } -void NextHopManager::drain() { - SWSS_LOG_ENTER(); +P4NextHopEntry *NextHopManager::getNextHopEntry(const std::string &next_hop_key) +{ + SWSS_LOG_ENTER(); - for (const auto& key_op_fvs_tuple : m_entries) { - std::string table_name; - std::string key; - parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &key); - const std::vector& attributes = - kfvFieldsValues(key_op_fvs_tuple); + auto it = m_nextHopTable.find(next_hop_key); - ReturnCode status; - auto app_db_entry_or = deserializeP4NextHopAppDbEntry(key, attributes); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", - QuotedVar(table_name + ":" + key).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - auto& app_db_entry = *app_db_entry_or; - - const std::string next_hop_key = - KeyGenerator::generateNextHopKey(app_db_entry.next_hop_id); - - // Fulfill the operation. - const std::string& operation = kfvOp(key_op_fvs_tuple); - if (operation == SET_COMMAND) { - status = validateAppDbEntry(app_db_entry); - if (!status.ok()) { - SWSS_LOG_ERROR( - "Validation failed for Nexthop APP DB entry with key %s: %s", - QuotedVar(kfvKey(key_op_fvs_tuple)).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - auto* next_hop_entry = getNextHopEntry(next_hop_key); - if (next_hop_entry == nullptr) { - // Create new next hop. - status = processAddRequest(app_db_entry); - } else { - // Modify existing next hop. - status = processUpdateRequest(app_db_entry, next_hop_entry); - } - } else if (operation == DEL_COMMAND) { - // Delete next hop. - status = processDeleteRequest(next_hop_key); - } else { - status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown operation type " << QuotedVar(operation); - SWSS_LOG_ERROR("%s", status.message().c_str()); - } - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - } - m_entries.clear(); + if (it == m_nextHopTable.end()) + { + return nullptr; + } + else + { + return &it->second; + } } -P4NextHopEntry* NextHopManager::getNextHopEntry( - const std::string& next_hop_key) { - SWSS_LOG_ENTER(); +ReturnCodeOr NextHopManager::deserializeP4NextHopAppDbEntry( + const std::string &key, const std::vector &attributes) +{ + SWSS_LOG_ENTER(); - auto it = m_nextHopTable.find(next_hop_key); + P4NextHopAppDbEntry app_db_entry = {}; + app_db_entry.neighbor_id = swss::IpAddress("0.0.0.0"); - if (it == m_nextHopTable.end()) { - return nullptr; - } else { - return &it->second; - } -} + try + { + nlohmann::json j = nlohmann::json::parse(key); + app_db_entry.next_hop_id = j[prependMatchField(p4orch::kNexthopId)]; + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Failed to deserialize next hop id"; + } -ReturnCodeOr -NextHopManager::deserializeP4NextHopAppDbEntry( - const std::string& key, - const std::vector& attributes) { - SWSS_LOG_ENTER(); - - P4NextHopAppDbEntry app_db_entry = {}; - app_db_entry.neighbor_id = swss::IpAddress("0.0.0.0"); - - try { - nlohmann::json j = nlohmann::json::parse(key); - app_db_entry.next_hop_id = j[prependMatchField(p4orch::kNexthopId)]; - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to deserialize next hop id"; - } - - for (const auto& it : attributes) { - const auto& field = fvField(it); - const auto& value = fvValue(it); - if (field == prependParamField(p4orch::kRouterInterfaceId)) { - app_db_entry.router_interface_id = value; - } else if (field == prependParamField(p4orch::kNeighborId)) { - try { - app_db_entry.neighbor_id = swss::IpAddress(value); - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid IP address " << QuotedVar(value) << " of field " - << QuotedVar(field); - } - } else if (field == prependParamField(p4orch::kTunnelId)) { - app_db_entry.gre_tunnel_id = value; - } else if (field == p4orch::kAction) { - app_db_entry.action_str = value; - } else if (field != p4orch::kControllerMetadata) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unexpected field " << QuotedVar(field) << " in table entry"; - } - } - - return app_db_entry; + for (const auto &it : attributes) + { + const auto &field = fvField(it); + const auto &value = fvValue(it); + if (field == prependParamField(p4orch::kRouterInterfaceId)) + { + app_db_entry.router_interface_id = value; + } + else if (field == prependParamField(p4orch::kNeighborId)) + { + try + { + app_db_entry.neighbor_id = swss::IpAddress(value); + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid IP address " << QuotedVar(value) << " of field " << QuotedVar(field); + } + } + else if (field == prependParamField(p4orch::kTunnelId)) + { + app_db_entry.gre_tunnel_id = value; + } + else if (field == p4orch::kAction) + { + app_db_entry.action_str = value; + } + else if (field != p4orch::kControllerMetadata) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unexpected field " << QuotedVar(field) << " in table entry"; + } + } + + return app_db_entry; } -ReturnCode NextHopManager::processAddRequest( - const P4NextHopAppDbEntry& app_db_entry) { - SWSS_LOG_ENTER(); - - P4NextHopEntry next_hop_entry( - app_db_entry.next_hop_id, app_db_entry.router_interface_id, - app_db_entry.gre_tunnel_id, app_db_entry.neighbor_id); - auto status = createNextHop(next_hop_entry); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to create next hop with key %s", - QuotedVar(next_hop_entry.next_hop_key).c_str()); - } - return status; +ReturnCode NextHopManager::processAddRequest(const P4NextHopAppDbEntry &app_db_entry) +{ + SWSS_LOG_ENTER(); + + P4NextHopEntry next_hop_entry(app_db_entry.next_hop_id, app_db_entry.router_interface_id, + app_db_entry.gre_tunnel_id, app_db_entry.neighbor_id); + auto status = createNextHop(next_hop_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to create next hop with key %s", QuotedVar(next_hop_entry.next_hop_key).c_str()); + } + return status; } -ReturnCode NextHopManager::createNextHop(P4NextHopEntry& next_hop_entry) { - SWSS_LOG_ENTER(); - - // Check the existence of the next hop in next hop manager and centralized - // mapper. - if (getNextHopEntry(next_hop_entry.next_hop_key) != nullptr) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_EXISTS) - << "Next hop with key " - << QuotedVar(next_hop_entry.next_hop_key) - << " already exists in next hop manager"); - } - if (m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_NEXT_HOP, - next_hop_entry.next_hop_key)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Next hop with key " << QuotedVar(next_hop_entry.next_hop_key) - << " already exists in centralized mapper"); - } - - if (!next_hop_entry.gre_tunnel_id.empty()) { - auto gre_tunnel_or = gP4Orch->getGreTunnelManager()->getConstGreTunnelEntry( - KeyGenerator::generateTunnelKey(next_hop_entry.gre_tunnel_id)); - if (!gre_tunnel_or.ok()) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "GRE Tunnel " - << QuotedVar(next_hop_entry.gre_tunnel_id) - << " does not exist in GRE Tunnel Manager"); - } - next_hop_entry.router_interface_id = (*gre_tunnel_or).router_interface_id; - // BRCM requires neighbor object to be created before GRE tunnel, referring - // to the one in GRE tunnel object when creating next_hop_entry_with - // setTunnelAction - next_hop_entry.neighbor_id = (*gre_tunnel_or).neighbor_id; - } - - // Neighbor doesn't have OID and the IP addr needed in next hop creation is - // neighbor_id, so only check neighbor existence in centralized mapper. - const auto neighbor_key = KeyGenerator::generateNeighborKey( - next_hop_entry.router_interface_id, next_hop_entry.neighbor_id); - if (!m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key)) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Neighbor with key " << QuotedVar(neighbor_key) - << " does not exist in centralized mapper"); - } - - ASSIGN_OR_RETURN(std::vector attrs, - getSaiAttrs(next_hop_entry)); - - // Call SAI API. - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_next_hop_api->create_next_hop(&next_hop_entry.next_hop_oid, gSwitchId, - (uint32_t)attrs.size(), attrs.data()), - "Failed to create next hop " << QuotedVar(next_hop_entry.next_hop_key)); - - if (!next_hop_entry.gre_tunnel_id.empty()) { - // On successful creation, increment ref count for tunnel object - m_p4OidMapper->increaseRefCount( - SAI_OBJECT_TYPE_TUNNEL, - KeyGenerator::generateTunnelKey(next_hop_entry.gre_tunnel_id)); - } else { - // On successful creation, increment ref count for router intf object - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey( - next_hop_entry.router_interface_id)); - } - - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key); - if (next_hop_entry.neighbor_id.isV4()) { - gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV4_NEXTHOP); - } else { - gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV6_NEXTHOP); - } - - // Add created entry to internal table. - m_nextHopTable.emplace(next_hop_entry.next_hop_key, next_hop_entry); - - // Add the key to OID map to centralized mapper. - m_p4OidMapper->setOID(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_entry.next_hop_key, - next_hop_entry.next_hop_oid); - - return ReturnCode(); +ReturnCode NextHopManager::createNextHop(P4NextHopEntry &next_hop_entry) +{ + SWSS_LOG_ENTER(); + + // Check the existence of the next hop in next hop manager and centralized + // mapper. + if (getNextHopEntry(next_hop_entry.next_hop_key) != nullptr) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_EXISTS) + << "Next hop with key " << QuotedVar(next_hop_entry.next_hop_key) + << " already exists in next hop manager"); + } + if (m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_entry.next_hop_key)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Next hop with key " << QuotedVar(next_hop_entry.next_hop_key) + << " already exists in centralized mapper"); + } + + if (!next_hop_entry.gre_tunnel_id.empty()) + { + auto gre_tunnel_or = gP4Orch->getGreTunnelManager()->getConstGreTunnelEntry( + KeyGenerator::generateTunnelKey(next_hop_entry.gre_tunnel_id)); + if (!gre_tunnel_or.ok()) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "GRE Tunnel " << QuotedVar(next_hop_entry.gre_tunnel_id) + << " does not exist in GRE Tunnel Manager"); + } + next_hop_entry.router_interface_id = (*gre_tunnel_or).router_interface_id; + // BRCM requires neighbor object to be created before GRE tunnel, referring + // to the one in GRE tunnel object when creating next_hop_entry_with + // setTunnelAction + next_hop_entry.neighbor_id = (*gre_tunnel_or).neighbor_id; + } + + // Neighbor doesn't have OID and the IP addr needed in next hop creation is + // neighbor_id, so only check neighbor existence in centralized mapper. + const auto neighbor_key = + KeyGenerator::generateNeighborKey(next_hop_entry.router_interface_id, next_hop_entry.neighbor_id); + if (!m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key)) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Neighbor with key " << QuotedVar(neighbor_key) + << " does not exist in centralized mapper"); + } + + ASSIGN_OR_RETURN(std::vector attrs, getSaiAttrs(next_hop_entry)); + + // Call SAI API. + CHECK_ERROR_AND_LOG_AND_RETURN(sai_next_hop_api->create_next_hop(&next_hop_entry.next_hop_oid, gSwitchId, + (uint32_t)attrs.size(), attrs.data()), + "Failed to create next hop " << QuotedVar(next_hop_entry.next_hop_key)); + + if (!next_hop_entry.gre_tunnel_id.empty()) + { + // On successful creation, increment ref count for tunnel object + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_TUNNEL, + KeyGenerator::generateTunnelKey(next_hop_entry.gre_tunnel_id)); + } + else + { + // On successful creation, increment ref count for router intf object + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(next_hop_entry.router_interface_id)); + } + + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key); + if (next_hop_entry.neighbor_id.isV4()) + { + gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV4_NEXTHOP); + } + else + { + gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV6_NEXTHOP); + } + + // Add created entry to internal table. + m_nextHopTable.emplace(next_hop_entry.next_hop_key, next_hop_entry); + + // Add the key to OID map to centralized mapper. + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_entry.next_hop_key, next_hop_entry.next_hop_oid); + + return ReturnCode(); } -ReturnCode NextHopManager::processUpdateRequest( - const P4NextHopAppDbEntry& app_db_entry, P4NextHopEntry* next_hop_entry) { - SWSS_LOG_ENTER(); +ReturnCode NextHopManager::processUpdateRequest(const P4NextHopAppDbEntry &app_db_entry, P4NextHopEntry *next_hop_entry) +{ + SWSS_LOG_ENTER(); - ReturnCode status = - ReturnCode(StatusCode::SWSS_RC_UNIMPLEMENTED) - << "Currently next hop doesn't support update. Next hop key " - << QuotedVar(next_hop_entry->next_hop_key); - SWSS_LOG_ERROR("%s", status.message().c_str()); - return status; + ReturnCode status = ReturnCode(StatusCode::SWSS_RC_UNIMPLEMENTED) + << "Currently next hop doesn't support update. Next hop key " + << QuotedVar(next_hop_entry->next_hop_key); + SWSS_LOG_ERROR("%s", status.message().c_str()); + return status; } -ReturnCode NextHopManager::processDeleteRequest( - const std::string& next_hop_key) { - SWSS_LOG_ENTER(); +ReturnCode NextHopManager::processDeleteRequest(const std::string &next_hop_key) +{ + SWSS_LOG_ENTER(); - auto status = removeNextHop(next_hop_key); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to remove next hop with key %s", - QuotedVar(next_hop_key).c_str()); - } + auto status = removeNextHop(next_hop_key); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to remove next hop with key %s", QuotedVar(next_hop_key).c_str()); + } - return status; + return status; } -ReturnCode NextHopManager::removeNextHop(const std::string& next_hop_key) { - SWSS_LOG_ENTER(); - - // Check the existence of the next hop in next hop manager and centralized - // mapper. - auto* next_hop_entry = getNextHopEntry(next_hop_key); - if (next_hop_entry == nullptr) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Next hop with key " << QuotedVar(next_hop_key) - << " does not exist in next hop manager"); - } - - // Check if there is anything referring to the next hop before deletion. - uint32_t ref_count; - if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key, - &ref_count)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Failed to get reference count for next hop " - << QuotedVar(next_hop_key)); - } - if (ref_count > 0) { - LOG_ERROR_AND_RETURN( - ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Next hop " << QuotedVar(next_hop_entry->next_hop_key) - << " referenced by other objects (ref_count = " << ref_count); - } - - // Call SAI API. - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_next_hop_api->remove_next_hop(next_hop_entry->next_hop_oid), - "Failed to remove next hop " << QuotedVar(next_hop_entry->next_hop_key)); - - if (!next_hop_entry->gre_tunnel_id.empty()) { - // On successful deletion, decrement ref count for tunnel object +ReturnCode NextHopManager::removeNextHop(const std::string &next_hop_key) +{ + SWSS_LOG_ENTER(); + + // Check the existence of the next hop in next hop manager and centralized + // mapper. + auto *next_hop_entry = getNextHopEntry(next_hop_key); + if (next_hop_entry == nullptr) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Next hop with key " << QuotedVar(next_hop_key) + << " does not exist in next hop manager"); + } + + // Check if there is anything referring to the next hop before deletion. + uint32_t ref_count; + if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key, &ref_count)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Failed to get reference count for next hop " + << QuotedVar(next_hop_key)); + } + if (ref_count > 0) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Next hop " << QuotedVar(next_hop_entry->next_hop_key) + << " referenced by other objects (ref_count = " << ref_count); + } + + // Call SAI API. + CHECK_ERROR_AND_LOG_AND_RETURN(sai_next_hop_api->remove_next_hop(next_hop_entry->next_hop_oid), + "Failed to remove next hop " << QuotedVar(next_hop_entry->next_hop_key)); + + if (!next_hop_entry->gre_tunnel_id.empty()) + { + // On successful deletion, decrement ref count for tunnel object + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_TUNNEL, + KeyGenerator::generateTunnelKey(next_hop_entry->gre_tunnel_id)); + } + else + { + // On successful deletion, decrement ref count for router intf object + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(next_hop_entry->router_interface_id)); + } + + std::string router_interface_id = next_hop_entry->router_interface_id; + if (!next_hop_entry->gre_tunnel_id.empty()) + { + auto gre_tunnel_or = gP4Orch->getGreTunnelManager()->getConstGreTunnelEntry( + KeyGenerator::generateTunnelKey(next_hop_entry->gre_tunnel_id)); + if (!gre_tunnel_or.ok()) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "GRE Tunnel " << QuotedVar(next_hop_entry->gre_tunnel_id) + << " does not exist in GRE Tunnel Manager"); + } + router_interface_id = (*gre_tunnel_or).router_interface_id; + } m_p4OidMapper->decreaseRefCount( - SAI_OBJECT_TYPE_TUNNEL, - KeyGenerator::generateTunnelKey(next_hop_entry->gre_tunnel_id)); - } else { - // On successful deletion, decrement ref count for router intf object - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey( - next_hop_entry->router_interface_id)); - } - - std::string router_interface_id = next_hop_entry->router_interface_id; - if (!next_hop_entry->gre_tunnel_id.empty()) { - auto gre_tunnel_or = gP4Orch->getGreTunnelManager()->getConstGreTunnelEntry( - KeyGenerator::generateTunnelKey(next_hop_entry->gre_tunnel_id)); - if (!gre_tunnel_or.ok()) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "GRE Tunnel " - << QuotedVar(next_hop_entry->gre_tunnel_id) - << " does not exist in GRE Tunnel Manager"); - } - router_interface_id = (*gre_tunnel_or).router_interface_id; - } - m_p4OidMapper->decreaseRefCount( - SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, - KeyGenerator::generateNeighborKey(router_interface_id, - next_hop_entry->neighbor_id)); - if (next_hop_entry->neighbor_id.isV4()) { - gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV4_NEXTHOP); - } else { - gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV6_NEXTHOP); - } - - // Remove the key to OID map to centralized mapper. - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key); - - // Remove the entry from internal table. - m_nextHopTable.erase(next_hop_key); - - return ReturnCode(); + SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, + KeyGenerator::generateNeighborKey(router_interface_id, next_hop_entry->neighbor_id)); + if (next_hop_entry->neighbor_id.isV4()) + { + gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV4_NEXTHOP); + } + else + { + gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV6_NEXTHOP); + } + + // Remove the key to OID map to centralized mapper. + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key); + + // Remove the entry from internal table. + m_nextHopTable.erase(next_hop_key); + + return ReturnCode(); } -std::string NextHopManager::verifyState( - const std::string& key, const std::vector& tuple) { - SWSS_LOG_ENTER(); - - auto pos = key.find_first_of(kTableKeyDelimiter); - if (pos == std::string::npos) { - return std::string("Invalid key: ") + key; - } - std::string p4rt_table = key.substr(0, pos); - std::string p4rt_key = key.substr(pos + 1); - if (p4rt_table != APP_P4RT_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - std::string table_name; - std::string key_content; - parseP4RTKey(p4rt_key, &table_name, &key_content); - if (table_name != APP_P4RT_NEXTHOP_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - - ReturnCode status; - auto app_db_entry_or = deserializeP4NextHopAppDbEntry(key_content, tuple); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - std::stringstream msg; - msg << "Unable to deserialize key " << QuotedVar(key) << ": " - << status.message(); - return msg.str(); - } - auto& app_db_entry = *app_db_entry_or; - const std::string next_hop_key = - KeyGenerator::generateNextHopKey(app_db_entry.next_hop_id); - auto* next_hop_entry = getNextHopEntry(next_hop_key); - if (next_hop_entry == nullptr) { - std::stringstream msg; - msg << "No entry found with key " << QuotedVar(key); - return msg.str(); - } - - std::string cache_result = verifyStateCache(app_db_entry, next_hop_entry); - std::string asic_db_result = verifyStateAsicDb(next_hop_entry); - if (cache_result.empty()) { - return asic_db_result; - } - if (asic_db_result.empty()) { - return cache_result; - } - return cache_result + "; " + asic_db_result; +std::string NextHopManager::verifyState(const std::string &key, const std::vector &tuple) +{ + SWSS_LOG_ENTER(); + + auto pos = key.find_first_of(kTableKeyDelimiter); + if (pos == std::string::npos) + { + return std::string("Invalid key: ") + key; + } + std::string p4rt_table = key.substr(0, pos); + std::string p4rt_key = key.substr(pos + 1); + if (p4rt_table != APP_P4RT_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } + std::string table_name; + std::string key_content; + parseP4RTKey(p4rt_key, &table_name, &key_content); + if (table_name != APP_P4RT_NEXTHOP_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } + + ReturnCode status; + auto app_db_entry_or = deserializeP4NextHopAppDbEntry(key_content, tuple); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + std::stringstream msg; + msg << "Unable to deserialize key " << QuotedVar(key) << ": " << status.message(); + return msg.str(); + } + auto &app_db_entry = *app_db_entry_or; + const std::string next_hop_key = KeyGenerator::generateNextHopKey(app_db_entry.next_hop_id); + auto *next_hop_entry = getNextHopEntry(next_hop_key); + if (next_hop_entry == nullptr) + { + std::stringstream msg; + msg << "No entry found with key " << QuotedVar(key); + return msg.str(); + } + + std::string cache_result = verifyStateCache(app_db_entry, next_hop_entry); + std::string asic_db_result = verifyStateAsicDb(next_hop_entry); + if (cache_result.empty()) + { + return asic_db_result; + } + if (asic_db_result.empty()) + { + return cache_result; + } + return cache_result + "; " + asic_db_result; } -std::string NextHopManager::verifyStateCache( - const P4NextHopAppDbEntry& app_db_entry, - const P4NextHopEntry* next_hop_entry) { - const std::string next_hop_key = - KeyGenerator::generateNextHopKey(app_db_entry.next_hop_id); - if (next_hop_entry->next_hop_key != next_hop_key) { - std::stringstream msg; - msg << "Nexthop with key " << QuotedVar(next_hop_key) - << " does not match internal cache " - << QuotedVar(next_hop_entry->next_hop_key) << " in nexthop manager."; - return msg.str(); - } - if (next_hop_entry->next_hop_id != app_db_entry.next_hop_id) { - std::stringstream msg; - msg << "Nexthop " << QuotedVar(app_db_entry.next_hop_id) - << " does not match internal cache " - << QuotedVar(next_hop_entry->next_hop_id) << " in nexthop manager."; - return msg.str(); - } - if (app_db_entry.action_str == p4orch::kSetIpNexthop && - next_hop_entry->router_interface_id != app_db_entry.router_interface_id) { - std::stringstream msg; - msg << "Nexthop " << QuotedVar(app_db_entry.next_hop_id) << " with ritf ID " - << QuotedVar(app_db_entry.router_interface_id) - << " does not match internal cache " - << QuotedVar(next_hop_entry->router_interface_id) - << " in nexthop manager."; - return msg.str(); - } - if (app_db_entry.action_str == p4orch::kSetIpNexthop && - next_hop_entry->neighbor_id.to_string() != - app_db_entry.neighbor_id.to_string()) { - std::stringstream msg; - msg << "Nexthop " << QuotedVar(app_db_entry.next_hop_id) - << " with neighbor ID " << app_db_entry.neighbor_id.to_string() - << " does not match internal cache " - << next_hop_entry->neighbor_id.to_string() << " in nexthop manager."; - return msg.str(); - } - - if (app_db_entry.action_str == p4orch::kSetTunnelNexthop && - next_hop_entry->gre_tunnel_id != app_db_entry.gre_tunnel_id) { - std::stringstream msg; - msg << "Nexthop " << QuotedVar(app_db_entry.next_hop_id) - << " with GRE tunnel ID " << QuotedVar(app_db_entry.gre_tunnel_id) - << " does not match internal cache " - << QuotedVar(next_hop_entry->gre_tunnel_id) << " in nexthop manager."; - return msg.str(); - } - if (!next_hop_entry->gre_tunnel_id.empty()) { - auto gre_tunnel_or = gP4Orch->getGreTunnelManager()->getConstGreTunnelEntry( - KeyGenerator::generateTunnelKey(next_hop_entry->gre_tunnel_id)); - if (!gre_tunnel_or.ok()) { - std::stringstream msg; - msg << "GRE Tunnel " << QuotedVar(next_hop_entry->gre_tunnel_id) - << " does not exist in GRE Tunnel Manager"; - return msg.str(); - } - P4GreTunnelEntry gre_tunnel = *gre_tunnel_or; - if (gre_tunnel.neighbor_id.to_string() != - next_hop_entry->neighbor_id.to_string()) { - std::stringstream msg; - msg << "Nexthop " << QuotedVar(next_hop_entry->next_hop_id) - << " with neighbor ID " - << QuotedVar(next_hop_entry->neighbor_id.to_string()) - << " in nexthop manager does not match internal cache " - << QuotedVar(gre_tunnel.neighbor_id.to_string()) << " with tunnel ID " - << QuotedVar(gre_tunnel.tunnel_id) << " in GRE tunnel manager."; - return msg.str(); - } - if (gre_tunnel.router_interface_id != next_hop_entry->router_interface_id) { - std::stringstream msg; - msg << "Nexthop " << QuotedVar(next_hop_entry->next_hop_id) - << " with rif ID " << QuotedVar(next_hop_entry->router_interface_id) - << " in nexthop manager does not match internal cache " - << QuotedVar(gre_tunnel.router_interface_id) << " with tunnel ID " - << QuotedVar(gre_tunnel.tunnel_id) << " in GRE tunnel manager."; - return msg.str(); - } - } - - return m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, - next_hop_entry->next_hop_key, - next_hop_entry->next_hop_oid); +std::string NextHopManager::verifyStateCache(const P4NextHopAppDbEntry &app_db_entry, + const P4NextHopEntry *next_hop_entry) +{ + const std::string next_hop_key = KeyGenerator::generateNextHopKey(app_db_entry.next_hop_id); + if (next_hop_entry->next_hop_key != next_hop_key) + { + std::stringstream msg; + msg << "Nexthop with key " << QuotedVar(next_hop_key) << " does not match internal cache " + << QuotedVar(next_hop_entry->next_hop_key) << " in nexthop manager."; + return msg.str(); + } + if (next_hop_entry->next_hop_id != app_db_entry.next_hop_id) + { + std::stringstream msg; + msg << "Nexthop " << QuotedVar(app_db_entry.next_hop_id) << " does not match internal cache " + << QuotedVar(next_hop_entry->next_hop_id) << " in nexthop manager."; + return msg.str(); + } + if (app_db_entry.action_str == p4orch::kSetIpNexthop && + next_hop_entry->router_interface_id != app_db_entry.router_interface_id) + { + std::stringstream msg; + msg << "Nexthop " << QuotedVar(app_db_entry.next_hop_id) << " with ritf ID " + << QuotedVar(app_db_entry.router_interface_id) << " does not match internal cache " + << QuotedVar(next_hop_entry->router_interface_id) << " in nexthop manager."; + return msg.str(); + } + if (app_db_entry.action_str == p4orch::kSetIpNexthop && + next_hop_entry->neighbor_id.to_string() != app_db_entry.neighbor_id.to_string()) + { + std::stringstream msg; + msg << "Nexthop " << QuotedVar(app_db_entry.next_hop_id) << " with neighbor ID " + << app_db_entry.neighbor_id.to_string() << " does not match internal cache " + << next_hop_entry->neighbor_id.to_string() << " in nexthop manager."; + return msg.str(); + } + + if (app_db_entry.action_str == p4orch::kSetTunnelNexthop && + next_hop_entry->gre_tunnel_id != app_db_entry.gre_tunnel_id) + { + std::stringstream msg; + msg << "Nexthop " << QuotedVar(app_db_entry.next_hop_id) << " with GRE tunnel ID " + << QuotedVar(app_db_entry.gre_tunnel_id) << " does not match internal cache " + << QuotedVar(next_hop_entry->gre_tunnel_id) << " in nexthop manager."; + return msg.str(); + } + if (!next_hop_entry->gre_tunnel_id.empty()) + { + auto gre_tunnel_or = gP4Orch->getGreTunnelManager()->getConstGreTunnelEntry( + KeyGenerator::generateTunnelKey(next_hop_entry->gre_tunnel_id)); + if (!gre_tunnel_or.ok()) + { + std::stringstream msg; + msg << "GRE Tunnel " << QuotedVar(next_hop_entry->gre_tunnel_id) << " does not exist in GRE Tunnel Manager"; + return msg.str(); + } + P4GreTunnelEntry gre_tunnel = *gre_tunnel_or; + if (gre_tunnel.neighbor_id.to_string() != next_hop_entry->neighbor_id.to_string()) + { + std::stringstream msg; + msg << "Nexthop " << QuotedVar(next_hop_entry->next_hop_id) << " with neighbor ID " + << QuotedVar(next_hop_entry->neighbor_id.to_string()) + << " in nexthop manager does not match internal cache " << QuotedVar(gre_tunnel.neighbor_id.to_string()) + << " with tunnel ID " << QuotedVar(gre_tunnel.tunnel_id) << " in GRE tunnel manager."; + return msg.str(); + } + if (gre_tunnel.router_interface_id != next_hop_entry->router_interface_id) + { + std::stringstream msg; + msg << "Nexthop " << QuotedVar(next_hop_entry->next_hop_id) << " with rif ID " + << QuotedVar(next_hop_entry->router_interface_id) + << " in nexthop manager does not match internal cache " << QuotedVar(gre_tunnel.router_interface_id) + << " with tunnel ID " << QuotedVar(gre_tunnel.tunnel_id) << " in GRE tunnel manager."; + return msg.str(); + } + } + + return m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_entry->next_hop_key, + next_hop_entry->next_hop_oid); } -std::string NextHopManager::verifyStateAsicDb( - const P4NextHopEntry* next_hop_entry) { - auto attrs_or = getSaiAttrs(*next_hop_entry); - if (!attrs_or.ok()) { - return std::string("Failed to get SAI attrs: ") + - attrs_or.status().message(); - } - std::vector attrs = *attrs_or; - std::vector exp = - saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_NEXT_HOP, (uint32_t)attrs.size(), attrs.data(), - /*countOnly=*/false); - - swss::DBConnector db("ASIC_DB", 0); - swss::Table table(&db, "ASIC_STATE"); - std::string key = sai_serialize_object_type(SAI_OBJECT_TYPE_NEXT_HOP) + ":" + - sai_serialize_object_id(next_hop_entry->next_hop_oid); - std::vector values; - if (!table.get(key, values)) { - return std::string("ASIC DB key not found ") + key; - } - - return verifyAttrs(values, exp, std::vector{}, - /*allow_unknown=*/false); +std::string NextHopManager::verifyStateAsicDb(const P4NextHopEntry *next_hop_entry) +{ + auto attrs_or = getSaiAttrs(*next_hop_entry); + if (!attrs_or.ok()) + { + return std::string("Failed to get SAI attrs: ") + attrs_or.status().message(); + } + std::vector attrs = *attrs_or; + std::vector exp = + saimeta::SaiAttributeList::serialize_attr_list(SAI_OBJECT_TYPE_NEXT_HOP, (uint32_t)attrs.size(), attrs.data(), + /*countOnly=*/false); + + swss::DBConnector db("ASIC_DB", 0); + swss::Table table(&db, "ASIC_STATE"); + std::string key = sai_serialize_object_type(SAI_OBJECT_TYPE_NEXT_HOP) + ":" + + sai_serialize_object_id(next_hop_entry->next_hop_oid); + std::vector values; + if (!table.get(key, values)) + { + return std::string("ASIC DB key not found ") + key; + } + + return verifyAttrs(values, exp, std::vector{}, + /*allow_unknown=*/false); } diff --git a/orchagent/p4orch/next_hop_manager.h b/orchagent/p4orch/next_hop_manager.h index 949f8934ed3..aac6f5e4446 100644 --- a/orchagent/p4orch/next_hop_manager.h +++ b/orchagent/p4orch/next_hop_manager.h @@ -14,102 +14,95 @@ #include "p4orch/router_interface_manager.h" #include "response_publisher_interface.h" #include "return_code.h" -extern "C" { +extern "C" +{ #include "sai.h" } // P4NextHopEntry holds NextHopManager's internal cache of P4 next hop entry. -struct P4NextHopEntry { - // Key of this entry, built from next_hop_id. - std::string next_hop_key; - - // Fields from P4 table. - // Match - std::string next_hop_id; - // Action - std::string router_interface_id; - std::string gre_tunnel_id; - swss::IpAddress neighbor_id; - - // SAI OID associated with this entry. - sai_object_id_t next_hop_oid = SAI_NULL_OBJECT_ID; - - P4NextHopEntry(const std::string& next_hop_id, - const std::string& router_interface_id, - const std::string& gre_tunnel_id, - const swss::IpAddress& neighbor_id); +struct P4NextHopEntry +{ + // Key of this entry, built from next_hop_id. + std::string next_hop_key; + + // Fields from P4 table. + // Match + std::string next_hop_id; + // Action + std::string router_interface_id; + std::string gre_tunnel_id; + swss::IpAddress neighbor_id; + + // SAI OID associated with this entry. + sai_object_id_t next_hop_oid = SAI_NULL_OBJECT_ID; + + P4NextHopEntry(const std::string &next_hop_id, const std::string &router_interface_id, + const std::string &gre_tunnel_id, const swss::IpAddress &neighbor_id); }; // NextHopManager listens to changes in table APP_P4RT_NEXTHOP_TABLE_NAME and // creates/updates/deletes next hop SAI object accordingly. -class NextHopManager : public ObjectManagerInterface { - public: - NextHopManager(P4OidMapper* p4oidMapper, - ResponsePublisherInterface* publisher) { - SWSS_LOG_ENTER(); - - assert(p4oidMapper != nullptr); - m_p4OidMapper = p4oidMapper; - assert(publisher != nullptr); - m_publisher = publisher; - } - - virtual ~NextHopManager() = default; - - void enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) override; - void drain() override; - std::string verifyState( - const std::string& key, - const std::vector& tuple) override; - ReturnCode getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) override; - - private: - // Gets the internal cached next hop entry by its key. - // Return nullptr if corresponding next hop entry is not cached. - P4NextHopEntry* getNextHopEntry(const std::string& next_hop_key); - - // Deserializes an entry from table APP_P4RT_NEXTHOP_TABLE_NAME. - ReturnCodeOr deserializeP4NextHopAppDbEntry( - const std::string& key, - const std::vector& attributes); - - // Processes add operation for an entry. - ReturnCode processAddRequest(const P4NextHopAppDbEntry& app_db_entry); - - // Creates an next hop in the next hop table. Return true on success. - ReturnCode createNextHop(P4NextHopEntry& next_hop_entry); - - // Processes update operation for an entry. - ReturnCode processUpdateRequest(const P4NextHopAppDbEntry& app_db_entry, - P4NextHopEntry* next_hop_entry); - - // Processes delete operation for an entry. - ReturnCode processDeleteRequest(const std::string& next_hop_key); - - // Deletes an next hop in the next hop table. Return true on success. - ReturnCode removeNextHop(const std::string& next_hop_key); - - // Verifies internal cache for an entry. - std::string verifyStateCache(const P4NextHopAppDbEntry& app_db_entry, - const P4NextHopEntry* next_hop_entry); - - // Verifies ASIC DB for an entry. - std::string verifyStateAsicDb(const P4NextHopEntry* next_hop_entry); - - // Returns the SAI attributes for an entry. - ReturnCodeOr> getSaiAttrs( - const P4NextHopEntry& next_hop_entry); - - // m_nextHopTable: next_hop_key, P4NextHopEntry - std::unordered_map m_nextHopTable; - - // Owners of pointers below must outlive this class's instance. - P4OidMapper* m_p4OidMapper; - ResponsePublisherInterface* m_publisher; - std::deque m_entries; - - friend class NextHopManagerTest; +class NextHopManager : public ObjectManagerInterface +{ + public: + NextHopManager(P4OidMapper *p4oidMapper, ResponsePublisherInterface *publisher) + { + SWSS_LOG_ENTER(); + + assert(p4oidMapper != nullptr); + m_p4OidMapper = p4oidMapper; + assert(publisher != nullptr); + m_publisher = publisher; + } + + virtual ~NextHopManager() = default; + + void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; + void drain() override; + std::string verifyState(const std::string &key, const std::vector &tuple) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; + + private: + // Gets the internal cached next hop entry by its key. + // Return nullptr if corresponding next hop entry is not cached. + P4NextHopEntry *getNextHopEntry(const std::string &next_hop_key); + + // Deserializes an entry from table APP_P4RT_NEXTHOP_TABLE_NAME. + ReturnCodeOr deserializeP4NextHopAppDbEntry( + const std::string &key, const std::vector &attributes); + + // Processes add operation for an entry. + ReturnCode processAddRequest(const P4NextHopAppDbEntry &app_db_entry); + + // Creates an next hop in the next hop table. Return true on success. + ReturnCode createNextHop(P4NextHopEntry &next_hop_entry); + + // Processes update operation for an entry. + ReturnCode processUpdateRequest(const P4NextHopAppDbEntry &app_db_entry, P4NextHopEntry *next_hop_entry); + + // Processes delete operation for an entry. + ReturnCode processDeleteRequest(const std::string &next_hop_key); + + // Deletes an next hop in the next hop table. Return true on success. + ReturnCode removeNextHop(const std::string &next_hop_key); + + // Verifies internal cache for an entry. + std::string verifyStateCache(const P4NextHopAppDbEntry &app_db_entry, const P4NextHopEntry *next_hop_entry); + + // Verifies ASIC DB for an entry. + std::string verifyStateAsicDb(const P4NextHopEntry *next_hop_entry); + + // Returns the SAI attributes for an entry. + ReturnCodeOr> getSaiAttrs(const P4NextHopEntry &next_hop_entry); + + // m_nextHopTable: next_hop_key, P4NextHopEntry + std::unordered_map m_nextHopTable; + + // Owners of pointers below must outlive this class's instance. + P4OidMapper *m_p4OidMapper; + ResponsePublisherInterface *m_publisher; + std::deque m_entries; + + friend class NextHopManagerTest; }; diff --git a/orchagent/p4orch/object_manager_interface.h b/orchagent/p4orch/object_manager_interface.h index 4e841a5d05f..1d44990edc5 100644 --- a/orchagent/p4orch/object_manager_interface.h +++ b/orchagent/p4orch/object_manager_interface.h @@ -2,25 +2,22 @@ #include "orch.h" -class ObjectManagerInterface { - public: - virtual ~ObjectManagerInterface() = default; +class ObjectManagerInterface +{ + public: + virtual ~ObjectManagerInterface() = default; - // Enqueues an entry into the manager - virtual void enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) = 0; + // Enqueues an entry into the manager + virtual void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) = 0; - // Processes all entries in the queue - virtual void drain() = 0; + // Processes all entries in the queue + virtual void drain() = 0; - // StateVerification helper function for the manager - virtual std::string verifyState( - const std::string& key, - const std::vector& tuple) = 0; + // StateVerification helper function for the manager + virtual std::string verifyState(const std::string &key, const std::vector &tuple) = 0; - // For sai extension objects depending on a sai object - // return sai object id for a given table with a given key - virtual ReturnCode getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) = 0; + // For sai extension objects depending on a sai object + // return sai object id for a given table with a given key + virtual ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) = 0; }; diff --git a/orchagent/p4orch/p4oidmapper.cpp b/orchagent/p4orch/p4oidmapper.cpp index ae60588abb9..63215846a62 100644 --- a/orchagent/p4orch/p4oidmapper.cpp +++ b/orchagent/p4orch/p4oidmapper.cpp @@ -7,207 +7,213 @@ #include "logger.h" #include "sai_serialize.h" -extern "C" { +extern "C" +{ #include "sai.h" } -namespace { +namespace +{ -std::string convertToDBField(_In_ const sai_object_type_t object_type, - _In_ const std::string& key) { - return sai_serialize_object_type(object_type) + ":" + key; +std::string convertToDBField(_In_ const sai_object_type_t object_type, _In_ const std::string &key) +{ + return sai_serialize_object_type(object_type) + ":" + key; } -} // namespace +} // namespace -P4OidMapper::P4OidMapper() - : m_db("APPL_STATE_DB", 0), m_table(&m_db, "P4RT_KEY_TO_OID") {} +P4OidMapper::P4OidMapper() : m_db("APPL_STATE_DB", 0), m_table(&m_db, "P4RT_KEY_TO_OID") +{ +} -bool P4OidMapper::setOID(_In_ sai_object_type_t object_type, - _In_ const std::string& key, _In_ sai_object_id_t oid, - _In_ uint32_t ref_count) { - SWSS_LOG_ENTER(); +bool P4OidMapper::setOID(_In_ sai_object_type_t object_type, _In_ const std::string &key, _In_ sai_object_id_t oid, + _In_ uint32_t ref_count) +{ + SWSS_LOG_ENTER(); - if (m_oidTables[object_type].find(key) != m_oidTables[object_type].end()) { - SWSS_LOG_ERROR( - "Key %s with SAI object type %d already exists in centralized mapper", - key.c_str(), object_type); - return false; - } + if (m_oidTables[object_type].find(key) != m_oidTables[object_type].end()) + { + SWSS_LOG_ERROR("Key %s with SAI object type %d already exists in centralized mapper", key.c_str(), object_type); + return false; + } - m_oidTables[object_type][key] = {oid, ref_count}; - m_table.hset("", convertToDBField(object_type, key), - sai_serialize_object_id(oid)); - return true; + m_oidTables[object_type][key] = {oid, ref_count}; + m_table.hset("", convertToDBField(object_type, key), sai_serialize_object_id(oid)); + return true; } -bool P4OidMapper::getOID(_In_ sai_object_type_t object_type, - _In_ const std::string& key, - _Out_ sai_object_id_t* oid) const { - SWSS_LOG_ENTER(); - - if (oid == nullptr) { - SWSS_LOG_ERROR("nullptr input in centralized mapper"); - return false; - } - - if (m_oidTables[object_type].find(key) == m_oidTables[object_type].end()) { - SWSS_LOG_ERROR( - "Key %s with SAI object type %d does not exist in centralized mapper", - key.c_str(), object_type); - return false; - } - - *oid = m_oidTables[object_type].at(key).sai_oid; - return true; +bool P4OidMapper::getOID(_In_ sai_object_type_t object_type, _In_ const std::string &key, + _Out_ sai_object_id_t *oid) const +{ + SWSS_LOG_ENTER(); + + if (oid == nullptr) + { + SWSS_LOG_ERROR("nullptr input in centralized mapper"); + return false; + } + + if (m_oidTables[object_type].find(key) == m_oidTables[object_type].end()) + { + SWSS_LOG_ERROR("Key %s with SAI object type %d does not exist in centralized mapper", key.c_str(), object_type); + return false; + } + + *oid = m_oidTables[object_type].at(key).sai_oid; + return true; } -bool P4OidMapper::getRefCount(_In_ sai_object_type_t object_type, - _In_ const std::string& key, - _Out_ uint32_t* ref_count) const { - SWSS_LOG_ENTER(); - - if (ref_count == nullptr) { - SWSS_LOG_ERROR("nullptr input in centralized mapper"); - return false; - } - - if (m_oidTables[object_type].find(key) == m_oidTables[object_type].end()) { - SWSS_LOG_ERROR( - "Key %s with SAI object type %d does not exist in " - "centralized mapper", - key.c_str(), object_type); - return false; - } - - *ref_count = m_oidTables[object_type].at(key).ref_count; - return true; +bool P4OidMapper::getRefCount(_In_ sai_object_type_t object_type, _In_ const std::string &key, + _Out_ uint32_t *ref_count) const +{ + SWSS_LOG_ENTER(); + + if (ref_count == nullptr) + { + SWSS_LOG_ERROR("nullptr input in centralized mapper"); + return false; + } + + if (m_oidTables[object_type].find(key) == m_oidTables[object_type].end()) + { + SWSS_LOG_ERROR("Key %s with SAI object type %d does not exist in " + "centralized mapper", + key.c_str(), object_type); + return false; + } + + *ref_count = m_oidTables[object_type].at(key).ref_count; + return true; } -bool P4OidMapper::eraseOID(_In_ sai_object_type_t object_type, - _In_ const std::string& key) { - SWSS_LOG_ENTER(); - - if (m_oidTables[object_type].find(key) == m_oidTables[object_type].end()) { - SWSS_LOG_ERROR( - "Key %s with SAI object type %d does not exist in " - "centralized mapper", - key.c_str(), object_type); - return false; - } - - if (m_oidTables[object_type][key].ref_count != 0) { - SWSS_LOG_ERROR( - "Key %s with SAI object type %d has non-zero reference count in " - "centralized mapper", - key.c_str(), object_type); - return false; - } - - m_oidTables[object_type].erase(key); - m_table.hdel("", convertToDBField(object_type, key)); - return true; +bool P4OidMapper::eraseOID(_In_ sai_object_type_t object_type, _In_ const std::string &key) +{ + SWSS_LOG_ENTER(); + + if (m_oidTables[object_type].find(key) == m_oidTables[object_type].end()) + { + SWSS_LOG_ERROR("Key %s with SAI object type %d does not exist in " + "centralized mapper", + key.c_str(), object_type); + return false; + } + + if (m_oidTables[object_type][key].ref_count != 0) + { + SWSS_LOG_ERROR("Key %s with SAI object type %d has non-zero reference count in " + "centralized mapper", + key.c_str(), object_type); + return false; + } + + m_oidTables[object_type].erase(key); + m_table.hdel("", convertToDBField(object_type, key)); + return true; } -void P4OidMapper::eraseAllOIDs(_In_ sai_object_type_t object_type) { - SWSS_LOG_ENTER(); +void P4OidMapper::eraseAllOIDs(_In_ sai_object_type_t object_type) +{ + SWSS_LOG_ENTER(); - m_oidTables[object_type].clear(); - m_table.del(""); + m_oidTables[object_type].clear(); + m_table.del(""); } -size_t P4OidMapper::getNumEntries(_In_ sai_object_type_t object_type) const { - SWSS_LOG_ENTER(); +size_t P4OidMapper::getNumEntries(_In_ sai_object_type_t object_type) const +{ + SWSS_LOG_ENTER(); - return (m_oidTables[object_type].size()); + return (m_oidTables[object_type].size()); } -bool P4OidMapper::existsOID(_In_ sai_object_type_t object_type, - _In_ const std::string& key) const { - SWSS_LOG_ENTER(); +bool P4OidMapper::existsOID(_In_ sai_object_type_t object_type, _In_ const std::string &key) const +{ + SWSS_LOG_ENTER(); - return m_oidTables[object_type].find(key) != m_oidTables[object_type].end(); + return m_oidTables[object_type].find(key) != m_oidTables[object_type].end(); } -bool P4OidMapper::increaseRefCount(_In_ sai_object_type_t object_type, - _In_ const std::string& key) { - SWSS_LOG_ENTER(); - - if (m_oidTables[object_type].find(key) == m_oidTables[object_type].end()) { - SWSS_LOG_ERROR( - "Key %s with SAI object type %d does not exist in " - "centralized mapper", - key.c_str(), object_type); - return false; - } - - if (m_oidTables[object_type][key].ref_count == - std::numeric_limits::max()) { - SWSS_LOG_ERROR( - "Key %s with SAI object type %d reached maximum ref_count %u in " - "centralized mapper", - key.c_str(), object_type, m_oidTables[object_type][key].ref_count); - return false; - } - - m_oidTables[object_type][key].ref_count++; - return true; +bool P4OidMapper::increaseRefCount(_In_ sai_object_type_t object_type, _In_ const std::string &key) +{ + SWSS_LOG_ENTER(); + + if (m_oidTables[object_type].find(key) == m_oidTables[object_type].end()) + { + SWSS_LOG_ERROR("Key %s with SAI object type %d does not exist in " + "centralized mapper", + key.c_str(), object_type); + return false; + } + + if (m_oidTables[object_type][key].ref_count == std::numeric_limits::max()) + { + SWSS_LOG_ERROR("Key %s with SAI object type %d reached maximum ref_count %u in " + "centralized mapper", + key.c_str(), object_type, m_oidTables[object_type][key].ref_count); + return false; + } + + m_oidTables[object_type][key].ref_count++; + return true; } -bool P4OidMapper::decreaseRefCount(_In_ sai_object_type_t object_type, - _In_ const std::string& key) { - SWSS_LOG_ENTER(); - - if (m_oidTables[object_type].find(key) == m_oidTables[object_type].end()) { - SWSS_LOG_ERROR( - "Key %s with SAI object type %d does not exist in " - "centralized mapper", - key.c_str(), object_type); - return false; - } - - if (m_oidTables[object_type][key].ref_count == 0) { - SWSS_LOG_ERROR( - "Key %s with SAI object type %d reached zero ref_count in " - "centralized mapper", - key.c_str(), object_type); - return false; - } - - m_oidTables[object_type][key].ref_count--; - return true; +bool P4OidMapper::decreaseRefCount(_In_ sai_object_type_t object_type, _In_ const std::string &key) +{ + SWSS_LOG_ENTER(); + + if (m_oidTables[object_type].find(key) == m_oidTables[object_type].end()) + { + SWSS_LOG_ERROR("Key %s with SAI object type %d does not exist in " + "centralized mapper", + key.c_str(), object_type); + return false; + } + + if (m_oidTables[object_type][key].ref_count == 0) + { + SWSS_LOG_ERROR("Key %s with SAI object type %d reached zero ref_count in " + "centralized mapper", + key.c_str(), object_type); + return false; + } + + m_oidTables[object_type][key].ref_count--; + return true; } -std::string P4OidMapper::verifyOIDMapping(_In_ sai_object_type_t object_type, - _In_ const std::string& key, - _In_ sai_object_id_t oid) { - SWSS_LOG_ENTER(); - - sai_object_id_t mapper_oid; - if (!getOID(object_type, key, &mapper_oid)) { - std::stringstream msg; - msg << "OID not found in mapper for key " << key; - return msg.str(); - } - if (mapper_oid != oid) { - std::stringstream msg; - msg << "OID mismatched in mapper for key " << key << ": " - << sai_serialize_object_id(oid) << " vs " - << sai_serialize_object_id(mapper_oid); - return msg.str(); - } - std::string db_oid; - if (!m_table.hget("", convertToDBField(object_type, key), db_oid)) { - std::stringstream msg; - msg << "OID not found in mapper DB for key " << key; - return msg.str(); - } - if (db_oid != sai_serialize_object_id(oid)) { - std::stringstream msg; - msg << "OID mismatched in mapper DB for key " << key << ": " << db_oid - << " vs " << sai_serialize_object_id(oid); - return msg.str(); - } - - return ""; +std::string P4OidMapper::verifyOIDMapping(_In_ sai_object_type_t object_type, _In_ const std::string &key, + _In_ sai_object_id_t oid) +{ + SWSS_LOG_ENTER(); + + sai_object_id_t mapper_oid; + if (!getOID(object_type, key, &mapper_oid)) + { + std::stringstream msg; + msg << "OID not found in mapper for key " << key; + return msg.str(); + } + if (mapper_oid != oid) + { + std::stringstream msg; + msg << "OID mismatched in mapper for key " << key << ": " << sai_serialize_object_id(oid) << " vs " + << sai_serialize_object_id(mapper_oid); + return msg.str(); + } + std::string db_oid; + if (!m_table.hget("", convertToDBField(object_type, key), db_oid)) + { + std::stringstream msg; + msg << "OID not found in mapper DB for key " << key; + return msg.str(); + } + if (db_oid != sai_serialize_object_id(oid)) + { + std::stringstream msg; + msg << "OID mismatched in mapper DB for key " << key << ": " << db_oid << " vs " + << sai_serialize_object_id(oid); + return msg.str(); + } + + return ""; } diff --git a/orchagent/p4orch/p4oidmapper.h b/orchagent/p4orch/p4oidmapper.h index 79042527593..325acf9503c 100644 --- a/orchagent/p4orch/p4oidmapper.h +++ b/orchagent/p4orch/p4oidmapper.h @@ -6,89 +6,84 @@ #include "dbconnector.h" #include "table.h" -extern "C" { +extern "C" +{ #include "sai.h" } // Interface for mapping P4 ID to SAI OID. // This class is not thread safe. -class P4OidMapper { - public: - // This is a dummy value for non-oid based objects only. - static constexpr sai_object_id_t kDummyOid = 0xdeadf00ddeadf00d; - - P4OidMapper(); - ~P4OidMapper() = default; - - // Sets oid for the given key for the specific object_type. Returns false if - // the key already exists. - bool setOID(_In_ sai_object_type_t object_type, _In_ const std::string& key, - _In_ sai_object_id_t oid, _In_ uint32_t ref_count = 0); - - // Sets dummy oid for the given key for the specific object_type. Should only - // be used for non-oid based object type. Returns false if the key - // already exists. - bool setDummyOID(_In_ sai_object_type_t object_type, - _In_ const std::string& key, _In_ uint32_t ref_count = 0) { - return setOID(object_type, key, /*oid=*/kDummyOid, ref_count); - } - - // Gets oid for the given key for the SAI object_type. - // Returns true on success. - bool getOID(_In_ sai_object_type_t object_type, _In_ const std::string& key, - _Out_ sai_object_id_t* oid) const; - - // Gets the reference count for the given key for the SAI object_type. - // Returns true on success. - bool getRefCount(_In_ sai_object_type_t object_type, - _In_ const std::string& key, - _Out_ uint32_t* ref_count) const; - - // Erases oid for the given key for the SAI object_type. - // This function checks if the reference count is zero or not before the - // operation. - // Returns true on success. - bool eraseOID(_In_ sai_object_type_t object_type, - _In_ const std::string& key); - - // Erases all oids for the SAI object_type. - // This function will erase all oids regardless of the reference counts. - void eraseAllOIDs(_In_ sai_object_type_t object_type); - - // Gets the number of oids for the SAI object_type. - size_t getNumEntries(_In_ sai_object_type_t object_type) const; - - // Checks whether OID mapping exists for the given key for the specific - // object type. - bool existsOID(_In_ sai_object_type_t object_type, - _In_ const std::string& key) const; - - // Increases the reference count for the given object. - // Returns true on success. - bool increaseRefCount(_In_ sai_object_type_t object_type, - _In_ const std::string& key); - - // Decreases the reference count for the given object. - // Returns true on success. - bool decreaseRefCount(_In_ sai_object_type_t object_type, - _In_ const std::string& key); - - // Verifies the OID mapping. - // Returns an empty string if the input has the correct mapping. Returns a - // non-empty error string otherwise. - std::string verifyOIDMapping(_In_ sai_object_type_t object_type, - _In_ const std::string& key, - _In_ sai_object_id_t oid); - - private: - struct MapperEntry { - sai_object_id_t sai_oid; - uint32_t ref_count; - }; - - // Buckets of map tables, one for every SAI object type. - std::unordered_map m_oidTables[SAI_OBJECT_TYPE_MAX]; - - swss::DBConnector m_db; - swss::Table m_table; +class P4OidMapper +{ + public: + // This is a dummy value for non-oid based objects only. + static constexpr sai_object_id_t kDummyOid = 0xdeadf00ddeadf00d; + + P4OidMapper(); + ~P4OidMapper() = default; + + // Sets oid for the given key for the specific object_type. Returns false if + // the key already exists. + bool setOID(_In_ sai_object_type_t object_type, _In_ const std::string &key, _In_ sai_object_id_t oid, + _In_ uint32_t ref_count = 0); + + // Sets dummy oid for the given key for the specific object_type. Should only + // be used for non-oid based object type. Returns false if the key + // already exists. + bool setDummyOID(_In_ sai_object_type_t object_type, _In_ const std::string &key, _In_ uint32_t ref_count = 0) + { + return setOID(object_type, key, /*oid=*/kDummyOid, ref_count); + } + + // Gets oid for the given key for the SAI object_type. + // Returns true on success. + bool getOID(_In_ sai_object_type_t object_type, _In_ const std::string &key, _Out_ sai_object_id_t *oid) const; + + // Gets the reference count for the given key for the SAI object_type. + // Returns true on success. + bool getRefCount(_In_ sai_object_type_t object_type, _In_ const std::string &key, _Out_ uint32_t *ref_count) const; + + // Erases oid for the given key for the SAI object_type. + // This function checks if the reference count is zero or not before the + // operation. + // Returns true on success. + bool eraseOID(_In_ sai_object_type_t object_type, _In_ const std::string &key); + + // Erases all oids for the SAI object_type. + // This function will erase all oids regardless of the reference counts. + void eraseAllOIDs(_In_ sai_object_type_t object_type); + + // Gets the number of oids for the SAI object_type. + size_t getNumEntries(_In_ sai_object_type_t object_type) const; + + // Checks whether OID mapping exists for the given key for the specific + // object type. + bool existsOID(_In_ sai_object_type_t object_type, _In_ const std::string &key) const; + + // Increases the reference count for the given object. + // Returns true on success. + bool increaseRefCount(_In_ sai_object_type_t object_type, _In_ const std::string &key); + + // Decreases the reference count for the given object. + // Returns true on success. + bool decreaseRefCount(_In_ sai_object_type_t object_type, _In_ const std::string &key); + + // Verifies the OID mapping. + // Returns an empty string if the input has the correct mapping. Returns a + // non-empty error string otherwise. + std::string verifyOIDMapping(_In_ sai_object_type_t object_type, _In_ const std::string &key, + _In_ sai_object_id_t oid); + + private: + struct MapperEntry + { + sai_object_id_t sai_oid; + uint32_t ref_count; + }; + + // Buckets of map tables, one for every SAI object type. + std::unordered_map m_oidTables[SAI_OBJECT_TYPE_MAX]; + + swss::DBConnector m_db; + swss::Table m_table; }; diff --git a/orchagent/p4orch/p4orch.cpp b/orchagent/p4orch/p4orch.cpp index f3848bb5f30..00e5ef6c4d9 100644 --- a/orchagent/p4orch/p4orch.cpp +++ b/orchagent/p4orch/p4orch.cpp @@ -24,252 +24,261 @@ #include "sai_serialize.h" #include "timer.h" -extern PortsOrch* gPortsOrch; +extern PortsOrch *gPortsOrch; #define P4_ACL_COUNTERS_STATS_POLL_TIMER_NAME "P4_ACL_COUNTERS_STATS_POLL_TIMER" #define P4_EXT_COUNTERS_STATS_POLL_TIMER_NAME "P4_EXT_COUNTERS_STATS_POLL_TIMER" #define APP_P4RT_EXT_TABLES_MANAGER "EXT_TABLES_MANAGER" -P4Orch::P4Orch(swss::DBConnector* db, std::vector tableNames, - VRFOrch* vrfOrch, CoppOrch* coppOrch) - : Orch(db, tableNames) { - SWSS_LOG_ENTER(); - - m_tablesDefnManager = - std::make_unique(&m_p4OidMapper, &m_publisher); - m_routerIntfManager = - std::make_unique(&m_p4OidMapper, &m_publisher); - m_neighborManager = - std::make_unique(&m_p4OidMapper, &m_publisher); - m_greTunnelManager = - std::make_unique(&m_p4OidMapper, &m_publisher); - m_nextHopManager = - std::make_unique(&m_p4OidMapper, &m_publisher); - m_routeManager = - std::make_unique(&m_p4OidMapper, vrfOrch, &m_publisher); - m_mirrorSessionManager = std::make_unique( - &m_p4OidMapper, &m_publisher); - m_aclTableManager = - std::make_unique(&m_p4OidMapper, &m_publisher); - m_aclRuleManager = std::make_unique( - &m_p4OidMapper, vrfOrch, coppOrch, &m_publisher); - m_wcmpManager = - std::make_unique(&m_p4OidMapper, &m_publisher); - m_l3AdmitManager = - std::make_unique(&m_p4OidMapper, &m_publisher); - m_extTablesManager = - std::make_unique(&m_p4OidMapper, vrfOrch, &m_publisher); - - m_p4TableToManagerMap[APP_P4RT_TABLES_DEFINITION_TABLE_NAME] = - m_tablesDefnManager.get(); - m_p4TableToManagerMap[APP_P4RT_ROUTER_INTERFACE_TABLE_NAME] = - m_routerIntfManager.get(); - m_p4TableToManagerMap[APP_P4RT_NEIGHBOR_TABLE_NAME] = m_neighborManager.get(); - m_p4TableToManagerMap[APP_P4RT_TUNNEL_TABLE_NAME] = m_greTunnelManager.get(); - m_p4TableToManagerMap[APP_P4RT_NEXTHOP_TABLE_NAME] = m_nextHopManager.get(); - m_p4TableToManagerMap[APP_P4RT_IPV4_TABLE_NAME] = m_routeManager.get(); - m_p4TableToManagerMap[APP_P4RT_IPV6_TABLE_NAME] = m_routeManager.get(); - m_p4TableToManagerMap[APP_P4RT_MIRROR_SESSION_TABLE_NAME] = - m_mirrorSessionManager.get(); - m_p4TableToManagerMap[APP_P4RT_ACL_TABLE_DEFINITION_NAME] = - m_aclTableManager.get(); - m_p4TableToManagerMap[APP_P4RT_WCMP_GROUP_TABLE_NAME] = m_wcmpManager.get(); - m_p4TableToManagerMap[APP_P4RT_L3_ADMIT_TABLE_NAME] = m_l3AdmitManager.get(); - m_p4TableToManagerMap[APP_P4RT_EXT_TABLES_MANAGER] = m_extTablesManager.get(); - - m_p4ManagerPrecedence.push_back(m_tablesDefnManager.get()); - m_p4ManagerPrecedence.push_back(m_routerIntfManager.get()); - m_p4ManagerPrecedence.push_back(m_neighborManager.get()); - m_p4ManagerPrecedence.push_back(m_greTunnelManager.get()); - m_p4ManagerPrecedence.push_back(m_nextHopManager.get()); - m_p4ManagerPrecedence.push_back(m_wcmpManager.get()); - m_p4ManagerPrecedence.push_back(m_routeManager.get()); - m_p4ManagerPrecedence.push_back(m_mirrorSessionManager.get()); - m_p4ManagerPrecedence.push_back(m_aclTableManager.get()); - m_p4ManagerPrecedence.push_back(m_aclRuleManager.get()); - m_p4ManagerPrecedence.push_back(m_l3AdmitManager.get()); - m_p4ManagerPrecedence.push_back(m_extTablesManager.get()); - - tablesinfo = nullptr; - // Add timer executor to update ACL counters stats in COUNTERS_DB - auto acl_interv = timespec{.tv_sec = P4_COUNTERS_READ_INTERVAL, .tv_nsec = 0}; - m_aclCounterStatsTimer = new swss::SelectableTimer(acl_interv); - auto acl_executor = new swss::ExecutableTimer( - m_aclCounterStatsTimer, this, P4_ACL_COUNTERS_STATS_POLL_TIMER_NAME); - Orch::addExecutor(acl_executor); - m_aclCounterStatsTimer->start(); - - // Add timer executor to update EXT counters stats in COUNTERS_DB - auto ext_interv = timespec{.tv_sec = P4_COUNTERS_READ_INTERVAL, .tv_nsec = 0}; - m_extCounterStatsTimer = new swss::SelectableTimer(ext_interv); - auto ext_executor = new swss::ExecutableTimer( - m_extCounterStatsTimer, this, P4_EXT_COUNTERS_STATS_POLL_TIMER_NAME); - Orch::addExecutor(ext_executor); - m_extCounterStatsTimer->start(); - - // Add port state change notification handling support - swss::DBConnector notificationsDb("ASIC_DB", 0); - m_portStatusNotificationConsumer = - new swss::NotificationConsumer(¬ificationsDb, "NOTIFICATIONS"); - auto portStatusNotifier = new Notifier(m_portStatusNotificationConsumer, this, - "PORT_STATUS_NOTIFICATIONS"); - Orch::addExecutor(portStatusNotifier); +P4Orch::P4Orch(swss::DBConnector *db, std::vector tableNames, VRFOrch *vrfOrch, CoppOrch *coppOrch) + : Orch(db, tableNames) +{ + SWSS_LOG_ENTER(); + + m_tablesDefnManager = std::make_unique(&m_p4OidMapper, &m_publisher); + m_routerIntfManager = std::make_unique(&m_p4OidMapper, &m_publisher); + m_neighborManager = std::make_unique(&m_p4OidMapper, &m_publisher); + m_greTunnelManager = std::make_unique(&m_p4OidMapper, &m_publisher); + m_nextHopManager = std::make_unique(&m_p4OidMapper, &m_publisher); + m_routeManager = std::make_unique(&m_p4OidMapper, vrfOrch, &m_publisher); + m_mirrorSessionManager = std::make_unique(&m_p4OidMapper, &m_publisher); + m_aclTableManager = std::make_unique(&m_p4OidMapper, &m_publisher); + m_aclRuleManager = std::make_unique(&m_p4OidMapper, vrfOrch, coppOrch, &m_publisher); + m_wcmpManager = std::make_unique(&m_p4OidMapper, &m_publisher); + m_l3AdmitManager = std::make_unique(&m_p4OidMapper, &m_publisher); + m_extTablesManager = std::make_unique(&m_p4OidMapper, vrfOrch, &m_publisher); + + m_p4TableToManagerMap[APP_P4RT_TABLES_DEFINITION_TABLE_NAME] = m_tablesDefnManager.get(); + m_p4TableToManagerMap[APP_P4RT_ROUTER_INTERFACE_TABLE_NAME] = m_routerIntfManager.get(); + m_p4TableToManagerMap[APP_P4RT_NEIGHBOR_TABLE_NAME] = m_neighborManager.get(); + m_p4TableToManagerMap[APP_P4RT_TUNNEL_TABLE_NAME] = m_greTunnelManager.get(); + m_p4TableToManagerMap[APP_P4RT_NEXTHOP_TABLE_NAME] = m_nextHopManager.get(); + m_p4TableToManagerMap[APP_P4RT_IPV4_TABLE_NAME] = m_routeManager.get(); + m_p4TableToManagerMap[APP_P4RT_IPV6_TABLE_NAME] = m_routeManager.get(); + m_p4TableToManagerMap[APP_P4RT_MIRROR_SESSION_TABLE_NAME] = m_mirrorSessionManager.get(); + m_p4TableToManagerMap[APP_P4RT_ACL_TABLE_DEFINITION_NAME] = m_aclTableManager.get(); + m_p4TableToManagerMap[APP_P4RT_WCMP_GROUP_TABLE_NAME] = m_wcmpManager.get(); + m_p4TableToManagerMap[APP_P4RT_L3_ADMIT_TABLE_NAME] = m_l3AdmitManager.get(); + m_p4TableToManagerMap[APP_P4RT_EXT_TABLES_MANAGER] = m_extTablesManager.get(); + + m_p4ManagerPrecedence.push_back(m_tablesDefnManager.get()); + m_p4ManagerPrecedence.push_back(m_routerIntfManager.get()); + m_p4ManagerPrecedence.push_back(m_neighborManager.get()); + m_p4ManagerPrecedence.push_back(m_greTunnelManager.get()); + m_p4ManagerPrecedence.push_back(m_nextHopManager.get()); + m_p4ManagerPrecedence.push_back(m_wcmpManager.get()); + m_p4ManagerPrecedence.push_back(m_routeManager.get()); + m_p4ManagerPrecedence.push_back(m_mirrorSessionManager.get()); + m_p4ManagerPrecedence.push_back(m_aclTableManager.get()); + m_p4ManagerPrecedence.push_back(m_aclRuleManager.get()); + m_p4ManagerPrecedence.push_back(m_l3AdmitManager.get()); + m_p4ManagerPrecedence.push_back(m_extTablesManager.get()); + + tablesinfo = nullptr; + // Add timer executor to update ACL counters stats in COUNTERS_DB + auto acl_interv = timespec{.tv_sec = P4_COUNTERS_READ_INTERVAL, .tv_nsec = 0}; + m_aclCounterStatsTimer = new swss::SelectableTimer(acl_interv); + auto acl_executor = new swss::ExecutableTimer(m_aclCounterStatsTimer, this, P4_ACL_COUNTERS_STATS_POLL_TIMER_NAME); + Orch::addExecutor(acl_executor); + m_aclCounterStatsTimer->start(); + + // Add timer executor to update EXT counters stats in COUNTERS_DB + auto ext_interv = timespec{.tv_sec = P4_COUNTERS_READ_INTERVAL, .tv_nsec = 0}; + m_extCounterStatsTimer = new swss::SelectableTimer(ext_interv); + auto ext_executor = new swss::ExecutableTimer(m_extCounterStatsTimer, this, P4_EXT_COUNTERS_STATS_POLL_TIMER_NAME); + Orch::addExecutor(ext_executor); + m_extCounterStatsTimer->start(); + + // Add port state change notification handling support + swss::DBConnector notificationsDb("ASIC_DB", 0); + m_portStatusNotificationConsumer = new swss::NotificationConsumer(¬ificationsDb, "NOTIFICATIONS"); + auto portStatusNotifier = new Notifier(m_portStatusNotificationConsumer, this, "PORT_STATUS_NOTIFICATIONS"); + Orch::addExecutor(portStatusNotifier); } -void P4Orch::doTask(Consumer& consumer) { - SWSS_LOG_ENTER(); - - if (!gPortsOrch->allPortsReady()) { - return; - } - - const std::string table_name = consumer.getTableName(); - if (table_name != APP_P4RT_TABLE_NAME) { - SWSS_LOG_ERROR("Incorrect table name %s (expected %s)", table_name.c_str(), - APP_P4RT_TABLE_NAME); - return; - } - - auto it = consumer.m_toSync.begin(); - while (it != consumer.m_toSync.end()) { - const swss::KeyOpFieldsValuesTuple key_op_fvs_tuple = it->second; - const std::string key = kfvKey(key_op_fvs_tuple); - it = consumer.m_toSync.erase(it); - std::string table_name; - std::string key_content; - parseP4RTKey(key, &table_name, &key_content); - if (table_name.empty()) { - auto status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Table name cannot be empty, but was empty in key: " - << key; - SWSS_LOG_ERROR("%s", status.message().c_str()); - m_publisher.publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status); - continue; +void P4Orch::doTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + + if (!gPortsOrch->allPortsReady()) + { + return; } - if (m_p4TableToManagerMap.find(table_name) != m_p4TableToManagerMap.end()) { - m_p4TableToManagerMap[table_name]->enqueue(table_name, key_op_fvs_tuple); - } else { - if (table_name.rfind(p4orch::kTablePrefixEXT, 0) != std::string::npos) { - m_p4TableToManagerMap[APP_P4RT_EXT_TABLES_MANAGER]->enqueue( - table_name, key_op_fvs_tuple); - } else { - auto status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to find P4Orch Manager for " << table_name - << " P4RT DB table"; - SWSS_LOG_ERROR("%s", status.message().c_str()); - m_publisher.publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status); - } + + const std::string table_name = consumer.getTableName(); + if (table_name != APP_P4RT_TABLE_NAME) + { + SWSS_LOG_ERROR("Incorrect table name %s (expected %s)", table_name.c_str(), APP_P4RT_TABLE_NAME); + return; } - } - for (const auto& manager : m_p4ManagerPrecedence) { - manager->drain(); - } + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + const swss::KeyOpFieldsValuesTuple key_op_fvs_tuple = it->second; + const std::string key = kfvKey(key_op_fvs_tuple); + it = consumer.m_toSync.erase(it); + std::string table_name; + std::string key_content; + parseP4RTKey(key, &table_name, &key_content); + if (table_name.empty()) + { + auto status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Table name cannot be empty, but was empty in key: " << key; + SWSS_LOG_ERROR("%s", status.message().c_str()); + m_publisher.publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status); + continue; + } + if (m_p4TableToManagerMap.find(table_name) != m_p4TableToManagerMap.end()) + { + m_p4TableToManagerMap[table_name]->enqueue(table_name, key_op_fvs_tuple); + } + else + { + if (table_name.rfind(p4orch::kTablePrefixEXT, 0) != std::string::npos) + { + m_p4TableToManagerMap[APP_P4RT_EXT_TABLES_MANAGER]->enqueue(table_name, key_op_fvs_tuple); + } + else + { + auto status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Failed to find P4Orch Manager for " << table_name << " P4RT DB table"; + SWSS_LOG_ERROR("%s", status.message().c_str()); + m_publisher.publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status); + } + } + } - m_publisher.flush(); -} + for (const auto &manager : m_p4ManagerPrecedence) + { + manager->drain(); + } -void P4Orch::doTask(swss::SelectableTimer& timer) { - SWSS_LOG_ENTER(); - - if (!gPortsOrch->allPortsReady()) { - return; - } - - if (&timer == m_aclCounterStatsTimer) { - m_aclRuleManager->doAclCounterStatsTask(); - } else if (&timer == m_extCounterStatsTimer) { - m_extTablesManager->doExtCounterStatsTask(); - } else { - SWSS_LOG_NOTICE( - "Unrecognized timer passed in P4Orch::doTask(swss::SelectableTimer& " - "timer)"); - } + m_publisher.flush(); } -void P4Orch::handlePortStatusChangeNotification(const std::string& op, - const std::string& data) { - if (op == "port_state_change") { - uint32_t count; - sai_port_oper_status_notification_t* port_oper_status = nullptr; - sai_deserialize_port_oper_status_ntf(data, count, &port_oper_status); - - for (uint32_t i = 0; i < count; i++) { - sai_object_id_t id = port_oper_status[i].port_id; - sai_port_oper_status_t status = port_oper_status[i].port_state; - - Port port; - if (!gPortsOrch->getPort(id, port)) { - SWSS_LOG_ERROR("Failed to get port object for port id 0x%" PRIx64, id); - continue; - } - - // Update port oper-status in local map - m_wcmpManager->updatePortOperStatusMap(port.m_alias, status); - - if (status == SAI_PORT_OPER_STATUS_UP) { - m_wcmpManager->restorePrunedNextHops(port.m_alias); - } else { - m_wcmpManager->pruneNextHops(port.m_alias); - } +void P4Orch::doTask(swss::SelectableTimer &timer) +{ + SWSS_LOG_ENTER(); + + if (!gPortsOrch->allPortsReady()) + { + return; } - sai_deserialize_free_port_oper_status_ntf(count, port_oper_status); - } + if (&timer == m_aclCounterStatsTimer) + { + m_aclRuleManager->doAclCounterStatsTask(); + } + else if (&timer == m_extCounterStatsTimer) + { + m_extTablesManager->doExtCounterStatsTask(); + } + else + { + SWSS_LOG_NOTICE("Unrecognized timer passed in P4Orch::doTask(swss::SelectableTimer& " + "timer)"); + } } -void P4Orch::doTask(NotificationConsumer& consumer) { - SWSS_LOG_ENTER(); +void P4Orch::handlePortStatusChangeNotification(const std::string &op, const std::string &data) +{ + if (op == "port_state_change") + { + uint32_t count; + sai_port_oper_status_notification_t *port_oper_status = nullptr; + sai_deserialize_port_oper_status_ntf(data, count, &port_oper_status); + + for (uint32_t i = 0; i < count; i++) + { + sai_object_id_t id = port_oper_status[i].port_id; + sai_port_oper_status_t status = port_oper_status[i].port_state; + + Port port; + if (!gPortsOrch->getPort(id, port)) + { + SWSS_LOG_ERROR("Failed to get port object for port id 0x%" PRIx64, id); + continue; + } + + // Update port oper-status in local map + m_wcmpManager->updatePortOperStatusMap(port.m_alias, status); + + if (status == SAI_PORT_OPER_STATUS_UP) + { + m_wcmpManager->restorePrunedNextHops(port.m_alias); + } + else + { + m_wcmpManager->pruneNextHops(port.m_alias); + } + } + + sai_deserialize_free_port_oper_status_ntf(count, port_oper_status); + } +} - if (!gPortsOrch->allPortsReady()) { - return; - } +void P4Orch::doTask(NotificationConsumer &consumer) +{ + SWSS_LOG_ENTER(); + + if (!gPortsOrch->allPortsReady()) + { + return; + } - std::string op, data; - std::vector values; + std::string op, data; + std::vector values; - consumer.pop(op, data, values); + consumer.pop(op, data, values); - if (&consumer == m_portStatusNotificationConsumer) { - handlePortStatusChangeNotification(op, data); - } + if (&consumer == m_portStatusNotificationConsumer) + { + handlePortStatusChangeNotification(op, data); + } } -bool P4Orch::addAclTableToManagerMapping(const std::string& acl_table_name) { - SWSS_LOG_ENTER(); - if (m_p4TableToManagerMap.find(acl_table_name) != - m_p4TableToManagerMap.end()) { - SWSS_LOG_NOTICE("Consumer for ACL table %s already exists in P4Orch", - acl_table_name.c_str()); - return false; - } - m_p4TableToManagerMap[acl_table_name] = m_aclRuleManager.get(); - return true; +bool P4Orch::addAclTableToManagerMapping(const std::string &acl_table_name) +{ + SWSS_LOG_ENTER(); + if (m_p4TableToManagerMap.find(acl_table_name) != m_p4TableToManagerMap.end()) + { + SWSS_LOG_NOTICE("Consumer for ACL table %s already exists in P4Orch", acl_table_name.c_str()); + return false; + } + m_p4TableToManagerMap[acl_table_name] = m_aclRuleManager.get(); + return true; } -bool P4Orch::removeAclTableToManagerMapping(const std::string& acl_table_name) { - SWSS_LOG_ENTER(); - if (m_p4TableToManagerMap.find(acl_table_name) == - m_p4TableToManagerMap.end()) { - SWSS_LOG_NOTICE("Consumer for ACL table %s does not exist in P4Orch", - acl_table_name.c_str()); - return false; - } - m_p4TableToManagerMap.erase(acl_table_name); - return true; +bool P4Orch::removeAclTableToManagerMapping(const std::string &acl_table_name) +{ + SWSS_LOG_ENTER(); + if (m_p4TableToManagerMap.find(acl_table_name) == m_p4TableToManagerMap.end()) + { + SWSS_LOG_NOTICE("Consumer for ACL table %s does not exist in P4Orch", acl_table_name.c_str()); + return false; + } + m_p4TableToManagerMap.erase(acl_table_name); + return true; } -p4orch::AclTableManager* P4Orch::getAclTableManager() { - return m_aclTableManager.get(); +p4orch::AclTableManager *P4Orch::getAclTableManager() +{ + return m_aclTableManager.get(); } -p4orch::AclRuleManager* P4Orch::getAclRuleManager() { - return m_aclRuleManager.get(); +p4orch::AclRuleManager *P4Orch::getAclRuleManager() +{ + return m_aclRuleManager.get(); } -p4orch::WcmpManager* P4Orch::getWcmpManager() { return m_wcmpManager.get(); } +p4orch::WcmpManager *P4Orch::getWcmpManager() +{ + return m_wcmpManager.get(); +} -GreTunnelManager* P4Orch::getGreTunnelManager() { - return m_greTunnelManager.get(); +GreTunnelManager *P4Orch::getGreTunnelManager() +{ + return m_greTunnelManager.get(); } diff --git a/orchagent/p4orch/p4orch.h b/orchagent/p4orch/p4orch.h index 6f41bca8c55..549aac17b20 100644 --- a/orchagent/p4orch/p4orch.h +++ b/orchagent/p4orch/p4orch.h @@ -38,55 +38,53 @@ static const std::map FixedTablesMap = { {"l3_admit_table", APP_P4RT_L3_ADMIT_TABLE_NAME}, {"tunnel_table", APP_P4RT_TUNNEL_TABLE_NAME}}; -class P4Orch : public Orch { - public: - P4Orch(swss::DBConnector* db, std::vector tableNames, - VRFOrch* vrfOrch, CoppOrch* coppOrch); - // Add ACL table to ACLRuleManager mapping in P4Orch. - bool addAclTableToManagerMapping(const std::string& acl_table_name); - // Remove the ACL table name to AclRuleManager mapping in P4Orch - bool removeAclTableToManagerMapping(const std::string& acl_table_name); - p4orch::AclTableManager* getAclTableManager(); - p4orch::AclRuleManager* getAclRuleManager(); - p4orch::WcmpManager* getWcmpManager(); - GreTunnelManager* getGreTunnelManager(); - TablesInfo* tablesinfo = NULL; +class P4Orch : public Orch +{ + public: + P4Orch(swss::DBConnector *db, std::vector tableNames, VRFOrch *vrfOrch, CoppOrch *coppOrch); + // Add ACL table to ACLRuleManager mapping in P4Orch. + bool addAclTableToManagerMapping(const std::string &acl_table_name); + // Remove the ACL table name to AclRuleManager mapping in P4Orch + bool removeAclTableToManagerMapping(const std::string &acl_table_name); + p4orch::AclTableManager *getAclTableManager(); + p4orch::AclRuleManager *getAclRuleManager(); + p4orch::WcmpManager *getWcmpManager(); + GreTunnelManager *getGreTunnelManager(); + TablesInfo *tablesinfo = NULL; - // m_p4TableToManagerMap: P4 APP DB table name, P4 Object Manager - std::unordered_map - m_p4TableToManagerMap; + // m_p4TableToManagerMap: P4 APP DB table name, P4 Object Manager + std::unordered_map m_p4TableToManagerMap; - private: - void doTask(Consumer& consumer); - void doTask(swss::SelectableTimer& timer); - void doTask(swss::NotificationConsumer& consumer); - void handlePortStatusChangeNotification(const std::string& op, - const std::string& data); + private: + void doTask(Consumer &consumer); + void doTask(swss::SelectableTimer &timer); + void doTask(swss::NotificationConsumer &consumer); + void handlePortStatusChangeNotification(const std::string &op, const std::string &data); - // P4 object manager request processing order. - std::vector m_p4ManagerPrecedence; + // P4 object manager request processing order. + std::vector m_p4ManagerPrecedence; - swss::SelectableTimer* m_aclCounterStatsTimer; - swss::SelectableTimer* m_extCounterStatsTimer; - P4OidMapper m_p4OidMapper; - std::unique_ptr m_tablesDefnManager; - std::unique_ptr m_routerIntfManager; - std::unique_ptr m_greTunnelManager; - std::unique_ptr m_neighborManager; - std::unique_ptr m_nextHopManager; - std::unique_ptr m_routeManager; - std::unique_ptr m_mirrorSessionManager; - std::unique_ptr m_aclTableManager; - std::unique_ptr m_aclRuleManager; - std::unique_ptr m_wcmpManager; - std::unique_ptr m_l3AdmitManager; - std::unique_ptr m_extTablesManager; + swss::SelectableTimer *m_aclCounterStatsTimer; + swss::SelectableTimer *m_extCounterStatsTimer; + P4OidMapper m_p4OidMapper; + std::unique_ptr m_tablesDefnManager; + std::unique_ptr m_routerIntfManager; + std::unique_ptr m_greTunnelManager; + std::unique_ptr m_neighborManager; + std::unique_ptr m_nextHopManager; + std::unique_ptr m_routeManager; + std::unique_ptr m_mirrorSessionManager; + std::unique_ptr m_aclTableManager; + std::unique_ptr m_aclRuleManager; + std::unique_ptr m_wcmpManager; + std::unique_ptr m_l3AdmitManager; + std::unique_ptr m_extTablesManager; - // Notification consumer for port state change - swss::NotificationConsumer* m_portStatusNotificationConsumer; + // Notification consumer for port state change + swss::NotificationConsumer *m_portStatusNotificationConsumer; - // Sepcial publisher that writes to APPL DB instead of APPL STATE DB. - ResponsePublisher m_publisher{"APPL_DB", /*bool buffered=*/true, /*db_write_thread=*/true}; + // Sepcial publisher that writes to APPL DB instead of APPL STATE DB. + ResponsePublisher m_publisher{"APPL_DB", /*bool buffered=*/true, /*db_write_thread=*/true}; - friend class p4orch::test::WcmpManagerTest; + friend class p4orch::test::WcmpManagerTest; }; diff --git a/orchagent/p4orch/p4orch_util.cpp b/orchagent/p4orch/p4orch_util.cpp index 451ce9d3732..dd0a4171ad8 100644 --- a/orchagent/p4orch/p4orch_util.cpp +++ b/orchagent/p4orch/p4orch_util.cpp @@ -4,217 +4,230 @@ #include "schema.h" using ::p4orch::kTableKeyDelimiter; -extern P4Orch* gP4Orch; +extern P4Orch *gP4Orch; // Prepends "match/" to the input string str to construct a new string. -std::string prependMatchField(const std::string& str) { - return std::string(p4orch::kMatchPrefix) + p4orch::kFieldDelimiter + str; +std::string prependMatchField(const std::string &str) +{ + return std::string(p4orch::kMatchPrefix) + p4orch::kFieldDelimiter + str; } // Prepends "param/" to the input string str to construct a new string. -std::string prependParamField(const std::string& str) { - return std::string(p4orch::kActionParamPrefix) + p4orch::kFieldDelimiter + - str; -} - -void parseP4RTKey(const std::string& key, std::string* table_name, - std::string* key_content) { - auto pos = key.find_first_of(kTableKeyDelimiter); - if (pos == std::string::npos) { - *table_name = ""; - *key_content = ""; - return; - } - *table_name = key.substr(0, pos); - *key_content = key.substr(pos + 1); -} - -std::string verifyAttrs(const std::vector& targets, - const std::vector& exp, - const std::vector& opt, - bool allow_unknown) { - std::map exp_map; - for (const auto& fv : exp) { - exp_map[fvField(fv)] = fvValue(fv); - } - std::map opt_map; - for (const auto& fv : opt) { - opt_map[fvField(fv)] = fvValue(fv); - } - - std::set fields; - for (const auto& fv : targets) { - fields.insert(fvField(fv)); - bool found = false; - if (exp_map.count(fvField(fv))) { - found = true; - if (fvValue(fv) != exp_map.at(fvField(fv))) { - return fvField(fv) + " value mismatch, exp " + exp_map.at(fvField(fv)) + - " got " + fvValue(fv); - } +std::string prependParamField(const std::string &str) +{ + return std::string(p4orch::kActionParamPrefix) + p4orch::kFieldDelimiter + str; +} + +void parseP4RTKey(const std::string &key, std::string *table_name, std::string *key_content) +{ + auto pos = key.find_first_of(kTableKeyDelimiter); + if (pos == std::string::npos) + { + *table_name = ""; + *key_content = ""; + return; } - if (opt_map.count(fvField(fv))) { - found = true; - if (fvValue(fv) != opt_map.at(fvField(fv))) { - return fvField(fv) + " value mismatch, exp " + opt_map.at(fvField(fv)) + - " got " + fvValue(fv); - } + *table_name = key.substr(0, pos); + *key_content = key.substr(pos + 1); +} + +std::string verifyAttrs(const std::vector &targets, + const std::vector &exp, const std::vector &opt, + bool allow_unknown) +{ + std::map exp_map; + for (const auto &fv : exp) + { + exp_map[fvField(fv)] = fvValue(fv); } - if (!found && !allow_unknown) { - return std::string("Unexpected field ") + fvField(fv); + std::map opt_map; + for (const auto &fv : opt) + { + opt_map[fvField(fv)] = fvValue(fv); } - } - for (const auto& it : exp_map) { - if (!fields.count(it.first)) { - return std::string("Missing field ") + it.first; - } - } - return ""; -} -TableInfo* getTableInfo(const std::string& table_name) { - if (!gP4Orch->tablesinfo) { - return nullptr; - } - - auto it = gP4Orch->tablesinfo->m_tableInfoMap.find(table_name); - if (it == gP4Orch->tablesinfo->m_tableInfoMap.end()) { - return nullptr; - } - - return &it->second; + std::set fields; + for (const auto &fv : targets) + { + fields.insert(fvField(fv)); + bool found = false; + if (exp_map.count(fvField(fv))) + { + found = true; + if (fvValue(fv) != exp_map.at(fvField(fv))) + { + return fvField(fv) + " value mismatch, exp " + exp_map.at(fvField(fv)) + " got " + fvValue(fv); + } + } + if (opt_map.count(fvField(fv))) + { + found = true; + if (fvValue(fv) != opt_map.at(fvField(fv))) + { + return fvField(fv) + " value mismatch, exp " + opt_map.at(fvField(fv)) + " got " + fvValue(fv); + } + } + if (!found && !allow_unknown) + { + return std::string("Unexpected field ") + fvField(fv); + } + } + for (const auto &it : exp_map) + { + if (!fields.count(it.first)) + { + return std::string("Missing field ") + it.first; + } + } + return ""; } -ActionInfo* getTableActionInfo(TableInfo* table, - const std::string& action_name) { - if (!table) { - return nullptr; - } - - auto it = table->action_fields.find(action_name); - if (it == table->action_fields.end()) { - return nullptr; - } +TableInfo *getTableInfo(const std::string &table_name) +{ + if (!gP4Orch->tablesinfo) + { + return nullptr; + } - return &it->second; -} + auto it = gP4Orch->tablesinfo->m_tableInfoMap.find(table_name); + if (it == gP4Orch->tablesinfo->m_tableInfoMap.end()) + { + return nullptr; + } -std::string KeyGenerator::generateTablesInfoKey(const std::string& context) { - std::map fv_map = {{"context", context}}; - return generateKey(fv_map); + return &it->second; } -std::string KeyGenerator::generateRouteKey(const std::string& vrf_id, - const swss::IpPrefix& ip_prefix) { - std::map fv_map = { - {p4orch::kVrfId, vrf_id}, - {ip_prefix.isV4() ? p4orch::kIpv4Dst : p4orch::kIpv6Dst, - ip_prefix.to_string()}}; - return generateKey(fv_map); -} +ActionInfo *getTableActionInfo(TableInfo *table, const std::string &action_name) +{ + if (!table) + { + return nullptr; + } -std::string KeyGenerator::generateRouterInterfaceKey( - const std::string& router_intf_id) { - std::map fv_map = { - {p4orch::kRouterInterfaceId, router_intf_id}}; - return generateKey(fv_map); -} + auto it = table->action_fields.find(action_name); + if (it == table->action_fields.end()) + { + return nullptr; + } -std::string KeyGenerator::generateNeighborKey( - const std::string& router_intf_id, const swss::IpAddress& neighbor_id) { - std::map fv_map = { - {p4orch::kRouterInterfaceId, router_intf_id}, - {p4orch::kNeighborId, neighbor_id.to_string()}}; - return generateKey(fv_map); + return &it->second; } -std::string KeyGenerator::generateNextHopKey(const std::string& next_hop_id) { - std::map fv_map = { - {p4orch::kNexthopId, next_hop_id}}; - return generateKey(fv_map); +std::string KeyGenerator::generateTablesInfoKey(const std::string &context) +{ + std::map fv_map = {{"context", context}}; + return generateKey(fv_map); } -std::string KeyGenerator::generateMirrorSessionKey( - const std::string& mirror_session_id) { - std::map fv_map = { - {p4orch::kMirrorSessionId, mirror_session_id}}; - return generateKey(fv_map); +std::string KeyGenerator::generateRouteKey(const std::string &vrf_id, const swss::IpPrefix &ip_prefix) +{ + std::map fv_map = { + {p4orch::kVrfId, vrf_id}, {ip_prefix.isV4() ? p4orch::kIpv4Dst : p4orch::kIpv6Dst, ip_prefix.to_string()}}; + return generateKey(fv_map); } -std::string KeyGenerator::generateWcmpGroupKey( - const std::string& wcmp_group_id) { - std::map fv_map = { - {p4orch::kWcmpGroupId, wcmp_group_id}}; - return generateKey(fv_map); +std::string KeyGenerator::generateRouterInterfaceKey(const std::string &router_intf_id) +{ + std::map fv_map = {{p4orch::kRouterInterfaceId, router_intf_id}}; + return generateKey(fv_map); } -std::string KeyGenerator::generateAclRuleKey( - const std::map& match_fields, - const std::string& priority) { - std::map fv_map = {}; - for (const auto& match_field : match_fields) { - fv_map.emplace(std::string(p4orch::kMatchPrefix) + p4orch::kFieldDelimiter + - match_field.first, - match_field.second); - } - fv_map.emplace(p4orch::kPriority, priority); - return generateKey(fv_map); +std::string KeyGenerator::generateNeighborKey(const std::string &router_intf_id, const swss::IpAddress &neighbor_id) +{ + std::map fv_map = {{p4orch::kRouterInterfaceId, router_intf_id}, + {p4orch::kNeighborId, neighbor_id.to_string()}}; + return generateKey(fv_map); } -std::string KeyGenerator::generateL3AdmitKey( - const swss::MacAddress& mac_address_data, - const swss::MacAddress& mac_address_mask, const std::string& port_name, - const uint32_t& priority) { - std::map fv_map = {}; - fv_map.emplace(std::string(p4orch::kMatchPrefix) + p4orch::kFieldDelimiter + - p4orch::kDstMac, - mac_address_data.to_string() + p4orch::kDataMaskDelimiter + - mac_address_mask.to_string()); - if (!port_name.empty()) { - fv_map.emplace(std::string(p4orch::kMatchPrefix) + p4orch::kFieldDelimiter + - p4orch::kInPort, - port_name); - } - fv_map.emplace(p4orch::kPriority, std::to_string(priority)); - return generateKey(fv_map); +std::string KeyGenerator::generateNextHopKey(const std::string &next_hop_id) +{ + std::map fv_map = {{p4orch::kNexthopId, next_hop_id}}; + return generateKey(fv_map); } -std::string KeyGenerator::generateTunnelKey(const std::string& tunnel_id) { - std::map fv_map = {{p4orch::kTunnelId, tunnel_id}}; - return generateKey(fv_map); +std::string KeyGenerator::generateMirrorSessionKey(const std::string &mirror_session_id) +{ + std::map fv_map = {{p4orch::kMirrorSessionId, mirror_session_id}}; + return generateKey(fv_map); } -std::string KeyGenerator::generateExtTableKey(const std::string& table_name, - const std::string& table_key) { - std::string key; - - key.append(table_name); - key.append(":"); - key.append(table_key); - - return key; +std::string KeyGenerator::generateWcmpGroupKey(const std::string &wcmp_group_id) +{ + std::map fv_map = {{p4orch::kWcmpGroupId, wcmp_group_id}}; + return generateKey(fv_map); } -std::string KeyGenerator::generateKey( - const std::map& fv_map) { - std::string key; - bool append_delimiter = false; - for (const auto& it : fv_map) { - if (append_delimiter) { - key.append(":"); - } else { - append_delimiter = true; +std::string KeyGenerator::generateAclRuleKey(const std::map &match_fields, + const std::string &priority) +{ + std::map fv_map = {}; + for (const auto &match_field : match_fields) + { + fv_map.emplace(std::string(p4orch::kMatchPrefix) + p4orch::kFieldDelimiter + match_field.first, + match_field.second); + } + fv_map.emplace(p4orch::kPriority, priority); + return generateKey(fv_map); +} + +std::string KeyGenerator::generateL3AdmitKey(const swss::MacAddress &mac_address_data, + const swss::MacAddress &mac_address_mask, const std::string &port_name, + const uint32_t &priority) +{ + std::map fv_map = {}; + fv_map.emplace(std::string(p4orch::kMatchPrefix) + p4orch::kFieldDelimiter + p4orch::kDstMac, + mac_address_data.to_string() + p4orch::kDataMaskDelimiter + mac_address_mask.to_string()); + if (!port_name.empty()) + { + fv_map.emplace(std::string(p4orch::kMatchPrefix) + p4orch::kFieldDelimiter + p4orch::kInPort, port_name); + } + fv_map.emplace(p4orch::kPriority, std::to_string(priority)); + return generateKey(fv_map); +} + +std::string KeyGenerator::generateTunnelKey(const std::string &tunnel_id) +{ + std::map fv_map = {{p4orch::kTunnelId, tunnel_id}}; + return generateKey(fv_map); +} + +std::string KeyGenerator::generateExtTableKey(const std::string &table_name, const std::string &table_key) +{ + std::string key; + + key.append(table_name); + key.append(":"); + key.append(table_key); + + return key; +} + +std::string KeyGenerator::generateKey(const std::map &fv_map) +{ + std::string key; + bool append_delimiter = false; + for (const auto &it : fv_map) + { + if (append_delimiter) + { + key.append(":"); + } + else + { + append_delimiter = true; + } + key.append(it.first); + key.append("="); + key.append(it.second); } - key.append(it.first); - key.append("="); - key.append(it.second); - } - return key; + return key; } -std::string trim(const std::string& s) { - size_t end = s.find_last_not_of(" "); - size_t start = s.find_first_not_of(" "); - return (end == std::string::npos) ? "" : s.substr(start, end - start + 1); +std::string trim(const std::string &s) +{ + size_t end = s.find_last_not_of(" "); + size_t start = s.find_first_not_of(" "); + return (end == std::string::npos) ? "" : s.substr(start, end - start + 1); } diff --git a/orchagent/p4orch/p4orch_util.h b/orchagent/p4orch/p4orch_util.h index 29fedbc5b85..9cfcf53a82c 100644 --- a/orchagent/p4orch/p4orch_util.h +++ b/orchagent/p4orch/p4orch_util.h @@ -12,133 +12,139 @@ #include "ipprefix.h" #include "macaddress.h" #include "table.h" -extern "C" { +extern "C" +{ #include "saitypes.h" } -namespace p4orch { +namespace p4orch +{ // Field names in P4RT APP DB entry. -constexpr char* kTablePrefixEXT = "EXT_"; -constexpr char* kRouterInterfaceId = "router_interface_id"; -constexpr char* kPort = "port"; -constexpr char* kInPort = "in_port"; -constexpr char* kSrcMac = "src_mac"; -constexpr char* kAction = "action"; -constexpr char* kActions = "actions"; -constexpr char* kWeight = "weight"; -constexpr char* kWatchPort = "watch_port"; -constexpr char* kNeighborId = "neighbor_id"; -constexpr char* kDstMac = "dst_mac"; -constexpr char* kNexthopId = "nexthop_id"; -constexpr char* kTunnelId = "tunnel_id"; -constexpr char* kVrfId = "vrf_id"; -constexpr char* kIpv4Dst = "ipv4_dst"; -constexpr char* kIpv6Dst = "ipv6_dst"; -constexpr char* kWcmpGroupId = "wcmp_group_id"; -constexpr char* kRouteMetadata = "route_metadata"; -constexpr char* kSetNexthopId = "set_nexthop_id"; -constexpr char* kSetWcmpGroupId = "set_wcmp_group_id"; -constexpr char* kSetNexthopIdAndMetadata = "set_nexthop_id_and_metadata"; -constexpr char* kSetWcmpGroupIdAndMetadata = "set_wcmp_group_id_and_metadata"; -constexpr char* kSetMetadataAndDrop = "set_metadata_and_drop"; -constexpr char* kSetNexthop = "set_nexthop"; -constexpr char* kSetIpNexthop = "set_ip_nexthop"; -constexpr char* kSetTunnelNexthop = "set_p2p_tunnel_encap_nexthop"; -constexpr char* kDrop = "drop"; -constexpr char* kTrap = "trap"; -constexpr char* kStage = "stage"; -constexpr char* kSize = "size"; -constexpr char* kPriority = "priority"; -constexpr char* kPacketColor = "packet_color"; -constexpr char* kMeterUnit = "meter/unit"; -constexpr char* kCounterUnit = "counter/unit"; +constexpr char *kTablePrefixEXT = "EXT_"; +constexpr char *kRouterInterfaceId = "router_interface_id"; +constexpr char *kPort = "port"; +constexpr char *kInPort = "in_port"; +constexpr char *kSrcMac = "src_mac"; +constexpr char *kAction = "action"; +constexpr char *kActions = "actions"; +constexpr char *kWeight = "weight"; +constexpr char *kWatchPort = "watch_port"; +constexpr char *kNeighborId = "neighbor_id"; +constexpr char *kDstMac = "dst_mac"; +constexpr char *kNexthopId = "nexthop_id"; +constexpr char *kTunnelId = "tunnel_id"; +constexpr char *kVrfId = "vrf_id"; +constexpr char *kIpv4Dst = "ipv4_dst"; +constexpr char *kIpv6Dst = "ipv6_dst"; +constexpr char *kWcmpGroupId = "wcmp_group_id"; +constexpr char *kRouteMetadata = "route_metadata"; +constexpr char *kSetNexthopId = "set_nexthop_id"; +constexpr char *kSetWcmpGroupId = "set_wcmp_group_id"; +constexpr char *kSetNexthopIdAndMetadata = "set_nexthop_id_and_metadata"; +constexpr char *kSetWcmpGroupIdAndMetadata = "set_wcmp_group_id_and_metadata"; +constexpr char *kSetMetadataAndDrop = "set_metadata_and_drop"; +constexpr char *kSetNexthop = "set_nexthop"; +constexpr char *kSetIpNexthop = "set_ip_nexthop"; +constexpr char *kSetTunnelNexthop = "set_p2p_tunnel_encap_nexthop"; +constexpr char *kDrop = "drop"; +constexpr char *kTrap = "trap"; +constexpr char *kStage = "stage"; +constexpr char *kSize = "size"; +constexpr char *kPriority = "priority"; +constexpr char *kPacketColor = "packet_color"; +constexpr char *kMeterUnit = "meter/unit"; +constexpr char *kCounterUnit = "counter/unit"; constexpr char kFieldDelimiter = '/'; constexpr char kTableKeyDelimiter = ':'; constexpr char kDataMaskDelimiter = '&'; constexpr char kPortsDelimiter = ','; -constexpr char* kMatchPrefix = "match"; -constexpr char* kActionParamPrefix = "param"; -constexpr char* kMeterPrefix = "meter"; -constexpr char* kMeterCir = "cir"; -constexpr char* kMeterCburst = "cburst"; -constexpr char* kMeterPir = "pir"; -constexpr char* kMeterPburst = "pburst"; -constexpr char* kControllerMetadata = "controller_metadata"; -constexpr char* kAclMatchFieldKind = "kind"; -constexpr char* kAclMatchFieldFormat = "format"; -constexpr char* kAclMatchFieldBitwidth = "bitwidth"; -constexpr char* kAclMatchFieldElements = "elements"; -constexpr char* kAclMatchFieldSaiField = "sai_field"; -constexpr char* kAclMatchFieldKindComposite = "composite"; -constexpr char* kAclMatchFieldKindUdf = "udf"; -constexpr char* kAclUdfBase = "base"; -constexpr char* kAclUdfOffset = "offset"; -constexpr char* kMirrorSessionId = "mirror_session_id"; -constexpr char* kSrcIp = "src_ip"; -constexpr char* kDstIp = "dst_ip"; -constexpr char* kEncapSrcIp = "encap_src_ip"; -constexpr char* kEncapDstIp = "encap_dst_ip"; -constexpr char* kTtl = "ttl"; -constexpr char* kTos = "tos"; -constexpr char* kMirrorAsIpv4Erspan = "mirror_as_ipv4_erspan"; -constexpr char* kL3AdmitAction = "admit_to_l3"; -constexpr char* kTunnelAction = "mark_for_p2p_tunnel_encap"; +constexpr char *kMatchPrefix = "match"; +constexpr char *kActionParamPrefix = "param"; +constexpr char *kMeterPrefix = "meter"; +constexpr char *kMeterCir = "cir"; +constexpr char *kMeterCburst = "cburst"; +constexpr char *kMeterPir = "pir"; +constexpr char *kMeterPburst = "pburst"; +constexpr char *kControllerMetadata = "controller_metadata"; +constexpr char *kAclMatchFieldKind = "kind"; +constexpr char *kAclMatchFieldFormat = "format"; +constexpr char *kAclMatchFieldBitwidth = "bitwidth"; +constexpr char *kAclMatchFieldElements = "elements"; +constexpr char *kAclMatchFieldSaiField = "sai_field"; +constexpr char *kAclMatchFieldKindComposite = "composite"; +constexpr char *kAclMatchFieldKindUdf = "udf"; +constexpr char *kAclUdfBase = "base"; +constexpr char *kAclUdfOffset = "offset"; +constexpr char *kMirrorSessionId = "mirror_session_id"; +constexpr char *kSrcIp = "src_ip"; +constexpr char *kDstIp = "dst_ip"; +constexpr char *kEncapSrcIp = "encap_src_ip"; +constexpr char *kEncapDstIp = "encap_dst_ip"; +constexpr char *kTtl = "ttl"; +constexpr char *kTos = "tos"; +constexpr char *kMirrorAsIpv4Erspan = "mirror_as_ipv4_erspan"; +constexpr char *kL3AdmitAction = "admit_to_l3"; +constexpr char *kTunnelAction = "mark_for_p2p_tunnel_encap"; // Field names in P4RT TABLE DEFINITION APP DB entry. -constexpr char* kTables = "tables"; -constexpr char* kId = "id"; -constexpr char* kName = "name"; -constexpr char* kAlias = "alias"; -constexpr char* kBitwidth = "bitwidth"; -constexpr char* kFormat = "format"; -constexpr char* kmatchFields = "matchFields"; -constexpr char* kActionParams = "params"; -constexpr char* kReferences = "references"; -constexpr char* kTableRef = "table"; -constexpr char* kMatchRef = "match"; -} // namespace p4orch +constexpr char *kTables = "tables"; +constexpr char *kId = "id"; +constexpr char *kName = "name"; +constexpr char *kAlias = "alias"; +constexpr char *kBitwidth = "bitwidth"; +constexpr char *kFormat = "format"; +constexpr char *kmatchFields = "matchFields"; +constexpr char *kActionParams = "params"; +constexpr char *kReferences = "references"; +constexpr char *kTableRef = "table"; +constexpr char *kMatchRef = "match"; +} // namespace p4orch // Prepends "match/" to the input string str to construct a new string. -std::string prependMatchField(const std::string& str); +std::string prependMatchField(const std::string &str); // Prepends "param/" to the input string str to construct a new string. -std::string prependParamField(const std::string& str); - -struct ActionParamInfo { - std::string name; - std::string fieldtype; - std::string datatype; - std::unordered_map table_reference_map; +std::string prependParamField(const std::string &str); + +struct ActionParamInfo +{ + std::string name; + std::string fieldtype; + std::string datatype; + std::unordered_map table_reference_map; }; -struct ActionInfo { - std::string name; - std::unordered_map params; - bool refers_to; +struct ActionInfo +{ + std::string name; + std::unordered_map params; + bool refers_to; }; -struct TableMatchInfo { - std::string name; - std::string fieldtype; - std::string datatype; - std::unordered_map table_reference_map; +struct TableMatchInfo +{ + std::string name; + std::string fieldtype; + std::string datatype; + std::unordered_map table_reference_map; }; /** * Dervied table definition * This is a derived state out of table definition provided by P4RT-APP */ -struct TableInfo { - std::string name; - int id; - int precedence; - std::unordered_map match_fields; - std::unordered_map action_fields; - bool counter_bytes_enabled; - bool counter_packets_enabled; - std::vector action_ref_tables; - // list of tables across all actions, of current table, refer to +struct TableInfo +{ + std::string name; + int id; + int precedence; + std::unordered_map match_fields; + std::unordered_map action_fields; + bool counter_bytes_enabled; + bool counter_packets_enabled; + std::vector action_ref_tables; + // list of tables across all actions, of current table, refer to }; /** @@ -146,158 +152,170 @@ struct TableInfo { */ typedef std::unordered_map TableInfoMap; -struct TablesInfoAppDbEntry { - std::string context; - std::string info; +struct TablesInfoAppDbEntry +{ + std::string context; + std::string info; }; -struct P4RouterInterfaceAppDbEntry { - std::string router_interface_id; - std::string port_name; - swss::MacAddress src_mac_address; - bool is_set_port_name = false; - bool is_set_src_mac = false; +struct P4RouterInterfaceAppDbEntry +{ + std::string router_interface_id; + std::string port_name; + swss::MacAddress src_mac_address; + bool is_set_port_name = false; + bool is_set_src_mac = false; }; -struct P4NeighborAppDbEntry { - std::string router_intf_id; - swss::IpAddress neighbor_id; - swss::MacAddress dst_mac_address; - bool is_set_dst_mac = false; +struct P4NeighborAppDbEntry +{ + std::string router_intf_id; + swss::IpAddress neighbor_id; + swss::MacAddress dst_mac_address; + bool is_set_dst_mac = false; }; -struct P4GreTunnelAppDbEntry { - // Match - std::string tunnel_id; - // Action - std::string router_interface_id; - swss::IpAddress encap_src_ip; - swss::IpAddress encap_dst_ip; - std::string action_str; +struct P4GreTunnelAppDbEntry +{ + // Match + std::string tunnel_id; + // Action + std::string router_interface_id; + swss::IpAddress encap_src_ip; + swss::IpAddress encap_dst_ip; + std::string action_str; }; // P4NextHopAppDbEntry holds entry deserialized from table // APP_P4RT_NEXTHOP_TABLE_NAME. -struct P4NextHopAppDbEntry { - // Key - std::string next_hop_id; - // Fields - std::string router_interface_id; - std::string gre_tunnel_id; - swss::IpAddress neighbor_id; - std::string action_str; +struct P4NextHopAppDbEntry +{ + // Key + std::string next_hop_id; + // Fields + std::string router_interface_id; + std::string gre_tunnel_id; + swss::IpAddress neighbor_id; + std::string action_str; }; // P4L3AdmitAppDbEntry holds entry deserialized from table // APP_P4RT_L3_ADMIT_TABLE_NAME. -struct P4L3AdmitAppDbEntry { - // Key (match parameters) - std::string port_name; // Optional - swss::MacAddress mac_address_data; - swss::MacAddress mac_address_mask; - uint32_t priority; +struct P4L3AdmitAppDbEntry +{ + // Key (match parameters) + std::string port_name; // Optional + swss::MacAddress mac_address_data; + swss::MacAddress mac_address_mask; + uint32_t priority; }; -struct P4MirrorSessionAppDbEntry { - // Key (match field) - std::string mirror_session_id; +struct P4MirrorSessionAppDbEntry +{ + // Key (match field) + std::string mirror_session_id; - // fields (action parameters) - std::string port; - bool has_port = false; + // fields (action parameters) + std::string port; + bool has_port = false; - swss::IpAddress src_ip; - bool has_src_ip = false; + swss::IpAddress src_ip; + bool has_src_ip = false; - swss::IpAddress dst_ip; - bool has_dst_ip = false; + swss::IpAddress dst_ip; + bool has_dst_ip = false; - swss::MacAddress src_mac; - bool has_src_mac = false; + swss::MacAddress src_mac; + bool has_src_mac = false; - swss::MacAddress dst_mac; - bool has_dst_mac = false; + swss::MacAddress dst_mac; + bool has_dst_mac = false; - uint8_t ttl = 0; - bool has_ttl = false; + uint8_t ttl = 0; + bool has_ttl = false; - uint8_t tos = 0; - bool has_tos = false; + uint8_t tos = 0; + bool has_tos = false; }; -struct P4ActionParamName { - std::string sai_action; - std::string p4_param_name; +struct P4ActionParamName +{ + std::string sai_action; + std::string p4_param_name; }; -struct P4PacketActionWithColor { - std::string packet_action; - std::string packet_color; +struct P4PacketActionWithColor +{ + std::string packet_action; + std::string packet_color; }; -struct P4AclTableDefinitionAppDbEntry { - // Key - std::string acl_table_name; - // Fields - std::string stage; - uint32_t size; - uint32_t priority; - std::map match_field_lookup; - std::map> action_field_lookup; - std::map> - packet_action_color_lookup; - std::string meter_unit; - std::string counter_unit; +struct P4AclTableDefinitionAppDbEntry +{ + // Key + std::string acl_table_name; + // Fields + std::string stage; + uint32_t size; + uint32_t priority; + std::map match_field_lookup; + std::map> action_field_lookup; + std::map> packet_action_color_lookup; + std::string meter_unit; + std::string counter_unit; }; -struct P4AclMeterAppDb { - bool enabled; - uint64_t cir; - uint64_t cburst; - uint64_t pir; - uint64_t pburst; - - P4AclMeterAppDb() : enabled(false) {} +struct P4AclMeterAppDb +{ + bool enabled; + uint64_t cir; + uint64_t cburst; + uint64_t pir; + uint64_t pburst; + + P4AclMeterAppDb() : enabled(false) + { + } }; -struct P4AclRuleAppDbEntry { - // Key - std::string acl_table_name; - std::map match_fvs; - uint32_t priority; - std::string db_key; - // Fields - std::string action; - std::map action_param_fvs; - P4AclMeterAppDb meter; +struct P4AclRuleAppDbEntry +{ + // Key + std::string acl_table_name; + std::map match_fvs; + uint32_t priority; + std::string db_key; + // Fields + std::string action; + std::map action_param_fvs; + P4AclMeterAppDb meter; }; -struct DepObject { - sai_object_type_t sai_object; - std::string key; - sai_object_id_t oid; +struct DepObject +{ + sai_object_type_t sai_object; + std::string key; + sai_object_id_t oid; }; -struct P4ExtTableAppDbEntry { - std::string db_key; - std::string table_name; - std::string table_key; - std::unordered_map> - action_params; - std::unordered_map action_dep_objects; +struct P4ExtTableAppDbEntry +{ + std::string db_key; + std::string table_name; + std::string table_key; + std::unordered_map> action_params; + std::unordered_map action_dep_objects; }; -TableInfo* getTableInfo(const std::string& table_name); -ActionInfo* getTableActionInfo(TableInfo* table, - const std::string& action_name); +TableInfo *getTableInfo(const std::string &table_name); +ActionInfo *getTableActionInfo(TableInfo *table, const std::string &action_name); // Get the table name and key content from the given P4RT key. // Outputs will be empty strings in case of error. // Example: FIXED_NEIGHBOR_TABLE:{content} // Table name: FIXED_NEIGHBOR_TABLE // Key content: {content} -void parseP4RTKey(const std::string& key, std::string* table_name, - std::string* key_content); +void parseP4RTKey(const std::string &key, std::string *table_name, std::string *key_content); // State verification function that verifies the table attributes. // Returns a non-empty string if verification fails. @@ -308,62 +326,54 @@ void parseP4RTKey(const std::string& key, std::string* table_name, // included. // allow_unknown: if set to false, verification will fail if there is an // attribute that is not in exp or opt. -std::string verifyAttrs(const std::vector& targets, - const std::vector& exp, - const std::vector& opt, +std::string verifyAttrs(const std::vector &targets, + const std::vector &exp, const std::vector &opt, bool allow_unknown); // class KeyGenerator includes member functions to generate keys for entries // stored in P4 Orch managers. -class KeyGenerator { - public: - static std::string generateTablesInfoKey(const std::string& context); +class KeyGenerator +{ + public: + static std::string generateTablesInfoKey(const std::string &context); - static std::string generateRouteKey(const std::string& vrf_id, - const swss::IpPrefix& ip_prefix); + static std::string generateRouteKey(const std::string &vrf_id, const swss::IpPrefix &ip_prefix); - static std::string generateRouterInterfaceKey( - const std::string& router_intf_id); + static std::string generateRouterInterfaceKey(const std::string &router_intf_id); - static std::string generateNeighborKey(const std::string& router_intf_id, - const swss::IpAddress& neighbor_id); + static std::string generateNeighborKey(const std::string &router_intf_id, const swss::IpAddress &neighbor_id); - static std::string generateNextHopKey(const std::string& next_hop_id); + static std::string generateNextHopKey(const std::string &next_hop_id); - static std::string generateMirrorSessionKey( - const std::string& mirror_session_id); + static std::string generateMirrorSessionKey(const std::string &mirror_session_id); - static std::string generateWcmpGroupKey(const std::string& wcmp_group_id); + static std::string generateWcmpGroupKey(const std::string &wcmp_group_id); - static std::string generateAclRuleKey( - const std::map& match_fields, - const std::string& priority); + static std::string generateAclRuleKey(const std::map &match_fields, + const std::string &priority); - static std::string generateL3AdmitKey( - const swss::MacAddress& mac_address_data, - const swss::MacAddress& mac_address_mask, const std::string& port_name, - const uint32_t& priority); + static std::string generateL3AdmitKey(const swss::MacAddress &mac_address_data, + const swss::MacAddress &mac_address_mask, const std::string &port_name, + const uint32_t &priority); - static std::string generateTunnelKey(const std::string& tunnel_id); + static std::string generateTunnelKey(const std::string &tunnel_id); - static std::string generateExtTableKey(const std::string& table_name, - const std::string& table_key); + static std::string generateExtTableKey(const std::string &table_name, const std::string &table_key); - // Generates key used by object managers and centralized mapper. - // Takes map of as input and returns a concatenated string - // of the form id1=value1:id2=value2... - static std::string generateKey( - const std::map& fv_map); + // Generates key used by object managers and centralized mapper. + // Takes map of as input and returns a concatenated string + // of the form id1=value1:id2=value2... + static std::string generateKey(const std::map &fv_map); }; // Inserts single quote for a variable name. // Returns a string. -template -std::string QuotedVar(T name) { - std::ostringstream ss; - ss << std::quoted(name, '\''); - return ss.str(); +template std::string QuotedVar(T name) +{ + std::ostringstream ss; + ss << std::quoted(name, '\''); + return ss.str(); } // Trim tailing and leading whitespace -std::string trim(const std::string& s); +std::string trim(const std::string &s); diff --git a/orchagent/p4orch/route_manager.cpp b/orchagent/p4orch/route_manager.cpp index 2b311dac5ad..c50b3bb4b91 100644 --- a/orchagent/p4orch/route_manager.cpp +++ b/orchagent/p4orch/route_manager.cpp @@ -23,1041 +23,1150 @@ using ::p4orch::kTableKeyDelimiter; extern sai_object_id_t gSwitchId; extern sai_object_id_t gVirtualRouterId; -extern sai_route_api_t* sai_route_api; +extern sai_route_api_t *sai_route_api; -extern CrmOrch* gCrmOrch; +extern CrmOrch *gCrmOrch; extern size_t gMaxBulkSize; -namespace { - -ReturnCode checkNextHopAndWcmpGroupAndRouteMetadataExistence( - bool expected_next_hop_existence, bool expected_wcmp_group_existence, - bool expected_route_metadata_existence, const P4RouteEntry& route_entry) { - if (route_entry.nexthop_id.empty() && expected_next_hop_existence) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Empty nexthop_id for route with " << route_entry.action - << " action"; - } - if (!route_entry.nexthop_id.empty() && !expected_next_hop_existence) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Non-empty nexthop_id for route with " << route_entry.action - << " action"; - } - if (route_entry.wcmp_group.empty() && expected_wcmp_group_existence) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Empty wcmp_group_id for route with " << route_entry.action - << " action"; - } - if (!route_entry.wcmp_group.empty() && !expected_wcmp_group_existence) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Non-empty wcmp_group_id for route with " << route_entry.action - << " action"; - } - if (route_entry.route_metadata.empty() && expected_route_metadata_existence) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Empty route_metadata for route with " << route_entry.action - << " action"; - } - if (!route_entry.route_metadata.empty() && - !expected_route_metadata_existence) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Non-empty route_metadata for route with " << route_entry.action - << " action"; - } - return ReturnCode(); +namespace +{ + +ReturnCode checkNextHopAndWcmpGroupAndRouteMetadataExistence(bool expected_next_hop_existence, + bool expected_wcmp_group_existence, + bool expected_route_metadata_existence, + const P4RouteEntry &route_entry) +{ + if (route_entry.nexthop_id.empty() && expected_next_hop_existence) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Empty nexthop_id for route with " << route_entry.action << " action"; + } + if (!route_entry.nexthop_id.empty() && !expected_next_hop_existence) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Non-empty nexthop_id for route with " << route_entry.action << " action"; + } + if (route_entry.wcmp_group.empty() && expected_wcmp_group_existence) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Empty wcmp_group_id for route with " << route_entry.action << " action"; + } + if (!route_entry.wcmp_group.empty() && !expected_wcmp_group_existence) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Non-empty wcmp_group_id for route with " << route_entry.action << " action"; + } + if (route_entry.route_metadata.empty() && expected_route_metadata_existence) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Empty route_metadata for route with " << route_entry.action << " action"; + } + if (!route_entry.route_metadata.empty() && !expected_route_metadata_existence) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Non-empty route_metadata for route with " << route_entry.action << " action"; + } + return ReturnCode(); } // Returns the nexthop OID of the given entry. // Raise critical state if OID cannot be found. -sai_object_id_t getNexthopOid(const P4RouteEntry& route_entry, - const P4OidMapper& mapper) { - sai_object_id_t oid = SAI_NULL_OBJECT_ID; - if (route_entry.action == p4orch::kSetNexthopId || - route_entry.action == p4orch::kSetNexthopIdAndMetadata) { - auto nexthop_key = KeyGenerator::generateNextHopKey(route_entry.nexthop_id); - if (!mapper.getOID(SAI_OBJECT_TYPE_NEXT_HOP, nexthop_key, &oid)) { - std::stringstream msg; - msg << "Nexthop " << QuotedVar(route_entry.nexthop_id) - << " does not exist"; - SWSS_LOG_ERROR("%s", msg.str().c_str()); - SWSS_RAISE_CRITICAL_STATE(msg.str()); - return oid; - } - } else if (route_entry.action == p4orch::kSetWcmpGroupId || - route_entry.action == p4orch::kSetWcmpGroupIdAndMetadata) { - auto wcmp_group_key = - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group); - if (!mapper.getOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key, &oid)) { - std::stringstream msg; - msg << "WCMP group " << QuotedVar(route_entry.nexthop_id) - << " does not exist"; - SWSS_LOG_ERROR("%s", msg.str().c_str()); - SWSS_RAISE_CRITICAL_STATE(msg.str()); - return oid; - } - } - return oid; +sai_object_id_t getNexthopOid(const P4RouteEntry &route_entry, const P4OidMapper &mapper) +{ + sai_object_id_t oid = SAI_NULL_OBJECT_ID; + if (route_entry.action == p4orch::kSetNexthopId || route_entry.action == p4orch::kSetNexthopIdAndMetadata) + { + auto nexthop_key = KeyGenerator::generateNextHopKey(route_entry.nexthop_id); + if (!mapper.getOID(SAI_OBJECT_TYPE_NEXT_HOP, nexthop_key, &oid)) + { + std::stringstream msg; + msg << "Nexthop " << QuotedVar(route_entry.nexthop_id) << " does not exist"; + SWSS_LOG_ERROR("%s", msg.str().c_str()); + SWSS_RAISE_CRITICAL_STATE(msg.str()); + return oid; + } + } + else if (route_entry.action == p4orch::kSetWcmpGroupId || route_entry.action == p4orch::kSetWcmpGroupIdAndMetadata) + { + auto wcmp_group_key = KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group); + if (!mapper.getOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key, &oid)) + { + std::stringstream msg; + msg << "WCMP group " << QuotedVar(route_entry.nexthop_id) << " does not exist"; + SWSS_LOG_ERROR("%s", msg.str().c_str()); + SWSS_RAISE_CRITICAL_STATE(msg.str()); + return oid; + } + } + return oid; } // Returns the SAI action of the given entry. -sai_packet_action_t getSaiAction(const P4RouteEntry& route_entry) { - if (route_entry.action == p4orch::kDrop || - route_entry.action == p4orch::kSetMetadataAndDrop) { - return SAI_PACKET_ACTION_DROP; - } else if (route_entry.action == p4orch::kTrap) { - return SAI_PACKET_ACTION_TRAP; - } - return SAI_PACKET_ACTION_FORWARD; +sai_packet_action_t getSaiAction(const P4RouteEntry &route_entry) +{ + if (route_entry.action == p4orch::kDrop || route_entry.action == p4orch::kSetMetadataAndDrop) + { + return SAI_PACKET_ACTION_DROP; + } + else if (route_entry.action == p4orch::kTrap) + { + return SAI_PACKET_ACTION_TRAP; + } + return SAI_PACKET_ACTION_FORWARD; } // Returns the metadata of the given entry. -uint32_t getMetadata(const P4RouteEntry& route_entry) { - if (route_entry.route_metadata.empty()) { - return 0; - } - return swss::to_uint(route_entry.route_metadata); +uint32_t getMetadata(const P4RouteEntry &route_entry) +{ + if (route_entry.route_metadata.empty()) + { + return 0; + } + return swss::to_uint(route_entry.route_metadata); } // Returns a list of SAI actions for route update. -std::vector getSaiActions(const std::string action) { - static const auto* const kRouteActionToSaiActions = new std::unordered_map< - std::string, std::vector>({ - {p4orch::kSetNexthopId, - std::vector{SAI_ROUTE_ENTRY_ATTR_META_DATA, - SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, - SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION}}, - {p4orch::kSetWcmpGroupId, - std::vector{SAI_ROUTE_ENTRY_ATTR_META_DATA, - SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, - SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION}}, - {p4orch::kSetNexthopIdAndMetadata, - std::vector{SAI_ROUTE_ENTRY_ATTR_META_DATA, - SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, - SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION}}, - {p4orch::kSetWcmpGroupIdAndMetadata, - std::vector{SAI_ROUTE_ENTRY_ATTR_META_DATA, - SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, - SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION}}, - {p4orch::kDrop, - std::vector{SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION, - SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, - SAI_ROUTE_ENTRY_ATTR_META_DATA}}, - {p4orch::kTrap, - std::vector{SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION, - SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, - SAI_ROUTE_ENTRY_ATTR_META_DATA}}, - {p4orch::kSetMetadataAndDrop, - std::vector{SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION, - SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, - SAI_ROUTE_ENTRY_ATTR_META_DATA}}, - }); - - if (kRouteActionToSaiActions->count(action) == 0) { - return std::vector{}; - } - return kRouteActionToSaiActions->at(action); +std::vector getSaiActions(const std::string action) +{ + static const auto *const kRouteActionToSaiActions = + new std::unordered_map>({ + {p4orch::kSetNexthopId, + std::vector{SAI_ROUTE_ENTRY_ATTR_META_DATA, SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, + SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION}}, + {p4orch::kSetWcmpGroupId, + std::vector{SAI_ROUTE_ENTRY_ATTR_META_DATA, SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, + SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION}}, + {p4orch::kSetNexthopIdAndMetadata, + std::vector{SAI_ROUTE_ENTRY_ATTR_META_DATA, SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, + SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION}}, + {p4orch::kSetWcmpGroupIdAndMetadata, + std::vector{SAI_ROUTE_ENTRY_ATTR_META_DATA, SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, + SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION}}, + {p4orch::kDrop, + std::vector{SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION, SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, + SAI_ROUTE_ENTRY_ATTR_META_DATA}}, + {p4orch::kTrap, + std::vector{SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION, SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, + SAI_ROUTE_ENTRY_ATTR_META_DATA}}, + {p4orch::kSetMetadataAndDrop, + std::vector{SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION, SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID, + SAI_ROUTE_ENTRY_ATTR_META_DATA}}, + }); + + if (kRouteActionToSaiActions->count(action) == 0) + { + return std::vector{}; + } + return kRouteActionToSaiActions->at(action); } -} // namespace +} // namespace -RouteUpdater::RouteUpdater(const P4RouteEntry& old_route, - const P4RouteEntry& new_route, P4OidMapper* mapper) - : m_oldRoute(old_route), - m_newRoute(new_route), - m_p4OidMapper(mapper), - m_actions(getSaiActions(new_route.action)) { - updateIdx(); +RouteUpdater::RouteUpdater(const P4RouteEntry &old_route, const P4RouteEntry &new_route, P4OidMapper *mapper) + : m_oldRoute(old_route), m_newRoute(new_route), m_p4OidMapper(mapper), m_actions(getSaiActions(new_route.action)) +{ + updateIdx(); } -P4RouteEntry RouteUpdater::getOldEntry() const { return m_oldRoute; } +P4RouteEntry RouteUpdater::getOldEntry() const +{ + return m_oldRoute; +} -P4RouteEntry RouteUpdater::getNewEntry() const { return m_newRoute; } +P4RouteEntry RouteUpdater::getNewEntry() const +{ + return m_newRoute; +} -sai_route_entry_t RouteUpdater::getSaiEntry() const { - return m_newRoute.sai_route_entry; +sai_route_entry_t RouteUpdater::getSaiEntry() const +{ + return m_newRoute.sai_route_entry; } -sai_attribute_t RouteUpdater::getSaiAttr() const { - sai_attribute_t route_attr = {}; - if (m_idx < 0 || m_idx >= static_cast(m_actions.size())) { - return route_attr; - } - route_attr.id = m_actions[m_idx]; - switch (m_actions[m_idx]) { +sai_attribute_t RouteUpdater::getSaiAttr() const +{ + sai_attribute_t route_attr = {}; + if (m_idx < 0 || m_idx >= static_cast(m_actions.size())) + { + return route_attr; + } + route_attr.id = m_actions[m_idx]; + switch (m_actions[m_idx]) + { case SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID: - route_attr.value.oid = (m_revert) - ? getNexthopOid(m_oldRoute, *m_p4OidMapper) - : getNexthopOid(m_newRoute, *m_p4OidMapper); - break; + route_attr.value.oid = + (m_revert) ? getNexthopOid(m_oldRoute, *m_p4OidMapper) : getNexthopOid(m_newRoute, *m_p4OidMapper); + break; case SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION: - route_attr.value.s32 = - (m_revert) ? getSaiAction(m_oldRoute) : getSaiAction(m_newRoute); - break; + route_attr.value.s32 = (m_revert) ? getSaiAction(m_oldRoute) : getSaiAction(m_newRoute); + break; default: - route_attr.value.u32 = - (m_revert) ? getMetadata(m_oldRoute) : getMetadata(m_newRoute); - } - return route_attr; + route_attr.value.u32 = (m_revert) ? getMetadata(m_oldRoute) : getMetadata(m_newRoute); + } + return route_attr; } -bool RouteUpdater::updateResult(sai_status_t sai_status) { - if (sai_status != SAI_STATUS_SUCCESS) { - if (m_revert) { - std::stringstream msg; - msg << "Failed to revert SAI attribute for route entry " - << QuotedVar(m_newRoute.route_entry_key); - SWSS_LOG_ERROR("%s SAI_STATUS: %s", msg.str().c_str(), - sai_serialize_status(sai_status).c_str()); - SWSS_RAISE_CRITICAL_STATE(msg.str()); - } else { - m_status = ReturnCode(sai_status) - << "Failed to update route entry " - << QuotedVar(m_newRoute.route_entry_key); - m_revert = true; - } - } - return updateIdx(); +bool RouteUpdater::updateResult(sai_status_t sai_status) +{ + if (sai_status != SAI_STATUS_SUCCESS) + { + if (m_revert) + { + std::stringstream msg; + msg << "Failed to revert SAI attribute for route entry " << QuotedVar(m_newRoute.route_entry_key); + SWSS_LOG_ERROR("%s SAI_STATUS: %s", msg.str().c_str(), sai_serialize_status(sai_status).c_str()); + SWSS_RAISE_CRITICAL_STATE(msg.str()); + } + else + { + m_status = ReturnCode(sai_status) + << "Failed to update route entry " << QuotedVar(m_newRoute.route_entry_key); + m_revert = true; + } + } + return updateIdx(); } -ReturnCode RouteUpdater::getStatus() const { return m_status; } +ReturnCode RouteUpdater::getStatus() const +{ + return m_status; +} -bool RouteUpdater::updateIdx() { - if (m_revert) { - for (--m_idx; m_idx >= 0; --m_idx) { - if (checkAction()) { - return false; - } +bool RouteUpdater::updateIdx() +{ + if (m_revert) + { + for (--m_idx; m_idx >= 0; --m_idx) + { + if (checkAction()) + { + return false; + } + } + return true; } - return true; - } - for (++m_idx; m_idx < static_cast(m_actions.size()); ++m_idx) { - if (checkAction()) { - return false; + for (++m_idx; m_idx < static_cast(m_actions.size()); ++m_idx) + { + if (checkAction()) + { + return false; + } } - } - return true; + return true; } -bool RouteUpdater::checkAction() const { - if (m_idx < 0 || m_idx >= static_cast(m_actions.size())) { - return false; - } - switch (m_actions[m_idx]) { - case SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID: - if (getNexthopOid(m_oldRoute, *m_p4OidMapper) == - getNexthopOid(m_newRoute, *m_p4OidMapper)) { +bool RouteUpdater::checkAction() const +{ + if (m_idx < 0 || m_idx >= static_cast(m_actions.size())) + { return false; - } - return true; + } + switch (m_actions[m_idx]) + { + case SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID: + if (getNexthopOid(m_oldRoute, *m_p4OidMapper) == getNexthopOid(m_newRoute, *m_p4OidMapper)) + { + return false; + } + return true; case SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION: - if (getSaiAction(m_oldRoute) == getSaiAction(m_newRoute)) { - return false; - } - return true; + if (getSaiAction(m_oldRoute) == getSaiAction(m_newRoute)) + { + return false; + } + return true; default: - if (getMetadata(m_oldRoute) == getMetadata(m_newRoute)) { - return false; - } - return true; - } - return false; + if (getMetadata(m_oldRoute) == getMetadata(m_newRoute)) + { + return false; + } + return true; + } + return false; } -RouteManager::RouteManager(P4OidMapper* p4oidMapper, VRFOrch* vrfOrch, - ResponsePublisherInterface* publisher) - : m_vrfOrch(vrfOrch), m_routerBulker(sai_route_api, gMaxBulkSize) { - SWSS_LOG_ENTER(); +RouteManager::RouteManager(P4OidMapper *p4oidMapper, VRFOrch *vrfOrch, ResponsePublisherInterface *publisher) + : m_vrfOrch(vrfOrch), m_routerBulker(sai_route_api, gMaxBulkSize) +{ + SWSS_LOG_ENTER(); - assert(p4oidMapper != nullptr); - m_p4OidMapper = p4oidMapper; - assert(publisher != nullptr); - m_publisher = publisher; + assert(p4oidMapper != nullptr); + m_p4OidMapper = p4oidMapper; + assert(publisher != nullptr); + m_publisher = publisher; } -sai_route_entry_t RouteManager::getSaiEntry(const P4RouteEntry& route_entry) { - sai_route_entry_t sai_entry; - sai_entry.vr_id = m_vrfOrch->getVRFid(route_entry.vrf_id); - sai_entry.switch_id = gSwitchId; - copy(sai_entry.destination, route_entry.route_prefix); - return sai_entry; +sai_route_entry_t RouteManager::getSaiEntry(const P4RouteEntry &route_entry) +{ + sai_route_entry_t sai_entry; + sai_entry.vr_id = m_vrfOrch->getVRFid(route_entry.vrf_id); + sai_entry.switch_id = gSwitchId; + copy(sai_entry.destination, route_entry.route_prefix); + return sai_entry; } -bool RouteManager::mergeRouteEntry(const P4RouteEntry& dest, - const P4RouteEntry& src, P4RouteEntry* ret) { - SWSS_LOG_ENTER(); +bool RouteManager::mergeRouteEntry(const P4RouteEntry &dest, const P4RouteEntry &src, P4RouteEntry *ret) +{ + SWSS_LOG_ENTER(); - *ret = src; - ret->sai_route_entry = dest.sai_route_entry; - if (ret->action != dest.action || ret->nexthop_id != dest.nexthop_id || - ret->wcmp_group != dest.wcmp_group || - ret->route_metadata != dest.route_metadata) { - return true; - } - return false; + *ret = src; + ret->sai_route_entry = dest.sai_route_entry; + if (ret->action != dest.action || ret->nexthop_id != dest.nexthop_id || ret->wcmp_group != dest.wcmp_group || + ret->route_metadata != dest.route_metadata) + { + return true; + } + return false; } -ReturnCodeOr RouteManager::deserializeRouteEntry( - const std::string& key, - const std::vector& attributes, - const std::string& table_name) { - SWSS_LOG_ENTER(); - - P4RouteEntry route_entry = {}; - std::string route_prefix; - try { - nlohmann::json j = nlohmann::json::parse(key); - route_entry.vrf_id = j[prependMatchField(p4orch::kVrfId)]; - if (table_name == APP_P4RT_IPV4_TABLE_NAME) { - if (j.find(prependMatchField(p4orch::kIpv4Dst)) != j.end()) { - route_prefix = j[prependMatchField(p4orch::kIpv4Dst)]; - } else { - route_prefix = "0.0.0.0/0"; - } - } else { - if (j.find(prependMatchField(p4orch::kIpv6Dst)) != j.end()) { - route_prefix = j[prependMatchField(p4orch::kIpv6Dst)]; - } else { - route_prefix = "::/0"; - } - } - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to deserialize route key"; - } - try { - route_entry.route_prefix = swss::IpPrefix(route_prefix); - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid IP prefix " << QuotedVar(route_prefix); - } - - route_entry.route_entry_key = KeyGenerator::generateRouteKey( - route_entry.vrf_id, route_entry.route_prefix); - - for (const auto& it : attributes) { - const auto& field = fvField(it); - const auto& value = fvValue(it); - if (field == p4orch::kAction) { - route_entry.action = value; - } else if (field == prependParamField(p4orch::kNexthopId)) { - route_entry.nexthop_id = value; - } else if (field == prependParamField(p4orch::kWcmpGroupId)) { - route_entry.wcmp_group = value; - } else if (field == prependParamField(p4orch::kRouteMetadata)) { - route_entry.route_metadata = value; - } else if (field != p4orch::kControllerMetadata) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unexpected field " << QuotedVar(field) << " in " << table_name; - } - } - - return route_entry; -} +ReturnCodeOr RouteManager::deserializeRouteEntry(const std::string &key, + const std::vector &attributes, + const std::string &table_name) +{ + SWSS_LOG_ENTER(); + + P4RouteEntry route_entry = {}; + std::string route_prefix; + try + { + nlohmann::json j = nlohmann::json::parse(key); + route_entry.vrf_id = j[prependMatchField(p4orch::kVrfId)]; + if (table_name == APP_P4RT_IPV4_TABLE_NAME) + { + if (j.find(prependMatchField(p4orch::kIpv4Dst)) != j.end()) + { + route_prefix = j[prependMatchField(p4orch::kIpv4Dst)]; + } + else + { + route_prefix = "0.0.0.0/0"; + } + } + else + { + if (j.find(prependMatchField(p4orch::kIpv6Dst)) != j.end()) + { + route_prefix = j[prependMatchField(p4orch::kIpv6Dst)]; + } + else + { + route_prefix = "::/0"; + } + } + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Failed to deserialize route key"; + } + try + { + route_entry.route_prefix = swss::IpPrefix(route_prefix); + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Invalid IP prefix " << QuotedVar(route_prefix); + } -P4RouteEntry* RouteManager::getRouteEntry(const std::string& route_entry_key) { - SWSS_LOG_ENTER(); + route_entry.route_entry_key = KeyGenerator::generateRouteKey(route_entry.vrf_id, route_entry.route_prefix); - if (m_routeTable.find(route_entry_key) == m_routeTable.end()) return nullptr; + for (const auto &it : attributes) + { + const auto &field = fvField(it); + const auto &value = fvValue(it); + if (field == p4orch::kAction) + { + route_entry.action = value; + } + else if (field == prependParamField(p4orch::kNexthopId)) + { + route_entry.nexthop_id = value; + } + else if (field == prependParamField(p4orch::kWcmpGroupId)) + { + route_entry.wcmp_group = value; + } + else if (field == prependParamField(p4orch::kRouteMetadata)) + { + route_entry.route_metadata = value; + } + else if (field != p4orch::kControllerMetadata) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unexpected field " << QuotedVar(field) << " in " << table_name; + } + } - return &m_routeTable[route_entry_key]; + return route_entry; } -ReturnCode RouteManager::validateRouteEntry(const P4RouteEntry& route_entry, - const std::string& operation) { - SWSS_LOG_ENTER(); - - if (!route_entry.nexthop_id.empty()) { - auto nexthop_key = KeyGenerator::generateNextHopKey(route_entry.nexthop_id); - if (!m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_NEXT_HOP, nexthop_key)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Nexthop ID " << QuotedVar(route_entry.nexthop_id) - << " does not exist"; - } - } - if (!route_entry.wcmp_group.empty()) { - auto wcmp_group_key = - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group); - if (!m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - wcmp_group_key)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "WCMP group " << QuotedVar(route_entry.wcmp_group) - << " does not exist"; - } - } - if (!route_entry.vrf_id.empty() && - !m_vrfOrch->isVRFexists(route_entry.vrf_id)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "No VRF found with name " << QuotedVar(route_entry.vrf_id); - } - - if (operation == SET_COMMAND) { - return validateSetRouteEntry(route_entry); - } else if (operation == DEL_COMMAND) { - return validateDelRouteEntry(route_entry); - } - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown operation type " << QuotedVar(operation); -} +P4RouteEntry *RouteManager::getRouteEntry(const std::string &route_entry_key) +{ + SWSS_LOG_ENTER(); + + if (m_routeTable.find(route_entry_key) == m_routeTable.end()) + return nullptr; -ReturnCode RouteManager::validateSetRouteEntry( - const P4RouteEntry& route_entry) { - auto* route_entry_ptr = getRouteEntry(route_entry.route_entry_key); - bool exist_in_mapper = m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, - route_entry.route_entry_key); - if (route_entry_ptr == nullptr && exist_in_mapper) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Route entry does not exist in manager but exists in the " - "centralized map"; - } - if (route_entry_ptr != nullptr && !exist_in_mapper) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Route entry exists in manager but does not exist in the " - "centralized map"; - } - std::string action = route_entry.action; - // If action is empty, this could be an update. - if (action.empty()) { - if (route_entry_ptr == nullptr) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Empty action for route"; - } - action = route_entry_ptr->action; - } - if (action == p4orch::kSetNexthopId) { - RETURN_IF_ERROR(checkNextHopAndWcmpGroupAndRouteMetadataExistence( - /*expected_next_hop_existence=*/true, - /*expected_wcmp_group_existence=*/false, - /*expected_route_metadata_existence=*/false, route_entry)); - } else if (action == p4orch::kSetWcmpGroupId) { - RETURN_IF_ERROR(checkNextHopAndWcmpGroupAndRouteMetadataExistence( - /*expected_next_hop_existence=*/false, - /*expected_wcmp_group_existence=*/true, - /*expected_route_metadata_existence=*/false, route_entry)); - } else if (action == p4orch::kSetNexthopIdAndMetadata) { - RETURN_IF_ERROR(checkNextHopAndWcmpGroupAndRouteMetadataExistence( - /*expected_next_hop_existence=*/true, - /*expected_wcmp_group_existence=*/false, - /*expected_route_metadata_existence=*/true, route_entry)); - } else if (action == p4orch::kSetWcmpGroupIdAndMetadata) { - RETURN_IF_ERROR(checkNextHopAndWcmpGroupAndRouteMetadataExistence( - /*expected_next_hop_existence=*/false, - /*expected_wcmp_group_existence=*/true, - /*expected_route_metadata_existence=*/true, route_entry)); - } else if (action == p4orch::kDrop || action == p4orch::kTrap) { - RETURN_IF_ERROR(checkNextHopAndWcmpGroupAndRouteMetadataExistence( - /*expected_next_hop_existence=*/false, - /*expected_wcmp_group_existence=*/false, - /*expected_route_metadata_existence=*/false, route_entry)); - } else if (action == p4orch::kSetMetadataAndDrop) { - RETURN_IF_ERROR(checkNextHopAndWcmpGroupAndRouteMetadataExistence( - /*expected_next_hop_existence=*/false, - /*expected_wcmp_group_existence=*/false, - /*expected_route_metadata_existence=*/true, route_entry)); - } else { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid action " << QuotedVar(action); - } - - if (!route_entry.route_metadata.empty()) { - try { - swss::to_uint(route_entry.route_metadata); - } catch (std::exception& e) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Action attribute " << QuotedVar(p4orch::kRouteMetadata) - << " is invalid for " << QuotedVar(route_entry.route_entry_key) - << ": Expect integer but got " - << QuotedVar(route_entry.route_metadata); - } - } - return ReturnCode(); + return &m_routeTable[route_entry_key]; } -ReturnCode RouteManager::validateDelRouteEntry( - const P4RouteEntry& route_entry) { - if (getRouteEntry(route_entry.route_entry_key) == nullptr) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Route entry does not exist"; - } - if (!m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, - route_entry.route_entry_key)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Route entry does not exist in the centralized map"); - } - if (!route_entry.action.empty()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Non-empty action for Del route"; - } - if (!route_entry.nexthop_id.empty()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Non-empty nexthop_id for Del route"; - } - if (!route_entry.wcmp_group.empty()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Non-empty wcmp_group for Del route"; - } - if (!route_entry.route_metadata.empty()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Non-empty route_metadata for Del route"; - } - return ReturnCode(); +ReturnCode RouteManager::validateRouteEntry(const P4RouteEntry &route_entry, const std::string &operation) +{ + SWSS_LOG_ENTER(); + + if (!route_entry.nexthop_id.empty()) + { + auto nexthop_key = KeyGenerator::generateNextHopKey(route_entry.nexthop_id); + if (!m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_NEXT_HOP, nexthop_key)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Nexthop ID " << QuotedVar(route_entry.nexthop_id) << " does not exist"; + } + } + if (!route_entry.wcmp_group.empty()) + { + auto wcmp_group_key = KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group); + if (!m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "WCMP group " << QuotedVar(route_entry.wcmp_group) << " does not exist"; + } + } + if (!route_entry.vrf_id.empty() && !m_vrfOrch->isVRFexists(route_entry.vrf_id)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) << "No VRF found with name " << QuotedVar(route_entry.vrf_id); + } + + if (operation == SET_COMMAND) + { + return validateSetRouteEntry(route_entry); + } + else if (operation == DEL_COMMAND) + { + return validateDelRouteEntry(route_entry); + } + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Unknown operation type " << QuotedVar(operation); } -std::vector RouteManager::createRouteEntries( - const std::vector& route_entries) { - SWSS_LOG_ENTER(); - - std::vector sai_route_entries(route_entries.size()); - // Currently, there are maximum of 2 SAI attributes for route creation. - // For drop and trap routes, there is one SAI attribute: - // SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION. - // For forwarding routes, the default SAI_ROUTE_ATTR_PACKET_ACTION is already - // SAI_PACKET_ACTION_FORWARD, so we don't need SAI_ROUTE_ATTR_PACKET_ACTION. - // But we need SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID and optionally - // SAI_ROUTE_ENTRY_ATTR_META_DATA. - std::vector sai_attrs(2 * route_entries.size()); - std::vector object_statuses(route_entries.size()); - std::vector statuses(route_entries.size()); - - for (size_t i = 0; i < route_entries.size(); ++i) { - const auto& route_entry = route_entries[i]; - sai_route_entries[i] = getSaiEntry(route_entry); - uint32_t num_attrs = 1; - if (route_entry.action == p4orch::kDrop) { - sai_attrs[2 * i].id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - sai_attrs[2 * i].value.s32 = SAI_PACKET_ACTION_DROP; - } else if (route_entry.action == p4orch::kTrap) { - sai_attrs[2 * i].id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - sai_attrs[2 * i].value.s32 = SAI_PACKET_ACTION_TRAP; - } else if (route_entry.action == p4orch::kSetMetadataAndDrop) { - sai_attrs[2 * i].id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - sai_attrs[2 * i].value.s32 = SAI_PACKET_ACTION_DROP; - sai_attrs[2 * i + 1].id = SAI_ROUTE_ENTRY_ATTR_META_DATA; - sai_attrs[2 * i + 1].value.u32 = - swss::to_uint(route_entry.route_metadata); - num_attrs++; - } else { - // Default SAI_ROUTE_ATTR_PACKET_ACTION is SAI_PACKET_ACTION_FORWARD. - sai_attrs[2 * i].id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - sai_attrs[2 * i].value.oid = getNexthopOid(route_entry, *m_p4OidMapper); - if (route_entry.action == p4orch::kSetNexthopIdAndMetadata || - route_entry.action == p4orch::kSetWcmpGroupIdAndMetadata) { - sai_attrs[2 * i + 1].id = SAI_ROUTE_ENTRY_ATTR_META_DATA; - sai_attrs[2 * i + 1].value.u32 = +ReturnCode RouteManager::validateSetRouteEntry(const P4RouteEntry &route_entry) +{ + auto *route_entry_ptr = getRouteEntry(route_entry.route_entry_key); + bool exist_in_mapper = m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, route_entry.route_entry_key); + if (route_entry_ptr == nullptr && exist_in_mapper) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) << "Route entry does not exist in manager but exists in the " + "centralized map"; + } + if (route_entry_ptr != nullptr && !exist_in_mapper) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) << "Route entry exists in manager but does not exist in the " + "centralized map"; + } + std::string action = route_entry.action; + // If action is empty, this could be an update. + if (action.empty()) + { + if (route_entry_ptr == nullptr) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Empty action for route"; + } + action = route_entry_ptr->action; + } + if (action == p4orch::kSetNexthopId) + { + RETURN_IF_ERROR(checkNextHopAndWcmpGroupAndRouteMetadataExistence( + /*expected_next_hop_existence=*/true, + /*expected_wcmp_group_existence=*/false, + /*expected_route_metadata_existence=*/false, route_entry)); + } + else if (action == p4orch::kSetWcmpGroupId) + { + RETURN_IF_ERROR(checkNextHopAndWcmpGroupAndRouteMetadataExistence( + /*expected_next_hop_existence=*/false, + /*expected_wcmp_group_existence=*/true, + /*expected_route_metadata_existence=*/false, route_entry)); + } + else if (action == p4orch::kSetNexthopIdAndMetadata) + { + RETURN_IF_ERROR(checkNextHopAndWcmpGroupAndRouteMetadataExistence( + /*expected_next_hop_existence=*/true, + /*expected_wcmp_group_existence=*/false, + /*expected_route_metadata_existence=*/true, route_entry)); + } + else if (action == p4orch::kSetWcmpGroupIdAndMetadata) + { + RETURN_IF_ERROR(checkNextHopAndWcmpGroupAndRouteMetadataExistence( + /*expected_next_hop_existence=*/false, + /*expected_wcmp_group_existence=*/true, + /*expected_route_metadata_existence=*/true, route_entry)); + } + else if (action == p4orch::kDrop || action == p4orch::kTrap) + { + RETURN_IF_ERROR(checkNextHopAndWcmpGroupAndRouteMetadataExistence( + /*expected_next_hop_existence=*/false, + /*expected_wcmp_group_existence=*/false, + /*expected_route_metadata_existence=*/false, route_entry)); + } + else if (action == p4orch::kSetMetadataAndDrop) + { + RETURN_IF_ERROR(checkNextHopAndWcmpGroupAndRouteMetadataExistence( + /*expected_next_hop_existence=*/false, + /*expected_wcmp_group_existence=*/false, + /*expected_route_metadata_existence=*/true, route_entry)); + } + else + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Invalid action " << QuotedVar(action); + } + + if (!route_entry.route_metadata.empty()) + { + try + { swss::to_uint(route_entry.route_metadata); - num_attrs++; - } - } - object_statuses[i] = - m_routerBulker.create_entry(&object_statuses[i], &sai_route_entries[i], - num_attrs, &sai_attrs[2 * i]); - } - - m_routerBulker.flush(); - - for (size_t i = 0; i < route_entries.size(); ++i) { - const auto& route_entry = route_entries[i]; - CHECK_ERROR_AND_LOG(object_statuses[i], - "Failed to create route entry " - << QuotedVar(route_entry.route_entry_key)); - if (object_statuses[i] == SAI_STATUS_SUCCESS) { - if (route_entry.action == p4orch::kSetNexthopId || - route_entry.action == p4orch::kSetNexthopIdAndMetadata) { - m_p4OidMapper->increaseRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id)); - } else if (route_entry.action == p4orch::kSetWcmpGroupId || - route_entry.action == p4orch::kSetWcmpGroupIdAndMetadata) { - m_p4OidMapper->increaseRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group)); - } - m_routeTable[route_entry.route_entry_key] = route_entry; - m_routeTable[route_entry.route_entry_key].sai_route_entry = - sai_route_entries[i]; - m_p4OidMapper->setDummyOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, - route_entry.route_entry_key); - if (route_entry.route_prefix.isV4()) { - gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV4_ROUTE); - } else { - gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV6_ROUTE); - } - m_vrfOrch->increaseVrfRefCount(route_entry.vrf_id); - statuses[i] = ReturnCode(); - } else { - statuses[i] = ReturnCode(object_statuses[i]) - << "Failed to create route entry " - << QuotedVar(route_entry.route_entry_key); - } - } - - return statuses; + } + catch (std::exception &e) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Action attribute " << QuotedVar(p4orch::kRouteMetadata) << " is invalid for " + << QuotedVar(route_entry.route_entry_key) << ": Expect integer but got " + << QuotedVar(route_entry.route_metadata); + } + } + return ReturnCode(); } -void RouteManager::updateRouteEntriesMeta(const P4RouteEntry& old_entry, - const P4RouteEntry& new_entry) { - if (getNexthopOid(old_entry, *m_p4OidMapper) != - getNexthopOid(new_entry, *m_p4OidMapper)) { - if (new_entry.action == p4orch::kSetNexthopId || - new_entry.action == p4orch::kSetNexthopIdAndMetadata) { - m_p4OidMapper->increaseRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(new_entry.nexthop_id)); - } else if (new_entry.action == p4orch::kSetWcmpGroupId || - new_entry.action == p4orch::kSetWcmpGroupIdAndMetadata) { - m_p4OidMapper->increaseRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(new_entry.wcmp_group)); - } - if (old_entry.action == p4orch::kSetNexthopId || - old_entry.action == p4orch::kSetNexthopIdAndMetadata) { - m_p4OidMapper->decreaseRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(old_entry.nexthop_id)); - } else if (old_entry.action == p4orch::kSetWcmpGroupId || - old_entry.action == p4orch::kSetWcmpGroupIdAndMetadata) { - m_p4OidMapper->decreaseRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(old_entry.wcmp_group)); - } - } - m_routeTable[new_entry.route_entry_key] = new_entry; +ReturnCode RouteManager::validateDelRouteEntry(const P4RouteEntry &route_entry) +{ + if (getRouteEntry(route_entry.route_entry_key) == nullptr) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) << "Route entry does not exist"; + } + if (!m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, route_entry.route_entry_key)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Route entry does not exist in the centralized map"); + } + if (!route_entry.action.empty()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Non-empty action for Del route"; + } + if (!route_entry.nexthop_id.empty()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Non-empty nexthop_id for Del route"; + } + if (!route_entry.wcmp_group.empty()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Non-empty wcmp_group for Del route"; + } + if (!route_entry.route_metadata.empty()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Non-empty route_metadata for Del route"; + } + return ReturnCode(); } -void RouteManager::updateRouteAttrs( - int size, const std::vector>& updaters, - std::vector& indice, std::vector& statuses) { - std::vector sai_route_entries(size); - std::vector sai_attrs(size); - std::vector object_statuses(size); - // We will perform route update in multiple SAI calls. - // If error is encountered, the previous SAI calls will be reverted. - // Raise critical state if the revert fails. - // We avoid changing multiple attributes of the same entry in a single bulk - // call. - constexpr int kMaxAttrUpdate = 20; - int i; - for (i = 0; i < kMaxAttrUpdate; ++i) { - for (int j = 0; j < size; ++j) { - sai_route_entries[j] = updaters[indice[j]]->getSaiEntry(); - sai_attrs[j] = updaters[indice[j]]->getSaiAttr(); - m_routerBulker.set_entry_attribute(&object_statuses[j], - &sai_route_entries[j], &sai_attrs[j]); +std::vector RouteManager::createRouteEntries(const std::vector &route_entries) +{ + SWSS_LOG_ENTER(); + + std::vector sai_route_entries(route_entries.size()); + // Currently, there are maximum of 2 SAI attributes for route creation. + // For drop and trap routes, there is one SAI attribute: + // SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION. + // For forwarding routes, the default SAI_ROUTE_ATTR_PACKET_ACTION is already + // SAI_PACKET_ACTION_FORWARD, so we don't need SAI_ROUTE_ATTR_PACKET_ACTION. + // But we need SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID and optionally + // SAI_ROUTE_ENTRY_ATTR_META_DATA. + std::vector sai_attrs(2 * route_entries.size()); + std::vector object_statuses(route_entries.size()); + std::vector statuses(route_entries.size()); + + for (size_t i = 0; i < route_entries.size(); ++i) + { + const auto &route_entry = route_entries[i]; + sai_route_entries[i] = getSaiEntry(route_entry); + uint32_t num_attrs = 1; + if (route_entry.action == p4orch::kDrop) + { + sai_attrs[2 * i].id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + sai_attrs[2 * i].value.s32 = SAI_PACKET_ACTION_DROP; + } + else if (route_entry.action == p4orch::kTrap) + { + sai_attrs[2 * i].id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + sai_attrs[2 * i].value.s32 = SAI_PACKET_ACTION_TRAP; + } + else if (route_entry.action == p4orch::kSetMetadataAndDrop) + { + sai_attrs[2 * i].id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + sai_attrs[2 * i].value.s32 = SAI_PACKET_ACTION_DROP; + sai_attrs[2 * i + 1].id = SAI_ROUTE_ENTRY_ATTR_META_DATA; + sai_attrs[2 * i + 1].value.u32 = swss::to_uint(route_entry.route_metadata); + num_attrs++; + } + else + { + // Default SAI_ROUTE_ATTR_PACKET_ACTION is SAI_PACKET_ACTION_FORWARD. + sai_attrs[2 * i].id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + sai_attrs[2 * i].value.oid = getNexthopOid(route_entry, *m_p4OidMapper); + if (route_entry.action == p4orch::kSetNexthopIdAndMetadata || + route_entry.action == p4orch::kSetWcmpGroupIdAndMetadata) + { + sai_attrs[2 * i + 1].id = SAI_ROUTE_ENTRY_ATTR_META_DATA; + sai_attrs[2 * i + 1].value.u32 = swss::to_uint(route_entry.route_metadata); + num_attrs++; + } + } + object_statuses[i] = + m_routerBulker.create_entry(&object_statuses[i], &sai_route_entries[i], num_attrs, &sai_attrs[2 * i]); } + m_routerBulker.flush(); - int new_size = 0; - for (int j = 0; j < size; j++) { - if (updaters[indice[j]]->updateResult(object_statuses[j])) { - statuses[indice[j]] = updaters[indice[j]]->getStatus(); - if (statuses[indice[j]].ok()) { - updateRouteEntriesMeta(updaters[indice[j]]->getOldEntry(), - updaters[indice[j]]->getNewEntry()); + + for (size_t i = 0; i < route_entries.size(); ++i) + { + const auto &route_entry = route_entries[i]; + CHECK_ERROR_AND_LOG(object_statuses[i], + "Failed to create route entry " << QuotedVar(route_entry.route_entry_key)); + if (object_statuses[i] == SAI_STATUS_SUCCESS) + { + if (route_entry.action == p4orch::kSetNexthopId || route_entry.action == p4orch::kSetNexthopIdAndMetadata) + { + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, + KeyGenerator::generateNextHopKey(route_entry.nexthop_id)); + } + else if (route_entry.action == p4orch::kSetWcmpGroupId || + route_entry.action == p4orch::kSetWcmpGroupIdAndMetadata) + { + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group)); + } + m_routeTable[route_entry.route_entry_key] = route_entry; + m_routeTable[route_entry.route_entry_key].sai_route_entry = sai_route_entries[i]; + m_p4OidMapper->setDummyOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, route_entry.route_entry_key); + if (route_entry.route_prefix.isV4()) + { + gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV4_ROUTE); + } + else + { + gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_IPV6_ROUTE); + } + m_vrfOrch->increaseVrfRefCount(route_entry.vrf_id); + statuses[i] = ReturnCode(); } - } else { - indice[new_size++] = indice[j]; - } - } - if (new_size == 0) { - break; - } - size = new_size; - } - // Just a safety check to prevent infinite loop. Should not happen. - if (i == kMaxAttrUpdate) { - SWSS_RAISE_CRITICAL_STATE("Route update operation did not terminate."); - } - return; -} + else + { + statuses[i] = ReturnCode(object_statuses[i]) + << "Failed to create route entry " << QuotedVar(route_entry.route_entry_key); + } + } -std::vector RouteManager::updateRouteEntries( - const std::vector& route_entries) { - SWSS_LOG_ENTER(); - - std::vector> updaters(route_entries.size()); - std::vector indice( - route_entries.size()); // index to the route_entries - std::vector statuses(route_entries.size()); - - int size = 0; - for (size_t i = 0; i < route_entries.size(); ++i) { - const auto& route_entry = route_entries[i]; - auto* route_entry_ptr = getRouteEntry(route_entry.route_entry_key); - P4RouteEntry new_entry; - if (!mergeRouteEntry(*route_entry_ptr, route_entry, &new_entry)) { - statuses[i] = ReturnCode(); - continue; - } - updaters[i] = std::unique_ptr( - new RouteUpdater(*route_entry_ptr, new_entry, m_p4OidMapper)); - indice[size++] = i; - } - if (size == 0) { return statuses; - } +} - updateRouteAttrs(size, updaters, indice, statuses); - return statuses; +void RouteManager::updateRouteEntriesMeta(const P4RouteEntry &old_entry, const P4RouteEntry &new_entry) +{ + if (getNexthopOid(old_entry, *m_p4OidMapper) != getNexthopOid(new_entry, *m_p4OidMapper)) + { + if (new_entry.action == p4orch::kSetNexthopId || new_entry.action == p4orch::kSetNexthopIdAndMetadata) + { + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, + KeyGenerator::generateNextHopKey(new_entry.nexthop_id)); + } + else if (new_entry.action == p4orch::kSetWcmpGroupId || new_entry.action == p4orch::kSetWcmpGroupIdAndMetadata) + { + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(new_entry.wcmp_group)); + } + if (old_entry.action == p4orch::kSetNexthopId || old_entry.action == p4orch::kSetNexthopIdAndMetadata) + { + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, + KeyGenerator::generateNextHopKey(old_entry.nexthop_id)); + } + else if (old_entry.action == p4orch::kSetWcmpGroupId || old_entry.action == p4orch::kSetWcmpGroupIdAndMetadata) + { + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(old_entry.wcmp_group)); + } + } + m_routeTable[new_entry.route_entry_key] = new_entry; } -std::vector RouteManager::deleteRouteEntries( - const std::vector& route_entries) { - SWSS_LOG_ENTER(); - - std::vector sai_route_entries(route_entries.size()); - std::vector object_statuses(route_entries.size()); - std::vector statuses(route_entries.size()); - - for (size_t i = 0; i < route_entries.size(); ++i) { - const auto& route_entry = route_entries[i]; - auto* route_entry_ptr = getRouteEntry(route_entry.route_entry_key); - sai_route_entries[i] = route_entry_ptr->sai_route_entry; - object_statuses[i] = - m_routerBulker.remove_entry(&object_statuses[i], &sai_route_entries[i]); - } - - m_routerBulker.flush(); - - for (size_t i = 0; i < route_entries.size(); ++i) { - const auto& route_entry = route_entries[i]; - auto* route_entry_ptr = getRouteEntry(route_entry.route_entry_key); - CHECK_ERROR_AND_LOG(object_statuses[i], - "Failed to delete route entry " - << QuotedVar(route_entry.route_entry_key)); - if (object_statuses[i] == SAI_STATUS_SUCCESS) { - if (route_entry_ptr->action == p4orch::kSetNexthopId || - route_entry_ptr->action == p4orch::kSetNexthopIdAndMetadata) { - m_p4OidMapper->decreaseRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry_ptr->nexthop_id)); - } else if (route_entry_ptr->action == p4orch::kSetWcmpGroupId || - route_entry_ptr->action == - p4orch::kSetWcmpGroupIdAndMetadata) { - m_p4OidMapper->decreaseRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry_ptr->wcmp_group)); - } - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, - route_entry.route_entry_key); - if (route_entry.route_prefix.isV4()) { - gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV4_ROUTE); - } else { - gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV6_ROUTE); - } - m_vrfOrch->decreaseVrfRefCount(route_entry.vrf_id); - m_routeTable.erase(route_entry.route_entry_key); - statuses[i] = ReturnCode(); - } else { - statuses[i] = ReturnCode(object_statuses[i]) - << "Failed to delete route entry " - << QuotedVar(route_entry.route_entry_key); - } - } - - return statuses; +void RouteManager::updateRouteAttrs(int size, const std::vector> &updaters, + std::vector &indice, std::vector &statuses) +{ + std::vector sai_route_entries(size); + std::vector sai_attrs(size); + std::vector object_statuses(size); + // We will perform route update in multiple SAI calls. + // If error is encountered, the previous SAI calls will be reverted. + // Raise critical state if the revert fails. + // We avoid changing multiple attributes of the same entry in a single bulk + // call. + constexpr int kMaxAttrUpdate = 20; + int i; + for (i = 0; i < kMaxAttrUpdate; ++i) + { + for (int j = 0; j < size; ++j) + { + sai_route_entries[j] = updaters[indice[j]]->getSaiEntry(); + sai_attrs[j] = updaters[indice[j]]->getSaiAttr(); + m_routerBulker.set_entry_attribute(&object_statuses[j], &sai_route_entries[j], &sai_attrs[j]); + } + m_routerBulker.flush(); + int new_size = 0; + for (int j = 0; j < size; j++) + { + if (updaters[indice[j]]->updateResult(object_statuses[j])) + { + statuses[indice[j]] = updaters[indice[j]]->getStatus(); + if (statuses[indice[j]].ok()) + { + updateRouteEntriesMeta(updaters[indice[j]]->getOldEntry(), updaters[indice[j]]->getNewEntry()); + } + } + else + { + indice[new_size++] = indice[j]; + } + } + if (new_size == 0) + { + break; + } + size = new_size; + } + // Just a safety check to prevent infinite loop. Should not happen. + if (i == kMaxAttrUpdate) + { + SWSS_RAISE_CRITICAL_STATE("Route update operation did not terminate."); + } + return; } -ReturnCode RouteManager::getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) { - return StatusCode::SWSS_RC_UNIMPLEMENTED; +std::vector RouteManager::updateRouteEntries(const std::vector &route_entries) +{ + SWSS_LOG_ENTER(); + + std::vector> updaters(route_entries.size()); + std::vector indice(route_entries.size()); // index to the route_entries + std::vector statuses(route_entries.size()); + + int size = 0; + for (size_t i = 0; i < route_entries.size(); ++i) + { + const auto &route_entry = route_entries[i]; + auto *route_entry_ptr = getRouteEntry(route_entry.route_entry_key); + P4RouteEntry new_entry; + if (!mergeRouteEntry(*route_entry_ptr, route_entry, &new_entry)) + { + statuses[i] = ReturnCode(); + continue; + } + updaters[i] = std::unique_ptr(new RouteUpdater(*route_entry_ptr, new_entry, m_p4OidMapper)); + indice[size++] = i; + } + if (size == 0) + { + return statuses; + } + + updateRouteAttrs(size, updaters, indice, statuses); + return statuses; } -void RouteManager::enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) { - m_entries.push_back(entry); +std::vector RouteManager::deleteRouteEntries(const std::vector &route_entries) +{ + SWSS_LOG_ENTER(); + + std::vector sai_route_entries(route_entries.size()); + std::vector object_statuses(route_entries.size()); + std::vector statuses(route_entries.size()); + + for (size_t i = 0; i < route_entries.size(); ++i) + { + const auto &route_entry = route_entries[i]; + auto *route_entry_ptr = getRouteEntry(route_entry.route_entry_key); + sai_route_entries[i] = route_entry_ptr->sai_route_entry; + object_statuses[i] = m_routerBulker.remove_entry(&object_statuses[i], &sai_route_entries[i]); + } + + m_routerBulker.flush(); + + for (size_t i = 0; i < route_entries.size(); ++i) + { + const auto &route_entry = route_entries[i]; + auto *route_entry_ptr = getRouteEntry(route_entry.route_entry_key); + CHECK_ERROR_AND_LOG(object_statuses[i], + "Failed to delete route entry " << QuotedVar(route_entry.route_entry_key)); + if (object_statuses[i] == SAI_STATUS_SUCCESS) + { + if (route_entry_ptr->action == p4orch::kSetNexthopId || + route_entry_ptr->action == p4orch::kSetNexthopIdAndMetadata) + { + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, + KeyGenerator::generateNextHopKey(route_entry_ptr->nexthop_id)); + } + else if (route_entry_ptr->action == p4orch::kSetWcmpGroupId || + route_entry_ptr->action == p4orch::kSetWcmpGroupIdAndMetadata) + { + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(route_entry_ptr->wcmp_group)); + } + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, route_entry.route_entry_key); + if (route_entry.route_prefix.isV4()) + { + gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV4_ROUTE); + } + else + { + gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_IPV6_ROUTE); + } + m_vrfOrch->decreaseVrfRefCount(route_entry.vrf_id); + m_routeTable.erase(route_entry.route_entry_key); + statuses[i] = ReturnCode(); + } + else + { + statuses[i] = ReturnCode(object_statuses[i]) + << "Failed to delete route entry " << QuotedVar(route_entry.route_entry_key); + } + } + + return statuses; +} + +ReturnCode RouteManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) +{ + return StatusCode::SWSS_RC_UNIMPLEMENTED; } -void RouteManager::drain() { - SWSS_LOG_ENTER(); +void RouteManager::enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) +{ + m_entries.push_back(entry); +} + +void RouteManager::drain() +{ + SWSS_LOG_ENTER(); + + std::vector create_route_list; + std::vector update_route_list; + std::vector delete_route_list; + std::vector create_tuple_list; + std::vector update_tuple_list; + std::vector delete_tuple_list; + std::unordered_set route_entry_list; + + for (const auto &key_op_fvs_tuple : m_entries) + { + std::string table_name; + std::string key; + parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &key); + const std::vector &attributes = kfvFieldsValues(key_op_fvs_tuple); + + ReturnCode status; + auto route_entry_or = deserializeRouteEntry(key, attributes, table_name); + if (!route_entry_or.ok()) + { + status = route_entry_or.status(); + SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", + QuotedVar(table_name + ":" + key).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + auto &route_entry = *route_entry_or; + + // A single batch should not modify the same route more than once. + if (route_entry_list.count(route_entry.route_entry_key) != 0) + { + status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Route entry has been included in the same batch"; + SWSS_LOG_ERROR("%s: %s", status.message().c_str(), QuotedVar(route_entry.route_entry_key).c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + + const std::string &operation = kfvOp(key_op_fvs_tuple); + status = validateRouteEntry(route_entry, operation); + if (!status.ok()) + { + SWSS_LOG_ERROR("Validation failed for Route APP DB entry with key %s: %s", + QuotedVar(table_name + ":" + key).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + route_entry_list.insert(route_entry.route_entry_key); + + if (operation == SET_COMMAND) + { + if (getRouteEntry(route_entry.route_entry_key) == nullptr) + { + create_route_list.push_back(route_entry); + create_tuple_list.push_back(key_op_fvs_tuple); + } + else + { + update_route_list.push_back(route_entry); + update_tuple_list.push_back(key_op_fvs_tuple); + } + } + else + { + delete_route_list.push_back(route_entry); + delete_tuple_list.push_back(key_op_fvs_tuple); + } + } + + if (!create_route_list.empty()) + { + auto statuses = createRouteEntries(create_route_list); + for (size_t i = 0; i < create_route_list.size(); ++i) + { + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(create_tuple_list[i]), + kfvFieldsValues(create_tuple_list[i]), statuses[i], + /*replace=*/true); + } + } + if (!update_route_list.empty()) + { + auto statuses = updateRouteEntries(update_route_list); + for (size_t i = 0; i < update_route_list.size(); ++i) + { + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(update_tuple_list[i]), + kfvFieldsValues(update_tuple_list[i]), statuses[i], + /*replace=*/true); + } + } + if (!delete_route_list.empty()) + { + auto statuses = deleteRouteEntries(delete_route_list); + for (size_t i = 0; i < delete_route_list.size(); ++i) + { + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(delete_tuple_list[i]), + kfvFieldsValues(delete_tuple_list[i]), statuses[i], + /*replace=*/true); + } + } + m_entries.clear(); +} - std::vector create_route_list; - std::vector update_route_list; - std::vector delete_route_list; - std::vector create_tuple_list; - std::vector update_tuple_list; - std::vector delete_tuple_list; - std::unordered_set route_entry_list; +std::string RouteManager::verifyState(const std::string &key, const std::vector &tuple) +{ + SWSS_LOG_ENTER(); - for (const auto& key_op_fvs_tuple : m_entries) { + auto pos = key.find_first_of(kTableKeyDelimiter); + if (pos == std::string::npos) + { + return std::string("Invalid key: ") + key; + } + std::string p4rt_table = key.substr(0, pos); + std::string p4rt_key = key.substr(pos + 1); + if (p4rt_table != APP_P4RT_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } std::string table_name; - std::string key; - parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &key); - const std::vector& attributes = - kfvFieldsValues(key_op_fvs_tuple); + std::string key_content; + parseP4RTKey(p4rt_key, &table_name, &key_content); + if (table_name != APP_P4RT_IPV4_TABLE_NAME && table_name != APP_P4RT_IPV6_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } ReturnCode status; - auto route_entry_or = deserializeRouteEntry(key, attributes, table_name); - if (!route_entry_or.ok()) { - status = route_entry_or.status(); - SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", - QuotedVar(table_name + ":" + key).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - auto& route_entry = *route_entry_or; - - // A single batch should not modify the same route more than once. - if (route_entry_list.count(route_entry.route_entry_key) != 0) { - status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Route entry has been included in the same batch"; - SWSS_LOG_ERROR("%s: %s", status.message().c_str(), - QuotedVar(route_entry.route_entry_key).c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - - const std::string& operation = kfvOp(key_op_fvs_tuple); - status = validateRouteEntry(route_entry, operation); - if (!status.ok()) { - SWSS_LOG_ERROR( - "Validation failed for Route APP DB entry with key %s: %s", - QuotedVar(table_name + ":" + key).c_str(), status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - route_entry_list.insert(route_entry.route_entry_key); - - if (operation == SET_COMMAND) { - if (getRouteEntry(route_entry.route_entry_key) == nullptr) { - create_route_list.push_back(route_entry); - create_tuple_list.push_back(key_op_fvs_tuple); - } else { - update_route_list.push_back(route_entry); - update_tuple_list.push_back(key_op_fvs_tuple); - } - } else { - delete_route_list.push_back(route_entry); - delete_tuple_list.push_back(key_op_fvs_tuple); - } - } - - if (!create_route_list.empty()) { - auto statuses = createRouteEntries(create_route_list); - for (size_t i = 0; i < create_route_list.size(); ++i) { - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(create_tuple_list[i]), - kfvFieldsValues(create_tuple_list[i]), statuses[i], - /*replace=*/true); - } - } - if (!update_route_list.empty()) { - auto statuses = updateRouteEntries(update_route_list); - for (size_t i = 0; i < update_route_list.size(); ++i) { - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(update_tuple_list[i]), - kfvFieldsValues(update_tuple_list[i]), statuses[i], - /*replace=*/true); - } - } - if (!delete_route_list.empty()) { - auto statuses = deleteRouteEntries(delete_route_list); - for (size_t i = 0; i < delete_route_list.size(); ++i) { - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(delete_tuple_list[i]), - kfvFieldsValues(delete_tuple_list[i]), statuses[i], - /*replace=*/true); - } - } - m_entries.clear(); -} + auto app_db_entry_or = deserializeRouteEntry(key_content, tuple, table_name); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + std::stringstream msg; + msg << "Unable to deserialize key " << QuotedVar(key) << ": " << status.message(); + return msg.str(); + } + auto &app_db_entry = *app_db_entry_or; + + auto *route_entry = getRouteEntry(app_db_entry.route_entry_key); + if (route_entry == nullptr) + { + std::stringstream msg; + msg << "No entry found with key " << QuotedVar(key); + return msg.str(); + } -std::string RouteManager::verifyState( - const std::string& key, const std::vector& tuple) { - SWSS_LOG_ENTER(); - - auto pos = key.find_first_of(kTableKeyDelimiter); - if (pos == std::string::npos) { - return std::string("Invalid key: ") + key; - } - std::string p4rt_table = key.substr(0, pos); - std::string p4rt_key = key.substr(pos + 1); - if (p4rt_table != APP_P4RT_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - std::string table_name; - std::string key_content; - parseP4RTKey(p4rt_key, &table_name, &key_content); - if (table_name != APP_P4RT_IPV4_TABLE_NAME && - table_name != APP_P4RT_IPV6_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - - ReturnCode status; - auto app_db_entry_or = deserializeRouteEntry(key_content, tuple, table_name); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - std::stringstream msg; - msg << "Unable to deserialize key " << QuotedVar(key) << ": " - << status.message(); - return msg.str(); - } - auto& app_db_entry = *app_db_entry_or; - - auto* route_entry = getRouteEntry(app_db_entry.route_entry_key); - if (route_entry == nullptr) { - std::stringstream msg; - msg << "No entry found with key " << QuotedVar(key); - return msg.str(); - } - - std::string cache_result = verifyStateCache(app_db_entry, route_entry); - std::string asic_db_result = verifyStateAsicDb(route_entry); - if (cache_result.empty()) { - return asic_db_result; - } - if (asic_db_result.empty()) { - return cache_result; - } - return cache_result + "; " + asic_db_result; + std::string cache_result = verifyStateCache(app_db_entry, route_entry); + std::string asic_db_result = verifyStateAsicDb(route_entry); + if (cache_result.empty()) + { + return asic_db_result; + } + if (asic_db_result.empty()) + { + return cache_result; + } + return cache_result + "; " + asic_db_result; } -std::string RouteManager::verifyStateCache(const P4RouteEntry& app_db_entry, - const P4RouteEntry* route_entry) { - ReturnCode status = validateRouteEntry(app_db_entry, SET_COMMAND); - if (!status.ok()) { - std::stringstream msg; - msg << "Validation failed for route DB entry with key " - << QuotedVar(app_db_entry.route_entry_key) << ": " << status.message(); - return msg.str(); - } - - if (route_entry->route_entry_key != app_db_entry.route_entry_key) { - std::stringstream msg; - msg << "Route entry " << QuotedVar(app_db_entry.route_entry_key) - << " does not match internal cache " - << QuotedVar(route_entry->route_entry_key) << " in route manager."; - return msg.str(); - } - if (route_entry->vrf_id != app_db_entry.vrf_id) { - std::stringstream msg; - msg << "Route entry " << QuotedVar(app_db_entry.route_entry_key) - << " with VRF " << QuotedVar(app_db_entry.vrf_id) - << " does not match internal cache " << QuotedVar(route_entry->vrf_id) - << " in route manager."; - return msg.str(); - } - if (route_entry->route_prefix.to_string() != - app_db_entry.route_prefix.to_string()) { - std::stringstream msg; - msg << "Route entry " << QuotedVar(app_db_entry.route_entry_key) - << " with route prefix " << app_db_entry.route_prefix.to_string() - << " does not match internal cache " - << route_entry->route_prefix.to_string() << " in route manager."; - return msg.str(); - } - if (route_entry->action != app_db_entry.action) { - std::stringstream msg; - msg << "Route entry " << QuotedVar(app_db_entry.route_entry_key) - << " with action " << QuotedVar(app_db_entry.action) - << " does not match internal cache " << QuotedVar(route_entry->action) - << " in route manager."; - return msg.str(); - } - if (route_entry->nexthop_id != app_db_entry.nexthop_id) { - std::stringstream msg; - msg << "Route entry " << QuotedVar(app_db_entry.route_entry_key) - << " with nexthop ID " << QuotedVar(app_db_entry.nexthop_id) - << " does not match internal cache " - << QuotedVar(route_entry->nexthop_id) << " in route manager."; - return msg.str(); - } - if (route_entry->wcmp_group != app_db_entry.wcmp_group) { - std::stringstream msg; - msg << "Route entry " << QuotedVar(app_db_entry.route_entry_key) - << " with WCMP group " << QuotedVar(app_db_entry.wcmp_group) - << " does not match internal cache " - << QuotedVar(route_entry->wcmp_group) << " in route manager."; - return msg.str(); - } - if (route_entry->route_metadata != app_db_entry.route_metadata) { - std::stringstream msg; - msg << "Route entry " << QuotedVar(app_db_entry.route_entry_key) - << " with metadata " << QuotedVar(app_db_entry.route_metadata) - << " does not match internal cache " - << QuotedVar(route_entry->route_metadata) << " in route manager."; - return msg.str(); - } - - return ""; +std::string RouteManager::verifyStateCache(const P4RouteEntry &app_db_entry, const P4RouteEntry *route_entry) +{ + ReturnCode status = validateRouteEntry(app_db_entry, SET_COMMAND); + if (!status.ok()) + { + std::stringstream msg; + msg << "Validation failed for route DB entry with key " << QuotedVar(app_db_entry.route_entry_key) << ": " + << status.message(); + return msg.str(); + } + + if (route_entry->route_entry_key != app_db_entry.route_entry_key) + { + std::stringstream msg; + msg << "Route entry " << QuotedVar(app_db_entry.route_entry_key) << " does not match internal cache " + << QuotedVar(route_entry->route_entry_key) << " in route manager."; + return msg.str(); + } + if (route_entry->vrf_id != app_db_entry.vrf_id) + { + std::stringstream msg; + msg << "Route entry " << QuotedVar(app_db_entry.route_entry_key) << " with VRF " + << QuotedVar(app_db_entry.vrf_id) << " does not match internal cache " << QuotedVar(route_entry->vrf_id) + << " in route manager."; + return msg.str(); + } + if (route_entry->route_prefix.to_string() != app_db_entry.route_prefix.to_string()) + { + std::stringstream msg; + msg << "Route entry " << QuotedVar(app_db_entry.route_entry_key) << " with route prefix " + << app_db_entry.route_prefix.to_string() << " does not match internal cache " + << route_entry->route_prefix.to_string() << " in route manager."; + return msg.str(); + } + if (route_entry->action != app_db_entry.action) + { + std::stringstream msg; + msg << "Route entry " << QuotedVar(app_db_entry.route_entry_key) << " with action " + << QuotedVar(app_db_entry.action) << " does not match internal cache " << QuotedVar(route_entry->action) + << " in route manager."; + return msg.str(); + } + if (route_entry->nexthop_id != app_db_entry.nexthop_id) + { + std::stringstream msg; + msg << "Route entry " << QuotedVar(app_db_entry.route_entry_key) << " with nexthop ID " + << QuotedVar(app_db_entry.nexthop_id) << " does not match internal cache " + << QuotedVar(route_entry->nexthop_id) << " in route manager."; + return msg.str(); + } + if (route_entry->wcmp_group != app_db_entry.wcmp_group) + { + std::stringstream msg; + msg << "Route entry " << QuotedVar(app_db_entry.route_entry_key) << " with WCMP group " + << QuotedVar(app_db_entry.wcmp_group) << " does not match internal cache " + << QuotedVar(route_entry->wcmp_group) << " in route manager."; + return msg.str(); + } + if (route_entry->route_metadata != app_db_entry.route_metadata) + { + std::stringstream msg; + msg << "Route entry " << QuotedVar(app_db_entry.route_entry_key) << " with metadata " + << QuotedVar(app_db_entry.route_metadata) << " does not match internal cache " + << QuotedVar(route_entry->route_metadata) << " in route manager."; + return msg.str(); + } + + return ""; } -std::string RouteManager::verifyStateAsicDb(const P4RouteEntry* route_entry) { - std::vector exp_attrs; - std::vector opt_attrs; - sai_attribute_t attr; - - if (route_entry->action == p4orch::kDrop) { - attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - attr.value.s32 = SAI_PACKET_ACTION_DROP; - exp_attrs.push_back(attr); - } else if (route_entry->action == p4orch::kTrap) { - attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - attr.value.s32 = SAI_PACKET_ACTION_TRAP; - exp_attrs.push_back(attr); - } else if (route_entry->action == p4orch::kSetMetadataAndDrop) { - attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - attr.value.s32 = SAI_PACKET_ACTION_DROP; - exp_attrs.push_back(attr); - attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; - attr.value.u32 = swss::to_uint(route_entry->route_metadata); - exp_attrs.push_back(attr); - } else { - attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - attr.value.oid = getNexthopOid(*route_entry, *m_p4OidMapper); - exp_attrs.push_back(attr); - if (route_entry->action == p4orch::kSetNexthopIdAndMetadata || - route_entry->action == p4orch::kSetWcmpGroupIdAndMetadata) { - attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; - attr.value.u32 = swss::to_uint(route_entry->route_metadata); - exp_attrs.push_back(attr); - } - } - - if (route_entry->action == p4orch::kDrop || - route_entry->action == p4orch::kTrap) { - attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - attr.value.oid = SAI_NULL_OBJECT_ID; - opt_attrs.push_back(attr); - attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; - attr.value.u32 = 0; - opt_attrs.push_back(attr); - } else if (route_entry->action == p4orch::kSetMetadataAndDrop) { - attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - attr.value.oid = SAI_NULL_OBJECT_ID; - opt_attrs.push_back(attr); - } else { - attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - attr.value.s32 = SAI_PACKET_ACTION_FORWARD; - opt_attrs.push_back(attr); - if (route_entry->action != p4orch::kSetNexthopIdAndMetadata && - route_entry->action != p4orch::kSetWcmpGroupIdAndMetadata) { - attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; - attr.value.u32 = 0; - opt_attrs.push_back(attr); - } - } - - std::vector exp = - saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_ROUTE_ENTRY, (uint32_t)exp_attrs.size(), - exp_attrs.data(), /*countOnly=*/false); - std::vector opt = - saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_ROUTE_ENTRY, (uint32_t)opt_attrs.size(), - opt_attrs.data(), /*countOnly=*/false); - - swss::DBConnector db("ASIC_DB", 0); - swss::Table table(&db, "ASIC_STATE"); - std::string key = sai_serialize_object_type(SAI_OBJECT_TYPE_ROUTE_ENTRY) + - ":" + sai_serialize_route_entry(getSaiEntry(*route_entry)); - std::vector values; - if (!table.get(key, values)) { - return std::string("ASIC DB key not found ") + key; - } - - return verifyAttrs(values, exp, opt, /*allow_unknown=*/false); +std::string RouteManager::verifyStateAsicDb(const P4RouteEntry *route_entry) +{ + std::vector exp_attrs; + std::vector opt_attrs; + sai_attribute_t attr; + + if (route_entry->action == p4orch::kDrop) + { + attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + attr.value.s32 = SAI_PACKET_ACTION_DROP; + exp_attrs.push_back(attr); + } + else if (route_entry->action == p4orch::kTrap) + { + attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + attr.value.s32 = SAI_PACKET_ACTION_TRAP; + exp_attrs.push_back(attr); + } + else if (route_entry->action == p4orch::kSetMetadataAndDrop) + { + attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + attr.value.s32 = SAI_PACKET_ACTION_DROP; + exp_attrs.push_back(attr); + attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; + attr.value.u32 = swss::to_uint(route_entry->route_metadata); + exp_attrs.push_back(attr); + } + else + { + attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + attr.value.oid = getNexthopOid(*route_entry, *m_p4OidMapper); + exp_attrs.push_back(attr); + if (route_entry->action == p4orch::kSetNexthopIdAndMetadata || + route_entry->action == p4orch::kSetWcmpGroupIdAndMetadata) + { + attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; + attr.value.u32 = swss::to_uint(route_entry->route_metadata); + exp_attrs.push_back(attr); + } + } + + if (route_entry->action == p4orch::kDrop || route_entry->action == p4orch::kTrap) + { + attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + attr.value.oid = SAI_NULL_OBJECT_ID; + opt_attrs.push_back(attr); + attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; + attr.value.u32 = 0; + opt_attrs.push_back(attr); + } + else if (route_entry->action == p4orch::kSetMetadataAndDrop) + { + attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + attr.value.oid = SAI_NULL_OBJECT_ID; + opt_attrs.push_back(attr); + } + else + { + attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + attr.value.s32 = SAI_PACKET_ACTION_FORWARD; + opt_attrs.push_back(attr); + if (route_entry->action != p4orch::kSetNexthopIdAndMetadata && + route_entry->action != p4orch::kSetWcmpGroupIdAndMetadata) + { + attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; + attr.value.u32 = 0; + opt_attrs.push_back(attr); + } + } + + std::vector exp = saimeta::SaiAttributeList::serialize_attr_list( + SAI_OBJECT_TYPE_ROUTE_ENTRY, (uint32_t)exp_attrs.size(), exp_attrs.data(), /*countOnly=*/false); + std::vector opt = saimeta::SaiAttributeList::serialize_attr_list( + SAI_OBJECT_TYPE_ROUTE_ENTRY, (uint32_t)opt_attrs.size(), opt_attrs.data(), /*countOnly=*/false); + + swss::DBConnector db("ASIC_DB", 0); + swss::Table table(&db, "ASIC_STATE"); + std::string key = sai_serialize_object_type(SAI_OBJECT_TYPE_ROUTE_ENTRY) + ":" + + sai_serialize_route_entry(getSaiEntry(*route_entry)); + std::vector values; + if (!table.get(key, values)) + { + return std::string("ASIC DB key not found ") + key; + } + + return verifyAttrs(values, exp, opt, /*allow_unknown=*/false); } diff --git a/orchagent/p4orch/route_manager.h b/orchagent/p4orch/route_manager.h index f6d86178511..72627a9bb3d 100644 --- a/orchagent/p4orch/route_manager.h +++ b/orchagent/p4orch/route_manager.h @@ -16,19 +16,21 @@ #include "response_publisher_interface.h" #include "return_code.h" #include "vrforch.h" -extern "C" { +extern "C" +{ #include "sai.h" } -struct P4RouteEntry { - std::string route_entry_key; // Unique key of a route entry. - std::string vrf_id; - swss::IpPrefix route_prefix; - std::string action; - std::string nexthop_id; - std::string wcmp_group; - std::string route_metadata; // go/gpins-pinball-vip-stats - sai_route_entry_t sai_route_entry; +struct P4RouteEntry +{ + std::string route_entry_key; // Unique key of a route entry. + std::string vrf_id; + swss::IpPrefix route_prefix; + std::string action; + std::string nexthop_id; + std::string wcmp_group; + std::string route_metadata; // go/gpins-pinball-vip-stats + sai_route_entry_t sai_route_entry; }; // P4RouteTable: Route ID, P4RouteEntry @@ -39,124 +41,111 @@ typedef std::unordered_map P4RouteTable; // attribute required in the route update. // RouteUpdater will raise critical state if recovery fails or nexthop OID // cannot be found. -class RouteUpdater { - public: - RouteUpdater(const P4RouteEntry& old_route, const P4RouteEntry& new_route, - P4OidMapper* mapper); - ~RouteUpdater() = default; - - P4RouteEntry getOldEntry() const; - P4RouteEntry getNewEntry() const; - sai_route_entry_t getSaiEntry() const; - // Returns the next SAI attribute that should be performed. - sai_attribute_t getSaiAttr() const; - // Updates the state by the given SAI result. - // Returns true if all operations are completed. - // This method will raise critical state if a recovery action fails. - bool updateResult(sai_status_t sai_status); - // Returns the overall status of the route update. - // This method should only be called after UpdateResult returns true. - ReturnCode getStatus() const; - - private: - // Updates the action index. - // Returns true if there are no more actions. - bool updateIdx(); - // Checks if the current action should be performed or not. - // Returns true if the action should be performed. - bool checkAction() const; - - P4OidMapper* m_p4OidMapper; - P4RouteEntry m_oldRoute; - P4RouteEntry m_newRoute; - ReturnCode m_status; - std::vector m_actions; - bool m_revert = false; - int m_idx = -1; +class RouteUpdater +{ + public: + RouteUpdater(const P4RouteEntry &old_route, const P4RouteEntry &new_route, P4OidMapper *mapper); + ~RouteUpdater() = default; + + P4RouteEntry getOldEntry() const; + P4RouteEntry getNewEntry() const; + sai_route_entry_t getSaiEntry() const; + // Returns the next SAI attribute that should be performed. + sai_attribute_t getSaiAttr() const; + // Updates the state by the given SAI result. + // Returns true if all operations are completed. + // This method will raise critical state if a recovery action fails. + bool updateResult(sai_status_t sai_status); + // Returns the overall status of the route update. + // This method should only be called after UpdateResult returns true. + ReturnCode getStatus() const; + + private: + // Updates the action index. + // Returns true if there are no more actions. + bool updateIdx(); + // Checks if the current action should be performed or not. + // Returns true if the action should be performed. + bool checkAction() const; + + P4OidMapper *m_p4OidMapper; + P4RouteEntry m_oldRoute; + P4RouteEntry m_newRoute; + ReturnCode m_status; + std::vector m_actions; + bool m_revert = false; + int m_idx = -1; }; -class RouteManager : public ObjectManagerInterface { - public: - RouteManager(P4OidMapper* p4oidMapper, VRFOrch* vrfOrch, - ResponsePublisherInterface* publisher); - virtual ~RouteManager() = default; - - void enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) override; - void drain() override; - std::string verifyState( - const std::string& key, - const std::vector& tuple) override; - ReturnCode getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) override; - - private: - // Applies route entry updates from src to dest. The merged result will be - // stored in ret. - // The src should have passed all validation checks. - // Return true if there are updates, false otherwise. - bool mergeRouteEntry(const P4RouteEntry& dest, const P4RouteEntry& src, - P4RouteEntry* ret); - - // Converts db table entry into P4RouteEntry. - ReturnCodeOr deserializeRouteEntry( - const std::string& key, - const std::vector& attributes, - const std::string& table_name); - - // Gets the internal cached route entry by its key. - // Return nullptr if corresponding route entry is not cached. - P4RouteEntry* getRouteEntry(const std::string& route_entry_key); - - // Performs route entry validation. - ReturnCode validateRouteEntry(const P4RouteEntry& route_entry, - const std::string& operation); - - // Performs route entry validation for SET command. - ReturnCode validateSetRouteEntry(const P4RouteEntry& route_entry); - - // Performs route entry validation for DEL command. - ReturnCode validateDelRouteEntry(const P4RouteEntry& route_entry); - - // Creates a list of route entries. - std::vector createRouteEntries( - const std::vector& route_entries); - - // Updates a list of route entries. - std::vector updateRouteEntries( - const std::vector& route_entries); - - // Deletes a list of route entries. - std::vector deleteRouteEntries( - const std::vector& route_entries); - - // On a successful route entry update, updates the reference counters and - // internal data. - void updateRouteEntriesMeta(const P4RouteEntry& old_entry, - const P4RouteEntry& new_entry); - - // Auxiliary method to perform route update. - void updateRouteAttrs( - int size, const std::vector>& updaters, - std::vector& indice, std::vector& statuses); - - // Verifies internal cache for an entry. - std::string verifyStateCache(const P4RouteEntry& app_db_entry, - const P4RouteEntry* route_entry); - - // Verifies ASIC DB for an entry. - std::string verifyStateAsicDb(const P4RouteEntry* route_entry); - - // Returns the SAI entry. - sai_route_entry_t getSaiEntry(const P4RouteEntry& route_entry); - - P4RouteTable m_routeTable; - P4OidMapper* m_p4OidMapper; - VRFOrch* m_vrfOrch; - EntityBulker m_routerBulker; - ResponsePublisherInterface* m_publisher; - std::deque m_entries; - - friend class RouteManagerTest; +class RouteManager : public ObjectManagerInterface +{ + public: + RouteManager(P4OidMapper *p4oidMapper, VRFOrch *vrfOrch, ResponsePublisherInterface *publisher); + virtual ~RouteManager() = default; + + void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; + void drain() override; + std::string verifyState(const std::string &key, const std::vector &tuple) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; + + private: + // Applies route entry updates from src to dest. The merged result will be + // stored in ret. + // The src should have passed all validation checks. + // Return true if there are updates, false otherwise. + bool mergeRouteEntry(const P4RouteEntry &dest, const P4RouteEntry &src, P4RouteEntry *ret); + + // Converts db table entry into P4RouteEntry. + ReturnCodeOr deserializeRouteEntry(const std::string &key, + const std::vector &attributes, + const std::string &table_name); + + // Gets the internal cached route entry by its key. + // Return nullptr if corresponding route entry is not cached. + P4RouteEntry *getRouteEntry(const std::string &route_entry_key); + + // Performs route entry validation. + ReturnCode validateRouteEntry(const P4RouteEntry &route_entry, const std::string &operation); + + // Performs route entry validation for SET command. + ReturnCode validateSetRouteEntry(const P4RouteEntry &route_entry); + + // Performs route entry validation for DEL command. + ReturnCode validateDelRouteEntry(const P4RouteEntry &route_entry); + + // Creates a list of route entries. + std::vector createRouteEntries(const std::vector &route_entries); + + // Updates a list of route entries. + std::vector updateRouteEntries(const std::vector &route_entries); + + // Deletes a list of route entries. + std::vector deleteRouteEntries(const std::vector &route_entries); + + // On a successful route entry update, updates the reference counters and + // internal data. + void updateRouteEntriesMeta(const P4RouteEntry &old_entry, const P4RouteEntry &new_entry); + + // Auxiliary method to perform route update. + void updateRouteAttrs(int size, const std::vector> &updaters, + std::vector &indice, std::vector &statuses); + + // Verifies internal cache for an entry. + std::string verifyStateCache(const P4RouteEntry &app_db_entry, const P4RouteEntry *route_entry); + + // Verifies ASIC DB for an entry. + std::string verifyStateAsicDb(const P4RouteEntry *route_entry); + + // Returns the SAI entry. + sai_route_entry_t getSaiEntry(const P4RouteEntry &route_entry); + + P4RouteTable m_routeTable; + P4OidMapper *m_p4OidMapper; + VRFOrch *m_vrfOrch; + EntityBulker m_routerBulker; + ResponsePublisherInterface *m_publisher; + std::deque m_entries; + + friend class RouteManagerTest; }; diff --git a/orchagent/p4orch/router_interface_manager.cpp b/orchagent/p4orch/router_interface_manager.cpp index 11f1460d052..de32576e682 100644 --- a/orchagent/p4orch/router_interface_manager.cpp +++ b/orchagent/p4orch/router_interface_manager.cpp @@ -24,533 +24,536 @@ using ::p4orch::kTableKeyDelimiter; extern sai_object_id_t gSwitchId; extern sai_object_id_t gVirtualRouterId; -extern sai_router_interface_api_t* sai_router_intfs_api; - -extern PortsOrch* gPortsOrch; -extern Directory gDirectory; +extern sai_router_interface_api_t *sai_router_intfs_api; + +extern PortsOrch *gPortsOrch; +extern Directory gDirectory; + +namespace +{ + +ReturnCode validateRouterInterfaceAppDbEntry(const P4RouterInterfaceAppDbEntry &app_db_entry) +{ + // Perform generic APP DB entry validations. Operation specific validations + // will be done by the respective request process methods. + + if (app_db_entry.is_set_port_name) + { + Port port; + if (!gPortsOrch->getPort(app_db_entry.port_name, port)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Port " << QuotedVar(app_db_entry.port_name) << " does not exist"; + } + } -namespace { + if ((app_db_entry.is_set_src_mac) && (app_db_entry.src_mac_address.to_string() == "00:00:00:00:00:00")) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid source mac address " << QuotedVar(app_db_entry.src_mac_address.to_string()); + } -ReturnCode validateRouterInterfaceAppDbEntry( - const P4RouterInterfaceAppDbEntry& app_db_entry) { - // Perform generic APP DB entry validations. Operation specific validations - // will be done by the respective request process methods. + return ReturnCode(); +} - if (app_db_entry.is_set_port_name) { +ReturnCodeOr> getSaiAttrs(const P4RouterInterfaceEntry &router_intf_entry) +{ Port port; - if (!gPortsOrch->getPort(app_db_entry.port_name, port)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Port " << QuotedVar(app_db_entry.port_name) - << " does not exist"; + if (!gPortsOrch->getPort(router_intf_entry.port_name, port)) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Failed to get port info for port " << QuotedVar(router_intf_entry.port_name)); } - } - if ((app_db_entry.is_set_src_mac) && - (app_db_entry.src_mac_address.to_string() == "00:00:00:00:00:00")) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid source mac address " - << QuotedVar(app_db_entry.src_mac_address.to_string()); - } + std::vector attrs; + sai_attribute_t attr; - return ReturnCode(); -} - -ReturnCodeOr> getSaiAttrs( - const P4RouterInterfaceEntry& router_intf_entry) { - Port port; - if (!gPortsOrch->getPort(router_intf_entry.port_name, port)) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Failed to get port info for port " - << QuotedVar(router_intf_entry.port_name)); - } - - std::vector attrs; - sai_attribute_t attr; - - // Map all P4 router interfaces to default VRF as virtual router is mandatory - // parameter for creation of router interfaces in SAI. - attr.id = SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID; - attr.value.oid = gVirtualRouterId; - attrs.push_back(attr); - - // If mac address is not set then swss::MacAddress initializes mac address - // to 00:00:00:00:00:00. - if (router_intf_entry.src_mac_address.to_string() != "00:00:00:00:00:00") { - attr.id = SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS; - memcpy(attr.value.mac, router_intf_entry.src_mac_address.getMac(), - sizeof(sai_mac_t)); + // Map all P4 router interfaces to default VRF as virtual router is mandatory + // parameter for creation of router interfaces in SAI. + attr.id = SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID; + attr.value.oid = gVirtualRouterId; attrs.push_back(attr); - } - attr.id = SAI_ROUTER_INTERFACE_ATTR_TYPE; - switch (port.m_type) { + // If mac address is not set then swss::MacAddress initializes mac address + // to 00:00:00:00:00:00. + if (router_intf_entry.src_mac_address.to_string() != "00:00:00:00:00:00") + { + attr.id = SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS; + memcpy(attr.value.mac, router_intf_entry.src_mac_address.getMac(), sizeof(sai_mac_t)); + attrs.push_back(attr); + } + + attr.id = SAI_ROUTER_INTERFACE_ATTR_TYPE; + switch (port.m_type) + { case Port::PHY: - attr.value.s32 = SAI_ROUTER_INTERFACE_TYPE_PORT; - attrs.push_back(attr); - attr.id = SAI_ROUTER_INTERFACE_ATTR_PORT_ID; - attr.value.oid = port.m_port_id; - break; + attr.value.s32 = SAI_ROUTER_INTERFACE_TYPE_PORT; + attrs.push_back(attr); + attr.id = SAI_ROUTER_INTERFACE_ATTR_PORT_ID; + attr.value.oid = port.m_port_id; + break; case Port::LAG: - attr.value.s32 = SAI_ROUTER_INTERFACE_TYPE_PORT; - attrs.push_back(attr); - attr.id = SAI_ROUTER_INTERFACE_ATTR_PORT_ID; - attr.value.oid = port.m_lag_id; - break; + attr.value.s32 = SAI_ROUTER_INTERFACE_TYPE_PORT; + attrs.push_back(attr); + attr.id = SAI_ROUTER_INTERFACE_ATTR_PORT_ID; + attr.value.oid = port.m_lag_id; + break; case Port::VLAN: - attr.value.s32 = SAI_ROUTER_INTERFACE_TYPE_VLAN; - attrs.push_back(attr); - attr.id = SAI_ROUTER_INTERFACE_ATTR_VLAN_ID; - attr.value.oid = port.m_vlan_info.vlan_oid; - break; + attr.value.s32 = SAI_ROUTER_INTERFACE_TYPE_VLAN; + attrs.push_back(attr); + attr.id = SAI_ROUTER_INTERFACE_ATTR_VLAN_ID; + attr.value.oid = port.m_vlan_info.vlan_oid; + break; // TODO: add support for PORT::SUBPORT default: - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unsupported port type: " << port.m_type); - } - attrs.push_back(attr); + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Unsupported port type: " << port.m_type); + } + attrs.push_back(attr); - // Configure port MTU on router interface - attr.id = SAI_ROUTER_INTERFACE_ATTR_MTU; - attr.value.u32 = port.m_mtu; - attrs.push_back(attr); + // Configure port MTU on router interface + attr.id = SAI_ROUTER_INTERFACE_ATTR_MTU; + attr.value.u32 = port.m_mtu; + attrs.push_back(attr); - return attrs; + return attrs; } -} // namespace - -ReturnCodeOr -RouterInterfaceManager::deserializeRouterIntfEntry( - const std::string& key, - const std::vector& attributes) { - SWSS_LOG_ENTER(); - - P4RouterInterfaceAppDbEntry app_db_entry = {}; - try { - nlohmann::json j = nlohmann::json::parse(key); - app_db_entry.router_interface_id = - j[prependMatchField(p4orch::kRouterInterfaceId)]; - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to deserialize router interface id"; - } - - for (const auto& it : attributes) { - const auto& field = fvField(it); - const auto& value = fvValue(it); - if (field == prependParamField(p4orch::kPort)) { - app_db_entry.port_name = value; - app_db_entry.is_set_port_name = true; - } else if (field == prependParamField(p4orch::kSrcMac)) { - try { - app_db_entry.src_mac_address = swss::MacAddress(value); - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid MAC address " << QuotedVar(value) << " of field " - << QuotedVar(field); - } - app_db_entry.is_set_src_mac = true; - } else if (field != p4orch::kAction && - field != p4orch::kControllerMetadata) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unexpected field " << QuotedVar(field) << " in table entry"; - } - } - - return app_db_entry; +} // namespace + +ReturnCodeOr RouterInterfaceManager::deserializeRouterIntfEntry( + const std::string &key, const std::vector &attributes) +{ + SWSS_LOG_ENTER(); + + P4RouterInterfaceAppDbEntry app_db_entry = {}; + try + { + nlohmann::json j = nlohmann::json::parse(key); + app_db_entry.router_interface_id = j[prependMatchField(p4orch::kRouterInterfaceId)]; + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Failed to deserialize router interface id"; + } + + for (const auto &it : attributes) + { + const auto &field = fvField(it); + const auto &value = fvValue(it); + if (field == prependParamField(p4orch::kPort)) + { + app_db_entry.port_name = value; + app_db_entry.is_set_port_name = true; + } + else if (field == prependParamField(p4orch::kSrcMac)) + { + try + { + app_db_entry.src_mac_address = swss::MacAddress(value); + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid MAC address " << QuotedVar(value) << " of field " << QuotedVar(field); + } + app_db_entry.is_set_src_mac = true; + } + else if (field != p4orch::kAction && field != p4orch::kControllerMetadata) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unexpected field " << QuotedVar(field) << " in table entry"; + } + } + + return app_db_entry; } -P4RouterInterfaceEntry* RouterInterfaceManager::getRouterInterfaceEntry( - const std::string& router_intf_key) { - SWSS_LOG_ENTER(); +P4RouterInterfaceEntry *RouterInterfaceManager::getRouterInterfaceEntry(const std::string &router_intf_key) +{ + SWSS_LOG_ENTER(); - if (m_routerIntfTable.find(router_intf_key) == m_routerIntfTable.end()) - return nullptr; + if (m_routerIntfTable.find(router_intf_key) == m_routerIntfTable.end()) + return nullptr; - return &m_routerIntfTable[router_intf_key]; + return &m_routerIntfTable[router_intf_key]; } -ReturnCode RouterInterfaceManager::createRouterInterface( - const std::string& router_intf_key, - P4RouterInterfaceEntry& router_intf_entry) { - SWSS_LOG_ENTER(); - - if (getRouterInterfaceEntry(router_intf_key) != nullptr) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_EXISTS) - << "Router interface " - << QuotedVar(router_intf_entry.router_interface_id) - << " already exists"); - } - - if (m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - router_intf_key)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Router interface " << QuotedVar(router_intf_key) - << " already exists in the centralized map"); - } - - ASSIGN_OR_RETURN(std::vector attrs, - getSaiAttrs(router_intf_entry)); - - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_router_intfs_api->create_router_interface( - &router_intf_entry.router_interface_oid, gSwitchId, - (uint32_t)attrs.size(), attrs.data()), - "Failed to create router interface " - << QuotedVar(router_intf_entry.router_interface_id)); - - gPortsOrch->increasePortRefCount(router_intf_entry.port_name); - gDirectory.get()->increaseVrfRefCount(gVirtualRouterId); - - m_routerIntfTable[router_intf_key] = router_intf_entry; - m_p4OidMapper->setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key, - router_intf_entry.router_interface_oid); - return ReturnCode(); +ReturnCode RouterInterfaceManager::createRouterInterface(const std::string &router_intf_key, + P4RouterInterfaceEntry &router_intf_entry) +{ + SWSS_LOG_ENTER(); + + if (getRouterInterfaceEntry(router_intf_key) != nullptr) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_EXISTS) + << "Router interface " << QuotedVar(router_intf_entry.router_interface_id) + << " already exists"); + } + + if (m_p4OidMapper->existsOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Router interface " << QuotedVar(router_intf_key) + << " already exists in the centralized map"); + } + + ASSIGN_OR_RETURN(std::vector attrs, getSaiAttrs(router_intf_entry)); + + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_router_intfs_api->create_router_interface(&router_intf_entry.router_interface_oid, gSwitchId, + (uint32_t)attrs.size(), attrs.data()), + "Failed to create router interface " << QuotedVar(router_intf_entry.router_interface_id)); + + gPortsOrch->increasePortRefCount(router_intf_entry.port_name); + gDirectory.get()->increaseVrfRefCount(gVirtualRouterId); + + m_routerIntfTable[router_intf_key] = router_intf_entry; + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key, router_intf_entry.router_interface_oid); + return ReturnCode(); } -ReturnCode RouterInterfaceManager::removeRouterInterface( - const std::string& router_intf_key) { - SWSS_LOG_ENTER(); - - auto* router_intf_entry = getRouterInterfaceEntry(router_intf_key); - if (router_intf_entry == nullptr) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Router interface entry with key " - << QuotedVar(router_intf_key) << " does not exist"); - } - - uint32_t ref_count; - if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - router_intf_key, &ref_count)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Failed to get reference count for router interface " - << QuotedVar(router_intf_entry->router_interface_id)); - } - if (ref_count > 0) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Router interface " - << QuotedVar(router_intf_entry->router_interface_id) - << " referenced by other objects (ref_count = " - << ref_count << ")"); - } - - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_router_intfs_api->remove_router_interface( - router_intf_entry->router_interface_oid), - "Failed to remove router interface " - << QuotedVar(router_intf_entry->router_interface_id)); - - gPortsOrch->decreasePortRefCount(router_intf_entry->port_name); - gDirectory.get()->decreaseVrfRefCount(gVirtualRouterId); - - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key); - m_routerIntfTable.erase(router_intf_key); - return ReturnCode(); +ReturnCode RouterInterfaceManager::removeRouterInterface(const std::string &router_intf_key) +{ + SWSS_LOG_ENTER(); + + auto *router_intf_entry = getRouterInterfaceEntry(router_intf_key); + if (router_intf_entry == nullptr) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Router interface entry with key " << QuotedVar(router_intf_key) << " does not exist"); + } + + uint32_t ref_count; + if (!m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key, &ref_count)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Failed to get reference count for router interface " + << QuotedVar(router_intf_entry->router_interface_id)); + } + if (ref_count > 0) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Router interface " << QuotedVar(router_intf_entry->router_interface_id) + << " referenced by other objects (ref_count = " << ref_count << ")"); + } + + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_router_intfs_api->remove_router_interface(router_intf_entry->router_interface_oid), + "Failed to remove router interface " << QuotedVar(router_intf_entry->router_interface_id)); + + gPortsOrch->decreasePortRefCount(router_intf_entry->port_name); + gDirectory.get()->decreaseVrfRefCount(gVirtualRouterId); + + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key); + m_routerIntfTable.erase(router_intf_key); + return ReturnCode(); } -ReturnCode RouterInterfaceManager::setSourceMacAddress( - P4RouterInterfaceEntry* router_intf_entry, - const swss::MacAddress& mac_address) { - SWSS_LOG_ENTER(); - - if (router_intf_entry->src_mac_address == mac_address) return ReturnCode(); - - sai_attribute_t attr; - attr.id = SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS; - memcpy(attr.value.mac, mac_address.getMac(), sizeof(sai_mac_t)); - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_router_intfs_api->set_router_interface_attribute( - router_intf_entry->router_interface_oid, &attr), - "Failed to set mac address " - << QuotedVar(mac_address.to_string()) << " on router interface " - << QuotedVar(router_intf_entry->router_interface_id)); - - router_intf_entry->src_mac_address = mac_address; - return ReturnCode(); +ReturnCode RouterInterfaceManager::setSourceMacAddress(P4RouterInterfaceEntry *router_intf_entry, + const swss::MacAddress &mac_address) +{ + SWSS_LOG_ENTER(); + + if (router_intf_entry->src_mac_address == mac_address) + return ReturnCode(); + + sai_attribute_t attr; + attr.id = SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS; + memcpy(attr.value.mac, mac_address.getMac(), sizeof(sai_mac_t)); + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_router_intfs_api->set_router_interface_attribute(router_intf_entry->router_interface_oid, &attr), + "Failed to set mac address " << QuotedVar(mac_address.to_string()) << " on router interface " + << QuotedVar(router_intf_entry->router_interface_id)); + + router_intf_entry->src_mac_address = mac_address; + return ReturnCode(); } -ReturnCode RouterInterfaceManager::processAddRequest( - const P4RouterInterfaceAppDbEntry& app_db_entry, - const std::string& router_intf_key) { - SWSS_LOG_ENTER(); - - // Perform operation specific validations. - if (!app_db_entry.is_set_port_name) { - LOG_ERROR_AND_RETURN( - ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << p4orch::kPort - << " is mandatory to create router interface. Failed to create " - "router interface " - << QuotedVar(app_db_entry.router_interface_id)); - } - - P4RouterInterfaceEntry router_intf_entry(app_db_entry.router_interface_id, - app_db_entry.port_name, - app_db_entry.src_mac_address); - auto status = createRouterInterface(router_intf_key, router_intf_entry); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to create router interface with key %s", - QuotedVar(router_intf_key).c_str()); - } - - return status; +ReturnCode RouterInterfaceManager::processAddRequest(const P4RouterInterfaceAppDbEntry &app_db_entry, + const std::string &router_intf_key) +{ + SWSS_LOG_ENTER(); + + // Perform operation specific validations. + if (!app_db_entry.is_set_port_name) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << p4orch::kPort + << " is mandatory to create router interface. Failed to create " + "router interface " + << QuotedVar(app_db_entry.router_interface_id)); + } + + P4RouterInterfaceEntry router_intf_entry(app_db_entry.router_interface_id, app_db_entry.port_name, + app_db_entry.src_mac_address); + auto status = createRouterInterface(router_intf_key, router_intf_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to create router interface with key %s", QuotedVar(router_intf_key).c_str()); + } + + return status; } -ReturnCode RouterInterfaceManager::processUpdateRequest( - const P4RouterInterfaceAppDbEntry& app_db_entry, - P4RouterInterfaceEntry* router_intf_entry) { - SWSS_LOG_ENTER(); - - // TODO: port_id is a create_only parameter in SAI. In order - // to update port name, current interface needs to be deleted and a new - // interface with updated parameters needs to be created. - if (app_db_entry.is_set_port_name && - router_intf_entry->port_name != app_db_entry.port_name) { - LOG_ERROR_AND_RETURN( - ReturnCode(StatusCode::SWSS_RC_UNIMPLEMENTED) - << "Updating port name for existing router interface is not " - "supported. Cannot update port name to " - << QuotedVar(app_db_entry.port_name) << " for router interface " - << QuotedVar(router_intf_entry->router_interface_id)); - } - - if (app_db_entry.is_set_src_mac) { - auto status = - setSourceMacAddress(router_intf_entry, app_db_entry.src_mac_address); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to update source mac address with key %s", - QuotedVar(router_intf_entry->router_interface_id).c_str()); - return status; - } - } - - return ReturnCode(); +ReturnCode RouterInterfaceManager::processUpdateRequest(const P4RouterInterfaceAppDbEntry &app_db_entry, + P4RouterInterfaceEntry *router_intf_entry) +{ + SWSS_LOG_ENTER(); + + // TODO: port_id is a create_only parameter in SAI. In order + // to update port name, current interface needs to be deleted and a new + // interface with updated parameters needs to be created. + if (app_db_entry.is_set_port_name && router_intf_entry->port_name != app_db_entry.port_name) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_UNIMPLEMENTED) + << "Updating port name for existing router interface is not " + "supported. Cannot update port name to " + << QuotedVar(app_db_entry.port_name) << " for router interface " + << QuotedVar(router_intf_entry->router_interface_id)); + } + + if (app_db_entry.is_set_src_mac) + { + auto status = setSourceMacAddress(router_intf_entry, app_db_entry.src_mac_address); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to update source mac address with key %s", + QuotedVar(router_intf_entry->router_interface_id).c_str()); + return status; + } + } + + return ReturnCode(); } -ReturnCode RouterInterfaceManager::processDeleteRequest( - const std::string& router_intf_key) { - SWSS_LOG_ENTER(); +ReturnCode RouterInterfaceManager::processDeleteRequest(const std::string &router_intf_key) +{ + SWSS_LOG_ENTER(); - auto status = removeRouterInterface(router_intf_key); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to remove router interface with key %s", - QuotedVar(router_intf_key).c_str()); - } + auto status = removeRouterInterface(router_intf_key); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to remove router interface with key %s", QuotedVar(router_intf_key).c_str()); + } - return status; + return status; } -ReturnCode RouterInterfaceManager::getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) { - std::string value; - - try { - nlohmann::json j = nlohmann::json::parse(json_key); - if (j.find(prependMatchField(p4orch::kRouterInterfaceId)) != j.end()) { - value = j.at(prependMatchField(p4orch::kRouterInterfaceId)) - .get(); - object_key = KeyGenerator::generateRouterInterfaceKey(value); - object_type = SAI_OBJECT_TYPE_ROUTER_INTERFACE; - return ReturnCode(); - } else { - SWSS_LOG_ERROR( - "%s match parameter absent: required for dependent object query", - p4orch::kRouterInterfaceId); - } - } catch (std::exception& ex) { - SWSS_LOG_ERROR("json_key parse error"); - } - - return StatusCode::SWSS_RC_INVALID_PARAM; +ReturnCode RouterInterfaceManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) +{ + std::string value; + + try + { + nlohmann::json j = nlohmann::json::parse(json_key); + if (j.find(prependMatchField(p4orch::kRouterInterfaceId)) != j.end()) + { + value = j.at(prependMatchField(p4orch::kRouterInterfaceId)).get(); + object_key = KeyGenerator::generateRouterInterfaceKey(value); + object_type = SAI_OBJECT_TYPE_ROUTER_INTERFACE; + return ReturnCode(); + } + else + { + SWSS_LOG_ERROR("%s match parameter absent: required for dependent object query", + p4orch::kRouterInterfaceId); + } + } + catch (std::exception &ex) + { + SWSS_LOG_ERROR("json_key parse error"); + } + + return StatusCode::SWSS_RC_INVALID_PARAM; } -void RouterInterfaceManager::enqueue( - const std::string& table_name, const swss::KeyOpFieldsValuesTuple& entry) { - m_entries.push_back(entry); +void RouterInterfaceManager::enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) +{ + m_entries.push_back(entry); } -void RouterInterfaceManager::drain() { - SWSS_LOG_ENTER(); +void RouterInterfaceManager::drain() +{ + SWSS_LOG_ENTER(); + + for (const auto &key_op_fvs_tuple : m_entries) + { + std::string table_name; + std::string db_key; + parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &db_key); + const std::vector &attributes = kfvFieldsValues(key_op_fvs_tuple); + + ReturnCode status; + auto app_db_entry_or = deserializeRouterIntfEntry(db_key, attributes); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", + QuotedVar(table_name + ":" + db_key).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + auto &app_db_entry = *app_db_entry_or; + + status = validateRouterInterfaceAppDbEntry(app_db_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Validation failed for Router Interface APP DB entry with key %s: %s", + QuotedVar(table_name + ":" + db_key).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + + const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_interface_id); + + const std::string &operation = kfvOp(key_op_fvs_tuple); + if (operation == SET_COMMAND) + { + auto *router_intf_entry = getRouterInterfaceEntry(router_intf_key); + if (router_intf_entry == nullptr) + { + // Create router interface + status = processAddRequest(app_db_entry, router_intf_key); + } + else + { + // Modify existing router interface + status = processUpdateRequest(app_db_entry, router_intf_entry); + } + } + else if (operation == DEL_COMMAND) + { + // Delete router interface + status = processDeleteRequest(router_intf_key); + } + else + { + status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Unknown operation type " << QuotedVar(operation); + SWSS_LOG_ERROR("%s", status.message().c_str()); + } + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), status, + /*replace=*/true); + } + m_entries.clear(); +} - for (const auto& key_op_fvs_tuple : m_entries) { +std::string RouterInterfaceManager::verifyState(const std::string &key, const std::vector &tuple) +{ + SWSS_LOG_ENTER(); + + auto pos = key.find_first_of(kTableKeyDelimiter); + if (pos == std::string::npos) + { + return std::string("Invalid key: ") + key; + } + std::string p4rt_table = key.substr(0, pos); + std::string p4rt_key = key.substr(pos + 1); + if (p4rt_table != APP_P4RT_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } std::string table_name; - std::string db_key; - parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &db_key); - const std::vector& attributes = - kfvFieldsValues(key_op_fvs_tuple); - - ReturnCode status; - auto app_db_entry_or = deserializeRouterIntfEntry(db_key, attributes); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", - QuotedVar(table_name + ":" + db_key).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - auto& app_db_entry = *app_db_entry_or; - - status = validateRouterInterfaceAppDbEntry(app_db_entry); - if (!status.ok()) { - SWSS_LOG_ERROR( - "Validation failed for Router Interface APP DB entry with key %s: %s", - QuotedVar(table_name + ":" + db_key).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - - const std::string router_intf_key = - KeyGenerator::generateRouterInterfaceKey( - app_db_entry.router_interface_id); - - const std::string& operation = kfvOp(key_op_fvs_tuple); - if (operation == SET_COMMAND) { - auto* router_intf_entry = getRouterInterfaceEntry(router_intf_key); - if (router_intf_entry == nullptr) { - // Create router interface - status = processAddRequest(app_db_entry, router_intf_key); - } else { - // Modify existing router interface - status = processUpdateRequest(app_db_entry, router_intf_entry); - } - } else if (operation == DEL_COMMAND) { - // Delete router interface - status = processDeleteRequest(router_intf_key); - } else { - status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown operation type " << QuotedVar(operation); - SWSS_LOG_ERROR("%s", status.message().c_str()); - } - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - } - m_entries.clear(); -} + std::string key_content; + parseP4RTKey(p4rt_key, &table_name, &key_content); + if (table_name != APP_P4RT_ROUTER_INTERFACE_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } -std::string RouterInterfaceManager::verifyState( - const std::string& key, const std::vector& tuple) { - SWSS_LOG_ENTER(); - - auto pos = key.find_first_of(kTableKeyDelimiter); - if (pos == std::string::npos) { - return std::string("Invalid key: ") + key; - } - std::string p4rt_table = key.substr(0, pos); - std::string p4rt_key = key.substr(pos + 1); - if (p4rt_table != APP_P4RT_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - std::string table_name; - std::string key_content; - parseP4RTKey(p4rt_key, &table_name, &key_content); - if (table_name != APP_P4RT_ROUTER_INTERFACE_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - - auto app_db_entry_or = deserializeRouterIntfEntry(key_content, tuple); - if (!app_db_entry_or.ok()) { - ReturnCode status = app_db_entry_or.status(); - std::stringstream msg; - msg << "Unable to deserialize key " << QuotedVar(key) << ": " - << status.message(); - return msg.str(); - } - auto& app_db_entry = *app_db_entry_or; - - const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey( - app_db_entry.router_interface_id); - auto* router_intf_entry = getRouterInterfaceEntry(router_intf_key); - if (router_intf_entry == nullptr) { - std::stringstream msg; - msg << "No entry found with key " << QuotedVar(key); - return msg.str(); - } - - std::string cache_result = verifyStateCache(app_db_entry, router_intf_entry); - std::string asic_db_result = verifyStateAsicDb(router_intf_entry); - if (cache_result.empty()) { - return asic_db_result; - } - if (asic_db_result.empty()) { - return cache_result; - } - return cache_result + "; " + asic_db_result; + auto app_db_entry_or = deserializeRouterIntfEntry(key_content, tuple); + if (!app_db_entry_or.ok()) + { + ReturnCode status = app_db_entry_or.status(); + std::stringstream msg; + msg << "Unable to deserialize key " << QuotedVar(key) << ": " << status.message(); + return msg.str(); + } + auto &app_db_entry = *app_db_entry_or; + + const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_interface_id); + auto *router_intf_entry = getRouterInterfaceEntry(router_intf_key); + if (router_intf_entry == nullptr) + { + std::stringstream msg; + msg << "No entry found with key " << QuotedVar(key); + return msg.str(); + } + + std::string cache_result = verifyStateCache(app_db_entry, router_intf_entry); + std::string asic_db_result = verifyStateAsicDb(router_intf_entry); + if (cache_result.empty()) + { + return asic_db_result; + } + if (asic_db_result.empty()) + { + return cache_result; + } + return cache_result + "; " + asic_db_result; } -std::string RouterInterfaceManager::verifyStateCache( - const P4RouterInterfaceAppDbEntry& app_db_entry, - const P4RouterInterfaceEntry* router_intf_entry) { - const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey( - app_db_entry.router_interface_id); - ReturnCode status = validateRouterInterfaceAppDbEntry(app_db_entry); - if (!status.ok()) { - std::stringstream msg; - msg << "Validation failed for Router Interface DB entry with key " - << QuotedVar(router_intf_key) << ": " << status.message(); - return msg.str(); - } - if (router_intf_entry->router_interface_id != - app_db_entry.router_interface_id) { - std::stringstream msg; - msg << "Router interface ID " << QuotedVar(app_db_entry.router_interface_id) - << " does not match internal cache " - << QuotedVar(router_intf_entry->router_interface_id) - << " in router interface manager."; - return msg.str(); - } - if (router_intf_entry->port_name != app_db_entry.port_name) { - std::stringstream msg; - msg << "Port name " << QuotedVar(app_db_entry.port_name) - << " does not match internal cache " - << QuotedVar(router_intf_entry->port_name) - << " in router interface manager."; - return msg.str(); - } - if (router_intf_entry->src_mac_address.to_string() != - app_db_entry.src_mac_address.to_string()) { - std::stringstream msg; - msg << "Source MAC address " << app_db_entry.src_mac_address.to_string() - << " does not match internal cache " - << router_intf_entry->src_mac_address.to_string() - << " in router interface manager."; - return msg.str(); - } - return m_p4OidMapper->verifyOIDMapping( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key, - router_intf_entry->router_interface_oid); +std::string RouterInterfaceManager::verifyStateCache(const P4RouterInterfaceAppDbEntry &app_db_entry, + const P4RouterInterfaceEntry *router_intf_entry) +{ + const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_interface_id); + ReturnCode status = validateRouterInterfaceAppDbEntry(app_db_entry); + if (!status.ok()) + { + std::stringstream msg; + msg << "Validation failed for Router Interface DB entry with key " << QuotedVar(router_intf_key) << ": " + << status.message(); + return msg.str(); + } + if (router_intf_entry->router_interface_id != app_db_entry.router_interface_id) + { + std::stringstream msg; + msg << "Router interface ID " << QuotedVar(app_db_entry.router_interface_id) + << " does not match internal cache " << QuotedVar(router_intf_entry->router_interface_id) + << " in router interface manager."; + return msg.str(); + } + if (router_intf_entry->port_name != app_db_entry.port_name) + { + std::stringstream msg; + msg << "Port name " << QuotedVar(app_db_entry.port_name) << " does not match internal cache " + << QuotedVar(router_intf_entry->port_name) << " in router interface manager."; + return msg.str(); + } + if (router_intf_entry->src_mac_address.to_string() != app_db_entry.src_mac_address.to_string()) + { + std::stringstream msg; + msg << "Source MAC address " << app_db_entry.src_mac_address.to_string() << " does not match internal cache " + << router_intf_entry->src_mac_address.to_string() << " in router interface manager."; + return msg.str(); + } + return m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key, + router_intf_entry->router_interface_oid); } -std::string RouterInterfaceManager::verifyStateAsicDb( - const P4RouterInterfaceEntry* router_intf_entry) { - auto attrs_or = getSaiAttrs(*router_intf_entry); - if (!attrs_or.ok()) { - return std::string("Failed to get SAI attrs: ") + - attrs_or.status().message(); - } - std::vector attrs = *attrs_or; - std::vector exp = - saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, (uint32_t)attrs.size(), - attrs.data(), /*countOnly=*/false); - - swss::DBConnector db("ASIC_DB", 0); - swss::Table table(&db, "ASIC_STATE"); - std::string key = - sai_serialize_object_type(SAI_OBJECT_TYPE_ROUTER_INTERFACE) + ":" + - sai_serialize_object_id(router_intf_entry->router_interface_oid); - std::vector values; - if (!table.get(key, values)) { - return std::string("ASIC DB key not found ") + key; - } - - return verifyAttrs(values, exp, std::vector{}, - /*allow_unknown=*/false); +std::string RouterInterfaceManager::verifyStateAsicDb(const P4RouterInterfaceEntry *router_intf_entry) +{ + auto attrs_or = getSaiAttrs(*router_intf_entry); + if (!attrs_or.ok()) + { + return std::string("Failed to get SAI attrs: ") + attrs_or.status().message(); + } + std::vector attrs = *attrs_or; + std::vector exp = saimeta::SaiAttributeList::serialize_attr_list( + SAI_OBJECT_TYPE_ROUTER_INTERFACE, (uint32_t)attrs.size(), attrs.data(), /*countOnly=*/false); + + swss::DBConnector db("ASIC_DB", 0); + swss::Table table(&db, "ASIC_STATE"); + std::string key = sai_serialize_object_type(SAI_OBJECT_TYPE_ROUTER_INTERFACE) + ":" + + sai_serialize_object_id(router_intf_entry->router_interface_oid); + std::vector values; + if (!table.get(key, values)) + { + return std::string("ASIC DB key not found ") + key; + } + + return verifyAttrs(values, exp, std::vector{}, + /*allow_unknown=*/false); } diff --git a/orchagent/p4orch/router_interface_manager.h b/orchagent/p4orch/router_interface_manager.h index 8983ab9f316..f33f4439792 100644 --- a/orchagent/p4orch/router_interface_manager.h +++ b/orchagent/p4orch/router_interface_manager.h @@ -12,78 +12,68 @@ #include "p4orch/p4orch_util.h" #include "response_publisher_interface.h" #include "return_code.h" -extern "C" { +extern "C" +{ #include "sai.h" } -struct P4RouterInterfaceEntry { - std::string router_interface_id; - std::string port_name; - swss::MacAddress src_mac_address; - sai_object_id_t router_interface_oid = 0; +struct P4RouterInterfaceEntry +{ + std::string router_interface_id; + std::string port_name; + swss::MacAddress src_mac_address; + sai_object_id_t router_interface_oid = 0; - P4RouterInterfaceEntry() = default; - P4RouterInterfaceEntry(const std::string& router_intf_id, - const std::string& port, - const swss::MacAddress& mac_address) - : router_interface_id(router_intf_id), - port_name(port), - src_mac_address(mac_address) {} + P4RouterInterfaceEntry() = default; + P4RouterInterfaceEntry(const std::string &router_intf_id, const std::string &port, + const swss::MacAddress &mac_address) + : router_interface_id(router_intf_id), port_name(port), src_mac_address(mac_address) + { + } }; // P4RouterInterfaceTable: Router Interface key, P4RouterInterfaceEntry -typedef std::unordered_map - P4RouterInterfaceTable; +typedef std::unordered_map P4RouterInterfaceTable; -class RouterInterfaceManager : public ObjectManagerInterface { - public: - RouterInterfaceManager(P4OidMapper* p4oidMapper, - ResponsePublisherInterface* publisher) { - SWSS_LOG_ENTER(); +class RouterInterfaceManager : public ObjectManagerInterface +{ + public: + RouterInterfaceManager(P4OidMapper *p4oidMapper, ResponsePublisherInterface *publisher) + { + SWSS_LOG_ENTER(); - assert(p4oidMapper != nullptr); - m_p4OidMapper = p4oidMapper; - assert(publisher != nullptr); - m_publisher = publisher; - } - virtual ~RouterInterfaceManager() = default; + assert(p4oidMapper != nullptr); + m_p4OidMapper = p4oidMapper; + assert(publisher != nullptr); + m_publisher = publisher; + } + virtual ~RouterInterfaceManager() = default; - void enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) override; - void drain() override; - std::string verifyState( - const std::string& key, - const std::vector& tuple) override; - ReturnCode getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) override; + void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; + void drain() override; + std::string verifyState(const std::string &key, const std::vector &tuple) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; - private: - ReturnCodeOr deserializeRouterIntfEntry( - const std::string& key, - const std::vector& attributes); - P4RouterInterfaceEntry* getRouterInterfaceEntry( - const std::string& router_intf_key); - ReturnCode createRouterInterface(const std::string& router_intf_key, - P4RouterInterfaceEntry& router_intf_entry); - ReturnCode removeRouterInterface(const std::string& router_intf_key); - ReturnCode setSourceMacAddress(P4RouterInterfaceEntry* router_intf_entry, - const swss::MacAddress& mac_address); - ReturnCode processAddRequest(const P4RouterInterfaceAppDbEntry& app_db_entry, - const std::string& router_intf_key); - ReturnCode processUpdateRequest( - const P4RouterInterfaceAppDbEntry& app_db_entry, - P4RouterInterfaceEntry* router_intf_entry); - ReturnCode processDeleteRequest(const std::string& router_intf_key); - std::string verifyStateCache(const P4RouterInterfaceAppDbEntry& app_db_entry, - const P4RouterInterfaceEntry* router_intf_entry); - std::string verifyStateAsicDb( - const P4RouterInterfaceEntry* router_intf_entry); + private: + ReturnCodeOr deserializeRouterIntfEntry( + const std::string &key, const std::vector &attributes); + P4RouterInterfaceEntry *getRouterInterfaceEntry(const std::string &router_intf_key); + ReturnCode createRouterInterface(const std::string &router_intf_key, P4RouterInterfaceEntry &router_intf_entry); + ReturnCode removeRouterInterface(const std::string &router_intf_key); + ReturnCode setSourceMacAddress(P4RouterInterfaceEntry *router_intf_entry, const swss::MacAddress &mac_address); + ReturnCode processAddRequest(const P4RouterInterfaceAppDbEntry &app_db_entry, const std::string &router_intf_key); + ReturnCode processUpdateRequest(const P4RouterInterfaceAppDbEntry &app_db_entry, + P4RouterInterfaceEntry *router_intf_entry); + ReturnCode processDeleteRequest(const std::string &router_intf_key); + std::string verifyStateCache(const P4RouterInterfaceAppDbEntry &app_db_entry, + const P4RouterInterfaceEntry *router_intf_entry); + std::string verifyStateAsicDb(const P4RouterInterfaceEntry *router_intf_entry); - P4RouterInterfaceTable m_routerIntfTable; - P4OidMapper* m_p4OidMapper; - ResponsePublisherInterface* m_publisher; - std::deque m_entries; + P4RouterInterfaceTable m_routerIntfTable; + P4OidMapper *m_p4OidMapper; + ResponsePublisherInterface *m_publisher; + std::deque m_entries; - friend class RouterInterfaceManagerTest; + friend class RouterInterfaceManagerTest; }; diff --git a/orchagent/p4orch/tables_definition_manager.cpp b/orchagent/p4orch/tables_definition_manager.cpp index 733d7501c51..1da15028e58 100644 --- a/orchagent/p4orch/tables_definition_manager.cpp +++ b/orchagent/p4orch/tables_definition_manager.cpp @@ -13,572 +13,658 @@ #include "p4orch/p4orch.h" #include "p4orch/p4orch_util.h" #include "tokenize.h" -extern "C" { +extern "C" +{ #include "saitypes.h" } -extern Directory gDirectory; -extern P4Orch* gP4Orch; +extern Directory gDirectory; +extern P4Orch *gP4Orch; const std::map format_datatype_map = { - {"MAC", "SAI_ATTR_VALUE_TYPE_MAC"}, - {"IPV4", "SAI_ATTR_VALUE_TYPE_IPV4"}, - {"IPV6", "SAI_ATTR_VALUE_TYPE_IPV6"}}; - -std::string BitwidthToDatatype(int bitwidth) { - std::string datatype = "SAI_ATTR_VALUE_TYPE_CHARDATA"; - - if (bitwidth <= 0) { - datatype = "SAI_ATTR_VALUE_TYPE_CHARDATA"; - } else if (bitwidth <= 8) { - datatype = "SAI_ATTR_VALUE_TYPE_UINT8"; - } else if (bitwidth <= 16) { - datatype = "SAI_ATTR_VALUE_TYPE_UINT16"; - } else if (bitwidth <= 32) { - datatype = "SAI_ATTR_VALUE_TYPE_UINT32"; - } else if (bitwidth <= 64) { - datatype = "SAI_ATTR_VALUE_TYPE_UINT64"; - } - - return datatype; + {"MAC", "SAI_ATTR_VALUE_TYPE_MAC"}, {"IPV4", "SAI_ATTR_VALUE_TYPE_IPV4"}, {"IPV6", "SAI_ATTR_VALUE_TYPE_IPV6"}}; + +std::string BitwidthToDatatype(int bitwidth) +{ + std::string datatype = "SAI_ATTR_VALUE_TYPE_CHARDATA"; + + if (bitwidth <= 0) + { + datatype = "SAI_ATTR_VALUE_TYPE_CHARDATA"; + } + else if (bitwidth <= 8) + { + datatype = "SAI_ATTR_VALUE_TYPE_UINT8"; + } + else if (bitwidth <= 16) + { + datatype = "SAI_ATTR_VALUE_TYPE_UINT16"; + } + else if (bitwidth <= 32) + { + datatype = "SAI_ATTR_VALUE_TYPE_UINT32"; + } + else if (bitwidth <= 64) + { + datatype = "SAI_ATTR_VALUE_TYPE_UINT64"; + } + + return datatype; } -std::string parseBitwidthToDatatype(const nlohmann::json& json) { - int bitwidth; - std::string datatype = "SAI_ATTR_VALUE_TYPE_CHARDATA"; +std::string parseBitwidthToDatatype(const nlohmann::json &json) +{ + int bitwidth; + std::string datatype = "SAI_ATTR_VALUE_TYPE_CHARDATA"; - if (json.find(p4orch::kBitwidth) != json.end()) { - bitwidth = json.at(p4orch::kBitwidth).get(); - datatype = BitwidthToDatatype(bitwidth); - } + if (json.find(p4orch::kBitwidth) != json.end()) + { + bitwidth = json.at(p4orch::kBitwidth).get(); + datatype = BitwidthToDatatype(bitwidth); + } - return datatype; + return datatype; } -std::string parseFormatToDatatype(const nlohmann::json& json, - std::string datatype) { - std::string format; +std::string parseFormatToDatatype(const nlohmann::json &json, std::string datatype) +{ + std::string format; - if (json.find(p4orch::kFormat) != json.end()) { - format = json.at(p4orch::kFormat).get(); + if (json.find(p4orch::kFormat) != json.end()) + { + format = json.at(p4orch::kFormat).get(); - auto it = format_datatype_map.find(format); - if (it != format_datatype_map.end()) { - datatype = it->second; + auto it = format_datatype_map.find(format); + if (it != format_datatype_map.end()) + { + datatype = it->second; + } } - } - return datatype; + return datatype; } -ReturnCode parseTableMatchReferences(const nlohmann::json& match_json, - TableMatchInfo& match) { - std::string table, field; - - if (match_json.find(p4orch::kReferences) != match_json.end()) { - for (const auto& ref_json : match_json[p4orch::kReferences]) { - try { - table = ref_json.at(p4orch::kTableRef).get(); - field = ref_json.at(p4orch::kMatchRef).get(); - match.table_reference_map[table] = field; - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "can not parse tables from app-db supplied table definition " - "info"; - } +ReturnCode parseTableMatchReferences(const nlohmann::json &match_json, TableMatchInfo &match) +{ + std::string table, field; + + if (match_json.find(p4orch::kReferences) != match_json.end()) + { + for (const auto &ref_json : match_json[p4orch::kReferences]) + { + try + { + table = ref_json.at(p4orch::kTableRef).get(); + field = ref_json.at(p4orch::kMatchRef).get(); + match.table_reference_map[table] = field; + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "can not parse tables from app-db supplied table definition " + "info"; + } + } } - } - return ReturnCode(); + return ReturnCode(); } -ReturnCode parseActionParamReferences(const nlohmann::json& param_json, - ActionParamInfo& param) { - std::string table, field; - - if (param_json.find(p4orch::kReferences) != param_json.end()) { - for (const auto& ref_json : param_json[p4orch::kReferences]) { - try { - table = ref_json.at(p4orch::kTableRef).get(); - field = ref_json.at(p4orch::kMatchRef).get(); - param.table_reference_map[table] = field; - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "can not parse tables from app-db supplied table definition " - "info"; - } +ReturnCode parseActionParamReferences(const nlohmann::json ¶m_json, ActionParamInfo ¶m) +{ + std::string table, field; + + if (param_json.find(p4orch::kReferences) != param_json.end()) + { + for (const auto &ref_json : param_json[p4orch::kReferences]) + { + try + { + table = ref_json.at(p4orch::kTableRef).get(); + field = ref_json.at(p4orch::kMatchRef).get(); + param.table_reference_map[table] = field; + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "can not parse tables from app-db supplied table definition " + "info"; + } + } } - } - return ReturnCode(); + return ReturnCode(); } -ReturnCode parseTableActionParams(const nlohmann::json& action_json, - ActionInfo& action) { - action.refers_to = false; - if (action_json.find(p4orch::kActionParams) != action_json.end()) { - for (const auto& param_json : action_json[p4orch::kActionParams]) { - try { - ActionParamInfo param; - std::string param_name; - - param_name = param_json.at(p4orch::kName).get(); - param.name = param_name; - param.datatype = parseBitwidthToDatatype(param_json); - param.datatype = parseFormatToDatatype(param_json, param.datatype); - parseActionParamReferences(param_json, param); - action.params[param_name] = param; - - if (!param.table_reference_map.empty()) { - /** - * Helps avoid walk of action parameters if this is set to false at - * action level - */ - action.refers_to = true; +ReturnCode parseTableActionParams(const nlohmann::json &action_json, ActionInfo &action) +{ + action.refers_to = false; + if (action_json.find(p4orch::kActionParams) != action_json.end()) + { + for (const auto ¶m_json : action_json[p4orch::kActionParams]) + { + try + { + ActionParamInfo param; + std::string param_name; + + param_name = param_json.at(p4orch::kName).get(); + param.name = param_name; + param.datatype = parseBitwidthToDatatype(param_json); + param.datatype = parseFormatToDatatype(param_json, param.datatype); + parseActionParamReferences(param_json, param); + action.params[param_name] = param; + + if (!param.table_reference_map.empty()) + { + /** + * Helps avoid walk of action parameters if this is set to false at + * action level + */ + action.refers_to = true; + } + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "can not parse tables from app-db supplied table definition " + "info"; + } } - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "can not parse tables from app-db supplied table definition " - "info"; - } } - } - return ReturnCode(); + return ReturnCode(); } -ReturnCode parseTableCounter(const nlohmann::json& table_json, - TableInfo& table) { - if (table_json.find(p4orch::kCounterUnit) != table_json.end()) { - auto unit = table_json.at(p4orch::kCounterUnit); - if (unit == "PACKETS") { - table.counter_packets_enabled = true; - } else if (unit == "BYTES") { - table.counter_bytes_enabled = true; - } else { - table.counter_packets_enabled = true; - table.counter_bytes_enabled = true; +ReturnCode parseTableCounter(const nlohmann::json &table_json, TableInfo &table) +{ + if (table_json.find(p4orch::kCounterUnit) != table_json.end()) + { + auto unit = table_json.at(p4orch::kCounterUnit); + if (unit == "PACKETS") + { + table.counter_packets_enabled = true; + } + else if (unit == "BYTES") + { + table.counter_bytes_enabled = true; + } + else + { + table.counter_packets_enabled = true; + table.counter_bytes_enabled = true; + } } - } - return ReturnCode(); + return ReturnCode(); } -ReturnCode parseTablesInfo(const nlohmann::json& info_json, - TablesInfo& info_entry) { - ReturnCode status; - int table_id; - std::string table_name, field_name; - - if (info_json.find(p4orch::kTables) == info_json.end()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "no tables in app-db supplied table definition info"; - } - - for (const auto& table_json : info_json[p4orch::kTables]) { - try { - table_id = table_json.at(p4orch::kId).get(); - table_name = table_json.at(p4orch::kAlias).get(); - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "can not parse tables from app-db supplied table definition " - "info"; +ReturnCode parseTablesInfo(const nlohmann::json &info_json, TablesInfo &info_entry) +{ + ReturnCode status; + int table_id; + std::string table_name, field_name; + + if (info_json.find(p4orch::kTables) == info_json.end()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "no tables in app-db supplied table definition info"; } - TableInfo table = {}; - table.name = table_name; - table.id = table_id; - try { - for (const auto& match_json : table_json[p4orch::kmatchFields]) { - TableMatchInfo match = {}; - std::string match_name; - - match_name = match_json.at(p4orch::kName).get(); - match.name = match_name; - match.datatype = parseBitwidthToDatatype(match_json); - match.datatype = parseFormatToDatatype(match_json, match.datatype); - parseTableMatchReferences(match_json, match); - table.match_fields[match_name] = match; - } - - for (const auto& action_json : table_json[p4orch::kActions]) { - ActionInfo action = {}; - std::string action_name; - - action_name = action_json.at(p4orch::kAlias).get(); - action.name = action_name; - parseTableActionParams(action_json, action); - table.action_fields[action_name] = action; - - /** - * If any parameter of action refers to another table, add that one in - * the cross-reference list of current table - */ - for (auto param_it = action.params.begin(); - param_it != action.params.end(); param_it++) { - ActionParamInfo action_param = param_it->second; - for (auto ref_it = action_param.table_reference_map.begin(); - ref_it != action_param.table_reference_map.end(); ref_it++) { - if (std::find(table.action_ref_tables.begin(), - table.action_ref_tables.end(), - ref_it->first) == table.action_ref_tables.end()) { - table.action_ref_tables.push_back(ref_it->first); + for (const auto &table_json : info_json[p4orch::kTables]) + { + try + { + table_id = table_json.at(p4orch::kId).get(); + table_name = table_json.at(p4orch::kAlias).get(); + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "can not parse tables from app-db supplied table definition " + "info"; + } + + TableInfo table = {}; + table.name = table_name; + table.id = table_id; + try + { + for (const auto &match_json : table_json[p4orch::kmatchFields]) + { + TableMatchInfo match = {}; + std::string match_name; + + match_name = match_json.at(p4orch::kName).get(); + match.name = match_name; + match.datatype = parseBitwidthToDatatype(match_json); + match.datatype = parseFormatToDatatype(match_json, match.datatype); + parseTableMatchReferences(match_json, match); + table.match_fields[match_name] = match; + } + + for (const auto &action_json : table_json[p4orch::kActions]) + { + ActionInfo action = {}; + std::string action_name; + + action_name = action_json.at(p4orch::kAlias).get(); + action.name = action_name; + parseTableActionParams(action_json, action); + table.action_fields[action_name] = action; + + /** + * If any parameter of action refers to another table, add that one in + * the cross-reference list of current table + */ + for (auto param_it = action.params.begin(); param_it != action.params.end(); param_it++) + { + ActionParamInfo action_param = param_it->second; + for (auto ref_it = action_param.table_reference_map.begin(); + ref_it != action_param.table_reference_map.end(); ref_it++) + { + if (std::find(table.action_ref_tables.begin(), table.action_ref_tables.end(), ref_it->first) == + table.action_ref_tables.end()) + { + table.action_ref_tables.push_back(ref_it->first); + } + } + } } - } + + parseTableCounter(table_json, table); + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "can not parse table " << QuotedVar(table_name.c_str()) << "match fields"; } - } - parseTableCounter(table_json, table); - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "can not parse table " << QuotedVar(table_name.c_str()) - << "match fields"; + info_entry.m_tableIdNameMap[std::to_string(table_id)] = table_name; + info_entry.m_tableInfoMap[table_name] = table; } - info_entry.m_tableIdNameMap[std::to_string(table_id)] = table_name; - info_entry.m_tableInfoMap[table_name] = table; - } - - return ReturnCode(); + return ReturnCode(); } -ReturnCodeOr -TablesDefnManager::deserializeTablesInfoEntry( - const std::string& key, - const std::vector& attributes) { - SWSS_LOG_ENTER(); - - TablesInfoAppDbEntry app_db_entry = {}; - try { - nlohmann::json j = nlohmann::json::parse(key); - app_db_entry.context = j["context"]; - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to deserialize tables info"; - } - - for (const auto& it : attributes) { - const auto& field = fvField(it); - std::string value = fvValue(it); - if (field == "info") { - app_db_entry.info = value; - } else { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unexpected field " << QuotedVar(field) << " in table entry"; +ReturnCodeOr TablesDefnManager::deserializeTablesInfoEntry( + const std::string &key, const std::vector &attributes) +{ + SWSS_LOG_ENTER(); + + TablesInfoAppDbEntry app_db_entry = {}; + try + { + nlohmann::json j = nlohmann::json::parse(key); + app_db_entry.context = j["context"]; + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Failed to deserialize tables info"; } - } - return app_db_entry; + for (const auto &it : attributes) + { + const auto &field = fvField(it); + std::string value = fvValue(it); + if (field == "info") + { + app_db_entry.info = value; + } + else + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unexpected field " << QuotedVar(field) << " in table entry"; + } + } + + return app_db_entry; } -ReturnCode validateTablesInfoAppDbEntry( - const TablesInfoAppDbEntry& app_db_entry) { - // Perform generic APP DB entry validations. Operation specific validations - // will be done by the respective request process methods. +ReturnCode validateTablesInfoAppDbEntry(const TablesInfoAppDbEntry &app_db_entry) +{ + // Perform generic APP DB entry validations. Operation specific validations + // will be done by the respective request process methods. - return ReturnCode(); + return ReturnCode(); } -TablesInfo* TablesDefnManager::getTablesInfoEntry( - const std::string& context_key) { - SWSS_LOG_ENTER(); +TablesInfo *TablesDefnManager::getTablesInfoEntry(const std::string &context_key) +{ + SWSS_LOG_ENTER(); - if (m_tablesinfoMap.find(context_key) == m_tablesinfoMap.end()) - return nullptr; + if (m_tablesinfoMap.find(context_key) == m_tablesinfoMap.end()) + return nullptr; - return &m_tablesinfoMap[context_key]; + return &m_tablesinfoMap[context_key]; } -ReturnCode TablesDefnManager::processAddRequest( - const TablesInfoAppDbEntry& app_db_entry, const std::string& context_key) { - nlohmann::json tablesinfo_json; - ReturnCode status; +ReturnCode TablesDefnManager::processAddRequest(const TablesInfoAppDbEntry &app_db_entry, + const std::string &context_key) +{ + nlohmann::json tablesinfo_json; + ReturnCode status; - SWSS_LOG_ENTER(); + SWSS_LOG_ENTER(); - if (!m_tablesinfoMap.empty()) { - // For now p4rt can send only same table-definition, so ignore it silently - return ReturnCode(); - } + if (!m_tablesinfoMap.empty()) + { + // For now p4rt can send only same table-definition, so ignore it silently + return ReturnCode(); + } - try { - tablesinfo_json = nlohmann::json::parse(app_db_entry.info); - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "tables info from appdb can not be parsed\n"; - } + try + { + tablesinfo_json = nlohmann::json::parse(app_db_entry.info); + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "tables info from appdb can not be parsed\n"; + } - TablesInfo tablesinfo_entry(app_db_entry.context, tablesinfo_json); + TablesInfo tablesinfo_entry(app_db_entry.context, tablesinfo_json); - status = parseTablesInfo(tablesinfo_json, tablesinfo_entry); - if (!status.ok()) { - return status; - } + status = parseTablesInfo(tablesinfo_json, tablesinfo_entry); + if (!status.ok()) + { + return status; + } - m_tablesinfoMap[app_db_entry.context] = tablesinfo_entry; - gP4Orch->tablesinfo = &m_tablesinfoMap[app_db_entry.context]; - return ReturnCode(); + m_tablesinfoMap[app_db_entry.context] = tablesinfo_entry; + gP4Orch->tablesinfo = &m_tablesinfoMap[app_db_entry.context]; + return ReturnCode(); } -ReturnCode TablesDefnManager::processUpdateRequest( - const TablesInfoAppDbEntry& app_db_entry, const std::string& context_key) { - SWSS_LOG_ENTER(); +ReturnCode TablesDefnManager::processUpdateRequest(const TablesInfoAppDbEntry &app_db_entry, + const std::string &context_key) +{ + SWSS_LOG_ENTER(); - return ReturnCode(StatusCode::SWSS_RC_UNIMPLEMENTED) - << "update of Tables Definition not supported"; + return ReturnCode(StatusCode::SWSS_RC_UNIMPLEMENTED) << "update of Tables Definition not supported"; } -ReturnCode TablesDefnManager::processDeleteRequest( - const std::string& context_key) { - SWSS_LOG_ENTER(); +ReturnCode TablesDefnManager::processDeleteRequest(const std::string &context_key) +{ + SWSS_LOG_ENTER(); - auto* tablesinfo = getTablesInfoEntry(context_key); + auto *tablesinfo = getTablesInfoEntry(context_key); - if (tablesinfo) { - if (gP4Orch->tablesinfo == tablesinfo) { - gP4Orch->tablesinfo = nullptr; - } + if (tablesinfo) + { + if (gP4Orch->tablesinfo == tablesinfo) + { + gP4Orch->tablesinfo = nullptr; + } - tablesinfo->m_tableIdNameMap.clear(); - } + tablesinfo->m_tableIdNameMap.clear(); + } - m_tablesinfoMap.erase(context_key); - return ReturnCode(); + m_tablesinfoMap.erase(context_key); + return ReturnCode(); } -ReturnCode TablesDefnManager::getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) { - return StatusCode::SWSS_RC_INVALID_PARAM; +ReturnCode TablesDefnManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) +{ + return StatusCode::SWSS_RC_INVALID_PARAM; } -std::unordered_map> createGraph( - std::vector> preReq) { - std::unordered_map> graph; +std::unordered_map> createGraph(std::vector> preReq) +{ + std::unordered_map> graph; - for (auto pre : preReq) { - auto it = graph.find(pre.second); - if (it != graph.end()) { - it->second.insert(pre.first); - } else { - graph[pre.second].insert(pre.first); + for (auto pre : preReq) + { + auto it = graph.find(pre.second); + if (it != graph.end()) + { + it->second.insert(pre.first); + } + else + { + graph[pre.second].insert(pre.first); + } } - } - return graph; + return graph; } -std::unordered_map computeIndegree( - std::unordered_map>& graph) { - std::unordered_map degrees; - - for (auto g_it = graph.begin(); g_it != graph.end(); g_it++) { - for (int neigh : g_it->second) { - auto n_it = degrees.find(neigh); - if (n_it != degrees.end()) { - n_it->second++; - } else { - degrees.insert({neigh, 0}); - } +std::unordered_map computeIndegree(std::unordered_map> &graph) +{ + std::unordered_map degrees; + + for (auto g_it = graph.begin(); g_it != graph.end(); g_it++) + { + for (int neigh : g_it->second) + { + auto n_it = degrees.find(neigh); + if (n_it != degrees.end()) + { + n_it->second++; + } + else + { + degrees.insert({neigh, 0}); + } + } } - } - return degrees; + return degrees; } -std::vector findTablePrecedence(int tables, - std::vector> preReq, - TablesInfo* tables_info) { - std::unordered_map> graph = createGraph(preReq); - std::unordered_map degrees = computeIndegree(graph); - std::vector visited; - std::vector toposort; - std::queue zeros; - - // initialize queue with tables having no dependencies - for (auto table_it = tables_info->m_tableInfoMap.begin(); - table_it != tables_info->m_tableInfoMap.end(); table_it++) { - TableInfo table_info = table_it->second; - if (degrees.find(table_info.id) == degrees.end()) { - zeros.push(table_info.id); - visited.push_back(table_info.id); - } - } - - for (int i = 0; i < tables; i++) { - // Err input data like possible cyclic dependencies, could not build - // precedence order - if (zeros.empty()) { - SWSS_LOG_ERROR("Filed to build table precedence order"); - return {}; +std::vector findTablePrecedence(int tables, std::vector> preReq, TablesInfo *tables_info) +{ + std::unordered_map> graph = createGraph(preReq); + std::unordered_map degrees = computeIndegree(graph); + std::vector visited; + std::vector toposort; + std::queue zeros; + + // initialize queue with tables having no dependencies + for (auto table_it = tables_info->m_tableInfoMap.begin(); table_it != tables_info->m_tableInfoMap.end(); table_it++) + { + TableInfo table_info = table_it->second; + if (degrees.find(table_info.id) == degrees.end()) + { + zeros.push(table_info.id); + visited.push_back(table_info.id); + } } - // Run BFS - int zero = zeros.front(); - zeros.pop(); - toposort.push_back(zero); - auto g_it = graph.find(zero); - if (g_it != graph.end()) { - for (int neigh : g_it->second) { - auto n_it = degrees.find(neigh); - if (n_it != degrees.end()) { - if (!n_it->second) { - if (std::find(visited.begin(), visited.end(), neigh) == - visited.end()) { - zeros.push(neigh); - visited.push_back(neigh); + for (int i = 0; i < tables; i++) + { + // Err input data like possible cyclic dependencies, could not build + // precedence order + if (zeros.empty()) + { + SWSS_LOG_ERROR("Filed to build table precedence order"); + return {}; + } + + // Run BFS + int zero = zeros.front(); + zeros.pop(); + toposort.push_back(zero); + auto g_it = graph.find(zero); + if (g_it != graph.end()) + { + for (int neigh : g_it->second) + { + auto n_it = degrees.find(neigh); + if (n_it != degrees.end()) + { + if (!n_it->second) + { + if (std::find(visited.begin(), visited.end(), neigh) == visited.end()) + { + zeros.push(neigh); + visited.push_back(neigh); + } + } + else + { + n_it->second--; + } + } } - } else { - n_it->second--; - } } - } } - } - return toposort; + return toposort; } -void buildTablePrecedence(TablesInfo* tables_info) { - std::vector> preReq; - std::vector orderedTables; - int tables = 0; +void buildTablePrecedence(TablesInfo *tables_info) +{ + std::vector> preReq; + std::vector orderedTables; + int tables = 0; - if (!tables_info) { - return; - } - - // build dependencies - for (auto table_it = tables_info->m_tableInfoMap.begin(); - table_it != tables_info->m_tableInfoMap.end(); table_it++) { - TableInfo table_info = table_it->second; - tables++; - - for (std::size_t i = 0; i < table_info.action_ref_tables.size(); i++) { - /** - * For now processing precedence order is only amongst extension tables - * Skip fixed tables, include them in precedence calculations when fixed - * and extension tables processing precedence may be interleaved - */ - if (FixedTablesMap.find(table_info.action_ref_tables[i]) != - FixedTablesMap.end()) { - continue; - } - - TableInfo ref_table_info = - tables_info->m_tableInfoMap[table_info.action_ref_tables[i]]; - if (std::find(preReq.begin(), preReq.end(), - std::make_pair(table_info.id, ref_table_info.id)) == - preReq.end()) { - preReq.push_back(std::make_pair(table_info.id, ref_table_info.id)); - } - } - } - - // find precedence of tables based on dependencies - orderedTables = findTablePrecedence(tables, preReq, tables_info); - - // update each table with calculated precedence value and build table - // precedence map - for (std::size_t i = 0; i < orderedTables.size(); i++) { - auto table_id = orderedTables[i]; - auto id_it = tables_info->m_tableIdNameMap.find(std::to_string(table_id)); - if (id_it == tables_info->m_tableIdNameMap.end()) { - continue; + if (!tables_info) + { + return; } - auto table_it = tables_info->m_tableInfoMap.find(id_it->second); - if (table_it == tables_info->m_tableInfoMap.end()) { - continue; + // build dependencies + for (auto table_it = tables_info->m_tableInfoMap.begin(); table_it != tables_info->m_tableInfoMap.end(); table_it++) + { + TableInfo table_info = table_it->second; + tables++; + + for (std::size_t i = 0; i < table_info.action_ref_tables.size(); i++) + { + /** + * For now processing precedence order is only amongst extension tables + * Skip fixed tables, include them in precedence calculations when fixed + * and extension tables processing precedence may be interleaved + */ + if (FixedTablesMap.find(table_info.action_ref_tables[i]) != FixedTablesMap.end()) + { + continue; + } + + TableInfo ref_table_info = tables_info->m_tableInfoMap[table_info.action_ref_tables[i]]; + if (std::find(preReq.begin(), preReq.end(), std::make_pair(table_info.id, ref_table_info.id)) == + preReq.end()) + { + preReq.push_back(std::make_pair(table_info.id, ref_table_info.id)); + } + } } - table_it->second.precedence = (int)i; - tables_info->m_tablePrecedenceMap[(int)i] = table_it->second.name; - } + // find precedence of tables based on dependencies + orderedTables = findTablePrecedence(tables, preReq, tables_info); + + // update each table with calculated precedence value and build table + // precedence map + for (std::size_t i = 0; i < orderedTables.size(); i++) + { + auto table_id = orderedTables[i]; + auto id_it = tables_info->m_tableIdNameMap.find(std::to_string(table_id)); + if (id_it == tables_info->m_tableIdNameMap.end()) + { + continue; + } - return; -} + auto table_it = tables_info->m_tableInfoMap.find(id_it->second); + if (table_it == tables_info->m_tableInfoMap.end()) + { + continue; + } -void TablesDefnManager::enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) { - m_entries.push_back(entry); + table_it->second.precedence = (int)i; + tables_info->m_tablePrecedenceMap[(int)i] = table_it->second.name; + } + + return; } -void TablesDefnManager::drain() { - SWSS_LOG_ENTER(); +void TablesDefnManager::enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) +{ + m_entries.push_back(entry); +} - for (const auto& key_op_fvs_tuple : m_entries) { - std::string table_name; - std::string key; - parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &key); - const std::vector& attributes = - kfvFieldsValues(key_op_fvs_tuple); +void TablesDefnManager::drain() +{ + SWSS_LOG_ENTER(); + + for (const auto &key_op_fvs_tuple : m_entries) + { + std::string table_name; + std::string key; + parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &key); + const std::vector &attributes = kfvFieldsValues(key_op_fvs_tuple); + + ReturnCode status; + auto app_db_entry_or = deserializeTablesInfoEntry(key, attributes); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", + QuotedVar(table_name + ":" + key).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + auto &app_db_entry = *app_db_entry_or; + + status = validateTablesInfoAppDbEntry(app_db_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Validation failed for tables definition APP DB entry with key %s: " + "%s", + QuotedVar(table_name + ":" + key).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } - ReturnCode status; - auto app_db_entry_or = deserializeTablesInfoEntry(key, attributes); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - SWSS_LOG_ERROR("Unable to deserialize APP DB entry with key %s: %s", - QuotedVar(table_name + ":" + key).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - auto& app_db_entry = *app_db_entry_or; - - status = validateTablesInfoAppDbEntry(app_db_entry); - if (!status.ok()) { - SWSS_LOG_ERROR( - "Validation failed for tables definition APP DB entry with key %s: " - "%s", - QuotedVar(table_name + ":" + key).c_str(), status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } + const std::string context_key = KeyGenerator::generateTablesInfoKey(app_db_entry.context); - const std::string context_key = - KeyGenerator::generateTablesInfoKey(app_db_entry.context); - - const std::string& operation = kfvOp(key_op_fvs_tuple); - if (operation == SET_COMMAND) { - auto* tablesinfo = getTablesInfoEntry(context_key); - if (tablesinfo == nullptr) { - // Create TablesInfo - status = processAddRequest(app_db_entry, context_key); - } else { - // Modify existing TablesInfo - status = processUpdateRequest(app_db_entry, context_key); - } - } else if (operation == DEL_COMMAND) { - // Delete TablesInfo - status = processDeleteRequest(context_key); - } else { - status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown operation type " << QuotedVar(operation); - SWSS_LOG_ERROR("%s", status.message().c_str()); - } - if (!status.ok()) { - SWSS_LOG_ERROR( - "Processing failed for tables definition APP DB entry with key %s: " - "%s", - QuotedVar(table_name + ":" + key).c_str(), status.message().c_str()); - } else { - buildTablePrecedence(gP4Orch->tablesinfo); + const std::string &operation = kfvOp(key_op_fvs_tuple); + if (operation == SET_COMMAND) + { + auto *tablesinfo = getTablesInfoEntry(context_key); + if (tablesinfo == nullptr) + { + // Create TablesInfo + status = processAddRequest(app_db_entry, context_key); + } + else + { + // Modify existing TablesInfo + status = processUpdateRequest(app_db_entry, context_key); + } + } + else if (operation == DEL_COMMAND) + { + // Delete TablesInfo + status = processDeleteRequest(context_key); + } + else + { + status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Unknown operation type " << QuotedVar(operation); + SWSS_LOG_ERROR("%s", status.message().c_str()); + } + if (!status.ok()) + { + SWSS_LOG_ERROR("Processing failed for tables definition APP DB entry with key %s: " + "%s", + QuotedVar(table_name + ":" + key).c_str(), status.message().c_str()); + } + else + { + buildTablePrecedence(gP4Orch->tablesinfo); + } + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), status, + /*replace=*/true); } - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - } - m_entries.clear(); + m_entries.clear(); } -std::string TablesDefnManager::verifyState( - const std::string& key, const std::vector& tuple) { - std::string result = ""; - SWSS_LOG_ENTER(); +std::string TablesDefnManager::verifyState(const std::string &key, const std::vector &tuple) +{ + std::string result = ""; + SWSS_LOG_ENTER(); - return result; + return result; } diff --git a/orchagent/p4orch/tables_definition_manager.h b/orchagent/p4orch/tables_definition_manager.h index 789b35ca7f7..85ca363bf53 100644 --- a/orchagent/p4orch/tables_definition_manager.h +++ b/orchagent/p4orch/tables_definition_manager.h @@ -13,23 +13,27 @@ #include "p4orch/p4orch_util.h" #include "response_publisher_interface.h" #include "return_code.h" -extern "C" { +extern "C" +{ #include "sai.h" } /** * A set of tables definition */ -struct TablesInfo { - std::string context; - nlohmann::json info; - std::unordered_map m_tableIdNameMap; - std::unordered_map m_tableInfoMap; - std::map m_tablePrecedenceMap; +struct TablesInfo +{ + std::string context; + nlohmann::json info; + std::unordered_map m_tableIdNameMap; + std::unordered_map m_tableInfoMap; + std::map m_tablePrecedenceMap; - TablesInfo() {}; - TablesInfo(const std::string& context_key, const nlohmann::json& info_value) - : context(context_key), info(info_value) {} + TablesInfo() {}; + TablesInfo(const std::string &context_key, const nlohmann::json &info_value) + : context(context_key), info(info_value) + { + } }; /** @@ -38,45 +42,38 @@ struct TablesInfo { */ typedef std::unordered_map TablesInfoMap; -class TablesDefnManager : public ObjectManagerInterface { - public: - TablesDefnManager(P4OidMapper* p4oidMapper, - ResponsePublisherInterface* publisher) { - SWSS_LOG_ENTER(); +class TablesDefnManager : public ObjectManagerInterface +{ + public: + TablesDefnManager(P4OidMapper *p4oidMapper, ResponsePublisherInterface *publisher) + { + SWSS_LOG_ENTER(); - assert(p4oidMapper != nullptr); - m_p4OidMapper = p4oidMapper; - assert(publisher != nullptr); - m_publisher = publisher; - } - virtual ~TablesDefnManager() = default; + assert(p4oidMapper != nullptr); + m_p4OidMapper = p4oidMapper; + assert(publisher != nullptr); + m_publisher = publisher; + } + virtual ~TablesDefnManager() = default; - void enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) override; - void drain() override; - std::string verifyState( - const std::string& key, - const std::vector& tuple) override; - ReturnCode getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) override; + void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; + void drain() override; + std::string verifyState(const std::string &key, const std::vector &tuple) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; - private: - ReturnCodeOr deserializeTablesInfoEntry( - const std::string& key, - const std::vector& attributes); - TablesInfo* getTablesInfoEntry(const std::string& context_key); - ReturnCode createTablesInfo(const std::string& context_key, - TablesInfo& tablesinfo_entry); - ReturnCode removeTablesInfo(const std::string& context_key); - ReturnCode processAddRequest(const TablesInfoAppDbEntry& app_db_entry, - const std::string& context_key); - ReturnCode processUpdateRequest(const TablesInfoAppDbEntry& app_db_entry, - const std::string& context_key); - ReturnCode processDeleteRequest(const std::string& context_key); + private: + ReturnCodeOr deserializeTablesInfoEntry(const std::string &key, + const std::vector &attributes); + TablesInfo *getTablesInfoEntry(const std::string &context_key); + ReturnCode createTablesInfo(const std::string &context_key, TablesInfo &tablesinfo_entry); + ReturnCode removeTablesInfo(const std::string &context_key); + ReturnCode processAddRequest(const TablesInfoAppDbEntry &app_db_entry, const std::string &context_key); + ReturnCode processUpdateRequest(const TablesInfoAppDbEntry &app_db_entry, const std::string &context_key); + ReturnCode processDeleteRequest(const std::string &context_key); - TablesInfoMap m_tablesinfoMap; - P4OidMapper* m_p4OidMapper; - ResponsePublisherInterface* m_publisher; - std::deque m_entries; + TablesInfoMap m_tablesinfoMap; + P4OidMapper *m_p4OidMapper; + ResponsePublisherInterface *m_publisher; + std::deque m_entries; }; diff --git a/orchagent/p4orch/tests/acl_manager_test.cpp b/orchagent/p4orch/tests/acl_manager_test.cpp index 34b4526cbe8..107dfdfde5b 100644 --- a/orchagent/p4orch/tests/acl_manager_test.cpp +++ b/orchagent/p4orch/tests/acl_manager_test.cpp @@ -25,33 +25,35 @@ using ::p4orch::kTableKeyDelimiter; -extern swss::DBConnector* gAppDb; -extern swss::DBConnector* gStateDb; -extern swss::DBConnector* gCountersDb; -extern swss::DBConnector* gConfigDb; -extern sai_acl_api_t* sai_acl_api; -extern sai_policer_api_t* sai_policer_api; -extern sai_hostif_api_t* sai_hostif_api; -extern sai_switch_api_t* sai_switch_api; -extern sai_udf_api_t* sai_udf_api; +extern swss::DBConnector *gAppDb; +extern swss::DBConnector *gStateDb; +extern swss::DBConnector *gCountersDb; +extern swss::DBConnector *gConfigDb; +extern sai_acl_api_t *sai_acl_api; +extern sai_policer_api_t *sai_policer_api; +extern sai_hostif_api_t *sai_hostif_api; +extern sai_switch_api_t *sai_switch_api; +extern sai_udf_api_t *sai_udf_api; extern int gBatchSize; -extern VRFOrch* gVrfOrch; -extern P4Orch* gP4Orch; -extern SwitchOrch* gSwitchOrch; +extern VRFOrch *gVrfOrch; +extern P4Orch *gP4Orch; +extern SwitchOrch *gSwitchOrch; extern sai_object_id_t gSwitchId; extern sai_object_id_t gVrfOid; extern sai_object_id_t gTrapGroupStartOid; extern sai_object_id_t gHostifStartOid; extern sai_object_id_t gUserDefinedTrapStartOid; -extern char* gVrfName; -extern char* gMirrorSession1; +extern char *gVrfName; +extern char *gMirrorSession1; extern sai_object_id_t kMirrorSessionOid1; -extern char* gMirrorSession2; +extern char *gMirrorSession2; extern sai_object_id_t kMirrorSessionOid2; extern bool gIsNatSupported; -namespace p4orch { -namespace test { +namespace p4orch +{ +namespace test +{ using ::testing::_; using ::testing::DoAll; @@ -64,7 +66,8 @@ using ::testing::SetArgPointee; using ::testing::StrictMock; using ::testing::Truly; -namespace { +namespace +{ constexpr sai_object_id_t kAclGroupIngressOid = 0xb00000000058f; constexpr sai_object_id_t kAclGroupEgressOid = 0xb000000000591; constexpr sai_object_id_t kAclGroupLookupOid = 0xb000000000592; @@ -78,6680 +81,5218 @@ constexpr sai_object_id_t kAclCounterOid1 = 3001; constexpr sai_object_id_t kUdfGroupOid1 = 4001; constexpr sai_object_id_t kUdfMatchOid1 = 5001; constexpr sai_object_id_t kUdfOid1 = 6001; -constexpr char* kAclIngressTableName = "ACL_PUNT_TABLE"; +constexpr char *kAclIngressTableName = "ACL_PUNT_TABLE"; // Matches the policer sai_attribute_t[] argument. -bool MatchSaiPolicerAttribute( - const int attrs_size, const sai_meter_type_t expected_type, - const sai_packet_action_t expected_gpa, - const sai_packet_action_t expected_ypa, - const sai_packet_action_t expected_rpa, const sai_uint64_t expected_cir, - const sai_uint64_t expected_pir, const sai_uint64_t expected_cbs, - const sai_uint64_t expected_pbs, const sai_attribute_t* attr_list) { - if (attr_list == nullptr) { - return false; - } - for (int i = 0; i < attrs_size; ++i) { - switch (attr_list[i].id) { - case SAI_POLICER_ATTR_CBS: - if (attr_list[i].value.u64 != expected_cbs) { - return false; - } - break; - case SAI_POLICER_ATTR_PBS: - if (attr_list[i].value.u64 != expected_pbs) { - return false; - } - break; - case SAI_POLICER_ATTR_CIR: - if (attr_list[i].value.u64 != expected_cir) { - return false; - } - break; - case SAI_POLICER_ATTR_PIR: - if (attr_list[i].value.u64 != expected_pir) { - return false; - } - break; - case SAI_POLICER_ATTR_GREEN_PACKET_ACTION: - if (attr_list[i].value.s32 != expected_gpa) { - return false; - } - break; - case SAI_POLICER_ATTR_YELLOW_PACKET_ACTION: - if (attr_list[i].value.s32 != expected_ypa) { - return false; - } - break; - case SAI_POLICER_ATTR_RED_PACKET_ACTION: - if (attr_list[i].value.s32 != expected_rpa) { - return false; - } - break; - case SAI_POLICER_ATTR_MODE: - if (attr_list[i].value.s32 != SAI_POLICER_MODE_TR_TCM) { - return false; - } - break; - case SAI_POLICER_ATTR_METER_TYPE: - if (attr_list[i].value.s32 != expected_type) { - return false; +bool MatchSaiPolicerAttribute(const int attrs_size, const sai_meter_type_t expected_type, + const sai_packet_action_t expected_gpa, const sai_packet_action_t expected_ypa, + const sai_packet_action_t expected_rpa, const sai_uint64_t expected_cir, + const sai_uint64_t expected_pir, const sai_uint64_t expected_cbs, + const sai_uint64_t expected_pbs, const sai_attribute_t *attr_list) +{ + if (attr_list == nullptr) + { + return false; + } + for (int i = 0; i < attrs_size; ++i) + { + switch (attr_list[i].id) + { + case SAI_POLICER_ATTR_CBS: + if (attr_list[i].value.u64 != expected_cbs) + { + return false; + } + break; + case SAI_POLICER_ATTR_PBS: + if (attr_list[i].value.u64 != expected_pbs) + { + return false; + } + break; + case SAI_POLICER_ATTR_CIR: + if (attr_list[i].value.u64 != expected_cir) + { + return false; + } + break; + case SAI_POLICER_ATTR_PIR: + if (attr_list[i].value.u64 != expected_pir) + { + return false; + } + break; + case SAI_POLICER_ATTR_GREEN_PACKET_ACTION: + if (attr_list[i].value.s32 != expected_gpa) + { + return false; + } + break; + case SAI_POLICER_ATTR_YELLOW_PACKET_ACTION: + if (attr_list[i].value.s32 != expected_ypa) + { + return false; + } + break; + case SAI_POLICER_ATTR_RED_PACKET_ACTION: + if (attr_list[i].value.s32 != expected_rpa) + { + return false; + } + break; + case SAI_POLICER_ATTR_MODE: + if (attr_list[i].value.s32 != SAI_POLICER_MODE_TR_TCM) + { + return false; + } + break; + case SAI_POLICER_ATTR_METER_TYPE: + if (attr_list[i].value.s32 != expected_type) + { + return false; + } + break; + default: + break; } - break; - default: - break; } - } - return true; + return true; } // Check the ACL stage sai_attribute_t list for ACL table group -bool MatchSaiAttributeAclGroupStage(const sai_acl_stage_t expected_stage, - const sai_attribute_t* attr_list) { - if (attr_list == nullptr) { - return false; - } - for (int i = 0; i < 3; ++i) { - switch (attr_list[i].id) { - case SAI_ACL_TABLE_GROUP_ATTR_ACL_STAGE: - if (attr_list[i].value.s32 != expected_stage) { - return false; - } - break; - case SAI_ACL_TABLE_GROUP_ATTR_TYPE: - if (attr_list[i].value.s32 != SAI_ACL_TABLE_GROUP_TYPE_PARALLEL) { - return false; - } - break; - case SAI_ACL_TABLE_ATTR_ACL_BIND_POINT_TYPE_LIST: - if (attr_list[i].value.s32list.count != 1 || - attr_list[i].value.s32list.list[0] != - SAI_ACL_BIND_POINT_TYPE_SWITCH) { - return false; - } - break; - default: +bool MatchSaiAttributeAclGroupStage(const sai_acl_stage_t expected_stage, const sai_attribute_t *attr_list) +{ + if (attr_list == nullptr) + { return false; } - } - return true; + for (int i = 0; i < 3; ++i) + { + switch (attr_list[i].id) + { + case SAI_ACL_TABLE_GROUP_ATTR_ACL_STAGE: + if (attr_list[i].value.s32 != expected_stage) + { + return false; + } + break; + case SAI_ACL_TABLE_GROUP_ATTR_TYPE: + if (attr_list[i].value.s32 != SAI_ACL_TABLE_GROUP_TYPE_PARALLEL) + { + return false; + } + break; + case SAI_ACL_TABLE_ATTR_ACL_BIND_POINT_TYPE_LIST: + if (attr_list[i].value.s32list.count != 1 || + attr_list[i].value.s32list.list[0] != SAI_ACL_BIND_POINT_TYPE_SWITCH) + { + return false; + } + break; + default: + return false; + } + } + return true; } // Check the ACL stage sai_attribute_t list for ACL table -bool MatchSaiAttributeAclTableStage(const sai_acl_stage_t expected_stage, - const sai_attribute_t* attr_list) { - if (attr_list == nullptr) { - return false; - } - if (attr_list[0].id != SAI_ACL_TABLE_GROUP_ATTR_ACL_STAGE || - attr_list[0].value.s32 != expected_stage) { - return false; - } - - return true; +bool MatchSaiAttributeAclTableStage(const sai_acl_stage_t expected_stage, const sai_attribute_t *attr_list) +{ + if (attr_list == nullptr) + { + return false; + } + if (attr_list[0].id != SAI_ACL_TABLE_GROUP_ATTR_ACL_STAGE || attr_list[0].value.s32 != expected_stage) + { + return false; + } + + return true; } -bool MatchSaiSwitchAttrByAclStage(const sai_switch_attr_t expected_switch_attr, - const sai_object_id_t group_oid, - const sai_attribute_t* attr) { - if (attr->id != expected_switch_attr || attr->value.oid != group_oid) { - return false; - } - return true; +bool MatchSaiSwitchAttrByAclStage(const sai_switch_attr_t expected_switch_attr, const sai_object_id_t group_oid, + const sai_attribute_t *attr) +{ + if (attr->id != expected_switch_attr || attr->value.oid != group_oid) + { + return false; + } + return true; } -std::string BuildMatchFieldJsonStrKindSaiField( - std::string sai_field, std::string format = P4_FORMAT_HEX_STRING, - uint32_t bitwidth = 0) { - nlohmann::json match_json; - match_json[kAclMatchFieldKind] = kAclMatchFieldSaiField; - match_json[kAclMatchFieldSaiField] = sai_field; - match_json[kAclMatchFieldFormat] = format; - if (format != P4_FORMAT_STRING) { - match_json[kAclMatchFieldBitwidth] = bitwidth; - } - return match_json.dump(); +std::string BuildMatchFieldJsonStrKindSaiField(std::string sai_field, std::string format = P4_FORMAT_HEX_STRING, + uint32_t bitwidth = 0) +{ + nlohmann::json match_json; + match_json[kAclMatchFieldKind] = kAclMatchFieldSaiField; + match_json[kAclMatchFieldSaiField] = sai_field; + match_json[kAclMatchFieldFormat] = format; + if (format != P4_FORMAT_STRING) + { + match_json[kAclMatchFieldBitwidth] = bitwidth; + } + return match_json.dump(); } -std::string BuildMatchFieldJsonStrKindComposite( - std::vector elements, - std::string format = P4_FORMAT_HEX_STRING, uint32_t bitwidth = 0) { - nlohmann::json match_json; - match_json[kAclMatchFieldKind] = kAclMatchFieldKindComposite; - for (const auto element : elements) { - match_json[kAclMatchFieldElements].push_back(element); - } - match_json[kAclMatchFieldFormat] = format; - match_json[kAclMatchFieldBitwidth] = bitwidth; - return match_json.dump(); +std::string BuildMatchFieldJsonStrKindComposite(std::vector elements, + std::string format = P4_FORMAT_HEX_STRING, uint32_t bitwidth = 0) +{ + nlohmann::json match_json; + match_json[kAclMatchFieldKind] = kAclMatchFieldKindComposite; + for (const auto element : elements) + { + match_json[kAclMatchFieldElements].push_back(element); + } + match_json[kAclMatchFieldFormat] = format; + match_json[kAclMatchFieldBitwidth] = bitwidth; + return match_json.dump(); } -std::string BuildMatchFieldJsonStrKindUdf( - std::string base, uint32_t offset, - std::string format = P4_FORMAT_HEX_STRING, uint32_t bitwidth = 0) { - nlohmann::json match_json; - match_json[kAclMatchFieldKind] = kAclMatchFieldKindUdf; - match_json[kAclUdfBase] = base; - match_json[kAclUdfOffset] = offset; - match_json[kAclMatchFieldFormat] = format; - match_json[kAclMatchFieldBitwidth] = bitwidth; - return match_json.dump(); +std::string BuildMatchFieldJsonStrKindUdf(std::string base, uint32_t offset, std::string format = P4_FORMAT_HEX_STRING, + uint32_t bitwidth = 0) +{ + nlohmann::json match_json; + match_json[kAclMatchFieldKind] = kAclMatchFieldKindUdf; + match_json[kAclUdfBase] = base; + match_json[kAclUdfOffset] = offset; + match_json[kAclMatchFieldFormat] = format; + match_json[kAclMatchFieldBitwidth] = bitwidth; + return match_json.dump(); } // Check if P4AclTableDefinitionAppDbEntry to P4AclTableDefinition mapping is as // expected -void IsExpectedAclTableDefinitionMapping( - const P4AclTableDefinition& acl_table_def, - const P4AclTableDefinitionAppDbEntry& app_db_entry) { - EXPECT_EQ(app_db_entry.acl_table_name, acl_table_def.acl_table_name); - EXPECT_EQ(app_db_entry.priority, acl_table_def.priority); - EXPECT_EQ(app_db_entry.size, acl_table_def.size); - EXPECT_EQ(app_db_entry.meter_unit, acl_table_def.meter_unit); - EXPECT_EQ(app_db_entry.counter_unit, acl_table_def.counter_unit); - for (const auto& raw_match_field : app_db_entry.match_field_lookup) { - const auto& p4_match = fvField(raw_match_field); - const auto& aggr_match_str = fvValue(raw_match_field); - try { - auto aggr_match_json = nlohmann::json::parse(aggr_match_str); - ASSERT_TRUE(aggr_match_json.is_object()); - auto kind = aggr_match_json[kAclMatchFieldKind]; - ASSERT_TRUE(!kind.is_null() && kind.is_string()); - if (kind == kAclMatchFieldKindComposite) { - auto format_str = aggr_match_json[kAclMatchFieldFormat]; - ASSERT_FALSE(format_str.is_null() || !format_str.is_string()); - auto format_it = formatLookup.find(format_str); - ASSERT_NE(formatLookup.end(), format_it); - if (format_it->second != Format::STRING) { - // bitwidth is required if the format is not "STRING" - auto bitwidth = aggr_match_json[kAclMatchFieldBitwidth]; - ASSERT_FALSE(bitwidth.is_null() || !bitwidth.is_number()); +void IsExpectedAclTableDefinitionMapping(const P4AclTableDefinition &acl_table_def, + const P4AclTableDefinitionAppDbEntry &app_db_entry) +{ + EXPECT_EQ(app_db_entry.acl_table_name, acl_table_def.acl_table_name); + EXPECT_EQ(app_db_entry.priority, acl_table_def.priority); + EXPECT_EQ(app_db_entry.size, acl_table_def.size); + EXPECT_EQ(app_db_entry.meter_unit, acl_table_def.meter_unit); + EXPECT_EQ(app_db_entry.counter_unit, acl_table_def.counter_unit); + for (const auto &raw_match_field : app_db_entry.match_field_lookup) + { + const auto &p4_match = fvField(raw_match_field); + const auto &aggr_match_str = fvValue(raw_match_field); + try + { + auto aggr_match_json = nlohmann::json::parse(aggr_match_str); + ASSERT_TRUE(aggr_match_json.is_object()); + auto kind = aggr_match_json[kAclMatchFieldKind]; + ASSERT_TRUE(!kind.is_null() && kind.is_string()); + if (kind == kAclMatchFieldKindComposite) + { + auto format_str = aggr_match_json[kAclMatchFieldFormat]; + ASSERT_FALSE(format_str.is_null() || !format_str.is_string()); + auto format_it = formatLookup.find(format_str); + ASSERT_NE(formatLookup.end(), format_it); + if (format_it->second != Format::STRING) + { + // bitwidth is required if the format is not "STRING" + auto bitwidth = aggr_match_json[kAclMatchFieldBitwidth]; + ASSERT_FALSE(bitwidth.is_null() || !bitwidth.is_number()); + } + auto elements = aggr_match_json[kAclMatchFieldElements]; + ASSERT_TRUE(!elements.is_null() && elements.is_array()); + if (elements[0][kAclMatchFieldKind] == kAclMatchFieldSaiField) + { + const auto &composite_sai_match_it = acl_table_def.composite_sai_match_fields_lookup.find(p4_match); + ASSERT_NE(acl_table_def.composite_sai_match_fields_lookup.end(), composite_sai_match_it); + for (const auto &element : composite_sai_match_it->second) + { + EXPECT_EQ(BYTE_BITWIDTH * IPV6_SINGLE_WORD_BYTES_LENGTH, element.bitwidth); + } + } + else if (elements[0][kAclMatchFieldKind] == kAclMatchFieldKindUdf) + { + const auto &composite_udf_match_it = acl_table_def.udf_fields_lookup.find(p4_match); + ASSERT_NE(acl_table_def.udf_fields_lookup.end(), composite_udf_match_it); + for (size_t i = 0; i < composite_udf_match_it->second.size(); i++) + { + EXPECT_EQ(elements[i][kAclMatchFieldBitwidth], + composite_udf_match_it->second[i].length * BYTE_BITWIDTH); + EXPECT_EQ(elements[i][kAclUdfOffset], composite_udf_match_it->second[i].offset); + EXPECT_EQ(app_db_entry.acl_table_name + "-" + p4_match + "-" + std::to_string(i), + composite_udf_match_it->second[i].group_id); + ASSERT_NE(udfBaseLookup.end(), udfBaseLookup.find(elements[i][kAclUdfBase])); + EXPECT_EQ(udfBaseLookup.find(elements[i][kAclUdfBase])->second, + composite_udf_match_it->second[i].base); + } + } + else + { + FAIL() << "Invalid kind for composite field element: " << elements[0][kAclMatchFieldKind]; + } + } + else if (kind == kAclMatchFieldKindUdf) + { + const auto &udf_match_it = acl_table_def.udf_fields_lookup.find(p4_match); + ASSERT_NE(acl_table_def.udf_fields_lookup.end(), udf_match_it); + EXPECT_EQ(1, udf_match_it->second.size()); + EXPECT_EQ(aggr_match_json[kAclMatchFieldBitwidth], udf_match_it->second[0].length * BYTE_BITWIDTH); + EXPECT_EQ(aggr_match_json[kAclUdfOffset], udf_match_it->second[0].offset); + EXPECT_EQ(app_db_entry.acl_table_name + "-" + p4_match + "-0", udf_match_it->second[0].group_id); + ASSERT_NE(udfBaseLookup.end(), udfBaseLookup.find(aggr_match_json[kAclUdfBase])); + EXPECT_EQ(udfBaseLookup.find(aggr_match_json[kAclUdfBase])->second, udf_match_it->second[0].base); + } + else + { + EXPECT_EQ(kAclMatchFieldSaiField, kind); + auto match_field = aggr_match_json[kAclMatchFieldSaiField]; + ASSERT_TRUE(!match_field.is_null() && match_field.is_string()); + auto field_suffix = swss::tokenize(match_field, kFieldDelimiter); + const auto &sai_field = field_suffix[0]; + ASSERT_NE(aclMatchEntryAttrLookup.end(), aclMatchEntryAttrLookup.find(sai_field)); + ASSERT_NE(aclMatchTableAttrLookup.end(), aclMatchTableAttrLookup.find(sai_field)); + EXPECT_EQ(aclMatchEntryAttrLookup.find(sai_field)->second, + acl_table_def.sai_match_field_lookup.find(p4_match)->second.entry_attr); + EXPECT_EQ(aclMatchTableAttrLookup.find(sai_field)->second, + acl_table_def.sai_match_field_lookup.find(p4_match)->second.table_attr); + } } - auto elements = aggr_match_json[kAclMatchFieldElements]; - ASSERT_TRUE(!elements.is_null() && elements.is_array()); - if (elements[0][kAclMatchFieldKind] == kAclMatchFieldSaiField) { - const auto& composite_sai_match_it = - acl_table_def.composite_sai_match_fields_lookup.find(p4_match); - ASSERT_NE(acl_table_def.composite_sai_match_fields_lookup.end(), - composite_sai_match_it); - for (const auto& element : composite_sai_match_it->second) { - EXPECT_EQ(BYTE_BITWIDTH * IPV6_SINGLE_WORD_BYTES_LENGTH, - element.bitwidth); - } - } else if (elements[0][kAclMatchFieldKind] == kAclMatchFieldKindUdf) { - const auto& composite_udf_match_it = - acl_table_def.udf_fields_lookup.find(p4_match); - ASSERT_NE(acl_table_def.udf_fields_lookup.end(), - composite_udf_match_it); - for (size_t i = 0; i < composite_udf_match_it->second.size(); i++) { - EXPECT_EQ(elements[i][kAclMatchFieldBitwidth], - composite_udf_match_it->second[i].length * BYTE_BITWIDTH); - EXPECT_EQ(elements[i][kAclUdfOffset], - composite_udf_match_it->second[i].offset); - EXPECT_EQ(app_db_entry.acl_table_name + "-" + p4_match + "-" + - std::to_string(i), - composite_udf_match_it->second[i].group_id); - ASSERT_NE(udfBaseLookup.end(), - udfBaseLookup.find(elements[i][kAclUdfBase])); - EXPECT_EQ(udfBaseLookup.find(elements[i][kAclUdfBase])->second, - composite_udf_match_it->second[i].base); - } - } else { - FAIL() << "Invalid kind for composite field element: " - << elements[0][kAclMatchFieldKind]; + catch (std::exception &ex) + { + FAIL() << "Exception when parsing match field. ex: " << ex.what(); } - } else if (kind == kAclMatchFieldKindUdf) { - const auto& udf_match_it = - acl_table_def.udf_fields_lookup.find(p4_match); - ASSERT_NE(acl_table_def.udf_fields_lookup.end(), udf_match_it); - EXPECT_EQ(1, udf_match_it->second.size()); - EXPECT_EQ(aggr_match_json[kAclMatchFieldBitwidth], - udf_match_it->second[0].length * BYTE_BITWIDTH); - EXPECT_EQ(aggr_match_json[kAclUdfOffset], - udf_match_it->second[0].offset); - EXPECT_EQ(app_db_entry.acl_table_name + "-" + p4_match + "-0", - udf_match_it->second[0].group_id); - ASSERT_NE(udfBaseLookup.end(), - udfBaseLookup.find(aggr_match_json[kAclUdfBase])); - EXPECT_EQ(udfBaseLookup.find(aggr_match_json[kAclUdfBase])->second, - udf_match_it->second[0].base); - } else { - EXPECT_EQ(kAclMatchFieldSaiField, kind); - auto match_field = aggr_match_json[kAclMatchFieldSaiField]; - ASSERT_TRUE(!match_field.is_null() && match_field.is_string()); - auto field_suffix = swss::tokenize(match_field, kFieldDelimiter); - const auto& sai_field = field_suffix[0]; - ASSERT_NE(aclMatchEntryAttrLookup.end(), - aclMatchEntryAttrLookup.find(sai_field)); - ASSERT_NE(aclMatchTableAttrLookup.end(), - aclMatchTableAttrLookup.find(sai_field)); - EXPECT_EQ(aclMatchEntryAttrLookup.find(sai_field)->second, - acl_table_def.sai_match_field_lookup.find(p4_match) - ->second.entry_attr); - EXPECT_EQ(aclMatchTableAttrLookup.find(sai_field)->second, - acl_table_def.sai_match_field_lookup.find(p4_match) - ->second.table_attr); - } - } catch (std::exception& ex) { - FAIL() << "Exception when parsing match field. ex: " << ex.what(); } - } - for (const auto& action_field : app_db_entry.action_field_lookup) { - const auto& sai_action_param_it = - acl_table_def.rule_action_field_lookup.find(fvField(action_field)); - ASSERT_NE(acl_table_def.rule_action_field_lookup.end(), - sai_action_param_it); - - for (size_t i = 0; i < fvValue(action_field).size(); ++i) { - ASSERT_NE(aclActionLookup.end(), - aclActionLookup.find(fvValue(action_field)[i].sai_action)); - EXPECT_EQ( - sai_action_param_it->second[i].action, - aclActionLookup.find(fvValue(action_field)[i].sai_action)->second); + for (const auto &action_field : app_db_entry.action_field_lookup) + { + const auto &sai_action_param_it = acl_table_def.rule_action_field_lookup.find(fvField(action_field)); + ASSERT_NE(acl_table_def.rule_action_field_lookup.end(), sai_action_param_it); + + for (size_t i = 0; i < fvValue(action_field).size(); ++i) + { + ASSERT_NE(aclActionLookup.end(), aclActionLookup.find(fvValue(action_field)[i].sai_action)); + EXPECT_EQ(sai_action_param_it->second[i].action, + aclActionLookup.find(fvValue(action_field)[i].sai_action)->second); + } } - } - - for (const auto& packet_action_color : - app_db_entry.packet_action_color_lookup) { - const auto& sai_action_color_it = - acl_table_def.rule_packet_action_color_lookup.find( - fvField(packet_action_color)); - ASSERT_NE(acl_table_def.rule_packet_action_color_lookup.end(), - sai_action_color_it); - for (size_t i = 0; i < fvValue(packet_action_color).size(); ++i) { - if (fvValue(packet_action_color)[i].packet_color.empty()) { - // Not a colored packet action, should be ACL entry attribute - // SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION instead of ACL policy - // attribute - const auto rule_action_it = acl_table_def.rule_action_field_lookup.find( - fvField(packet_action_color)); - ASSERT_NE(acl_table_def.rule_action_field_lookup.end(), rule_action_it); - bool found_packet_action = false; - for (const auto& action_with_param : rule_action_it->second) { - if (action_with_param.param_value == - fvValue(packet_action_color)[i].packet_action) { - // Only one packet action is allowed and no parameter should be - // added for SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION attribute. - // Return false if multiple packet actions are found or - // parameter name is not empty - EXPECT_FALSE(found_packet_action || - !action_with_param.param_name.empty()); - found_packet_action = true; - } + + for (const auto &packet_action_color : app_db_entry.packet_action_color_lookup) + { + const auto &sai_action_color_it = + acl_table_def.rule_packet_action_color_lookup.find(fvField(packet_action_color)); + ASSERT_NE(acl_table_def.rule_packet_action_color_lookup.end(), sai_action_color_it); + for (size_t i = 0; i < fvValue(packet_action_color).size(); ++i) + { + if (fvValue(packet_action_color)[i].packet_color.empty()) + { + // Not a colored packet action, should be ACL entry attribute + // SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION instead of ACL policy + // attribute + const auto rule_action_it = acl_table_def.rule_action_field_lookup.find(fvField(packet_action_color)); + ASSERT_NE(acl_table_def.rule_action_field_lookup.end(), rule_action_it); + bool found_packet_action = false; + for (const auto &action_with_param : rule_action_it->second) + { + if (action_with_param.param_value == fvValue(packet_action_color)[i].packet_action) + { + // Only one packet action is allowed and no parameter should be + // added for SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION attribute. + // Return false if multiple packet actions are found or + // parameter name is not empty + EXPECT_FALSE(found_packet_action || !action_with_param.param_name.empty()); + found_packet_action = true; + } + } + // No packet action was found, return false. + EXPECT_TRUE(found_packet_action); + continue; + } + const auto &packet_color_policer_attr_it = + aclPacketColorPolicerAttrLookup.find(fvValue(packet_action_color)[i].packet_color); + const auto &packet_action_it = aclPacketActionLookup.find(fvValue(packet_action_color)[i].packet_action); + ASSERT_NE(aclPacketColorPolicerAttrLookup.end(), packet_color_policer_attr_it); + ASSERT_NE(aclPacketActionLookup.end(), packet_action_it); + + const auto &sai_packet_action_it = sai_action_color_it->second.find(packet_color_policer_attr_it->second); + ASSERT_NE(sai_action_color_it->second.end(), sai_packet_action_it); + EXPECT_EQ(sai_packet_action_it->second, packet_action_it->second); } - // No packet action was found, return false. - EXPECT_TRUE(found_packet_action); - continue; - } - const auto& packet_color_policer_attr_it = - aclPacketColorPolicerAttrLookup.find( - fvValue(packet_action_color)[i].packet_color); - const auto& packet_action_it = aclPacketActionLookup.find( - fvValue(packet_action_color)[i].packet_action); - ASSERT_NE(aclPacketColorPolicerAttrLookup.end(), - packet_color_policer_attr_it); - ASSERT_NE(aclPacketActionLookup.end(), packet_action_it); - - const auto& sai_packet_action_it = sai_action_color_it->second.find( - packet_color_policer_attr_it->second); - ASSERT_NE(sai_action_color_it->second.end(), sai_packet_action_it); - EXPECT_EQ(sai_packet_action_it->second, packet_action_it->second); } - } } // Check if P4AclRuleAppDbEntry to P4AclRule field mapping is as // expected given table definition. Specific match and action value // validation should be done in caller method -void IsExpectedAclRuleMapping(const P4AclRule* acl_rule, - const P4AclRuleAppDbEntry& app_db_entry, - const P4AclTableDefinition& table_def) { - // Check table name and priority - EXPECT_EQ(app_db_entry.acl_table_name, acl_rule->acl_table_name); - EXPECT_EQ(app_db_entry.priority, acl_rule->priority); - // Check match field - for (const auto& app_db_match_fv : app_db_entry.match_fvs) { - // TODO: Fake UDF field until SAI supports it - if (table_def.udf_fields_lookup.find(fvField(app_db_match_fv)) != - table_def.udf_fields_lookup.end()) - continue; - const auto& composite_sai_match_fields_it = - table_def.composite_sai_match_fields_lookup.find( - fvField(app_db_match_fv)); - if (composite_sai_match_fields_it != - table_def.composite_sai_match_fields_lookup.end()) { - for (const auto& composite_sai_match_field : - composite_sai_match_fields_it->second) { - const auto& match_fv_it = - acl_rule->match_fvs.find(composite_sai_match_field.entry_attr); +void IsExpectedAclRuleMapping(const P4AclRule *acl_rule, const P4AclRuleAppDbEntry &app_db_entry, + const P4AclTableDefinition &table_def) +{ + // Check table name and priority + EXPECT_EQ(app_db_entry.acl_table_name, acl_rule->acl_table_name); + EXPECT_EQ(app_db_entry.priority, acl_rule->priority); + // Check match field + for (const auto &app_db_match_fv : app_db_entry.match_fvs) + { + // TODO: Fake UDF field until SAI supports it + if (table_def.udf_fields_lookup.find(fvField(app_db_match_fv)) != table_def.udf_fields_lookup.end()) + continue; + const auto &composite_sai_match_fields_it = + table_def.composite_sai_match_fields_lookup.find(fvField(app_db_match_fv)); + if (composite_sai_match_fields_it != table_def.composite_sai_match_fields_lookup.end()) + { + for (const auto &composite_sai_match_field : composite_sai_match_fields_it->second) + { + const auto &match_fv_it = acl_rule->match_fvs.find(composite_sai_match_field.entry_attr); + ASSERT_NE(acl_rule->match_fvs.end(), match_fv_it); + EXPECT_TRUE(match_fv_it->second.aclfield.enable); + } + continue; + } + const auto &match_field_it = table_def.sai_match_field_lookup.find(fvField(app_db_match_fv)); + ASSERT_NE(table_def.sai_match_field_lookup.end(), match_field_it); + const auto &match_fv_it = acl_rule->match_fvs.find(match_field_it->second.entry_attr); ASSERT_NE(acl_rule->match_fvs.end(), match_fv_it); EXPECT_TRUE(match_fv_it->second.aclfield.enable); - } - continue; } - const auto& match_field_it = - table_def.sai_match_field_lookup.find(fvField(app_db_match_fv)); - ASSERT_NE(table_def.sai_match_field_lookup.end(), match_field_it); - const auto& match_fv_it = - acl_rule->match_fvs.find(match_field_it->second.entry_attr); - ASSERT_NE(acl_rule->match_fvs.end(), match_fv_it); - EXPECT_TRUE(match_fv_it->second.aclfield.enable); - } - // Check action field - ASSERT_EQ(acl_rule->p4_action, app_db_entry.action); - const auto& actions_field_it = - table_def.rule_action_field_lookup.find(app_db_entry.action); - const auto& packet_action_color_it = - table_def.rule_packet_action_color_lookup.find(app_db_entry.action); - ASSERT_NE(table_def.rule_action_field_lookup.end(), actions_field_it); - ASSERT_NE(table_def.rule_packet_action_color_lookup.end(), - packet_action_color_it); - if (actions_field_it != table_def.rule_action_field_lookup.end()) { - for (const auto& action_field : actions_field_it->second) { - ASSERT_NE(acl_rule->action_fvs.find(action_field.action), - acl_rule->action_fvs.end()); + // Check action field + ASSERT_EQ(acl_rule->p4_action, app_db_entry.action); + const auto &actions_field_it = table_def.rule_action_field_lookup.find(app_db_entry.action); + const auto &packet_action_color_it = table_def.rule_packet_action_color_lookup.find(app_db_entry.action); + ASSERT_NE(table_def.rule_action_field_lookup.end(), actions_field_it); + ASSERT_NE(table_def.rule_packet_action_color_lookup.end(), packet_action_color_it); + if (actions_field_it != table_def.rule_action_field_lookup.end()) + { + for (const auto &action_field : actions_field_it->second) + { + ASSERT_NE(acl_rule->action_fvs.find(action_field.action), acl_rule->action_fvs.end()); + } } - } - // Check meter field value - if (packet_action_color_it != - table_def.rule_packet_action_color_lookup.end() && - !packet_action_color_it->second.empty()) { - ASSERT_EQ(acl_rule->meter.packet_color_actions, - packet_action_color_it->second); - } - if (!table_def.meter_unit.empty()) { - EXPECT_TRUE(acl_rule->meter.enabled); - EXPECT_EQ(SAI_POLICER_MODE_TR_TCM, acl_rule->meter.mode); - EXPECT_EQ(app_db_entry.meter.cir, acl_rule->meter.cir); - EXPECT_EQ(app_db_entry.meter.cburst, acl_rule->meter.cburst); - EXPECT_EQ(app_db_entry.meter.pir, acl_rule->meter.pir); - EXPECT_EQ(app_db_entry.meter.pburst, acl_rule->meter.pburst); - if (table_def.meter_unit == P4_METER_UNIT_BYTES) { - EXPECT_EQ(SAI_METER_TYPE_BYTES, acl_rule->meter.type); + // Check meter field value + if (packet_action_color_it != table_def.rule_packet_action_color_lookup.end() && + !packet_action_color_it->second.empty()) + { + ASSERT_EQ(acl_rule->meter.packet_color_actions, packet_action_color_it->second); } - if (table_def.meter_unit == P4_METER_UNIT_PACKETS) { - EXPECT_EQ(SAI_METER_TYPE_PACKETS, acl_rule->meter.type); + if (!table_def.meter_unit.empty()) + { + EXPECT_TRUE(acl_rule->meter.enabled); + EXPECT_EQ(SAI_POLICER_MODE_TR_TCM, acl_rule->meter.mode); + EXPECT_EQ(app_db_entry.meter.cir, acl_rule->meter.cir); + EXPECT_EQ(app_db_entry.meter.cburst, acl_rule->meter.cburst); + EXPECT_EQ(app_db_entry.meter.pir, acl_rule->meter.pir); + EXPECT_EQ(app_db_entry.meter.pburst, acl_rule->meter.pburst); + if (table_def.meter_unit == P4_METER_UNIT_BYTES) + { + EXPECT_EQ(SAI_METER_TYPE_BYTES, acl_rule->meter.type); + } + if (table_def.meter_unit == P4_METER_UNIT_PACKETS) + { + EXPECT_EQ(SAI_METER_TYPE_PACKETS, acl_rule->meter.type); + } + } + // Check counter field value + if (table_def.counter_unit.empty()) + { + EXPECT_FALSE(acl_rule->counter.packets_enabled); + EXPECT_FALSE(acl_rule->counter.bytes_enabled); + return; + } + if (table_def.counter_unit == P4_COUNTER_UNIT_BOTH) + { + EXPECT_TRUE(acl_rule->counter.bytes_enabled && acl_rule->counter.packets_enabled); + } + else if (table_def.counter_unit == P4_COUNTER_UNIT_BYTES) + { + EXPECT_TRUE(acl_rule->counter.bytes_enabled && !acl_rule->counter.packets_enabled); + } + else + { + EXPECT_TRUE(table_def.counter_unit == P4_COUNTER_UNIT_PACKETS && !acl_rule->counter.bytes_enabled && + acl_rule->counter.packets_enabled); } - } - // Check counter field value - if (table_def.counter_unit.empty()) { - EXPECT_FALSE(acl_rule->counter.packets_enabled); - EXPECT_FALSE(acl_rule->counter.bytes_enabled); - return; - } - if (table_def.counter_unit == P4_COUNTER_UNIT_BOTH) { - EXPECT_TRUE(acl_rule->counter.bytes_enabled && - acl_rule->counter.packets_enabled); - } else if (table_def.counter_unit == P4_COUNTER_UNIT_BYTES) { - EXPECT_TRUE(acl_rule->counter.bytes_enabled && - !acl_rule->counter.packets_enabled); - } else { - EXPECT_TRUE(table_def.counter_unit == P4_COUNTER_UNIT_PACKETS && - !acl_rule->counter.bytes_enabled && - acl_rule->counter.packets_enabled); - } } -std::vector getDefaultTableDefFieldValueTuples() { - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{kStage, STAGE_INGRESS}); - attributes.push_back(swss::FieldValueTuple{kSize, "123"}); - attributes.push_back(swss::FieldValueTuple{kPriority, "234"}); - attributes.push_back( - swss::FieldValueTuple{"meter/unit", P4_METER_UNIT_BYTES}); - attributes.push_back( - swss::FieldValueTuple{"counter/unit", P4_COUNTER_UNIT_BOTH}); - attributes.push_back(swss::FieldValueTuple{ - "match/ether_type", - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ETHER_TYPE)}); - attributes.push_back(swss::FieldValueTuple{ - "match/ether_dst", - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_MAC, P4_FORMAT_MAC)}); - attributes.push_back(swss::FieldValueTuple{ - "match/ipv6_dst", - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_IPV6, P4_FORMAT_IPV6)}); - attributes.push_back(swss::FieldValueTuple{ - "match/is_ip", - BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + - kFieldDelimiter + P4_IP_TYPE_BIT_IP)}); - attributes.push_back(swss::FieldValueTuple{ - "match/is_ipv4", BuildMatchFieldJsonStrKindSaiField( - std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + - P4_IP_TYPE_BIT_IPV4ANY)}); - attributes.push_back(swss::FieldValueTuple{ - "match/is_ipv6", BuildMatchFieldJsonStrKindSaiField( - std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + - P4_IP_TYPE_BIT_IPV6ANY)}); - attributes.push_back(swss::FieldValueTuple{ - "match/is_arp", BuildMatchFieldJsonStrKindSaiField( - std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + - P4_IP_TYPE_BIT_ARP)}); - attributes.push_back(swss::FieldValueTuple{ - "match/is_arp_request", - BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + - kFieldDelimiter + - P4_IP_TYPE_BIT_ARP_REQUEST)}); - attributes.push_back(swss::FieldValueTuple{ - "match/is_arp_reply", BuildMatchFieldJsonStrKindSaiField( - std::string(P4_MATCH_IP_TYPE) + - kFieldDelimiter + P4_IP_TYPE_BIT_ARP_REPLY)}); - attributes.push_back(swss::FieldValueTuple{ - "match/ipv6_next_header", - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IPV6_NEXT_HEADER)}); - attributes.push_back(swss::FieldValueTuple{ - "match/ttl", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TTL)}); - attributes.push_back(swss::FieldValueTuple{ - "match/icmp_type", - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ICMP_TYPE)}); - attributes.push_back(swss::FieldValueTuple{ - "match/l4_dst_port", - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_L4_DST_PORT)}); - attributes.push_back(swss::FieldValueTuple{ - "match/udf2", BuildMatchFieldJsonStrKindUdf("SAI_UDF_BASE_L3", 56, - P4_FORMAT_HEX_STRING, 16)}); - attributes.push_back(swss::FieldValueTuple{ - "action/copy_and_set_tc", - "[{\"action\":\"SAI_PACKET_ACTION_COPY\",\"packet_color\":\"SAI_" - "PACKET_" - "COLOR_GREEN\"},{\"action\":\"SAI_ACL_ENTRY_ATTR_ACTION_SET_TC\"," - "\"param\":\"traffic_class\"}]"}); - attributes.push_back(swss::FieldValueTuple{ - "action/punt_and_set_tc", - "[{\"action\":\"SAI_PACKET_ACTION_TRAP\"},{\"action\":\"SAI_ACL_" - "ENTRY_" - "ATTR_ACTION_SET_TC\",\"param\":\"traffic_class\"}]"}); - return attributes; +std::vector getDefaultTableDefFieldValueTuples() +{ + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{kStage, STAGE_INGRESS}); + attributes.push_back(swss::FieldValueTuple{kSize, "123"}); + attributes.push_back(swss::FieldValueTuple{kPriority, "234"}); + attributes.push_back(swss::FieldValueTuple{"meter/unit", P4_METER_UNIT_BYTES}); + attributes.push_back(swss::FieldValueTuple{"counter/unit", P4_COUNTER_UNIT_BOTH}); + attributes.push_back( + swss::FieldValueTuple{"match/ether_type", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ETHER_TYPE)}); + attributes.push_back( + swss::FieldValueTuple{"match/ether_dst", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_MAC, P4_FORMAT_MAC)}); + attributes.push_back( + swss::FieldValueTuple{"match/ipv6_dst", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_IPV6, P4_FORMAT_IPV6)}); + attributes.push_back(swss::FieldValueTuple{ + "match/is_ip", + BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + P4_IP_TYPE_BIT_IP)}); + attributes.push_back(swss::FieldValueTuple{ + "match/is_ipv4", + BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + P4_IP_TYPE_BIT_IPV4ANY)}); + attributes.push_back(swss::FieldValueTuple{ + "match/is_ipv6", + BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + P4_IP_TYPE_BIT_IPV6ANY)}); + attributes.push_back(swss::FieldValueTuple{ + "match/is_arp", + BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + P4_IP_TYPE_BIT_ARP)}); + attributes.push_back(swss::FieldValueTuple{ + "match/is_arp_request", BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + + P4_IP_TYPE_BIT_ARP_REQUEST)}); + attributes.push_back(swss::FieldValueTuple{ + "match/is_arp_reply", BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + + P4_IP_TYPE_BIT_ARP_REPLY)}); + attributes.push_back( + swss::FieldValueTuple{"match/ipv6_next_header", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IPV6_NEXT_HEADER)}); + attributes.push_back(swss::FieldValueTuple{"match/ttl", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TTL)}); + attributes.push_back( + swss::FieldValueTuple{"match/icmp_type", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ICMP_TYPE)}); + attributes.push_back( + swss::FieldValueTuple{"match/l4_dst_port", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_L4_DST_PORT)}); + attributes.push_back(swss::FieldValueTuple{ + "match/udf2", BuildMatchFieldJsonStrKindUdf("SAI_UDF_BASE_L3", 56, P4_FORMAT_HEX_STRING, 16)}); + attributes.push_back(swss::FieldValueTuple{"action/copy_and_set_tc", + "[{\"action\":\"SAI_PACKET_ACTION_COPY\",\"packet_color\":\"SAI_" + "PACKET_" + "COLOR_GREEN\"},{\"action\":\"SAI_ACL_ENTRY_ATTR_ACTION_SET_TC\"," + "\"param\":\"traffic_class\"}]"}); + attributes.push_back(swss::FieldValueTuple{"action/punt_and_set_tc", + "[{\"action\":\"SAI_PACKET_ACTION_TRAP\"},{\"action\":\"SAI_ACL_" + "ENTRY_" + "ATTR_ACTION_SET_TC\",\"param\":\"traffic_class\"}]"}); + return attributes; } -P4AclTableDefinitionAppDbEntry getDefaultAclTableDefAppDbEntry() { - P4AclTableDefinitionAppDbEntry app_db_entry; - app_db_entry.acl_table_name = kAclIngressTableName; - app_db_entry.size = 123; - app_db_entry.stage = STAGE_INGRESS; - app_db_entry.priority = 234; - app_db_entry.meter_unit = P4_METER_UNIT_BYTES; - app_db_entry.counter_unit = P4_COUNTER_UNIT_BOTH; - // Match field mapping from P4 program to SAI entry attribute - app_db_entry.match_field_lookup["ether_type"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ETHER_TYPE); - app_db_entry.match_field_lookup["ether_dst"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_MAC, P4_FORMAT_MAC); - app_db_entry.match_field_lookup["ether_src"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_SRC_MAC, P4_FORMAT_MAC); - app_db_entry.match_field_lookup["ipv6_dst"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_IPV6, P4_FORMAT_IPV6); - app_db_entry.match_field_lookup["ipv6_next_header"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IPV6_NEXT_HEADER); - app_db_entry.match_field_lookup["ttl"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TTL); - app_db_entry.match_field_lookup["in_ports"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IN_PORTS, P4_FORMAT_STRING); - app_db_entry.match_field_lookup["in_port"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IN_PORT, P4_FORMAT_STRING); - app_db_entry.match_field_lookup["out_ports"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_OUT_PORTS, P4_FORMAT_STRING); - app_db_entry.match_field_lookup["out_port"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_OUT_PORT, P4_FORMAT_STRING); - app_db_entry.match_field_lookup["is_ip"] = BuildMatchFieldJsonStrKindSaiField( - std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + P4_IP_TYPE_BIT_IP); - app_db_entry.match_field_lookup["is_ipv4"] = - BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + - kFieldDelimiter + - P4_IP_TYPE_BIT_IPV4ANY); - app_db_entry.match_field_lookup["is_ipv6"] = - BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + - kFieldDelimiter + - P4_IP_TYPE_BIT_IPV6ANY); - app_db_entry.match_field_lookup["is_arp"] = - BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + - kFieldDelimiter + P4_IP_TYPE_BIT_ARP); - app_db_entry.match_field_lookup["is_arp_request"] = - BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + - kFieldDelimiter + - P4_IP_TYPE_BIT_ARP_REQUEST); - app_db_entry.match_field_lookup["is_arp_reply"] = - BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + - kFieldDelimiter + - P4_IP_TYPE_BIT_ARP_REPLY); - app_db_entry.match_field_lookup["tcp_flags"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TCP_FLAGS); - app_db_entry.match_field_lookup["ip_flags"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IP_FLAGS); - app_db_entry.match_field_lookup["l4_src_port"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_L4_SRC_PORT); - app_db_entry.match_field_lookup["l4_dst_port"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_L4_DST_PORT); - app_db_entry.match_field_lookup["ip_id"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IP_ID); - app_db_entry.match_field_lookup["inner_l4_src_port"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_L4_SRC_PORT); - app_db_entry.match_field_lookup["inner_l4_dst_port"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_L4_DST_PORT); - app_db_entry.match_field_lookup["dscp"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DSCP); - app_db_entry.match_field_lookup["inner_ip_src"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_SRC_IP, P4_FORMAT_IPV4); - app_db_entry.match_field_lookup["inner_ip_dst"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_DST_IP, P4_FORMAT_IPV4); - app_db_entry.match_field_lookup["inner_ipv6_src"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_SRC_IPV6, - P4_FORMAT_IPV6); - app_db_entry.match_field_lookup["inner_ipv6_dst"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_DST_IPV6, - P4_FORMAT_IPV6); - app_db_entry.match_field_lookup["ip_src"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_SRC_IP, P4_FORMAT_IPV4); - app_db_entry.match_field_lookup["ip_dst"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_IP, P4_FORMAT_IPV4); - app_db_entry.match_field_lookup["ipv6_src"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_SRC_IPV6, P4_FORMAT_IPV6); - app_db_entry.match_field_lookup["tc"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TRAFFIC_CLASS); - app_db_entry.match_field_lookup["icmp_type"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ICMP_TYPE); - app_db_entry.match_field_lookup["icmp_code"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ICMP_CODE); - app_db_entry.match_field_lookup["tos"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TOS); - app_db_entry.match_field_lookup["icmpv6_type"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ICMPV6_TYPE); - app_db_entry.match_field_lookup["icmpv6_code"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ICMPV6_CODE); - app_db_entry.match_field_lookup["ecn"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ECN); - app_db_entry.match_field_lookup["inner_ip_protocol"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_IP_PROTOCOL); - app_db_entry.match_field_lookup["ip_protocol"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IP_PROTOCOL); - app_db_entry.match_field_lookup["ipv6_flow_label"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IPV6_FLOW_LABEL); - app_db_entry.match_field_lookup["tunnel_vni"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TUNNEL_VNI); - app_db_entry.match_field_lookup["ip_frag"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IP_FRAG, P4_FORMAT_STRING); - app_db_entry.match_field_lookup["packet_vlan"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_PACKET_VLAN, - P4_FORMAT_STRING); - app_db_entry.match_field_lookup["outer_vlan_pri"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_OUTER_VLAN_PRI); - app_db_entry.match_field_lookup["outer_vlan_id"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_OUTER_VLAN_ID); - app_db_entry.match_field_lookup["outer_vlan_cfi"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_OUTER_VLAN_CFI); - app_db_entry.match_field_lookup["inner_vlan_pri"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_VLAN_PRI); - app_db_entry.match_field_lookup["inner_vlan_id"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_VLAN_ID); - app_db_entry.match_field_lookup["inner_vlan_cfi"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_VLAN_CFI); - app_db_entry.match_field_lookup["l3_class_id"] = - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ROUTE_DST_USER_META, - P4_FORMAT_HEX_STRING, /*bitwidth=*/6); - app_db_entry.match_field_lookup["src_ipv6_64bit"] = - BuildMatchFieldJsonStrKindComposite( - {nlohmann::json::parse(BuildMatchFieldJsonStrKindSaiField( - P4_MATCH_SRC_IPV6_WORD3, P4_FORMAT_IPV6, 32)), - nlohmann::json::parse(BuildMatchFieldJsonStrKindSaiField( - P4_MATCH_SRC_IPV6_WORD2, P4_FORMAT_IPV6, 32))}, - P4_FORMAT_IPV6, 64); - app_db_entry.match_field_lookup["arp_tpa"] = - BuildMatchFieldJsonStrKindComposite( - {nlohmann::json::parse(BuildMatchFieldJsonStrKindUdf( - "SAI_UDF_BASE_L3", 24, P4_FORMAT_HEX_STRING, 16)), - nlohmann::json::parse(BuildMatchFieldJsonStrKindUdf( - "SAI_UDF_BASE_L3", 26, P4_FORMAT_HEX_STRING, 16))}, - P4_FORMAT_HEX_STRING, 32); - app_db_entry.match_field_lookup["udf2"] = BuildMatchFieldJsonStrKindUdf( - "SAI_UDF_BASE_L3", 56, P4_FORMAT_HEX_STRING, 16); - - // Action field mapping, from P4 action to SAI action - app_db_entry.action_field_lookup["set_packet_action"].push_back( - {.sai_action = P4_ACTION_PACKET_ACTION, - .p4_param_name = "packet_action"}); - app_db_entry.action_field_lookup["copy_and_set_tc"].push_back( - {.sai_action = P4_ACTION_SET_TRAFFIC_CLASS, - .p4_param_name = "traffic_class"}); - app_db_entry.action_field_lookup["punt_and_set_tc"].push_back( - {.sai_action = P4_ACTION_SET_TRAFFIC_CLASS, - .p4_param_name = "traffic_class"}); - app_db_entry.packet_action_color_lookup["copy_and_set_tc"].push_back( - {.packet_action = P4_PACKET_ACTION_COPY, - .packet_color = P4_PACKET_COLOR_GREEN}); - app_db_entry.packet_action_color_lookup["punt_and_set_tc"].push_back( - {.packet_action = P4_PACKET_ACTION_PUNT, .packet_color = EMPTY_STRING}); - app_db_entry.packet_action_color_lookup["punt_non_green_pk"].push_back( - {.packet_action = P4_PACKET_ACTION_PUNT, - .packet_color = P4_PACKET_COLOR_YELLOW}); - app_db_entry.packet_action_color_lookup["punt_non_green_pk"].push_back( - {.packet_action = P4_PACKET_ACTION_PUNT, - .packet_color = P4_PACKET_COLOR_RED}); - app_db_entry.action_field_lookup["redirect"].push_back( - {.sai_action = P4_ACTION_REDIRECT, .p4_param_name = "target"}); - app_db_entry.action_field_lookup["endpoint_ip"].push_back( - {.sai_action = P4_ACTION_ENDPOINT_IP, .p4_param_name = "ip_address"}); - app_db_entry.action_field_lookup["mirror_ingress"].push_back( - {.sai_action = P4_ACTION_MIRROR_INGRESS, .p4_param_name = "target"}); - app_db_entry.action_field_lookup["mirror_egress"].push_back( - {.sai_action = P4_ACTION_MIRROR_EGRESS, .p4_param_name = "target"}); - app_db_entry.action_field_lookup["set_packet_color"].push_back( - {.sai_action = P4_ACTION_SET_PACKET_COLOR, - .p4_param_name = "packet_color"}); - app_db_entry.action_field_lookup["set_src_mac"].push_back( - {.sai_action = P4_ACTION_SET_SRC_MAC, .p4_param_name = "mac_address"}); - app_db_entry.action_field_lookup["set_dst_mac"].push_back( - {.sai_action = P4_ACTION_SET_DST_MAC, .p4_param_name = "mac_address"}); - app_db_entry.action_field_lookup["set_src_ip"].push_back( - {.sai_action = P4_ACTION_SET_SRC_IP, .p4_param_name = "ip_address"}); - app_db_entry.action_field_lookup["set_dst_ip"].push_back( - {.sai_action = P4_ACTION_SET_DST_IP, .p4_param_name = "ip_address"}); - app_db_entry.action_field_lookup["set_src_ipv6"].push_back( - {.sai_action = P4_ACTION_SET_SRC_IPV6, .p4_param_name = "ip_address"}); - app_db_entry.action_field_lookup["set_dst_ipv6"].push_back( - {.sai_action = P4_ACTION_SET_DST_IPV6, .p4_param_name = "ip_address"}); - app_db_entry.action_field_lookup["set_dscp_and_ecn"].push_back( - {.sai_action = P4_ACTION_SET_DSCP, .p4_param_name = "dscp"}); - app_db_entry.action_field_lookup["set_dscp_and_ecn"].push_back( - {.sai_action = P4_ACTION_SET_ECN, .p4_param_name = "ecn"}); - app_db_entry.action_field_lookup["set_inner_vlan"].push_back( - {.sai_action = P4_ACTION_SET_INNER_VLAN_PRIORITY, - .p4_param_name = "vlan_pri"}); - app_db_entry.action_field_lookup["set_inner_vlan"].push_back( - {.sai_action = P4_ACTION_SET_INNER_VLAN_ID, .p4_param_name = "vlan_id"}); - app_db_entry.action_field_lookup["set_outer_vlan"].push_back( - {.sai_action = P4_ACTION_SET_OUTER_VLAN_PRIORITY, - .p4_param_name = "vlan_pri"}); - app_db_entry.action_field_lookup["set_outer_vlan"].push_back( - {.sai_action = P4_ACTION_SET_OUTER_VLAN_ID, .p4_param_name = "vlan_id"}); - app_db_entry.action_field_lookup["set_l4_src_port"].push_back( - {.sai_action = P4_ACTION_SET_L4_SRC_PORT, .p4_param_name = "port"}); - app_db_entry.action_field_lookup["set_l4_dst_port"].push_back( - {.sai_action = P4_ACTION_SET_L4_DST_PORT, .p4_param_name = "port"}); - app_db_entry.action_field_lookup["flood"].push_back( - {.sai_action = P4_ACTION_FLOOD, .p4_param_name = EMPTY_STRING}); - app_db_entry.action_field_lookup["decrement_ttl"].push_back( - {.sai_action = P4_ACTION_DECREMENT_TTL, .p4_param_name = EMPTY_STRING}); - app_db_entry.action_field_lookup["do_not_learn"].push_back( - {.sai_action = P4_ACTION_SET_DO_NOT_LEARN, - .p4_param_name = EMPTY_STRING}); - app_db_entry.action_field_lookup["set_vrf"].push_back( - {.sai_action = P4_ACTION_SET_VRF, .p4_param_name = "vrf"}); - app_db_entry.action_field_lookup["qos_queue"].push_back( - {.sai_action = P4_ACTION_SET_QOS_QUEUE, .p4_param_name = "cpu_queue"}); - - // "action/acl_trap" = [ - // {"action": "SAI_PACKET_ACTION_TRAP", "packet_color": - // "SAI_PACKET_COLOR_GREEN"}, - // {"action": "SAI_PACKET_ACTION_DROP", "packet_color": - // "SAI_PACKET_COLOR_YELLOW"}, - // {"action": "SAI_PACKET_ACTION_DROP", "packet_color": - // "SAI_PACKET_COLOR_RED"}, - // {"action": "QOS_QUEUE", "param": "queue"} - // ] - app_db_entry.action_field_lookup["acl_trap"].push_back( - {.sai_action = P4_ACTION_SET_QOS_QUEUE, .p4_param_name = "queue"}); - app_db_entry.packet_action_color_lookup["acl_trap"].push_back( - {.packet_action = P4_PACKET_ACTION_PUNT, - .packet_color = P4_PACKET_COLOR_GREEN}); - app_db_entry.packet_action_color_lookup["acl_trap"].push_back( - {.packet_action = P4_PACKET_ACTION_DROP, - .packet_color = P4_PACKET_COLOR_YELLOW}); - app_db_entry.packet_action_color_lookup["acl_trap"].push_back( - {.packet_action = P4_PACKET_ACTION_DROP, - .packet_color = P4_PACKET_COLOR_RED}); - return app_db_entry; +P4AclTableDefinitionAppDbEntry getDefaultAclTableDefAppDbEntry() +{ + P4AclTableDefinitionAppDbEntry app_db_entry; + app_db_entry.acl_table_name = kAclIngressTableName; + app_db_entry.size = 123; + app_db_entry.stage = STAGE_INGRESS; + app_db_entry.priority = 234; + app_db_entry.meter_unit = P4_METER_UNIT_BYTES; + app_db_entry.counter_unit = P4_COUNTER_UNIT_BOTH; + // Match field mapping from P4 program to SAI entry attribute + app_db_entry.match_field_lookup["ether_type"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ETHER_TYPE); + app_db_entry.match_field_lookup["ether_dst"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_MAC, P4_FORMAT_MAC); + app_db_entry.match_field_lookup["ether_src"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_SRC_MAC, P4_FORMAT_MAC); + app_db_entry.match_field_lookup["ipv6_dst"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_IPV6, P4_FORMAT_IPV6); + app_db_entry.match_field_lookup["ipv6_next_header"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IPV6_NEXT_HEADER); + app_db_entry.match_field_lookup["ttl"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TTL); + app_db_entry.match_field_lookup["in_ports"] = + BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IN_PORTS, P4_FORMAT_STRING); + app_db_entry.match_field_lookup["in_port"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IN_PORT, P4_FORMAT_STRING); + app_db_entry.match_field_lookup["out_ports"] = + BuildMatchFieldJsonStrKindSaiField(P4_MATCH_OUT_PORTS, P4_FORMAT_STRING); + app_db_entry.match_field_lookup["out_port"] = + BuildMatchFieldJsonStrKindSaiField(P4_MATCH_OUT_PORT, P4_FORMAT_STRING); + app_db_entry.match_field_lookup["is_ip"] = + BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + P4_IP_TYPE_BIT_IP); + app_db_entry.match_field_lookup["is_ipv4"] = + BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + P4_IP_TYPE_BIT_IPV4ANY); + app_db_entry.match_field_lookup["is_ipv6"] = + BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + P4_IP_TYPE_BIT_IPV6ANY); + app_db_entry.match_field_lookup["is_arp"] = + BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + P4_IP_TYPE_BIT_ARP); + app_db_entry.match_field_lookup["is_arp_request"] = BuildMatchFieldJsonStrKindSaiField( + std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + P4_IP_TYPE_BIT_ARP_REQUEST); + app_db_entry.match_field_lookup["is_arp_reply"] = + BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + P4_IP_TYPE_BIT_ARP_REPLY); + app_db_entry.match_field_lookup["tcp_flags"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TCP_FLAGS); + app_db_entry.match_field_lookup["ip_flags"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IP_FLAGS); + app_db_entry.match_field_lookup["l4_src_port"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_L4_SRC_PORT); + app_db_entry.match_field_lookup["l4_dst_port"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_L4_DST_PORT); + app_db_entry.match_field_lookup["ip_id"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IP_ID); + app_db_entry.match_field_lookup["inner_l4_src_port"] = + BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_L4_SRC_PORT); + app_db_entry.match_field_lookup["inner_l4_dst_port"] = + BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_L4_DST_PORT); + app_db_entry.match_field_lookup["dscp"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DSCP); + app_db_entry.match_field_lookup["inner_ip_src"] = + BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_SRC_IP, P4_FORMAT_IPV4); + app_db_entry.match_field_lookup["inner_ip_dst"] = + BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_DST_IP, P4_FORMAT_IPV4); + app_db_entry.match_field_lookup["inner_ipv6_src"] = + BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_SRC_IPV6, P4_FORMAT_IPV6); + app_db_entry.match_field_lookup["inner_ipv6_dst"] = + BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_DST_IPV6, P4_FORMAT_IPV6); + app_db_entry.match_field_lookup["ip_src"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_SRC_IP, P4_FORMAT_IPV4); + app_db_entry.match_field_lookup["ip_dst"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_IP, P4_FORMAT_IPV4); + app_db_entry.match_field_lookup["ipv6_src"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_SRC_IPV6, P4_FORMAT_IPV6); + app_db_entry.match_field_lookup["tc"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TRAFFIC_CLASS); + app_db_entry.match_field_lookup["icmp_type"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ICMP_TYPE); + app_db_entry.match_field_lookup["icmp_code"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ICMP_CODE); + app_db_entry.match_field_lookup["tos"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TOS); + app_db_entry.match_field_lookup["icmpv6_type"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ICMPV6_TYPE); + app_db_entry.match_field_lookup["icmpv6_code"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ICMPV6_CODE); + app_db_entry.match_field_lookup["ecn"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ECN); + app_db_entry.match_field_lookup["inner_ip_protocol"] = + BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_IP_PROTOCOL); + app_db_entry.match_field_lookup["ip_protocol"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IP_PROTOCOL); + app_db_entry.match_field_lookup["ipv6_flow_label"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IPV6_FLOW_LABEL); + app_db_entry.match_field_lookup["tunnel_vni"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TUNNEL_VNI); + app_db_entry.match_field_lookup["ip_frag"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IP_FRAG, P4_FORMAT_STRING); + app_db_entry.match_field_lookup["packet_vlan"] = + BuildMatchFieldJsonStrKindSaiField(P4_MATCH_PACKET_VLAN, P4_FORMAT_STRING); + app_db_entry.match_field_lookup["outer_vlan_pri"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_OUTER_VLAN_PRI); + app_db_entry.match_field_lookup["outer_vlan_id"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_OUTER_VLAN_ID); + app_db_entry.match_field_lookup["outer_vlan_cfi"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_OUTER_VLAN_CFI); + app_db_entry.match_field_lookup["inner_vlan_pri"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_VLAN_PRI); + app_db_entry.match_field_lookup["inner_vlan_id"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_VLAN_ID); + app_db_entry.match_field_lookup["inner_vlan_cfi"] = BuildMatchFieldJsonStrKindSaiField(P4_MATCH_INNER_VLAN_CFI); + app_db_entry.match_field_lookup["l3_class_id"] = + BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ROUTE_DST_USER_META, P4_FORMAT_HEX_STRING, /*bitwidth=*/6); + app_db_entry.match_field_lookup["src_ipv6_64bit"] = BuildMatchFieldJsonStrKindComposite( + {nlohmann::json::parse(BuildMatchFieldJsonStrKindSaiField(P4_MATCH_SRC_IPV6_WORD3, P4_FORMAT_IPV6, 32)), + nlohmann::json::parse(BuildMatchFieldJsonStrKindSaiField(P4_MATCH_SRC_IPV6_WORD2, P4_FORMAT_IPV6, 32))}, + P4_FORMAT_IPV6, 64); + app_db_entry.match_field_lookup["arp_tpa"] = BuildMatchFieldJsonStrKindComposite( + {nlohmann::json::parse(BuildMatchFieldJsonStrKindUdf("SAI_UDF_BASE_L3", 24, P4_FORMAT_HEX_STRING, 16)), + nlohmann::json::parse(BuildMatchFieldJsonStrKindUdf("SAI_UDF_BASE_L3", 26, P4_FORMAT_HEX_STRING, 16))}, + P4_FORMAT_HEX_STRING, 32); + app_db_entry.match_field_lookup["udf2"] = + BuildMatchFieldJsonStrKindUdf("SAI_UDF_BASE_L3", 56, P4_FORMAT_HEX_STRING, 16); + + // Action field mapping, from P4 action to SAI action + app_db_entry.action_field_lookup["set_packet_action"].push_back( + {.sai_action = P4_ACTION_PACKET_ACTION, .p4_param_name = "packet_action"}); + app_db_entry.action_field_lookup["copy_and_set_tc"].push_back( + {.sai_action = P4_ACTION_SET_TRAFFIC_CLASS, .p4_param_name = "traffic_class"}); + app_db_entry.action_field_lookup["punt_and_set_tc"].push_back( + {.sai_action = P4_ACTION_SET_TRAFFIC_CLASS, .p4_param_name = "traffic_class"}); + app_db_entry.packet_action_color_lookup["copy_and_set_tc"].push_back( + {.packet_action = P4_PACKET_ACTION_COPY, .packet_color = P4_PACKET_COLOR_GREEN}); + app_db_entry.packet_action_color_lookup["punt_and_set_tc"].push_back( + {.packet_action = P4_PACKET_ACTION_PUNT, .packet_color = EMPTY_STRING}); + app_db_entry.packet_action_color_lookup["punt_non_green_pk"].push_back( + {.packet_action = P4_PACKET_ACTION_PUNT, .packet_color = P4_PACKET_COLOR_YELLOW}); + app_db_entry.packet_action_color_lookup["punt_non_green_pk"].push_back( + {.packet_action = P4_PACKET_ACTION_PUNT, .packet_color = P4_PACKET_COLOR_RED}); + app_db_entry.action_field_lookup["redirect"].push_back( + {.sai_action = P4_ACTION_REDIRECT, .p4_param_name = "target"}); + app_db_entry.action_field_lookup["endpoint_ip"].push_back( + {.sai_action = P4_ACTION_ENDPOINT_IP, .p4_param_name = "ip_address"}); + app_db_entry.action_field_lookup["mirror_ingress"].push_back( + {.sai_action = P4_ACTION_MIRROR_INGRESS, .p4_param_name = "target"}); + app_db_entry.action_field_lookup["mirror_egress"].push_back( + {.sai_action = P4_ACTION_MIRROR_EGRESS, .p4_param_name = "target"}); + app_db_entry.action_field_lookup["set_packet_color"].push_back( + {.sai_action = P4_ACTION_SET_PACKET_COLOR, .p4_param_name = "packet_color"}); + app_db_entry.action_field_lookup["set_src_mac"].push_back( + {.sai_action = P4_ACTION_SET_SRC_MAC, .p4_param_name = "mac_address"}); + app_db_entry.action_field_lookup["set_dst_mac"].push_back( + {.sai_action = P4_ACTION_SET_DST_MAC, .p4_param_name = "mac_address"}); + app_db_entry.action_field_lookup["set_src_ip"].push_back( + {.sai_action = P4_ACTION_SET_SRC_IP, .p4_param_name = "ip_address"}); + app_db_entry.action_field_lookup["set_dst_ip"].push_back( + {.sai_action = P4_ACTION_SET_DST_IP, .p4_param_name = "ip_address"}); + app_db_entry.action_field_lookup["set_src_ipv6"].push_back( + {.sai_action = P4_ACTION_SET_SRC_IPV6, .p4_param_name = "ip_address"}); + app_db_entry.action_field_lookup["set_dst_ipv6"].push_back( + {.sai_action = P4_ACTION_SET_DST_IPV6, .p4_param_name = "ip_address"}); + app_db_entry.action_field_lookup["set_dscp_and_ecn"].push_back( + {.sai_action = P4_ACTION_SET_DSCP, .p4_param_name = "dscp"}); + app_db_entry.action_field_lookup["set_dscp_and_ecn"].push_back( + {.sai_action = P4_ACTION_SET_ECN, .p4_param_name = "ecn"}); + app_db_entry.action_field_lookup["set_inner_vlan"].push_back( + {.sai_action = P4_ACTION_SET_INNER_VLAN_PRIORITY, .p4_param_name = "vlan_pri"}); + app_db_entry.action_field_lookup["set_inner_vlan"].push_back( + {.sai_action = P4_ACTION_SET_INNER_VLAN_ID, .p4_param_name = "vlan_id"}); + app_db_entry.action_field_lookup["set_outer_vlan"].push_back( + {.sai_action = P4_ACTION_SET_OUTER_VLAN_PRIORITY, .p4_param_name = "vlan_pri"}); + app_db_entry.action_field_lookup["set_outer_vlan"].push_back( + {.sai_action = P4_ACTION_SET_OUTER_VLAN_ID, .p4_param_name = "vlan_id"}); + app_db_entry.action_field_lookup["set_l4_src_port"].push_back( + {.sai_action = P4_ACTION_SET_L4_SRC_PORT, .p4_param_name = "port"}); + app_db_entry.action_field_lookup["set_l4_dst_port"].push_back( + {.sai_action = P4_ACTION_SET_L4_DST_PORT, .p4_param_name = "port"}); + app_db_entry.action_field_lookup["flood"].push_back({.sai_action = P4_ACTION_FLOOD, .p4_param_name = EMPTY_STRING}); + app_db_entry.action_field_lookup["decrement_ttl"].push_back( + {.sai_action = P4_ACTION_DECREMENT_TTL, .p4_param_name = EMPTY_STRING}); + app_db_entry.action_field_lookup["do_not_learn"].push_back( + {.sai_action = P4_ACTION_SET_DO_NOT_LEARN, .p4_param_name = EMPTY_STRING}); + app_db_entry.action_field_lookup["set_vrf"].push_back({.sai_action = P4_ACTION_SET_VRF, .p4_param_name = "vrf"}); + app_db_entry.action_field_lookup["qos_queue"].push_back( + {.sai_action = P4_ACTION_SET_QOS_QUEUE, .p4_param_name = "cpu_queue"}); + + // "action/acl_trap" = [ + // {"action": "SAI_PACKET_ACTION_TRAP", "packet_color": + // "SAI_PACKET_COLOR_GREEN"}, + // {"action": "SAI_PACKET_ACTION_DROP", "packet_color": + // "SAI_PACKET_COLOR_YELLOW"}, + // {"action": "SAI_PACKET_ACTION_DROP", "packet_color": + // "SAI_PACKET_COLOR_RED"}, + // {"action": "QOS_QUEUE", "param": "queue"} + // ] + app_db_entry.action_field_lookup["acl_trap"].push_back( + {.sai_action = P4_ACTION_SET_QOS_QUEUE, .p4_param_name = "queue"}); + app_db_entry.packet_action_color_lookup["acl_trap"].push_back( + {.packet_action = P4_PACKET_ACTION_PUNT, .packet_color = P4_PACKET_COLOR_GREEN}); + app_db_entry.packet_action_color_lookup["acl_trap"].push_back( + {.packet_action = P4_PACKET_ACTION_DROP, .packet_color = P4_PACKET_COLOR_YELLOW}); + app_db_entry.packet_action_color_lookup["acl_trap"].push_back( + {.packet_action = P4_PACKET_ACTION_DROP, .packet_color = P4_PACKET_COLOR_RED}); + return app_db_entry; } -std::vector getDefaultRuleFieldValueTuples() { - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{kAction, "copy_and_set_tc"}); - attributes.push_back(swss::FieldValueTuple{"param/traffic_class", "0x20"}); - attributes.push_back(swss::FieldValueTuple{"meter/cir", "80"}); - attributes.push_back(swss::FieldValueTuple{"meter/cburst", "80"}); - attributes.push_back(swss::FieldValueTuple{"meter/pir", "200"}); - attributes.push_back(swss::FieldValueTuple{"meter/pburst", "200"}); - attributes.push_back(swss::FieldValueTuple{"controller_metadata", "..."}); - return attributes; +std::vector getDefaultRuleFieldValueTuples() +{ + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{kAction, "copy_and_set_tc"}); + attributes.push_back(swss::FieldValueTuple{"param/traffic_class", "0x20"}); + attributes.push_back(swss::FieldValueTuple{"meter/cir", "80"}); + attributes.push_back(swss::FieldValueTuple{"meter/cburst", "80"}); + attributes.push_back(swss::FieldValueTuple{"meter/pir", "200"}); + attributes.push_back(swss::FieldValueTuple{"meter/pburst", "200"}); + attributes.push_back(swss::FieldValueTuple{"controller_metadata", "..."}); + return attributes; } -P4AclRuleAppDbEntry getDefaultAclRuleAppDbEntryWithoutAction() { - P4AclRuleAppDbEntry app_db_entry; - app_db_entry.acl_table_name = kAclIngressTableName; - app_db_entry.priority = 100; - // ACL rule match fields - app_db_entry.match_fvs["ether_type"] = "0x0800"; - app_db_entry.match_fvs["ipv6_dst"] = "fdf8:f53b:82e4::53"; - app_db_entry.match_fvs["ether_dst"] = "AA:BB:CC:DD:EE:FF"; - app_db_entry.match_fvs["ether_src"] = "AA:BB:CC:DD:EE:FF"; - app_db_entry.match_fvs["ipv6_next_header"] = "1"; - app_db_entry.match_fvs["src_ipv6_64bit"] = "fdf8:f53b:82e4::"; - app_db_entry.match_fvs["arp_tpa"] = "0xff112231"; - app_db_entry.match_fvs["udf2"] = "0x9876 & 0xAAAA"; - app_db_entry.db_key = - "ACL_PUNT_TABLE:{\"match/ether_type\": \"0x0800\",\"match/ipv6_dst\": " - "\"fdf8:f53b:82e4::53\",\"match/ether_dst\": \"AA:BB:CC:DD:EE:FF\", " - "\"match/ether_src\": \"AA:BB:CC:DD:EE:FF\", \"match/ipv6_next_header\": " - "\"1\", \"match/src_ipv6_64bit\": " - "\"fdf8:f53b:82e4::\",\"match/arp_tpa\": \"0xff112231\",\"match/udf2\": " - "\"0x9876 & 0xAAAA\",\"priority\":100}"; - // ACL meter fields - app_db_entry.meter.enabled = true; - app_db_entry.meter.cir = 80; - app_db_entry.meter.cburst = 80; - app_db_entry.meter.pir = 200; - app_db_entry.meter.pburst = 200; - return app_db_entry; +P4AclRuleAppDbEntry getDefaultAclRuleAppDbEntryWithoutAction() +{ + P4AclRuleAppDbEntry app_db_entry; + app_db_entry.acl_table_name = kAclIngressTableName; + app_db_entry.priority = 100; + // ACL rule match fields + app_db_entry.match_fvs["ether_type"] = "0x0800"; + app_db_entry.match_fvs["ipv6_dst"] = "fdf8:f53b:82e4::53"; + app_db_entry.match_fvs["ether_dst"] = "AA:BB:CC:DD:EE:FF"; + app_db_entry.match_fvs["ether_src"] = "AA:BB:CC:DD:EE:FF"; + app_db_entry.match_fvs["ipv6_next_header"] = "1"; + app_db_entry.match_fvs["src_ipv6_64bit"] = "fdf8:f53b:82e4::"; + app_db_entry.match_fvs["arp_tpa"] = "0xff112231"; + app_db_entry.match_fvs["udf2"] = "0x9876 & 0xAAAA"; + app_db_entry.db_key = "ACL_PUNT_TABLE:{\"match/ether_type\": \"0x0800\",\"match/ipv6_dst\": " + "\"fdf8:f53b:82e4::53\",\"match/ether_dst\": \"AA:BB:CC:DD:EE:FF\", " + "\"match/ether_src\": \"AA:BB:CC:DD:EE:FF\", \"match/ipv6_next_header\": " + "\"1\", \"match/src_ipv6_64bit\": " + "\"fdf8:f53b:82e4::\",\"match/arp_tpa\": \"0xff112231\",\"match/udf2\": " + "\"0x9876 & 0xAAAA\",\"priority\":100}"; + // ACL meter fields + app_db_entry.meter.enabled = true; + app_db_entry.meter.cir = 80; + app_db_entry.meter.cburst = 80; + app_db_entry.meter.pir = 200; + app_db_entry.meter.pburst = 200; + return app_db_entry; } -const std::string concatTableNameAndRuleKey(const std::string& table_name, - const std::string& rule_key) { - return table_name + kTableKeyDelimiter + rule_key; +const std::string concatTableNameAndRuleKey(const std::string &table_name, const std::string &rule_key) +{ + return table_name + kTableKeyDelimiter + rule_key; } -} // namespace +} // namespace + +class AclManagerTest : public ::testing::Test +{ + protected: + AclManagerTest() + { + setUpMockApi(); + setUpCoppOrch(); + setUpSwitchOrch(); + setUpP4Orch(); + // const auto& acl_groups = gSwitchOrch->getAclGroupsBindingToSwitch(); + // EXPECT_EQ(3, acl_groups.size()); + // EXPECT_NE(acl_groups.end(), acl_groups.find(SAI_ACL_STAGE_INGRESS)); + // EXPECT_EQ(kAclGroupIngressOid, + // acl_groups.at(SAI_ACL_STAGE_INGRESS).m_saiObjectId); + // EXPECT_NE(acl_groups.end(), acl_groups.find(SAI_ACL_STAGE_EGRESS)); + // EXPECT_EQ(kAclGroupEgressOid, + // acl_groups.at(SAI_ACL_STAGE_EGRESS).m_saiObjectId); + // EXPECT_NE(acl_groups.end(), acl_groups.find(SAI_ACL_STAGE_PRE_INGRESS)); + // EXPECT_EQ(kAclGroupLookupOid, + // acl_groups.at(SAI_ACL_STAGE_PRE_INGRESS).m_saiObjectId); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_MIRROR_SESSION, KeyGenerator::generateMirrorSessionKey(gMirrorSession1), + kMirrorSessionOid1); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_MIRROR_SESSION, KeyGenerator::generateMirrorSessionKey(gMirrorSession2), + kMirrorSessionOid2); + } -class AclManagerTest : public ::testing::Test { - protected: - AclManagerTest() { - setUpMockApi(); - setUpCoppOrch(); - setUpSwitchOrch(); - setUpP4Orch(); - // const auto& acl_groups = gSwitchOrch->getAclGroupsBindingToSwitch(); - // EXPECT_EQ(3, acl_groups.size()); - // EXPECT_NE(acl_groups.end(), acl_groups.find(SAI_ACL_STAGE_INGRESS)); - // EXPECT_EQ(kAclGroupIngressOid, - // acl_groups.at(SAI_ACL_STAGE_INGRESS).m_saiObjectId); - // EXPECT_NE(acl_groups.end(), acl_groups.find(SAI_ACL_STAGE_EGRESS)); - // EXPECT_EQ(kAclGroupEgressOid, - // acl_groups.at(SAI_ACL_STAGE_EGRESS).m_saiObjectId); - // EXPECT_NE(acl_groups.end(), acl_groups.find(SAI_ACL_STAGE_PRE_INGRESS)); - // EXPECT_EQ(kAclGroupLookupOid, - // acl_groups.at(SAI_ACL_STAGE_PRE_INGRESS).m_saiObjectId); - p4_oid_mapper_->setOID( - SAI_OBJECT_TYPE_MIRROR_SESSION, - KeyGenerator::generateMirrorSessionKey(gMirrorSession1), - kMirrorSessionOid1); - p4_oid_mapper_->setOID( - SAI_OBJECT_TYPE_MIRROR_SESSION, - KeyGenerator::generateMirrorSessionKey(gMirrorSession2), - kMirrorSessionOid2); - } - - ~AclManagerTest() { cleanupAclManagerTest(); } - - void cleanupAclManagerTest() { - EXPECT_CALL(mock_sai_udf_, remove_udf_match(_)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - delete gP4Orch; - delete copp_orch_; - delete gSwitchOrch; - } - - void setUpMockApi() { - mock_sai_acl = &mock_sai_acl_; - mock_sai_serialize = &mock_sai_serialize_; - mock_sai_policer = &mock_sai_policer_; - mock_sai_hostif = &mock_sai_hostif_; - mock_sai_switch = &mock_sai_switch_; - mock_sai_udf = &mock_sai_udf_; - sai_acl_api->create_acl_table = create_acl_table; - sai_acl_api->remove_acl_table = remove_acl_table; - sai_acl_api->create_acl_table_group = create_acl_table_group; - sai_acl_api->remove_acl_table_group = remove_acl_table_group; - sai_acl_api->create_acl_table_group_member = create_acl_table_group_member; - sai_acl_api->remove_acl_table_group_member = remove_acl_table_group_member; - sai_acl_api->get_acl_counter_attribute = get_acl_counter_attribute; - sai_acl_api->create_acl_entry = create_acl_entry; - sai_acl_api->remove_acl_entry = remove_acl_entry; - sai_acl_api->set_acl_entry_attribute = set_acl_entry_attribute; - sai_acl_api->create_acl_counter = create_acl_counter; - sai_acl_api->remove_acl_counter = remove_acl_counter; - sai_policer_api->create_policer = create_policer; - sai_policer_api->remove_policer = remove_policer; - sai_policer_api->get_policer_stats = get_policer_stats; - sai_policer_api->set_policer_attribute = set_policer_attribute; - sai_hostif_api->create_hostif_table_entry = mock_create_hostif_table_entry; - sai_hostif_api->remove_hostif_table_entry = mock_remove_hostif_table_entry; - sai_hostif_api->create_hostif_trap_group = mock_create_hostif_trap_group; - sai_hostif_api->create_hostif_trap = mock_create_hostif_trap; - sai_hostif_api->create_hostif = mock_create_hostif; - sai_hostif_api->remove_hostif = mock_remove_hostif; - sai_hostif_api->create_hostif_user_defined_trap = - mock_create_hostif_user_defined_trap; - sai_hostif_api->remove_hostif_user_defined_trap = - mock_remove_hostif_user_defined_trap; - sai_switch_api->get_switch_attribute = mock_get_switch_attribute; - sai_switch_api->set_switch_attribute = mock_set_switch_attribute; - sai_udf_api->remove_udf = remove_udf; - sai_udf_api->create_udf = create_udf; - sai_udf_api->remove_udf_group = remove_udf_group; - sai_udf_api->create_udf_group = create_udf_group; - sai_udf_api->remove_udf_match = remove_udf_match; - sai_udf_api->create_udf_match = create_udf_match; - } - - void setUpCoppOrch() { - // init copp orch - EXPECT_CALL(mock_sai_hostif_, create_hostif_table_entry(_, _, _, _)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_hostif_, create_hostif_trap(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_switch_, get_switch_attribute(_, _, _)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - copp_orch_ = new CoppOrch(gAppDb, APP_COPP_TABLE_NAME); - // add trap group and genetlink for each CPU queue - swss::Table app_copp_table(gAppDb, APP_COPP_TABLE_NAME); - for (uint64_t queue_num = 1; queue_num <= P4_CPU_QUEUE_MAX_NUM; - queue_num++) { - std::vector attrs; - attrs.push_back({"queue", std::to_string(queue_num)}); - attrs.push_back({"genetlink_name", "genl_packet"}); - attrs.push_back({"genetlink_mcgrp_name", "packets"}); - app_copp_table.set( - GENL_PACKET_TRAP_GROUP_NAME_PREFIX + std::to_string(queue_num), - attrs); + ~AclManagerTest() + { + cleanupAclManagerTest(); } - sai_object_id_t trap_group_oid = gTrapGroupStartOid; - sai_object_id_t hostif_oid = gHostifStartOid; - EXPECT_CALL(mock_sai_hostif_, create_hostif_trap_group(_, _, _, _)) - .Times(P4_CPU_QUEUE_MAX_NUM) - .WillRepeatedly(DoAll( - Invoke([&trap_group_oid]( - sai_object_id_t* oid, sai_object_id_t switch_id, - uint32_t attr_count, const sai_attribute_t* attr_list) { - *oid = ++trap_group_oid; - }), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_hostif_, create_hostif(_, _, _, _)) - .Times(P4_CPU_QUEUE_MAX_NUM) - .WillRepeatedly(DoAll( - Invoke([&hostif_oid](sai_object_id_t* oid, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list) { - *oid = ++hostif_oid; - }), - Return(SAI_STATUS_SUCCESS))); - copp_orch_->addExistingData(&app_copp_table); - static_cast(copp_orch_)->doTask(); - } + void cleanupAclManagerTest() + { + EXPECT_CALL(mock_sai_udf_, remove_udf_match(_)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + delete gP4Orch; + delete copp_orch_; + delete gSwitchOrch; + } - void setUpSwitchOrch() { - EXPECT_CALL(mock_sai_serialize_, sai_serialize_object_id(_)) - .WillRepeatedly(Return(EMPTY_STRING)); - TableConnector stateDbSwitchTable(gStateDb, "SWITCH_CAPABILITY"); - TableConnector app_switch_table(gAppDb, APP_SWITCH_TABLE_NAME); - TableConnector conf_asic_sensors(gConfigDb, CFG_ASIC_SENSORS_TABLE_NAME); - std::vector switch_tables = {conf_asic_sensors, - app_switch_table}; - gSwitchOrch = new SwitchOrch(gAppDb, switch_tables, stateDbSwitchTable); - } - - void setUpP4Orch() { - EXPECT_CALL(mock_sai_serialize_, sai_serialize_object_id(_)) - .WillRepeatedly(Return(EMPTY_STRING)); - EXPECT_CALL( - mock_sai_acl_, - create_acl_table_group( - _, Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchSaiAttributeAclGroupStage, - SAI_ACL_STAGE_INGRESS, std::placeholders::_1)))) - .WillRepeatedly(DoAll(SetArgPointee<0>(kAclGroupIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL( - mock_sai_acl_, - create_acl_table_group( - _, Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchSaiAttributeAclGroupStage, - SAI_ACL_STAGE_EGRESS, std::placeholders::_1)))) - .WillRepeatedly(DoAll(SetArgPointee<0>(kAclGroupEgressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL( - mock_sai_acl_, - create_acl_table_group( - _, Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchSaiAttributeAclGroupStage, - SAI_ACL_STAGE_PRE_INGRESS, std::placeholders::_1)))) - .WillRepeatedly(DoAll(SetArgPointee<0>(kAclGroupLookupOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_switch_, - set_switch_attribute( - Eq(gSwitchId), Truly(std::bind(MatchSaiSwitchAttrByAclStage, - SAI_SWITCH_ATTR_INGRESS_ACL, - kAclGroupIngressOid, - std::placeholders::_1)))) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_switch_, - set_switch_attribute( - Eq(gSwitchId), Truly(std::bind(MatchSaiSwitchAttrByAclStage, - SAI_SWITCH_ATTR_EGRESS_ACL, - kAclGroupEgressOid, - std::placeholders::_1)))) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL( - mock_sai_switch_, - set_switch_attribute( - Eq(gSwitchId), - Truly(std::bind(MatchSaiSwitchAttrByAclStage, - SAI_SWITCH_ATTR_PRE_INGRESS_ACL, kAclGroupLookupOid, - std::placeholders::_1)))) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - std::vector p4_tables; - gP4Orch = new P4Orch(gAppDb, p4_tables, gVrfOrch, copp_orch_); - acl_table_manager_ = gP4Orch->getAclTableManager(); - acl_rule_manager_ = gP4Orch->getAclRuleManager(); - p4_oid_mapper_ = acl_table_manager_->m_p4OidMapper; - } - - void AddDefaultUserTrapsSaiCalls(sai_object_id_t* user_defined_trap_oid) { - EXPECT_CALL(mock_sai_hostif_, create_hostif_user_defined_trap(_, _, _, _)) - .Times(P4_CPU_QUEUE_MAX_NUM) - .WillRepeatedly(DoAll( - Invoke([user_defined_trap_oid]( - sai_object_id_t* oid, sai_object_id_t switch_id, - uint32_t attr_count, const sai_attribute_t* attr_list) { - *oid = ++(*user_defined_trap_oid); - }), - Return(SAI_STATUS_SUCCESS))); - } - - void AddDefaultIngressTable() { - const auto& app_db_entry = getDefaultAclTableDefAppDbEntry(); - EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), - Return(SAI_STATUS_SUCCESS))); + void setUpMockApi() + { + mock_sai_acl = &mock_sai_acl_; + mock_sai_serialize = &mock_sai_serialize_; + mock_sai_policer = &mock_sai_policer_; + mock_sai_hostif = &mock_sai_hostif_; + mock_sai_switch = &mock_sai_switch_; + mock_sai_udf = &mock_sai_udf_; + sai_acl_api->create_acl_table = create_acl_table; + sai_acl_api->remove_acl_table = remove_acl_table; + sai_acl_api->create_acl_table_group = create_acl_table_group; + sai_acl_api->remove_acl_table_group = remove_acl_table_group; + sai_acl_api->create_acl_table_group_member = create_acl_table_group_member; + sai_acl_api->remove_acl_table_group_member = remove_acl_table_group_member; + sai_acl_api->get_acl_counter_attribute = get_acl_counter_attribute; + sai_acl_api->create_acl_entry = create_acl_entry; + sai_acl_api->remove_acl_entry = remove_acl_entry; + sai_acl_api->set_acl_entry_attribute = set_acl_entry_attribute; + sai_acl_api->create_acl_counter = create_acl_counter; + sai_acl_api->remove_acl_counter = remove_acl_counter; + sai_policer_api->create_policer = create_policer; + sai_policer_api->remove_policer = remove_policer; + sai_policer_api->get_policer_stats = get_policer_stats; + sai_policer_api->set_policer_attribute = set_policer_attribute; + sai_hostif_api->create_hostif_table_entry = mock_create_hostif_table_entry; + sai_hostif_api->remove_hostif_table_entry = mock_remove_hostif_table_entry; + sai_hostif_api->create_hostif_trap_group = mock_create_hostif_trap_group; + sai_hostif_api->create_hostif_trap = mock_create_hostif_trap; + sai_hostif_api->create_hostif = mock_create_hostif; + sai_hostif_api->remove_hostif = mock_remove_hostif; + sai_hostif_api->create_hostif_user_defined_trap = mock_create_hostif_user_defined_trap; + sai_hostif_api->remove_hostif_user_defined_trap = mock_remove_hostif_user_defined_trap; + sai_switch_api->get_switch_attribute = mock_get_switch_attribute; + sai_switch_api->set_switch_attribute = mock_set_switch_attribute; + sai_udf_api->remove_udf = remove_udf; + sai_udf_api->create_udf = create_udf; + sai_udf_api->remove_udf_group = remove_udf_group; + sai_udf_api->create_udf_group = create_udf_group; + sai_udf_api->remove_udf_match = remove_udf_match; + sai_udf_api->create_udf_match = create_udf_match; + } + + void setUpCoppOrch() + { + // init copp orch + EXPECT_CALL(mock_sai_hostif_, create_hostif_table_entry(_, _, _, _)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_hostif_, create_hostif_trap(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_switch_, get_switch_attribute(_, _, _)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + copp_orch_ = new CoppOrch(gAppDb, APP_COPP_TABLE_NAME); + // add trap group and genetlink for each CPU queue + swss::Table app_copp_table(gAppDb, APP_COPP_TABLE_NAME); + for (uint64_t queue_num = 1; queue_num <= P4_CPU_QUEUE_MAX_NUM; queue_num++) + { + std::vector attrs; + attrs.push_back({"queue", std::to_string(queue_num)}); + attrs.push_back({"genetlink_name", "genl_packet"}); + attrs.push_back({"genetlink_mcgrp_name", "packets"}); + app_copp_table.set(GENL_PACKET_TRAP_GROUP_NAME_PREFIX + std::to_string(queue_num), attrs); + } + sai_object_id_t trap_group_oid = gTrapGroupStartOid; + sai_object_id_t hostif_oid = gHostifStartOid; + EXPECT_CALL(mock_sai_hostif_, create_hostif_trap_group(_, _, _, _)) + .Times(P4_CPU_QUEUE_MAX_NUM) + .WillRepeatedly( + DoAll(Invoke([&trap_group_oid](sai_object_id_t *oid, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) { *oid = ++trap_group_oid; }), + Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_hostif_, create_hostif(_, _, _, _)) + .Times(P4_CPU_QUEUE_MAX_NUM) + .WillRepeatedly( + DoAll(Invoke([&hostif_oid](sai_object_id_t *oid, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) { *oid = ++hostif_oid; }), + Return(SAI_STATUS_SUCCESS))); + + copp_orch_->addExistingData(&app_copp_table); + static_cast(copp_orch_)->doTask(); + } + + void setUpSwitchOrch() + { + EXPECT_CALL(mock_sai_serialize_, sai_serialize_object_id(_)).WillRepeatedly(Return(EMPTY_STRING)); + TableConnector stateDbSwitchTable(gStateDb, "SWITCH_CAPABILITY"); + TableConnector app_switch_table(gAppDb, APP_SWITCH_TABLE_NAME); + TableConnector conf_asic_sensors(gConfigDb, CFG_ASIC_SENSORS_TABLE_NAME); + std::vector switch_tables = {conf_asic_sensors, app_switch_table}; + gSwitchOrch = new SwitchOrch(gAppDb, switch_tables, stateDbSwitchTable); + } + + void setUpP4Orch() + { + EXPECT_CALL(mock_sai_serialize_, sai_serialize_object_id(_)).WillRepeatedly(Return(EMPTY_STRING)); + EXPECT_CALL(mock_sai_acl_, + create_acl_table_group( + _, Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchSaiAttributeAclGroupStage, SAI_ACL_STAGE_INGRESS, std::placeholders::_1)))) + .WillRepeatedly(DoAll(SetArgPointee<0>(kAclGroupIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, + create_acl_table_group( + _, Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchSaiAttributeAclGroupStage, SAI_ACL_STAGE_EGRESS, std::placeholders::_1)))) + .WillRepeatedly(DoAll(SetArgPointee<0>(kAclGroupEgressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, + create_acl_table_group(_, Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchSaiAttributeAclGroupStage, SAI_ACL_STAGE_PRE_INGRESS, + std::placeholders::_1)))) + .WillRepeatedly(DoAll(SetArgPointee<0>(kAclGroupLookupOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_switch_, + set_switch_attribute(Eq(gSwitchId), + Truly(std::bind(MatchSaiSwitchAttrByAclStage, SAI_SWITCH_ATTR_INGRESS_ACL, + kAclGroupIngressOid, std::placeholders::_1)))) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_switch_, + set_switch_attribute(Eq(gSwitchId), + Truly(std::bind(MatchSaiSwitchAttrByAclStage, SAI_SWITCH_ATTR_EGRESS_ACL, + kAclGroupEgressOid, std::placeholders::_1)))) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_switch_, + set_switch_attribute(Eq(gSwitchId), + Truly(std::bind(MatchSaiSwitchAttrByAclStage, SAI_SWITCH_ATTR_PRE_INGRESS_ACL, + kAclGroupLookupOid, std::placeholders::_1)))) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + std::vector p4_tables; + gP4Orch = new P4Orch(gAppDb, p4_tables, gVrfOrch, copp_orch_); + acl_table_manager_ = gP4Orch->getAclTableManager(); + acl_rule_manager_ = gP4Orch->getAclRuleManager(); + p4_oid_mapper_ = acl_table_manager_->m_p4OidMapper; + } + + void AddDefaultUserTrapsSaiCalls(sai_object_id_t *user_defined_trap_oid) + { + EXPECT_CALL(mock_sai_hostif_, create_hostif_user_defined_trap(_, _, _, _)) + .Times(P4_CPU_QUEUE_MAX_NUM) + .WillRepeatedly(DoAll(Invoke([user_defined_trap_oid]( + sai_object_id_t *oid, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) { *oid = ++(*user_defined_trap_oid); }), + Return(SAI_STATUS_SUCCESS))); + } + + void AddDefaultIngressTable() + { + const auto &app_db_entry = getDefaultAclTableDefAppDbEntry(); + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) + .Times(3) + .WillRepeatedly(DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) + .Times(3) + .WillRepeatedly(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; + AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); + ASSERT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddTableRequest(app_db_entry)); + ASSERT_NO_FATAL_FAILURE( + IsExpectedAclTableDefinitionMapping(*GetAclTable(app_db_entry.acl_table_name), app_db_entry)); + } + + void DrainTableTuples() + { + acl_table_manager_->drain(); + } + void EnqueueTableTuple(const swss::KeyOpFieldsValuesTuple &entry) + { + acl_table_manager_->enqueue(APP_P4RT_ACL_TABLE_DEFINITION_NAME, entry); + } + std::string VerifyTableState(const std::string &key, const std::vector &tuple) + { + return acl_table_manager_->verifyState(key, tuple); + } + + void DrainRuleTuples() + { + acl_rule_manager_->drain(); + } + void EnqueueRuleTuple(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) + { + acl_rule_manager_->enqueue(table_name, entry); + } + std::string VerifyRuleState(const std::string &key, const std::vector &tuple) + { + return acl_rule_manager_->verifyState(key, tuple); + } + + ReturnCodeOr DeserializeAclTableDefinitionAppDbEntry( + const std::string &key, const std::vector &attributes) + { + return acl_table_manager_->deserializeAclTableDefinitionAppDbEntry(key, attributes); + } + + ReturnCodeOr DeserializeAclRuleAppDbEntry(const std::string &acl_table_name, + const std::string &key, + const std::vector &attributes) + { + return acl_rule_manager_->deserializeAclRuleAppDbEntry(acl_table_name, key, attributes); + } + + P4AclTableDefinition *GetAclTable(const std::string &acl_table_name) + { + return acl_table_manager_->getAclTable(acl_table_name); + } + + P4AclRule *GetAclRule(const std::string &acl_table_name, const std::string &acl_rule_key) + { + return acl_rule_manager_->getAclRule(acl_table_name, acl_rule_key); + } + + ReturnCode ProcessAddTableRequest(const P4AclTableDefinitionAppDbEntry &app_db_entry) + { + return acl_table_manager_->processAddTableRequest(app_db_entry); + } + + ReturnCode ProcessDeleteTableRequest(const std::string &acl_table_name) + { + return acl_table_manager_->processDeleteTableRequest(acl_table_name); + } + + ReturnCode ProcessAddRuleRequest(const std::string &acl_rule_key, const P4AclRuleAppDbEntry &app_db_entry) + { + return acl_rule_manager_->processAddRuleRequest(acl_rule_key, app_db_entry); + } + + ReturnCode ProcessUpdateRuleRequest(const P4AclRuleAppDbEntry &app_db_entry, const P4AclRule &old_acl_rule) + { + return acl_rule_manager_->processUpdateRuleRequest(app_db_entry, old_acl_rule); + } + + ReturnCode ProcessDeleteRuleRequest(const std::string &acl_table_name, const std::string &acl_rule_key) + { + return acl_rule_manager_->processDeleteRuleRequest(acl_table_name, acl_rule_key); + } + + void DoAclCounterStatsTask() + { + acl_rule_manager_->doAclCounterStatsTask(); + } + + ReturnCode CreateAclGroupMember(const P4AclTableDefinition &acl_table, sai_object_id_t *acl_grp_mem_oid) + { + return acl_table_manager_->createAclGroupMember(acl_table, acl_grp_mem_oid); + } + + StrictMock mock_sai_acl_; + StrictMock mock_sai_serialize_; + StrictMock mock_sai_policer_; + StrictMock mock_sai_hostif_; + StrictMock mock_sai_switch_; + StrictMock mock_sai_udf_; + CoppOrch *copp_orch_; + P4OidMapper *p4_oid_mapper_; + p4orch::AclTableManager *acl_table_manager_; + p4orch::AclRuleManager *acl_rule_manager_; +}; + +TEST_F(AclManagerTest, DrainTableTuplesToProcessSetDelRequestSucceeds) +{ + const auto &p4rtAclTableName = + std::string(APP_P4RT_ACL_TABLE_DEFINITION_NAME) + kTableKeyDelimiter + kAclIngressTableName; + EnqueueTableTuple( + swss::KeyOpFieldsValuesTuple({p4rtAclTableName, SET_COMMAND, getDefaultTableDefFieldValueTuples()})); + + // Drain table tuples to process SET request + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, Eq(gSwitchId), Gt(2), + Truly(std::bind(MatchSaiAttributeAclTableStage, SAI_ACL_STAGE_INGRESS, + std::placeholders::_1)))) + .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, Eq(gSwitchId), Eq(3), NotNull())) + .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), Return(SAI_STATUS_SUCCESS))); EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); + .WillOnce(DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .Times(3) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); + .WillOnce(DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .Times(3) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; - AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); - ASSERT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddTableRequest(app_db_entry)); - ASSERT_NO_FATAL_FAILURE(IsExpectedAclTableDefinitionMapping( - *GetAclTable(app_db_entry.acl_table_name), app_db_entry)); - } - - void DrainTableTuples() { acl_table_manager_->drain(); } - void EnqueueTableTuple(const swss::KeyOpFieldsValuesTuple& entry) { - acl_table_manager_->enqueue(APP_P4RT_ACL_TABLE_DEFINITION_NAME, entry); - } - std::string VerifyTableState( - const std::string& key, const std::vector& tuple) { - return acl_table_manager_->verifyState(key, tuple); - } - - void DrainRuleTuples() { acl_rule_manager_->drain(); } - void EnqueueRuleTuple(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) { - acl_rule_manager_->enqueue(table_name, entry); - } - std::string VerifyRuleState(const std::string& key, - const std::vector& tuple) { - return acl_rule_manager_->verifyState(key, tuple); - } - - ReturnCodeOr - DeserializeAclTableDefinitionAppDbEntry( - const std::string& key, - const std::vector& attributes) { - return acl_table_manager_->deserializeAclTableDefinitionAppDbEntry( - key, attributes); - } - - ReturnCodeOr DeserializeAclRuleAppDbEntry( - const std::string& acl_table_name, const std::string& key, - const std::vector& attributes) { - return acl_rule_manager_->deserializeAclRuleAppDbEntry(acl_table_name, key, - attributes); - } - - P4AclTableDefinition* GetAclTable(const std::string& acl_table_name) { - return acl_table_manager_->getAclTable(acl_table_name); - } - - P4AclRule* GetAclRule(const std::string& acl_table_name, - const std::string& acl_rule_key) { - return acl_rule_manager_->getAclRule(acl_table_name, acl_rule_key); - } - - ReturnCode ProcessAddTableRequest( - const P4AclTableDefinitionAppDbEntry& app_db_entry) { - return acl_table_manager_->processAddTableRequest(app_db_entry); - } - - ReturnCode ProcessDeleteTableRequest(const std::string& acl_table_name) { - return acl_table_manager_->processDeleteTableRequest(acl_table_name); - } - - ReturnCode ProcessAddRuleRequest(const std::string& acl_rule_key, - const P4AclRuleAppDbEntry& app_db_entry) { - return acl_rule_manager_->processAddRuleRequest(acl_rule_key, app_db_entry); - } - - ReturnCode ProcessUpdateRuleRequest(const P4AclRuleAppDbEntry& app_db_entry, - const P4AclRule& old_acl_rule) { - return acl_rule_manager_->processUpdateRuleRequest(app_db_entry, - old_acl_rule); - } - - ReturnCode ProcessDeleteRuleRequest(const std::string& acl_table_name, - const std::string& acl_rule_key) { - return acl_rule_manager_->processDeleteRuleRequest(acl_table_name, - acl_rule_key); - } - - void DoAclCounterStatsTask() { acl_rule_manager_->doAclCounterStatsTask(); } - - ReturnCode CreateAclGroupMember(const P4AclTableDefinition& acl_table, - sai_object_id_t* acl_grp_mem_oid) { - return acl_table_manager_->createAclGroupMember(acl_table, acl_grp_mem_oid); - } - - StrictMock mock_sai_acl_; - StrictMock mock_sai_serialize_; - StrictMock mock_sai_policer_; - StrictMock mock_sai_hostif_; - StrictMock mock_sai_switch_; - StrictMock mock_sai_udf_; - CoppOrch* copp_orch_; - P4OidMapper* p4_oid_mapper_; - p4orch::AclTableManager* acl_table_manager_; - p4orch::AclRuleManager* acl_rule_manager_; -}; + .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + DrainTableTuples(); + EXPECT_NE(nullptr, GetAclTable(kAclIngressTableName)); -TEST_F(AclManagerTest, DrainTableTuplesToProcessSetDelRequestSucceeds) { - const auto& p4rtAclTableName = - std::string(APP_P4RT_ACL_TABLE_DEFINITION_NAME) + kTableKeyDelimiter + - kAclIngressTableName; - EnqueueTableTuple(swss::KeyOpFieldsValuesTuple( - {p4rtAclTableName, SET_COMMAND, getDefaultTableDefFieldValueTuples()})); - - // Drain table tuples to process SET request - EXPECT_CALL(mock_sai_acl_, - create_acl_table(_, Eq(gSwitchId), Gt(2), - Truly(std::bind(MatchSaiAttributeAclTableStage, - SAI_ACL_STAGE_INGRESS, - std::placeholders::_1)))) - .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, - create_acl_table_group_member(_, Eq(gSwitchId), Eq(3), NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - DrainTableTuples(); - EXPECT_NE(nullptr, GetAclTable(kAclIngressTableName)); - - // Drain table tuples to process DEL request - EXPECT_CALL(mock_sai_acl_, remove_acl_table(Eq(kAclTableIngressOid))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, - remove_acl_table_group_member(Eq(kAclGroupMemberIngressOid))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf_group(Eq(kUdfGroupOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EnqueueTableTuple( - swss::KeyOpFieldsValuesTuple({p4rtAclTableName, DEL_COMMAND, {}})); - DrainTableTuples(); - EXPECT_EQ(nullptr, GetAclTable(kAclIngressTableName)); + // Drain table tuples to process DEL request + EXPECT_CALL(mock_sai_acl_, remove_acl_table(Eq(kAclTableIngressOid))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(Eq(kAclGroupMemberIngressOid))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf_group(Eq(kUdfGroupOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EnqueueTableTuple(swss::KeyOpFieldsValuesTuple({p4rtAclTableName, DEL_COMMAND, {}})); + DrainTableTuples(); + EXPECT_EQ(nullptr, GetAclTable(kAclIngressTableName)); } -TEST_F(AclManagerTest, DrainTableTuplesToProcessUpdateRequestExpectFails) { - const auto& p4rtAclTableName = - std::string(APP_P4RT_ACL_TABLE_DEFINITION_NAME) + kTableKeyDelimiter + - kAclIngressTableName; - auto attributes = getDefaultTableDefFieldValueTuples(); - EnqueueTableTuple(swss::KeyOpFieldsValuesTuple( - {p4rtAclTableName, SET_COMMAND, attributes})); - - // Drain table tuples to process SET request, create a table with priority - // 234 - EXPECT_CALL(mock_sai_acl_, - create_acl_table(_, Eq(gSwitchId), Gt(2), - Truly(std::bind(MatchSaiAttributeAclTableStage, - SAI_ACL_STAGE_INGRESS, - std::placeholders::_1)))) - .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, - create_acl_table_group_member(_, Eq(gSwitchId), Eq(3), NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - - DrainTableTuples(); - EXPECT_NE(nullptr, GetAclTable(kAclIngressTableName)); - - // Drain table tuples to process SET request, try to update table priority - // to 100: should fail to update. - attributes.push_back(swss::FieldValueTuple{kPriority, "100"}); - EnqueueTableTuple(swss::KeyOpFieldsValuesTuple( - {p4rtAclTableName, SET_COMMAND, attributes})); - DrainTableTuples(); - EXPECT_EQ(234, GetAclTable(kAclIngressTableName)->priority); +TEST_F(AclManagerTest, DrainTableTuplesToProcessUpdateRequestExpectFails) +{ + const auto &p4rtAclTableName = + std::string(APP_P4RT_ACL_TABLE_DEFINITION_NAME) + kTableKeyDelimiter + kAclIngressTableName; + auto attributes = getDefaultTableDefFieldValueTuples(); + EnqueueTableTuple(swss::KeyOpFieldsValuesTuple({p4rtAclTableName, SET_COMMAND, attributes})); + + // Drain table tuples to process SET request, create a table with priority + // 234 + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, Eq(gSwitchId), Gt(2), + Truly(std::bind(MatchSaiAttributeAclTableStage, SAI_ACL_STAGE_INGRESS, + std::placeholders::_1)))) + .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, Eq(gSwitchId), Eq(3), NotNull())) + .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + + DrainTableTuples(); + EXPECT_NE(nullptr, GetAclTable(kAclIngressTableName)); + + // Drain table tuples to process SET request, try to update table priority + // to 100: should fail to update. + attributes.push_back(swss::FieldValueTuple{kPriority, "100"}); + EnqueueTableTuple(swss::KeyOpFieldsValuesTuple({p4rtAclTableName, SET_COMMAND, attributes})); + DrainTableTuples(); + EXPECT_EQ(234, GetAclTable(kAclIngressTableName)->priority); } -TEST_F(AclManagerTest, DrainTableTuplesWithInvalidTableNameOpsFails) { - auto p4rtAclTableName = - std::string("UNDEFINED") + kTableKeyDelimiter + kAclIngressTableName; - EnqueueTableTuple(swss::KeyOpFieldsValuesTuple( - {p4rtAclTableName, SET_COMMAND, getDefaultTableDefFieldValueTuples()})); - // Drain table tuples to process SET request on invalid ACL definition table - // name: "UNDEFINED" - DrainTableTuples(); - EXPECT_EQ(nullptr, GetAclTable(kAclIngressTableName)); - - p4rtAclTableName = std::string(APP_P4RT_ACL_TABLE_DEFINITION_NAME) + - kTableKeyDelimiter + kAclIngressTableName; - EnqueueTableTuple(swss::KeyOpFieldsValuesTuple( - {p4rtAclTableName, "UPDATE", getDefaultTableDefFieldValueTuples()})); - // Drain table tuples to process invalid operation: "UPDATE" - DrainTableTuples(); - EXPECT_EQ(nullptr, GetAclTable(kAclIngressTableName)); +TEST_F(AclManagerTest, DrainTableTuplesWithInvalidTableNameOpsFails) +{ + auto p4rtAclTableName = std::string("UNDEFINED") + kTableKeyDelimiter + kAclIngressTableName; + EnqueueTableTuple( + swss::KeyOpFieldsValuesTuple({p4rtAclTableName, SET_COMMAND, getDefaultTableDefFieldValueTuples()})); + // Drain table tuples to process SET request on invalid ACL definition table + // name: "UNDEFINED" + DrainTableTuples(); + EXPECT_EQ(nullptr, GetAclTable(kAclIngressTableName)); + + p4rtAclTableName = std::string(APP_P4RT_ACL_TABLE_DEFINITION_NAME) + kTableKeyDelimiter + kAclIngressTableName; + EnqueueTableTuple(swss::KeyOpFieldsValuesTuple({p4rtAclTableName, "UPDATE", getDefaultTableDefFieldValueTuples()})); + // Drain table tuples to process invalid operation: "UPDATE" + DrainTableTuples(); + EXPECT_EQ(nullptr, GetAclTable(kAclIngressTableName)); } -TEST_F(AclManagerTest, DrainTableTuplesWithInvalidFieldFails) { - auto attributes = getDefaultTableDefFieldValueTuples(); - const auto& p4rtAclTableName = - std::string(APP_P4RT_ACL_TABLE_DEFINITION_NAME) + kTableKeyDelimiter + - kAclIngressTableName; - - // Invalid attribute field - attributes.push_back(swss::FieldValueTuple{"undefined", "undefined"}); - EnqueueTableTuple(swss::KeyOpFieldsValuesTuple( - {p4rtAclTableName, SET_COMMAND, attributes})); - // Drain table tuples to process SET request - DrainTableTuples(); - EXPECT_EQ(nullptr, GetAclTable(kAclIngressTableName)); - - // Invalid attribute field - attributes.pop_back(); - attributes.push_back( - swss::FieldValueTuple{"undefined/undefined", "undefined"}); - EnqueueTableTuple(swss::KeyOpFieldsValuesTuple( - {p4rtAclTableName, SET_COMMAND, attributes})); - // Drain table tuples to process SET request - DrainTableTuples(); - EXPECT_EQ(nullptr, GetAclTable(kAclIngressTableName)); - - // Invalid meter unit value - attributes.pop_back(); - attributes.push_back(swss::FieldValueTuple{"meter/unit", "undefined"}); - EnqueueTableTuple(swss::KeyOpFieldsValuesTuple( - {p4rtAclTableName, SET_COMMAND, attributes})); - // Drain table tuples to process SET request - DrainTableTuples(); - EXPECT_EQ(nullptr, GetAclTable(kAclIngressTableName)); - - // Invalid counter unit value - attributes.pop_back(); - attributes.push_back(swss::FieldValueTuple{"counter/unit", "undefined"}); - EnqueueTableTuple(swss::KeyOpFieldsValuesTuple( - {p4rtAclTableName, SET_COMMAND, attributes})); - // Drain table tuples to process SET request - DrainTableTuples(); - EXPECT_EQ(nullptr, GetAclTable(kAclIngressTableName)); +TEST_F(AclManagerTest, DrainTableTuplesWithInvalidFieldFails) +{ + auto attributes = getDefaultTableDefFieldValueTuples(); + const auto &p4rtAclTableName = + std::string(APP_P4RT_ACL_TABLE_DEFINITION_NAME) + kTableKeyDelimiter + kAclIngressTableName; + + // Invalid attribute field + attributes.push_back(swss::FieldValueTuple{"undefined", "undefined"}); + EnqueueTableTuple(swss::KeyOpFieldsValuesTuple({p4rtAclTableName, SET_COMMAND, attributes})); + // Drain table tuples to process SET request + DrainTableTuples(); + EXPECT_EQ(nullptr, GetAclTable(kAclIngressTableName)); + + // Invalid attribute field + attributes.pop_back(); + attributes.push_back(swss::FieldValueTuple{"undefined/undefined", "undefined"}); + EnqueueTableTuple(swss::KeyOpFieldsValuesTuple({p4rtAclTableName, SET_COMMAND, attributes})); + // Drain table tuples to process SET request + DrainTableTuples(); + EXPECT_EQ(nullptr, GetAclTable(kAclIngressTableName)); + + // Invalid meter unit value + attributes.pop_back(); + attributes.push_back(swss::FieldValueTuple{"meter/unit", "undefined"}); + EnqueueTableTuple(swss::KeyOpFieldsValuesTuple({p4rtAclTableName, SET_COMMAND, attributes})); + // Drain table tuples to process SET request + DrainTableTuples(); + EXPECT_EQ(nullptr, GetAclTable(kAclIngressTableName)); + + // Invalid counter unit value + attributes.pop_back(); + attributes.push_back(swss::FieldValueTuple{"counter/unit", "undefined"}); + EnqueueTableTuple(swss::KeyOpFieldsValuesTuple({p4rtAclTableName, SET_COMMAND, attributes})); + // Drain table tuples to process SET request + DrainTableTuples(); + EXPECT_EQ(nullptr, GetAclTable(kAclIngressTableName)); } -TEST_F(AclManagerTest, CreateIngressPuntTableSucceeds) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto acl_table = GetAclTable(kAclIngressTableName); - EXPECT_NE(nullptr, acl_table); - sai_object_id_t grp_member_oid; - sai_object_id_t grp_oid; - sai_object_id_t table_oid; - EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER, - kAclIngressTableName, &grp_member_oid)); - EXPECT_EQ(kAclGroupMemberIngressOid, grp_member_oid); - EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_ACL_TABLE, - kAclIngressTableName, &table_oid)); - EXPECT_EQ(kAclTableIngressOid, table_oid); - // The ACL group creation logic is moved out from P4Orch to SwitchOrch - EXPECT_FALSE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_ACL_TABLE_GROUP, - kAclIngressTableName, &grp_oid)); - const auto& acl_groups = gSwitchOrch->getAclGroupsBindingToSwitch(); - ASSERT_NE(acl_groups.end(), acl_groups.find(SAI_ACL_STAGE_INGRESS)); - EXPECT_EQ(1, acl_groups.at(SAI_ACL_STAGE_INGRESS).m_objsDependingOnMe.size()); - EXPECT_NE( - acl_groups.at(SAI_ACL_STAGE_INGRESS).m_objsDependingOnMe.end(), - acl_groups.at(SAI_ACL_STAGE_INGRESS) - .m_objsDependingOnMe.find(sai_serialize_object_id(grp_member_oid))); +TEST_F(AclManagerTest, CreateIngressPuntTableSucceeds) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto acl_table = GetAclTable(kAclIngressTableName); + EXPECT_NE(nullptr, acl_table); + sai_object_id_t grp_member_oid; + sai_object_id_t grp_oid; + sai_object_id_t table_oid; + EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER, kAclIngressTableName, &grp_member_oid)); + EXPECT_EQ(kAclGroupMemberIngressOid, grp_member_oid); + EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_ACL_TABLE, kAclIngressTableName, &table_oid)); + EXPECT_EQ(kAclTableIngressOid, table_oid); + // The ACL group creation logic is moved out from P4Orch to SwitchOrch + EXPECT_FALSE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_ACL_TABLE_GROUP, kAclIngressTableName, &grp_oid)); + const auto &acl_groups = gSwitchOrch->getAclGroupsBindingToSwitch(); + ASSERT_NE(acl_groups.end(), acl_groups.find(SAI_ACL_STAGE_INGRESS)); + EXPECT_EQ(1, acl_groups.at(SAI_ACL_STAGE_INGRESS).m_objsDependingOnMe.size()); + EXPECT_NE(acl_groups.at(SAI_ACL_STAGE_INGRESS).m_objsDependingOnMe.end(), + acl_groups.at(SAI_ACL_STAGE_INGRESS).m_objsDependingOnMe.find(sai_serialize_object_id(grp_member_oid))); } -TEST_F(AclManagerTest, CreatePuntTableFailsWhenUserTrapsSaiCallFails) { - auto app_db_entry = getDefaultAclTableDefAppDbEntry(); - EXPECT_CALL(mock_sai_hostif_, create_hostif_user_defined_trap(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(gUserDefinedTrapStartOid + 1), - Return(SAI_STATUS_SUCCESS))) - .WillOnce(Return(SAI_STATUS_INSUFFICIENT_RESOURCES)); - EXPECT_CALL(mock_sai_hostif_, create_hostif_table_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(gHostifStartOid + 1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_hostif_, - remove_hostif_table_entry(Eq(gHostifStartOid + 1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_hostif_, - remove_hostif_user_defined_trap(Eq(gUserDefinedTrapStartOid + 1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - // The user defined traps fail to create - EXPECT_EQ(StatusCode::SWSS_RC_FULL, ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - sai_object_id_t oid; - EXPECT_FALSE(p4_oid_mapper_->getOID( - SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP, - std::to_string(gUserDefinedTrapStartOid + 1), &oid)); - - EXPECT_CALL(mock_sai_hostif_, create_hostif_user_defined_trap(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(gUserDefinedTrapStartOid + 1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_hostif_, create_hostif_table_entry(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_INSUFFICIENT_RESOURCES)); - EXPECT_CALL(mock_sai_hostif_, - remove_hostif_user_defined_trap(Eq(gUserDefinedTrapStartOid + 1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - // The hostif table entry fails to create - EXPECT_EQ(StatusCode::SWSS_RC_FULL, ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - EXPECT_CALL(mock_sai_hostif_, create_hostif_user_defined_trap(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(gUserDefinedTrapStartOid + 1), - Return(SAI_STATUS_SUCCESS))) - .WillOnce(Return(SAI_STATUS_INSUFFICIENT_RESOURCES)); - EXPECT_CALL(mock_sai_hostif_, create_hostif_table_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(gHostifStartOid + 1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_hostif_, - remove_hostif_table_entry(Eq(gHostifStartOid + 1))) - .WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); - // The 2nd user defined trap fails to create, the 1st hostif table entry fails - // to remove - EXPECT_EQ(StatusCode::SWSS_RC_FULL, ProcessAddTableRequest(app_db_entry)); +TEST_F(AclManagerTest, CreatePuntTableFailsWhenUserTrapsSaiCallFails) +{ + auto app_db_entry = getDefaultAclTableDefAppDbEntry(); + EXPECT_CALL(mock_sai_hostif_, create_hostif_user_defined_trap(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(gUserDefinedTrapStartOid + 1), Return(SAI_STATUS_SUCCESS))) + .WillOnce(Return(SAI_STATUS_INSUFFICIENT_RESOURCES)); + EXPECT_CALL(mock_sai_hostif_, create_hostif_table_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(gHostifStartOid + 1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_hostif_, remove_hostif_table_entry(Eq(gHostifStartOid + 1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_hostif_, remove_hostif_user_defined_trap(Eq(gUserDefinedTrapStartOid + 1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + // The user defined traps fail to create + EXPECT_EQ(StatusCode::SWSS_RC_FULL, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + sai_object_id_t oid; + EXPECT_FALSE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_HOSTIF_USER_DEFINED_TRAP, + std::to_string(gUserDefinedTrapStartOid + 1), &oid)); + + EXPECT_CALL(mock_sai_hostif_, create_hostif_user_defined_trap(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(gUserDefinedTrapStartOid + 1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_hostif_, create_hostif_table_entry(_, _, _, _)) + .WillOnce(Return(SAI_STATUS_INSUFFICIENT_RESOURCES)); + EXPECT_CALL(mock_sai_hostif_, remove_hostif_user_defined_trap(Eq(gUserDefinedTrapStartOid + 1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + // The hostif table entry fails to create + EXPECT_EQ(StatusCode::SWSS_RC_FULL, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + EXPECT_CALL(mock_sai_hostif_, create_hostif_user_defined_trap(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(gUserDefinedTrapStartOid + 1), Return(SAI_STATUS_SUCCESS))) + .WillOnce(Return(SAI_STATUS_INSUFFICIENT_RESOURCES)); + EXPECT_CALL(mock_sai_hostif_, create_hostif_table_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(gHostifStartOid + 1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_hostif_, remove_hostif_table_entry(Eq(gHostifStartOid + 1))) + .WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); + // The 2nd user defined trap fails to create, the 1st hostif table entry fails + // to remove + EXPECT_EQ(StatusCode::SWSS_RC_FULL, ProcessAddTableRequest(app_db_entry)); } -TEST_F(AclManagerTest, - DISABLED_CreatePuntTableFailsWhenUserTrapGroupOrHostifNotFound) { - auto app_db_entry = getDefaultAclTableDefAppDbEntry(); - const auto skip_cpu_queue = 1; - // init copp orch - EXPECT_CALL(mock_sai_hostif_, create_hostif_table_entry(_, _, _, _)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_hostif_, create_hostif_trap(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_switch_, get_switch_attribute(_, _, _)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - swss::Table app_copp_table(gAppDb, APP_COPP_TABLE_NAME); - // Clean up APP_COPP_TABLE_NAME table entries - for (int queue_num = 1; queue_num <= P4_CPU_QUEUE_MAX_NUM; queue_num++) { - app_copp_table.del(GENL_PACKET_TRAP_GROUP_NAME_PREFIX + - std::to_string(queue_num)); - } - cleanupAclManagerTest(); - copp_orch_ = new CoppOrch(gAppDb, APP_COPP_TABLE_NAME); - setUpSwitchOrch(); - // Update p4orch to use new copp orch - setUpP4Orch(); - // Fail to create ACL table because the trap group is absent - EXPECT_EQ("Trap group was not found given trap group name: " + - std::string(GENL_PACKET_TRAP_GROUP_NAME_PREFIX) + - std::to_string(skip_cpu_queue), - ProcessAddTableRequest(app_db_entry).message()); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Create the trap group for CPU queue 1 without host interface(genl - // attributes) - std::vector attrs; - attrs.push_back({"queue", std::to_string(skip_cpu_queue)}); - // Add one COPP_TABLE entry with trap group info, without hostif info - app_copp_table.set( - GENL_PACKET_TRAP_GROUP_NAME_PREFIX + std::to_string(skip_cpu_queue), - attrs); - copp_orch_->addExistingData(&app_copp_table); - EXPECT_CALL(mock_sai_hostif_, create_hostif_trap_group(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(gTrapGroupStartOid + skip_cpu_queue), - Return(SAI_STATUS_SUCCESS))); - static_cast(copp_orch_)->doTask(); - // Fail to create ACL table because the host interface is absent - EXPECT_EQ("Hostif object id was not found given trap group - " + - std::string(GENL_PACKET_TRAP_GROUP_NAME_PREFIX) + - std::to_string(skip_cpu_queue), - ProcessAddTableRequest(app_db_entry).message()); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); +TEST_F(AclManagerTest, DISABLED_CreatePuntTableFailsWhenUserTrapGroupOrHostifNotFound) +{ + auto app_db_entry = getDefaultAclTableDefAppDbEntry(); + const auto skip_cpu_queue = 1; + // init copp orch + EXPECT_CALL(mock_sai_hostif_, create_hostif_table_entry(_, _, _, _)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_hostif_, create_hostif_trap(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_switch_, get_switch_attribute(_, _, _)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + swss::Table app_copp_table(gAppDb, APP_COPP_TABLE_NAME); + // Clean up APP_COPP_TABLE_NAME table entries + for (int queue_num = 1; queue_num <= P4_CPU_QUEUE_MAX_NUM; queue_num++) + { + app_copp_table.del(GENL_PACKET_TRAP_GROUP_NAME_PREFIX + std::to_string(queue_num)); + } + cleanupAclManagerTest(); + copp_orch_ = new CoppOrch(gAppDb, APP_COPP_TABLE_NAME); + setUpSwitchOrch(); + // Update p4orch to use new copp orch + setUpP4Orch(); + // Fail to create ACL table because the trap group is absent + EXPECT_EQ("Trap group was not found given trap group name: " + std::string(GENL_PACKET_TRAP_GROUP_NAME_PREFIX) + + std::to_string(skip_cpu_queue), + ProcessAddTableRequest(app_db_entry).message()); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Create the trap group for CPU queue 1 without host interface(genl + // attributes) + std::vector attrs; + attrs.push_back({"queue", std::to_string(skip_cpu_queue)}); + // Add one COPP_TABLE entry with trap group info, without hostif info + app_copp_table.set(GENL_PACKET_TRAP_GROUP_NAME_PREFIX + std::to_string(skip_cpu_queue), attrs); + copp_orch_->addExistingData(&app_copp_table); + EXPECT_CALL(mock_sai_hostif_, create_hostif_trap_group(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(gTrapGroupStartOid + skip_cpu_queue), Return(SAI_STATUS_SUCCESS))); + static_cast(copp_orch_)->doTask(); + // Fail to create ACL table because the host interface is absent + EXPECT_EQ("Hostif object id was not found given trap group - " + std::string(GENL_PACKET_TRAP_GROUP_NAME_PREFIX) + + std::to_string(skip_cpu_queue), + ProcessAddTableRequest(app_db_entry).message()); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); } -TEST_F(AclManagerTest, CreateIngressPuntTableFailsWhenCapabilityExceeds) { - auto app_db_entry = getDefaultAclTableDefAppDbEntry(); - sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; - AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); - EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .Times(3) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_INSUFFICIENT_RESOURCES)); - EXPECT_CALL(mock_sai_udf_, remove_udf_group(Eq(kUdfGroupOid1))) - .Times(3) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf(_)) - .Times(3) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_FULL, ProcessAddTableRequest(app_db_entry)); +TEST_F(AclManagerTest, CreateIngressPuntTableFailsWhenCapabilityExceeds) +{ + auto app_db_entry = getDefaultAclTableDefAppDbEntry(); + sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; + AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); + EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) + .Times(3) + .WillRepeatedly(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)).WillOnce(Return(SAI_STATUS_INSUFFICIENT_RESOURCES)); + EXPECT_CALL(mock_sai_udf_, remove_udf_group(Eq(kUdfGroupOid1))).Times(3).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf(_)).Times(3).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_FULL, ProcessAddTableRequest(app_db_entry)); } -TEST_F(AclManagerTest, - CreateIngressPuntTableFailsWhenFailedToCreateTableGroupMember) { - auto app_db_entry = getDefaultAclTableDefAppDbEntry(); - sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; - AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); - EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .Times(3) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf_group(Eq(kUdfGroupOid1))) - .Times(3) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf(_)) - .Times(3) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddTableRequest(app_db_entry)); +TEST_F(AclManagerTest, CreateIngressPuntTableFailsWhenFailedToCreateTableGroupMember) +{ + auto app_db_entry = getDefaultAclTableDefAppDbEntry(); + sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; + AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); + EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) + .Times(3) + .WillRepeatedly(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)).WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf_group(Eq(kUdfGroupOid1))).Times(3).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf(_)).Times(3).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddTableRequest(app_db_entry)); } -TEST_F(AclManagerTest, - CreateIngressPuntTableRaisesCriticalStateWhenAclTableRecoveryFails) { - auto app_db_entry = getDefaultAclTableDefAppDbEntry(); - sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; - AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); - EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .Times(3) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_udf_, remove_udf_group(Eq(kUdfGroupOid1))) - .Times(3) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf(_)) - .Times(3) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddTableRequest(app_db_entry)); +TEST_F(AclManagerTest, CreateIngressPuntTableRaisesCriticalStateWhenAclTableRecoveryFails) +{ + auto app_db_entry = getDefaultAclTableDefAppDbEntry(); + sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; + AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); + EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) + .Times(3) + .WillRepeatedly(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)).WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)).WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_udf_, remove_udf_group(Eq(kUdfGroupOid1))).Times(3).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf(_)).Times(3).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddTableRequest(app_db_entry)); } -TEST_F(AclManagerTest, - CreateIngressPuntTableRaisesCriticalStateWhenUdfGroupRecoveryFails) { - auto app_db_entry = getDefaultAclTableDefAppDbEntry(); - sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; - AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); - EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .Times(3) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf_group(Eq(kUdfGroupOid1))) - .Times(3) - .WillRepeatedly(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_udf_, remove_udf(_)) - .Times(3) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - // TODO: Expect critical state x3. - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddTableRequest(app_db_entry)); +TEST_F(AclManagerTest, CreateIngressPuntTableRaisesCriticalStateWhenUdfGroupRecoveryFails) +{ + auto app_db_entry = getDefaultAclTableDefAppDbEntry(); + sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; + AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); + EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) + .Times(3) + .WillRepeatedly(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)).WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf_group(Eq(kUdfGroupOid1))).Times(3).WillRepeatedly(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_udf_, remove_udf(_)).Times(3).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + // TODO: Expect critical state x3. + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddTableRequest(app_db_entry)); } -TEST_F(AclManagerTest, - CreateIngressPuntTableRaisesCriticalStateWhenUdfRecoveryFails) { - auto app_db_entry = getDefaultAclTableDefAppDbEntry(); - sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; - AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); - EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .Times(3) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - // UDF recovery failure will also cause UDF group recovery failure since the - // reference count will not be zero if UDF failed to be removed. - EXPECT_CALL(mock_sai_udf_, remove_udf(_)) - .Times(3) - .WillRepeatedly(Return(SAI_STATUS_FAILURE)); - // TODO: Expect critical state x6. - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddTableRequest(app_db_entry)); +TEST_F(AclManagerTest, CreateIngressPuntTableRaisesCriticalStateWhenUdfRecoveryFails) +{ + auto app_db_entry = getDefaultAclTableDefAppDbEntry(); + sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; + AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); + EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) + .Times(3) + .WillRepeatedly(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)).WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + // UDF recovery failure will also cause UDF group recovery failure since the + // reference count will not be zero if UDF failed to be removed. + EXPECT_CALL(mock_sai_udf_, remove_udf(_)).Times(3).WillRepeatedly(Return(SAI_STATUS_FAILURE)); + // TODO: Expect critical state x6. + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddTableRequest(app_db_entry)); } -TEST_F(AclManagerTest, CreateIngressPuntTableFailsWhenFailedToCreateUdf) { - auto app_db_entry = getDefaultAclTableDefAppDbEntry(); - sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; - AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); - // Fail to create the first UDF, and success to remove the first UDF - // group - EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_udf_, remove_udf_group(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddTableRequest(app_db_entry)); - EXPECT_FALSE(p4_oid_mapper_->existsOID( - SAI_OBJECT_TYPE_UDF, - std::string(kAclIngressTableName) + "-arp_tpa-0-base1-offset24")); - EXPECT_FALSE(p4_oid_mapper_->existsOID( - SAI_OBJECT_TYPE_UDF_GROUP, - std::string(kAclIngressTableName) + "-arp_tpa-0")); - - // Fail to create the second UDF group, and success to remove the first UDF - // group and UDF - EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, remove_udf_group(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddTableRequest(app_db_entry)); - EXPECT_FALSE(p4_oid_mapper_->existsOID( - SAI_OBJECT_TYPE_UDF, - std::string(kAclIngressTableName) + "-arp_tpa-0-base1-offset24")); - EXPECT_FALSE(p4_oid_mapper_->existsOID( - SAI_OBJECT_TYPE_UDF_GROUP, - std::string(kAclIngressTableName) + "-arp_tpa-0")); - - // Fail to create the second UDF group, and fail to remove the first UDF - // group - EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, remove_udf_group(_)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_udf_, remove_udf(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddTableRequest(app_db_entry)); - EXPECT_FALSE(p4_oid_mapper_->existsOID( - SAI_OBJECT_TYPE_UDF, - std::string(kAclIngressTableName) + "-arp_tpa-0-base1-offset24")); - EXPECT_TRUE(p4_oid_mapper_->existsOID( - SAI_OBJECT_TYPE_UDF_GROUP, - std::string(kAclIngressTableName) + "-arp_tpa-0")); - p4_oid_mapper_->eraseOID(SAI_OBJECT_TYPE_UDF_GROUP, - std::string(kAclIngressTableName) + "-arp_tpa-0"); - - // Fail to create the second UDF group, and fail to remove the first UDF and - // UDF group - EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, remove_udf(_)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - // TODO: Expect critical state x2. - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddTableRequest(app_db_entry)); - EXPECT_TRUE(p4_oid_mapper_->existsOID( - SAI_OBJECT_TYPE_UDF, - std::string(kAclIngressTableName) + "-arp_tpa-0-base1-offset24")); - EXPECT_TRUE(p4_oid_mapper_->existsOID( - SAI_OBJECT_TYPE_UDF_GROUP, - std::string(kAclIngressTableName) + "-arp_tpa-0")); +TEST_F(AclManagerTest, CreateIngressPuntTableFailsWhenFailedToCreateUdf) +{ + auto app_db_entry = getDefaultAclTableDefAppDbEntry(); + sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; + AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); + // Fail to create the first UDF, and success to remove the first UDF + // group + EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)).WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_udf_, remove_udf_group(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddTableRequest(app_db_entry)); + EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_UDF, + std::string(kAclIngressTableName) + "-arp_tpa-0-base1-offset24")); + EXPECT_FALSE( + p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_UDF_GROUP, std::string(kAclIngressTableName) + "-arp_tpa-0")); + + // Fail to create the second UDF group, and success to remove the first UDF + // group and UDF + EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, remove_udf_group(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddTableRequest(app_db_entry)); + EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_UDF, + std::string(kAclIngressTableName) + "-arp_tpa-0-base1-offset24")); + EXPECT_FALSE( + p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_UDF_GROUP, std::string(kAclIngressTableName) + "-arp_tpa-0")); + + // Fail to create the second UDF group, and fail to remove the first UDF + // group + EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, remove_udf_group(_)).WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_udf_, remove_udf(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddTableRequest(app_db_entry)); + EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_UDF, + std::string(kAclIngressTableName) + "-arp_tpa-0-base1-offset24")); + EXPECT_TRUE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_UDF_GROUP, std::string(kAclIngressTableName) + "-arp_tpa-0")); + p4_oid_mapper_->eraseOID(SAI_OBJECT_TYPE_UDF_GROUP, std::string(kAclIngressTableName) + "-arp_tpa-0"); + + // Fail to create the second UDF group, and fail to remove the first UDF and + // UDF group + EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, remove_udf(_)).WillOnce(Return(SAI_STATUS_FAILURE)); + // TODO: Expect critical state x2. + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddTableRequest(app_db_entry)); + EXPECT_TRUE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_UDF, + std::string(kAclIngressTableName) + "-arp_tpa-0-base1-offset24")); + EXPECT_TRUE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_UDF_GROUP, std::string(kAclIngressTableName) + "-arp_tpa-0")); } -TEST_F(AclManagerTest, CreatePuntTableWithInvalidStageFails) { - auto app_db_entry = getDefaultAclTableDefAppDbEntry(); - // Invalid stage - app_db_entry.stage = "RANDOM"; +TEST_F(AclManagerTest, CreatePuntTableWithInvalidStageFails) +{ + auto app_db_entry = getDefaultAclTableDefAppDbEntry(); + // Invalid stage + app_db_entry.stage = "RANDOM"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); } -TEST_F(AclManagerTest, CreatePuntTableWithInvalidSaiMatchFieldFails) { - auto app_db_entry = getDefaultAclTableDefAppDbEntry(); - // Invalid SAI match field - app_db_entry.match_field_lookup["random"] = - BuildMatchFieldJsonStrKindSaiField("RANDOM"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - app_db_entry.match_field_lookup.erase("random"); - - // Invalid match field str - should be JSON str - app_db_entry.match_field_lookup["ether_type"] = P4_MATCH_ETHER_TYPE; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - should be object instead of array - app_db_entry.match_field_lookup["ether_type"] = - "[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_" - "ETHER_TYPE\",\"format\":\"HEX_STRING\",\"bitwidth\":8}]"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - missing kind - app_db_entry.match_field_lookup["ether_type"] = - "{\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE\",\"format\":" - "\"HEX_STRING\",\"bitwidth\":8}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - invalid kind - app_db_entry.match_field_lookup["ether_type"] = - "{\"kind\":\"field\",\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_ETHER_" - "TYPE\",\"format\":\"HEX_STRING\",\"bitwidth\":8}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - missing format - app_db_entry.match_field_lookup["ether_type"] = - "{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_" - "ETHER_TYPE\",\"bitwidth\":8}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - invalid format - app_db_entry.match_field_lookup["ether_type"] = - "{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_" - "ETHER_TYPE\",\"format\":\"INVALID_TYPE\",\"bitwidth\":8}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - not expected format for the field - app_db_entry.match_field_lookup["ether_type"] = - "{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_" - "ETHER_TYPE\",\"format\":\"IPV4\",\"bitwidth\":8}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - missing bitwidth - app_db_entry.match_field_lookup["ether_type"] = - "{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_" - "ETHER_TYPE\",\"format\":\"HEX_STRING\"}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - missing sai_field - app_db_entry.match_field_lookup["ether_type"] = - "{\"kind\":\"sai_field\",\"format\":\"HEX_STRING\",\"bitwidth\":8}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Unsupported IP_TYPE bit type - app_db_entry.match_field_lookup.erase("ether_type"); - app_db_entry.match_field_lookup["is_non_ip"] = - BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + - kFieldDelimiter + "NONIP"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); +TEST_F(AclManagerTest, CreatePuntTableWithInvalidSaiMatchFieldFails) +{ + auto app_db_entry = getDefaultAclTableDefAppDbEntry(); + // Invalid SAI match field + app_db_entry.match_field_lookup["random"] = BuildMatchFieldJsonStrKindSaiField("RANDOM"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + app_db_entry.match_field_lookup.erase("random"); + + // Invalid match field str - should be JSON str + app_db_entry.match_field_lookup["ether_type"] = P4_MATCH_ETHER_TYPE; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - should be object instead of array + app_db_entry.match_field_lookup["ether_type"] = "[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_" + "ETHER_TYPE\",\"format\":\"HEX_STRING\",\"bitwidth\":8}]"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - missing kind + app_db_entry.match_field_lookup["ether_type"] = "{\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE\",\"format\":" + "\"HEX_STRING\",\"bitwidth\":8}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - invalid kind + app_db_entry.match_field_lookup["ether_type"] = + "{\"kind\":\"field\",\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_ETHER_" + "TYPE\",\"format\":\"HEX_STRING\",\"bitwidth\":8}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - missing format + app_db_entry.match_field_lookup["ether_type"] = "{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_" + "ETHER_TYPE\",\"bitwidth\":8}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - invalid format + app_db_entry.match_field_lookup["ether_type"] = "{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_" + "ETHER_TYPE\",\"format\":\"INVALID_TYPE\",\"bitwidth\":8}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - not expected format for the field + app_db_entry.match_field_lookup["ether_type"] = "{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_" + "ETHER_TYPE\",\"format\":\"IPV4\",\"bitwidth\":8}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - missing bitwidth + app_db_entry.match_field_lookup["ether_type"] = "{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_" + "ETHER_TYPE\",\"format\":\"HEX_STRING\"}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - missing sai_field + app_db_entry.match_field_lookup["ether_type"] = "{\"kind\":\"sai_field\",\"format\":\"HEX_STRING\",\"bitwidth\":8}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Unsupported IP_TYPE bit type + app_db_entry.match_field_lookup.erase("ether_type"); + app_db_entry.match_field_lookup["is_non_ip"] = + BuildMatchFieldJsonStrKindSaiField(std::string(P4_MATCH_IP_TYPE) + kFieldDelimiter + "NONIP"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); } -TEST_F(AclManagerTest, CreatePuntTableWithInvalidCompositeSaiMatchFieldFails) { - auto app_db_entry = getDefaultAclTableDefAppDbEntry(); - - // Invalid match field str - missing format - app_db_entry.match_field_lookup["src_ipv6_64bit"] = - "{\"kind\":\"composite\",\"bitwidth\":64," - "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" - "ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":32},{\"kind\":\"sai_field\"," - "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":" - "32}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - invalid format - app_db_entry.match_field_lookup["src_ipv6_64bit"] = - "{\"kind\":\"composite\",\"format\":\"IPV4\",\"bitwidth\":64," - "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" - "ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":32},{\"kind\":\"sai_field\"," - "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":" - "32}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - invalid total bitwidth - app_db_entry.match_field_lookup["src_ipv6_64bit"] = - "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":65," - "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" - "ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":32},{\"kind\":\"sai_field\"," - "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":" - "32}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - missing element.bitwidth - app_db_entry.match_field_lookup["src_ipv6_64bit"] = - "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":64," - "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" - "ATTR_FIELD_SRC_IPV6_WORD3\"},{\"kind\":\"sai_field\"," - "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":" - "32}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - invalid element.bitwidth - app_db_entry.match_field_lookup["src_ipv6_64bit"] = - "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":63," - "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" - "ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":31},{\"kind\":\"sai_field\"," - "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":" - "32}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - invalid element kind - app_db_entry.match_field_lookup["src_ipv6_64bit"] = - "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":64," - "\"elements\":[{\"kind\":\"field\",\"sai_field\":\"SAI_ACL_TABLE_" - "ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":32},{\"kind\":\"sai_field\"," - "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":" - "32}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - missing element.sai_field - app_db_entry.match_field_lookup["src_ipv6_64bit"] = - "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":64," - "\"elements\":[{\"kind\":\"sai_field\",\"bitwidth\":32},{\"kind\":\"sai_" - "field\",\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\"," - "\"bitwidth\":32}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - invalid element.sai_field - app_db_entry.match_field_lookup["src_ipv6_64bit"] = - "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":64," - "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" - "ATTR_FIELD_SRC_IPV6\",\"bitwidth\":32},{\"kind\":\"sai_field\"," - "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":" - "32}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - invalid elements length - app_db_entry.match_field_lookup["src_ipv6_64bit"] = - "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":64," - "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" - "ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":32}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - invalid first element.sai_field - app_db_entry.match_field_lookup["src_ipv6_64bit"] = - "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":64," - "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" - "ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":32},{\"kind\":\"sai_field\"," - "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":" - "32}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - invalid second element.sai_field - app_db_entry.match_field_lookup["src_ipv6_64bit"] = - "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":64," - "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" - "ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":32},{\"kind\":\"sai_field\"," - "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":" - "32}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); +TEST_F(AclManagerTest, CreatePuntTableWithInvalidCompositeSaiMatchFieldFails) +{ + auto app_db_entry = getDefaultAclTableDefAppDbEntry(); + + // Invalid match field str - missing format + app_db_entry.match_field_lookup["src_ipv6_64bit"] = + "{\"kind\":\"composite\",\"bitwidth\":64," + "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" + "ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":32},{\"kind\":\"sai_field\"," + "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":" + "32}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - invalid format + app_db_entry.match_field_lookup["src_ipv6_64bit"] = + "{\"kind\":\"composite\",\"format\":\"IPV4\",\"bitwidth\":64," + "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" + "ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":32},{\"kind\":\"sai_field\"," + "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":" + "32}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - invalid total bitwidth + app_db_entry.match_field_lookup["src_ipv6_64bit"] = + "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":65," + "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" + "ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":32},{\"kind\":\"sai_field\"," + "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":" + "32}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - missing element.bitwidth + app_db_entry.match_field_lookup["src_ipv6_64bit"] = + "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":64," + "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" + "ATTR_FIELD_SRC_IPV6_WORD3\"},{\"kind\":\"sai_field\"," + "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":" + "32}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - invalid element.bitwidth + app_db_entry.match_field_lookup["src_ipv6_64bit"] = + "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":63," + "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" + "ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":31},{\"kind\":\"sai_field\"," + "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":" + "32}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - invalid element kind + app_db_entry.match_field_lookup["src_ipv6_64bit"] = + "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":64," + "\"elements\":[{\"kind\":\"field\",\"sai_field\":\"SAI_ACL_TABLE_" + "ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":32},{\"kind\":\"sai_field\"," + "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":" + "32}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - missing element.sai_field + app_db_entry.match_field_lookup["src_ipv6_64bit"] = + "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":64," + "\"elements\":[{\"kind\":\"sai_field\",\"bitwidth\":32},{\"kind\":\"sai_" + "field\",\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\"," + "\"bitwidth\":32}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - invalid element.sai_field + app_db_entry.match_field_lookup["src_ipv6_64bit"] = + "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":64," + "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" + "ATTR_FIELD_SRC_IPV6\",\"bitwidth\":32},{\"kind\":\"sai_field\"," + "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":" + "32}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - invalid elements length + app_db_entry.match_field_lookup["src_ipv6_64bit"] = + "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":64," + "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" + "ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":32}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - invalid first element.sai_field + app_db_entry.match_field_lookup["src_ipv6_64bit"] = + "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":64," + "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" + "ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":32},{\"kind\":\"sai_field\"," + "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD2\",\"bitwidth\":" + "32}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - invalid second element.sai_field + app_db_entry.match_field_lookup["src_ipv6_64bit"] = + "{\"kind\":\"composite\",\"format\":\"IPV6\",\"bitwidth\":64," + "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" + "ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":32},{\"kind\":\"sai_field\"," + "\"sai_field\":\"SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":" + "32}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); } -TEST_F(AclManagerTest, CreatePuntTableWithInvalidCompositeUdfMatchFieldFails) { - auto app_db_entry = getDefaultAclTableDefAppDbEntry(); - - // Invalid match field str - missing format - app_db_entry.match_field_lookup["arp_tpa"] = - "{\"kind\":\"composite\",\"bitwidth\":32," - "\"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"format\":" - "\"IPV4\",\"bitwidth\":16,\"offset\":24},{\"kind\":\"udf\",\"base\":" - "\"SAI_UDF_BASE_L3\",\"format\":\"IPV4\",\"bitwidth\":" - "16,\"offset\":26}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - invalid format - app_db_entry.match_field_lookup["arp_tpa"] = - "{\"kind\":\"composite\",\"format\":\"IP\",\"bitwidth\":32," - "\"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"format\":" - "\"IPV6\",\"bitwidth\":16,\"offset\":24},{\"kind\":\"udf\",\"base\":" - "\"SAI_UDF_BASE_L3\",\"format\":\"IPV4\",\"bitwidth\":" - "16,\"offset\":26}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - invalid total bitwidth - app_db_entry.match_field_lookup["arp_tpa"] = - "{\"kind\":\"composite\",\"format\":\"IPV4\",\"bitwidth\":33," - "\"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"format\":" - "\"IPV4\",\"bitwidth\":16,\"offset\":24},{\"kind\":" - "\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"format\":\"IPV4\",\"bitwidth\":" - "16,\"offset\":26}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - missing element.kind - app_db_entry.match_field_lookup["arp_tpa"] = - "{\"kind\":\"composite\",\"format\":\"IPV4\",\"bitwidth\":32," - "\"elements\":[{\"base\":\"SAI_UDF_BASE_L3\",\"format\":" - "\"IPV4\",\"bitwidth\":15,\"offset\":24},{\"kind\":\"udf\",\"base\":" - "\"SAI_UDF_BASE_L3\",\"format\":\"IPV4\",\"bitwidth\":" - "16,\"offset\":26}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - inconsistent element.kind - app_db_entry.match_field_lookup["arp_tpa"] = - "{\"kind\":\"composite\",\"format\":\"IPV4\",\"bitwidth\":32," - "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" - "ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":32},{\"kind\":\"udf\",\"base\":" - "\"SAI_UDF_BASE_L3\",\"bitwidth\":" - "16,\"offset\":26}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - missing element.bitwidth - app_db_entry.match_field_lookup["arp_tpa"] = - "{\"kind\":\"composite\",\"format\":\"HEX_STRING\",\"bitwidth\":32," - "\"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"offset\":" - "24},{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"bitwidth\":" - "16,\"offset\":26}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - invalid element.bitwidth - app_db_entry.match_field_lookup["arp_tpa"] = - "{\"kind\":\"composite\",\"format\":\"HEX_STRING\",\"bitwidth\":31," - "\"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\"," - "\"bitwidth\":15,\"offset\":24},{\"kind\":\"udf\",\"base\":\"SAI_UDF_" - "BASE_L3\",\"bitwidth\":" - "16,\"offset\":26}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - invalid element.base - app_db_entry.match_field_lookup["arp_tpa"] = - "{\"kind\":\"composite\",\"format\":\"HEX_STRING\",\"bitwidth\":32," - "\"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE\",\"bitwidth\":" - "16,\"offset\":24},{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\"," - "\"bitwidth\":" - "16,\"offset\":26}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - missing element.base - app_db_entry.match_field_lookup["arp_tpa"] = - "{\"kind\":\"composite\",\"format\":\"HEX_STRING\",\"bitwidth\":32," - "\"elements\":[{\"kind\":\"udf\",\"bitwidth\":16,\"offset\":24},{" - "\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"bitwidth\":" - "16,\"offset\":26}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - missing element.offset - app_db_entry.match_field_lookup["arp_tpa"] = - "{\"kind\":\"composite\",\"format\":\"HEX_STRING\",\"bitwidth\":32," - "\"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\"," - "\"bitwidth\":16},{\"kind\":" - "\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"bitwidth\":" - "16,\"offset\":26}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - elements is empty - app_db_entry.match_field_lookup["arp_tpa"] = - "{\"kind\":\"composite\",\"format\":\"HEX_STRING\",\"bitwidth\":32," - "\"elements\":[]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - invalid element, should be an object - app_db_entry.match_field_lookup["arp_tpa"] = - "{\"kind\":\"composite\",\"format\":\"HEX_STRING\",\"bitwidth\":32," - "\"elements\":[\"group-1\"]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - - // Invalid match field str - missing bitwidth - app_db_entry.match_field_lookup["arp_tpa"] = - "{\"kind\":\"composite\",\"format\":\"HEX_STRING\"," - "\"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\"," - "\"bitwidth\":16,\"offset\":24},{\"kind\":" - "\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"bitwidth\":" - "16,\"offset\":26}]}"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); +TEST_F(AclManagerTest, CreatePuntTableWithInvalidCompositeUdfMatchFieldFails) +{ + auto app_db_entry = getDefaultAclTableDefAppDbEntry(); + + // Invalid match field str - missing format + app_db_entry.match_field_lookup["arp_tpa"] = + "{\"kind\":\"composite\",\"bitwidth\":32," + "\"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"format\":" + "\"IPV4\",\"bitwidth\":16,\"offset\":24},{\"kind\":\"udf\",\"base\":" + "\"SAI_UDF_BASE_L3\",\"format\":\"IPV4\",\"bitwidth\":" + "16,\"offset\":26}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - invalid format + app_db_entry.match_field_lookup["arp_tpa"] = + "{\"kind\":\"composite\",\"format\":\"IP\",\"bitwidth\":32," + "\"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"format\":" + "\"IPV6\",\"bitwidth\":16,\"offset\":24},{\"kind\":\"udf\",\"base\":" + "\"SAI_UDF_BASE_L3\",\"format\":\"IPV4\",\"bitwidth\":" + "16,\"offset\":26}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - invalid total bitwidth + app_db_entry.match_field_lookup["arp_tpa"] = + "{\"kind\":\"composite\",\"format\":\"IPV4\",\"bitwidth\":33," + "\"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"format\":" + "\"IPV4\",\"bitwidth\":16,\"offset\":24},{\"kind\":" + "\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"format\":\"IPV4\",\"bitwidth\":" + "16,\"offset\":26}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - missing element.kind + app_db_entry.match_field_lookup["arp_tpa"] = "{\"kind\":\"composite\",\"format\":\"IPV4\",\"bitwidth\":32," + "\"elements\":[{\"base\":\"SAI_UDF_BASE_L3\",\"format\":" + "\"IPV4\",\"bitwidth\":15,\"offset\":24},{\"kind\":\"udf\",\"base\":" + "\"SAI_UDF_BASE_L3\",\"format\":\"IPV4\",\"bitwidth\":" + "16,\"offset\":26}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - inconsistent element.kind + app_db_entry.match_field_lookup["arp_tpa"] = + "{\"kind\":\"composite\",\"format\":\"IPV4\",\"bitwidth\":32," + "\"elements\":[{\"kind\":\"sai_field\",\"sai_field\":\"SAI_ACL_TABLE_" + "ATTR_FIELD_SRC_IPV6_WORD3\",\"bitwidth\":32},{\"kind\":\"udf\",\"base\":" + "\"SAI_UDF_BASE_L3\",\"bitwidth\":" + "16,\"offset\":26}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - missing element.bitwidth + app_db_entry.match_field_lookup["arp_tpa"] = + "{\"kind\":\"composite\",\"format\":\"HEX_STRING\",\"bitwidth\":32," + "\"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"offset\":" + "24},{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"bitwidth\":" + "16,\"offset\":26}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - invalid element.bitwidth + app_db_entry.match_field_lookup["arp_tpa"] = "{\"kind\":\"composite\",\"format\":\"HEX_STRING\",\"bitwidth\":31," + "\"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\"," + "\"bitwidth\":15,\"offset\":24},{\"kind\":\"udf\",\"base\":\"SAI_UDF_" + "BASE_L3\",\"bitwidth\":" + "16,\"offset\":26}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - invalid element.base + app_db_entry.match_field_lookup["arp_tpa"] = + "{\"kind\":\"composite\",\"format\":\"HEX_STRING\",\"bitwidth\":32," + "\"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE\",\"bitwidth\":" + "16,\"offset\":24},{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\"," + "\"bitwidth\":" + "16,\"offset\":26}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - missing element.base + app_db_entry.match_field_lookup["arp_tpa"] = "{\"kind\":\"composite\",\"format\":\"HEX_STRING\",\"bitwidth\":32," + "\"elements\":[{\"kind\":\"udf\",\"bitwidth\":16,\"offset\":24},{" + "\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"bitwidth\":" + "16,\"offset\":26}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - missing element.offset + app_db_entry.match_field_lookup["arp_tpa"] = "{\"kind\":\"composite\",\"format\":\"HEX_STRING\",\"bitwidth\":32," + "\"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\"," + "\"bitwidth\":16},{\"kind\":" + "\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"bitwidth\":" + "16,\"offset\":26}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - elements is empty + app_db_entry.match_field_lookup["arp_tpa"] = "{\"kind\":\"composite\",\"format\":\"HEX_STRING\",\"bitwidth\":32," + "\"elements\":[]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - invalid element, should be an object + app_db_entry.match_field_lookup["arp_tpa"] = "{\"kind\":\"composite\",\"format\":\"HEX_STRING\",\"bitwidth\":32," + "\"elements\":[\"group-1\"]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + + // Invalid match field str - missing bitwidth + app_db_entry.match_field_lookup["arp_tpa"] = "{\"kind\":\"composite\",\"format\":\"HEX_STRING\"," + "\"elements\":[{\"kind\":\"udf\",\"base\":\"SAI_UDF_BASE_L3\"," + "\"bitwidth\":16,\"offset\":24},{\"kind\":" + "\"udf\",\"base\":\"SAI_UDF_BASE_L3\",\"bitwidth\":" + "16,\"offset\":26}]}"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); } -TEST_F(AclManagerTest, CreatePuntTableWithInvalidActionFieldFails) { - auto app_db_entry = getDefaultAclTableDefAppDbEntry(); +TEST_F(AclManagerTest, CreatePuntTableWithInvalidActionFieldFails) +{ + auto app_db_entry = getDefaultAclTableDefAppDbEntry(); - // Invalid action field - app_db_entry.action_field_lookup["random_action"].push_back( - {.sai_action = "RANDOM_ACTION", .p4_param_name = "DUMMY"}); + // Invalid action field + app_db_entry.action_field_lookup["random_action"].push_back( + {.sai_action = "RANDOM_ACTION", .p4_param_name = "DUMMY"}); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); } -TEST_F(AclManagerTest, CreatePuntTableWithInvalidPacketColorFieldFails) { - auto app_db_entry = getDefaultAclTableDefAppDbEntry(); - sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; - AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); +TEST_F(AclManagerTest, CreatePuntTableWithInvalidPacketColorFieldFails) +{ + auto app_db_entry = getDefaultAclTableDefAppDbEntry(); + sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; + AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); - // Invalid packet_color field - app_db_entry.packet_action_color_lookup["invalid_packet_color"].push_back( - {.packet_action = P4_PACKET_ACTION_PUNT, .packet_color = "DUMMY"}); + // Invalid packet_color field + app_db_entry.packet_action_color_lookup["invalid_packet_color"].push_back( + {.packet_action = P4_PACKET_ACTION_PUNT, .packet_color = "DUMMY"}); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); - // Invalid packet_action field - app_db_entry.packet_action_color_lookup.erase("invalid_packet_color"); - app_db_entry.packet_action_color_lookup["invalid_packet_action"].push_back( - {.packet_action = "PUNT", .packet_color = P4_PACKET_COLOR_GREEN}); + // Invalid packet_action field + app_db_entry.packet_action_color_lookup.erase("invalid_packet_color"); + app_db_entry.packet_action_color_lookup["invalid_packet_action"].push_back( + {.packet_action = "PUNT", .packet_color = P4_PACKET_COLOR_GREEN}); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddTableRequest(app_db_entry)); - EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddTableRequest(app_db_entry)); + EXPECT_EQ(nullptr, GetAclTable(app_db_entry.acl_table_name)); } -TEST_F(AclManagerTest, CreateAclGroupMemberFailsWhenAclGroupWasNotFound) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto* acl_table = GetAclTable(kAclIngressTableName); - acl_table->stage = SAI_ACL_STAGE_INGRESS_MACSEC; - sai_object_id_t grp_member_oid; - EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), - Return(SAI_STATUS_SUCCESS))); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, - CreateAclGroupMember(*acl_table, &grp_member_oid)); +TEST_F(AclManagerTest, CreateAclGroupMemberFailsWhenAclGroupWasNotFound) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto *acl_table = GetAclTable(kAclIngressTableName); + acl_table->stage = SAI_ACL_STAGE_INGRESS_MACSEC; + sai_object_id_t grp_member_oid; + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), Return(SAI_STATUS_SUCCESS))); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, CreateAclGroupMember(*acl_table, &grp_member_oid)); } -TEST_F(AclManagerTest, DeserializeValidAclTableDefAppDbSucceeds) { - auto app_db_entry_or = DeserializeAclTableDefinitionAppDbEntry( - kAclIngressTableName, getDefaultTableDefFieldValueTuples()); - EXPECT_TRUE(app_db_entry_or.ok()); - auto& app_db_entry = *app_db_entry_or; - EXPECT_EQ(kAclIngressTableName, app_db_entry.acl_table_name); - EXPECT_EQ(123, app_db_entry.size); - EXPECT_EQ(STAGE_INGRESS, app_db_entry.stage); - EXPECT_EQ(234, app_db_entry.priority); - EXPECT_EQ(P4_METER_UNIT_BYTES, app_db_entry.meter_unit); - EXPECT_EQ(P4_COUNTER_UNIT_BOTH, app_db_entry.counter_unit); - EXPECT_EQ(BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ETHER_TYPE), - app_db_entry.match_field_lookup.find("ether_type")->second); - EXPECT_EQ(BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_MAC, P4_FORMAT_MAC), - app_db_entry.match_field_lookup.find("ether_dst")->second); - EXPECT_EQ( - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_IPV6, P4_FORMAT_IPV6), - app_db_entry.match_field_lookup.find("ipv6_dst")->second); - EXPECT_EQ(BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IPV6_NEXT_HEADER), - app_db_entry.match_field_lookup.find("ipv6_next_header")->second); - EXPECT_EQ(BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TTL), - app_db_entry.match_field_lookup.find("ttl")->second); - EXPECT_EQ(BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ICMP_TYPE), - app_db_entry.match_field_lookup.find("icmp_type")->second); - EXPECT_EQ(BuildMatchFieldJsonStrKindSaiField(P4_MATCH_L4_DST_PORT), - app_db_entry.match_field_lookup.find("l4_dst_port")->second); - EXPECT_EQ(P4_ACTION_SET_TRAFFIC_CLASS, - app_db_entry.action_field_lookup.find("copy_and_set_tc") - ->second[0] - .sai_action); - EXPECT_EQ("traffic_class", - app_db_entry.action_field_lookup.find("copy_and_set_tc") - ->second[0] - .p4_param_name); - EXPECT_EQ(P4_ACTION_SET_TRAFFIC_CLASS, - app_db_entry.action_field_lookup.find("punt_and_set_tc") - ->second[0] - .sai_action); - EXPECT_EQ("traffic_class", - app_db_entry.action_field_lookup.find("punt_and_set_tc") - ->second[0] - .p4_param_name); - EXPECT_EQ(P4_PACKET_ACTION_COPY, - app_db_entry.packet_action_color_lookup.find("copy_and_set_tc") - ->second[0] - .packet_action); - EXPECT_EQ(P4_PACKET_COLOR_GREEN, - app_db_entry.packet_action_color_lookup.find("copy_and_set_tc") - ->second[0] - .packet_color); - EXPECT_EQ(P4_PACKET_ACTION_PUNT, - app_db_entry.packet_action_color_lookup.find("punt_and_set_tc") - ->second[0] - .packet_action); - EXPECT_EQ(EMPTY_STRING, - app_db_entry.packet_action_color_lookup.find("punt_and_set_tc") - ->second[0] - .packet_color); +TEST_F(AclManagerTest, DeserializeValidAclTableDefAppDbSucceeds) +{ + auto app_db_entry_or = + DeserializeAclTableDefinitionAppDbEntry(kAclIngressTableName, getDefaultTableDefFieldValueTuples()); + EXPECT_TRUE(app_db_entry_or.ok()); + auto &app_db_entry = *app_db_entry_or; + EXPECT_EQ(kAclIngressTableName, app_db_entry.acl_table_name); + EXPECT_EQ(123, app_db_entry.size); + EXPECT_EQ(STAGE_INGRESS, app_db_entry.stage); + EXPECT_EQ(234, app_db_entry.priority); + EXPECT_EQ(P4_METER_UNIT_BYTES, app_db_entry.meter_unit); + EXPECT_EQ(P4_COUNTER_UNIT_BOTH, app_db_entry.counter_unit); + EXPECT_EQ(BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ETHER_TYPE), + app_db_entry.match_field_lookup.find("ether_type")->second); + EXPECT_EQ(BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_MAC, P4_FORMAT_MAC), + app_db_entry.match_field_lookup.find("ether_dst")->second); + EXPECT_EQ(BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_IPV6, P4_FORMAT_IPV6), + app_db_entry.match_field_lookup.find("ipv6_dst")->second); + EXPECT_EQ(BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IPV6_NEXT_HEADER), + app_db_entry.match_field_lookup.find("ipv6_next_header")->second); + EXPECT_EQ(BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TTL), app_db_entry.match_field_lookup.find("ttl")->second); + EXPECT_EQ(BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ICMP_TYPE), + app_db_entry.match_field_lookup.find("icmp_type")->second); + EXPECT_EQ(BuildMatchFieldJsonStrKindSaiField(P4_MATCH_L4_DST_PORT), + app_db_entry.match_field_lookup.find("l4_dst_port")->second); + EXPECT_EQ(P4_ACTION_SET_TRAFFIC_CLASS, + app_db_entry.action_field_lookup.find("copy_and_set_tc")->second[0].sai_action); + EXPECT_EQ("traffic_class", app_db_entry.action_field_lookup.find("copy_and_set_tc")->second[0].p4_param_name); + EXPECT_EQ(P4_ACTION_SET_TRAFFIC_CLASS, + app_db_entry.action_field_lookup.find("punt_and_set_tc")->second[0].sai_action); + EXPECT_EQ("traffic_class", app_db_entry.action_field_lookup.find("punt_and_set_tc")->second[0].p4_param_name); + EXPECT_EQ(P4_PACKET_ACTION_COPY, + app_db_entry.packet_action_color_lookup.find("copy_and_set_tc")->second[0].packet_action); + EXPECT_EQ(P4_PACKET_COLOR_GREEN, + app_db_entry.packet_action_color_lookup.find("copy_and_set_tc")->second[0].packet_color); + EXPECT_EQ(P4_PACKET_ACTION_PUNT, + app_db_entry.packet_action_color_lookup.find("punt_and_set_tc")->second[0].packet_action); + EXPECT_EQ(EMPTY_STRING, app_db_entry.packet_action_color_lookup.find("punt_and_set_tc")->second[0].packet_color); } -TEST_F(AclManagerTest, DeserializeAclTableDefAppDbWithInvalidJsonFails) { - std::string acl_table_name = kAclIngressTableName; - auto attributes = getDefaultTableDefFieldValueTuples(); - - // Invalid action JSON - attributes.push_back(swss::FieldValueTuple{ - "action/drop_and_set_tc", - "[{\"action\":\"SAI_PACKET_ACTION_COPY\";\"packet_color\":\"SAI_PACKET_" - "COLOR_GREEN\"};{\"action\":\"SAI_ACL_ENTRY_ATTR_ACTION_SET_TC\";" - "\"param\":\"traffic_class\"}]"}); - EXPECT_FALSE( - DeserializeAclTableDefinitionAppDbEntry(acl_table_name, attributes).ok()); - - attributes.pop_back(); - attributes.push_back(swss::FieldValueTuple{ - "action/drop_and_set_tc", - "[{\"action\"-\"SAI_PACKET_ACTION_COPY\",\"packet_color\"-\"SAI_PACKET_" - "COLOR_GREEN\"},{\"action\"-\"SAI_ACL_ENTRY_ATTR_ACTION_SET_TC\"," - "\"param\"-\"traffic_class\"}]"}); - EXPECT_FALSE( - DeserializeAclTableDefinitionAppDbEntry(acl_table_name, attributes).ok()); - - attributes.pop_back(); - attributes.push_back(swss::FieldValueTuple{ - "action/drop_and_set_tc", "[\"action\":\"SAI_PACKET_ACTION_COPY\"]"}); - EXPECT_FALSE( - DeserializeAclTableDefinitionAppDbEntry(acl_table_name, attributes).ok()); +TEST_F(AclManagerTest, DeserializeAclTableDefAppDbWithInvalidJsonFails) +{ + std::string acl_table_name = kAclIngressTableName; + auto attributes = getDefaultTableDefFieldValueTuples(); + + // Invalid action JSON + attributes.push_back(swss::FieldValueTuple{"action/drop_and_set_tc", + "[{\"action\":\"SAI_PACKET_ACTION_COPY\";\"packet_color\":\"SAI_PACKET_" + "COLOR_GREEN\"};{\"action\":\"SAI_ACL_ENTRY_ATTR_ACTION_SET_TC\";" + "\"param\":\"traffic_class\"}]"}); + EXPECT_FALSE(DeserializeAclTableDefinitionAppDbEntry(acl_table_name, attributes).ok()); + + attributes.pop_back(); + attributes.push_back(swss::FieldValueTuple{"action/drop_and_set_tc", + "[{\"action\"-\"SAI_PACKET_ACTION_COPY\",\"packet_color\"-\"SAI_PACKET_" + "COLOR_GREEN\"},{\"action\"-\"SAI_ACL_ENTRY_ATTR_ACTION_SET_TC\"," + "\"param\"-\"traffic_class\"}]"}); + EXPECT_FALSE(DeserializeAclTableDefinitionAppDbEntry(acl_table_name, attributes).ok()); + + attributes.pop_back(); + attributes.push_back(swss::FieldValueTuple{"action/drop_and_set_tc", "[\"action\":\"SAI_PACKET_ACTION_COPY\"]"}); + EXPECT_FALSE(DeserializeAclTableDefinitionAppDbEntry(acl_table_name, attributes).ok()); } -TEST_F(AclManagerTest, DeserializeAclTableDefAppDbWithInvalidSizeFails) { - std::string acl_table_name = kAclIngressTableName; - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{kStage, STAGE_INGRESS}); - attributes.push_back(swss::FieldValueTuple{kPriority, "234"}); - attributes.push_back( - swss::FieldValueTuple{"meter/unit", P4_METER_UNIT_BYTES}); - attributes.push_back( - swss::FieldValueTuple{"counter/unit", P4_COUNTER_UNIT_BOTH}); - attributes.push_back(swss::FieldValueTuple{ - "match/ether_type", - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ETHER_TYPE)}); - attributes.push_back(swss::FieldValueTuple{ - "match/ether_dst", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_MAC)}); - attributes.push_back(swss::FieldValueTuple{ - "match/ipv6_dst", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_IPV6)}); - attributes.push_back(swss::FieldValueTuple{ - "match/ipv6_next_header", - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IPV6_NEXT_HEADER)}); - attributes.push_back(swss::FieldValueTuple{ - "match/ttl", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TTL)}); - attributes.push_back(swss::FieldValueTuple{ - "match/icmp_type", - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ICMP_TYPE)}); - attributes.push_back(swss::FieldValueTuple{ - "match/l4_dst_port", - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_L4_DST_PORT)}); - attributes.push_back(swss::FieldValueTuple{ - "action/copy_and_set_tc", - "[{\"action\":\"SAI_PACKET_ACTION_COPY\",\"packet_color\":\"SAI_PACKET_" - "COLOR_GREEN\"},{\"action\":\"SAI_ACL_ENTRY_ATTR_ACTION_SET_TC\"," - "\"param\":\"traffic_class\"}]"}); - attributes.push_back(swss::FieldValueTuple{ - "action/punt_and_set_tc", - "[{\"action\":\"SAI_PACKET_ACTION_TRAP\"},{\"action\":\"SAI_ACL_ENTRY_" - "ATTR_ACTION_SET_TC\",\"param\":\"traffic_class\"}]"}); - - // Invalid table size - attributes.push_back(swss::FieldValueTuple{kSize, "-123"}); - EXPECT_FALSE( - DeserializeAclTableDefinitionAppDbEntry(acl_table_name, attributes).ok()); +TEST_F(AclManagerTest, DeserializeAclTableDefAppDbWithInvalidSizeFails) +{ + std::string acl_table_name = kAclIngressTableName; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{kStage, STAGE_INGRESS}); + attributes.push_back(swss::FieldValueTuple{kPriority, "234"}); + attributes.push_back(swss::FieldValueTuple{"meter/unit", P4_METER_UNIT_BYTES}); + attributes.push_back(swss::FieldValueTuple{"counter/unit", P4_COUNTER_UNIT_BOTH}); + attributes.push_back( + swss::FieldValueTuple{"match/ether_type", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ETHER_TYPE)}); + attributes.push_back( + swss::FieldValueTuple{"match/ether_dst", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_MAC)}); + attributes.push_back( + swss::FieldValueTuple{"match/ipv6_dst", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_IPV6)}); + attributes.push_back( + swss::FieldValueTuple{"match/ipv6_next_header", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IPV6_NEXT_HEADER)}); + attributes.push_back(swss::FieldValueTuple{"match/ttl", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TTL)}); + attributes.push_back( + swss::FieldValueTuple{"match/icmp_type", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ICMP_TYPE)}); + attributes.push_back( + swss::FieldValueTuple{"match/l4_dst_port", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_L4_DST_PORT)}); + attributes.push_back(swss::FieldValueTuple{"action/copy_and_set_tc", + "[{\"action\":\"SAI_PACKET_ACTION_COPY\",\"packet_color\":\"SAI_PACKET_" + "COLOR_GREEN\"},{\"action\":\"SAI_ACL_ENTRY_ATTR_ACTION_SET_TC\"," + "\"param\":\"traffic_class\"}]"}); + attributes.push_back(swss::FieldValueTuple{"action/punt_and_set_tc", + "[{\"action\":\"SAI_PACKET_ACTION_TRAP\"},{\"action\":\"SAI_ACL_ENTRY_" + "ATTR_ACTION_SET_TC\",\"param\":\"traffic_class\"}]"}); + + // Invalid table size + attributes.push_back(swss::FieldValueTuple{kSize, "-123"}); + EXPECT_FALSE(DeserializeAclTableDefinitionAppDbEntry(acl_table_name, attributes).ok()); } -TEST_F(AclManagerTest, DeserializeAclTableDefAppDbWithInvalidPriorityFails) { - std::string acl_table_name = kAclIngressTableName; - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{kStage, STAGE_INGRESS}); - attributes.push_back(swss::FieldValueTuple{kSize, "234"}); - attributes.push_back( - swss::FieldValueTuple{"meter/unit", P4_METER_UNIT_BYTES}); - attributes.push_back( - swss::FieldValueTuple{"counter/unit", P4_COUNTER_UNIT_BOTH}); - attributes.push_back(swss::FieldValueTuple{ - "match/ether_type", - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ETHER_TYPE)}); - attributes.push_back(swss::FieldValueTuple{ - "match/ether_dst", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_MAC)}); - attributes.push_back(swss::FieldValueTuple{ - "match/ipv6_dst", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_IPV6)}); - attributes.push_back(swss::FieldValueTuple{ - "match/ipv6_next_header", - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IPV6_NEXT_HEADER)}); - attributes.push_back(swss::FieldValueTuple{ - "match/ttl", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TTL)}); - attributes.push_back(swss::FieldValueTuple{ - "match/icmp_type", - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ICMP_TYPE)}); - attributes.push_back(swss::FieldValueTuple{ - "match/l4_dst_port", - BuildMatchFieldJsonStrKindSaiField(P4_MATCH_L4_DST_PORT)}); - attributes.push_back(swss::FieldValueTuple{ - "action/copy_and_set_tc", - "[{\"action\":\"SAI_PACKET_ACTION_COPY\",\"packet_color\":\"SAI_PACKET_" - "COLOR_GREEN\"},{\"action\":\"SAI_ACL_ENTRY_ATTR_ACTION_SET_TC\"," - "\"param\":\"traffic_class\"}]"}); - attributes.push_back(swss::FieldValueTuple{ - "action/punt_and_set_tc", - "[{\"action\":\"SAI_PACKET_ACTION_TRAP\"},{\"action\":\"SAI_ACL_ENTRY_" - "ATTR_ACTION_SET_TC\",\"param\":\"traffic_class\"}]"}); - - // Invalid table priority - attributes.push_back(swss::FieldValueTuple{kPriority, "-123"}); - EXPECT_FALSE( - DeserializeAclTableDefinitionAppDbEntry(acl_table_name, attributes).ok()); +TEST_F(AclManagerTest, DeserializeAclTableDefAppDbWithInvalidPriorityFails) +{ + std::string acl_table_name = kAclIngressTableName; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{kStage, STAGE_INGRESS}); + attributes.push_back(swss::FieldValueTuple{kSize, "234"}); + attributes.push_back(swss::FieldValueTuple{"meter/unit", P4_METER_UNIT_BYTES}); + attributes.push_back(swss::FieldValueTuple{"counter/unit", P4_COUNTER_UNIT_BOTH}); + attributes.push_back( + swss::FieldValueTuple{"match/ether_type", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ETHER_TYPE)}); + attributes.push_back( + swss::FieldValueTuple{"match/ether_dst", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_MAC)}); + attributes.push_back( + swss::FieldValueTuple{"match/ipv6_dst", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_DST_IPV6)}); + attributes.push_back( + swss::FieldValueTuple{"match/ipv6_next_header", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_IPV6_NEXT_HEADER)}); + attributes.push_back(swss::FieldValueTuple{"match/ttl", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_TTL)}); + attributes.push_back( + swss::FieldValueTuple{"match/icmp_type", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_ICMP_TYPE)}); + attributes.push_back( + swss::FieldValueTuple{"match/l4_dst_port", BuildMatchFieldJsonStrKindSaiField(P4_MATCH_L4_DST_PORT)}); + attributes.push_back(swss::FieldValueTuple{"action/copy_and_set_tc", + "[{\"action\":\"SAI_PACKET_ACTION_COPY\",\"packet_color\":\"SAI_PACKET_" + "COLOR_GREEN\"},{\"action\":\"SAI_ACL_ENTRY_ATTR_ACTION_SET_TC\"," + "\"param\":\"traffic_class\"}]"}); + attributes.push_back(swss::FieldValueTuple{"action/punt_and_set_tc", + "[{\"action\":\"SAI_PACKET_ACTION_TRAP\"},{\"action\":\"SAI_ACL_ENTRY_" + "ATTR_ACTION_SET_TC\",\"param\":\"traffic_class\"}]"}); + + // Invalid table priority + attributes.push_back(swss::FieldValueTuple{kPriority, "-123"}); + EXPECT_FALSE(DeserializeAclTableDefinitionAppDbEntry(acl_table_name, attributes).ok()); } -TEST_F(AclManagerTest, RemoveIngressPuntTableSucceeds) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf_group(Eq(kUdfGroupOid1))) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf(_)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - const auto& acl_groups = gSwitchOrch->getAclGroupsBindingToSwitch(); - ASSERT_NE(acl_groups.end(), acl_groups.find(SAI_ACL_STAGE_INGRESS)); - EXPECT_EQ(1, acl_groups.at(SAI_ACL_STAGE_INGRESS).m_objsDependingOnMe.size()); - EXPECT_NE(acl_groups.at(SAI_ACL_STAGE_INGRESS).m_objsDependingOnMe.end(), - acl_groups.at(SAI_ACL_STAGE_INGRESS) - .m_objsDependingOnMe.find( - sai_serialize_object_id(kAclGroupMemberIngressOid))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteTableRequest(kAclIngressTableName)); - ASSERT_NE(acl_groups.end(), acl_groups.find(SAI_ACL_STAGE_INGRESS)); - EXPECT_EQ(0, acl_groups.at(SAI_ACL_STAGE_INGRESS).m_objsDependingOnMe.size()); +TEST_F(AclManagerTest, RemoveIngressPuntTableSucceeds) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf_group(Eq(kUdfGroupOid1))).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf(_)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + const auto &acl_groups = gSwitchOrch->getAclGroupsBindingToSwitch(); + ASSERT_NE(acl_groups.end(), acl_groups.find(SAI_ACL_STAGE_INGRESS)); + EXPECT_EQ(1, acl_groups.at(SAI_ACL_STAGE_INGRESS).m_objsDependingOnMe.size()); + EXPECT_NE(acl_groups.at(SAI_ACL_STAGE_INGRESS).m_objsDependingOnMe.end(), + acl_groups.at(SAI_ACL_STAGE_INGRESS) + .m_objsDependingOnMe.find(sai_serialize_object_id(kAclGroupMemberIngressOid))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteTableRequest(kAclIngressTableName)); + ASSERT_NE(acl_groups.end(), acl_groups.find(SAI_ACL_STAGE_INGRESS)); + EXPECT_EQ(0, acl_groups.at(SAI_ACL_STAGE_INGRESS).m_objsDependingOnMe.size()); } -TEST_F(AclManagerTest, RemoveIngressPuntRuleFails) { - // Create ACL table - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - - // Insert the first ACL rule - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - auto acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - app_db_entry.action = "set_dst_ipv6"; - app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclCounterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - - // Fails to remove ACL rule when sai_acl_api->remove_acl_entry() fails - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(_)) - .WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); - EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - const auto& table_name_and_rule_key = - concatTableNameAndRuleKey(kAclIngressTableName, acl_rule_key); - // Fails to remove ACL rule when rule does not exist - p4_oid_mapper_->eraseOID(SAI_OBJECT_TYPE_ACL_ENTRY, table_name_and_rule_key); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_ACL_ENTRY, table_name_and_rule_key, - kAclIngressRuleOid1); - - // Fails to remove ACL rule when reference count > 0 - p4_oid_mapper_->increaseRefCount(SAI_OBJECT_TYPE_ACL_ENTRY, - table_name_and_rule_key); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - p4_oid_mapper_->decreaseRefCount(SAI_OBJECT_TYPE_ACL_ENTRY, - table_name_and_rule_key); - - // Fails to remove ACL rule when sai_policer_api->remove_policer() fails - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Fails to remove ACL rule when sai_policer_api->remove_policer() fails and - // recovery fails - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_FAILURE))); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Fails to remove ACL rule when the counter does not exist. - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - p4_oid_mapper_->decreaseRefCount(SAI_OBJECT_TYPE_ACL_COUNTER, - table_name_and_rule_key); - p4_oid_mapper_->eraseOID(SAI_OBJECT_TYPE_ACL_COUNTER, - table_name_and_rule_key); - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_ACL_COUNTER, table_name_and_rule_key, - kAclCounterOid1, 1); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, - kAclMeterOid1); - - // Fails to remove ACL rule when sai_acl_api->remove_acl_counter() fails - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Fails to remove ACL rule when sai_acl_api->remove_acl_counter() fails and - // ACL rule recovery fails. - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_FAILURE))); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Fails to remove ACL rule when sai_acl_api->remove_acl_counter() fails and - // meter recovery fails - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_FAILURE))); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Fails to remove ACL rule when the meter does not exist. - // The previous test fails to recover the ACL meter, and hence the meter does - // not exist. - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, - kAclMeterOid1); +TEST_F(AclManagerTest, RemoveIngressPuntRuleFails) +{ + // Create ACL table + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + + // Insert the first ACL rule + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + auto acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + app_db_entry.action = "set_dst_ipv6"; + app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclCounterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + + // Fails to remove ACL rule when sai_acl_api->remove_acl_entry() fails + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(_)).WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); + EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + const auto &table_name_and_rule_key = concatTableNameAndRuleKey(kAclIngressTableName, acl_rule_key); + // Fails to remove ACL rule when rule does not exist + p4_oid_mapper_->eraseOID(SAI_OBJECT_TYPE_ACL_ENTRY, table_name_and_rule_key); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_ACL_ENTRY, table_name_and_rule_key, kAclIngressRuleOid1); + + // Fails to remove ACL rule when reference count > 0 + p4_oid_mapper_->increaseRefCount(SAI_OBJECT_TYPE_ACL_ENTRY, table_name_and_rule_key); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + p4_oid_mapper_->decreaseRefCount(SAI_OBJECT_TYPE_ACL_ENTRY, table_name_and_rule_key); + + // Fails to remove ACL rule when sai_policer_api->remove_policer() fails + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Fails to remove ACL rule when sai_policer_api->remove_policer() fails and + // recovery fails + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_FAILURE))); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Fails to remove ACL rule when the counter does not exist. + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + p4_oid_mapper_->decreaseRefCount(SAI_OBJECT_TYPE_ACL_COUNTER, table_name_and_rule_key); + p4_oid_mapper_->eraseOID(SAI_OBJECT_TYPE_ACL_COUNTER, table_name_and_rule_key); + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_ACL_COUNTER, table_name_and_rule_key, kAclCounterOid1, 1); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, kAclMeterOid1); + + // Fails to remove ACL rule when sai_acl_api->remove_acl_counter() fails + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Fails to remove ACL rule when sai_acl_api->remove_acl_counter() fails and + // ACL rule recovery fails. + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_FAILURE))); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Fails to remove ACL rule when sai_acl_api->remove_acl_counter() fails and + // meter recovery fails + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_FAILURE))); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Fails to remove ACL rule when the meter does not exist. + // The previous test fails to recover the ACL meter, and hence the meter does + // not exist. + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, kAclMeterOid1); } -TEST_F(AclManagerTest, RemoveNonExistingPuntTableFails) { - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessDeleteTableRequest(kAclIngressTableName)); +TEST_F(AclManagerTest, RemoveNonExistingPuntTableFails) +{ + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessDeleteTableRequest(kAclIngressTableName)); } -TEST_F(AclManagerTest, RemoveAclTableFailsWhenAclRuleExists) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - - // Insert the first ACL rule - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - auto acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - app_db_entry.action = "set_dst_ipv6"; - app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - - // Fails to remove ACL table when the table is nonempty - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessDeleteTableRequest(kAclIngressTableName)); +TEST_F(AclManagerTest, RemoveAclTableFailsWhenAclRuleExists) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + + // Insert the first ACL rule + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + auto acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + app_db_entry.action = "set_dst_ipv6"; + app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + + // Fails to remove ACL table when the table is nonempty + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessDeleteTableRequest(kAclIngressTableName)); } -TEST_F(AclManagerTest, RemoveAclTableFailsWhenTableDoesNotExist) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - p4_oid_mapper_->eraseOID(SAI_OBJECT_TYPE_ACL_TABLE, kAclIngressTableName); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, - ProcessDeleteTableRequest(kAclIngressTableName)); +TEST_F(AclManagerTest, RemoveAclTableFailsWhenTableDoesNotExist) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + p4_oid_mapper_->eraseOID(SAI_OBJECT_TYPE_ACL_TABLE, kAclIngressTableName); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, ProcessDeleteTableRequest(kAclIngressTableName)); } -TEST_F(AclManagerTest, RemoveAclTableFailsWhenTableRefCountIsNotZero) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - p4_oid_mapper_->increaseRefCount(SAI_OBJECT_TYPE_ACL_TABLE, - kAclIngressTableName); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessDeleteTableRequest(kAclIngressTableName)); +TEST_F(AclManagerTest, RemoveAclTableFailsWhenTableRefCountIsNotZero) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + p4_oid_mapper_->increaseRefCount(SAI_OBJECT_TYPE_ACL_TABLE, kAclIngressTableName); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessDeleteTableRequest(kAclIngressTableName)); } -TEST_F(AclManagerTest, RemoveAclTableFailsWhenSaiCallFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - ProcessDeleteTableRequest(kAclIngressTableName)); +TEST_F(AclManagerTest, RemoveAclTableFailsWhenSaiCallFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)).WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessDeleteTableRequest(kAclIngressTableName)); } -TEST_F(AclManagerTest, - RemoveAclTableRaisesCriticalStateWhenAclGroupMemberRecoveryFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - ProcessDeleteTableRequest(kAclIngressTableName)); +TEST_F(AclManagerTest, RemoveAclTableRaisesCriticalStateWhenAclGroupMemberRecoveryFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)).WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)).WillOnce(Return(SAI_STATUS_FAILURE)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessDeleteTableRequest(kAclIngressTableName)); } -TEST_F(AclManagerTest, RemoveAclTableFailsWhenAclTableGroupMemberDoesNotExist) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - p4_oid_mapper_->eraseOID(SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER, - kAclIngressTableName); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessDeleteTableRequest(kAclIngressTableName)); +TEST_F(AclManagerTest, RemoveAclTableFailsWhenAclTableGroupMemberDoesNotExist) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + p4_oid_mapper_->eraseOID(SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER, kAclIngressTableName); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessDeleteTableRequest(kAclIngressTableName)); } -TEST_F(AclManagerTest, - RemoveAclTableFailsWhenRemoveAclTableGroupMemberSaiCallFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - ProcessDeleteTableRequest(kAclIngressTableName)); +TEST_F(AclManagerTest, RemoveAclTableFailsWhenRemoveAclTableGroupMemberSaiCallFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)).WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessDeleteTableRequest(kAclIngressTableName)); } -TEST_F(AclManagerTest, RemoveAclTableFailsWhenRemoveUdfSaiCallFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf(_)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - ProcessDeleteTableRequest(kAclIngressTableName)); +TEST_F(AclManagerTest, RemoveAclTableFailsWhenRemoveUdfSaiCallFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf(_)).WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessDeleteTableRequest(kAclIngressTableName)); } -TEST_F(AclManagerTest, RemoveAclTableFailsWhenRemoveUdfGroupSaiCallFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf_group(_)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - ProcessDeleteTableRequest(kAclIngressTableName)); +TEST_F(AclManagerTest, RemoveAclTableFailsWhenRemoveUdfGroupSaiCallFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf_group(_)).WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessDeleteTableRequest(kAclIngressTableName)); } -TEST_F(AclManagerTest, - RemoveAclTableFailsRaisesCriticalStateWhenUdfRecoveryFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf_group(_)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), - Return(SAI_STATUS_SUCCESS))); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - ProcessDeleteTableRequest(kAclIngressTableName)); +TEST_F(AclManagerTest, RemoveAclTableFailsRaisesCriticalStateWhenUdfRecoveryFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf_group(_)).WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)).WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), Return(SAI_STATUS_SUCCESS))); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessDeleteTableRequest(kAclIngressTableName)); } -TEST_F(AclManagerTest, - RemoveAclTableFailsRaisesCriticalStateWhenUdfGroupRecoveryFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_udf_, remove_udf_group(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - // If UDF group recovery fails, UDF recovery and ACL table recovery will also - // fail since they depend on the UDF group. - EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - // TODO: Expect critical state x3. - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - ProcessDeleteTableRequest(kAclIngressTableName)); +TEST_F(AclManagerTest, RemoveAclTableFailsRaisesCriticalStateWhenUdfGroupRecoveryFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf(_)).WillOnce(Return(SAI_STATUS_SUCCESS)).WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_udf_, remove_udf_group(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + // If UDF group recovery fails, UDF recovery and ACL table recovery will also + // fail since they depend on the UDF group. + EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)).WillOnce(Return(SAI_STATUS_FAILURE)); + // TODO: Expect critical state x3. + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessDeleteTableRequest(kAclIngressTableName)); } -TEST_F(AclManagerTest, RemoveAclTableFailsWhenUdfHasNonZeroRefCount) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), - Return(SAI_STATUS_SUCCESS))); - p4_oid_mapper_->increaseRefCount( - SAI_OBJECT_TYPE_UDF, - std::string(kAclIngressTableName) + "-arp_tpa-0-base1-offset24"); - EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, - ProcessDeleteTableRequest(kAclIngressTableName)); +TEST_F(AclManagerTest, RemoveAclTableFailsWhenUdfHasNonZeroRefCount) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), Return(SAI_STATUS_SUCCESS))); + p4_oid_mapper_->increaseRefCount(SAI_OBJECT_TYPE_UDF, + std::string(kAclIngressTableName) + "-arp_tpa-0-base1-offset24"); + EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, ProcessDeleteTableRequest(kAclIngressTableName)); } -TEST_F(AclManagerTest, RemoveAclTableFailsWhenUdfGroupHasNonZeroRefCount) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), - Return(SAI_STATUS_SUCCESS))); - p4_oid_mapper_->increaseRefCount( - SAI_OBJECT_TYPE_UDF_GROUP, - std::string(kAclIngressTableName) + "-arp_tpa-0"); - EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, - ProcessDeleteTableRequest(kAclIngressTableName)); +TEST_F(AclManagerTest, RemoveAclTableFailsWhenUdfGroupHasNonZeroRefCount) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), Return(SAI_STATUS_SUCCESS))); + p4_oid_mapper_->increaseRefCount(SAI_OBJECT_TYPE_UDF_GROUP, std::string(kAclIngressTableName) + "-arp_tpa-0"); + EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, ProcessDeleteTableRequest(kAclIngressTableName)); } -TEST_F(AclManagerTest, RemoveAclTableFailsWhenAclGroupWasNotFound) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto* acl_table = GetAclTable(kAclIngressTableName); - acl_table->stage = SAI_ACL_STAGE_INGRESS_MACSEC; - EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, - ProcessDeleteTableRequest(kAclIngressTableName)); +TEST_F(AclManagerTest, RemoveAclTableFailsWhenAclGroupWasNotFound) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto *acl_table = GetAclTable(kAclIngressTableName); + acl_table->stage = SAI_ACL_STAGE_INGRESS_MACSEC; + EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, ProcessDeleteTableRequest(kAclIngressTableName)); } -TEST_F(AclManagerTest, RemoveAclGroupsSucceedsAfterCleanup) { - // Create ACL table - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - // Insert the first ACL rule - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - auto acl_rule_key1 = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - app_db_entry.action = "set_dst_ipv6"; - app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key1, app_db_entry)); - // Insert the second ACL rule - app_db_entry.match_fvs["tc"] = "1"; - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid2), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid2), Return(SAI_STATUS_SUCCESS))); - auto acl_rule_key2 = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key2, app_db_entry)); - // There are 3 groups created, only group in INGRESS stage is nonempty. - // Other groups can be deleted in below RemoveAllGroups() - EXPECT_CALL(mock_sai_switch_, set_switch_attribute(Eq(gSwitchId), _)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table_group(_)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - - // Remove ACL groups - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid2))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid2))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf_group(Eq(kUdfGroupOid1))) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_udf_, remove_udf(_)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - // Remove rules - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key1)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key2)); - // Remove table - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteTableRequest(kAclIngressTableName)); +TEST_F(AclManagerTest, RemoveAclGroupsSucceedsAfterCleanup) +{ + // Create ACL table + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + // Insert the first ACL rule + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + auto acl_rule_key1 = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + app_db_entry.action = "set_dst_ipv6"; + app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key1, app_db_entry)); + // Insert the second ACL rule + app_db_entry.match_fvs["tc"] = "1"; + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid2), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid2), Return(SAI_STATUS_SUCCESS))); + auto acl_rule_key2 = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key2, app_db_entry)); + // There are 3 groups created, only group in INGRESS stage is nonempty. + // Other groups can be deleted in below RemoveAllGroups() + EXPECT_CALL(mock_sai_switch_, set_switch_attribute(Eq(gSwitchId), _)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table_group(_)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + + // Remove ACL groups + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid2))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid2))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table_group_member(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf_group(Eq(kUdfGroupOid1))).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_udf_, remove_udf(_)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + // Remove rules + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key1)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key2)); + // Remove table + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteTableRequest(kAclIngressTableName)); } -TEST_F(AclManagerTest, DrainRuleTuplesToProcessSetRequestSucceeds) { - auto app_db_entry = getDefaultAclTableDefAppDbEntry(); - app_db_entry.counter_unit = P4_COUNTER_UNIT_PACKETS; - app_db_entry.meter_unit = P4_METER_UNIT_PACKETS; - EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .Times(3) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; - AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); - ASSERT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddTableRequest(app_db_entry)); - ASSERT_NO_FATAL_FAILURE(IsExpectedAclTableDefinitionMapping( - *GetAclTable(app_db_entry.acl_table_name), app_db_entry)); - const auto& acl_rule_json_key = - "{\"match/ether_type\":\"0x0800\",\"match/" - "ipv6_dst\":\"fdf8:f53b:82e4::53 & " - "fdf8:f53b:82e4::53\",\"priority\":15}"; - const auto& rule_tuple_key = std::string(kAclIngressTableName) + - kTableKeyDelimiter + acl_rule_json_key; - EnqueueRuleTuple( - std::string(kAclIngressTableName), - swss::KeyOpFieldsValuesTuple( - {rule_tuple_key, SET_COMMAND, getDefaultRuleFieldValueTuples()})); - - // Update request on exact rule without change will not need SAI call - EnqueueRuleTuple( - std::string(kAclIngressTableName), - swss::KeyOpFieldsValuesTuple( - {rule_tuple_key, SET_COMMAND, getDefaultRuleFieldValueTuples()})); - - // Drain rule tuples to process SET request - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - DrainRuleTuples(); - - const auto& acl_rule_key = - "match/ether_type=0x0800:match/ipv6_dst=fdf8:f53b:82e4::53 & " - "fdf8:f53b:82e4::53:priority=15"; - const auto* acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - EXPECT_EQ(kAclIngressRuleOid1, acl_rule->acl_entry_oid); +TEST_F(AclManagerTest, DrainRuleTuplesToProcessSetRequestSucceeds) +{ + auto app_db_entry = getDefaultAclTableDefAppDbEntry(); + app_db_entry.counter_unit = P4_COUNTER_UNIT_PACKETS; + app_db_entry.meter_unit = P4_METER_UNIT_PACKETS; + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) + .Times(3) + .WillRepeatedly(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; + AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); + ASSERT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddTableRequest(app_db_entry)); + ASSERT_NO_FATAL_FAILURE( + IsExpectedAclTableDefinitionMapping(*GetAclTable(app_db_entry.acl_table_name), app_db_entry)); + const auto &acl_rule_json_key = "{\"match/ether_type\":\"0x0800\",\"match/" + "ipv6_dst\":\"fdf8:f53b:82e4::53 & " + "fdf8:f53b:82e4::53\",\"priority\":15}"; + const auto &rule_tuple_key = std::string(kAclIngressTableName) + kTableKeyDelimiter + acl_rule_json_key; + EnqueueRuleTuple(std::string(kAclIngressTableName), + swss::KeyOpFieldsValuesTuple({rule_tuple_key, SET_COMMAND, getDefaultRuleFieldValueTuples()})); + + // Update request on exact rule without change will not need SAI call + EnqueueRuleTuple(std::string(kAclIngressTableName), + swss::KeyOpFieldsValuesTuple({rule_tuple_key, SET_COMMAND, getDefaultRuleFieldValueTuples()})); + + // Drain rule tuples to process SET request + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + DrainRuleTuples(); + + const auto &acl_rule_key = "match/ether_type=0x0800:match/ipv6_dst=fdf8:f53b:82e4::53 & " + "fdf8:f53b:82e4::53:priority=15"; + const auto *acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + EXPECT_EQ(kAclIngressRuleOid1, acl_rule->acl_entry_oid); } -TEST_F(AclManagerTest, DrainRuleTuplesToProcessSetDelRequestSucceeds) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto attributes = getDefaultRuleFieldValueTuples(); - const auto& acl_rule_json_key = - "{\"match/ether_type\":\"0x0800\",\"match/" - "ipv6_dst\":\"fdf8:f53b:82e4::53 & " - "fdf8:f53b:82e4::53\",\"priority\":15}"; - const auto& rule_tuple_key = std::string(kAclIngressTableName) + - kTableKeyDelimiter + acl_rule_json_key; - EnqueueRuleTuple( - std::string(kAclIngressTableName), - swss::KeyOpFieldsValuesTuple({rule_tuple_key, SET_COMMAND, attributes})); - - // Drain ACL rule tuple to process SET request - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclCounterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - DrainRuleTuples(); - // Populate counter stats - EXPECT_CALL(mock_sai_policer_, get_policer_stats(Eq(kAclMeterOid1), _, _, _)) - .WillOnce(DoAll( - Invoke([](sai_object_id_t policer_id, uint32_t number_of_counters, - const sai_stat_id_t* counter_ids, uint64_t* counters) { - counters[0] = 100; // green_bytes - }), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, - get_acl_counter_attribute(Eq(kAclCounterOid1), _, _)) - .WillOnce( - DoAll(Invoke([](sai_object_id_t acl_counter_id, uint32_t attr_count, - sai_attribute_t* counter_attr) { - counter_attr[0].value.u64 = 100; // bytes - }), - Return(SAI_STATUS_SUCCESS))); - DoAclCounterStatsTask(); - auto counters_table = std::make_unique( - gCountersDb, std::string(COUNTERS_TABLE) + DEFAULT_KEY_SEPARATOR + - APP_P4RT_TABLE_NAME); - std::vector values; - EXPECT_TRUE(counters_table->get(rule_tuple_key, values)); - - const auto& acl_rule_key = - "match/ether_type=0x0800:match/ipv6_dst=fdf8:f53b:82e4::53 & " - "fdf8:f53b:82e4::53:priority=15"; - const auto* acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - EXPECT_EQ(kAclIngressRuleOid1, acl_rule->acl_entry_oid); - EXPECT_EQ(rule_tuple_key, acl_rule->db_key); - - // Drain ACL rule tuple to process DEL request - attributes.clear(); - EnqueueRuleTuple( - std::string(kAclIngressTableName), - swss::KeyOpFieldsValuesTuple({rule_tuple_key, DEL_COMMAND, attributes})); - - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - DrainRuleTuples(); - EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); +TEST_F(AclManagerTest, DrainRuleTuplesToProcessSetDelRequestSucceeds) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto attributes = getDefaultRuleFieldValueTuples(); + const auto &acl_rule_json_key = "{\"match/ether_type\":\"0x0800\",\"match/" + "ipv6_dst\":\"fdf8:f53b:82e4::53 & " + "fdf8:f53b:82e4::53\",\"priority\":15}"; + const auto &rule_tuple_key = std::string(kAclIngressTableName) + kTableKeyDelimiter + acl_rule_json_key; + EnqueueRuleTuple(std::string(kAclIngressTableName), + swss::KeyOpFieldsValuesTuple({rule_tuple_key, SET_COMMAND, attributes})); + + // Drain ACL rule tuple to process SET request + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclCounterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + DrainRuleTuples(); + // Populate counter stats + EXPECT_CALL(mock_sai_policer_, get_policer_stats(Eq(kAclMeterOid1), _, _, _)) + .WillOnce(DoAll(Invoke([](sai_object_id_t policer_id, uint32_t number_of_counters, + const sai_stat_id_t *counter_ids, uint64_t *counters) { + counters[0] = 100; // green_bytes + }), + Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, get_acl_counter_attribute(Eq(kAclCounterOid1), _, _)) + .WillOnce(DoAll(Invoke([](sai_object_id_t acl_counter_id, uint32_t attr_count, sai_attribute_t *counter_attr) { + counter_attr[0].value.u64 = 100; // bytes + }), + Return(SAI_STATUS_SUCCESS))); + DoAclCounterStatsTask(); + auto counters_table = std::make_unique(gCountersDb, std::string(COUNTERS_TABLE) + + DEFAULT_KEY_SEPARATOR + APP_P4RT_TABLE_NAME); + std::vector values; + EXPECT_TRUE(counters_table->get(rule_tuple_key, values)); + + const auto &acl_rule_key = "match/ether_type=0x0800:match/ipv6_dst=fdf8:f53b:82e4::53 & " + "fdf8:f53b:82e4::53:priority=15"; + const auto *acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + EXPECT_EQ(kAclIngressRuleOid1, acl_rule->acl_entry_oid); + EXPECT_EQ(rule_tuple_key, acl_rule->db_key); + + // Drain ACL rule tuple to process DEL request + attributes.clear(); + EnqueueRuleTuple(std::string(kAclIngressTableName), + swss::KeyOpFieldsValuesTuple({rule_tuple_key, DEL_COMMAND, attributes})); + + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + DrainRuleTuples(); + EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); } -TEST_F(AclManagerTest, - DrainRuleTuplesToProcessSetRequestInvalidTableNameRuleKeyFails) { - auto attributes = getDefaultRuleFieldValueTuples(); - auto acl_rule_json_key = - "{\"match/ether_type\":\"0x0800\",\"match/" - "ipv6_dst\":\"fdf8:f53b:82e4::53 & " - "fdf8:f53b:82e4::53\",\"priority\":15}"; - auto rule_tuple_key = std::string("INVALID_TABLE_NAME") + kTableKeyDelimiter + - acl_rule_json_key; - EnqueueRuleTuple( - std::string("INVALID_TABLE_NAME"), - swss::KeyOpFieldsValuesTuple({rule_tuple_key, SET_COMMAND, attributes})); - // Drain rule tuple to process SET request with invalid ACL table name: - // "INVALID_TABLE_NAME" - DrainRuleTuples(); - - auto acl_rule_key = - "match/ether_type=0x0800:match/ipv6_dst=fdf8:f53b:82e4::53 & " - "fdf8:f53b:82e4::53:priority=15"; - EXPECT_EQ(nullptr, GetAclRule("INVALID_TABLE_NAME", acl_rule_key)); - - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - acl_rule_json_key = - "{\"match/ether_type\":\"0x0800\",\"match/" - "ipv6_dst\":\"fdf8:f53b:82e4::53 & " - "fdf8:f53b:82e4::53\"}"; - rule_tuple_key = std::string(kAclIngressTableName) + kTableKeyDelimiter + - acl_rule_json_key; - acl_rule_key = - "match/ether_type=0x0800:match/ipv6_dst=fdf8:f53b:82e4::53 & " - "fdf8:f53b:82e4::53"; - EnqueueRuleTuple( - std::string(kAclIngressTableName), - swss::KeyOpFieldsValuesTuple({rule_tuple_key, SET_COMMAND, attributes})); - // Drain rule tuple to process SET request without priority field in rule - // JSON key - DrainRuleTuples(); - EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); +TEST_F(AclManagerTest, DrainRuleTuplesToProcessSetRequestInvalidTableNameRuleKeyFails) +{ + auto attributes = getDefaultRuleFieldValueTuples(); + auto acl_rule_json_key = "{\"match/ether_type\":\"0x0800\",\"match/" + "ipv6_dst\":\"fdf8:f53b:82e4::53 & " + "fdf8:f53b:82e4::53\",\"priority\":15}"; + auto rule_tuple_key = std::string("INVALID_TABLE_NAME") + kTableKeyDelimiter + acl_rule_json_key; + EnqueueRuleTuple(std::string("INVALID_TABLE_NAME"), + swss::KeyOpFieldsValuesTuple({rule_tuple_key, SET_COMMAND, attributes})); + // Drain rule tuple to process SET request with invalid ACL table name: + // "INVALID_TABLE_NAME" + DrainRuleTuples(); + + auto acl_rule_key = "match/ether_type=0x0800:match/ipv6_dst=fdf8:f53b:82e4::53 & " + "fdf8:f53b:82e4::53:priority=15"; + EXPECT_EQ(nullptr, GetAclRule("INVALID_TABLE_NAME", acl_rule_key)); + + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + acl_rule_json_key = "{\"match/ether_type\":\"0x0800\",\"match/" + "ipv6_dst\":\"fdf8:f53b:82e4::53 & " + "fdf8:f53b:82e4::53\"}"; + rule_tuple_key = std::string(kAclIngressTableName) + kTableKeyDelimiter + acl_rule_json_key; + acl_rule_key = "match/ether_type=0x0800:match/ipv6_dst=fdf8:f53b:82e4::53 & " + "fdf8:f53b:82e4::53"; + EnqueueRuleTuple(std::string(kAclIngressTableName), + swss::KeyOpFieldsValuesTuple({rule_tuple_key, SET_COMMAND, attributes})); + // Drain rule tuple to process SET request without priority field in rule + // JSON key + DrainRuleTuples(); + EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); } -TEST_F(AclManagerTest, DeserializeAclRuleAppDbWithInvalidPriorityFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto attributes = getDefaultRuleFieldValueTuples(); +TEST_F(AclManagerTest, DeserializeAclRuleAppDbWithInvalidPriorityFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto attributes = getDefaultRuleFieldValueTuples(); - // ACL rule json key has invalid priority - const auto& acl_rule_json_key = - "{\"match/ether_type\":\"0x0800\",\"match/" - "ipv6_dst\":\"fdf8:f53b:82e4::53 & " - "fdf8:f53b:82e4::53\",\"priority\":-15}"; + // ACL rule json key has invalid priority + const auto &acl_rule_json_key = "{\"match/ether_type\":\"0x0800\",\"match/" + "ipv6_dst\":\"fdf8:f53b:82e4::53 & " + "fdf8:f53b:82e4::53\",\"priority\":-15}"; - EXPECT_FALSE(DeserializeAclRuleAppDbEntry(kAclIngressTableName, - acl_rule_json_key, attributes) - .ok()); + EXPECT_FALSE(DeserializeAclRuleAppDbEntry(kAclIngressTableName, acl_rule_json_key, attributes).ok()); } -TEST_F(AclManagerTest, DeserializeAclRuleAppDbWithInvalidMeterFieldFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - std::string acl_table_name = kAclIngressTableName; - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{kAction, "copy_and_set_tc"}); - attributes.push_back(swss::FieldValueTuple{"param/traffic_class", "0x20"}); - attributes.push_back(swss::FieldValueTuple{"meter/cburst", "80"}); - attributes.push_back(swss::FieldValueTuple{"meter/pir", "200"}); - attributes.push_back(swss::FieldValueTuple{"meter/pburst", "200"}); - const auto& acl_rule_json_key = - "{\"match/ether_type\":\"0x0800\",\"match/" - "ipv6_dst\":\"fdf8:f53b:82e4::53 & " - "fdf8:f53b:82e4::53\",\"priority\":15}"; - - // ACL rule has invalid cir value in meter field - attributes.push_back(swss::FieldValueTuple{"meter/cir", "-80"}); - EXPECT_FALSE(DeserializeAclRuleAppDbEntry(acl_table_name, acl_rule_json_key, - attributes) - .ok()); - - // ACL rule has invalid meter field - attributes.pop_back(); - attributes.push_back(swss::FieldValueTuple{"meter/undefined", "80"}); - EXPECT_FALSE(DeserializeAclRuleAppDbEntry(acl_table_name, acl_rule_json_key, - attributes) - .ok()); - - // ACL rule has invalid field - attributes.pop_back(); - attributes.push_back(swss::FieldValueTuple{"undefined/undefined", "80"}); - EXPECT_FALSE(DeserializeAclRuleAppDbEntry(acl_table_name, acl_rule_json_key, - attributes) - .ok()); - - // ACL rule has invalid meter field - attributes.pop_back(); - attributes.push_back(swss::FieldValueTuple{"undefined", "80"}); - EXPECT_FALSE(DeserializeAclRuleAppDbEntry(acl_table_name, acl_rule_json_key, - attributes) - .ok()); +TEST_F(AclManagerTest, DeserializeAclRuleAppDbWithInvalidMeterFieldFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + std::string acl_table_name = kAclIngressTableName; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{kAction, "copy_and_set_tc"}); + attributes.push_back(swss::FieldValueTuple{"param/traffic_class", "0x20"}); + attributes.push_back(swss::FieldValueTuple{"meter/cburst", "80"}); + attributes.push_back(swss::FieldValueTuple{"meter/pir", "200"}); + attributes.push_back(swss::FieldValueTuple{"meter/pburst", "200"}); + const auto &acl_rule_json_key = "{\"match/ether_type\":\"0x0800\",\"match/" + "ipv6_dst\":\"fdf8:f53b:82e4::53 & " + "fdf8:f53b:82e4::53\",\"priority\":15}"; + + // ACL rule has invalid cir value in meter field + attributes.push_back(swss::FieldValueTuple{"meter/cir", "-80"}); + EXPECT_FALSE(DeserializeAclRuleAppDbEntry(acl_table_name, acl_rule_json_key, attributes).ok()); + + // ACL rule has invalid meter field + attributes.pop_back(); + attributes.push_back(swss::FieldValueTuple{"meter/undefined", "80"}); + EXPECT_FALSE(DeserializeAclRuleAppDbEntry(acl_table_name, acl_rule_json_key, attributes).ok()); + + // ACL rule has invalid field + attributes.pop_back(); + attributes.push_back(swss::FieldValueTuple{"undefined/undefined", "80"}); + EXPECT_FALSE(DeserializeAclRuleAppDbEntry(acl_table_name, acl_rule_json_key, attributes).ok()); + + // ACL rule has invalid meter field + attributes.pop_back(); + attributes.push_back(swss::FieldValueTuple{"undefined", "80"}); + EXPECT_FALSE(DeserializeAclRuleAppDbEntry(acl_table_name, acl_rule_json_key, attributes).ok()); } -TEST_F(AclManagerTest, DrainRuleTuplesWithInvalidCommand) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto attributes = getDefaultRuleFieldValueTuples(); - const auto& acl_rule_json_key = - "{\"match/ether_type\":\"0x0800\",\"match/" - "ipv6_dst\":\"fdf8:f53b:82e4::53 & " - "fdf8:f53b:82e4::53\",\"priority\":15}"; - const auto& rule_tuple_key = std::string(kAclIngressTableName) + - kTableKeyDelimiter + acl_rule_json_key; - EnqueueRuleTuple(std::string(kAclIngressTableName), - swss::KeyOpFieldsValuesTuple( - {rule_tuple_key, "INVALID_COMMAND", attributes})); - DrainRuleTuples(); - const auto& acl_rule_key = - "match/ether_type=0x0800:match/ipv6_dst=fdf8:f53b:82e4::53 & " - "fdf8:f53b:82e4::53:priority=15"; - EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); +TEST_F(AclManagerTest, DrainRuleTuplesWithInvalidCommand) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto attributes = getDefaultRuleFieldValueTuples(); + const auto &acl_rule_json_key = "{\"match/ether_type\":\"0x0800\",\"match/" + "ipv6_dst\":\"fdf8:f53b:82e4::53 & " + "fdf8:f53b:82e4::53\",\"priority\":15}"; + const auto &rule_tuple_key = std::string(kAclIngressTableName) + kTableKeyDelimiter + acl_rule_json_key; + EnqueueRuleTuple(std::string(kAclIngressTableName), + swss::KeyOpFieldsValuesTuple({rule_tuple_key, "INVALID_COMMAND", attributes})); + DrainRuleTuples(); + const auto &acl_rule_key = "match/ether_type=0x0800:match/ipv6_dst=fdf8:f53b:82e4::53 & " + "fdf8:f53b:82e4::53:priority=15"; + EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); } -TEST_F(AclManagerTest, DeserializeAclRuleAppDbWithInvalidMatchFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - // ACL rule json key has invalid match field - auto acl_rule_json_key = - "{\"undefined/undefined\":\"0x0800\",\"priority\":15}"; - EXPECT_FALSE(DeserializeAclRuleAppDbEntry(kAclIngressTableName, - acl_rule_json_key, - getDefaultRuleFieldValueTuples()) - .ok()); - // ACL rule json key is missing match prefix - acl_rule_json_key = "{\"ipv6_dst\":\"0x0800\",\"priority\":15}"; - EXPECT_FALSE(DeserializeAclRuleAppDbEntry(kAclIngressTableName, - acl_rule_json_key, - getDefaultRuleFieldValueTuples()) - .ok()); +TEST_F(AclManagerTest, DeserializeAclRuleAppDbWithInvalidMatchFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + // ACL rule json key has invalid match field + auto acl_rule_json_key = "{\"undefined/undefined\":\"0x0800\",\"priority\":15}"; + EXPECT_FALSE( + DeserializeAclRuleAppDbEntry(kAclIngressTableName, acl_rule_json_key, getDefaultRuleFieldValueTuples()).ok()); + // ACL rule json key is missing match prefix + acl_rule_json_key = "{\"ipv6_dst\":\"0x0800\",\"priority\":15}"; + EXPECT_FALSE( + DeserializeAclRuleAppDbEntry(kAclIngressTableName, acl_rule_json_key, getDefaultRuleFieldValueTuples()).ok()); } -TEST_F(AclManagerTest, DeserializeAclRuleAppDbWithInvalidJsonFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto attributes = getDefaultRuleFieldValueTuples(); - // ACL rule json key is an invalid JSON - EXPECT_FALSE(DeserializeAclRuleAppDbEntry(kAclIngressTableName, - "{\"undefined\"}", attributes) - .ok()); - EXPECT_FALSE(DeserializeAclRuleAppDbEntry( - kAclIngressTableName, - "[{\"ipv6_dst\":\"0x0800\",\"priority\":15}]", attributes) - .ok()); +TEST_F(AclManagerTest, DeserializeAclRuleAppDbWithInvalidJsonFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto attributes = getDefaultRuleFieldValueTuples(); + // ACL rule json key is an invalid JSON + EXPECT_FALSE(DeserializeAclRuleAppDbEntry(kAclIngressTableName, "{\"undefined\"}", attributes).ok()); + EXPECT_FALSE( + DeserializeAclRuleAppDbEntry(kAclIngressTableName, "[{\"ipv6_dst\":\"0x0800\",\"priority\":15}]", attributes) + .ok()); } -TEST_F(AclManagerTest, CreateAclRuleWithInvalidSaiMatchFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - app_db_entry.action = "punt_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "0x20"; - auto acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - // ACL rule has invalid in/out port(s) - app_db_entry.match_fvs["in_port"] = "Eth0"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs.erase("in_port"); - app_db_entry.match_fvs["out_port"] = "Eth0"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs.erase("out_port"); - app_db_entry.match_fvs["in_ports"] = "Eth0,Eth1"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs["in_ports"] = ""; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs.erase("in_ports"); - app_db_entry.match_fvs["out_ports"] = ""; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs["out_ports"] = "Eth0,Eth1"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs.erase("out_ports"); - - // ACL rule has invalid ipv6_dst - app_db_entry.match_fvs["ipv6_dst"] = "10.0.0.2"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs["ipv6_dst"] = "10.0.0.2 & 255.255.255.0"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs["ipv6_dst"] = "fdf8:f53b:82e4::53 & 255.255.255.0"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs["ipv6_dst"] = "null"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs["ipv6_dst"] = "fdf8:f53b:82e4::53"; - - // ACL rule has invalid ip_src - app_db_entry.match_fvs["ip_src"] = "fdf8:f53b:82e4::53"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs["ip_src"] = "fdf8:f53b:82e4::53 & ffff:ffff:ffff::"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs["ip_src"] = "10.0.0.2 & ffff:ffff:ffff::"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs["ip_src"] = "null"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs["ip_src"] = "10.0.0.2"; - - // ACL rule has invalid ether_type - app_db_entry.match_fvs["ether_type"] = "0x88800"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs["ether_type"] = "0x0800"; - - // ACL rule has invalid ip_frag - app_db_entry.match_fvs["ip_frag"] = "invalid"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs.erase("ip_frag"); - - // ACL rule has invalid packet_vlan - app_db_entry.match_fvs["packet_vlan"] = "invalid"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs.erase("packet_vlan"); - - // ACL rule has invalid UDF field: should be HEX_STRING - app_db_entry.match_fvs["arp_tpa"] = "invalid"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - - // ACL rule has invalid UDF field: invalid HEX_STRING length - app_db_entry.match_fvs["arp_tpa"] = "0xff"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - - // ACL table misses UDF group definition - const auto& acl_table_acl_tableapp_db_entry = - getDefaultAclTableDefAppDbEntry(); - auto* acl_table = GetAclTable(acl_table_acl_tableapp_db_entry.acl_table_name); - std::map saved_udf_group_attr_index_lookup = - acl_table->udf_group_attr_index_lookup; - acl_table->udf_group_attr_index_lookup.clear(); - app_db_entry.match_fvs["arp_tpa"] = "0xff112231"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs.erase("arp_tpa"); - acl_table->udf_group_attr_index_lookup = saved_udf_group_attr_index_lookup; - - // ACL rule has undefined match field - app_db_entry.match_fvs["undefined"] = "1"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs.erase("undefined"); +TEST_F(AclManagerTest, CreateAclRuleWithInvalidSaiMatchFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + app_db_entry.action = "punt_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "0x20"; + auto acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + // ACL rule has invalid in/out port(s) + app_db_entry.match_fvs["in_port"] = "Eth0"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs.erase("in_port"); + app_db_entry.match_fvs["out_port"] = "Eth0"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs.erase("out_port"); + app_db_entry.match_fvs["in_ports"] = "Eth0,Eth1"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs["in_ports"] = ""; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs.erase("in_ports"); + app_db_entry.match_fvs["out_ports"] = ""; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs["out_ports"] = "Eth0,Eth1"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs.erase("out_ports"); + + // ACL rule has invalid ipv6_dst + app_db_entry.match_fvs["ipv6_dst"] = "10.0.0.2"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs["ipv6_dst"] = "10.0.0.2 & 255.255.255.0"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs["ipv6_dst"] = "fdf8:f53b:82e4::53 & 255.255.255.0"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs["ipv6_dst"] = "null"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs["ipv6_dst"] = "fdf8:f53b:82e4::53"; + + // ACL rule has invalid ip_src + app_db_entry.match_fvs["ip_src"] = "fdf8:f53b:82e4::53"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs["ip_src"] = "fdf8:f53b:82e4::53 & ffff:ffff:ffff::"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs["ip_src"] = "10.0.0.2 & ffff:ffff:ffff::"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs["ip_src"] = "null"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs["ip_src"] = "10.0.0.2"; + + // ACL rule has invalid ether_type + app_db_entry.match_fvs["ether_type"] = "0x88800"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs["ether_type"] = "0x0800"; + + // ACL rule has invalid ip_frag + app_db_entry.match_fvs["ip_frag"] = "invalid"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs.erase("ip_frag"); + + // ACL rule has invalid packet_vlan + app_db_entry.match_fvs["packet_vlan"] = "invalid"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs.erase("packet_vlan"); + + // ACL rule has invalid UDF field: should be HEX_STRING + app_db_entry.match_fvs["arp_tpa"] = "invalid"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + + // ACL rule has invalid UDF field: invalid HEX_STRING length + app_db_entry.match_fvs["arp_tpa"] = "0xff"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + + // ACL table misses UDF group definition + const auto &acl_table_acl_tableapp_db_entry = getDefaultAclTableDefAppDbEntry(); + auto *acl_table = GetAclTable(acl_table_acl_tableapp_db_entry.acl_table_name); + std::map saved_udf_group_attr_index_lookup = acl_table->udf_group_attr_index_lookup; + acl_table->udf_group_attr_index_lookup.clear(); + app_db_entry.match_fvs["arp_tpa"] = "0xff112231"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs.erase("arp_tpa"); + acl_table->udf_group_attr_index_lookup = saved_udf_group_attr_index_lookup; + + // ACL rule has undefined match field + app_db_entry.match_fvs["undefined"] = "1"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs.erase("undefined"); } -TEST_F(AclManagerTest, CreateAclRuleWithInvalidCompositeSaiMatchFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - app_db_entry.action = "punt_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "0x20"; - auto acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - // ACL rule has invalid src_ipv6_64bit(composite SAI field) - should be ipv6 - // address - app_db_entry.match_fvs["src_ipv6_64bit"] = "Eth0"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs["src_ipv6_64bit"] = "10.0.0.1"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs["src_ipv6_64bit"] = "10.0.0.1 & ffff:ffff::"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.match_fvs["src_ipv6_64bit"] = - "fdf8:f53b:82e4:: & 255.255.255.255"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); +TEST_F(AclManagerTest, CreateAclRuleWithInvalidCompositeSaiMatchFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + app_db_entry.action = "punt_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "0x20"; + auto acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + // ACL rule has invalid src_ipv6_64bit(composite SAI field) - should be ipv6 + // address + app_db_entry.match_fvs["src_ipv6_64bit"] = "Eth0"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs["src_ipv6_64bit"] = "10.0.0.1"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs["src_ipv6_64bit"] = "10.0.0.1 & ffff:ffff::"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.match_fvs["src_ipv6_64bit"] = "fdf8:f53b:82e4:: & 255.255.255.255"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); } -TEST_F(AclManagerTest, AclRuleWithValidMatchFields) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - app_db_entry.action = "punt_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "0x20"; - - // Match fields registered in table definition - app_db_entry.match_fvs["ether_dst"] = "AA:BB:CC:DD:EE:FF & FF:FF:FF:FF:FF:FF"; - app_db_entry.match_fvs["ttl"] = "0x2 & 0xFF"; - app_db_entry.match_fvs["in_ports"] = "Ethernet1,Ethernet2"; - app_db_entry.match_fvs["in_port"] = "Ethernet3"; - app_db_entry.match_fvs["out_ports"] = "Ethernet4,Ethernet5"; - app_db_entry.match_fvs["out_port"] = "Ethernet6"; - app_db_entry.match_fvs["tcp_flags"] = " 0x2 & 0x3F "; - app_db_entry.match_fvs["ip_flags"] = "0x2"; - app_db_entry.match_fvs["l4_src_port"] = "0x2e90 & 0xFFF0"; - app_db_entry.match_fvs["l4_dst_port"] = "0x2e98"; - app_db_entry.match_fvs["ip_id"] = "2"; - app_db_entry.match_fvs["inner_l4_src_port"] = "1212"; - app_db_entry.match_fvs["inner_l4_dst_port"] = "1212"; - app_db_entry.match_fvs["dscp"] = "8"; - app_db_entry.match_fvs["inner_ip_src"] = "192.50.128.0"; - app_db_entry.match_fvs["inner_ip_dst"] = "192.50.128.0/17"; - app_db_entry.match_fvs["inner_ipv6_src"] = "1234:5678::"; - app_db_entry.match_fvs["inner_ipv6_dst"] = "2001:db8:3c4d:15::/64"; - app_db_entry.match_fvs["ip_src"] = " 192.50.128.0 & 255.255.255.0 "; - app_db_entry.match_fvs["ip_dst"] = "192.50.128.0/17"; - app_db_entry.match_fvs["ipv6_src"] = "2001:db8:3c4d:15::/64"; - app_db_entry.match_fvs["tc"] = "1"; - app_db_entry.match_fvs["icmp_type"] = "9"; // RA - app_db_entry.match_fvs["icmp_code"] = "0"; // Normal RA - app_db_entry.match_fvs["tos"] = "32"; - app_db_entry.match_fvs["icmpv6_type"] = "134"; // RA - app_db_entry.match_fvs["icmpv6_code"] = "0"; // Normal RA - app_db_entry.match_fvs["ecn"] = "0"; - app_db_entry.match_fvs["inner_ip_protocol"] = "0x01"; // ICMP - app_db_entry.match_fvs["ip_protocol"] = "0x6"; // TCP - app_db_entry.match_fvs["ipv6_flow_label"] = "0x88 & 0xFFFFFFFF"; - app_db_entry.match_fvs["tunnel_vni"] = "88"; - app_db_entry.match_fvs["ip_frag"] = P4_IP_FRAG_HEAD; - app_db_entry.match_fvs["packet_vlan"] = P4_PACKET_VLAN_SINGLE_OUTER_TAG; - app_db_entry.match_fvs["outer_vlan_pri"] = "100"; - app_db_entry.match_fvs["outer_vlan_id"] = "100"; - app_db_entry.match_fvs["outer_vlan_cfi"] = "100"; - app_db_entry.match_fvs["inner_vlan_pri"] = "200"; - app_db_entry.match_fvs["inner_vlan_id"] = "200"; - app_db_entry.match_fvs["inner_vlan_cfi"] = "200"; - - const auto& acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - auto* acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - auto* acl_table = GetAclTable(kAclIngressTableName); - ASSERT_NE(nullptr, acl_rule); - ASSERT_NE(nullptr, acl_table); - EXPECT_NO_FATAL_FAILURE( - IsExpectedAclRuleMapping(acl_rule, app_db_entry, *acl_table)); - EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); - - // Check match field value - EXPECT_EQ(2, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS] - .aclfield.data.objlist.count); - EXPECT_EQ(0x112233, acl_rule->in_ports_oids[0]); - EXPECT_EQ(0x1fed3, acl_rule->in_ports_oids[1]); - EXPECT_EQ(2, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS] - .aclfield.data.objlist.count); - EXPECT_EQ(0x9988, acl_rule->out_ports_oids[0]); - EXPECT_EQ(0x56789abcdef, acl_rule->out_ports_oids[1]); - - // Verify SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN - EXPECT_EQ(2, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .aclfield.data.u8list.count); - EXPECT_EQ( - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .data[0], - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .aclfield.data.u8list.list[0]); - EXPECT_EQ( - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .data[1], - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .aclfield.data.u8list.list[1]); - EXPECT_EQ( - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .mask[0], - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .aclfield.mask.u8list.list[0]); - EXPECT_EQ( - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .mask[1], - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .aclfield.mask.u8list.list[1]); - EXPECT_EQ( - 0xff, - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .data[0]); - EXPECT_EQ( - 0x11, - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .data[1]); - EXPECT_EQ( - 0xff, - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .mask[0]); - EXPECT_EQ( - 0xff, - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .mask[1]); - // Verify SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1 - EXPECT_EQ(2, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1] - .aclfield.data.objlist.count); - EXPECT_EQ( - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1] - .data[0], - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1] - .aclfield.data.u8list.list[0]); - EXPECT_EQ( - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1] - .data[1], - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1] - .aclfield.data.u8list.list[1]); - EXPECT_EQ( - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1] - .mask[0], - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1] - .aclfield.mask.u8list.list[0]); - EXPECT_EQ( - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1] - .mask[1], - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1] - .aclfield.mask.u8list.list[1]); - EXPECT_EQ( - 0x22, - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1] - .data[0]); - EXPECT_EQ( - 0x31, - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1] - .data[1]); - EXPECT_EQ( - 0xff, - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1] - .mask[0]); - EXPECT_EQ( - 0xff, - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1] - .mask[1]); - EXPECT_EQ( - 0xaabbccdd, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IN_PORT].aclfield.data.oid); - EXPECT_EQ( - 0x56789abcdff, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORT].aclfield.data.oid); - EXPECT_EQ( - 0x2, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_TCP_FLAGS].aclfield.data.u8); - EXPECT_EQ( - 0x3F, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_TCP_FLAGS].aclfield.mask.u8); - EXPECT_EQ( - 0x2, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IP_FLAGS].aclfield.data.u8); - EXPECT_EQ( - 0x3F, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IP_FLAGS].aclfield.mask.u8); - EXPECT_EQ( - 8, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_DSCP].aclfield.data.u8); - EXPECT_EQ( - 0x3F, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_DSCP].aclfield.mask.u8); - EXPECT_EQ(0x0800, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE] - .aclfield.data.u16); - EXPECT_EQ(0xFFFF, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE] - .aclfield.mask.u16); - EXPECT_EQ(0x2e90, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_L4_SRC_PORT] - .aclfield.data.u16); - EXPECT_EQ(0xFFF0, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_L4_SRC_PORT] - .aclfield.mask.u16); - EXPECT_EQ(2, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IP_IDENTIFICATION] - .aclfield.data.u16); - EXPECT_EQ(0xFFFF, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IP_IDENTIFICATION] - .aclfield.mask.u16); - EXPECT_EQ(100, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_OUTER_VLAN_ID] - .aclfield.data.u16); - EXPECT_EQ(0xFFFF, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_OUTER_VLAN_ID] - .aclfield.mask.u16); - // 192.50.128.0 - EXPECT_EQ(swss::IpPrefix("192.50.128.0").getIp().getV4Addr(), - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_INNER_SRC_IP] - .aclfield.data.ip4); - EXPECT_EQ(swss::IpPrefix("192.50.128.0").getMask().getV4Addr(), - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_INNER_SRC_IP] - .aclfield.mask.ip4); - // 192.50.128.0 & 255.255.255.0 - EXPECT_EQ( - swss::IpAddress("192.50.128.0").getV4Addr(), - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_SRC_IP].aclfield.data.ip4); - EXPECT_EQ( - swss::IpAddress("255.255.255.0").getV4Addr(), - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_SRC_IP].aclfield.mask.ip4); - EXPECT_EQ( - 0, - memcmp(acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_SRC_IPV6] - .aclfield.data.ip6, - swss::IpPrefix("2001:db8:3c4d:15::/64").getIp().getV6Addr(), 16)); - EXPECT_EQ( - 0, memcmp(acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_SRC_IPV6] - .aclfield.mask.ip6, - swss::IpPrefix("2001:db8:3c4d:15::/64").getMask().getV6Addr(), - 16)); - - EXPECT_EQ(0, memcmp(acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_SRC_MAC] - .aclfield.data.mac, - swss::MacAddress("AA:BB:CC:DD:EE:FF").getMac(), 6)); - EXPECT_EQ(0, memcmp(acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_DST_MAC] - .aclfield.data.mac, - swss::MacAddress("AA:BB:CC:DD:EE:FF").getMac(), 6)); - EXPECT_EQ(0, memcmp(acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_DST_MAC] - .aclfield.mask.mac, - swss::MacAddress("FF:FF:FF:FF:FF:FF").getMac(), 6)); - EXPECT_EQ(1, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_TC].aclfield.data.u8); - EXPECT_EQ(0xFF, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_TC].aclfield.mask.u8); - EXPECT_EQ(0x88, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IPV6_FLOW_LABEL] - .aclfield.data.u32); - EXPECT_EQ(0xFFFFFFFF, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IPV6_FLOW_LABEL] - .aclfield.mask.u32); - EXPECT_EQ(SAI_ACL_IP_FRAG_HEAD, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_FRAG] - .aclfield.data.u32); - EXPECT_EQ(SAI_PACKET_VLAN_SINGLE_OUTER_TAG, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_PACKET_VLAN] - .aclfield.data.u32); - - // Check action field value - EXPECT_EQ(SAI_PACKET_ACTION_TRAP, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.parameter.s32); - EXPECT_EQ(0x20, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); +TEST_F(AclManagerTest, AclRuleWithValidMatchFields) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + app_db_entry.action = "punt_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "0x20"; + + // Match fields registered in table definition + app_db_entry.match_fvs["ether_dst"] = "AA:BB:CC:DD:EE:FF & FF:FF:FF:FF:FF:FF"; + app_db_entry.match_fvs["ttl"] = "0x2 & 0xFF"; + app_db_entry.match_fvs["in_ports"] = "Ethernet1,Ethernet2"; + app_db_entry.match_fvs["in_port"] = "Ethernet3"; + app_db_entry.match_fvs["out_ports"] = "Ethernet4,Ethernet5"; + app_db_entry.match_fvs["out_port"] = "Ethernet6"; + app_db_entry.match_fvs["tcp_flags"] = " 0x2 & 0x3F "; + app_db_entry.match_fvs["ip_flags"] = "0x2"; + app_db_entry.match_fvs["l4_src_port"] = "0x2e90 & 0xFFF0"; + app_db_entry.match_fvs["l4_dst_port"] = "0x2e98"; + app_db_entry.match_fvs["ip_id"] = "2"; + app_db_entry.match_fvs["inner_l4_src_port"] = "1212"; + app_db_entry.match_fvs["inner_l4_dst_port"] = "1212"; + app_db_entry.match_fvs["dscp"] = "8"; + app_db_entry.match_fvs["inner_ip_src"] = "192.50.128.0"; + app_db_entry.match_fvs["inner_ip_dst"] = "192.50.128.0/17"; + app_db_entry.match_fvs["inner_ipv6_src"] = "1234:5678::"; + app_db_entry.match_fvs["inner_ipv6_dst"] = "2001:db8:3c4d:15::/64"; + app_db_entry.match_fvs["ip_src"] = " 192.50.128.0 & 255.255.255.0 "; + app_db_entry.match_fvs["ip_dst"] = "192.50.128.0/17"; + app_db_entry.match_fvs["ipv6_src"] = "2001:db8:3c4d:15::/64"; + app_db_entry.match_fvs["tc"] = "1"; + app_db_entry.match_fvs["icmp_type"] = "9"; // RA + app_db_entry.match_fvs["icmp_code"] = "0"; // Normal RA + app_db_entry.match_fvs["tos"] = "32"; + app_db_entry.match_fvs["icmpv6_type"] = "134"; // RA + app_db_entry.match_fvs["icmpv6_code"] = "0"; // Normal RA + app_db_entry.match_fvs["ecn"] = "0"; + app_db_entry.match_fvs["inner_ip_protocol"] = "0x01"; // ICMP + app_db_entry.match_fvs["ip_protocol"] = "0x6"; // TCP + app_db_entry.match_fvs["ipv6_flow_label"] = "0x88 & 0xFFFFFFFF"; + app_db_entry.match_fvs["tunnel_vni"] = "88"; + app_db_entry.match_fvs["ip_frag"] = P4_IP_FRAG_HEAD; + app_db_entry.match_fvs["packet_vlan"] = P4_PACKET_VLAN_SINGLE_OUTER_TAG; + app_db_entry.match_fvs["outer_vlan_pri"] = "100"; + app_db_entry.match_fvs["outer_vlan_id"] = "100"; + app_db_entry.match_fvs["outer_vlan_cfi"] = "100"; + app_db_entry.match_fvs["inner_vlan_pri"] = "200"; + app_db_entry.match_fvs["inner_vlan_id"] = "200"; + app_db_entry.match_fvs["inner_vlan_cfi"] = "200"; + + const auto &acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + auto *acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + auto *acl_table = GetAclTable(kAclIngressTableName); + ASSERT_NE(nullptr, acl_rule); + ASSERT_NE(nullptr, acl_table); + EXPECT_NO_FATAL_FAILURE(IsExpectedAclRuleMapping(acl_rule, app_db_entry, *acl_table)); + EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); + + // Check match field value + EXPECT_EQ(2, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS].aclfield.data.objlist.count); + EXPECT_EQ(0x112233, acl_rule->in_ports_oids[0]); + EXPECT_EQ(0x1fed3, acl_rule->in_ports_oids[1]); + EXPECT_EQ(2, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS].aclfield.data.objlist.count); + EXPECT_EQ(0x9988, acl_rule->out_ports_oids[0]); + EXPECT_EQ(0x56789abcdef, acl_rule->out_ports_oids[1]); + + // Verify SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN + EXPECT_EQ(2, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].aclfield.data.u8list.count); + EXPECT_EQ(acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].data[0], + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].aclfield.data.u8list.list[0]); + EXPECT_EQ(acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].data[1], + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].aclfield.data.u8list.list[1]); + EXPECT_EQ(acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].mask[0], + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].aclfield.mask.u8list.list[0]); + EXPECT_EQ(acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].mask[1], + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].aclfield.mask.u8list.list[1]); + EXPECT_EQ(0xff, acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].data[0]); + EXPECT_EQ(0x11, acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].data[1]); + EXPECT_EQ(0xff, acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].mask[0]); + EXPECT_EQ(0xff, acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].mask[1]); + // Verify SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1 + EXPECT_EQ(2, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1].aclfield.data.objlist.count); + EXPECT_EQ(acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1].data[0], + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1].aclfield.data.u8list.list[0]); + EXPECT_EQ(acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1].data[1], + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1].aclfield.data.u8list.list[1]); + EXPECT_EQ(acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1].mask[0], + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1].aclfield.mask.u8list.list[0]); + EXPECT_EQ(acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1].mask[1], + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1].aclfield.mask.u8list.list[1]); + EXPECT_EQ(0x22, acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1].data[0]); + EXPECT_EQ(0x31, acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1].data[1]); + EXPECT_EQ(0xff, acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1].mask[0]); + EXPECT_EQ(0xff, acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1].mask[1]); + EXPECT_EQ(0xaabbccdd, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IN_PORT].aclfield.data.oid); + EXPECT_EQ(0x56789abcdff, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORT].aclfield.data.oid); + EXPECT_EQ(0x2, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_TCP_FLAGS].aclfield.data.u8); + EXPECT_EQ(0x3F, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_TCP_FLAGS].aclfield.mask.u8); + EXPECT_EQ(0x2, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IP_FLAGS].aclfield.data.u8); + EXPECT_EQ(0x3F, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IP_FLAGS].aclfield.mask.u8); + EXPECT_EQ(8, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_DSCP].aclfield.data.u8); + EXPECT_EQ(0x3F, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_DSCP].aclfield.mask.u8); + EXPECT_EQ(0x0800, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE].aclfield.data.u16); + EXPECT_EQ(0xFFFF, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE].aclfield.mask.u16); + EXPECT_EQ(0x2e90, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_L4_SRC_PORT].aclfield.data.u16); + EXPECT_EQ(0xFFF0, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_L4_SRC_PORT].aclfield.mask.u16); + EXPECT_EQ(2, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IP_IDENTIFICATION].aclfield.data.u16); + EXPECT_EQ(0xFFFF, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IP_IDENTIFICATION].aclfield.mask.u16); + EXPECT_EQ(100, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_OUTER_VLAN_ID].aclfield.data.u16); + EXPECT_EQ(0xFFFF, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_OUTER_VLAN_ID].aclfield.mask.u16); + // 192.50.128.0 + EXPECT_EQ(swss::IpPrefix("192.50.128.0").getIp().getV4Addr(), + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_INNER_SRC_IP].aclfield.data.ip4); + EXPECT_EQ(swss::IpPrefix("192.50.128.0").getMask().getV4Addr(), + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_INNER_SRC_IP].aclfield.mask.ip4); + // 192.50.128.0 & 255.255.255.0 + EXPECT_EQ(swss::IpAddress("192.50.128.0").getV4Addr(), + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_SRC_IP].aclfield.data.ip4); + EXPECT_EQ(swss::IpAddress("255.255.255.0").getV4Addr(), + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_SRC_IP].aclfield.mask.ip4); + EXPECT_EQ(0, memcmp(acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_SRC_IPV6].aclfield.data.ip6, + swss::IpPrefix("2001:db8:3c4d:15::/64").getIp().getV6Addr(), 16)); + EXPECT_EQ(0, memcmp(acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_SRC_IPV6].aclfield.mask.ip6, + swss::IpPrefix("2001:db8:3c4d:15::/64").getMask().getV6Addr(), 16)); + + EXPECT_EQ(0, memcmp(acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_SRC_MAC].aclfield.data.mac, + swss::MacAddress("AA:BB:CC:DD:EE:FF").getMac(), 6)); + EXPECT_EQ(0, memcmp(acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_DST_MAC].aclfield.data.mac, + swss::MacAddress("AA:BB:CC:DD:EE:FF").getMac(), 6)); + EXPECT_EQ(0, memcmp(acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_DST_MAC].aclfield.mask.mac, + swss::MacAddress("FF:FF:FF:FF:FF:FF").getMac(), 6)); + EXPECT_EQ(1, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_TC].aclfield.data.u8); + EXPECT_EQ(0xFF, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_TC].aclfield.mask.u8); + EXPECT_EQ(0x88, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IPV6_FLOW_LABEL].aclfield.data.u32); + EXPECT_EQ(0xFFFFFFFF, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IPV6_FLOW_LABEL].aclfield.mask.u32); + EXPECT_EQ(SAI_ACL_IP_FRAG_HEAD, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_FRAG].aclfield.data.u32); + EXPECT_EQ(SAI_PACKET_VLAN_SINGLE_OUTER_TAG, + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_PACKET_VLAN].aclfield.data.u32); + + // Check action field value + EXPECT_EQ(SAI_PACKET_ACTION_TRAP, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.parameter.s32); + EXPECT_EQ(0x20, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); } -TEST_F(AclManagerTest, AclRuleWithColorPacketActionsButNoRateLimit) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - - // Create app_db_entry with color packet action, but no rate limit attributes - P4AclRuleAppDbEntry app_db_entry; - app_db_entry.acl_table_name = kAclIngressTableName; - app_db_entry.priority = 100; - // ACL rule match fields - app_db_entry.match_fvs["ether_type"] = "0x0800"; - app_db_entry.match_fvs["ipv6_dst"] = "fdf8:f53b:82e4::53"; - app_db_entry.match_fvs["ether_dst"] = "AA:BB:CC:DD:EE:FF"; - app_db_entry.match_fvs["ether_src"] = "AA:BB:CC:DD:EE:FF"; - app_db_entry.match_fvs["ipv6_next_header"] = "1"; - app_db_entry.match_fvs["src_ipv6_64bit"] = "fdf8:f53b:82e4::"; - app_db_entry.match_fvs["arp_tpa"] = "0xff112231"; - app_db_entry.match_fvs["udf2"] = "0x9876 & 0xAAAA"; - app_db_entry.db_key = - "ACL_PUNT_TABLE:{\"match/ether_type\": \"0x0800\",\"match/ipv6_dst\": " - "\"fdf8:f53b:82e4::53\",\"match/ether_dst\": \"AA:BB:CC:DD:EE:FF\", " - "\"match/ether_src\": \"AA:BB:CC:DD:EE:FF\", \"match/ipv6_next_header\": " - "\"1\", \"match/src_ipv6_64bit\": " - "\"fdf8:f53b:82e4::\",\"match/arp_tpa\": \"0xff112231\",\"match/udf2\": " - "\"0x9876 & 0xAAAA\",\"priority\":100}"; - - const auto& acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - // Set user defined trap for QOS_QUEUE, and color packet actions in meter - int queue_num = 8; - app_db_entry.action = "acl_trap"; - app_db_entry.action_param_fvs["queue"] = std::to_string(queue_num); - // Install rule - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL( - mock_sai_policer_, - create_policer( - _, Eq(gSwitchId), Eq(9), - Truly(std::bind(MatchSaiPolicerAttribute, 9, SAI_METER_TYPE_PACKETS, - SAI_PACKET_ACTION_TRAP, SAI_PACKET_ACTION_DROP, - SAI_PACKET_ACTION_DROP, 0x7fffffff, 0x7fffffff, - 0x7fffffff, 0x7fffffff, std::placeholders::_1)))) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - auto acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(gUserDefinedTrapStartOid + queue_num, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID] - .aclaction.parameter.oid); +TEST_F(AclManagerTest, AclRuleWithColorPacketActionsButNoRateLimit) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + + // Create app_db_entry with color packet action, but no rate limit attributes + P4AclRuleAppDbEntry app_db_entry; + app_db_entry.acl_table_name = kAclIngressTableName; + app_db_entry.priority = 100; + // ACL rule match fields + app_db_entry.match_fvs["ether_type"] = "0x0800"; + app_db_entry.match_fvs["ipv6_dst"] = "fdf8:f53b:82e4::53"; + app_db_entry.match_fvs["ether_dst"] = "AA:BB:CC:DD:EE:FF"; + app_db_entry.match_fvs["ether_src"] = "AA:BB:CC:DD:EE:FF"; + app_db_entry.match_fvs["ipv6_next_header"] = "1"; + app_db_entry.match_fvs["src_ipv6_64bit"] = "fdf8:f53b:82e4::"; + app_db_entry.match_fvs["arp_tpa"] = "0xff112231"; + app_db_entry.match_fvs["udf2"] = "0x9876 & 0xAAAA"; + app_db_entry.db_key = "ACL_PUNT_TABLE:{\"match/ether_type\": \"0x0800\",\"match/ipv6_dst\": " + "\"fdf8:f53b:82e4::53\",\"match/ether_dst\": \"AA:BB:CC:DD:EE:FF\", " + "\"match/ether_src\": \"AA:BB:CC:DD:EE:FF\", \"match/ipv6_next_header\": " + "\"1\", \"match/src_ipv6_64bit\": " + "\"fdf8:f53b:82e4::\",\"match/arp_tpa\": \"0xff112231\",\"match/udf2\": " + "\"0x9876 & 0xAAAA\",\"priority\":100}"; + + const auto &acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + // Set user defined trap for QOS_QUEUE, and color packet actions in meter + int queue_num = 8; + app_db_entry.action = "acl_trap"; + app_db_entry.action_param_fvs["queue"] = std::to_string(queue_num); + // Install rule + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, + create_policer(_, Eq(gSwitchId), Eq(9), + Truly(std::bind(MatchSaiPolicerAttribute, 9, SAI_METER_TYPE_PACKETS, + SAI_PACKET_ACTION_TRAP, SAI_PACKET_ACTION_DROP, SAI_PACKET_ACTION_DROP, + 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, std::placeholders::_1)))) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + auto acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(gUserDefinedTrapStartOid + queue_num, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID].aclaction.parameter.oid); } -TEST_F(AclManagerTest, AclRuleWithValidAction) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - const auto& acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - // Redirect action - app_db_entry.action = "redirect"; - app_db_entry.action_param_fvs["target"] = "Ethernet1"; - // Install rule - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - auto* acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(/*port_oid=*/0x112233, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT] - .aclaction.parameter.oid); - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); - - // Redirect action - app_db_entry.action = "redirect"; - app_db_entry.action_param_fvs["target"] = "Ethernet7"; - // Install rule - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(/*port_oid=*/0x1234, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT] - .aclaction.parameter.oid); - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); - - // Set up an next hop mapping - const std::string next_hop_id = "ju1u32m1.atl11:qe-3/7"; - const auto& next_hop_key = KeyGenerator::generateNextHopKey(next_hop_id); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key, - /*next_hop_oid=*/1); - app_db_entry.action = "redirect"; - app_db_entry.action_param_fvs["target"] = next_hop_id; - // Install rule - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(/*next_hop_oid=*/1, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT] - .aclaction.parameter.oid); - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); - - // Set endpoint Ip action - app_db_entry.action = "endpoint_ip"; - app_db_entry.action_param_fvs["ip_address"] = "127.0.0.1"; - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(swss::IpAddress("127.0.0.1").getV4Addr(), - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_ENDPOINT_IP] - .aclaction.parameter.ip4); - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - // Install rule - app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(0, - memcmp(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_ENDPOINT_IP] - .aclaction.parameter.ip6, - swss::IpAddress("fdf8:f53b:82e4::53").getV6Addr(), 16)); - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Mirror ingress action - app_db_entry.action = "mirror_ingress"; - app_db_entry.action_param_fvs["target"] = gMirrorSession1; - // Install rule - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - - // Check action field value - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS] - .aclaction.enable); - EXPECT_EQ( - kMirrorSessionOid1, - acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS] - .oid); - EXPECT_EQ( - gMirrorSession1, - acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS] - .name); - - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Mirror egress action - app_db_entry.action = "mirror_egress"; - app_db_entry.action_param_fvs["target"] = gMirrorSession2; - // Install rule - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - - // Check action field value - EXPECT_EQ( - acl_rule->action_fvs.end(), - acl_rule->action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS)); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS] - .aclaction.enable); - EXPECT_EQ( - kMirrorSessionOid2, - acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS] - .oid); - EXPECT_EQ( - gMirrorSession2, - acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS] - .name); - - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Set Packet Color - app_db_entry.action = "set_packet_color"; - app_db_entry.action_param_fvs["packet_color"] = "SAI_PACKET_COLOR_YELLOW"; - // Install rule - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(SAI_PACKET_COLOR_YELLOW, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_PACKET_COLOR] - .aclaction.parameter.s32); - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Set Src Mac - app_db_entry.action = "set_src_mac"; - app_db_entry.action_param_fvs["mac_address"] = "AA:BB:CC:DD:EE:FF"; - - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(0, - memcmp(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_MAC] - .aclaction.parameter.mac, - swss::MacAddress("AA:BB:CC:DD:EE:FF").getMac(), 6)); - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Set src IP - app_db_entry.action = "set_src_ip"; - app_db_entry.action_param_fvs["ip_address"] = "10.0.0.1"; - - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(swss::IpAddress("10.0.0.1").getV4Addr(), - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_IP] - .aclaction.parameter.ip4); - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Set IPv6 Dst - app_db_entry.action = "set_dst_ipv6"; - app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; - - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(0, - memcmp(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_DST_IPV6] - .aclaction.parameter.ip6, - swss::IpAddress("fdf8:f53b:82e4::53").getV6Addr(), 16)); - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Set DSCP and ECN - app_db_entry.action = "set_dscp_and_ecn"; - app_db_entry.action_param_fvs["dscp"] = "8"; - app_db_entry.action_param_fvs["ecn"] = "0"; - - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(8, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_DSCP] - .aclaction.parameter.u8); - EXPECT_EQ(0, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_ECN] - .aclaction.parameter.u8); - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Set Inner VLAN - app_db_entry.action = "set_inner_vlan"; - app_db_entry.action_param_fvs["vlan_pri"] = "100"; - app_db_entry.action_param_fvs["vlan_id"] = "100"; - - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(100, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_ID] - .aclaction.parameter.u32); - EXPECT_EQ(100, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_PRI] - .aclaction.parameter.u8); - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Set L4Src Port - app_db_entry.action = "set_l4_src_port"; - app_db_entry.action_param_fvs["port"] = "1212"; - - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(1212, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_L4_SRC_PORT] - .aclaction.parameter.u16); - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Flood action - app_db_entry.action = "flood"; - - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_FLOOD].aclaction.enable); - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Set user defined trap for QOS_QUEUE - int queue_num = 2; - app_db_entry.action = "qos_queue"; - app_db_entry.action_param_fvs["cpu_queue"] = std::to_string(queue_num); - // Install rule - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(gUserDefinedTrapStartOid + queue_num, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID] - .aclaction.parameter.oid); - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); +TEST_F(AclManagerTest, AclRuleWithValidAction) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + const auto &acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + // Redirect action + app_db_entry.action = "redirect"; + app_db_entry.action_param_fvs["target"] = "Ethernet1"; + // Install rule + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + auto *acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(/*port_oid=*/0x112233, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT].aclaction.parameter.oid); + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); + + // Redirect action + app_db_entry.action = "redirect"; + app_db_entry.action_param_fvs["target"] = "Ethernet7"; + // Install rule + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(/*port_oid=*/0x1234, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT].aclaction.parameter.oid); + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); + + // Set up an next hop mapping + const std::string next_hop_id = "ju1u32m1.atl11:qe-3/7"; + const auto &next_hop_key = KeyGenerator::generateNextHopKey(next_hop_id); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key, + /*next_hop_oid=*/1); + app_db_entry.action = "redirect"; + app_db_entry.action_param_fvs["target"] = next_hop_id; + // Install rule + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(/*next_hop_oid=*/1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT].aclaction.parameter.oid); + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); + + // Set endpoint Ip action + app_db_entry.action = "endpoint_ip"; + app_db_entry.action_param_fvs["ip_address"] = "127.0.0.1"; + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(swss::IpAddress("127.0.0.1").getV4Addr(), + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_ENDPOINT_IP].aclaction.parameter.ip4); + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + // Install rule + app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(0, memcmp(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_ENDPOINT_IP].aclaction.parameter.ip6, + swss::IpAddress("fdf8:f53b:82e4::53").getV6Addr(), 16)); + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Mirror ingress action + app_db_entry.action = "mirror_ingress"; + app_db_entry.action_param_fvs["target"] = gMirrorSession1; + // Install rule + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + + // Check action field value + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS].aclaction.enable); + EXPECT_EQ(kMirrorSessionOid1, acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS].oid); + EXPECT_EQ(gMirrorSession1, acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS].name); + + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Mirror egress action + app_db_entry.action = "mirror_egress"; + app_db_entry.action_param_fvs["target"] = gMirrorSession2; + // Install rule + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + + // Check action field value + EXPECT_EQ(acl_rule->action_fvs.end(), acl_rule->action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS)); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS].aclaction.enable); + EXPECT_EQ(kMirrorSessionOid2, acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS].oid); + EXPECT_EQ(gMirrorSession2, acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS].name); + + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Set Packet Color + app_db_entry.action = "set_packet_color"; + app_db_entry.action_param_fvs["packet_color"] = "SAI_PACKET_COLOR_YELLOW"; + // Install rule + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(SAI_PACKET_COLOR_YELLOW, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_PACKET_COLOR].aclaction.parameter.s32); + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Set Src Mac + app_db_entry.action = "set_src_mac"; + app_db_entry.action_param_fvs["mac_address"] = "AA:BB:CC:DD:EE:FF"; + + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(0, memcmp(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_MAC].aclaction.parameter.mac, + swss::MacAddress("AA:BB:CC:DD:EE:FF").getMac(), 6)); + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Set src IP + app_db_entry.action = "set_src_ip"; + app_db_entry.action_param_fvs["ip_address"] = "10.0.0.1"; + + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(swss::IpAddress("10.0.0.1").getV4Addr(), + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_IP].aclaction.parameter.ip4); + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Set IPv6 Dst + app_db_entry.action = "set_dst_ipv6"; + app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; + + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(0, memcmp(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_DST_IPV6].aclaction.parameter.ip6, + swss::IpAddress("fdf8:f53b:82e4::53").getV6Addr(), 16)); + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Set DSCP and ECN + app_db_entry.action = "set_dscp_and_ecn"; + app_db_entry.action_param_fvs["dscp"] = "8"; + app_db_entry.action_param_fvs["ecn"] = "0"; + + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(8, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_DSCP].aclaction.parameter.u8); + EXPECT_EQ(0, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_ECN].aclaction.parameter.u8); + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Set Inner VLAN + app_db_entry.action = "set_inner_vlan"; + app_db_entry.action_param_fvs["vlan_pri"] = "100"; + app_db_entry.action_param_fvs["vlan_id"] = "100"; + + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(100, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_ID].aclaction.parameter.u32); + EXPECT_EQ(100, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_PRI].aclaction.parameter.u8); + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Set L4Src Port + app_db_entry.action = "set_l4_src_port"; + app_db_entry.action_param_fvs["port"] = "1212"; + + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(1212, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_L4_SRC_PORT].aclaction.parameter.u16); + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Flood action + app_db_entry.action = "flood"; + + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_FLOOD].aclaction.enable); + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Set user defined trap for QOS_QUEUE + int queue_num = 2; + app_db_entry.action = "qos_queue"; + app_db_entry.action_param_fvs["cpu_queue"] = std::to_string(queue_num); + // Install rule + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(gUserDefinedTrapStartOid + queue_num, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID].aclaction.parameter.oid); + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); } -TEST_F(AclManagerTest, AclRuleWithVrfAction) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - const auto& acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - // Set vrf - app_db_entry.action = "set_vrf"; - app_db_entry.action_param_fvs["vrf"] = gVrfName; - // Install rule - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - auto* acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(gVrfOid, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF] - .aclaction.parameter.oid); - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); +TEST_F(AclManagerTest, AclRuleWithVrfAction) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + const auto &acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + // Set vrf + app_db_entry.action = "set_vrf"; + app_db_entry.action_param_fvs["vrf"] = gVrfName; + // Install rule + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + auto *acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(gVrfOid, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF].aclaction.parameter.oid); + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); } -TEST_F(AclManagerTest, AclRuleWithIpTypeBitEncoding) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - // Set src IP - app_db_entry.action = "set_src_ip"; - app_db_entry.action_param_fvs["ip_address"] = "10.0.0.1"; - - // Successful cases - // Wildcard match on IP_TYPE: SAI_ACL_IP_TYPE_ANY - auto acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - auto acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check match field IP_TYPE - EXPECT_NE(acl_rule->match_fvs.end(), - acl_rule->match_fvs.find(SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE)); - EXPECT_EQ(SAI_ACL_IP_TYPE_ANY, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE] - .aclfield.data.u32); - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // is_ip { value: 0x1 mask: 0x1 } = SAI_ACL_IP_TYPE_IP - app_db_entry.match_fvs["is_ip"] = "0x1"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check match field IP_TYPE - EXPECT_EQ(SAI_ACL_IP_TYPE_IP, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE] - .aclfield.data.u32); - // Remove rule - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // is_ip { value: 0x0 mask: 0x1 } = SAI_ACL_IP_TYPE_NON_IP - app_db_entry.match_fvs["is_ip"] = "0x0 & 0x1"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check match field IP_TYPE - EXPECT_EQ(SAI_ACL_IP_TYPE_NON_IP, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE] - .aclfield.data.u32); - // Remove rule - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // is_ipv4 { value: 0x1 mask: 0x1 } = SAI_ACL_IP_TYPE_IPV4ANY - app_db_entry.match_fvs.erase("is_ip"); - app_db_entry.match_fvs["is_ipv4"] = "0x1 & 0x1"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check match field IP_TYPE - EXPECT_EQ(SAI_ACL_IP_TYPE_IPV4ANY, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE] - .aclfield.data.u32); - // Remove rule - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // is_ipv4 { value: 0x0 mask: 0x1 } = SAI_ACL_IP_TYPE_NON_IPV4 - app_db_entry.match_fvs["is_ipv4"] = "0x0"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check match field IP_TYPE - EXPECT_EQ(SAI_ACL_IP_TYPE_NON_IPV4, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE] - .aclfield.data.u32); - // Remove rule - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // is_ipv6 { value: 0x1 mask: 0x1 } = SAI_ACL_IP_TYPE_IPV6ANY - app_db_entry.match_fvs.erase("is_ipv4"); - app_db_entry.match_fvs["is_ipv6"] = "0x1"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check match field IP_TYPE - EXPECT_EQ(SAI_ACL_IP_TYPE_IPV6ANY, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE] - .aclfield.data.u32); - // Remove rule - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // is_ipv6 { value: 0x0 mask: 0x1 } = SAI_ACL_IP_TYPE_NON_IPV6 - app_db_entry.match_fvs["is_ipv6"] = "0x0"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check match field IP_TYPE - EXPECT_EQ(SAI_ACL_IP_TYPE_NON_IPV6, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE] - .aclfield.data.u32); - // Remove rule - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // is_arp { value: 0x1 mask: 0x1 } = SAI_ACL_IP_TYPE_ARP - app_db_entry.match_fvs.erase("is_ipv6"); - app_db_entry.match_fvs["is_arp"] = "0x1 & 0x1"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check match field IP_TYPE - EXPECT_EQ(SAI_ACL_IP_TYPE_ARP, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE] - .aclfield.data.u32); - // Remove rule - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // is_arp_request { value: 0x1 mask: 0x1 } = SAI_ACL_IP_TYPE_ARP_REQUEST - app_db_entry.match_fvs.erase("is_arp"); - app_db_entry.match_fvs["is_arp_request"] = "0x1 & 0x1"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check match field IP_TYPE - EXPECT_EQ(SAI_ACL_IP_TYPE_ARP_REQUEST, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE] - .aclfield.data.u32); - // Remove rule - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // is_arp_reply { value: 0x1 mask: 0x1 } = SAI_ACL_IP_TYPE_ARP_REPLY - app_db_entry.match_fvs.erase("is_arp_request"); - app_db_entry.match_fvs["is_arp_reply"] = "0x1 & 0x1"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check match field IP_TYPE - EXPECT_EQ(SAI_ACL_IP_TYPE_ARP_REPLY, - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE] - .aclfield.data.u32); - // Remove rule - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - - // Failed cases - // is_arp_reply { value: 0x0 mask: 0x1 } = N/A - app_db_entry.match_fvs["is_arp_reply"] = "0x0 & 0x1"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_EQ(nullptr, acl_rule); - - // is_arp_request { value: 0x0 mask: 0x1 } = N/A - app_db_entry.match_fvs.erase("is_arp_reply"); - app_db_entry.match_fvs["is_arp_request"] = "0x0"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_EQ(nullptr, acl_rule); - - // is_arp { value: 0x0 mask: 0x1 } = N/A - app_db_entry.match_fvs.erase("is_arp_request"); - app_db_entry.match_fvs["is_arp"] = "0x0"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_EQ(nullptr, acl_rule); - - // is_ip { value: 0x1 mask: 0x0 } = N/A - app_db_entry.match_fvs.erase("is_arp"); - app_db_entry.match_fvs["is_ip"] = "0x1 & 0x0"; - acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_EQ(nullptr, acl_rule); +TEST_F(AclManagerTest, AclRuleWithIpTypeBitEncoding) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + // Set src IP + app_db_entry.action = "set_src_ip"; + app_db_entry.action_param_fvs["ip_address"] = "10.0.0.1"; + + // Successful cases + // Wildcard match on IP_TYPE: SAI_ACL_IP_TYPE_ANY + auto acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + auto acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check match field IP_TYPE + EXPECT_NE(acl_rule->match_fvs.end(), acl_rule->match_fvs.find(SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE)); + EXPECT_EQ(SAI_ACL_IP_TYPE_ANY, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE].aclfield.data.u32); + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // is_ip { value: 0x1 mask: 0x1 } = SAI_ACL_IP_TYPE_IP + app_db_entry.match_fvs["is_ip"] = "0x1"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check match field IP_TYPE + EXPECT_EQ(SAI_ACL_IP_TYPE_IP, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE].aclfield.data.u32); + // Remove rule + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // is_ip { value: 0x0 mask: 0x1 } = SAI_ACL_IP_TYPE_NON_IP + app_db_entry.match_fvs["is_ip"] = "0x0 & 0x1"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check match field IP_TYPE + EXPECT_EQ(SAI_ACL_IP_TYPE_NON_IP, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE].aclfield.data.u32); + // Remove rule + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // is_ipv4 { value: 0x1 mask: 0x1 } = SAI_ACL_IP_TYPE_IPV4ANY + app_db_entry.match_fvs.erase("is_ip"); + app_db_entry.match_fvs["is_ipv4"] = "0x1 & 0x1"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check match field IP_TYPE + EXPECT_EQ(SAI_ACL_IP_TYPE_IPV4ANY, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE].aclfield.data.u32); + // Remove rule + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // is_ipv4 { value: 0x0 mask: 0x1 } = SAI_ACL_IP_TYPE_NON_IPV4 + app_db_entry.match_fvs["is_ipv4"] = "0x0"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check match field IP_TYPE + EXPECT_EQ(SAI_ACL_IP_TYPE_NON_IPV4, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE].aclfield.data.u32); + // Remove rule + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // is_ipv6 { value: 0x1 mask: 0x1 } = SAI_ACL_IP_TYPE_IPV6ANY + app_db_entry.match_fvs.erase("is_ipv4"); + app_db_entry.match_fvs["is_ipv6"] = "0x1"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check match field IP_TYPE + EXPECT_EQ(SAI_ACL_IP_TYPE_IPV6ANY, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE].aclfield.data.u32); + // Remove rule + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // is_ipv6 { value: 0x0 mask: 0x1 } = SAI_ACL_IP_TYPE_NON_IPV6 + app_db_entry.match_fvs["is_ipv6"] = "0x0"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check match field IP_TYPE + EXPECT_EQ(SAI_ACL_IP_TYPE_NON_IPV6, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE].aclfield.data.u32); + // Remove rule + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // is_arp { value: 0x1 mask: 0x1 } = SAI_ACL_IP_TYPE_ARP + app_db_entry.match_fvs.erase("is_ipv6"); + app_db_entry.match_fvs["is_arp"] = "0x1 & 0x1"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check match field IP_TYPE + EXPECT_EQ(SAI_ACL_IP_TYPE_ARP, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE].aclfield.data.u32); + // Remove rule + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // is_arp_request { value: 0x1 mask: 0x1 } = SAI_ACL_IP_TYPE_ARP_REQUEST + app_db_entry.match_fvs.erase("is_arp"); + app_db_entry.match_fvs["is_arp_request"] = "0x1 & 0x1"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check match field IP_TYPE + EXPECT_EQ(SAI_ACL_IP_TYPE_ARP_REQUEST, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE].aclfield.data.u32); + // Remove rule + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // is_arp_reply { value: 0x1 mask: 0x1 } = SAI_ACL_IP_TYPE_ARP_REPLY + app_db_entry.match_fvs.erase("is_arp_request"); + app_db_entry.match_fvs["is_arp_reply"] = "0x1 & 0x1"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check match field IP_TYPE + EXPECT_EQ(SAI_ACL_IP_TYPE_ARP_REPLY, acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE].aclfield.data.u32); + // Remove rule + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + + // Failed cases + // is_arp_reply { value: 0x0 mask: 0x1 } = N/A + app_db_entry.match_fvs["is_arp_reply"] = "0x0 & 0x1"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_EQ(nullptr, acl_rule); + + // is_arp_request { value: 0x0 mask: 0x1 } = N/A + app_db_entry.match_fvs.erase("is_arp_reply"); + app_db_entry.match_fvs["is_arp_request"] = "0x0"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_EQ(nullptr, acl_rule); + + // is_arp { value: 0x0 mask: 0x1 } = N/A + app_db_entry.match_fvs.erase("is_arp_request"); + app_db_entry.match_fvs["is_arp"] = "0x0"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_EQ(nullptr, acl_rule); + + // is_ip { value: 0x1 mask: 0x0 } = N/A + app_db_entry.match_fvs.erase("is_arp"); + app_db_entry.match_fvs["is_ip"] = "0x1 & 0x0"; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_EQ(nullptr, acl_rule); } -TEST_F(AclManagerTest, UpdateAclRuleWithActionMeterChange) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - const auto& acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - sai_object_id_t meter_oid; - uint32_t ref_cnt; - const auto& table_name_and_rule_key = - concatTableNameAndRuleKey(kAclIngressTableName, acl_rule_key); - app_db_entry.action = "punt_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "1"; - // Install rule - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - auto* acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(SAI_PACKET_ACTION_TRAP, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.parameter.s32); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.enable); - EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); - EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &meter_oid)); - EXPECT_EQ(kAclMeterOid1, meter_oid); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - // Update action parameter value - app_db_entry.action = "punt_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "2"; - // Update rule - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(SAI_PACKET_ACTION_TRAP, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.parameter.s32); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.enable); - EXPECT_EQ(2, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); - EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); - - EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &meter_oid)); - EXPECT_EQ(kAclMeterOid1, meter_oid); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - // Update packet action: Copy green packet - app_db_entry.action = "copy_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "2"; - app_db_entry.meter.cburst = 500; - app_db_entry.meter.cir = 500; - app_db_entry.meter.pburst = 600; - app_db_entry.meter.pir = 600; - // Update meter attribute for green packet action - EXPECT_CALL(mock_sai_policer_, set_policer_attribute(Eq(kAclMeterOid1), _)) - .Times(5) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(acl_rule->action_fvs.end(), - acl_rule->action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION)); - EXPECT_EQ(2, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); - EXPECT_FALSE(acl_rule->meter.packet_color_actions.empty()); - EXPECT_NE(acl_rule->meter.packet_color_actions.find( - SAI_POLICER_ATTR_GREEN_PACKET_ACTION), - acl_rule->meter.packet_color_actions.end()); - EXPECT_EQ(SAI_PACKET_ACTION_COPY, - acl_rule->meter - .packet_color_actions[SAI_POLICER_ATTR_GREEN_PACKET_ACTION]); - EXPECT_EQ(500, acl_rule->meter.cburst); - EXPECT_EQ(500, acl_rule->meter.cir); - EXPECT_EQ(600, acl_rule->meter.pburst); - EXPECT_EQ(600, acl_rule->meter.pir); - EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &meter_oid)); - EXPECT_EQ(kAclMeterOid1, meter_oid); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - // Update ACL rule : disable rate limiting, packet action is still existing. - app_db_entry.meter.enabled = false; - // Update meter attribute for green packet action - EXPECT_CALL(mock_sai_policer_, set_policer_attribute(Eq(kAclMeterOid1), _)) - .Times(4) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_FALSE(acl_rule->meter.packet_color_actions.empty()); - EXPECT_NE(acl_rule->meter.packet_color_actions.find( - SAI_POLICER_ATTR_GREEN_PACKET_ACTION), - acl_rule->meter.packet_color_actions.end()); - EXPECT_EQ(SAI_PACKET_ACTION_COPY, - acl_rule->meter - .packet_color_actions[SAI_POLICER_ATTR_GREEN_PACKET_ACTION]); - EXPECT_EQ(2, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); - EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &meter_oid)); - EXPECT_TRUE(acl_rule->meter.enabled); - EXPECT_EQ(0x7fffffff, acl_rule->meter.cburst); - EXPECT_EQ(0x7fffffff, acl_rule->meter.cir); - EXPECT_EQ(0x7fffffff, acl_rule->meter.pburst); - EXPECT_EQ(0x7fffffff, acl_rule->meter.pir); - - // Update meter: enable rate limiting and reset green packet action - app_db_entry.action = "punt_and_set_tc"; - app_db_entry.meter.enabled = true; - // Update meter and rule: reset color packet action and update entry - // attribute - EXPECT_CALL(mock_sai_policer_, set_policer_attribute(Eq(kAclMeterOid1), _)) - .Times(5) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(SAI_PACKET_ACTION_TRAP, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.parameter.s32); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.enable); - EXPECT_EQ(2, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); - EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); - EXPECT_EQ(500, acl_rule->meter.cburst); - EXPECT_EQ(500, acl_rule->meter.cir); - EXPECT_EQ(600, acl_rule->meter.pburst); - EXPECT_EQ(600, acl_rule->meter.pir); - EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &meter_oid)); - EXPECT_EQ(kAclMeterOid1, meter_oid); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - // Update ACL rule : disable meter - app_db_entry.meter.enabled = false; - // Update meter attribute for green packet action - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(SAI_PACKET_ACTION_TRAP, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.parameter.s32); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.enable); - EXPECT_EQ(2, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); - EXPECT_FALSE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &meter_oid)); - EXPECT_EQ(0, acl_rule->meter.cburst); - EXPECT_EQ(0, acl_rule->meter.cir); - EXPECT_EQ(0, acl_rule->meter.pburst); - EXPECT_EQ(0, acl_rule->meter.pir); - EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); - EXPECT_FALSE(acl_rule->meter.enabled); - - // Update ACL rule : enable meter - app_db_entry.meter.enabled = true; - // Update meter attribute for green packet action - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid2), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(2, acl_rule->action_fvs.size()); - EXPECT_EQ(SAI_PACKET_ACTION_TRAP, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.parameter.s32); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.enable); - EXPECT_EQ(2, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); - EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &meter_oid)); - EXPECT_EQ(kAclMeterOid2, meter_oid); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); - EXPECT_TRUE(acl_rule->meter.enabled); - - // Redirect action - app_db_entry.action = "redirect"; - app_db_entry.action_param_fvs["target"] = "Ethernet1"; - // Update rule - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .Times(3) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_EQ( - /*port_oid=*/0x112233, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT] - .aclaction.parameter.oid); - - // Set up an next hop mapping - const std::string next_hop_id = "ju1u32m1.atl11:qe-3/7"; - const auto& next_hop_key = KeyGenerator::generateNextHopKey(next_hop_id); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key, - /*next_hop_oid=*/1); - app_db_entry.action = "redirect"; - app_db_entry.action_param_fvs["target"] = next_hop_id; - // Update rule - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_EQ(/*next_hop_oid=*/1, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT] - .aclaction.parameter.oid); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - next_hop_key, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - EXPECT_EQ(next_hop_key, acl_rule->action_redirect_nexthop_key); - - // Set endpoint Ip action - app_db_entry.action = "endpoint_ip"; - app_db_entry.action_param_fvs["ip_address"] = "127.0.0.1"; - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .Times(2) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(swss::IpAddress("127.0.0.1").getV4Addr(), - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_ENDPOINT_IP] - .aclaction.parameter.ip4); - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - next_hop_key, &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .Times(1) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_EQ(0, - memcmp(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_ENDPOINT_IP] - .aclaction.parameter.ip6, - swss::IpAddress("fdf8:f53b:82e4::53").getV6Addr(), 16)); - - // Set src Mac - app_db_entry.action = "set_src_mac"; - app_db_entry.action_param_fvs["mac_address"] = "AA:BB:CC:DD:EE:FF"; - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .Times(2) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_EQ(0, - memcmp(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_MAC] - .aclaction.parameter.mac, - swss::MacAddress("AA:BB:CC:DD:EE:FF").getMac(), 6)); - app_db_entry.action_param_fvs["mac_address"] = "11:22:33:44:55:66"; - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_EQ(0, - memcmp(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_MAC] - .aclaction.parameter.mac, - swss::MacAddress("11:22:33:44:55:66").getMac(), 6)); - - // Set Inner VLAN - app_db_entry.action = "set_inner_vlan"; - app_db_entry.action_param_fvs["vlan_pri"] = "100"; - app_db_entry.action_param_fvs["vlan_id"] = "100"; - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .Times(3) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(2, acl_rule->action_fvs.size()); - EXPECT_EQ(100, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_ID] - .aclaction.parameter.u32); - EXPECT_EQ(100, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_PRI] - .aclaction.parameter.u8); - app_db_entry.action_param_fvs["vlan_pri"] = "150"; - app_db_entry.action_param_fvs["vlan_id"] = "150"; - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .Times(2) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(2, acl_rule->action_fvs.size()); - EXPECT_EQ(150, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_ID] - .aclaction.parameter.u32); - EXPECT_EQ(150, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_PRI] - .aclaction.parameter.u8); - - // Set src IP - app_db_entry.action = "set_src_ip"; - app_db_entry.action_param_fvs["ip_address"] = "10.0.0.1"; - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .Times(3) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_EQ(swss::IpAddress("10.0.0.1").getV4Addr(), - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_IP] - .aclaction.parameter.ip4); - app_db_entry.action_param_fvs["ip_address"] = "10.10.10.1"; - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .Times(1) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_EQ(swss::IpAddress("10.10.10.1").getV4Addr(), - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_IP] - .aclaction.parameter.ip4); - - // Set IPv6 Dst - app_db_entry.action = "set_dst_ipv6"; - app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .Times(2) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_EQ(0, - memcmp(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_DST_IPV6] - .aclaction.parameter.ip6, - swss::IpAddress("fdf8:f53b:82e4::53").getV6Addr(), 16)); - app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b::53"; - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .Times(1) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_EQ(0, - memcmp(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_DST_IPV6] - .aclaction.parameter.ip6, - swss::IpAddress("fdf8:f53b::53").getV6Addr(), 16)); - - // Mirror ingress action - app_db_entry.action = "mirror_ingress"; - app_db_entry.action_param_fvs["target"] = gMirrorSession1; - // Update rule - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .Times(3) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - - // Check action field value - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS] - .aclaction.enable); - EXPECT_EQ( - kMirrorSessionOid1, - acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS] - .oid); - EXPECT_EQ( - gMirrorSession1, - acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS] - .name); - - app_db_entry.action_param_fvs["target"] = gMirrorSession2; - - // Update rule - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - - // Check action field value - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS] - .aclaction.enable); - EXPECT_EQ( - kMirrorSessionOid2, - acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS] - .oid); - EXPECT_EQ( - gMirrorSession2, - acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS] - .name); - - // Flood action - app_db_entry.action = "flood"; - - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .Times(2) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_FLOOD].aclaction.enable); - - // QOS_QUEUE action to set user defined trap for CPU queue number 3 - int queue_num = 3; - app_db_entry.action = "qos_queue"; - app_db_entry.action_param_fvs["cpu_queue"] = std::to_string(queue_num); - - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .Times(2) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID] - .aclaction.enable); - EXPECT_EQ(gUserDefinedTrapStartOid + queue_num, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID] - .aclaction.parameter.oid); - - // QOS_QUEUE action to set user defined trap CPU queue number 4 - queue_num = 4; - app_db_entry.action_param_fvs["cpu_queue"] = std::to_string(queue_num); - - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID] - .aclaction.enable); - EXPECT_EQ(gUserDefinedTrapStartOid + queue_num, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID] - .aclaction.parameter.oid); +TEST_F(AclManagerTest, UpdateAclRuleWithActionMeterChange) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + const auto &acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + sai_object_id_t meter_oid; + uint32_t ref_cnt; + const auto &table_name_and_rule_key = concatTableNameAndRuleKey(kAclIngressTableName, acl_rule_key); + app_db_entry.action = "punt_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "1"; + // Install rule + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + auto *acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(SAI_PACKET_ACTION_TRAP, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.parameter.s32); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.enable); + EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); + EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &meter_oid)); + EXPECT_EQ(kAclMeterOid1, meter_oid); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + // Update action parameter value + app_db_entry.action = "punt_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "2"; + // Update rule + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(SAI_PACKET_ACTION_TRAP, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.parameter.s32); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.enable); + EXPECT_EQ(2, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); + EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); + + EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &meter_oid)); + EXPECT_EQ(kAclMeterOid1, meter_oid); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + // Update packet action: Copy green packet + app_db_entry.action = "copy_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "2"; + app_db_entry.meter.cburst = 500; + app_db_entry.meter.cir = 500; + app_db_entry.meter.pburst = 600; + app_db_entry.meter.pir = 600; + // Update meter attribute for green packet action + EXPECT_CALL(mock_sai_policer_, set_policer_attribute(Eq(kAclMeterOid1), _)) + .Times(5) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(acl_rule->action_fvs.end(), acl_rule->action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION)); + EXPECT_EQ(2, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); + EXPECT_FALSE(acl_rule->meter.packet_color_actions.empty()); + EXPECT_NE(acl_rule->meter.packet_color_actions.find(SAI_POLICER_ATTR_GREEN_PACKET_ACTION), + acl_rule->meter.packet_color_actions.end()); + EXPECT_EQ(SAI_PACKET_ACTION_COPY, acl_rule->meter.packet_color_actions[SAI_POLICER_ATTR_GREEN_PACKET_ACTION]); + EXPECT_EQ(500, acl_rule->meter.cburst); + EXPECT_EQ(500, acl_rule->meter.cir); + EXPECT_EQ(600, acl_rule->meter.pburst); + EXPECT_EQ(600, acl_rule->meter.pir); + EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &meter_oid)); + EXPECT_EQ(kAclMeterOid1, meter_oid); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + // Update ACL rule : disable rate limiting, packet action is still existing. + app_db_entry.meter.enabled = false; + // Update meter attribute for green packet action + EXPECT_CALL(mock_sai_policer_, set_policer_attribute(Eq(kAclMeterOid1), _)) + .Times(4) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_FALSE(acl_rule->meter.packet_color_actions.empty()); + EXPECT_NE(acl_rule->meter.packet_color_actions.find(SAI_POLICER_ATTR_GREEN_PACKET_ACTION), + acl_rule->meter.packet_color_actions.end()); + EXPECT_EQ(SAI_PACKET_ACTION_COPY, acl_rule->meter.packet_color_actions[SAI_POLICER_ATTR_GREEN_PACKET_ACTION]); + EXPECT_EQ(2, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); + EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &meter_oid)); + EXPECT_TRUE(acl_rule->meter.enabled); + EXPECT_EQ(0x7fffffff, acl_rule->meter.cburst); + EXPECT_EQ(0x7fffffff, acl_rule->meter.cir); + EXPECT_EQ(0x7fffffff, acl_rule->meter.pburst); + EXPECT_EQ(0x7fffffff, acl_rule->meter.pir); + + // Update meter: enable rate limiting and reset green packet action + app_db_entry.action = "punt_and_set_tc"; + app_db_entry.meter.enabled = true; + // Update meter and rule: reset color packet action and update entry + // attribute + EXPECT_CALL(mock_sai_policer_, set_policer_attribute(Eq(kAclMeterOid1), _)) + .Times(5) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(SAI_PACKET_ACTION_TRAP, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.parameter.s32); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.enable); + EXPECT_EQ(2, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); + EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); + EXPECT_EQ(500, acl_rule->meter.cburst); + EXPECT_EQ(500, acl_rule->meter.cir); + EXPECT_EQ(600, acl_rule->meter.pburst); + EXPECT_EQ(600, acl_rule->meter.pir); + EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &meter_oid)); + EXPECT_EQ(kAclMeterOid1, meter_oid); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + // Update ACL rule : disable meter + app_db_entry.meter.enabled = false; + // Update meter attribute for green packet action + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(SAI_PACKET_ACTION_TRAP, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.parameter.s32); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.enable); + EXPECT_EQ(2, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); + EXPECT_FALSE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &meter_oid)); + EXPECT_EQ(0, acl_rule->meter.cburst); + EXPECT_EQ(0, acl_rule->meter.cir); + EXPECT_EQ(0, acl_rule->meter.pburst); + EXPECT_EQ(0, acl_rule->meter.pir); + EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); + EXPECT_FALSE(acl_rule->meter.enabled); + + // Update ACL rule : enable meter + app_db_entry.meter.enabled = true; + // Update meter attribute for green packet action + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid2), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(2, acl_rule->action_fvs.size()); + EXPECT_EQ(SAI_PACKET_ACTION_TRAP, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.parameter.s32); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.enable); + EXPECT_EQ(2, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); + EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &meter_oid)); + EXPECT_EQ(kAclMeterOid2, meter_oid); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); + EXPECT_TRUE(acl_rule->meter.enabled); + + // Redirect action + app_db_entry.action = "redirect"; + app_db_entry.action_param_fvs["target"] = "Ethernet1"; + // Update rule + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .Times(3) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_EQ( + /*port_oid=*/0x112233, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT].aclaction.parameter.oid); + + // Set up an next hop mapping + const std::string next_hop_id = "ju1u32m1.atl11:qe-3/7"; + const auto &next_hop_key = KeyGenerator::generateNextHopKey(next_hop_id); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key, + /*next_hop_oid=*/1); + app_db_entry.action = "redirect"; + app_db_entry.action_param_fvs["target"] = next_hop_id; + // Update rule + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_EQ(/*next_hop_oid=*/1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT].aclaction.parameter.oid); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + EXPECT_EQ(next_hop_key, acl_rule->action_redirect_nexthop_key); + + // Set endpoint Ip action + app_db_entry.action = "endpoint_ip"; + app_db_entry.action_param_fvs["ip_address"] = "127.0.0.1"; + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .Times(2) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(swss::IpAddress("127.0.0.1").getV4Addr(), + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_ENDPOINT_IP].aclaction.parameter.ip4); + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key, &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .Times(1) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_EQ(0, memcmp(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_ENDPOINT_IP].aclaction.parameter.ip6, + swss::IpAddress("fdf8:f53b:82e4::53").getV6Addr(), 16)); + + // Set src Mac + app_db_entry.action = "set_src_mac"; + app_db_entry.action_param_fvs["mac_address"] = "AA:BB:CC:DD:EE:FF"; + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .Times(2) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_EQ(0, memcmp(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_MAC].aclaction.parameter.mac, + swss::MacAddress("AA:BB:CC:DD:EE:FF").getMac(), 6)); + app_db_entry.action_param_fvs["mac_address"] = "11:22:33:44:55:66"; + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_EQ(0, memcmp(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_MAC].aclaction.parameter.mac, + swss::MacAddress("11:22:33:44:55:66").getMac(), 6)); + + // Set Inner VLAN + app_db_entry.action = "set_inner_vlan"; + app_db_entry.action_param_fvs["vlan_pri"] = "100"; + app_db_entry.action_param_fvs["vlan_id"] = "100"; + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .Times(3) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(2, acl_rule->action_fvs.size()); + EXPECT_EQ(100, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_ID].aclaction.parameter.u32); + EXPECT_EQ(100, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_PRI].aclaction.parameter.u8); + app_db_entry.action_param_fvs["vlan_pri"] = "150"; + app_db_entry.action_param_fvs["vlan_id"] = "150"; + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .Times(2) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(2, acl_rule->action_fvs.size()); + EXPECT_EQ(150, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_ID].aclaction.parameter.u32); + EXPECT_EQ(150, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_INNER_VLAN_PRI].aclaction.parameter.u8); + + // Set src IP + app_db_entry.action = "set_src_ip"; + app_db_entry.action_param_fvs["ip_address"] = "10.0.0.1"; + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .Times(3) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_EQ(swss::IpAddress("10.0.0.1").getV4Addr(), + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_IP].aclaction.parameter.ip4); + app_db_entry.action_param_fvs["ip_address"] = "10.10.10.1"; + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .Times(1) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_EQ(swss::IpAddress("10.10.10.1").getV4Addr(), + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_SRC_IP].aclaction.parameter.ip4); + + // Set IPv6 Dst + app_db_entry.action = "set_dst_ipv6"; + app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .Times(2) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_EQ(0, memcmp(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_DST_IPV6].aclaction.parameter.ip6, + swss::IpAddress("fdf8:f53b:82e4::53").getV6Addr(), 16)); + app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b::53"; + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .Times(1) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_EQ(0, memcmp(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_DST_IPV6].aclaction.parameter.ip6, + swss::IpAddress("fdf8:f53b::53").getV6Addr(), 16)); + + // Mirror ingress action + app_db_entry.action = "mirror_ingress"; + app_db_entry.action_param_fvs["target"] = gMirrorSession1; + // Update rule + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .Times(3) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + + // Check action field value + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS].aclaction.enable); + EXPECT_EQ(kMirrorSessionOid1, acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS].oid); + EXPECT_EQ(gMirrorSession1, acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS].name); + + app_db_entry.action_param_fvs["target"] = gMirrorSession2; + + // Update rule + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + + // Check action field value + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS].aclaction.enable); + EXPECT_EQ(kMirrorSessionOid2, acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS].oid); + EXPECT_EQ(gMirrorSession2, acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS].name); + + // Flood action + app_db_entry.action = "flood"; + + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .Times(2) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_FLOOD].aclaction.enable); + + // QOS_QUEUE action to set user defined trap for CPU queue number 3 + int queue_num = 3; + app_db_entry.action = "qos_queue"; + app_db_entry.action_param_fvs["cpu_queue"] = std::to_string(queue_num); + + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .Times(2) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID].aclaction.enable); + EXPECT_EQ(gUserDefinedTrapStartOid + queue_num, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID].aclaction.parameter.oid); + + // QOS_QUEUE action to set user defined trap CPU queue number 4 + queue_num = 4; + app_db_entry.action_param_fvs["cpu_queue"] = std::to_string(queue_num); + + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID].aclaction.enable); + EXPECT_EQ(gUserDefinedTrapStartOid + queue_num, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_USER_TRAP_ID].aclaction.parameter.oid); } -TEST_F(AclManagerTest, UpdateAclRuleWithVrfActionChange) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - const auto& acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - const auto& table_name_and_rule_key = - concatTableNameAndRuleKey(kAclIngressTableName, acl_rule_key); - app_db_entry.action = "punt_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "1"; - // Install rule - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - auto* acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - - // Set VRF - app_db_entry.action = "set_vrf"; - app_db_entry.action_param_fvs["vrf"] = gVrfName; - // Update rule - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .Times(3) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_EQ(gVrfOid, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF] - .aclaction.parameter.oid); - app_db_entry.action_param_fvs["vrf"] = ""; - // Update rule - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(1, acl_rule->action_fvs.size()); - EXPECT_EQ(gVirtualRouterId, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF] - .aclaction.parameter.oid); +TEST_F(AclManagerTest, UpdateAclRuleWithVrfActionChange) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + const auto &acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); + const auto &table_name_and_rule_key = concatTableNameAndRuleKey(kAclIngressTableName, acl_rule_key); + app_db_entry.action = "punt_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "1"; + // Install rule + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + auto *acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + + // Set VRF + app_db_entry.action = "set_vrf"; + app_db_entry.action_param_fvs["vrf"] = gVrfName; + // Update rule + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .Times(3) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_EQ(gVrfOid, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF].aclaction.parameter.oid); + app_db_entry.action_param_fvs["vrf"] = ""; + // Update rule + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(1, acl_rule->action_fvs.size()); + EXPECT_EQ(gVirtualRouterId, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_VRF].aclaction.parameter.oid); } -TEST_F(AclManagerTest, UpdateAclRuleFailsWhenSaiCallFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - auto acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "15"); - - sai_object_id_t meter_oid; - uint32_t ref_cnt; - const auto& table_name_and_rule_key = - concatTableNameAndRuleKey(kAclIngressTableName, acl_rule_key); - app_db_entry.action = "punt_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "1"; - // Install rule - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - auto* acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - - // Update packet action: Copy green packet. Fails when update meter - // attribute fails - app_db_entry.action = "copy_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "2"; - // Update meter attribute for green packet action - EXPECT_CALL(mock_sai_policer_, set_policer_attribute(Eq(kAclMeterOid1), _)) - .WillOnce(Return(SAI_STATUS_NOT_SUPPORTED)); - EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ("punt_and_set_tc", acl_rule->p4_action); - EXPECT_EQ(SAI_PACKET_ACTION_TRAP, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.parameter.s32); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.enable); - EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); - EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &meter_oid)); - EXPECT_EQ(kAclMeterOid1, meter_oid); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - // Update packet action and rate limiting. Fails when update meter attribute - // fails plue meter attribute recovery fails. - app_db_entry.action = "copy_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "2"; - app_db_entry.meter.cburst = 500; - app_db_entry.meter.cir = 500; - app_db_entry.meter.pburst = 600; - app_db_entry.meter.pir = 600; - // Update meter attribute for green packet action - EXPECT_CALL(mock_sai_policer_, set_policer_attribute(Eq(kAclMeterOid1), _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_FAILURE)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ("punt_and_set_tc", acl_rule->p4_action); - EXPECT_EQ(SAI_PACKET_ACTION_TRAP, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.parameter.s32); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.enable); - EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); - EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &meter_oid)); - EXPECT_EQ(kAclMeterOid1, meter_oid); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - // Update packet action: Copy green packet. Fails when action param is - // missing - app_db_entry.action = "copy_and_set_tc"; - app_db_entry.action_param_fvs.erase("traffic_class"); - app_db_entry.meter.cburst = 80; - app_db_entry.meter.cir = 80; - app_db_entry.meter.pburst = 200; - app_db_entry.meter.pir = 200; - // Update meter attribute for green packet action - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ("punt_and_set_tc", acl_rule->p4_action); - EXPECT_EQ(SAI_PACKET_ACTION_TRAP, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.parameter.s32); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.enable); - EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); - EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &meter_oid)); - EXPECT_EQ(kAclMeterOid1, meter_oid); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - // Update packet action: Copy green packet. Fails when updating ACL rule - // fails - app_db_entry.action = "copy_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "2"; - // Update meter attribute for green packet action - EXPECT_CALL(mock_sai_policer_, set_policer_attribute(Eq(kAclMeterOid1), _)) - .Times(2) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .WillOnce(Return(SAI_STATUS_NOT_SUPPORTED)); - EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ("punt_and_set_tc", acl_rule->p4_action); - EXPECT_EQ(SAI_PACKET_ACTION_TRAP, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.parameter.s32); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.enable); - EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); - EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &meter_oid)); - EXPECT_EQ(kAclMeterOid1, meter_oid); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - // Update packet action: Copy green packet. Fails when updating ACL rule - // fails and meter recovery fails - app_db_entry.action = "copy_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "2"; - // Update meter attribute for green packet action - EXPECT_CALL(mock_sai_policer_, set_policer_attribute(Eq(kAclMeterOid1), _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .WillOnce(Return(SAI_STATUS_NOT_SUPPORTED)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ("punt_and_set_tc", acl_rule->p4_action); - EXPECT_EQ(SAI_PACKET_ACTION_TRAP, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.parameter.s32); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.enable); - EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); - EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &meter_oid)); - EXPECT_EQ(kAclMeterOid1, meter_oid); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - // Remove meter in ACL rule: fails when deleting meter fails plus ACL rule - // recovery fails. - app_db_entry.meter.enabled = false; - app_db_entry.action = "punt_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "2"; - // Remove meter - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ(SAI_PACKET_ACTION_TRAP, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.parameter.s32); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.enable); - EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); - EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); - EXPECT_TRUE(acl_rule->meter.enabled); - EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &meter_oid)); - EXPECT_EQ(kAclMeterOid1, meter_oid); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - // Successfully remove meter - app_db_entry.action = "punt_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "1"; - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action field value - EXPECT_EQ("punt_and_set_tc", acl_rule->p4_action); - EXPECT_EQ(SAI_PACKET_ACTION_TRAP, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.parameter.s32); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.enable); - EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); - EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); - EXPECT_FALSE(acl_rule->meter.enabled); - EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_POLICER, - table_name_and_rule_key)); - - // Add meter in ACL rule with packet color action - app_db_entry.meter.enabled = true; - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid2), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid2))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action and meter - EXPECT_EQ(SAI_PACKET_ACTION_TRAP, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.parameter.s32); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.enable); - EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); - EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); - EXPECT_FALSE(acl_rule->meter.enabled); - - // Add meter in ACL rule with packet color action. Fails when updating ACL - // rule fails and meter recovery fails - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid2), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, - set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) - .WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid2))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, - ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); - acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(nullptr, acl_rule); - // Check action and meter - EXPECT_EQ(SAI_PACKET_ACTION_TRAP, - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.parameter.s32); - EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION] - .aclaction.enable); - EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] - .aclaction.parameter.u8); - EXPECT_TRUE( - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); - EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); - EXPECT_FALSE(acl_rule->meter.enabled); +TEST_F(AclManagerTest, UpdateAclRuleFailsWhenSaiCallFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + auto acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "15"); + + sai_object_id_t meter_oid; + uint32_t ref_cnt; + const auto &table_name_and_rule_key = concatTableNameAndRuleKey(kAclIngressTableName, acl_rule_key); + app_db_entry.action = "punt_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "1"; + // Install rule + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + auto *acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + + // Update packet action: Copy green packet. Fails when update meter + // attribute fails + app_db_entry.action = "copy_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "2"; + // Update meter attribute for green packet action + EXPECT_CALL(mock_sai_policer_, set_policer_attribute(Eq(kAclMeterOid1), _)) + .WillOnce(Return(SAI_STATUS_NOT_SUPPORTED)); + EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ("punt_and_set_tc", acl_rule->p4_action); + EXPECT_EQ(SAI_PACKET_ACTION_TRAP, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.parameter.s32); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.enable); + EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); + EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &meter_oid)); + EXPECT_EQ(kAclMeterOid1, meter_oid); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + // Update packet action and rate limiting. Fails when update meter attribute + // fails plue meter attribute recovery fails. + app_db_entry.action = "copy_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "2"; + app_db_entry.meter.cburst = 500; + app_db_entry.meter.cir = 500; + app_db_entry.meter.pburst = 600; + app_db_entry.meter.pir = 600; + // Update meter attribute for green packet action + EXPECT_CALL(mock_sai_policer_, set_policer_attribute(Eq(kAclMeterOid1), _)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_FAILURE)) + .WillOnce(Return(SAI_STATUS_FAILURE)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ("punt_and_set_tc", acl_rule->p4_action); + EXPECT_EQ(SAI_PACKET_ACTION_TRAP, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.parameter.s32); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.enable); + EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); + EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &meter_oid)); + EXPECT_EQ(kAclMeterOid1, meter_oid); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + // Update packet action: Copy green packet. Fails when action param is + // missing + app_db_entry.action = "copy_and_set_tc"; + app_db_entry.action_param_fvs.erase("traffic_class"); + app_db_entry.meter.cburst = 80; + app_db_entry.meter.cir = 80; + app_db_entry.meter.pburst = 200; + app_db_entry.meter.pir = 200; + // Update meter attribute for green packet action + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ("punt_and_set_tc", acl_rule->p4_action); + EXPECT_EQ(SAI_PACKET_ACTION_TRAP, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.parameter.s32); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.enable); + EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); + EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &meter_oid)); + EXPECT_EQ(kAclMeterOid1, meter_oid); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + // Update packet action: Copy green packet. Fails when updating ACL rule + // fails + app_db_entry.action = "copy_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "2"; + // Update meter attribute for green packet action + EXPECT_CALL(mock_sai_policer_, set_policer_attribute(Eq(kAclMeterOid1), _)) + .Times(2) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .WillOnce(Return(SAI_STATUS_NOT_SUPPORTED)); + EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ("punt_and_set_tc", acl_rule->p4_action); + EXPECT_EQ(SAI_PACKET_ACTION_TRAP, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.parameter.s32); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.enable); + EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); + EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &meter_oid)); + EXPECT_EQ(kAclMeterOid1, meter_oid); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + // Update packet action: Copy green packet. Fails when updating ACL rule + // fails and meter recovery fails + app_db_entry.action = "copy_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "2"; + // Update meter attribute for green packet action + EXPECT_CALL(mock_sai_policer_, set_policer_attribute(Eq(kAclMeterOid1), _)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .WillOnce(Return(SAI_STATUS_NOT_SUPPORTED)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ("punt_and_set_tc", acl_rule->p4_action); + EXPECT_EQ(SAI_PACKET_ACTION_TRAP, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.parameter.s32); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.enable); + EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); + EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &meter_oid)); + EXPECT_EQ(kAclMeterOid1, meter_oid); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + // Remove meter in ACL rule: fails when deleting meter fails plus ACL rule + // recovery fails. + app_db_entry.meter.enabled = false; + app_db_entry.action = "punt_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "2"; + // Remove meter + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_FAILURE)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ(SAI_PACKET_ACTION_TRAP, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.parameter.s32); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.enable); + EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); + EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); + EXPECT_TRUE(acl_rule->meter.enabled); + EXPECT_TRUE(p4_oid_mapper_->getOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &meter_oid)); + EXPECT_EQ(kAclMeterOid1, meter_oid); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + // Successfully remove meter + app_db_entry.action = "punt_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "1"; + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action field value + EXPECT_EQ("punt_and_set_tc", acl_rule->p4_action); + EXPECT_EQ(SAI_PACKET_ACTION_TRAP, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.parameter.s32); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.enable); + EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); + EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); + EXPECT_FALSE(acl_rule->meter.enabled); + EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_POLICER, table_name_and_rule_key)); + + // Add meter in ACL rule with packet color action + app_db_entry.meter.enabled = true; + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid2), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid2))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action and meter + EXPECT_EQ(SAI_PACKET_ACTION_TRAP, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.parameter.s32); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.enable); + EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); + EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); + EXPECT_FALSE(acl_rule->meter.enabled); + + // Add meter in ACL rule with packet color action. Fails when updating ACL + // rule fails and meter recovery fails + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid2), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, set_acl_entry_attribute(Eq(kAclIngressRuleOid1), _)) + .WillOnce(Return(SAI_STATUS_OBJECT_IN_USE)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid2))).WillOnce(Return(SAI_STATUS_FAILURE)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, ProcessUpdateRuleRequest(app_db_entry, *acl_rule)); + acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(nullptr, acl_rule); + // Check action and meter + EXPECT_EQ(SAI_PACKET_ACTION_TRAP, + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.parameter.s32); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION].aclaction.enable); + EXPECT_EQ(1, acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.parameter.u8); + EXPECT_TRUE(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC].aclaction.enable); + EXPECT_TRUE(acl_rule->meter.packet_color_actions.empty()); + EXPECT_FALSE(acl_rule->meter.enabled); } -TEST_F(AclManagerTest, CreateAclRuleWithInvalidActionFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - const auto& acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "15"); - - // ACL rule has redirect action with invalid next_hop_id - const std::string next_hop_id = "ju1u32m1.atl11:qe-3/7"; - app_db_entry.action = "redirect"; - app_db_entry.action_param_fvs["target"] = next_hop_id; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.action_param_fvs.erase("target"); - // ACL rule has redirect action with wrong port type - app_db_entry.action_param_fvs["target"] = "Ethernet8"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.action_param_fvs.erase("target"); - // ACL rule has invalid action - app_db_entry.action = "set_tc"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - // ACL rule has invalid IP address - app_db_entry.action = "endpoint_ip"; - app_db_entry.action_param_fvs["ip_address"] = "invalid"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.action_param_fvs.erase("ip_address"); - // ACL rule is missing action parameter - app_db_entry.action = "set_src_ip"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - // ACL rule with invalid action parameter field "ipv4", should be "ip" - app_db_entry.action = "set_src_ip"; - app_db_entry.action_param_fvs["ipv4"] = "10.0.0.1"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.action_param_fvs.erase("ipv4"); - // ACL rule has invalid MAC address - app_db_entry.action = "set_src_mac"; - app_db_entry.action_param_fvs["mac_address"] = "invalid"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.action_param_fvs.erase("mac_address"); - // ACL rule with invalid packet action value - app_db_entry.action = "set_packet_action"; - app_db_entry.action_param_fvs["packet_action"] = - "PUNT"; // Invalid packet action str - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.action_param_fvs.erase("packet_action"); - // ACL rule with invalid packet color value - app_db_entry.action = "set_packet_color"; - app_db_entry.action_param_fvs["packet_color"] = - "YELLOW"; // Invalid color str - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.action_param_fvs.erase("packet_color"); - // Invalid Mirror ingress session - app_db_entry.action = "mirror_ingress"; - app_db_entry.action_param_fvs["target"] = "Session"; - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.action_param_fvs.erase("target"); - // Invalid cpu queue number - app_db_entry.action = "qos_queue"; - app_db_entry.action_param_fvs["cpu_queue"] = "10"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.action_param_fvs["cpu_queue"] = "invalid"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.action_param_fvs.erase("cpu_queue"); - // ACL rule has invalid dscp - app_db_entry.action = "set_dscp_and_ecn"; - app_db_entry.action_param_fvs["dscp"] = "invalid"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.action_param_fvs.erase("dscp"); - // ACL rule has invalid vlan id - app_db_entry.action = "set_inner_vlan"; - app_db_entry.action_param_fvs["vlan_id"] = "invalid"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.action_param_fvs.erase("vlan_id"); - // ACL rule has invalid port number - app_db_entry.action = "set_l4_src_port"; - app_db_entry.action_param_fvs["port"] = "invalid"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.action_param_fvs.erase("port"); +TEST_F(AclManagerTest, CreateAclRuleWithInvalidActionFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + const auto &acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "15"); + + // ACL rule has redirect action with invalid next_hop_id + const std::string next_hop_id = "ju1u32m1.atl11:qe-3/7"; + app_db_entry.action = "redirect"; + app_db_entry.action_param_fvs["target"] = next_hop_id; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action_param_fvs.erase("target"); + // ACL rule has redirect action with wrong port type + app_db_entry.action_param_fvs["target"] = "Ethernet8"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action_param_fvs.erase("target"); + // ACL rule has invalid action + app_db_entry.action = "set_tc"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + // ACL rule has invalid IP address + app_db_entry.action = "endpoint_ip"; + app_db_entry.action_param_fvs["ip_address"] = "invalid"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action_param_fvs.erase("ip_address"); + // ACL rule is missing action parameter + app_db_entry.action = "set_src_ip"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + // ACL rule with invalid action parameter field "ipv4", should be "ip" + app_db_entry.action = "set_src_ip"; + app_db_entry.action_param_fvs["ipv4"] = "10.0.0.1"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action_param_fvs.erase("ipv4"); + // ACL rule has invalid MAC address + app_db_entry.action = "set_src_mac"; + app_db_entry.action_param_fvs["mac_address"] = "invalid"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action_param_fvs.erase("mac_address"); + // ACL rule with invalid packet action value + app_db_entry.action = "set_packet_action"; + app_db_entry.action_param_fvs["packet_action"] = "PUNT"; // Invalid packet action str + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action_param_fvs.erase("packet_action"); + // ACL rule with invalid packet color value + app_db_entry.action = "set_packet_color"; + app_db_entry.action_param_fvs["packet_color"] = "YELLOW"; // Invalid color str + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action_param_fvs.erase("packet_color"); + // Invalid Mirror ingress session + app_db_entry.action = "mirror_ingress"; + app_db_entry.action_param_fvs["target"] = "Session"; + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action_param_fvs.erase("target"); + // Invalid cpu queue number + app_db_entry.action = "qos_queue"; + app_db_entry.action_param_fvs["cpu_queue"] = "10"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action_param_fvs["cpu_queue"] = "invalid"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action_param_fvs.erase("cpu_queue"); + // ACL rule has invalid dscp + app_db_entry.action = "set_dscp_and_ecn"; + app_db_entry.action_param_fvs["dscp"] = "invalid"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action_param_fvs.erase("dscp"); + // ACL rule has invalid vlan id + app_db_entry.action = "set_inner_vlan"; + app_db_entry.action_param_fvs["vlan_id"] = "invalid"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action_param_fvs.erase("vlan_id"); + // ACL rule has invalid port number + app_db_entry.action = "set_l4_src_port"; + app_db_entry.action_param_fvs["port"] = "invalid"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action_param_fvs.erase("port"); } -TEST_F(AclManagerTest, CreateAclRuleWithInvalidVrfActionFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - const auto& acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "15"); - - // ACL rule with invalid VRF name - app_db_entry.action = "set_vrf"; - app_db_entry.action_param_fvs["vrf"] = "Vrf-yellow"; - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); +TEST_F(AclManagerTest, CreateAclRuleWithInvalidVrfActionFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + const auto &acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "15"); + + // ACL rule with invalid VRF name + app_db_entry.action = "set_vrf"; + app_db_entry.action_param_fvs["vrf"] = "Vrf-yellow"; + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); } -TEST_F(AclManagerTest, CreateAclRuleWithInvalidUnitsInTableFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto* acl_table = GetAclTable(kAclIngressTableName); - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - app_db_entry.action = "punt_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "0x20"; - const auto& acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "15"); - - // Invalid meter unit - acl_table->meter_unit = "INVALID"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_table->meter_unit = P4_METER_UNIT_BYTES; - - // Invalid counter unit - acl_table->counter_unit = "INVALID"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - acl_table->counter_unit = P4_COUNTER_UNIT_BOTH; +TEST_F(AclManagerTest, CreateAclRuleWithInvalidUnitsInTableFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto *acl_table = GetAclTable(kAclIngressTableName); + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + app_db_entry.action = "punt_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "0x20"; + const auto &acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "15"); + + // Invalid meter unit + acl_table->meter_unit = "INVALID"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_table->meter_unit = P4_METER_UNIT_BYTES; + + // Invalid counter unit + acl_table->counter_unit = "INVALID"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + acl_table->counter_unit = P4_COUNTER_UNIT_BOTH; } -TEST_F(AclManagerTest, CreateAclRuleFailsWhenSaiCallFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - auto acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "15"); - - // Set up an next hop mapping - const std::string next_hop_id = "ju1u32m1.atl11:qe-1/7"; - const auto& next_hop_key = KeyGenerator::generateNextHopKey(next_hop_id); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key, - /*next_hop_oid=*/1); - app_db_entry.action = "redirect"; - app_db_entry.action_param_fvs["target"] = next_hop_id; - - // Fails to create ACL rule when sai_acl_api->create_acl_entry() fails - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_NOT_IMPLEMENTED)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - uint32_t ref_count; - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - next_hop_key, &ref_count)); - EXPECT_EQ(0, ref_count); - - // Set VRF action - app_db_entry.action = "set_vrf"; - app_db_entry.action_param_fvs["vrf"] = gVrfName; - acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "15"); - - // Fails to create ACL rule when sai_acl_api->create_acl_entry() fails - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_NOT_IMPLEMENTED)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - - // Fails to create ACL rule when sai_acl_api->create_acl_entry() fails plus - // meter and counter recovery fails - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_NOT_IMPLEMENTED)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - // TODO: Expect critical state x2. - EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - - // Fails to create ACL rule when sai_acl_api->create_policer() fails - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_NOT_IMPLEMENTED)); - EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - - // Fails to create ACL rule when sai_acl_api->create_acl_counter() fails - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_NOT_IMPLEMENTED)); - EXPECT_CALL(mock_sai_policer_, remove_policer(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - - // Fails to create ACL rule when sai_acl_api->create_acl_counter() fails and - // meter recovery fails - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_NOT_IMPLEMENTED)); - EXPECT_CALL(mock_sai_policer_, remove_policer(_)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); +TEST_F(AclManagerTest, CreateAclRuleFailsWhenSaiCallFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + auto acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "15"); + + // Set up an next hop mapping + const std::string next_hop_id = "ju1u32m1.atl11:qe-1/7"; + const auto &next_hop_key = KeyGenerator::generateNextHopKey(next_hop_id); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key, + /*next_hop_oid=*/1); + app_db_entry.action = "redirect"; + app_db_entry.action_param_fvs["target"] = next_hop_id; + + // Fails to create ACL rule when sai_acl_api->create_acl_entry() fails + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)).WillOnce(Return(SAI_STATUS_NOT_IMPLEMENTED)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + uint32_t ref_count; + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key, &ref_count)); + EXPECT_EQ(0, ref_count); + + // Set VRF action + app_db_entry.action = "set_vrf"; + app_db_entry.action_param_fvs["vrf"] = gVrfName; + acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "15"); + + // Fails to create ACL rule when sai_acl_api->create_acl_entry() fails + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)).WillOnce(Return(SAI_STATUS_NOT_IMPLEMENTED)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + + // Fails to create ACL rule when sai_acl_api->create_acl_entry() fails plus + // meter and counter recovery fails + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)).WillOnce(Return(SAI_STATUS_NOT_IMPLEMENTED)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(_)).WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillOnce(Return(SAI_STATUS_FAILURE)); + // TODO: Expect critical state x2. + EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + + // Fails to create ACL rule when sai_acl_api->create_policer() fails + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)).WillOnce(Return(SAI_STATUS_NOT_IMPLEMENTED)); + EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + + // Fails to create ACL rule when sai_acl_api->create_acl_counter() fails + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_NOT_IMPLEMENTED)); + EXPECT_CALL(mock_sai_policer_, remove_policer(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + + // Fails to create ACL rule when sai_acl_api->create_acl_counter() fails and + // meter recovery fails + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)).WillOnce(Return(SAI_STATUS_NOT_IMPLEMENTED)); + EXPECT_CALL(mock_sai_policer_, remove_policer(_)).WillOnce(Return(SAI_STATUS_FAILURE)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); } -TEST_F(AclManagerTest, CreateAclRuleWithInvalidSetSrcIpActionFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - const auto& acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); +TEST_F(AclManagerTest, CreateAclRuleWithInvalidSetSrcIpActionFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + const auto &acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - app_db_entry.action = "set_src_ip"; - app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action = "set_src_ip"; + app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.action_param_fvs["ip_address"] = "null"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action_param_fvs["ip_address"] = "null"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); } -TEST_F(AclManagerTest, CreateAclRuleWithInvalidSetDstIpv6ActionFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - const auto& acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); +TEST_F(AclManagerTest, CreateAclRuleWithInvalidSetDstIpv6ActionFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + const auto &acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "100"); - app_db_entry.action = "set_dst_ipv6"; - app_db_entry.action_param_fvs["ip_address"] = "10.0.0.2"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action = "set_dst_ipv6"; + app_db_entry.action_param_fvs["ip_address"] = "10.0.0.2"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - app_db_entry.action_param_fvs["ip_address"] = "null"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + app_db_entry.action_param_fvs["ip_address"] = "null"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); } -TEST_F(AclManagerTest, DeleteAclRuleWhenTableDoesNotExistFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - app_db_entry.action = "punt_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "0x20"; - const auto& acl_rule_key = - KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "15"); - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .Times(2) - .WillRepeatedly(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclCounterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .Times(2) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - - p4_oid_mapper_->decreaseRefCount(SAI_OBJECT_TYPE_ACL_TABLE, - kAclIngressTableName); - p4_oid_mapper_->decreaseRefCount(SAI_OBJECT_TYPE_ACL_TABLE, - kAclIngressTableName); - p4_oid_mapper_->eraseOID(SAI_OBJECT_TYPE_ACL_TABLE, kAclIngressTableName); - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); +TEST_F(AclManagerTest, DeleteAclRuleWhenTableDoesNotExistFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + app_db_entry.action = "punt_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "0x20"; + const auto &acl_rule_key = KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, "15"); + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .Times(2) + .WillRepeatedly(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclCounterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .Times(2) + .WillRepeatedly(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + + p4_oid_mapper_->decreaseRefCount(SAI_OBJECT_TYPE_ACL_TABLE, kAclIngressTableName); + p4_oid_mapper_->decreaseRefCount(SAI_OBJECT_TYPE_ACL_TABLE, kAclIngressTableName); + p4_oid_mapper_->eraseOID(SAI_OBJECT_TYPE_ACL_TABLE, kAclIngressTableName); + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); } -TEST_F(AclManagerTest, DoAclCounterStatsTaskSucceeds) { - auto app_db_def_entry = getDefaultAclTableDefAppDbEntry(); - app_db_def_entry.counter_unit = P4_COUNTER_UNIT_BOTH; - EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .Times(3) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; - AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); - ASSERT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddTableRequest(app_db_def_entry)); - auto counters_table = std::make_unique( - gCountersDb, std::string(COUNTERS_TABLE) + DEFAULT_KEY_SEPARATOR + - APP_P4RT_TABLE_NAME); - - // Insert the first ACL rule - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - const auto& acl_rule_key = KeyGenerator::generateAclRuleKey( - app_db_entry.match_fvs, std::to_string(app_db_entry.priority)); - const auto& counter_stats_key = app_db_entry.db_key; - std::vector values; - std::string stats; - app_db_entry.action = "set_dst_ipv6"; - app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kAclCounterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - - // Populate counter stats in COUNTERS_DB - EXPECT_CALL(mock_sai_acl_, - get_acl_counter_attribute(Eq(kAclCounterOid1), _, _)) - .WillOnce( - DoAll(Invoke([](sai_object_id_t acl_counter_id, uint32_t attr_count, - sai_attribute_t* counter_attr) { - counter_attr[0].value.u64 = 50; // packets - counter_attr[1].value.u64 = 500; // bytes - }), - Return(SAI_STATUS_SUCCESS))); - DoAclCounterStatsTask(); - // Only packets and bytes are populated in COUNTERS_DB - EXPECT_TRUE( - counters_table->hget(counter_stats_key, P4_COUNTER_STATS_PACKETS, stats)); - EXPECT_EQ("50", stats); - EXPECT_TRUE( - counters_table->hget(counter_stats_key, P4_COUNTER_STATS_BYTES, stats)); - EXPECT_EQ("500", stats); - EXPECT_FALSE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_GREEN_PACKETS, stats)); - EXPECT_FALSE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_GREEN_BYTES, stats)); - EXPECT_FALSE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_RED_PACKETS, stats)); - EXPECT_FALSE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_RED_BYTES, stats)); - EXPECT_FALSE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_YELLOW_PACKETS, stats)); - EXPECT_FALSE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_YELLOW_BYTES, stats)); - - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(Eq(kAclCounterOid1))) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); - EXPECT_FALSE(counters_table->get(counter_stats_key, values)); - - // Install rule with packet color GREEN - app_db_entry.action = "copy_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "0x20"; - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - // Populate counter stats in COUNTERS_DB - EXPECT_CALL(mock_sai_policer_, get_policer_stats(Eq(kAclMeterOid1), _, _, _)) - .WillOnce(DoAll( - Invoke([](sai_object_id_t policer_id, uint32_t number_of_counters, - const sai_stat_id_t* counter_ids, uint64_t* counters) { - counters[0] = 10; // green_packets - counters[1] = 100; // green_bytes - }), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, - get_acl_counter_attribute(Eq(kAclCounterOid1), _, _)) - .WillOnce( - DoAll(Invoke([](sai_object_id_t acl_counter_id, uint32_t attr_count, - sai_attribute_t* counter_attr) { - counter_attr[0].value.u64 = 10; // packets - counter_attr[1].value.u64 = 100; // bytes - }), - Return(SAI_STATUS_SUCCESS))); - DoAclCounterStatsTask(); - // Only green_packets and green_bytes are populated in COUNTERS_DB - EXPECT_TRUE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_GREEN_PACKETS, stats)); - EXPECT_EQ("10", stats); - - EXPECT_TRUE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_GREEN_BYTES, stats)); - EXPECT_EQ("100", stats); - EXPECT_FALSE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_RED_PACKETS, stats)); - EXPECT_FALSE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_RED_BYTES, stats)); - EXPECT_FALSE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_YELLOW_PACKETS, stats)); - EXPECT_FALSE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_YELLOW_BYTES, stats)); - EXPECT_TRUE( - counters_table->hget(counter_stats_key, P4_COUNTER_STATS_PACKETS, stats)); - EXPECT_EQ("10", stats); - EXPECT_TRUE( - counters_table->hget(counter_stats_key, P4_COUNTER_STATS_BYTES, stats)); - EXPECT_EQ("100", stats); - - // Remove rule - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); - EXPECT_FALSE(counters_table->get(counter_stats_key, values)); - - // Install rule with packet color YELLOW and RED - app_db_entry.action = "punt_non_green_pk"; - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - // Populate counter stats in COUNTERS_DB - EXPECT_CALL(mock_sai_policer_, get_policer_stats(Eq(kAclMeterOid1), _, _, _)) - .WillOnce(DoAll( - Invoke([](sai_object_id_t policer_id, uint32_t number_of_counters, - const sai_stat_id_t* counter_ids, uint64_t* counters) { - counters[0] = 20; // yellow_packets - counters[1] = 200; // yellow_bytes - counters[2] = 30; // red_packets - counters[3] = 300; // red_bytes - }), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, - get_acl_counter_attribute(Eq(kAclCounterOid1), _, _)) - .WillOnce( - DoAll(Invoke([](sai_object_id_t acl_counter_id, uint32_t attr_count, - sai_attribute_t* counter_attr) { - counter_attr[0].value.u64 = 50; // packets - counter_attr[1].value.u64 = 500; // bytes - }), - Return(SAI_STATUS_SUCCESS))); - DoAclCounterStatsTask(); - // Only yellow/red_packets and yellow/red_bytes are populated in COUNTERS_DB - EXPECT_TRUE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_YELLOW_PACKETS, stats)); - EXPECT_EQ("20", stats); - EXPECT_TRUE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_YELLOW_BYTES, stats)); - EXPECT_EQ("200", stats); - EXPECT_TRUE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_RED_PACKETS, stats)); - EXPECT_EQ("30", stats); - EXPECT_TRUE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_RED_BYTES, stats)); - EXPECT_EQ("300", stats); - EXPECT_FALSE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_GREEN_PACKETS, stats)); - EXPECT_FALSE(counters_table->hget(counter_stats_key, - P4_COUNTER_STATS_GREEN_BYTES, stats)); - EXPECT_TRUE( - counters_table->hget(counter_stats_key, P4_COUNTER_STATS_PACKETS, stats)); - EXPECT_EQ("50", stats); - EXPECT_TRUE( - counters_table->hget(counter_stats_key, P4_COUNTER_STATS_BYTES, stats)); - EXPECT_EQ("500", stats); - // Remove rule - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); - EXPECT_FALSE(counters_table->get(counter_stats_key, values)); +TEST_F(AclManagerTest, DoAclCounterStatsTaskSucceeds) +{ + auto app_db_def_entry = getDefaultAclTableDefAppDbEntry(); + app_db_def_entry.counter_unit = P4_COUNTER_UNIT_BOTH; + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) + .Times(3) + .WillRepeatedly(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + sai_object_id_t user_defined_trap_oid = gUserDefinedTrapStartOid; + AddDefaultUserTrapsSaiCalls(&user_defined_trap_oid); + ASSERT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddTableRequest(app_db_def_entry)); + auto counters_table = std::make_unique(gCountersDb, std::string(COUNTERS_TABLE) + + DEFAULT_KEY_SEPARATOR + APP_P4RT_TABLE_NAME); + + // Insert the first ACL rule + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + const auto &acl_rule_key = + KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, std::to_string(app_db_entry.priority)); + const auto &counter_stats_key = app_db_entry.db_key; + std::vector values; + std::string stats; + app_db_entry.action = "set_dst_ipv6"; + app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kAclCounterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + + // Populate counter stats in COUNTERS_DB + EXPECT_CALL(mock_sai_acl_, get_acl_counter_attribute(Eq(kAclCounterOid1), _, _)) + .WillOnce(DoAll(Invoke([](sai_object_id_t acl_counter_id, uint32_t attr_count, sai_attribute_t *counter_attr) { + counter_attr[0].value.u64 = 50; // packets + counter_attr[1].value.u64 = 500; // bytes + }), + Return(SAI_STATUS_SUCCESS))); + DoAclCounterStatsTask(); + // Only packets and bytes are populated in COUNTERS_DB + EXPECT_TRUE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_PACKETS, stats)); + EXPECT_EQ("50", stats); + EXPECT_TRUE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_BYTES, stats)); + EXPECT_EQ("500", stats); + EXPECT_FALSE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_GREEN_PACKETS, stats)); + EXPECT_FALSE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_GREEN_BYTES, stats)); + EXPECT_FALSE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_RED_PACKETS, stats)); + EXPECT_FALSE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_RED_BYTES, stats)); + EXPECT_FALSE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_YELLOW_PACKETS, stats)); + EXPECT_FALSE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_YELLOW_BYTES, stats)); + + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(Eq(kAclCounterOid1))).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); + EXPECT_FALSE(counters_table->get(counter_stats_key, values)); + + // Install rule with packet color GREEN + app_db_entry.action = "copy_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "0x20"; + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + // Populate counter stats in COUNTERS_DB + EXPECT_CALL(mock_sai_policer_, get_policer_stats(Eq(kAclMeterOid1), _, _, _)) + .WillOnce(DoAll(Invoke([](sai_object_id_t policer_id, uint32_t number_of_counters, + const sai_stat_id_t *counter_ids, uint64_t *counters) { + counters[0] = 10; // green_packets + counters[1] = 100; // green_bytes + }), + Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, get_acl_counter_attribute(Eq(kAclCounterOid1), _, _)) + .WillOnce(DoAll(Invoke([](sai_object_id_t acl_counter_id, uint32_t attr_count, sai_attribute_t *counter_attr) { + counter_attr[0].value.u64 = 10; // packets + counter_attr[1].value.u64 = 100; // bytes + }), + Return(SAI_STATUS_SUCCESS))); + DoAclCounterStatsTask(); + // Only green_packets and green_bytes are populated in COUNTERS_DB + EXPECT_TRUE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_GREEN_PACKETS, stats)); + EXPECT_EQ("10", stats); + + EXPECT_TRUE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_GREEN_BYTES, stats)); + EXPECT_EQ("100", stats); + EXPECT_FALSE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_RED_PACKETS, stats)); + EXPECT_FALSE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_RED_BYTES, stats)); + EXPECT_FALSE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_YELLOW_PACKETS, stats)); + EXPECT_FALSE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_YELLOW_BYTES, stats)); + EXPECT_TRUE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_PACKETS, stats)); + EXPECT_EQ("10", stats); + EXPECT_TRUE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_BYTES, stats)); + EXPECT_EQ("100", stats); + + // Remove rule + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); + EXPECT_FALSE(counters_table->get(counter_stats_key, values)); + + // Install rule with packet color YELLOW and RED + app_db_entry.action = "punt_non_green_pk"; + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + // Populate counter stats in COUNTERS_DB + EXPECT_CALL(mock_sai_policer_, get_policer_stats(Eq(kAclMeterOid1), _, _, _)) + .WillOnce(DoAll(Invoke([](sai_object_id_t policer_id, uint32_t number_of_counters, + const sai_stat_id_t *counter_ids, uint64_t *counters) { + counters[0] = 20; // yellow_packets + counters[1] = 200; // yellow_bytes + counters[2] = 30; // red_packets + counters[3] = 300; // red_bytes + }), + Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, get_acl_counter_attribute(Eq(kAclCounterOid1), _, _)) + .WillOnce(DoAll(Invoke([](sai_object_id_t acl_counter_id, uint32_t attr_count, sai_attribute_t *counter_attr) { + counter_attr[0].value.u64 = 50; // packets + counter_attr[1].value.u64 = 500; // bytes + }), + Return(SAI_STATUS_SUCCESS))); + DoAclCounterStatsTask(); + // Only yellow/red_packets and yellow/red_bytes are populated in COUNTERS_DB + EXPECT_TRUE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_YELLOW_PACKETS, stats)); + EXPECT_EQ("20", stats); + EXPECT_TRUE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_YELLOW_BYTES, stats)); + EXPECT_EQ("200", stats); + EXPECT_TRUE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_RED_PACKETS, stats)); + EXPECT_EQ("30", stats); + EXPECT_TRUE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_RED_BYTES, stats)); + EXPECT_EQ("300", stats); + EXPECT_FALSE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_GREEN_PACKETS, stats)); + EXPECT_FALSE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_GREEN_BYTES, stats)); + EXPECT_TRUE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_PACKETS, stats)); + EXPECT_EQ("50", stats); + EXPECT_TRUE(counters_table->hget(counter_stats_key, P4_COUNTER_STATS_BYTES, stats)); + EXPECT_EQ("500", stats); + // Remove rule + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); + EXPECT_FALSE(counters_table->get(counter_stats_key, values)); } -TEST_F(AclManagerTest, DoAclCounterStatsTaskFailsWhenSaiCallFails) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto counters_table = std::make_unique( - gCountersDb, std::string(COUNTERS_TABLE) + DEFAULT_KEY_SEPARATOR + - APP_P4RT_TABLE_NAME); - - // Insert the ACL rule - auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); - const auto& acl_rule_key = KeyGenerator::generateAclRuleKey( - app_db_entry.match_fvs, std::to_string(app_db_entry.priority)); - const auto& counter_stats_key = app_db_entry.db_key; - std::vector values; - std::string stats; - app_db_entry.action = "set_dst_ipv6"; - app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kAclCounterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillRepeatedly( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - - // Populate counter stats in COUNTERS_DB - EXPECT_CALL(mock_sai_acl_, - get_acl_counter_attribute(Eq(kAclCounterOid1), _, _)) - .WillOnce(Return(SAI_STATUS_NOT_IMPLEMENTED)); - DoAclCounterStatsTask(); - EXPECT_FALSE(counters_table->get(counter_stats_key, values)); - - // Remove rule - EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_counter(Eq(kAclCounterOid1))) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); - - // Install rule with packet color GREEN - app_db_entry.action = "copy_and_set_tc"; - app_db_entry.action_param_fvs["traffic_class"] = "0x20"; - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRuleRequest(acl_rule_key, app_db_entry)); - // Fails when get_policer_stats() is not implemented - EXPECT_CALL(mock_sai_policer_, get_policer_stats(Eq(kAclMeterOid1), _, _, _)) - .WillOnce(Return(SAI_STATUS_NOT_SUPPORTED)); - DoAclCounterStatsTask(); - EXPECT_FALSE(counters_table->get(counter_stats_key, values)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); - EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); +TEST_F(AclManagerTest, DoAclCounterStatsTaskFailsWhenSaiCallFails) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto counters_table = std::make_unique(gCountersDb, std::string(COUNTERS_TABLE) + + DEFAULT_KEY_SEPARATOR + APP_P4RT_TABLE_NAME); + + // Insert the ACL rule + auto app_db_entry = getDefaultAclRuleAppDbEntryWithoutAction(); + const auto &acl_rule_key = + KeyGenerator::generateAclRuleKey(app_db_entry.match_fvs, std::to_string(app_db_entry.priority)); + const auto &counter_stats_key = app_db_entry.db_key; + std::vector values; + std::string stats; + app_db_entry.action = "set_dst_ipv6"; + app_db_entry.action_param_fvs["ip_address"] = "fdf8:f53b:82e4::53"; + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kAclCounterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillRepeatedly(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + + // Populate counter stats in COUNTERS_DB + EXPECT_CALL(mock_sai_acl_, get_acl_counter_attribute(Eq(kAclCounterOid1), _, _)) + .WillOnce(Return(SAI_STATUS_NOT_IMPLEMENTED)); + DoAclCounterStatsTask(); + EXPECT_FALSE(counters_table->get(counter_stats_key, values)); + + // Remove rule + EXPECT_CALL(mock_sai_acl_, remove_acl_entry(Eq(kAclIngressRuleOid1))).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_counter(Eq(kAclCounterOid1))).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_policer_, remove_policer(Eq(kAclMeterOid1))).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); + + // Install rule with packet color GREEN + app_db_entry.action = "copy_and_set_tc"; + app_db_entry.action_param_fvs["traffic_class"] = "0x20"; + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRuleRequest(acl_rule_key, app_db_entry)); + // Fails when get_policer_stats() is not implemented + EXPECT_CALL(mock_sai_policer_, get_policer_stats(Eq(kAclMeterOid1), _, _, _)) + .WillOnce(Return(SAI_STATUS_NOT_SUPPORTED)); + DoAclCounterStatsTask(); + EXPECT_FALSE(counters_table->get(counter_stats_key, values)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRuleRequest(kAclIngressTableName, acl_rule_key)); + EXPECT_EQ(nullptr, GetAclRule(kAclIngressTableName, acl_rule_key)); } -TEST_F(AclManagerTest, DISABLED_InitCreateGroupFails) { - // Failed to create ACL groups - EXPECT_CALL(mock_sai_serialize_, sai_serialize_object_id(_)) - .WillRepeatedly(Return(EMPTY_STRING)); - EXPECT_CALL(mock_sai_acl_, create_acl_table_group(_, Eq(gSwitchId), Eq(3), _)) - .WillOnce(Return(SAI_STATUS_TABLE_FULL)); - TableConnector stateDbSwitchTable(gStateDb, "SWITCH_CAPABILITY"); - TableConnector app_switch_table(gAppDb, APP_SWITCH_TABLE_NAME); - TableConnector conf_asic_sensors(gConfigDb, CFG_ASIC_SENSORS_TABLE_NAME); - std::vector switch_tables = {conf_asic_sensors, - app_switch_table}; - EXPECT_THROW(new SwitchOrch(gAppDb, switch_tables, stateDbSwitchTable), - std::runtime_error); +TEST_F(AclManagerTest, DISABLED_InitCreateGroupFails) +{ + // Failed to create ACL groups + EXPECT_CALL(mock_sai_serialize_, sai_serialize_object_id(_)).WillRepeatedly(Return(EMPTY_STRING)); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group(_, Eq(gSwitchId), Eq(3), _)) + .WillOnce(Return(SAI_STATUS_TABLE_FULL)); + TableConnector stateDbSwitchTable(gStateDb, "SWITCH_CAPABILITY"); + TableConnector app_switch_table(gAppDb, APP_SWITCH_TABLE_NAME); + TableConnector conf_asic_sensors(gConfigDb, CFG_ASIC_SENSORS_TABLE_NAME); + std::vector switch_tables = {conf_asic_sensors, app_switch_table}; + EXPECT_THROW(new SwitchOrch(gAppDb, switch_tables, stateDbSwitchTable), std::runtime_error); } -TEST_F(AclManagerTest, DISABLED_InitBindGroupToSwitchFails) { - EXPECT_CALL(mock_sai_serialize_, sai_serialize_object_id(_)) - .WillRepeatedly(Return(EMPTY_STRING)); - // Failed to bind ACL group to switch attribute. - EXPECT_CALL(mock_sai_acl_, create_acl_table_group(_, Eq(gSwitchId), Eq(3), _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclGroupIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_switch_, set_switch_attribute(Eq(gSwitchId), _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - TableConnector stateDbSwitchTable(gStateDb, "SWITCH_CAPABILITY"); - TableConnector app_switch_table(gAppDb, APP_SWITCH_TABLE_NAME); - TableConnector conf_asic_sensors(gConfigDb, CFG_ASIC_SENSORS_TABLE_NAME); - std::vector switch_tables = {conf_asic_sensors, - app_switch_table}; - EXPECT_THROW(new SwitchOrch(gAppDb, switch_tables, stateDbSwitchTable), - std::runtime_error); +TEST_F(AclManagerTest, DISABLED_InitBindGroupToSwitchFails) +{ + EXPECT_CALL(mock_sai_serialize_, sai_serialize_object_id(_)).WillRepeatedly(Return(EMPTY_STRING)); + // Failed to bind ACL group to switch attribute. + EXPECT_CALL(mock_sai_acl_, create_acl_table_group(_, Eq(gSwitchId), Eq(3), _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclGroupIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_switch_, set_switch_attribute(Eq(gSwitchId), _)).WillOnce(Return(SAI_STATUS_FAILURE)); + TableConnector stateDbSwitchTable(gStateDb, "SWITCH_CAPABILITY"); + TableConnector app_switch_table(gAppDb, APP_SWITCH_TABLE_NAME); + TableConnector conf_asic_sensors(gConfigDb, CFG_ASIC_SENSORS_TABLE_NAME); + std::vector switch_tables = {conf_asic_sensors, app_switch_table}; + EXPECT_THROW(new SwitchOrch(gAppDb, switch_tables, stateDbSwitchTable), std::runtime_error); } -TEST_F(AclManagerTest, AclTableVerifyStateTest) { - const auto& p4rtAclTableName = - std::string(APP_P4RT_ACL_TABLE_DEFINITION_NAME) + kTableKeyDelimiter + - kAclIngressTableName; - std::vector attributes = - getDefaultTableDefFieldValueTuples(); - EnqueueTableTuple(swss::KeyOpFieldsValuesTuple( - {p4rtAclTableName, SET_COMMAND, attributes})); - EXPECT_CALL(mock_sai_acl_, - create_acl_table(_, Eq(gSwitchId), Gt(2), - Truly(std::bind(MatchSaiAttributeAclTableStage, - SAI_ACL_STAGE_INGRESS, - std::placeholders::_1)))) - .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, - create_acl_table_group_member(_, Eq(gSwitchId), Eq(3), NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - DrainTableTuples(); - auto* acl_table = GetAclTable(kAclIngressTableName); - EXPECT_NE(acl_table, nullptr); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set( - "SAI_OBJECT_TYPE_ACL_TABLE:oid:0x7000000000606", - std::vector{ - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_ACL_STAGE", - "SAI_ACL_STAGE_INGRESS"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_SIZE", "123"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_DST_MAC", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ICMP_TYPE", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_IPV6_NEXT_HEADER", - "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_TTL", "true"}, - swss::FieldValueTuple{ - "SAI_ACL_TABLE_ATTR_USER_DEFINED_FIELD_GROUP_MIN", "oid:0xfa1"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_ACL_ACTION_TYPE_LIST", - "1:SAI_ACL_ACTION_TYPE_COUNTER"}}); - table.set( - "SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER:oid:0xc000000000607", - std::vector{ - swss::FieldValueTuple{ - "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_GROUP_ID", - "oid:0xb00000000058f"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_ID", - "oid:0x7000000000606"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_GROUP_MEMBER_ATTR_PRIORITY", - "234"}}); - table.set("SAI_OBJECT_TYPE_UDF_GROUP:oid:0xfa1", - std::vector{ - swss::FieldValueTuple{"SAI_UDF_GROUP_ATTR_TYPE", - "SAI_UDF_GROUP_TYPE_GENERIC"}, - swss::FieldValueTuple{"SAI_UDF_GROUP_ATTR_LENGTH", "2"}}); - table.set("SAI_OBJECT_TYPE_UDF:oid:0x1771", - std::vector{ - swss::FieldValueTuple{"SAI_UDF_ATTR_GROUP_ID", "oid:0xfa1"}, - swss::FieldValueTuple{"SAI_UDF_ATTR_MATCH_ID", "oid:0x1389"}, - swss::FieldValueTuple{"SAI_UDF_ATTR_BASE", "SAI_UDF_BASE_L3"}, - swss::FieldValueTuple{"SAI_UDF_ATTR_OFFSET", "56"}}); - - // Verification should succeed with vaild key and value. - const std::string db_key = - std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + p4rtAclTableName; - EXPECT_EQ(VerifyTableState(db_key, attributes), ""); - - // Invalid key should fail verification. - EXPECT_FALSE(VerifyTableState("invalid", attributes).empty()); - EXPECT_FALSE(VerifyTableState("invalid:invalid", attributes).empty()); - EXPECT_FALSE(VerifyTableState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", - attributes) - .empty()); - EXPECT_FALSE( - VerifyTableState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", - attributes) - .empty()); - EXPECT_FALSE( - VerifyTableState(std::string(APP_P4RT_TABLE_NAME) + ":DEFINITION:invalid", - attributes) - .empty()); - - // Verification should fail with invalid attribute. - EXPECT_FALSE(VerifyTableState(db_key, - std::vector{ - swss::FieldValueTuple{kSize, "-1"}}) - .empty()); - EXPECT_FALSE( - VerifyTableState(db_key, - std::vector{ - swss::FieldValueTuple{"meter/unit", "invalid"}}) - .empty()); - EXPECT_FALSE(VerifyTableState(db_key, - std::vector{ - swss::FieldValueTuple{kStage, "invalid"}}) - .empty()); - EXPECT_FALSE( - VerifyTableState( - db_key, - std::vector{ - swss::FieldValueTuple{kStage, STAGE_INGRESS}, - swss::FieldValueTuple{kSize, "123"}, - swss::FieldValueTuple{kPriority, "234"}, - swss::FieldValueTuple{"meter/unit", P4_METER_UNIT_BYTES}, - swss::FieldValueTuple{"counter/unit", P4_COUNTER_UNIT_BOTH}, - swss::FieldValueTuple{"match/ether_type", "invalid"}}) - .empty()); - EXPECT_FALSE( - VerifyTableState( - db_key, - std::vector{ - swss::FieldValueTuple{kStage, STAGE_INGRESS}, - swss::FieldValueTuple{kSize, "123"}, - swss::FieldValueTuple{kPriority, "234"}, - swss::FieldValueTuple{"meter/unit", P4_METER_UNIT_BYTES}, - swss::FieldValueTuple{"counter/unit", P4_COUNTER_UNIT_BOTH}, - swss::FieldValueTuple{"action/copy_and_set_tc", - "[{\"action\":\"invalid\"}]"}}) - .empty()); - EXPECT_FALSE( - VerifyTableState( - db_key, - std::vector{ - swss::FieldValueTuple{kStage, STAGE_INGRESS}, - swss::FieldValueTuple{kSize, "123"}, - swss::FieldValueTuple{kPriority, "234"}, - swss::FieldValueTuple{"meter/unit", P4_METER_UNIT_BYTES}, - swss::FieldValueTuple{"counter/unit", P4_COUNTER_UNIT_BOTH}, - swss::FieldValueTuple{"action/punt_and_set_tc", - "[{\"action\":\"SAI_PACKET_ACTION_COPY\"," - "\"packet_color\":\"invalid\"}]"}}) - .empty()); - - // Verification should fail if ACL table name mismatches. - auto saved_acl_table_name = acl_table->acl_table_name; - acl_table->acl_table_name = "invalid"; - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - acl_table->acl_table_name = saved_acl_table_name; - - // Verification should fail if stage mismatches. - auto saved_stage = acl_table->stage; - acl_table->stage = SAI_ACL_STAGE_EGRESS; - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - acl_table->stage = saved_stage; - - // Verification should fail if size mismatches. - auto saved_size = acl_table->size; - acl_table->size = 111; - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - acl_table->size = saved_size; - - // Verification should fail if priority mismatches. - auto saved_priority = acl_table->priority; - acl_table->priority = 111; - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - acl_table->priority = saved_priority; - - // Verification should fail if meter unit mismatches. - auto saved_meter_unit = acl_table->meter_unit; - acl_table->meter_unit = P4_METER_UNIT_PACKETS; - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - acl_table->meter_unit = saved_meter_unit; - - // Verification should fail if counter unit mismatches. - auto saved_counter_unit = acl_table->counter_unit; - acl_table->counter_unit = P4_COUNTER_UNIT_PACKETS; - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - acl_table->counter_unit = saved_counter_unit; - - // Verification should fail if composite SAI match fields lookup mismatches. - acl_table->composite_sai_match_fields_lookup["invalid"] = - std::vector{}; - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - acl_table->composite_sai_match_fields_lookup.erase("invalid"); - - // Verification should fail if UDF fields lookup mismatches. - acl_table->udf_fields_lookup["invalid"] = std::vector{}; - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - acl_table->udf_fields_lookup.erase("invalid"); - - // Verification should fail if UDF group attr index lookup mismatches. - acl_table->udf_group_attr_index_lookup["invalid"] = 0; - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - acl_table->udf_group_attr_index_lookup.erase("invalid"); - - // Verification should fail if SAI match field mismatches. - acl_table->sai_match_field_lookup["invalid"] = SaiMatchField{}; - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - acl_table->sai_match_field_lookup.erase("invalid"); - - // Verification should fail if IP type bit type lookup mismatches. - acl_table->ip_type_bit_type_lookup["invalid"] = "invalid"; - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - acl_table->ip_type_bit_type_lookup.erase("invalid"); - - // Verification should fail if rule action field lookup mismatches. - acl_table->rule_action_field_lookup["invalid"] = - std::vector{}; - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - acl_table->rule_action_field_lookup.erase("invalid"); - - // Verification should fail if rule packet action color lookup mismatches. - acl_table->rule_packet_action_color_lookup["invalid"] = - std::map{}; - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - acl_table->rule_packet_action_color_lookup.erase("invalid"); - - // Verification should fail if group member OID mapping mismatches. - auto saved_group_member_oid = acl_table->group_member_oid; - acl_table->group_member_oid = 0; - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - acl_table->group_member_oid = saved_group_member_oid; - - // Verification should fail if ACL table OID mapping mismatches. - auto saved_table_oid = acl_table->table_oid; - acl_table->table_oid = 0; - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - acl_table->table_oid = saved_table_oid; +TEST_F(AclManagerTest, AclTableVerifyStateTest) +{ + const auto &p4rtAclTableName = + std::string(APP_P4RT_ACL_TABLE_DEFINITION_NAME) + kTableKeyDelimiter + kAclIngressTableName; + std::vector attributes = getDefaultTableDefFieldValueTuples(); + EnqueueTableTuple(swss::KeyOpFieldsValuesTuple({p4rtAclTableName, SET_COMMAND, attributes})); + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, Eq(gSwitchId), Gt(2), + Truly(std::bind(MatchSaiAttributeAclTableStage, SAI_ACL_STAGE_INGRESS, + std::placeholders::_1)))) + .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, Eq(gSwitchId), Eq(3), NotNull())) + .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + DrainTableTuples(); + auto *acl_table = GetAclTable(kAclIngressTableName); + EXPECT_NE(acl_table, nullptr); + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set("SAI_OBJECT_TYPE_ACL_TABLE:oid:0x7000000000606", + std::vector{ + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_ACL_STAGE", "SAI_ACL_STAGE_INGRESS"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_SIZE", "123"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_DST_MAC", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ICMP_TYPE", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_IPV6_NEXT_HEADER", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_TTL", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_USER_DEFINED_FIELD_GROUP_MIN", "oid:0xfa1"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_ACL_ACTION_TYPE_LIST", "1:SAI_ACL_ACTION_TYPE_COUNTER"}}); + table.set("SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER:oid:0xc000000000607", + std::vector{ + swss::FieldValueTuple{"SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_GROUP_ID", "oid:0xb00000000058f"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_ID", "oid:0x7000000000606"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_GROUP_MEMBER_ATTR_PRIORITY", "234"}}); + table.set("SAI_OBJECT_TYPE_UDF_GROUP:oid:0xfa1", + std::vector{ + swss::FieldValueTuple{"SAI_UDF_GROUP_ATTR_TYPE", "SAI_UDF_GROUP_TYPE_GENERIC"}, + swss::FieldValueTuple{"SAI_UDF_GROUP_ATTR_LENGTH", "2"}}); + table.set("SAI_OBJECT_TYPE_UDF:oid:0x1771", + std::vector{swss::FieldValueTuple{"SAI_UDF_ATTR_GROUP_ID", "oid:0xfa1"}, + swss::FieldValueTuple{"SAI_UDF_ATTR_MATCH_ID", "oid:0x1389"}, + swss::FieldValueTuple{"SAI_UDF_ATTR_BASE", "SAI_UDF_BASE_L3"}, + swss::FieldValueTuple{"SAI_UDF_ATTR_OFFSET", "56"}}); + + // Verification should succeed with vaild key and value. + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + p4rtAclTableName; + EXPECT_EQ(VerifyTableState(db_key, attributes), ""); + + // Invalid key should fail verification. + EXPECT_FALSE(VerifyTableState("invalid", attributes).empty()); + EXPECT_FALSE(VerifyTableState("invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyTableState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes).empty()); + EXPECT_FALSE(VerifyTableState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyTableState(std::string(APP_P4RT_TABLE_NAME) + ":DEFINITION:invalid", attributes).empty()); + + // Verification should fail with invalid attribute. + EXPECT_FALSE( + VerifyTableState(db_key, std::vector{swss::FieldValueTuple{kSize, "-1"}}).empty()); + EXPECT_FALSE( + VerifyTableState(db_key, std::vector{swss::FieldValueTuple{"meter/unit", "invalid"}}) + .empty()); + EXPECT_FALSE( + VerifyTableState(db_key, std::vector{swss::FieldValueTuple{kStage, "invalid"}}).empty()); + EXPECT_FALSE(VerifyTableState(db_key, + std::vector{ + swss::FieldValueTuple{kStage, STAGE_INGRESS}, swss::FieldValueTuple{kSize, "123"}, + swss::FieldValueTuple{kPriority, "234"}, + swss::FieldValueTuple{"meter/unit", P4_METER_UNIT_BYTES}, + swss::FieldValueTuple{"counter/unit", P4_COUNTER_UNIT_BOTH}, + swss::FieldValueTuple{"match/ether_type", "invalid"}}) + .empty()); + EXPECT_FALSE(VerifyTableState(db_key, + std::vector{ + swss::FieldValueTuple{kStage, STAGE_INGRESS}, swss::FieldValueTuple{kSize, "123"}, + swss::FieldValueTuple{kPriority, "234"}, + swss::FieldValueTuple{"meter/unit", P4_METER_UNIT_BYTES}, + swss::FieldValueTuple{"counter/unit", P4_COUNTER_UNIT_BOTH}, + swss::FieldValueTuple{"action/copy_and_set_tc", "[{\"action\":\"invalid\"}]"}}) + .empty()); + EXPECT_FALSE( + VerifyTableState(db_key, + std::vector{ + swss::FieldValueTuple{kStage, STAGE_INGRESS}, swss::FieldValueTuple{kSize, "123"}, + swss::FieldValueTuple{kPriority, "234"}, + swss::FieldValueTuple{"meter/unit", P4_METER_UNIT_BYTES}, + swss::FieldValueTuple{"counter/unit", P4_COUNTER_UNIT_BOTH}, + swss::FieldValueTuple{"action/punt_and_set_tc", "[{\"action\":\"SAI_PACKET_ACTION_COPY\"," + "\"packet_color\":\"invalid\"}]"}}) + .empty()); + + // Verification should fail if ACL table name mismatches. + auto saved_acl_table_name = acl_table->acl_table_name; + acl_table->acl_table_name = "invalid"; + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + acl_table->acl_table_name = saved_acl_table_name; + + // Verification should fail if stage mismatches. + auto saved_stage = acl_table->stage; + acl_table->stage = SAI_ACL_STAGE_EGRESS; + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + acl_table->stage = saved_stage; + + // Verification should fail if size mismatches. + auto saved_size = acl_table->size; + acl_table->size = 111; + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + acl_table->size = saved_size; + + // Verification should fail if priority mismatches. + auto saved_priority = acl_table->priority; + acl_table->priority = 111; + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + acl_table->priority = saved_priority; + + // Verification should fail if meter unit mismatches. + auto saved_meter_unit = acl_table->meter_unit; + acl_table->meter_unit = P4_METER_UNIT_PACKETS; + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + acl_table->meter_unit = saved_meter_unit; + + // Verification should fail if counter unit mismatches. + auto saved_counter_unit = acl_table->counter_unit; + acl_table->counter_unit = P4_COUNTER_UNIT_PACKETS; + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + acl_table->counter_unit = saved_counter_unit; + + // Verification should fail if composite SAI match fields lookup mismatches. + acl_table->composite_sai_match_fields_lookup["invalid"] = std::vector{}; + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + acl_table->composite_sai_match_fields_lookup.erase("invalid"); + + // Verification should fail if UDF fields lookup mismatches. + acl_table->udf_fields_lookup["invalid"] = std::vector{}; + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + acl_table->udf_fields_lookup.erase("invalid"); + + // Verification should fail if UDF group attr index lookup mismatches. + acl_table->udf_group_attr_index_lookup["invalid"] = 0; + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + acl_table->udf_group_attr_index_lookup.erase("invalid"); + + // Verification should fail if SAI match field mismatches. + acl_table->sai_match_field_lookup["invalid"] = SaiMatchField{}; + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + acl_table->sai_match_field_lookup.erase("invalid"); + + // Verification should fail if IP type bit type lookup mismatches. + acl_table->ip_type_bit_type_lookup["invalid"] = "invalid"; + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + acl_table->ip_type_bit_type_lookup.erase("invalid"); + + // Verification should fail if rule action field lookup mismatches. + acl_table->rule_action_field_lookup["invalid"] = std::vector{}; + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + acl_table->rule_action_field_lookup.erase("invalid"); + + // Verification should fail if rule packet action color lookup mismatches. + acl_table->rule_packet_action_color_lookup["invalid"] = std::map{}; + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + acl_table->rule_packet_action_color_lookup.erase("invalid"); + + // Verification should fail if group member OID mapping mismatches. + auto saved_group_member_oid = acl_table->group_member_oid; + acl_table->group_member_oid = 0; + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + acl_table->group_member_oid = saved_group_member_oid; + + // Verification should fail if ACL table OID mapping mismatches. + auto saved_table_oid = acl_table->table_oid; + acl_table->table_oid = 0; + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + acl_table->table_oid = saved_table_oid; } -TEST_F(AclManagerTest, AclRuleVerifyStateTest) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{kAction, "mirror_ingress"}); - attributes.push_back(swss::FieldValueTuple{"param/target", gMirrorSession1}); - attributes.push_back(swss::FieldValueTuple{"meter/cir", "80"}); - attributes.push_back(swss::FieldValueTuple{"meter/cburst", "80"}); - attributes.push_back(swss::FieldValueTuple{"meter/pir", "200"}); - attributes.push_back(swss::FieldValueTuple{"meter/pburst", "200"}); - attributes.push_back(swss::FieldValueTuple{"controller_metadata", "..."}); - const auto& acl_rule_json_key = - "{\"match/ether_type\":\"0x0800\",\"match/" - "ipv6_dst\":\"fdf8:f53b:82e4::53 & " - "fdf8:f53b:82e4::53\",\"match/arp_tpa\": \"0xff112231\", " - "\"match/in_ports\": \"Ethernet1,Ethernet2\", \"match/out_ports\": " - "\"Ethernet4,Ethernet5\", \"priority\":15}"; - const auto& rule_tuple_key = std::string(kAclIngressTableName) + - kTableKeyDelimiter + acl_rule_json_key; - EnqueueRuleTuple( - std::string(kAclIngressTableName), - swss::KeyOpFieldsValuesTuple({rule_tuple_key, SET_COMMAND, attributes})); - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclCounterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - DrainRuleTuples(); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set( - "SAI_OBJECT_TYPE_ACL_ENTRY:oid:0x3e9", - std::vector{ - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_TABLE_ID", - "oid:0x7000000000606"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_PRIORITY", "15"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ADMIN_STATE", "true"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_DST_IPV6", - "fdf8:f53b:82e4::53&mask:fdf8:f53b:82e4::53"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE", - "2048&mask:0xffff"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE", - "SAI_ACL_IP_TYPE_ANY&mask:0xffffffffffffffff"}, - swss::FieldValueTuple{ - "SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN", - "2:255,17&mask:2:0xff,0xff"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1", - "2:34,49&mask:2:0xff,0xff"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS", - "2:oid:0x112233,oid:0x1fed3"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS", - "2:oid:0x9988,oid:0x56789abcdef"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS", - "1:oid:0x2329"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_SET_POLICER", - "oid:0x7d1"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_COUNTER", - "oid:0xbb9"}}); - table.set("SAI_OBJECT_TYPE_ACL_COUNTER:oid:0xbb9", - std::vector{ - swss::FieldValueTuple{"SAI_ACL_COUNTER_ATTR_TABLE_ID", - "oid:0x7000000000606"}, - swss::FieldValueTuple{"SAI_ACL_COUNTER_ATTR_ENABLE_BYTE_COUNT", - "true"}, - swss::FieldValueTuple{ - "SAI_ACL_COUNTER_ATTR_ENABLE_PACKET_COUNT", "true"}}); - table.set("SAI_OBJECT_TYPE_POLICER:oid:0x7d1", - std::vector{ - swss::FieldValueTuple{"SAI_POLICER_ATTR_MODE", - "SAI_POLICER_MODE_TR_TCM"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_METER_TYPE", - "SAI_METER_TYPE_BYTES"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_CBS", "80"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_CIR", "80"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_PIR", "200"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_PBS", "200"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_GREEN_PACKET_ACTION", - "SAI_PACKET_ACTION_COPY"}}); - - // Verification should succeed with vaild key and value. - const std::string db_key = - std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + rule_tuple_key; - EXPECT_EQ(VerifyRuleState(db_key, attributes), ""); - - // Invalid key should fail verification. - EXPECT_FALSE(VerifyRuleState("invalid", attributes).empty()); - EXPECT_FALSE(VerifyRuleState("invalid:invalid", attributes).empty()); - EXPECT_FALSE( - VerifyRuleState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes) - .empty()); - EXPECT_FALSE( - VerifyRuleState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", - attributes) - .empty()); - EXPECT_FALSE(VerifyRuleState( - std::string(APP_P4RT_TABLE_NAME) + ":ACL_PUNT_TABLE:invalid", - attributes) - .empty()); - EXPECT_FALSE( - VerifyRuleState( - std::string(APP_P4RT_TABLE_NAME) + - ":ACL_PUNT_TABLE:{\"match/ether_type\":\"0x0800\",\"match/" - "ipv6_dst\":\"fdf8:f53b:82e4::53 & " - "fdf8:f53b:82e4::53\",\"priority\":0}", - attributes) - .empty()); - EXPECT_FALSE( - VerifyRuleState( - std::string(APP_P4RT_TABLE_NAME) + - ":ACL_PUNT_TABLE:{\"match/ether_type\":\"0x0800\",\"match/" - "ipv6_dst\":\"127.0.0.1/24\",\"priority\":15}", - attributes) - .empty()); - - // Verification should fail if entry does not exist. - EXPECT_FALSE( - VerifyRuleState( - std::string(APP_P4RT_TABLE_NAME) + - ":ACL_PUNT_TABLE:{\"match/ether_type\":\"0x0800\",\"match/" - "ipv6_dst\":\"fdf8:f53b:82e4::54 & " - "fdf8:f53b:82e4::54\",\"priority\":15}", - attributes) - .empty()); - - // Verification should fail with invalid attribute. - EXPECT_FALSE( - VerifyTableState(db_key, - std::vector{{kAction, "invalid"}}) - .empty()); - - auto* acl_table = GetAclTable(kAclIngressTableName); - EXPECT_NE(acl_table, nullptr); - const auto& acl_rule_key = - "match/arp_tpa=0xff112231:match/ether_type=0x0800:match/" - "in_ports=Ethernet1,Ethernet2:match/ipv6_dst=fdf8:f53b:82e4::53 & " - "fdf8:f53b:82e4::53:match/out_ports=Ethernet4,Ethernet5:priority=15"; - auto* acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); - ASSERT_NE(acl_rule, nullptr); - - // Verification should fail if ACL rule key mismatches. - auto saved_acl_rule_key = acl_rule->acl_rule_key; - acl_rule->acl_rule_key = "invalid"; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->acl_rule_key = saved_acl_rule_key; - - // Verification should fail if ACL table name mismatches. - auto saved_acl_table_name = acl_rule->acl_table_name; - acl_rule->acl_table_name = "invalid"; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->acl_table_name = saved_acl_table_name; - - // Verification should fail if DB key mismatches. - auto saved_db_key = acl_rule->db_key; - acl_rule->db_key = "invalid"; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->db_key = saved_db_key; - - // Verification should fail if action mismatches. - auto saved_p4_action = acl_rule->p4_action; - acl_rule->p4_action = "invalid"; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->p4_action = saved_p4_action; - - // Verification should fail if priority mismatches. - auto saved_priority = acl_rule->priority; - acl_rule->priority = 111; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->priority = saved_priority; - - // Verification should fail if ACL table name mismatches. - saved_acl_table_name = acl_table->acl_table_name; - acl_table->acl_table_name = "invalid"; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_table->acl_table_name = saved_acl_table_name; - - // Verification should fail if ACL table OID mismatches. - auto saved_acl_table_oid = acl_rule->acl_table_oid; - acl_rule->acl_table_oid = 0; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->acl_table_oid = saved_acl_table_oid; - - // Verification should fail if ACL table meter unit is invalid. - auto saved_meter_unit = acl_table->meter_unit; - acl_table->meter_unit = "invalid"; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_table->meter_unit = saved_meter_unit; - - // Verification should fail if ACL table counter unit mismatches. - auto saved_counter_unit = acl_table->counter_unit; - acl_table->counter_unit = P4_COUNTER_UNIT_PACKETS; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_table->counter_unit = P4_COUNTER_UNIT_BYTES; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_table->counter_unit = saved_counter_unit; - - // Verification should fail if mirror_ingress action is incorrect - EXPECT_NE(acl_rule->action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS), - acl_rule->action_fvs.end()); - auto mirror_sessions = - std::move(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS]); - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS] = - sai_attribute_value_t{}; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - - acl_rule->action_fvs.erase(SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS); - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS] = - sai_attribute_value_t{}; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS] = - std::move(mirror_sessions); - acl_rule->action_fvs.erase(SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS); - - // Verification should fail if match fvs mismatches. - auto saved_match_fvs = acl_rule->match_fvs; - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IN_PORT] = - sai_attribute_value_t{}; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->match_fvs.erase(SAI_ACL_ENTRY_ATTR_FIELD_IN_PORT); - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE] = - sai_attribute_value_t{}; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->match_fvs.erase(SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE); - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IN_PORT] = - sai_attribute_value_t{}; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->match_fvs = saved_match_fvs; - - // Verification should fail if action fvs mismatches. - auto saved_action_fvs = acl_rule->action_fvs; - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT] = - sai_attribute_value_t{}; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->action_fvs.erase(SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT); - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] = - sai_attribute_value_t{}; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->action_fvs.erase(SAI_ACL_ENTRY_ATTR_ACTION_SET_TC); - acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT] = - sai_attribute_value_t{}; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->action_fvs = saved_action_fvs; - - // Verification should fail if meter mismatches. - auto saved_meter_cir = acl_rule->meter.cir; - acl_rule->meter.cir = 0; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->meter.cir = saved_meter_cir; - - // Verification should fail if counter mismatches. - auto saved_counter_bytes_enabled = acl_rule->counter.bytes_enabled; - acl_rule->counter.bytes_enabled = false; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->counter.bytes_enabled = saved_counter_bytes_enabled; - - // Verification should fail if action qos queue number mismatches. - auto saved_action_qos_queue_num = acl_rule->action_qos_queue_num; - acl_rule->action_qos_queue_num = 111; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->action_qos_queue_num = saved_action_qos_queue_num; - - // Verification should fail if action redirect nexthop key mismatches. - auto saved_action_redirect_nexthop_key = - acl_rule->action_redirect_nexthop_key; - acl_rule->action_redirect_nexthop_key = 111; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->action_redirect_nexthop_key = saved_action_redirect_nexthop_key; - - // Verification should fail if action mirror section mismatches. - acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS] = - P4AclMirrorSession{}; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->action_mirror_sessions.erase( - SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS); - - // Verification should fail if UDF data mask mismatches. - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_2] = - P4UdfDataMask{}; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->udf_data_masks.erase(SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_2); - - // Verification should fail if UDF data mask pointer mismatches. - auto udf_data_mask = std::move( - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN]); - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] = - sai_attribute_value_t{}; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) - << VerifyRuleState(db_key, attributes); - - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .aclfield.data.u8list.count = 1; - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .aclfield.mask.u8list.count = 2; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) - << VerifyRuleState(db_key, attributes); - - acl_rule->match_fvs.erase(SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN); - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_2] = - sai_attribute_value_t{}; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) - << VerifyRuleState(db_key, attributes); - acl_rule->match_fvs.erase(SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_2); - - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .aclfield.data.u8list.list = nullptr; - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .aclfield.data.u8list.count = 2; - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .aclfield.mask.u8list.list = - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .mask.data(); - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .aclfield.mask.u8list.count = 2; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) - << VerifyRuleState(db_key, attributes); - - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .aclfield.data.u8list.list = - acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .data.data(); - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] - .aclfield.mask.u8list.list = nullptr; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) - << VerifyRuleState(db_key, attributes); - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] = - std::move(udf_data_mask); - - // Verification should fail if in ports mismatches. - acl_rule->in_ports.push_back("invalid"); - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->in_ports.pop_back(); - - // Verification should fail if out ports mismatches. - acl_rule->out_ports.push_back("invalid"); - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->out_ports.pop_back(); - - // Verification should fail if in ports OIDs mismatches. - acl_rule->in_ports_oids.push_back(0); - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->in_ports_oids.pop_back(); - - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS] - .aclfield.data.objlist.list = nullptr; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) - << VerifyRuleState(db_key, attributes); - - acl_rule->match_fvs.erase(SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS); - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) - << VerifyRuleState(db_key, attributes); - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS] - .aclfield.data.objlist.list = acl_rule->in_ports_oids.data(); - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS].aclfield.enable = true; - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS] - .aclfield.data.objlist.count = 2; - EXPECT_TRUE(VerifyRuleState(db_key, attributes).empty()) - << VerifyRuleState(db_key, attributes); - - // Verification should fail if out ports OIDs mismatches. - acl_rule->out_ports_oids.push_back(0); - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) - << VerifyRuleState(db_key, attributes); - acl_rule->out_ports_oids.pop_back(); - - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS] - .aclfield.data.objlist.list = nullptr; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) - << VerifyRuleState(db_key, attributes); - - acl_rule->match_fvs.erase(SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS); - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) - << VerifyRuleState(db_key, attributes); - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS] - .aclfield.data.objlist.list = acl_rule->out_ports_oids.data(); - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS] - .aclfield.data.objlist.count = 2; - acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS].aclfield.enable = - true; - EXPECT_TRUE(VerifyRuleState(db_key, attributes).empty()) - << VerifyRuleState(db_key, attributes); - - // Verification should fail if ACL rule OID mismatches. - auto saved_acl_entry_oid = acl_rule->acl_entry_oid; - acl_rule->acl_entry_oid = 0; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->acl_entry_oid = saved_acl_entry_oid; - - // Verification should fail if meter OID mismatches. - auto saved_meter_oid = acl_rule->meter.meter_oid; - acl_rule->meter.meter_oid = 0; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->meter.meter_oid = saved_meter_oid; - - // Verification should fail if counter OID mismatches. - auto saved_counter_oid = acl_rule->counter.counter_oid; - acl_rule->counter.counter_oid = 0; - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - acl_rule->counter.counter_oid = saved_counter_oid; +TEST_F(AclManagerTest, AclRuleVerifyStateTest) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{kAction, "mirror_ingress"}); + attributes.push_back(swss::FieldValueTuple{"param/target", gMirrorSession1}); + attributes.push_back(swss::FieldValueTuple{"meter/cir", "80"}); + attributes.push_back(swss::FieldValueTuple{"meter/cburst", "80"}); + attributes.push_back(swss::FieldValueTuple{"meter/pir", "200"}); + attributes.push_back(swss::FieldValueTuple{"meter/pburst", "200"}); + attributes.push_back(swss::FieldValueTuple{"controller_metadata", "..."}); + const auto &acl_rule_json_key = "{\"match/ether_type\":\"0x0800\",\"match/" + "ipv6_dst\":\"fdf8:f53b:82e4::53 & " + "fdf8:f53b:82e4::53\",\"match/arp_tpa\": \"0xff112231\", " + "\"match/in_ports\": \"Ethernet1,Ethernet2\", \"match/out_ports\": " + "\"Ethernet4,Ethernet5\", \"priority\":15}"; + const auto &rule_tuple_key = std::string(kAclIngressTableName) + kTableKeyDelimiter + acl_rule_json_key; + EnqueueRuleTuple(std::string(kAclIngressTableName), + swss::KeyOpFieldsValuesTuple({rule_tuple_key, SET_COMMAND, attributes})); + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclCounterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + DrainRuleTuples(); + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set( + "SAI_OBJECT_TYPE_ACL_ENTRY:oid:0x3e9", + std::vector{ + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_TABLE_ID", "oid:0x7000000000606"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_PRIORITY", "15"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ADMIN_STATE", "true"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_DST_IPV6", "fdf8:f53b:82e4::53&mask:fdf8:f53b:82e4::53"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE", "2048&mask:0xffff"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE", + "SAI_ACL_IP_TYPE_ANY&mask:0xffffffffffffffff"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN", "2:255,17&mask:2:0xff,0xff"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_1", "2:34,49&mask:2:0xff,0xff"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS", "2:oid:0x112233,oid:0x1fed3"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS", "2:oid:0x9988,oid:0x56789abcdef"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS", "1:oid:0x2329"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_SET_POLICER", "oid:0x7d1"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_COUNTER", "oid:0xbb9"}}); + table.set("SAI_OBJECT_TYPE_ACL_COUNTER:oid:0xbb9", + std::vector{ + swss::FieldValueTuple{"SAI_ACL_COUNTER_ATTR_TABLE_ID", "oid:0x7000000000606"}, + swss::FieldValueTuple{"SAI_ACL_COUNTER_ATTR_ENABLE_BYTE_COUNT", "true"}, + swss::FieldValueTuple{"SAI_ACL_COUNTER_ATTR_ENABLE_PACKET_COUNT", "true"}}); + table.set( + "SAI_OBJECT_TYPE_POLICER:oid:0x7d1", + std::vector{ + swss::FieldValueTuple{"SAI_POLICER_ATTR_MODE", "SAI_POLICER_MODE_TR_TCM"}, + swss::FieldValueTuple{"SAI_POLICER_ATTR_METER_TYPE", "SAI_METER_TYPE_BYTES"}, + swss::FieldValueTuple{"SAI_POLICER_ATTR_CBS", "80"}, swss::FieldValueTuple{"SAI_POLICER_ATTR_CIR", "80"}, + swss::FieldValueTuple{"SAI_POLICER_ATTR_PIR", "200"}, swss::FieldValueTuple{"SAI_POLICER_ATTR_PBS", "200"}, + swss::FieldValueTuple{"SAI_POLICER_ATTR_GREEN_PACKET_ACTION", "SAI_PACKET_ACTION_COPY"}}); + + // Verification should succeed with vaild key and value. + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + rule_tuple_key; + EXPECT_EQ(VerifyRuleState(db_key, attributes), ""); + + // Invalid key should fail verification. + EXPECT_FALSE(VerifyRuleState("invalid", attributes).empty()); + EXPECT_FALSE(VerifyRuleState("invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyRuleState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes).empty()); + EXPECT_FALSE(VerifyRuleState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyRuleState(std::string(APP_P4RT_TABLE_NAME) + ":ACL_PUNT_TABLE:invalid", attributes).empty()); + EXPECT_FALSE(VerifyRuleState(std::string(APP_P4RT_TABLE_NAME) + + ":ACL_PUNT_TABLE:{\"match/ether_type\":\"0x0800\",\"match/" + "ipv6_dst\":\"fdf8:f53b:82e4::53 & " + "fdf8:f53b:82e4::53\",\"priority\":0}", + attributes) + .empty()); + EXPECT_FALSE(VerifyRuleState(std::string(APP_P4RT_TABLE_NAME) + + ":ACL_PUNT_TABLE:{\"match/ether_type\":\"0x0800\",\"match/" + "ipv6_dst\":\"127.0.0.1/24\",\"priority\":15}", + attributes) + .empty()); + + // Verification should fail if entry does not exist. + EXPECT_FALSE(VerifyRuleState(std::string(APP_P4RT_TABLE_NAME) + + ":ACL_PUNT_TABLE:{\"match/ether_type\":\"0x0800\",\"match/" + "ipv6_dst\":\"fdf8:f53b:82e4::54 & " + "fdf8:f53b:82e4::54\",\"priority\":15}", + attributes) + .empty()); + + // Verification should fail with invalid attribute. + EXPECT_FALSE(VerifyTableState(db_key, std::vector{{kAction, "invalid"}}).empty()); + + auto *acl_table = GetAclTable(kAclIngressTableName); + EXPECT_NE(acl_table, nullptr); + const auto &acl_rule_key = "match/arp_tpa=0xff112231:match/ether_type=0x0800:match/" + "in_ports=Ethernet1,Ethernet2:match/ipv6_dst=fdf8:f53b:82e4::53 & " + "fdf8:f53b:82e4::53:match/out_ports=Ethernet4,Ethernet5:priority=15"; + auto *acl_rule = GetAclRule(kAclIngressTableName, acl_rule_key); + ASSERT_NE(acl_rule, nullptr); + + // Verification should fail if ACL rule key mismatches. + auto saved_acl_rule_key = acl_rule->acl_rule_key; + acl_rule->acl_rule_key = "invalid"; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->acl_rule_key = saved_acl_rule_key; + + // Verification should fail if ACL table name mismatches. + auto saved_acl_table_name = acl_rule->acl_table_name; + acl_rule->acl_table_name = "invalid"; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->acl_table_name = saved_acl_table_name; + + // Verification should fail if DB key mismatches. + auto saved_db_key = acl_rule->db_key; + acl_rule->db_key = "invalid"; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->db_key = saved_db_key; + + // Verification should fail if action mismatches. + auto saved_p4_action = acl_rule->p4_action; + acl_rule->p4_action = "invalid"; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->p4_action = saved_p4_action; + + // Verification should fail if priority mismatches. + auto saved_priority = acl_rule->priority; + acl_rule->priority = 111; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->priority = saved_priority; + + // Verification should fail if ACL table name mismatches. + saved_acl_table_name = acl_table->acl_table_name; + acl_table->acl_table_name = "invalid"; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_table->acl_table_name = saved_acl_table_name; + + // Verification should fail if ACL table OID mismatches. + auto saved_acl_table_oid = acl_rule->acl_table_oid; + acl_rule->acl_table_oid = 0; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->acl_table_oid = saved_acl_table_oid; + + // Verification should fail if ACL table meter unit is invalid. + auto saved_meter_unit = acl_table->meter_unit; + acl_table->meter_unit = "invalid"; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_table->meter_unit = saved_meter_unit; + + // Verification should fail if ACL table counter unit mismatches. + auto saved_counter_unit = acl_table->counter_unit; + acl_table->counter_unit = P4_COUNTER_UNIT_PACKETS; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_table->counter_unit = P4_COUNTER_UNIT_BYTES; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_table->counter_unit = saved_counter_unit; + + // Verification should fail if mirror_ingress action is incorrect + EXPECT_NE(acl_rule->action_fvs.find(SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS), acl_rule->action_fvs.end()); + auto mirror_sessions = std::move(acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS]); + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS] = sai_attribute_value_t{}; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + + acl_rule->action_fvs.erase(SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS); + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS] = sai_attribute_value_t{}; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_INGRESS] = std::move(mirror_sessions); + acl_rule->action_fvs.erase(SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS); + + // Verification should fail if match fvs mismatches. + auto saved_match_fvs = acl_rule->match_fvs; + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IN_PORT] = sai_attribute_value_t{}; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->match_fvs.erase(SAI_ACL_ENTRY_ATTR_FIELD_IN_PORT); + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE] = sai_attribute_value_t{}; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->match_fvs.erase(SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE); + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IN_PORT] = sai_attribute_value_t{}; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->match_fvs = saved_match_fvs; + + // Verification should fail if action fvs mismatches. + auto saved_action_fvs = acl_rule->action_fvs; + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT] = sai_attribute_value_t{}; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->action_fvs.erase(SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT); + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_SET_TC] = sai_attribute_value_t{}; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->action_fvs.erase(SAI_ACL_ENTRY_ATTR_ACTION_SET_TC); + acl_rule->action_fvs[SAI_ACL_ENTRY_ATTR_ACTION_REDIRECT] = sai_attribute_value_t{}; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->action_fvs = saved_action_fvs; + + // Verification should fail if meter mismatches. + auto saved_meter_cir = acl_rule->meter.cir; + acl_rule->meter.cir = 0; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->meter.cir = saved_meter_cir; + + // Verification should fail if counter mismatches. + auto saved_counter_bytes_enabled = acl_rule->counter.bytes_enabled; + acl_rule->counter.bytes_enabled = false; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->counter.bytes_enabled = saved_counter_bytes_enabled; + + // Verification should fail if action qos queue number mismatches. + auto saved_action_qos_queue_num = acl_rule->action_qos_queue_num; + acl_rule->action_qos_queue_num = 111; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->action_qos_queue_num = saved_action_qos_queue_num; + + // Verification should fail if action redirect nexthop key mismatches. + auto saved_action_redirect_nexthop_key = acl_rule->action_redirect_nexthop_key; + acl_rule->action_redirect_nexthop_key = 111; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->action_redirect_nexthop_key = saved_action_redirect_nexthop_key; + + // Verification should fail if action mirror section mismatches. + acl_rule->action_mirror_sessions[SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS] = P4AclMirrorSession{}; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->action_mirror_sessions.erase(SAI_ACL_ENTRY_ATTR_ACTION_MIRROR_EGRESS); + + // Verification should fail if UDF data mask mismatches. + acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_2] = P4UdfDataMask{}; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->udf_data_masks.erase(SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_2); + + // Verification should fail if UDF data mask pointer mismatches. + auto udf_data_mask = std::move(acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN]); + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] = sai_attribute_value_t{}; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) << VerifyRuleState(db_key, attributes); + + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].aclfield.data.u8list.count = 1; + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].aclfield.mask.u8list.count = 2; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) << VerifyRuleState(db_key, attributes); + + acl_rule->match_fvs.erase(SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN); + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_2] = sai_attribute_value_t{}; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) << VerifyRuleState(db_key, attributes); + acl_rule->match_fvs.erase(SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_2); + + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].aclfield.data.u8list.list = nullptr; + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].aclfield.data.u8list.count = 2; + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].aclfield.mask.u8list.list = + acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].mask.data(); + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].aclfield.mask.u8list.count = 2; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) << VerifyRuleState(db_key, attributes); + + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].aclfield.data.u8list.list = + acl_rule->udf_data_masks[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].data.data(); + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN].aclfield.mask.u8list.list = nullptr; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) << VerifyRuleState(db_key, attributes); + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_USER_DEFINED_FIELD_GROUP_MIN] = std::move(udf_data_mask); + + // Verification should fail if in ports mismatches. + acl_rule->in_ports.push_back("invalid"); + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->in_ports.pop_back(); + + // Verification should fail if out ports mismatches. + acl_rule->out_ports.push_back("invalid"); + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->out_ports.pop_back(); + + // Verification should fail if in ports OIDs mismatches. + acl_rule->in_ports_oids.push_back(0); + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->in_ports_oids.pop_back(); + + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS].aclfield.data.objlist.list = nullptr; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) << VerifyRuleState(db_key, attributes); + + acl_rule->match_fvs.erase(SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS); + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) << VerifyRuleState(db_key, attributes); + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS].aclfield.data.objlist.list = acl_rule->in_ports_oids.data(); + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS].aclfield.enable = true; + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS].aclfield.data.objlist.count = 2; + EXPECT_TRUE(VerifyRuleState(db_key, attributes).empty()) << VerifyRuleState(db_key, attributes); + + // Verification should fail if out ports OIDs mismatches. + acl_rule->out_ports_oids.push_back(0); + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) << VerifyRuleState(db_key, attributes); + acl_rule->out_ports_oids.pop_back(); + + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS].aclfield.data.objlist.list = nullptr; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) << VerifyRuleState(db_key, attributes); + + acl_rule->match_fvs.erase(SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS); + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()) << VerifyRuleState(db_key, attributes); + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS].aclfield.data.objlist.list = + acl_rule->out_ports_oids.data(); + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS].aclfield.data.objlist.count = 2; + acl_rule->match_fvs[SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS].aclfield.enable = true; + EXPECT_TRUE(VerifyRuleState(db_key, attributes).empty()) << VerifyRuleState(db_key, attributes); + + // Verification should fail if ACL rule OID mismatches. + auto saved_acl_entry_oid = acl_rule->acl_entry_oid; + acl_rule->acl_entry_oid = 0; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->acl_entry_oid = saved_acl_entry_oid; + + // Verification should fail if meter OID mismatches. + auto saved_meter_oid = acl_rule->meter.meter_oid; + acl_rule->meter.meter_oid = 0; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->meter.meter_oid = saved_meter_oid; + + // Verification should fail if counter OID mismatches. + auto saved_counter_oid = acl_rule->counter.counter_oid; + acl_rule->counter.counter_oid = 0; + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + acl_rule->counter.counter_oid = saved_counter_oid; } -TEST_F(AclManagerTest, AclTableVerifyStateAsicDbTest) { - const auto& p4rtAclTableName = - std::string(APP_P4RT_ACL_TABLE_DEFINITION_NAME) + kTableKeyDelimiter + - kAclIngressTableName; - std::vector attributes = - getDefaultTableDefFieldValueTuples(); - EnqueueTableTuple(swss::KeyOpFieldsValuesTuple( - {p4rtAclTableName, SET_COMMAND, attributes})); - EXPECT_CALL(mock_sai_acl_, - create_acl_table(_, Eq(gSwitchId), Gt(2), - Truly(std::bind(MatchSaiAttributeAclTableStage, - SAI_ACL_STAGE_INGRESS, - std::placeholders::_1)))) - .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, - create_acl_table_group_member(_, Eq(gSwitchId), Eq(3), NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); - DrainTableTuples(); - auto* acl_table = GetAclTable(kAclIngressTableName); - EXPECT_NE(acl_table, nullptr); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set( - "SAI_OBJECT_TYPE_ACL_TABLE:oid:0x7000000000606", - std::vector{ - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_ACL_STAGE", - "SAI_ACL_STAGE_INGRESS"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_SIZE", "123"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_DST_MAC", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ICMP_TYPE", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_IPV6_NEXT_HEADER", - "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_TTL", "true"}, - swss::FieldValueTuple{ - "SAI_ACL_TABLE_ATTR_USER_DEFINED_FIELD_GROUP_MIN", "oid:0xfa1"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_ACL_ACTION_TYPE_LIST", - "1:SAI_ACL_ACTION_TYPE_COUNTER"}}); - table.set( - "SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER:oid:0xc000000000607", - std::vector{ - swss::FieldValueTuple{ - "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_GROUP_ID", - "oid:0xb00000000058f"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_ID", - "oid:0x7000000000606"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_GROUP_MEMBER_ATTR_PRIORITY", - "234"}}); - table.set("SAI_OBJECT_TYPE_UDF_GROUP:oid:0xfa1", - std::vector{ - swss::FieldValueTuple{"SAI_UDF_GROUP_ATTR_TYPE", - "SAI_UDF_GROUP_TYPE_GENERIC"}, - swss::FieldValueTuple{"SAI_UDF_GROUP_ATTR_LENGTH", "2"}}); - table.set("SAI_OBJECT_TYPE_UDF:oid:0x1771", - std::vector{ - swss::FieldValueTuple{"SAI_UDF_ATTR_GROUP_ID", "oid:0xfa1"}, - swss::FieldValueTuple{"SAI_UDF_ATTR_MATCH_ID", "oid:0x1389"}, - swss::FieldValueTuple{"SAI_UDF_ATTR_BASE", "SAI_UDF_BASE_L3"}, - swss::FieldValueTuple{"SAI_UDF_ATTR_OFFSET", "56"}}); - - // Verification should succeed with correct ASIC DB values. - const std::string db_key = - std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + p4rtAclTableName; - EXPECT_EQ(VerifyTableState(db_key, attributes), ""); - - // Verification should fail if ACL table mismatch. - table.set("SAI_OBJECT_TYPE_ACL_TABLE:oid:0x7000000000606", - std::vector{swss::FieldValueTuple{ - "SAI_ACL_TABLE_ATTR_ACL_STAGE", "SAI_ACL_STAGE_EGRESS"}}); - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - - // Verification should fail if ACL table is missing. - table.del("SAI_OBJECT_TYPE_ACL_TABLE:oid:0x7000000000606"); - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - table.set( - "SAI_OBJECT_TYPE_ACL_TABLE:oid:0x7000000000606", - std::vector{ - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_ACL_STAGE", - "SAI_ACL_STAGE_INGRESS"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_SIZE", "123"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_DST_MAC", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ICMP_TYPE", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_IPV6_NEXT_HEADER", - "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT", "true"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_TTL", "true"}, - swss::FieldValueTuple{ - "SAI_ACL_TABLE_ATTR_USER_DEFINED_FIELD_GROUP_MIN", "oid:0xfa1"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_ACL_ACTION_TYPE_LIST", - "1:SAI_ACL_ACTION_TYPE_COUNTER"}}); - - // Verification should fail if table group member mismatch. - table.set("SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER:oid:0xc000000000607", - std::vector{swss::FieldValueTuple{ - "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_PRIORITY", "0"}}); - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - - // Verification should fail if table group member is missing. - table.del("SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER:oid:0xc000000000607"); - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - table.set( - "SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER:oid:0xc000000000607", - std::vector{ - swss::FieldValueTuple{ - "SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_GROUP_ID", - "oid:0xb00000000058f"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_ID", - "oid:0x7000000000606"}, - swss::FieldValueTuple{"SAI_ACL_TABLE_GROUP_MEMBER_ATTR_PRIORITY", - "234"}}); - - // Verification should fail if udf group mismatch. - table.set("SAI_OBJECT_TYPE_UDF_GROUP:oid:0xfa1", - std::vector{ - swss::FieldValueTuple{"SAI_UDF_GROUP_ATTR_LENGTH", "1"}}); - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - - // Verification should fail if udf group is missing. - table.del("SAI_OBJECT_TYPE_UDF_GROUP:oid:0xfa1"); - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - table.set("SAI_OBJECT_TYPE_UDF_GROUP:oid:0xfa1", - std::vector{ - swss::FieldValueTuple{"SAI_UDF_GROUP_ATTR_TYPE", - "SAI_UDF_GROUP_TYPE_GENERIC"}, - swss::FieldValueTuple{"SAI_UDF_GROUP_ATTR_LENGTH", "2"}}); - - // Verification should fail if udf mismatch. - table.set("SAI_OBJECT_TYPE_UDF:oid:0x1771", - std::vector{ - swss::FieldValueTuple{"SAI_UDF_ATTR_OFFSET", "1"}}); - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - - // Verification should fail if udf is missing. - table.del("SAI_OBJECT_TYPE_UDF:oid:0x1771"); - EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); - table.set("SAI_OBJECT_TYPE_UDF:oid:0x1771", - std::vector{ - swss::FieldValueTuple{"SAI_UDF_ATTR_GROUP_ID", "oid:0xfa1"}, - swss::FieldValueTuple{"SAI_UDF_ATTR_MATCH_ID", "oid:0x1389"}, - swss::FieldValueTuple{"SAI_UDF_ATTR_BASE", "SAI_UDF_BASE_L3"}, - swss::FieldValueTuple{"SAI_UDF_ATTR_OFFSET", "56"}}); +TEST_F(AclManagerTest, AclTableVerifyStateAsicDbTest) +{ + const auto &p4rtAclTableName = + std::string(APP_P4RT_ACL_TABLE_DEFINITION_NAME) + kTableKeyDelimiter + kAclIngressTableName; + std::vector attributes = getDefaultTableDefFieldValueTuples(); + EnqueueTableTuple(swss::KeyOpFieldsValuesTuple({p4rtAclTableName, SET_COMMAND, attributes})); + EXPECT_CALL(mock_sai_acl_, create_acl_table(_, Eq(gSwitchId), Gt(2), + Truly(std::bind(MatchSaiAttributeAclTableStage, SAI_ACL_STAGE_INGRESS, + std::placeholders::_1)))) + .WillOnce(DoAll(SetArgPointee<0>(kAclTableIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_table_group_member(_, Eq(gSwitchId), Eq(3), NotNull())) + .WillOnce(DoAll(SetArgPointee<0>(kAclGroupMemberIngressOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_match(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfMatchOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf_group(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfGroupOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_udf_, create_udf(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kUdfOid1), Return(SAI_STATUS_SUCCESS))); + DrainTableTuples(); + auto *acl_table = GetAclTable(kAclIngressTableName); + EXPECT_NE(acl_table, nullptr); + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set("SAI_OBJECT_TYPE_ACL_TABLE:oid:0x7000000000606", + std::vector{ + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_ACL_STAGE", "SAI_ACL_STAGE_INGRESS"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_SIZE", "123"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_DST_MAC", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ICMP_TYPE", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_IPV6_NEXT_HEADER", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_TTL", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_USER_DEFINED_FIELD_GROUP_MIN", "oid:0xfa1"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_ACL_ACTION_TYPE_LIST", "1:SAI_ACL_ACTION_TYPE_COUNTER"}}); + table.set("SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER:oid:0xc000000000607", + std::vector{ + swss::FieldValueTuple{"SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_GROUP_ID", "oid:0xb00000000058f"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_ID", "oid:0x7000000000606"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_GROUP_MEMBER_ATTR_PRIORITY", "234"}}); + table.set("SAI_OBJECT_TYPE_UDF_GROUP:oid:0xfa1", + std::vector{ + swss::FieldValueTuple{"SAI_UDF_GROUP_ATTR_TYPE", "SAI_UDF_GROUP_TYPE_GENERIC"}, + swss::FieldValueTuple{"SAI_UDF_GROUP_ATTR_LENGTH", "2"}}); + table.set("SAI_OBJECT_TYPE_UDF:oid:0x1771", + std::vector{swss::FieldValueTuple{"SAI_UDF_ATTR_GROUP_ID", "oid:0xfa1"}, + swss::FieldValueTuple{"SAI_UDF_ATTR_MATCH_ID", "oid:0x1389"}, + swss::FieldValueTuple{"SAI_UDF_ATTR_BASE", "SAI_UDF_BASE_L3"}, + swss::FieldValueTuple{"SAI_UDF_ATTR_OFFSET", "56"}}); + + // Verification should succeed with correct ASIC DB values. + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + p4rtAclTableName; + EXPECT_EQ(VerifyTableState(db_key, attributes), ""); + + // Verification should fail if ACL table mismatch. + table.set("SAI_OBJECT_TYPE_ACL_TABLE:oid:0x7000000000606", + std::vector{ + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_ACL_STAGE", "SAI_ACL_STAGE_EGRESS"}}); + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + + // Verification should fail if ACL table is missing. + table.del("SAI_OBJECT_TYPE_ACL_TABLE:oid:0x7000000000606"); + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + table.set("SAI_OBJECT_TYPE_ACL_TABLE:oid:0x7000000000606", + std::vector{ + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_ACL_STAGE", "SAI_ACL_STAGE_INGRESS"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_SIZE", "123"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_DST_MAC", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_ICMP_TYPE", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_IPV6_NEXT_HEADER", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_FIELD_TTL", "true"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_USER_DEFINED_FIELD_GROUP_MIN", "oid:0xfa1"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_ATTR_ACL_ACTION_TYPE_LIST", "1:SAI_ACL_ACTION_TYPE_COUNTER"}}); + + // Verification should fail if table group member mismatch. + table.set( + "SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER:oid:0xc000000000607", + std::vector{swss::FieldValueTuple{"SAI_ACL_TABLE_GROUP_MEMBER_ATTR_PRIORITY", "0"}}); + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + + // Verification should fail if table group member is missing. + table.del("SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER:oid:0xc000000000607"); + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + table.set("SAI_OBJECT_TYPE_ACL_TABLE_GROUP_MEMBER:oid:0xc000000000607", + std::vector{ + swss::FieldValueTuple{"SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_GROUP_ID", "oid:0xb00000000058f"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_GROUP_MEMBER_ATTR_ACL_TABLE_ID", "oid:0x7000000000606"}, + swss::FieldValueTuple{"SAI_ACL_TABLE_GROUP_MEMBER_ATTR_PRIORITY", "234"}}); + + // Verification should fail if udf group mismatch. + table.set("SAI_OBJECT_TYPE_UDF_GROUP:oid:0xfa1", + std::vector{swss::FieldValueTuple{"SAI_UDF_GROUP_ATTR_LENGTH", "1"}}); + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + + // Verification should fail if udf group is missing. + table.del("SAI_OBJECT_TYPE_UDF_GROUP:oid:0xfa1"); + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + table.set("SAI_OBJECT_TYPE_UDF_GROUP:oid:0xfa1", + std::vector{ + swss::FieldValueTuple{"SAI_UDF_GROUP_ATTR_TYPE", "SAI_UDF_GROUP_TYPE_GENERIC"}, + swss::FieldValueTuple{"SAI_UDF_GROUP_ATTR_LENGTH", "2"}}); + + // Verification should fail if udf mismatch. + table.set("SAI_OBJECT_TYPE_UDF:oid:0x1771", + std::vector{swss::FieldValueTuple{"SAI_UDF_ATTR_OFFSET", "1"}}); + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + + // Verification should fail if udf is missing. + table.del("SAI_OBJECT_TYPE_UDF:oid:0x1771"); + EXPECT_FALSE(VerifyTableState(db_key, attributes).empty()); + table.set("SAI_OBJECT_TYPE_UDF:oid:0x1771", + std::vector{swss::FieldValueTuple{"SAI_UDF_ATTR_GROUP_ID", "oid:0xfa1"}, + swss::FieldValueTuple{"SAI_UDF_ATTR_MATCH_ID", "oid:0x1389"}, + swss::FieldValueTuple{"SAI_UDF_ATTR_BASE", "SAI_UDF_BASE_L3"}, + swss::FieldValueTuple{"SAI_UDF_ATTR_OFFSET", "56"}}); } -TEST_F(AclManagerTest, AclRuleVerifyStateAsicDbTest) { - ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); - auto attributes = getDefaultRuleFieldValueTuples(); - const auto& acl_rule_json_key = - "{\"match/ether_type\":\"0x0800\",\"match/" - "ipv6_dst\":\"fdf8:f53b:82e4::53 & " - "fdf8:f53b:82e4::53\",\"priority\":15}"; - const auto& rule_tuple_key = std::string(kAclIngressTableName) + - kTableKeyDelimiter + acl_rule_json_key; - EnqueueRuleTuple( - std::string(kAclIngressTableName), - swss::KeyOpFieldsValuesTuple({rule_tuple_key, SET_COMMAND, attributes})); - EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclCounterOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); - DrainRuleTuples(); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set( - "SAI_OBJECT_TYPE_ACL_ENTRY:oid:0x3e9", - std::vector{ - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_TABLE_ID", - "oid:0x7000000000606"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_PRIORITY", "15"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ADMIN_STATE", "true"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_DST_IPV6", - "fdf8:f53b:82e4::53&mask:fdf8:f53b:82e4::53"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE", - "2048&mask:0xffff"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE", - "SAI_ACL_IP_TYPE_ANY&mask:0xffffffffffffffff"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_SET_TC", "32"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_SET_POLICER", - "oid:0x7d1"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_COUNTER", - "oid:0xbb9"}}); - table.set("SAI_OBJECT_TYPE_ACL_COUNTER:oid:0xbb9", - std::vector{ - swss::FieldValueTuple{"SAI_ACL_COUNTER_ATTR_TABLE_ID", - "oid:0x7000000000606"}, - swss::FieldValueTuple{"SAI_ACL_COUNTER_ATTR_ENABLE_BYTE_COUNT", - "true"}, - swss::FieldValueTuple{ - "SAI_ACL_COUNTER_ATTR_ENABLE_PACKET_COUNT", "true"}}); - table.set("SAI_OBJECT_TYPE_POLICER:oid:0x7d1", - std::vector{ - swss::FieldValueTuple{"SAI_POLICER_ATTR_MODE", - "SAI_POLICER_MODE_TR_TCM"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_METER_TYPE", - "SAI_METER_TYPE_BYTES"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_CBS", "80"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_CIR", "80"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_PIR", "200"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_PBS", "200"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_GREEN_PACKET_ACTION", - "SAI_PACKET_ACTION_COPY"}}); - - // Verification should succeed with correct ASIC DB values. - const std::string db_key = - std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + rule_tuple_key; - EXPECT_EQ(VerifyRuleState(db_key, attributes), ""); - - // Verification should fail if ACL entry mismatch. - table.set("SAI_OBJECT_TYPE_ACL_ENTRY:oid:0x3e9", - std::vector{ - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_PRIORITY", "20"}}); - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - - // Verification should fail if ACL entry is missing. - table.del("SAI_OBJECT_TYPE_ACL_ENTRY:oid:0x3e9"); - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - table.set( - "SAI_OBJECT_TYPE_ACL_ENTRY:oid:0x3e9", - std::vector{ - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_TABLE_ID", - "oid:0x7000000000606"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_PRIORITY", "15"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ADMIN_STATE", "true"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_DST_IPV6", - "fdf8:f53b:82e4::53&mask:fdf8:f53b:82e4::53"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE", - "2048&mask:0xffff"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE", - "SAI_ACL_IP_TYPE_ANY&mask:0xffffffffffffffff"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_SET_TC", "32"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_SET_POLICER", - "oid:0x7d1"}, - swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_COUNTER", - "oid:0xbb9"}}); - - // Verification should fail if counter entry mismatch. - table.set("SAI_OBJECT_TYPE_ACL_COUNTER:oid:0xbb9", - std::vector{swss::FieldValueTuple{ - "SAI_ACL_COUNTER_ATTR_TABLE_ID", "oid:0x0"}}); - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - - // Verification should fail if counter entry is missing. - table.del("SAI_OBJECT_TYPE_ACL_COUNTER:oid:0xbb9"); - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - table.set("SAI_OBJECT_TYPE_ACL_COUNTER:oid:0xbb9", - std::vector{ - swss::FieldValueTuple{"SAI_ACL_COUNTER_ATTR_TABLE_ID", - "oid:0x7000000000606"}, - swss::FieldValueTuple{"SAI_ACL_COUNTER_ATTR_ENABLE_BYTE_COUNT", - "true"}, - swss::FieldValueTuple{ - "SAI_ACL_COUNTER_ATTR_ENABLE_PACKET_COUNT", "true"}}); - - // Verification should fail if meter entry mismatch. - table.set("SAI_OBJECT_TYPE_POLICER:oid:0x7d1", - std::vector{ - swss::FieldValueTuple{"SAI_POLICER_ATTR_CBS", "0"}}); - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - - // Verification should fail if meter entry is missing. - table.del("SAI_OBJECT_TYPE_POLICER:oid:0x7d1"); - EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); - table.set("SAI_OBJECT_TYPE_POLICER:oid:0x7d1", - std::vector{ - swss::FieldValueTuple{"SAI_POLICER_ATTR_MODE", - "SAI_POLICER_MODE_TR_TCM"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_METER_TYPE", - "SAI_METER_TYPE_BYTES"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_CBS", "80"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_CIR", "80"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_PIR", "200"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_PBS", "200"}, - swss::FieldValueTuple{"SAI_POLICER_ATTR_GREEN_PACKET_ACTION", - "SAI_PACKET_ACTION_COPY"}}); +TEST_F(AclManagerTest, AclRuleVerifyStateAsicDbTest) +{ + ASSERT_NO_FATAL_FAILURE(AddDefaultIngressTable()); + auto attributes = getDefaultRuleFieldValueTuples(); + const auto &acl_rule_json_key = "{\"match/ether_type\":\"0x0800\",\"match/" + "ipv6_dst\":\"fdf8:f53b:82e4::53 & " + "fdf8:f53b:82e4::53\",\"priority\":15}"; + const auto &rule_tuple_key = std::string(kAclIngressTableName) + kTableKeyDelimiter + acl_rule_json_key; + EnqueueRuleTuple(std::string(kAclIngressTableName), + swss::KeyOpFieldsValuesTuple({rule_tuple_key, SET_COMMAND, attributes})); + EXPECT_CALL(mock_sai_acl_, create_acl_entry(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclIngressRuleOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_acl_, create_acl_counter(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclCounterOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_policer_, create_policer(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kAclMeterOid1), Return(SAI_STATUS_SUCCESS))); + DrainRuleTuples(); + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set( + "SAI_OBJECT_TYPE_ACL_ENTRY:oid:0x3e9", + std::vector{ + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_TABLE_ID", "oid:0x7000000000606"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_PRIORITY", "15"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ADMIN_STATE", "true"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_DST_IPV6", "fdf8:f53b:82e4::53&mask:fdf8:f53b:82e4::53"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE", "2048&mask:0xffff"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE", + "SAI_ACL_IP_TYPE_ANY&mask:0xffffffffffffffff"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_SET_TC", "32"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_SET_POLICER", "oid:0x7d1"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_COUNTER", "oid:0xbb9"}}); + table.set("SAI_OBJECT_TYPE_ACL_COUNTER:oid:0xbb9", + std::vector{ + swss::FieldValueTuple{"SAI_ACL_COUNTER_ATTR_TABLE_ID", "oid:0x7000000000606"}, + swss::FieldValueTuple{"SAI_ACL_COUNTER_ATTR_ENABLE_BYTE_COUNT", "true"}, + swss::FieldValueTuple{"SAI_ACL_COUNTER_ATTR_ENABLE_PACKET_COUNT", "true"}}); + table.set( + "SAI_OBJECT_TYPE_POLICER:oid:0x7d1", + std::vector{ + swss::FieldValueTuple{"SAI_POLICER_ATTR_MODE", "SAI_POLICER_MODE_TR_TCM"}, + swss::FieldValueTuple{"SAI_POLICER_ATTR_METER_TYPE", "SAI_METER_TYPE_BYTES"}, + swss::FieldValueTuple{"SAI_POLICER_ATTR_CBS", "80"}, swss::FieldValueTuple{"SAI_POLICER_ATTR_CIR", "80"}, + swss::FieldValueTuple{"SAI_POLICER_ATTR_PIR", "200"}, swss::FieldValueTuple{"SAI_POLICER_ATTR_PBS", "200"}, + swss::FieldValueTuple{"SAI_POLICER_ATTR_GREEN_PACKET_ACTION", "SAI_PACKET_ACTION_COPY"}}); + + // Verification should succeed with correct ASIC DB values. + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + rule_tuple_key; + EXPECT_EQ(VerifyRuleState(db_key, attributes), ""); + + // Verification should fail if ACL entry mismatch. + table.set("SAI_OBJECT_TYPE_ACL_ENTRY:oid:0x3e9", + std::vector{swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_PRIORITY", "20"}}); + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + + // Verification should fail if ACL entry is missing. + table.del("SAI_OBJECT_TYPE_ACL_ENTRY:oid:0x3e9"); + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + table.set( + "SAI_OBJECT_TYPE_ACL_ENTRY:oid:0x3e9", + std::vector{ + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_TABLE_ID", "oid:0x7000000000606"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_PRIORITY", "15"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ADMIN_STATE", "true"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_DST_IPV6", "fdf8:f53b:82e4::53&mask:fdf8:f53b:82e4::53"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_ETHER_TYPE", "2048&mask:0xffff"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_FIELD_ACL_IP_TYPE", + "SAI_ACL_IP_TYPE_ANY&mask:0xffffffffffffffff"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_SET_TC", "32"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_SET_POLICER", "oid:0x7d1"}, + swss::FieldValueTuple{"SAI_ACL_ENTRY_ATTR_ACTION_COUNTER", "oid:0xbb9"}}); + + // Verification should fail if counter entry mismatch. + table.set("SAI_OBJECT_TYPE_ACL_COUNTER:oid:0xbb9", + std::vector{swss::FieldValueTuple{"SAI_ACL_COUNTER_ATTR_TABLE_ID", "oid:0x0"}}); + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + + // Verification should fail if counter entry is missing. + table.del("SAI_OBJECT_TYPE_ACL_COUNTER:oid:0xbb9"); + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + table.set("SAI_OBJECT_TYPE_ACL_COUNTER:oid:0xbb9", + std::vector{ + swss::FieldValueTuple{"SAI_ACL_COUNTER_ATTR_TABLE_ID", "oid:0x7000000000606"}, + swss::FieldValueTuple{"SAI_ACL_COUNTER_ATTR_ENABLE_BYTE_COUNT", "true"}, + swss::FieldValueTuple{"SAI_ACL_COUNTER_ATTR_ENABLE_PACKET_COUNT", "true"}}); + + // Verification should fail if meter entry mismatch. + table.set("SAI_OBJECT_TYPE_POLICER:oid:0x7d1", + std::vector{swss::FieldValueTuple{"SAI_POLICER_ATTR_CBS", "0"}}); + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + + // Verification should fail if meter entry is missing. + table.del("SAI_OBJECT_TYPE_POLICER:oid:0x7d1"); + EXPECT_FALSE(VerifyRuleState(db_key, attributes).empty()); + table.set( + "SAI_OBJECT_TYPE_POLICER:oid:0x7d1", + std::vector{ + swss::FieldValueTuple{"SAI_POLICER_ATTR_MODE", "SAI_POLICER_MODE_TR_TCM"}, + swss::FieldValueTuple{"SAI_POLICER_ATTR_METER_TYPE", "SAI_METER_TYPE_BYTES"}, + swss::FieldValueTuple{"SAI_POLICER_ATTR_CBS", "80"}, swss::FieldValueTuple{"SAI_POLICER_ATTR_CIR", "80"}, + swss::FieldValueTuple{"SAI_POLICER_ATTR_PIR", "200"}, swss::FieldValueTuple{"SAI_POLICER_ATTR_PBS", "200"}, + swss::FieldValueTuple{"SAI_POLICER_ATTR_GREEN_PACKET_ACTION", "SAI_PACKET_ACTION_COPY"}}); } -} // namespace test -} // namespace p4orch +} // namespace test +} // namespace p4orch diff --git a/orchagent/p4orch/tests/fake_consumerstatetable.cpp b/orchagent/p4orch/tests/fake_consumerstatetable.cpp index 47f92489539..045950abfd0 100644 --- a/orchagent/p4orch/tests/fake_consumerstatetable.cpp +++ b/orchagent/p4orch/tests/fake_consumerstatetable.cpp @@ -1,11 +1,11 @@ #include "consumerstatetable.h" -namespace swss { +namespace swss +{ -ConsumerStateTable::ConsumerStateTable(DBConnector* db, - const std::string& tableName, - int popBatchSize, int pri) - : ConsumerTableBase(db, tableName, popBatchSize, pri), - TableName_KeySet(tableName) {} +ConsumerStateTable::ConsumerStateTable(DBConnector *db, const std::string &tableName, int popBatchSize, int pri) + : ConsumerTableBase(db, tableName, popBatchSize, pri), TableName_KeySet(tableName) +{ +} -} // namespace swss +} // namespace swss diff --git a/orchagent/p4orch/tests/fake_crmorch.cpp b/orchagent/p4orch/tests/fake_crmorch.cpp index 6b25a23ec2f..63c19b9fdfa 100644 --- a/orchagent/p4orch/tests/fake_crmorch.cpp +++ b/orchagent/p4orch/tests/fake_crmorch.cpp @@ -3,51 +3,73 @@ #include "crmorch.h" -CrmOrch::CrmOrch(swss::DBConnector* db, std::string tableName) - : Orch(db, std::vector{}) {} +CrmOrch::CrmOrch(swss::DBConnector *db, std::string tableName) : Orch(db, std::vector{}) +{ +} -void CrmOrch::incCrmResUsedCounter(CrmResourceType resource) {} +void CrmOrch::incCrmResUsedCounter(CrmResourceType resource) +{ +} -void CrmOrch::decCrmResUsedCounter(CrmResourceType resource) {} +void CrmOrch::decCrmResUsedCounter(CrmResourceType resource) +{ +} -void CrmOrch::incCrmAclUsedCounter(CrmResourceType resource, - sai_acl_stage_t stage, - sai_acl_bind_point_type_t point) {} +void CrmOrch::incCrmAclUsedCounter(CrmResourceType resource, sai_acl_stage_t stage, sai_acl_bind_point_type_t point) +{ +} -void CrmOrch::decCrmAclUsedCounter(CrmResourceType resource, - sai_acl_stage_t stage, - sai_acl_bind_point_type_t point, - sai_object_id_t oid) {} +void CrmOrch::decCrmAclUsedCounter(CrmResourceType resource, sai_acl_stage_t stage, sai_acl_bind_point_type_t point, + sai_object_id_t oid) +{ +} -void CrmOrch::incCrmAclTableUsedCounter(CrmResourceType resource, - sai_object_id_t tableId) {} +void CrmOrch::incCrmAclTableUsedCounter(CrmResourceType resource, sai_object_id_t tableId) +{ +} -void CrmOrch::decCrmAclTableUsedCounter(CrmResourceType resource, - sai_object_id_t tableId) {} +void CrmOrch::decCrmAclTableUsedCounter(CrmResourceType resource, sai_object_id_t tableId) +{ +} -void CrmOrch::incCrmExtTableUsedCounter(CrmResourceType resource, - std::string table_name) {} +void CrmOrch::incCrmExtTableUsedCounter(CrmResourceType resource, std::string table_name) +{ +} -void CrmOrch::decCrmExtTableUsedCounter(CrmResourceType resource, - std::string table_name) {} +void CrmOrch::decCrmExtTableUsedCounter(CrmResourceType resource, std::string table_name) +{ +} -void CrmOrch::doTask(Consumer& consumer) {} +void CrmOrch::doTask(Consumer &consumer) +{ +} -void CrmOrch::handleSetCommand(const std::string& key, - const std::vector& data) { +void CrmOrch::handleSetCommand(const std::string &key, const std::vector &data) +{ } -void CrmOrch::doTask(swss::SelectableTimer& timer) {} +void CrmOrch::doTask(swss::SelectableTimer &timer) +{ +} -void CrmOrch::getResAvailableCounters() {} +void CrmOrch::getResAvailableCounters() +{ +} -void CrmOrch::updateCrmCountersTable() {} +void CrmOrch::updateCrmCountersTable() +{ +} -void CrmOrch::checkCrmThresholds() {} +void CrmOrch::checkCrmThresholds() +{ +} -std::string CrmOrch::getCrmAclKey(sai_acl_stage_t stage, - sai_acl_bind_point_type_t bindPoint) { - return ""; +std::string CrmOrch::getCrmAclKey(sai_acl_stage_t stage, sai_acl_bind_point_type_t bindPoint) +{ + return ""; } -std::string CrmOrch::getCrmAclTableKey(sai_object_id_t id) { return ""; } +std::string CrmOrch::getCrmAclTableKey(sai_object_id_t id) +{ + return ""; +} diff --git a/orchagent/p4orch/tests/fake_dbconnector.cpp b/orchagent/p4orch/tests/fake_dbconnector.cpp index 37fb0b2c96d..89487fad61b 100644 --- a/orchagent/p4orch/tests/fake_dbconnector.cpp +++ b/orchagent/p4orch/tests/fake_dbconnector.cpp @@ -5,58 +5,70 @@ #include "dbconnector.h" -namespace swss { +namespace swss +{ static std::map dbNameIdMap = { - {"APPL_DB", 0}, {"ASIC_DB", 1}, {"COUNTERS_DB", 2}, - {"CONFIG_DB", 4}, {"FLEX_COUNTER_DB", 5}, {"STATE_DB", 6}, + {"APPL_DB", 0}, {"ASIC_DB", 1}, {"COUNTERS_DB", 2}, {"CONFIG_DB", 4}, {"FLEX_COUNTER_DB", 5}, {"STATE_DB", 6}, }; -using DbDataT = - std::map>>; +using DbDataT = std::map>>; -namespace fake_db_connector { +namespace fake_db_connector +{ DbDataT gDB; -} // namespace fake_db_connector +} // namespace fake_db_connector using namespace fake_db_connector; -RedisContext::RedisContext() {} +RedisContext::RedisContext() +{ +} -RedisContext::~RedisContext() {} +RedisContext::~RedisContext() +{ +} -DBConnector::DBConnector(int dbId, const std::string& hostname, int port, - unsigned int timeout) - : m_dbId(dbId) {} +DBConnector::DBConnector(int dbId, const std::string &hostname, int port, unsigned int timeout) : m_dbId(dbId) +{ +} -DBConnector::DBConnector(const std::string& dbName, unsigned int timeout, - bool isTcpConn) { - if (dbNameIdMap.find(dbName) != dbNameIdMap.end()) { - m_dbId = dbNameIdMap[dbName]; - } else { - m_dbId = -1; - } +DBConnector::DBConnector(const std::string &dbName, unsigned int timeout, bool isTcpConn) +{ + if (dbNameIdMap.find(dbName) != dbNameIdMap.end()) + { + m_dbId = dbNameIdMap[dbName]; + } + else + { + m_dbId = -1; + } } -DBConnector::DBConnector(int dbId, const std::string& unixPath, - unsigned int timeout) - : m_dbId(dbId) {} +DBConnector::DBConnector(int dbId, const std::string &unixPath, unsigned int timeout) : m_dbId(dbId) +{ +} -int DBConnector::getDbId() const { return m_dbId; } +int DBConnector::getDbId() const +{ + return m_dbId; +} -void DBConnector::hset(const std::string& key, const std::string& field, - const std::string& value) { - gDB[m_dbId][key][field] = value; +void DBConnector::hset(const std::string &key, const std::string &field, const std::string &value) +{ + gDB[m_dbId][key][field] = value; } -std::vector DBConnector::keys(const std::string& key) { - std::vector list; - for (auto const& x : gDB[m_dbId]) { - list.push_back(x.first); - } - return list; +std::vector DBConnector::keys(const std::string &key) +{ + std::vector list; + for (auto const &x : gDB[m_dbId]) + { + list.push_back(x.first); + } + return list; } -} // namespace swss +} // namespace swss diff --git a/orchagent/p4orch/tests/fake_flexcounterorch.cpp b/orchagent/p4orch/tests/fake_flexcounterorch.cpp index 61a00943ee2..91d6be3d14c 100644 --- a/orchagent/p4orch/tests/fake_flexcounterorch.cpp +++ b/orchagent/p4orch/tests/fake_flexcounterorch.cpp @@ -1,20 +1,32 @@ #include "copporch.h" #include "flexcounterorch.h" -FlexCounterOrch::FlexCounterOrch(swss::DBConnector* db, - std::vector& tableNames) - : Orch(db, tableNames), - m_flexCounterConfigTable(db, CFG_FLEX_COUNTER_TABLE_NAME), - m_bufferQueueConfigTable(db, CFG_BUFFER_QUEUE_TABLE_NAME), - m_bufferPgConfigTable(db, CFG_BUFFER_PG_TABLE_NAME), - m_deviceMetadataConfigTable(db, CFG_DEVICE_METADATA_TABLE_NAME) {} +FlexCounterOrch::FlexCounterOrch(swss::DBConnector *db, std::vector &tableNames) + : Orch(db, tableNames), m_flexCounterConfigTable(db, CFG_FLEX_COUNTER_TABLE_NAME), + m_bufferQueueConfigTable(db, CFG_BUFFER_QUEUE_TABLE_NAME), m_bufferPgConfigTable(db, CFG_BUFFER_PG_TABLE_NAME), + m_deviceMetadataConfigTable(db, CFG_DEVICE_METADATA_TABLE_NAME) +{ +} -FlexCounterOrch::~FlexCounterOrch(void) {} +FlexCounterOrch::~FlexCounterOrch(void) +{ +} -void FlexCounterOrch::doTask(Consumer& consumer) {} +void FlexCounterOrch::doTask(Consumer &consumer) +{ +} -bool FlexCounterOrch::getPortCountersState() const { return true; } +bool FlexCounterOrch::getPortCountersState() const +{ + return true; +} -bool FlexCounterOrch::getPortBufferDropCountersState() const { return true; } +bool FlexCounterOrch::getPortBufferDropCountersState() const +{ + return true; +} -bool FlexCounterOrch::bake() { return true; } \ No newline at end of file +bool FlexCounterOrch::bake() +{ + return true; +} \ No newline at end of file diff --git a/orchagent/p4orch/tests/fake_flowcounterrouteorch.cpp b/orchagent/p4orch/tests/fake_flowcounterrouteorch.cpp index c0fe8499856..08caf52fe6d 100644 --- a/orchagent/p4orch/tests/fake_flowcounterrouteorch.cpp +++ b/orchagent/p4orch/tests/fake_flowcounterrouteorch.cpp @@ -2,141 +2,177 @@ #include "flowcounterrouteorch.h" extern size_t gMaxBulkSize; -extern sai_route_api_t* sai_route_api; +extern sai_route_api_t *sai_route_api; #define ROUTE_FLOW_COUNTER_POLLING_INTERVAL_MS 10000 -FlowCounterRouteOrch::FlowCounterRouteOrch( - swss::DBConnector* db, const std::vector& tableNames) - : Orch(db, tableNames), - mRouteFlowCounterMgr(ROUTE_FLOW_COUNTER_FLEX_COUNTER_GROUP, - StatsMode::READ, - ROUTE_FLOW_COUNTER_POLLING_INTERVAL_MS, false), - gRouteBulker(sai_route_api, gMaxBulkSize) {} +FlowCounterRouteOrch::FlowCounterRouteOrch(swss::DBConnector *db, const std::vector &tableNames) + : Orch(db, tableNames), mRouteFlowCounterMgr(ROUTE_FLOW_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, + ROUTE_FLOW_COUNTER_POLLING_INTERVAL_MS, false), + gRouteBulker(sai_route_api, gMaxBulkSize) +{ +} -FlowCounterRouteOrch::~FlowCounterRouteOrch(void) {} +FlowCounterRouteOrch::~FlowCounterRouteOrch(void) +{ +} -void FlowCounterRouteOrch::generateRouteFlowStats() {} +void FlowCounterRouteOrch::generateRouteFlowStats() +{ +} -void FlowCounterRouteOrch::clearRouteFlowStats() {} +void FlowCounterRouteOrch::clearRouteFlowStats() +{ +} -void FlowCounterRouteOrch::addRoutePattern(const std::string& pattern, size_t) { +void FlowCounterRouteOrch::addRoutePattern(const std::string &pattern, size_t) +{ } -void FlowCounterRouteOrch::removeRoutePattern(const std::string& pattern) {} +void FlowCounterRouteOrch::removeRoutePattern(const std::string &pattern) +{ +} -void FlowCounterRouteOrch::onAddMiscRouteEntry(sai_object_id_t vrf_id, - const IpPrefix& ip_prefix, - bool add_to_cache) {} +void FlowCounterRouteOrch::onAddMiscRouteEntry(sai_object_id_t vrf_id, const IpPrefix &ip_prefix, bool add_to_cache) +{ +} -void FlowCounterRouteOrch::onAddMiscRouteEntry(sai_object_id_t vrf_id, - const sai_ip_prefix_t& ip_pfx, - bool add_to_cache) {} +void FlowCounterRouteOrch::onAddMiscRouteEntry(sai_object_id_t vrf_id, const sai_ip_prefix_t &ip_pfx, bool add_to_cache) +{ +} -void FlowCounterRouteOrch::onRemoveMiscRouteEntry(sai_object_id_t vrf_id, - const IpPrefix& ip_prefix, - bool remove_from_cache) {} +void FlowCounterRouteOrch::onRemoveMiscRouteEntry(sai_object_id_t vrf_id, const IpPrefix &ip_prefix, + bool remove_from_cache) +{ +} -void FlowCounterRouteOrch::onRemoveMiscRouteEntry(sai_object_id_t vrf_id, - const sai_ip_prefix_t& ip_pfx, - bool remove_from_cache) {} +void FlowCounterRouteOrch::onRemoveMiscRouteEntry(sai_object_id_t vrf_id, const sai_ip_prefix_t &ip_pfx, + bool remove_from_cache) +{ +} -void FlowCounterRouteOrch::onAddVR(sai_object_id_t vrf_id) {} +void FlowCounterRouteOrch::onAddVR(sai_object_id_t vrf_id) +{ +} -void FlowCounterRouteOrch::onRemoveVR(sai_object_id_t vrf_id) {} +void FlowCounterRouteOrch::onRemoveVR(sai_object_id_t vrf_id) +{ +} -void FlowCounterRouteOrch::handleRouteAdd(sai_object_id_t vrf_id, - const IpPrefix& ip_prefix) {} +void FlowCounterRouteOrch::handleRouteAdd(sai_object_id_t vrf_id, const IpPrefix &ip_prefix) +{ +} -void FlowCounterRouteOrch::handleRouteRemove(sai_object_id_t vrf_id, - const IpPrefix& ip_prefix) {} +void FlowCounterRouteOrch::handleRouteRemove(sai_object_id_t vrf_id, const IpPrefix &ip_prefix) +{ +} -void FlowCounterRouteOrch::processRouteFlowCounterBinding() {} +void FlowCounterRouteOrch::processRouteFlowCounterBinding() +{ +} -void FlowCounterRouteOrch::doTask(Consumer& consumer) {} +void FlowCounterRouteOrch::doTask(Consumer &consumer) +{ +} -void FlowCounterRouteOrch::doTask(SelectableTimer& timer) {} +void FlowCounterRouteOrch::doTask(SelectableTimer &timer) +{ +} -void FlowCounterRouteOrch::initRouteFlowCounterCapability() {} +void FlowCounterRouteOrch::initRouteFlowCounterCapability() +{ +} -void FlowCounterRouteOrch::removeRoutePattern( - const RoutePattern& route_pattern) {} +void FlowCounterRouteOrch::removeRoutePattern(const RoutePattern &route_pattern) +{ +} -void FlowCounterRouteOrch::removeRouteFlowCounterFromDB( - sai_object_id_t vrf_id, const IpPrefix& ip_prefix, - sai_object_id_t counter_oid) {} +void FlowCounterRouteOrch::removeRouteFlowCounterFromDB(sai_object_id_t vrf_id, const IpPrefix &ip_prefix, + sai_object_id_t counter_oid) +{ +} -bool FlowCounterRouteOrch::bindFlowCounter(const RoutePattern& route_pattern, - sai_object_id_t vrf_id, - const IpPrefix& ip_prefix) { - return true; +bool FlowCounterRouteOrch::bindFlowCounter(const RoutePattern &route_pattern, sai_object_id_t vrf_id, + const IpPrefix &ip_prefix) +{ + return true; } -void FlowCounterRouteOrch::unbindFlowCounter(const RoutePattern& route_pattern, - sai_object_id_t vrf_id, - const IpPrefix& ip_prefix, - sai_object_id_t counter_oid) {} +void FlowCounterRouteOrch::unbindFlowCounter(const RoutePattern &route_pattern, sai_object_id_t vrf_id, + const IpPrefix &ip_prefix, sai_object_id_t counter_oid) +{ +} -void FlowCounterRouteOrch::pendingUpdateFlexDb( - const RoutePattern& route_pattern, const IpPrefix& ip_prefix, - sai_object_id_t counter_oid) {} +void FlowCounterRouteOrch::pendingUpdateFlexDb(const RoutePattern &route_pattern, const IpPrefix &ip_prefix, + sai_object_id_t counter_oid) +{ +} -void FlowCounterRouteOrch::updateRouterFlowCounterCache( - const RoutePattern& route_pattern, const IpPrefix& ip_prefix, - sai_object_id_t counter_oid, RouterFlowCounterCache& cache) {} +void FlowCounterRouteOrch::updateRouterFlowCounterCache(const RoutePattern &route_pattern, const IpPrefix &ip_prefix, + sai_object_id_t counter_oid, RouterFlowCounterCache &cache) +{ +} -bool FlowCounterRouteOrch::validateRoutePattern( - const RoutePattern& route_pattern) const { - return true; +bool FlowCounterRouteOrch::validateRoutePattern(const RoutePattern &route_pattern) const +{ + return true; } -void FlowCounterRouteOrch::onRoutePatternMaxMatchCountChange( - RoutePattern& route_pattern, size_t new_max_match_count) {} +void FlowCounterRouteOrch::onRoutePatternMaxMatchCountChange(RoutePattern &route_pattern, size_t new_max_match_count) +{ +} -bool FlowCounterRouteOrch::isRouteAlreadyBound( - const RoutePattern& route_pattern, const IpPrefix& ip_prefix) const { - return true; +bool FlowCounterRouteOrch::isRouteAlreadyBound(const RoutePattern &route_pattern, const IpPrefix &ip_prefix) const +{ + return true; } -void FlowCounterRouteOrch::createRouteFlowCounterByPattern( - const RoutePattern& route_pattern, size_t currentBoundCount) {} +void FlowCounterRouteOrch::createRouteFlowCounterByPattern(const RoutePattern &route_pattern, size_t currentBoundCount) +{ +} -bool FlowCounterRouteOrch::removeRouteFlowCounter( - const RoutePattern& route_pattern, sai_object_id_t vrf_id, - const IpPrefix& ip_prefix) { - return true; +bool FlowCounterRouteOrch::removeRouteFlowCounter(const RoutePattern &route_pattern, sai_object_id_t vrf_id, + const IpPrefix &ip_prefix) +{ + return true; } -void FlowCounterRouteOrch::createRouteFlowCounterFromVnetRoutes( - const RoutePattern& route_pattern, size_t& current_bound_count) {} +void FlowCounterRouteOrch::createRouteFlowCounterFromVnetRoutes(const RoutePattern &route_pattern, + size_t ¤t_bound_count) +{ +} -void FlowCounterRouteOrch::reapRouteFlowCounterByPattern( - const RoutePattern& route_pattern, size_t currentBoundCount) {} +void FlowCounterRouteOrch::reapRouteFlowCounterByPattern(const RoutePattern &route_pattern, size_t currentBoundCount) +{ +} -bool FlowCounterRouteOrch::isRouteFlowCounterEnabled() const { return true; } +bool FlowCounterRouteOrch::isRouteFlowCounterEnabled() const +{ + return true; +} -void FlowCounterRouteOrch::getRouteFlowCounterNameMapKey( - sai_object_id_t vrf_id, const IpPrefix& ip_prefix, std::string& key) {} +void FlowCounterRouteOrch::getRouteFlowCounterNameMapKey(sai_object_id_t vrf_id, const IpPrefix &ip_prefix, + std::string &key) +{ +} -size_t FlowCounterRouteOrch::getRouteFlowCounterSizeByPattern( - const RoutePattern& route_pattern) const { - return 0; +size_t FlowCounterRouteOrch::getRouteFlowCounterSizeByPattern(const RoutePattern &route_pattern) const +{ + return 0; } -bool FlowCounterRouteOrch::parseRouteKeyForRoutePattern(const std::string& key, - char sep, - sai_object_id_t& vrf_id, - IpPrefix& ip_prefix, - std::string& vrf_name) { - return true; +bool FlowCounterRouteOrch::parseRouteKeyForRoutePattern(const std::string &key, char sep, sai_object_id_t &vrf_id, + IpPrefix &ip_prefix, std::string &vrf_name) +{ + return true; } -bool FlowCounterRouteOrch::getVrfIdByVnetName(const std::string& vnet_name, - sai_object_id_t& vrf_id) { - return true; +bool FlowCounterRouteOrch::getVrfIdByVnetName(const std::string &vnet_name, sai_object_id_t &vrf_id) +{ + return true; } -bool FlowCounterRouteOrch::getVnetNameByVrfId(sai_object_id_t vrf_id, - std::string& vnet_name) { - return true; +bool FlowCounterRouteOrch::getVnetNameByVrfId(sai_object_id_t vrf_id, std::string &vnet_name) +{ + return true; } diff --git a/orchagent/p4orch/tests/fake_notificationconsumer.cpp b/orchagent/p4orch/tests/fake_notificationconsumer.cpp index d5ebe16f6c5..b903b336aba 100644 --- a/orchagent/p4orch/tests/fake_notificationconsumer.cpp +++ b/orchagent/p4orch/tests/fake_notificationconsumer.cpp @@ -1,16 +1,13 @@ #include "notificationconsumer.h" -namespace swss { +namespace swss +{ -NotificationConsumer::NotificationConsumer(swss::DBConnector* db, - const std::string& channel, int pri, +NotificationConsumer::NotificationConsumer(swss::DBConnector *db, const std::string &channel, int pri, size_t popBatchSize) - : Selectable(pri), - POP_BATCH_SIZE(popBatchSize), - m_db(db), - m_subscribe(NULL), - m_channel(channel) { - SWSS_LOG_ENTER(); + : Selectable(pri), POP_BATCH_SIZE(popBatchSize), m_db(db), m_subscribe(NULL), m_channel(channel) +{ + SWSS_LOG_ENTER(); } -} // namespace swss +} // namespace swss diff --git a/orchagent/p4orch/tests/fake_portorch.cpp b/orchagent/p4orch/tests/fake_portorch.cpp index cafa46c98e0..a34a30eb4b5 100644 --- a/orchagent/p4orch/tests/fake_portorch.cpp +++ b/orchagent/p4orch/tests/fake_portorch.cpp @@ -1,4 +1,5 @@ -extern "C" { +extern "C" +{ #include "sai.h" } @@ -11,475 +12,688 @@ extern "C" { #define PORT_BUFFER_DROP_STAT_POLLING_INTERVAL_MS 60000 #define QUEUE_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS 10000 -PortsOrch::PortsOrch(DBConnector* db, DBConnector* stateDb, - vector& tableNames, - DBConnector* chassisAppDb) - : Orch(db, tableNames), - m_portStateTable(stateDb, STATE_PORT_TABLE_NAME), +PortsOrch::PortsOrch(DBConnector *db, DBConnector *stateDb, vector &tableNames, + DBConnector *chassisAppDb) + : Orch(db, tableNames), m_portStateTable(stateDb, STATE_PORT_TABLE_NAME), port_stat_manager(PORT_STAT_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, PORT_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, true), - port_buffer_drop_stat_manager( - PORT_BUFFER_DROP_STAT_FLEX_COUNTER_GROUP, StatsMode::READ, - PORT_BUFFER_DROP_STAT_POLLING_INTERVAL_MS, true), + port_buffer_drop_stat_manager(PORT_BUFFER_DROP_STAT_FLEX_COUNTER_GROUP, StatsMode::READ, + PORT_BUFFER_DROP_STAT_POLLING_INTERVAL_MS, true), queue_stat_manager(QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, - QUEUE_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, true) {} - -bool PortsOrch::allPortsReady() { return true; } + QUEUE_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, true) +{ +} -bool PortsOrch::isInitDone() { return true; } +bool PortsOrch::allPortsReady() +{ + return true; +} -bool PortsOrch::isConfigDone() { return true; } +bool PortsOrch::isInitDone() +{ + return true; +} -bool PortsOrch::isPortAdminUp(const string& alias) { return true; } +bool PortsOrch::isConfigDone() +{ + return true; +} -std::map& PortsOrch::getAllPorts() { return m_portList; } +bool PortsOrch::isPortAdminUp(const string &alias) +{ + return true; +} -bool PortsOrch::bake() { return true; } +std::map &PortsOrch::getAllPorts() +{ + return m_portList; +} -void PortsOrch::cleanPortTable(const vector& keys) {} +bool PortsOrch::bake() +{ + return true; +} -bool PortsOrch::getBridgePort(sai_object_id_t id, Port& port) { return true; } +void PortsOrch::cleanPortTable(const vector &keys) +{ +} -bool PortsOrch::setBridgePortLearningFDB( - Port& port, sai_bridge_port_fdb_learning_mode_t mode) { - return true; +bool PortsOrch::getBridgePort(sai_object_id_t id, Port &port) +{ + return true; } -bool PortsOrch::getPort(string alias, Port& port) { - if (m_portList.find(alias) == m_portList.end()) { - return false; - } - port = m_portList[alias]; - return true; +bool PortsOrch::setBridgePortLearningFDB(Port &port, sai_bridge_port_fdb_learning_mode_t mode) +{ + return true; } -bool PortsOrch::getPort(sai_object_id_t id, Port& port) { - for (const auto& p : m_portList) { - if (p.second.m_port_id == id) { - port = p.second; - return true; +bool PortsOrch::getPort(string alias, Port &port) +{ + if (m_portList.find(alias) == m_portList.end()) + { + return false; + } + port = m_portList[alias]; + return true; +} + +bool PortsOrch::getPort(sai_object_id_t id, Port &port) +{ + for (const auto &p : m_portList) + { + if (p.second.m_port_id == id) + { + port = p.second; + return true; + } } - } - return false; + return false; } -void PortsOrch::increasePortRefCount(const string& alias) {} +void PortsOrch::increasePortRefCount(const string &alias) +{ +} -void PortsOrch::decreasePortRefCount(const string& alias) {} +void PortsOrch::decreasePortRefCount(const string &alias) +{ +} -bool PortsOrch::getPortByBridgePortId(sai_object_id_t bridge_port_id, - Port& port) { - return true; +bool PortsOrch::getPortByBridgePortId(sai_object_id_t bridge_port_id, Port &port) +{ + return true; } -void PortsOrch::setPort(string alias, Port port) { m_portList[alias] = port; } +void PortsOrch::setPort(string alias, Port port) +{ + m_portList[alias] = port; +} -void PortsOrch::getCpuPort(Port& port) {} +void PortsOrch::getCpuPort(Port &port) +{ +} -bool PortsOrch::getInbandPort(Port& port) { return true; } +bool PortsOrch::getInbandPort(Port &port) +{ + return true; +} -bool PortsOrch::getVlanByVlanId(sai_vlan_id_t vlan_id, Port& vlan) { - return true; +bool PortsOrch::getVlanByVlanId(sai_vlan_id_t vlan_id, Port &vlan) +{ + return true; } -bool PortsOrch::setHostIntfsOperStatus(const Port& port, bool up) const { - return true; +bool PortsOrch::setHostIntfsOperStatus(const Port &port, bool up) const +{ + return true; } -void PortsOrch::updateDbPortOperStatus(const Port& port, - sai_port_oper_status_t status) const {} +void PortsOrch::updateDbPortOperStatus(const Port &port, sai_port_oper_status_t status) const +{ +} -bool PortsOrch::createVlanHostIntf(Port& vl, string hostif_name) { - return true; +bool PortsOrch::createVlanHostIntf(Port &vl, string hostif_name) +{ + return true; } -bool PortsOrch::removeVlanHostIntf(Port vl) { return true; } +bool PortsOrch::removeVlanHostIntf(Port vl) +{ + return true; +} -bool PortsOrch::createBindAclTableGroup(sai_object_id_t port_oid, - sai_object_id_t acl_table_oid, - sai_object_id_t& group_oid, - acl_stage_type_t acl_stage) { - return true; +bool PortsOrch::createBindAclTableGroup(sai_object_id_t port_oid, sai_object_id_t acl_table_oid, + sai_object_id_t &group_oid, acl_stage_type_t acl_stage) +{ + return true; } -bool PortsOrch::unbindRemoveAclTableGroup(sai_object_id_t port_oid, - sai_object_id_t acl_table_oid, - acl_stage_type_t acl_stage) { - return true; +bool PortsOrch::unbindRemoveAclTableGroup(sai_object_id_t port_oid, sai_object_id_t acl_table_oid, + acl_stage_type_t acl_stage) +{ + return true; } -bool PortsOrch::bindAclTable(sai_object_id_t id, sai_object_id_t table_oid, - sai_object_id_t& group_member_oid, - acl_stage_type_t acl_stage) { - return true; +bool PortsOrch::bindAclTable(sai_object_id_t id, sai_object_id_t table_oid, sai_object_id_t &group_member_oid, + acl_stage_type_t acl_stage) +{ + return true; } -bool PortsOrch::unbindAclTable(sai_object_id_t port_oid, - sai_object_id_t acl_table_oid, - sai_object_id_t acl_group_member_oid, - acl_stage_type_t acl_stage) { - return true; +bool PortsOrch::unbindAclTable(sai_object_id_t port_oid, sai_object_id_t acl_table_oid, + sai_object_id_t acl_group_member_oid, acl_stage_type_t acl_stage) +{ + return true; } -bool PortsOrch::bindUnbindAclTableGroup(Port& port, bool ingress, bool bind) { - return true; +bool PortsOrch::bindUnbindAclTableGroup(Port &port, bool ingress, bool bind) +{ + return true; } -bool PortsOrch::getPortPfc(sai_object_id_t portId, uint8_t* pfc_bitmask) { - return true; +bool PortsOrch::getPortPfc(sai_object_id_t portId, uint8_t *pfc_bitmask) +{ + return true; } -bool PortsOrch::setPortPfc(sai_object_id_t portId, uint8_t pfc_bitmask) { - return true; +bool PortsOrch::setPortPfc(sai_object_id_t portId, uint8_t pfc_bitmask) +{ + return true; } -void PortsOrch::generateQueueMap( - std::map queuesStateVector) {} +void PortsOrch::generateQueueMap(std::map queuesStateVector) +{ +} -void PortsOrch::generateQueueMapPerPort(const Port& port, - FlexCounterQueueStates& queuesState, - bool voq) {} +void PortsOrch::generateQueueMapPerPort(const Port &port, FlexCounterQueueStates &queuesState, bool voq) +{ +} -void PortsOrch::createPortBufferQueueCounters(const Port& port, string queues) { +void PortsOrch::createPortBufferQueueCounters(const Port &port, string queues) +{ } -void PortsOrch::removePortBufferQueueCounters(const Port& port, string queues) { +void PortsOrch::removePortBufferQueueCounters(const Port &port, string queues) +{ } -void PortsOrch::generatePriorityGroupMap( - std::map pgsStateVector) {} +void PortsOrch::generatePriorityGroupMap(std::map pgsStateVector) +{ +} -void PortsOrch::generatePriorityGroupMapPerPort(const Port& port, - FlexCounterPgStates& pgsState) { +void PortsOrch::generatePriorityGroupMapPerPort(const Port &port, FlexCounterPgStates &pgsState) +{ } -void PortsOrch::createPortBufferPgCounters(const Port& port, string pgs) {} +void PortsOrch::createPortBufferPgCounters(const Port &port, string pgs) +{ +} -void PortsOrch::removePortBufferPgCounters(const Port& port, string pgs) {} +void PortsOrch::removePortBufferPgCounters(const Port &port, string pgs) +{ +} -void PortsOrch::generatePortCounterMap() {} +void PortsOrch::generatePortCounterMap() +{ +} -void PortsOrch::generatePortBufferDropCounterMap() {} +void PortsOrch::generatePortBufferDropCounterMap() +{ +} -void PortsOrch::refreshPortStatus() {} +void PortsOrch::refreshPortStatus() +{ +} -bool PortsOrch::removeAclTableGroup(const Port& p) { return true; } +bool PortsOrch::removeAclTableGroup(const Port &p) +{ + return true; +} -bool PortsOrch::addSubPort(Port& port, const string& alias, const string& vlan, - const bool& adminUp, const uint32_t& mtu) { - return true; +bool PortsOrch::addSubPort(Port &port, const string &alias, const string &vlan, const bool &adminUp, + const uint32_t &mtu) +{ + return true; } -bool PortsOrch::removeSubPort(const string& alias) { return true; } +bool PortsOrch::removeSubPort(const string &alias) +{ + return true; +} -bool PortsOrch::updateL3VniStatus(uint16_t vlan_id, bool status) { - return true; +bool PortsOrch::updateL3VniStatus(uint16_t vlan_id, bool status) +{ + return true; } -void PortsOrch::getLagMember(Port& lag, vector& portv) {} +void PortsOrch::getLagMember(Port &lag, vector &portv) +{ +} -void PortsOrch::updateChildPortsMtu(const Port& p, const uint32_t mtu) {} +void PortsOrch::updateChildPortsMtu(const Port &p, const uint32_t mtu) +{ +} -bool PortsOrch::addTunnel(string tunnel, sai_object_id_t, bool learning) { - return true; +bool PortsOrch::addTunnel(string tunnel, sai_object_id_t, bool learning) +{ + return true; } -bool PortsOrch::removeTunnel(Port tunnel) { return true; } +bool PortsOrch::removeTunnel(Port tunnel) +{ + return true; +} -bool PortsOrch::addBridgePort(Port& port) { return true; } +bool PortsOrch::addBridgePort(Port &port) +{ + return true; +} -bool PortsOrch::removeBridgePort(Port& port) { return true; } +bool PortsOrch::removeBridgePort(Port &port) +{ + return true; +} -bool PortsOrch::addVlanMember(Port& vlan, Port& port, string& tagging_mode, - string end_point_ip) { - return true; +bool PortsOrch::addVlanMember(Port &vlan, Port &port, string &tagging_mode, string end_point_ip) +{ + return true; } -bool PortsOrch::removeVlanMember(Port& vlan, Port& port, string end_point_ip) { - return true; +bool PortsOrch::removeVlanMember(Port &vlan, Port &port, string end_point_ip) +{ + return true; } -bool PortsOrch::isVlanMember(Port& vlan, Port& port, string end_point_ip) { - return true; +bool PortsOrch::isVlanMember(Port &vlan, Port &port, string end_point_ip) +{ + return true; } -bool PortsOrch::addVlanFloodGroups(Port& vlan, Port& port, - string end_point_ip) { - return true; +bool PortsOrch::addVlanFloodGroups(Port &vlan, Port &port, string end_point_ip) +{ + return true; } -bool PortsOrch::removeVlanEndPointIp(Port& vlan, Port& port, - string end_point_ip) { - return true; +bool PortsOrch::removeVlanEndPointIp(Port &vlan, Port &port, string end_point_ip) +{ + return true; } -void PortsOrch::increaseBridgePortRefCount(Port& port) {} +void PortsOrch::increaseBridgePortRefCount(Port &port) +{ +} -void PortsOrch::decreaseBridgePortRefCount(Port& port) {} +void PortsOrch::decreaseBridgePortRefCount(Port &port) +{ +} -bool PortsOrch::getBridgePortReferenceCount(Port& port) { return true; } +bool PortsOrch::getBridgePortReferenceCount(Port &port) +{ + return true; +} -bool PortsOrch::isInbandPort(const string& alias) { return true; } +bool PortsOrch::isInbandPort(const string &alias) +{ + return true; +} -bool PortsOrch::setVoqInbandIntf(string& alias, string& type) { return true; } +bool PortsOrch::setVoqInbandIntf(string &alias, string &type) +{ + return true; +} -bool PortsOrch::getRecircPort(Port& p, Port::Role role) { return true; } +bool PortsOrch::getRecircPort(Port &p, Port::Role role) +{ + return true; +} -const gearbox_phy_t* PortsOrch::getGearboxPhy(const Port& port) { - return nullptr; +const gearbox_phy_t *PortsOrch::getGearboxPhy(const Port &port) +{ + return nullptr; } -bool PortsOrch::getPortIPG(sai_object_id_t port_id, uint32_t& ipg) { - return true; +bool PortsOrch::getPortIPG(sai_object_id_t port_id, uint32_t &ipg) +{ + return true; } -bool PortsOrch::setPortIPG(sai_object_id_t port_id, uint32_t ipg) { - return true; +bool PortsOrch::setPortIPG(sai_object_id_t port_id, uint32_t ipg) +{ + return true; } -bool PortsOrch::getPortOperStatus(const Port& port, - sai_port_oper_status_t& status) const { - status = port.m_oper_status; - return true; +bool PortsOrch::getPortOperStatus(const Port &port, sai_port_oper_status_t &status) const +{ + status = port.m_oper_status; + return true; } -std::string PortsOrch::getQueueWatermarkFlexCounterTableKey(std::string s) { - return ""; +std::string PortsOrch::getQueueWatermarkFlexCounterTableKey(std::string s) +{ + return ""; } -std::string PortsOrch::getPriorityGroupWatermarkFlexCounterTableKey( - std::string s) { - return ""; +std::string PortsOrch::getPriorityGroupWatermarkFlexCounterTableKey(std::string s) +{ + return ""; } -std::string PortsOrch::getPriorityGroupDropPacketsFlexCounterTableKey( - std::string s) { - return ""; +std::string PortsOrch::getPriorityGroupDropPacketsFlexCounterTableKey(std::string s) +{ + return ""; } -std::string PortsOrch::getPortRateFlexCounterTableKey(std::string s) { - return ""; +std::string PortsOrch::getPortRateFlexCounterTableKey(std::string s) +{ + return ""; } -void PortsOrch::doTask() {} +void PortsOrch::doTask() +{ +} -void PortsOrch::doTask(Consumer& consumer) {} +void PortsOrch::doTask(Consumer &consumer) +{ +} -void PortsOrch::doPortTask(Consumer& consumer) {} +void PortsOrch::doPortTask(Consumer &consumer) +{ +} -void PortsOrch::doVlanTask(Consumer& consumer) {} +void PortsOrch::doVlanTask(Consumer &consumer) +{ +} -void PortsOrch::doVlanMemberTask(Consumer& consumer) {} +void PortsOrch::doVlanMemberTask(Consumer &consumer) +{ +} -void PortsOrch::doLagTask(Consumer& consumer) {} +void PortsOrch::doLagTask(Consumer &consumer) +{ +} -void PortsOrch::doLagMemberTask(Consumer& consumer) {} +void PortsOrch::doLagMemberTask(Consumer &consumer) +{ +} -void PortsOrch::doTask(NotificationConsumer& consumer) {} +void PortsOrch::doTask(NotificationConsumer &consumer) +{ +} -void PortsOrch::removePortFromLanesMap(string alias) {} +void PortsOrch::removePortFromLanesMap(string alias) +{ +} -void PortsOrch::removePortFromPortListMap(sai_object_id_t port_id) {} +void PortsOrch::removePortFromPortListMap(sai_object_id_t port_id) +{ +} -void PortsOrch::removeDefaultVlanMembers() {} +void PortsOrch::removeDefaultVlanMembers() +{ +} -void PortsOrch::removeDefaultBridgePorts() {} +void PortsOrch::removeDefaultBridgePorts() +{ +} -bool PortsOrch::initializePort(Port& port) { return true; } +bool PortsOrch::initializePort(Port &port) +{ + return true; +} -void PortsOrch::initializePriorityGroups(Port& port) {} +void PortsOrch::initializePriorityGroups(Port &port) +{ +} -void PortsOrch::initializePortBufferMaximumParameters(Port& port) {} +void PortsOrch::initializePortBufferMaximumParameters(Port &port) +{ +} -void PortsOrch::initializeQueues(Port& port) {} +void PortsOrch::initializeQueues(Port &port) +{ +} -bool PortsOrch::addHostIntfs(Port& port, string alias, - sai_object_id_t& host_intfs_id) { - return true; +bool PortsOrch::addHostIntfs(Port &port, string alias, sai_object_id_t &host_intfs_id) +{ + return true; } -bool PortsOrch::setHostIntfsStripTag(Port& port, sai_hostif_vlan_tag_t strip) { - return true; +bool PortsOrch::setHostIntfsStripTag(Port &port, sai_hostif_vlan_tag_t strip) +{ + return true; } -bool PortsOrch::setBridgePortLearnMode( - Port& port, sai_bridge_port_fdb_learning_mode_t learn_mode) { - return true; +bool PortsOrch::setBridgePortLearnMode(Port &port, sai_bridge_port_fdb_learning_mode_t learn_mode) +{ + return true; } -bool PortsOrch::addVlan(string vlan) { return true; } +bool PortsOrch::addVlan(string vlan) +{ + return true; +} -bool PortsOrch::removeVlan(Port vlan) { return true; } +bool PortsOrch::removeVlan(Port vlan) +{ + return true; +} -bool PortsOrch::addLag(string lag, uint32_t spa_id, int32_t switch_id) { - return true; +bool PortsOrch::addLag(string lag, uint32_t spa_id, int32_t switch_id) +{ + return true; } -bool PortsOrch::removeLag(Port lag) { return true; } +bool PortsOrch::removeLag(Port lag) +{ + return true; +} -bool PortsOrch::setLagTpid(sai_object_id_t id, sai_uint16_t tpid) { - return true; +bool PortsOrch::setLagTpid(sai_object_id_t id, sai_uint16_t tpid) +{ + return true; } -bool PortsOrch::addLagMember(Port& lag, Port& port, string member_status) { - return true; +bool PortsOrch::addLagMember(Port &lag, Port &port, string member_status) +{ + return true; } -bool PortsOrch::removeLagMember(Port& lag, Port& port) { return true; } +bool PortsOrch::removeLagMember(Port &lag, Port &port) +{ + return true; +} -bool PortsOrch::setCollectionOnLagMember(Port& lagMember, - bool enableCollection) { - return true; +bool PortsOrch::setCollectionOnLagMember(Port &lagMember, bool enableCollection) +{ + return true; } -bool PortsOrch::setDistributionOnLagMember(Port& lagMember, - bool enableDistribution) { - return true; +bool PortsOrch::setDistributionOnLagMember(Port &lagMember, bool enableDistribution) +{ + return true; } -sai_status_t PortsOrch::removePort(sai_object_id_t port_id) { - return SAI_STATUS_SUCCESS; +sai_status_t PortsOrch::removePort(sai_object_id_t port_id) +{ + return SAI_STATUS_SUCCESS; } -bool PortsOrch::initPort(const PortConfig& port) { return true; } +bool PortsOrch::initPort(const PortConfig &port) +{ + return true; +} -void PortsOrch::deInitPort(string alias, sai_object_id_t port_id) {} +void PortsOrch::deInitPort(string alias, sai_object_id_t port_id) +{ +} -bool PortsOrch::setPortAdminStatus(Port& port, bool up) { return true; } +bool PortsOrch::setPortAdminStatus(Port &port, bool up) +{ + return true; +} -bool PortsOrch::getPortAdminStatus(sai_object_id_t id, bool& up) { - return true; +bool PortsOrch::getPortAdminStatus(sai_object_id_t id, bool &up) +{ + return true; } -bool PortsOrch::setPortMtu(const Port& port, sai_uint32_t mtu) { return true; } +bool PortsOrch::setPortMtu(const Port &port, sai_uint32_t mtu) +{ + return true; +} -bool PortsOrch::setPortTpid(Port& port, sai_uint16_t tpid) { return true; } +bool PortsOrch::setPortTpid(Port &port, sai_uint16_t tpid) +{ + return true; +} -bool PortsOrch::setPortPvid(Port& port, sai_uint32_t pvid) { return true; } +bool PortsOrch::setPortPvid(Port &port, sai_uint32_t pvid) +{ + return true; +} -bool PortsOrch::getPortPvid(Port& port, sai_uint32_t& pvid) { return true; } +bool PortsOrch::getPortPvid(Port &port, sai_uint32_t &pvid) +{ + return true; +} -bool PortsOrch::setPortFec(Port& port, sai_port_fec_mode_t fec_mode, - bool override_fec) { - return true; +bool PortsOrch::setPortFec(Port &port, sai_port_fec_mode_t fec_mode, bool override_fec) +{ + return true; } -bool PortsOrch::isFecModeSupported(const Port& port, - sai_port_fec_mode_t fec_mode) { - return true; +bool PortsOrch::isFecModeSupported(const Port &port, sai_port_fec_mode_t fec_mode) +{ + return true; } -bool PortsOrch::setPortPfcAsym(Port& port, - sai_port_priority_flow_control_mode_t pfc_asym) { - return true; +bool PortsOrch::setPortPfcAsym(Port &port, sai_port_priority_flow_control_mode_t pfc_asym) +{ + return true; } -bool PortsOrch::getDestPortId(sai_object_id_t src_port_id, - dest_port_type_t port_type, - sai_object_id_t& des_port_id) { - return true; +bool PortsOrch::getDestPortId(sai_object_id_t src_port_id, dest_port_type_t port_type, sai_object_id_t &des_port_id) +{ + return true; } -bool PortsOrch::setBridgePortAdminStatus(sai_object_id_t id, bool up) { - return true; +bool PortsOrch::setBridgePortAdminStatus(sai_object_id_t id, bool up) +{ + return true; } -bool PortsOrch::isSpeedSupported(const std::string& alias, - sai_object_id_t port_id, sai_uint32_t speed) { - return true; +bool PortsOrch::isSpeedSupported(const std::string &alias, sai_object_id_t port_id, sai_uint32_t speed) +{ + return true; } -void PortsOrch::getPortSupportedSpeeds(const std::string& alias, - sai_object_id_t port_id, - PortSupportedSpeeds& supported_speeds) {} +void PortsOrch::getPortSupportedSpeeds(const std::string &alias, sai_object_id_t port_id, + PortSupportedSpeeds &supported_speeds) +{ +} -void PortsOrch::initPortSupportedSpeeds(const std::string& alias, - sai_object_id_t port_id) {} +void PortsOrch::initPortSupportedSpeeds(const std::string &alias, sai_object_id_t port_id) +{ +} -task_process_status PortsOrch::setPortSpeed(Port& port, sai_uint32_t speed) { - return task_success; +task_process_status PortsOrch::setPortSpeed(Port &port, sai_uint32_t speed) +{ + return task_success; } -bool PortsOrch::getPortSpeed(sai_object_id_t port_id, sai_uint32_t& speed) { - return true; +bool PortsOrch::getPortSpeed(sai_object_id_t port_id, sai_uint32_t &speed) +{ + return true; } -bool PortsOrch::setGearboxPortsAttr(const Port& port, sai_port_attr_t id, - void* value, bool override_fec) { - return true; +bool PortsOrch::setGearboxPortsAttr(const Port &port, sai_port_attr_t id, void *value, bool override_fec) +{ + return true; } -bool PortsOrch::setGearboxPortAttr(const Port& port, dest_port_type_t port_type, - sai_port_attr_t id, void* value, - bool override_fec) { - return true; +bool PortsOrch::setGearboxPortAttr(const Port &port, dest_port_type_t port_type, sai_port_attr_t id, void *value, + bool override_fec) +{ + return true; } -task_process_status PortsOrch::setPortAdvSpeeds( - Port& port, std::set& speed_list) { - return task_success; +task_process_status PortsOrch::setPortAdvSpeeds(Port &port, std::set &speed_list) +{ + return task_success; } -bool PortsOrch::getQueueTypeAndIndex(sai_object_id_t queue_id, string& type, - uint8_t& index) { - return true; +bool PortsOrch::getQueueTypeAndIndex(sai_object_id_t queue_id, string &type, uint8_t &index) +{ + return true; } -bool PortsOrch::isAutoNegEnabled(sai_object_id_t id) { return true; } +bool PortsOrch::isAutoNegEnabled(sai_object_id_t id) +{ + return true; +} -task_process_status PortsOrch::setPortAutoNeg(Port& port, bool autoneg) { - return task_success; +task_process_status PortsOrch::setPortAutoNeg(Port &port, bool autoneg) +{ + return task_success; } -task_process_status PortsOrch::setPortInterfaceType( - Port& port, sai_port_interface_type_t interface_type) { - return task_success; +task_process_status PortsOrch::setPortInterfaceType(Port &port, sai_port_interface_type_t interface_type) +{ + return task_success; } -task_process_status PortsOrch::setPortAdvInterfaceTypes( - Port& port, std::set& interface_types) { - return task_success; +task_process_status PortsOrch::setPortAdvInterfaceTypes(Port &port, + std::set &interface_types) +{ + return task_success; } -void PortsOrch::updatePortOperStatus(Port& port, - sai_port_oper_status_t status) {} +void PortsOrch::updatePortOperStatus(Port &port, sai_port_oper_status_t status) +{ +} -bool PortsOrch::getPortOperSpeed(const Port& port, sai_uint32_t& speed) const { - return true; +bool PortsOrch::getPortOperSpeed(const Port &port, sai_uint32_t &speed) const +{ + return true; } -void PortsOrch::updateDbPortOperSpeed(Port& port, sai_uint32_t speed) {} +void PortsOrch::updateDbPortOperSpeed(Port &port, sai_uint32_t speed) +{ +} -void PortsOrch::getPortSerdesVal(const std::string& s, - std::vector& lane_values, int base) { +void PortsOrch::getPortSerdesVal(const std::string &s, std::vector &lane_values, int base) +{ } -void PortsOrch::removePortSerdesAttribute(sai_object_id_t port_id) {} +void PortsOrch::removePortSerdesAttribute(sai_object_id_t port_id) +{ +} -bool PortsOrch::getSaiAclBindPointType( - Port::Type type, sai_acl_bind_point_type_t& sai_acl_bind_type) { - return true; +bool PortsOrch::getSaiAclBindPointType(Port::Type type, sai_acl_bind_point_type_t &sai_acl_bind_type) +{ + return true; } -void PortsOrch::initGearbox() {} +void PortsOrch::initGearbox() +{ +} -bool PortsOrch::initGearboxPort(Port& port) { return true; } +bool PortsOrch::initGearboxPort(Port &port) +{ + return true; +} -bool PortsOrch::getSystemPorts() { return true; } +bool PortsOrch::getSystemPorts() +{ + return true; +} -bool PortsOrch::addSystemPorts() { return true; } +bool PortsOrch::addSystemPorts() +{ + return true; +} -void PortsOrch::voqSyncAddLag(Port& lag) {} +void PortsOrch::voqSyncAddLag(Port &lag) +{ +} -void PortsOrch::voqSyncDelLag(Port& lag) {} +void PortsOrch::voqSyncDelLag(Port &lag) +{ +} -void PortsOrch::voqSyncAddLagMember(Port& lag, Port& port, string status) {} +void PortsOrch::voqSyncAddLagMember(Port &lag, Port &port, string status) +{ +} -void PortsOrch::voqSyncDelLagMember(Port& lag, Port& port) {} +void PortsOrch::voqSyncDelLagMember(Port &lag, Port &port) +{ +} -std::unordered_set PortsOrch::generateCounterStats( - const string& type, bool gearbox) { - return {}; +std::unordered_set PortsOrch::generateCounterStats(const string &type, bool gearbox) +{ + return {}; } -void PortsOrch::doTask(swss::SelectableTimer& timer) {} +void PortsOrch::doTask(swss::SelectableTimer &timer) +{ +} diff --git a/orchagent/p4orch/tests/fake_producertable.cpp b/orchagent/p4orch/tests/fake_producertable.cpp index 6254c4c1582..703be025ebe 100644 --- a/orchagent/p4orch/tests/fake_producertable.cpp +++ b/orchagent/p4orch/tests/fake_producertable.cpp @@ -3,18 +3,25 @@ #include "producertable.h" -namespace swss { +namespace swss +{ -ProducerTable::ProducerTable(DBConnector* db, const std::string& tableName) - : TableBase(tableName, ":"), TableName_KeyValueOpQueues(tableName) {} +ProducerTable::ProducerTable(DBConnector *db, const std::string &tableName) + : TableBase(tableName, ":"), TableName_KeyValueOpQueues(tableName) +{ +} -ProducerTable::~ProducerTable() {} +ProducerTable::~ProducerTable() +{ +} -void ProducerTable::set(const std::string& key, - const std::vector& values, - const std::string& op, const std::string& prefix) {} +void ProducerTable::set(const std::string &key, const std::vector &values, const std::string &op, + const std::string &prefix) +{ +} -void ProducerTable::del(const std::string& key, const std::string& op, - const std::string& prefix) {} +void ProducerTable::del(const std::string &key, const std::string &op, const std::string &prefix) +{ +} -} // namespace swss +} // namespace swss diff --git a/orchagent/p4orch/tests/fake_subscriberstatetable.cpp b/orchagent/p4orch/tests/fake_subscriberstatetable.cpp index 8eda3e2f7ce..729fbcefae9 100644 --- a/orchagent/p4orch/tests/fake_subscriberstatetable.cpp +++ b/orchagent/p4orch/tests/fake_subscriberstatetable.cpp @@ -1,11 +1,11 @@ #include "subscriberstatetable.h" -namespace swss { +namespace swss +{ -SubscriberStateTable::SubscriberStateTable(DBConnector* db, - const std::string& tableName, - int popBatchSize, int pri) - : ConsumerTableBase(db, tableName, popBatchSize, pri), - m_table(db, tableName) {} +SubscriberStateTable::SubscriberStateTable(DBConnector *db, const std::string &tableName, int popBatchSize, int pri) + : ConsumerTableBase(db, tableName, popBatchSize, pri), m_table(db, tableName) +{ +} -} // namespace swss +} // namespace swss diff --git a/orchagent/p4orch/tests/fake_table.cpp b/orchagent/p4orch/tests/fake_table.cpp index 50ebe9b6f2c..e1f785f048c 100644 --- a/orchagent/p4orch/tests/fake_table.cpp +++ b/orchagent/p4orch/tests/fake_table.cpp @@ -2,82 +2,96 @@ #include "table.h" -namespace swss { +namespace swss +{ using TableDataT = std::map>; using TablesT = std::map; -namespace fake_db { +namespace fake_db +{ TablesT gTables; -} // namespace fake_db +} // namespace fake_db using namespace fake_db; -Table::Table(const DBConnector* db, const std::string& tableName) - : TableBase(tableName, ":") {} - -Table::~Table() {} +Table::Table(const DBConnector *db, const std::string &tableName) : TableBase(tableName, ":") +{ +} -void Table::hset(const std::string& key, const std::string& field, - const std::string& value, const std::string& /*op*/, - const std::string& /*prefix*/) { - gTables[getTableName()][key][field] = value; +Table::~Table() +{ } -void Table::set(const std::string& key, - const std::vector& values, - const std::string& /*op*/, const std::string& /*prefix*/) { - auto& fvs = gTables[getTableName()][key]; - for (const auto& fv : values) { - fvs[fv.first] = fv.second; - } +void Table::hset(const std::string &key, const std::string &field, const std::string &value, const std::string & /*op*/, + const std::string & /*prefix*/) +{ + gTables[getTableName()][key][field] = value; } -bool Table::hget(const std::string& key, const std::string& field, - std::string& value) { - const auto& table_data = gTables[getTableName()]; - const auto& key_it = table_data.find(key); - if (key_it == table_data.end()) { - return false; - } - const auto& field_it = key_it->second.find(field); - if (field_it == key_it->second.end()) { - return false; - } - value = field_it->second; - return true; +void Table::set(const std::string &key, const std::vector &values, const std::string & /*op*/, + const std::string & /*prefix*/) +{ + auto &fvs = gTables[getTableName()][key]; + for (const auto &fv : values) + { + fvs[fv.first] = fv.second; + } } -bool Table::get(const std::string& key, std::vector& ovalues) { - const auto& table_data = gTables[getTableName()]; - if (table_data.find(key) == table_data.end()) { - return false; - } +bool Table::hget(const std::string &key, const std::string &field, std::string &value) +{ + const auto &table_data = gTables[getTableName()]; + const auto &key_it = table_data.find(key); + if (key_it == table_data.end()) + { + return false; + } + const auto &field_it = key_it->second.find(field); + if (field_it == key_it->second.end()) + { + return false; + } + value = field_it->second; + return true; +} - for (const auto& fv : table_data.at(key)) { - ovalues.push_back({fv.first, fv.second}); - } - return true; +bool Table::get(const std::string &key, std::vector &ovalues) +{ + const auto &table_data = gTables[getTableName()]; + if (table_data.find(key) == table_data.end()) + { + return false; + } + + for (const auto &fv : table_data.at(key)) + { + ovalues.push_back({fv.first, fv.second}); + } + return true; } -void Table::del(const std::string& key, const std::string& /*op*/, - const std::string& /*prefix*/) { - gTables[getTableName()].erase(key); +void Table::del(const std::string &key, const std::string & /*op*/, const std::string & /*prefix*/) +{ + gTables[getTableName()].erase(key); } -void Table::hdel(const std::string& key, const std::string& field, - const std::string& /*op*/, const std::string& /*prefix*/) { - gTables[getTableName()][key].erase(field); +void Table::hdel(const std::string &key, const std::string &field, const std::string & /*op*/, + const std::string & /*prefix*/) +{ + gTables[getTableName()][key].erase(field); } -void Table::getKeys(std::vector& keys) { - keys.clear(); - auto table = gTables[getTableName()]; - for (const auto& it : table) { - keys.push_back(it.first); - } +void Table::getKeys(std::vector &keys) +{ + keys.clear(); + auto table = gTables[getTableName()]; + for (const auto &it : table) + { + keys.push_back(it.first); + } } -} // namespace swss +} // namespace swss diff --git a/orchagent/p4orch/tests/gre_tunnel_manager_test.cpp b/orchagent/p4orch/tests/gre_tunnel_manager_test.cpp index f3e145a6578..da3ae3578be 100644 --- a/orchagent/p4orch/tests/gre_tunnel_manager_test.cpp +++ b/orchagent/p4orch/tests/gre_tunnel_manager_test.cpp @@ -18,7 +18,8 @@ #include "p4orch_util.h" #include "return_code.h" #include "swssnet.h" -extern "C" { +extern "C" +{ #include "sai.h" } @@ -33,1043 +34,876 @@ using ::testing::StrictMock; using ::testing::Truly; extern sai_object_id_t gSwitchId; -extern sai_tunnel_api_t* sai_tunnel_api; -extern sai_router_interface_api_t* sai_router_intfs_api; -extern MockSaiTunnel* mock_sai_tunnel; +extern sai_tunnel_api_t *sai_tunnel_api; +extern sai_router_interface_api_t *sai_router_intfs_api; +extern MockSaiTunnel *mock_sai_tunnel; -namespace { -constexpr char* kRouterInterfaceId1 = "intf-eth-1/2/3"; +namespace +{ +constexpr char *kRouterInterfaceId1 = "intf-eth-1/2/3"; constexpr sai_object_id_t kRouterInterfaceOid1 = 1; -constexpr char* kGreTunnelP4AppDbId1 = "tunnel-1"; -constexpr char* kGreTunnelP4AppDbKey1 = R"({"match/tunnel_id":"tunnel-1"})"; +constexpr char *kGreTunnelP4AppDbId1 = "tunnel-1"; +constexpr char *kGreTunnelP4AppDbKey1 = R"({"match/tunnel_id":"tunnel-1"})"; constexpr sai_object_id_t kGreTunnelOid1 = 0x11; constexpr sai_object_id_t kOverlayRifOid1 = 0x101; // APP DB entries for Add request. -const P4GreTunnelAppDbEntry kP4GreTunnelAppDbEntry1{ - /*tunnel_id=*/"tunnel-1", - /*router_interface_id=*/"intf-eth-1/2/3", - /*encap_src_ip=*/swss::IpAddress("2607:f8b0:8096:3110::1"), - /*encap_dst_ip=*/swss::IpAddress("2607:f8b0:8096:311a::2"), - /*action_str=*/"mark_for_p2p_tunnel_encap"}; - -std::unordered_map -CreateAttributeListForGreTunnelObject(const P4GreTunnelAppDbEntry& app_entry, - const sai_object_id_t& rif_oid) { - std::unordered_map tunnel_attrs; - sai_attribute_t tunnel_attr; - - tunnel_attr.id = SAI_TUNNEL_ATTR_TYPE; - tunnel_attr.value.s32 = SAI_TUNNEL_TYPE_IPINIP_GRE; - tunnel_attrs.insert({tunnel_attr.id, tunnel_attr.value}); - - tunnel_attr.id = SAI_TUNNEL_ATTR_PEER_MODE; - tunnel_attr.value.s32 = SAI_TUNNEL_PEER_MODE_P2P; - tunnel_attrs.insert({tunnel_attr.id, tunnel_attr.value}); - - tunnel_attr.id = SAI_TUNNEL_ATTR_OVERLAY_INTERFACE; - tunnel_attr.value.oid = kOverlayRifOid1; - tunnel_attrs.insert({tunnel_attr.id, tunnel_attr.value}); - - tunnel_attr.id = SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE; - tunnel_attr.value.oid = rif_oid; - tunnel_attrs.insert({tunnel_attr.id, tunnel_attr.value}); - - tunnel_attr.id = SAI_TUNNEL_ATTR_ENCAP_SRC_IP; - swss::copy(tunnel_attr.value.ipaddr, app_entry.encap_src_ip); - tunnel_attrs.insert({tunnel_attr.id, tunnel_attr.value}); - - tunnel_attr.id = SAI_TUNNEL_ATTR_ENCAP_DST_IP; - swss::copy(tunnel_attr.value.ipaddr, app_entry.encap_dst_ip); - tunnel_attrs.insert({tunnel_attr.id, tunnel_attr.value}); - - return tunnel_attrs; +const P4GreTunnelAppDbEntry kP4GreTunnelAppDbEntry1{/*tunnel_id=*/"tunnel-1", + /*router_interface_id=*/"intf-eth-1/2/3", + /*encap_src_ip=*/swss::IpAddress("2607:f8b0:8096:3110::1"), + /*encap_dst_ip=*/swss::IpAddress("2607:f8b0:8096:311a::2"), + /*action_str=*/"mark_for_p2p_tunnel_encap"}; + +std::unordered_map CreateAttributeListForGreTunnelObject( + const P4GreTunnelAppDbEntry &app_entry, const sai_object_id_t &rif_oid) +{ + std::unordered_map tunnel_attrs; + sai_attribute_t tunnel_attr; + + tunnel_attr.id = SAI_TUNNEL_ATTR_TYPE; + tunnel_attr.value.s32 = SAI_TUNNEL_TYPE_IPINIP_GRE; + tunnel_attrs.insert({tunnel_attr.id, tunnel_attr.value}); + + tunnel_attr.id = SAI_TUNNEL_ATTR_PEER_MODE; + tunnel_attr.value.s32 = SAI_TUNNEL_PEER_MODE_P2P; + tunnel_attrs.insert({tunnel_attr.id, tunnel_attr.value}); + + tunnel_attr.id = SAI_TUNNEL_ATTR_OVERLAY_INTERFACE; + tunnel_attr.value.oid = kOverlayRifOid1; + tunnel_attrs.insert({tunnel_attr.id, tunnel_attr.value}); + + tunnel_attr.id = SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE; + tunnel_attr.value.oid = rif_oid; + tunnel_attrs.insert({tunnel_attr.id, tunnel_attr.value}); + + tunnel_attr.id = SAI_TUNNEL_ATTR_ENCAP_SRC_IP; + swss::copy(tunnel_attr.value.ipaddr, app_entry.encap_src_ip); + tunnel_attrs.insert({tunnel_attr.id, tunnel_attr.value}); + + tunnel_attr.id = SAI_TUNNEL_ATTR_ENCAP_DST_IP; + swss::copy(tunnel_attr.value.ipaddr, app_entry.encap_dst_ip); + tunnel_attrs.insert({tunnel_attr.id, tunnel_attr.value}); + + return tunnel_attrs; } // Verifies whether the attribute list is the same as expected. // Returns true if they match; otherwise, false. -bool MatchCreateGreTunnelArgAttrList( - const sai_attribute_t* attr_list, - const std::unordered_map& - expected_attr_list) { - if (attr_list == nullptr) { - return false; - } - - // Sanity check for expected_attr_list. - const auto end = expected_attr_list.end(); - if (expected_attr_list.size() < 3 || - expected_attr_list.find(SAI_TUNNEL_ATTR_TYPE) == end || - expected_attr_list.find(SAI_TUNNEL_ATTR_PEER_MODE) == end || - expected_attr_list.find(SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE) == end || - expected_attr_list.find(SAI_TUNNEL_ATTR_OVERLAY_INTERFACE) == end || - expected_attr_list.find(SAI_TUNNEL_ATTR_ENCAP_SRC_IP) == end || - expected_attr_list.find(SAI_TUNNEL_ATTR_ENCAP_DST_IP) == end) { - return false; - } - - size_t valid_attrs_num = 0; - for (size_t i = 0; i < expected_attr_list.size(); ++i) { - switch (attr_list[i].id) { - case SAI_TUNNEL_ATTR_TYPE: { - if (attr_list[i].value.s32 != - expected_attr_list.at(SAI_TUNNEL_ATTR_TYPE).s32) { - return false; +bool MatchCreateGreTunnelArgAttrList(const sai_attribute_t *attr_list, + const std::unordered_map &expected_attr_list) +{ + if (attr_list == nullptr) + { + return false; + } + + // Sanity check for expected_attr_list. + const auto end = expected_attr_list.end(); + if (expected_attr_list.size() < 3 || expected_attr_list.find(SAI_TUNNEL_ATTR_TYPE) == end || + expected_attr_list.find(SAI_TUNNEL_ATTR_PEER_MODE) == end || + expected_attr_list.find(SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE) == end || + expected_attr_list.find(SAI_TUNNEL_ATTR_OVERLAY_INTERFACE) == end || + expected_attr_list.find(SAI_TUNNEL_ATTR_ENCAP_SRC_IP) == end || + expected_attr_list.find(SAI_TUNNEL_ATTR_ENCAP_DST_IP) == end) + { + return false; + } + + size_t valid_attrs_num = 0; + for (size_t i = 0; i < expected_attr_list.size(); ++i) + { + switch (attr_list[i].id) + { + case SAI_TUNNEL_ATTR_TYPE: { + if (attr_list[i].value.s32 != expected_attr_list.at(SAI_TUNNEL_ATTR_TYPE).s32) + { + return false; + } + valid_attrs_num++; + break; } - valid_attrs_num++; - break; - } - case SAI_TUNNEL_ATTR_PEER_MODE: { - if (attr_list[i].value.s32 != - expected_attr_list.at(SAI_TUNNEL_ATTR_PEER_MODE).s32) { - return false; + case SAI_TUNNEL_ATTR_PEER_MODE: { + if (attr_list[i].value.s32 != expected_attr_list.at(SAI_TUNNEL_ATTR_PEER_MODE).s32) + { + return false; + } + valid_attrs_num++; + break; } - valid_attrs_num++; - break; - } - case SAI_TUNNEL_ATTR_ENCAP_SRC_IP: { - if (attr_list[i].value.ipaddr.addr_family != - expected_attr_list.at(SAI_TUNNEL_ATTR_ENCAP_SRC_IP) - .ipaddr.addr_family || - (attr_list[i].value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV4 && - attr_list[i].value.ipaddr.addr.ip4 != - expected_attr_list.at(SAI_TUNNEL_ATTR_ENCAP_SRC_IP) - .ipaddr.addr.ip4) || - (attr_list[i].value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV6 && - memcmp(&attr_list[i].value.ipaddr.addr.ip6, - &expected_attr_list.at(SAI_TUNNEL_ATTR_ENCAP_SRC_IP) - .ipaddr.addr.ip6, - sizeof(sai_ip6_t)) != 0)) { - return false; + case SAI_TUNNEL_ATTR_ENCAP_SRC_IP: { + if (attr_list[i].value.ipaddr.addr_family != + expected_attr_list.at(SAI_TUNNEL_ATTR_ENCAP_SRC_IP).ipaddr.addr_family || + (attr_list[i].value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV4 && + attr_list[i].value.ipaddr.addr.ip4 != + expected_attr_list.at(SAI_TUNNEL_ATTR_ENCAP_SRC_IP).ipaddr.addr.ip4) || + (attr_list[i].value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV6 && + memcmp(&attr_list[i].value.ipaddr.addr.ip6, + &expected_attr_list.at(SAI_TUNNEL_ATTR_ENCAP_SRC_IP).ipaddr.addr.ip6, sizeof(sai_ip6_t)) != 0)) + { + return false; + } + valid_attrs_num++; + break; } - valid_attrs_num++; - break; - } - case SAI_TUNNEL_ATTR_ENCAP_DST_IP: { - if (attr_list[i].value.ipaddr.addr_family != - expected_attr_list.at(SAI_TUNNEL_ATTR_ENCAP_DST_IP) - .ipaddr.addr_family || - (attr_list[i].value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV4 && - attr_list[i].value.ipaddr.addr.ip4 != - expected_attr_list.at(SAI_TUNNEL_ATTR_ENCAP_DST_IP) - .ipaddr.addr.ip4) || - (attr_list[i].value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV6 && - memcmp(&attr_list[i].value.ipaddr.addr.ip6, - &expected_attr_list.at(SAI_TUNNEL_ATTR_ENCAP_DST_IP) - .ipaddr.addr.ip6, - sizeof(sai_ip6_t)) != 0)) { - return false; + case SAI_TUNNEL_ATTR_ENCAP_DST_IP: { + if (attr_list[i].value.ipaddr.addr_family != + expected_attr_list.at(SAI_TUNNEL_ATTR_ENCAP_DST_IP).ipaddr.addr_family || + (attr_list[i].value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV4 && + attr_list[i].value.ipaddr.addr.ip4 != + expected_attr_list.at(SAI_TUNNEL_ATTR_ENCAP_DST_IP).ipaddr.addr.ip4) || + (attr_list[i].value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV6 && + memcmp(&attr_list[i].value.ipaddr.addr.ip6, + &expected_attr_list.at(SAI_TUNNEL_ATTR_ENCAP_DST_IP).ipaddr.addr.ip6, sizeof(sai_ip6_t)) != 0)) + { + return false; + } + valid_attrs_num++; + break; } - valid_attrs_num++; - break; - } - case SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE: { - if (expected_attr_list.find(SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE) == - end || - expected_attr_list.at(SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE).oid != - attr_list[i].value.oid) { - return false; + case SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE: { + if (expected_attr_list.find(SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE) == end || + expected_attr_list.at(SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE).oid != attr_list[i].value.oid) + { + return false; + } + valid_attrs_num++; + break; } - valid_attrs_num++; - break; - } - case SAI_TUNNEL_ATTR_OVERLAY_INTERFACE: { - if (expected_attr_list.find(SAI_TUNNEL_ATTR_OVERLAY_INTERFACE) == end || - expected_attr_list.at(SAI_TUNNEL_ATTR_OVERLAY_INTERFACE).oid != - attr_list[i].value.oid) { - return false; + case SAI_TUNNEL_ATTR_OVERLAY_INTERFACE: { + if (expected_attr_list.find(SAI_TUNNEL_ATTR_OVERLAY_INTERFACE) == end || + expected_attr_list.at(SAI_TUNNEL_ATTR_OVERLAY_INTERFACE).oid != attr_list[i].value.oid) + { + return false; + } + valid_attrs_num++; + break; + } + default: + return false; } - valid_attrs_num++; - break; - } - default: - return false; } - } - if (expected_attr_list.size() != valid_attrs_num) { - return false; - } + if (expected_attr_list.size() != valid_attrs_num) + { + return false; + } - return true; + return true; } -} // namespace - -class GreTunnelManagerTest : public ::testing::Test { - protected: - GreTunnelManagerTest() : gre_tunnel_manager_(&p4_oid_mapper_, &publisher_) {} - - void SetUp() override { - // Set up mock stuff for SAI tunnel API structure. - mock_sai_tunnel = &mock_sai_tunnel_; - sai_tunnel_api->create_tunnel = mock_create_tunnel; - sai_tunnel_api->remove_tunnel = mock_remove_tunnel; - // Set up mock stuff for SAI router interface API structure. - mock_sai_router_intf = &mock_sai_router_intf_; - sai_router_intfs_api->create_router_interface = - mock_create_router_interface; - sai_router_intfs_api->remove_router_interface = - mock_remove_router_interface; - - mock_sai_serialize = &mock_sai_serialize_; - } - - void Enqueue(const swss::KeyOpFieldsValuesTuple& entry) { - gre_tunnel_manager_.enqueue(APP_P4RT_TUNNEL_TABLE_NAME, entry); - } - - void Drain() { gre_tunnel_manager_.drain(); } - - std::string VerifyState(const std::string& key, - const std::vector& tuple) { - return gre_tunnel_manager_.verifyState(key, tuple); - } - - ReturnCode ProcessAddRequest(const P4GreTunnelAppDbEntry& app_db_entry) { - return gre_tunnel_manager_.processAddRequest(app_db_entry); - } - - ReturnCode ProcessDeleteRequest(const std::string& tunnel_key) { - return gre_tunnel_manager_.processDeleteRequest(tunnel_key); - } - - P4GreTunnelEntry* GetGreTunnelEntry(const std::string& tunnel_key) { - return gre_tunnel_manager_.getGreTunnelEntry(tunnel_key); - } - - ReturnCodeOr DeserializeP4GreTunnelAppDbEntry( - const std::string& key, - const std::vector& attributes) { - return gre_tunnel_manager_.deserializeP4GreTunnelAppDbEntry(key, - attributes); - } - - // Adds the gre tunnel entry -- kP4GreTunnelAppDbEntry1, via gre tunnel - // manager's ProcessAddRequest (). This function also takes care of all the - // dependencies of the gre tunnel entry. Returns a valid pointer to gre tunnel - // entry on success. - P4GreTunnelEntry* AddGreTunnelEntry1(); - - // Validates that a P4 App gre tunnel entry is correctly added in gre tunnel - // manager and centralized mapper. Returns true on success. - bool ValidateGreTunnelEntryAdd(const P4GreTunnelAppDbEntry& app_db_entry); - - // Return true if the specified the object has the expected number of - // reference. - bool ValidateRefCnt(sai_object_type_t object_type, const std::string& key, - uint32_t expected_ref_count) { - uint32_t ref_count; - if (!p4_oid_mapper_.getRefCount(object_type, key, &ref_count)) return false; - return ref_count == expected_ref_count; - } - - StrictMock mock_sai_tunnel_; - StrictMock mock_sai_router_intf_; - StrictMock mock_sai_serialize_; - MockResponsePublisher publisher_; - P4OidMapper p4_oid_mapper_; - GreTunnelManager gre_tunnel_manager_; +} // namespace + +class GreTunnelManagerTest : public ::testing::Test +{ + protected: + GreTunnelManagerTest() : gre_tunnel_manager_(&p4_oid_mapper_, &publisher_) + { + } + + void SetUp() override + { + // Set up mock stuff for SAI tunnel API structure. + mock_sai_tunnel = &mock_sai_tunnel_; + sai_tunnel_api->create_tunnel = mock_create_tunnel; + sai_tunnel_api->remove_tunnel = mock_remove_tunnel; + // Set up mock stuff for SAI router interface API structure. + mock_sai_router_intf = &mock_sai_router_intf_; + sai_router_intfs_api->create_router_interface = mock_create_router_interface; + sai_router_intfs_api->remove_router_interface = mock_remove_router_interface; + + mock_sai_serialize = &mock_sai_serialize_; + } + + void Enqueue(const swss::KeyOpFieldsValuesTuple &entry) + { + gre_tunnel_manager_.enqueue(APP_P4RT_TUNNEL_TABLE_NAME, entry); + } + + void Drain() + { + gre_tunnel_manager_.drain(); + } + + std::string VerifyState(const std::string &key, const std::vector &tuple) + { + return gre_tunnel_manager_.verifyState(key, tuple); + } + + ReturnCode ProcessAddRequest(const P4GreTunnelAppDbEntry &app_db_entry) + { + return gre_tunnel_manager_.processAddRequest(app_db_entry); + } + + ReturnCode ProcessDeleteRequest(const std::string &tunnel_key) + { + return gre_tunnel_manager_.processDeleteRequest(tunnel_key); + } + + P4GreTunnelEntry *GetGreTunnelEntry(const std::string &tunnel_key) + { + return gre_tunnel_manager_.getGreTunnelEntry(tunnel_key); + } + + ReturnCodeOr DeserializeP4GreTunnelAppDbEntry( + const std::string &key, const std::vector &attributes) + { + return gre_tunnel_manager_.deserializeP4GreTunnelAppDbEntry(key, attributes); + } + + // Adds the gre tunnel entry -- kP4GreTunnelAppDbEntry1, via gre tunnel + // manager's ProcessAddRequest (). This function also takes care of all the + // dependencies of the gre tunnel entry. Returns a valid pointer to gre tunnel + // entry on success. + P4GreTunnelEntry *AddGreTunnelEntry1(); + + // Validates that a P4 App gre tunnel entry is correctly added in gre tunnel + // manager and centralized mapper. Returns true on success. + bool ValidateGreTunnelEntryAdd(const P4GreTunnelAppDbEntry &app_db_entry); + + // Return true if the specified the object has the expected number of + // reference. + bool ValidateRefCnt(sai_object_type_t object_type, const std::string &key, uint32_t expected_ref_count) + { + uint32_t ref_count; + if (!p4_oid_mapper_.getRefCount(object_type, key, &ref_count)) + return false; + return ref_count == expected_ref_count; + } + + StrictMock mock_sai_tunnel_; + StrictMock mock_sai_router_intf_; + StrictMock mock_sai_serialize_; + MockResponsePublisher publisher_; + P4OidMapper p4_oid_mapper_; + GreTunnelManager gre_tunnel_manager_; }; -P4GreTunnelEntry* GreTunnelManagerTest::AddGreTunnelEntry1() { - const auto gre_tunnel_key = - KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); - EXPECT_TRUE(p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), - kRouterInterfaceOid1)); - - // Set up mock call. - EXPECT_CALL( - mock_sai_router_intf_, - create_router_interface(::testing::NotNull(), Eq(gSwitchId), Eq(2), _)) - .WillOnce( - DoAll(SetArgPointee<0>(kOverlayRifOid1), Return(SAI_STATUS_SUCCESS))); - - EXPECT_CALL( - mock_sai_tunnel_, - create_tunnel(::testing::NotNull(), Eq(gSwitchId), Eq(6), - Truly(std::bind( - MatchCreateGreTunnelArgAttrList, std::placeholders::_1, - CreateAttributeListForGreTunnelObject( - kP4GreTunnelAppDbEntry1, kRouterInterfaceOid1))))) - .WillOnce( - DoAll(SetArgPointee<0>(kGreTunnelOid1), Return(SAI_STATUS_SUCCESS))); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRequest(kP4GreTunnelAppDbEntry1)); - - return GetGreTunnelEntry(gre_tunnel_key); +P4GreTunnelEntry *GreTunnelManagerTest::AddGreTunnelEntry1() +{ + const auto gre_tunnel_key = KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); + EXPECT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), + kRouterInterfaceOid1)); + + // Set up mock call. + EXPECT_CALL(mock_sai_router_intf_, create_router_interface(::testing::NotNull(), Eq(gSwitchId), Eq(2), _)) + .WillOnce(DoAll(SetArgPointee<0>(kOverlayRifOid1), Return(SAI_STATUS_SUCCESS))); + + EXPECT_CALL(mock_sai_tunnel_, create_tunnel(::testing::NotNull(), Eq(gSwitchId), Eq(6), + Truly(std::bind(MatchCreateGreTunnelArgAttrList, std::placeholders::_1, + CreateAttributeListForGreTunnelObject( + kP4GreTunnelAppDbEntry1, kRouterInterfaceOid1))))) + .WillOnce(DoAll(SetArgPointee<0>(kGreTunnelOid1), Return(SAI_STATUS_SUCCESS))); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRequest(kP4GreTunnelAppDbEntry1)); + + return GetGreTunnelEntry(gre_tunnel_key); } -bool GreTunnelManagerTest::ValidateGreTunnelEntryAdd( - const P4GreTunnelAppDbEntry& app_db_entry) { - const auto* p4_gre_tunnel_entry = GetGreTunnelEntry( - KeyGenerator::generateTunnelKey(app_db_entry.tunnel_id)); - if (p4_gre_tunnel_entry == nullptr || - p4_gre_tunnel_entry->encap_src_ip != app_db_entry.encap_src_ip || - p4_gre_tunnel_entry->encap_dst_ip != app_db_entry.encap_dst_ip || - p4_gre_tunnel_entry->neighbor_id != app_db_entry.encap_dst_ip || - p4_gre_tunnel_entry->router_interface_id != - app_db_entry.router_interface_id || - p4_gre_tunnel_entry->tunnel_id != app_db_entry.tunnel_id) { - return false; - } - - return true; +bool GreTunnelManagerTest::ValidateGreTunnelEntryAdd(const P4GreTunnelAppDbEntry &app_db_entry) +{ + const auto *p4_gre_tunnel_entry = GetGreTunnelEntry(KeyGenerator::generateTunnelKey(app_db_entry.tunnel_id)); + if (p4_gre_tunnel_entry == nullptr || p4_gre_tunnel_entry->encap_src_ip != app_db_entry.encap_src_ip || + p4_gre_tunnel_entry->encap_dst_ip != app_db_entry.encap_dst_ip || + p4_gre_tunnel_entry->neighbor_id != app_db_entry.encap_dst_ip || + p4_gre_tunnel_entry->router_interface_id != app_db_entry.router_interface_id || + p4_gre_tunnel_entry->tunnel_id != app_db_entry.tunnel_id) + { + return false; + } + + return true; } -TEST_F(GreTunnelManagerTest, ProcessAddRequestShouldSucceedAddingNewGreTunnel) { - AddGreTunnelEntry1(); - EXPECT_TRUE(ValidateGreTunnelEntryAdd(kP4GreTunnelAppDbEntry1)); +TEST_F(GreTunnelManagerTest, ProcessAddRequestShouldSucceedAddingNewGreTunnel) +{ + AddGreTunnelEntry1(); + EXPECT_TRUE(ValidateGreTunnelEntryAdd(kP4GreTunnelAppDbEntry1)); } -TEST_F(GreTunnelManagerTest, - ProcessAddRequestShouldFailWhenGreTunnelExistInCentralMapper) { - const auto gre_tunnel_key = - KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); - ASSERT_EQ(gre_tunnel_key, "tunnel_id=tunnel-1"); - ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key, - kGreTunnelOid1)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, - ProcessAddRequest(kP4GreTunnelAppDbEntry1)); +TEST_F(GreTunnelManagerTest, ProcessAddRequestShouldFailWhenGreTunnelExistInCentralMapper) +{ + const auto gre_tunnel_key = KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); + ASSERT_EQ(gre_tunnel_key, "tunnel_id=tunnel-1"); + ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key, kGreTunnelOid1)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, ProcessAddRequest(kP4GreTunnelAppDbEntry1)); } -TEST_F(GreTunnelManagerTest, - ProcessAddRequestShouldFailWhenDependingPortIsNotPresent) { - const P4GreTunnelAppDbEntry kAppDbEntry{ - /*tunnel_id=*/"tunnel-1", - /*router_interface_id=*/"intf-eth-1/2/3", - /*encap_src_ip=*/swss::IpAddress("2607:f8b0:8096:3110::1"), - /*encap_dst_ip=*/swss::IpAddress("2607:f8b0:8096:311a::2"), - /*action_str=*/"mark_for_p2p_tunnel_encap"}; - const auto gre_tunnel_key = - KeyGenerator::generateTunnelKey(kAppDbEntry.tunnel_id); +TEST_F(GreTunnelManagerTest, ProcessAddRequestShouldFailWhenDependingPortIsNotPresent) +{ + const P4GreTunnelAppDbEntry kAppDbEntry{/*tunnel_id=*/"tunnel-1", + /*router_interface_id=*/"intf-eth-1/2/3", + /*encap_src_ip=*/swss::IpAddress("2607:f8b0:8096:3110::1"), + /*encap_dst_ip=*/swss::IpAddress("2607:f8b0:8096:311a::2"), + /*action_str=*/"mark_for_p2p_tunnel_encap"}; + const auto gre_tunnel_key = KeyGenerator::generateTunnelKey(kAppDbEntry.tunnel_id); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessAddRequest(kAppDbEntry)); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessAddRequest(kAppDbEntry)); - EXPECT_EQ(GetGreTunnelEntry(gre_tunnel_key), nullptr); + EXPECT_EQ(GetGreTunnelEntry(gre_tunnel_key), nullptr); } -TEST_F(GreTunnelManagerTest, ProcessAddRequestShouldFailWhenRifSaiCallFails) { - const auto gre_tunnel_key = - KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); - EXPECT_TRUE(p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), - kRouterInterfaceOid1)); - // Set up mock call. - EXPECT_CALL( - mock_sai_router_intf_, - create_router_interface(::testing::NotNull(), Eq(gSwitchId), Eq(2), _)) - .WillOnce( - DoAll(SetArgPointee<0>(kOverlayRifOid1), Return(SAI_STATUS_FAILURE))); - - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - ProcessAddRequest(kP4GreTunnelAppDbEntry1)); - - // The add request failed for the gre tunnel entry. - EXPECT_EQ(GetGreTunnelEntry(gre_tunnel_key), nullptr); +TEST_F(GreTunnelManagerTest, ProcessAddRequestShouldFailWhenRifSaiCallFails) +{ + const auto gre_tunnel_key = KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); + EXPECT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), + kRouterInterfaceOid1)); + // Set up mock call. + EXPECT_CALL(mock_sai_router_intf_, create_router_interface(::testing::NotNull(), Eq(gSwitchId), Eq(2), _)) + .WillOnce(DoAll(SetArgPointee<0>(kOverlayRifOid1), Return(SAI_STATUS_FAILURE))); + + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddRequest(kP4GreTunnelAppDbEntry1)); + + // The add request failed for the gre tunnel entry. + EXPECT_EQ(GetGreTunnelEntry(gre_tunnel_key), nullptr); } -TEST_F(GreTunnelManagerTest, - ProcessAddRequestShouldFailWhenTunnelSaiCallFails) { - const auto gre_tunnel_key = - KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); - EXPECT_TRUE(p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), - kRouterInterfaceOid1)); - // Set up mock call. - EXPECT_CALL( - mock_sai_router_intf_, - create_router_interface(::testing::NotNull(), Eq(gSwitchId), Eq(2), _)) - .WillOnce( - DoAll(SetArgPointee<0>(kOverlayRifOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL( - mock_sai_tunnel_, - create_tunnel(::testing::NotNull(), Eq(gSwitchId), Eq(6), - Truly(std::bind( - MatchCreateGreTunnelArgAttrList, std::placeholders::_1, - CreateAttributeListForGreTunnelObject( - kP4GreTunnelAppDbEntry1, kRouterInterfaceOid1))))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_router_intf_, - remove_router_interface(Eq(kOverlayRifOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - ProcessAddRequest(kP4GreTunnelAppDbEntry1)); - - // The add request failed for the gre tunnel entry. - EXPECT_EQ(GetGreTunnelEntry(gre_tunnel_key), nullptr); +TEST_F(GreTunnelManagerTest, ProcessAddRequestShouldFailWhenTunnelSaiCallFails) +{ + const auto gre_tunnel_key = KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); + EXPECT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), + kRouterInterfaceOid1)); + // Set up mock call. + EXPECT_CALL(mock_sai_router_intf_, create_router_interface(::testing::NotNull(), Eq(gSwitchId), Eq(2), _)) + .WillOnce(DoAll(SetArgPointee<0>(kOverlayRifOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_tunnel_, create_tunnel(::testing::NotNull(), Eq(gSwitchId), Eq(6), + Truly(std::bind(MatchCreateGreTunnelArgAttrList, std::placeholders::_1, + CreateAttributeListForGreTunnelObject( + kP4GreTunnelAppDbEntry1, kRouterInterfaceOid1))))) + .WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_router_intf_, remove_router_interface(Eq(kOverlayRifOid1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddRequest(kP4GreTunnelAppDbEntry1)); + + // The add request failed for the gre tunnel entry. + EXPECT_EQ(GetGreTunnelEntry(gre_tunnel_key), nullptr); } -TEST_F(GreTunnelManagerTest, - ProcessAddRequestShouldRaiseCriticalWhenRecoverySaiCallFails) { - const auto gre_tunnel_key = - KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); - EXPECT_TRUE(p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), - kRouterInterfaceOid1)); - // Set up mock call. - EXPECT_CALL( - mock_sai_router_intf_, - create_router_interface(::testing::NotNull(), Eq(gSwitchId), Eq(2), _)) - .WillOnce( - DoAll(SetArgPointee<0>(kOverlayRifOid1), Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL( - mock_sai_tunnel_, - create_tunnel(::testing::NotNull(), Eq(gSwitchId), Eq(6), - Truly(std::bind( - MatchCreateGreTunnelArgAttrList, std::placeholders::_1, - CreateAttributeListForGreTunnelObject( - kP4GreTunnelAppDbEntry1, kRouterInterfaceOid1))))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL(mock_sai_router_intf_, - remove_router_interface(Eq(kOverlayRifOid1))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - // TODO: Expect critical state. - - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - ProcessAddRequest(kP4GreTunnelAppDbEntry1)); - - // The add request failed for the gre tunnel entry. - EXPECT_EQ(GetGreTunnelEntry(gre_tunnel_key), nullptr); +TEST_F(GreTunnelManagerTest, ProcessAddRequestShouldRaiseCriticalWhenRecoverySaiCallFails) +{ + const auto gre_tunnel_key = KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); + EXPECT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), + kRouterInterfaceOid1)); + // Set up mock call. + EXPECT_CALL(mock_sai_router_intf_, create_router_interface(::testing::NotNull(), Eq(gSwitchId), Eq(2), _)) + .WillOnce(DoAll(SetArgPointee<0>(kOverlayRifOid1), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_tunnel_, create_tunnel(::testing::NotNull(), Eq(gSwitchId), Eq(6), + Truly(std::bind(MatchCreateGreTunnelArgAttrList, std::placeholders::_1, + CreateAttributeListForGreTunnelObject( + kP4GreTunnelAppDbEntry1, kRouterInterfaceOid1))))) + .WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_router_intf_, remove_router_interface(Eq(kOverlayRifOid1))) + .WillOnce(Return(SAI_STATUS_FAILURE)); + // TODO: Expect critical state. + + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddRequest(kP4GreTunnelAppDbEntry1)); + + // The add request failed for the gre tunnel entry. + EXPECT_EQ(GetGreTunnelEntry(gre_tunnel_key), nullptr); } -TEST_F(GreTunnelManagerTest, - ProcessDeleteRequestShouldFailForNonExistingGreTunnel) { - const auto gre_tunnel_key = - KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessDeleteRequest(gre_tunnel_key)); +TEST_F(GreTunnelManagerTest, ProcessDeleteRequestShouldFailForNonExistingGreTunnel) +{ + const auto gre_tunnel_key = KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessDeleteRequest(gre_tunnel_key)); } -TEST_F(GreTunnelManagerTest, - ProcessDeleteRequestShouldFailIfGreTunnelEntryIsAbsentInCentralMapper) { - auto* p4_tunnel_entry = AddGreTunnelEntry1(); - ASSERT_NE(p4_tunnel_entry, nullptr); +TEST_F(GreTunnelManagerTest, ProcessDeleteRequestShouldFailIfGreTunnelEntryIsAbsentInCentralMapper) +{ + auto *p4_tunnel_entry = AddGreTunnelEntry1(); + ASSERT_NE(p4_tunnel_entry, nullptr); - const auto gre_tunnel_key = - KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); + const auto gre_tunnel_key = KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); - ASSERT_TRUE(p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key)); + ASSERT_TRUE(p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, ProcessDeleteRequest(gre_tunnel_key)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, ProcessDeleteRequest(gre_tunnel_key)); - // Validate the gre tunnel entry is not deleted in P4 gre tunnel manager. - p4_tunnel_entry = GetGreTunnelEntry(gre_tunnel_key); - ASSERT_NE(p4_tunnel_entry, nullptr); + // Validate the gre tunnel entry is not deleted in P4 gre tunnel manager. + p4_tunnel_entry = GetGreTunnelEntry(gre_tunnel_key); + ASSERT_NE(p4_tunnel_entry, nullptr); } -TEST_F(GreTunnelManagerTest, - ProcessDeleteRequestShouldFailIfGreTunnelEntryIsStillReferenced) { - auto* p4_tunnel_entry = AddGreTunnelEntry1(); - ASSERT_NE(p4_tunnel_entry, nullptr); +TEST_F(GreTunnelManagerTest, ProcessDeleteRequestShouldFailIfGreTunnelEntryIsStillReferenced) +{ + auto *p4_tunnel_entry = AddGreTunnelEntry1(); + ASSERT_NE(p4_tunnel_entry, nullptr); - const auto gre_tunnel_key = - KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); - ASSERT_TRUE( - p4_oid_mapper_.increaseRefCount(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key)); + const auto gre_tunnel_key = KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); + ASSERT_TRUE(p4_oid_mapper_.increaseRefCount(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key)); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessDeleteRequest(gre_tunnel_key)); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessDeleteRequest(gre_tunnel_key)); - // Validate the gre tunnel entry is not deleted in either P4 gre tunnel - // manager or central mapper. - p4_tunnel_entry = GetGreTunnelEntry(gre_tunnel_key); - ASSERT_NE(p4_tunnel_entry, nullptr); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key, 1)); + // Validate the gre tunnel entry is not deleted in either P4 gre tunnel + // manager or central mapper. + p4_tunnel_entry = GetGreTunnelEntry(gre_tunnel_key); + ASSERT_NE(p4_tunnel_entry, nullptr); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key, 1)); } -TEST_F(GreTunnelManagerTest, - ProcessDeleteRequestShouldFailIfTunnelSaiCallFails) { - auto* p4_tunnel_entry = AddGreTunnelEntry1(); - ASSERT_NE(p4_tunnel_entry, nullptr); +TEST_F(GreTunnelManagerTest, ProcessDeleteRequestShouldFailIfTunnelSaiCallFails) +{ + auto *p4_tunnel_entry = AddGreTunnelEntry1(); + ASSERT_NE(p4_tunnel_entry, nullptr); - const auto gre_tunnel_key = - KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); + const auto gre_tunnel_key = KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); - // Set up mock call. - EXPECT_CALL(mock_sai_tunnel_, remove_tunnel(Eq(p4_tunnel_entry->tunnel_oid))) - .WillOnce(Return(SAI_STATUS_FAILURE)); + // Set up mock call. + EXPECT_CALL(mock_sai_tunnel_, remove_tunnel(Eq(p4_tunnel_entry->tunnel_oid))).WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessDeleteRequest(gre_tunnel_key)); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessDeleteRequest(gre_tunnel_key)); - // Validate the gre tunnel entry is not deleted in either P4 gre tunnel - // manager or central mapper. - p4_tunnel_entry = GetGreTunnelEntry(gre_tunnel_key); - ASSERT_NE(p4_tunnel_entry, nullptr); - EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key)); + // Validate the gre tunnel entry is not deleted in either P4 gre tunnel + // manager or central mapper. + p4_tunnel_entry = GetGreTunnelEntry(gre_tunnel_key); + ASSERT_NE(p4_tunnel_entry, nullptr); + EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key)); } -TEST_F(GreTunnelManagerTest, ProcessDeleteRequestShouldFailIfRifSaiCallFails) { - auto* p4_tunnel_entry = AddGreTunnelEntry1(); - ASSERT_NE(p4_tunnel_entry, nullptr); - - const auto gre_tunnel_key = - KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); - - // Set up mock call. - EXPECT_CALL(mock_sai_tunnel_, remove_tunnel(Eq(p4_tunnel_entry->tunnel_oid))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_router_intf_, - remove_router_interface(Eq(kOverlayRifOid1))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL( - mock_sai_tunnel_, - create_tunnel(::testing::NotNull(), Eq(gSwitchId), Eq(6), - Truly(std::bind( - MatchCreateGreTunnelArgAttrList, std::placeholders::_1, - CreateAttributeListForGreTunnelObject( - kP4GreTunnelAppDbEntry1, kRouterInterfaceOid1))))) - .WillOnce( - DoAll(SetArgPointee<0>(kGreTunnelOid1), Return(SAI_STATUS_SUCCESS))); - - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessDeleteRequest(gre_tunnel_key)); - - // Validate the gre tunnel entry is not deleted in either P4 gre tunnel - // manager or central mapper. - p4_tunnel_entry = GetGreTunnelEntry(gre_tunnel_key); - ASSERT_NE(p4_tunnel_entry, nullptr); - EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key)); +TEST_F(GreTunnelManagerTest, ProcessDeleteRequestShouldFailIfRifSaiCallFails) +{ + auto *p4_tunnel_entry = AddGreTunnelEntry1(); + ASSERT_NE(p4_tunnel_entry, nullptr); + + const auto gre_tunnel_key = KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); + + // Set up mock call. + EXPECT_CALL(mock_sai_tunnel_, remove_tunnel(Eq(p4_tunnel_entry->tunnel_oid))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_router_intf_, remove_router_interface(Eq(kOverlayRifOid1))) + .WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_tunnel_, create_tunnel(::testing::NotNull(), Eq(gSwitchId), Eq(6), + Truly(std::bind(MatchCreateGreTunnelArgAttrList, std::placeholders::_1, + CreateAttributeListForGreTunnelObject( + kP4GreTunnelAppDbEntry1, kRouterInterfaceOid1))))) + .WillOnce(DoAll(SetArgPointee<0>(kGreTunnelOid1), Return(SAI_STATUS_SUCCESS))); + + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessDeleteRequest(gre_tunnel_key)); + + // Validate the gre tunnel entry is not deleted in either P4 gre tunnel + // manager or central mapper. + p4_tunnel_entry = GetGreTunnelEntry(gre_tunnel_key); + ASSERT_NE(p4_tunnel_entry, nullptr); + EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key)); } -TEST_F(GreTunnelManagerTest, - ProcessDeleteRequestShouldRaiseCriticalIfRecoverySaiCallFails) { - auto* p4_tunnel_entry = AddGreTunnelEntry1(); - ASSERT_NE(p4_tunnel_entry, nullptr); - - const auto gre_tunnel_key = - KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); - - // Set up mock call. - EXPECT_CALL(mock_sai_tunnel_, remove_tunnel(Eq(p4_tunnel_entry->tunnel_oid))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_router_intf_, - remove_router_interface(Eq(kOverlayRifOid1))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_CALL( - mock_sai_tunnel_, - create_tunnel(::testing::NotNull(), Eq(gSwitchId), Eq(6), - Truly(std::bind( - MatchCreateGreTunnelArgAttrList, std::placeholders::_1, - CreateAttributeListForGreTunnelObject( - kP4GreTunnelAppDbEntry1, kRouterInterfaceOid1))))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - - // TODO: Expect critical state. - - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessDeleteRequest(gre_tunnel_key)); - - // Validate the gre tunnel entry is not deleted in either P4 gre tunnel - // manager or central mapper. - p4_tunnel_entry = GetGreTunnelEntry(gre_tunnel_key); - ASSERT_NE(p4_tunnel_entry, nullptr); - EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key)); +TEST_F(GreTunnelManagerTest, ProcessDeleteRequestShouldRaiseCriticalIfRecoverySaiCallFails) +{ + auto *p4_tunnel_entry = AddGreTunnelEntry1(); + ASSERT_NE(p4_tunnel_entry, nullptr); + + const auto gre_tunnel_key = KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); + + // Set up mock call. + EXPECT_CALL(mock_sai_tunnel_, remove_tunnel(Eq(p4_tunnel_entry->tunnel_oid))).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_router_intf_, remove_router_interface(Eq(kOverlayRifOid1))) + .WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_tunnel_, create_tunnel(::testing::NotNull(), Eq(gSwitchId), Eq(6), + Truly(std::bind(MatchCreateGreTunnelArgAttrList, std::placeholders::_1, + CreateAttributeListForGreTunnelObject( + kP4GreTunnelAppDbEntry1, kRouterInterfaceOid1))))) + .WillOnce(Return(SAI_STATUS_FAILURE)); + + // TODO: Expect critical state. + + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessDeleteRequest(gre_tunnel_key)); + + // Validate the gre tunnel entry is not deleted in either P4 gre tunnel + // manager or central mapper. + p4_tunnel_entry = GetGreTunnelEntry(gre_tunnel_key); + ASSERT_NE(p4_tunnel_entry, nullptr); + EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key)); } -TEST_F(GreTunnelManagerTest, - GetGreTunnelEntryShouldReturnNullPointerForNonexistingGreTunnel) { - const auto gre_tunnel_key = - KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); - EXPECT_EQ(GetGreTunnelEntry(gre_tunnel_key), nullptr); +TEST_F(GreTunnelManagerTest, GetGreTunnelEntryShouldReturnNullPointerForNonexistingGreTunnel) +{ + const auto gre_tunnel_key = KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); + EXPECT_EQ(GetGreTunnelEntry(gre_tunnel_key), nullptr); } -TEST_F(GreTunnelManagerTest, - DeserializeP4GreTunnelAppDbEntryShouldReturnNullPointerForInvalidField) { - std::vector attributes = { - swss::FieldValueTuple(p4orch::kAction, p4orch::kTunnelAction), - swss::FieldValueTuple("UNKNOWN_FIELD", "UNKOWN")}; +TEST_F(GreTunnelManagerTest, DeserializeP4GreTunnelAppDbEntryShouldReturnNullPointerForInvalidField) +{ + std::vector attributes = {swss::FieldValueTuple(p4orch::kAction, p4orch::kTunnelAction), + swss::FieldValueTuple("UNKNOWN_FIELD", "UNKOWN")}; - EXPECT_FALSE( - DeserializeP4GreTunnelAppDbEntry(kGreTunnelP4AppDbKey1, attributes).ok()); + EXPECT_FALSE(DeserializeP4GreTunnelAppDbEntry(kGreTunnelP4AppDbKey1, attributes).ok()); } -TEST_F(GreTunnelManagerTest, - DeserializeP4GreTunnelAppDbEntryShouldReturnNullPointerForInvalidIP) { - std::vector attributes = { - swss::FieldValueTuple(p4orch::kAction, p4orch::kTunnelAction), - swss::FieldValueTuple(prependParamField(p4orch::kRouterInterfaceId), - kRouterInterfaceId1), - swss::FieldValueTuple(prependParamField(p4orch::kEncapSrcIp), "1.2.3.4"), - swss::FieldValueTuple(prependParamField(p4orch::kEncapDstIp), "2.3.4.5")}; - EXPECT_TRUE( - DeserializeP4GreTunnelAppDbEntry(kGreTunnelP4AppDbKey1, attributes).ok()); - attributes = { - swss::FieldValueTuple(p4orch::kAction, p4orch::kTunnelAction), - swss::FieldValueTuple(prependParamField(p4orch::kRouterInterfaceId), - kRouterInterfaceId1), - swss::FieldValueTuple(prependParamField(p4orch::kEncapSrcIp), "1:2:3:4"), - swss::FieldValueTuple(prependParamField(p4orch::kEncapDstIp), "1.2.3.5")}; - EXPECT_FALSE( - DeserializeP4GreTunnelAppDbEntry(kGreTunnelP4AppDbKey1, attributes).ok()); - attributes = { - swss::FieldValueTuple(p4orch::kAction, p4orch::kTunnelAction), - swss::FieldValueTuple(prependParamField(p4orch::kRouterInterfaceId), - kRouterInterfaceId1), - swss::FieldValueTuple(prependParamField(p4orch::kEncapSrcIp), "1.2.3.4"), - swss::FieldValueTuple(prependParamField(p4orch::kEncapDstIp), "1:2:3:5")}; - EXPECT_FALSE( - DeserializeP4GreTunnelAppDbEntry(kGreTunnelP4AppDbKey1, attributes).ok()); +TEST_F(GreTunnelManagerTest, DeserializeP4GreTunnelAppDbEntryShouldReturnNullPointerForInvalidIP) +{ + std::vector attributes = { + swss::FieldValueTuple(p4orch::kAction, p4orch::kTunnelAction), + swss::FieldValueTuple(prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId1), + swss::FieldValueTuple(prependParamField(p4orch::kEncapSrcIp), "1.2.3.4"), + swss::FieldValueTuple(prependParamField(p4orch::kEncapDstIp), "2.3.4.5")}; + EXPECT_TRUE(DeserializeP4GreTunnelAppDbEntry(kGreTunnelP4AppDbKey1, attributes).ok()); + attributes = {swss::FieldValueTuple(p4orch::kAction, p4orch::kTunnelAction), + swss::FieldValueTuple(prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId1), + swss::FieldValueTuple(prependParamField(p4orch::kEncapSrcIp), "1:2:3:4"), + swss::FieldValueTuple(prependParamField(p4orch::kEncapDstIp), "1.2.3.5")}; + EXPECT_FALSE(DeserializeP4GreTunnelAppDbEntry(kGreTunnelP4AppDbKey1, attributes).ok()); + attributes = {swss::FieldValueTuple(p4orch::kAction, p4orch::kTunnelAction), + swss::FieldValueTuple(prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId1), + swss::FieldValueTuple(prependParamField(p4orch::kEncapSrcIp), "1.2.3.4"), + swss::FieldValueTuple(prependParamField(p4orch::kEncapDstIp), "1:2:3:5")}; + EXPECT_FALSE(DeserializeP4GreTunnelAppDbEntry(kGreTunnelP4AppDbKey1, attributes).ok()); } -TEST_F(GreTunnelManagerTest, - DeserializeP4GreTunnelAppDbEntryShouldReturnNullPointerForInvalidKey) { - std::vector attributes = { - {p4orch::kAction, p4orch::kTunnelAction}, - {prependParamField(p4orch::kRouterInterfaceId), - kP4GreTunnelAppDbEntry1.router_interface_id}, - {prependParamField(p4orch::kEncapSrcIp), - kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}, - {prependParamField(p4orch::kEncapDstIp), - kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}}; - constexpr char* kInvalidAppDbKey = R"({"tunnel_id":1})"; - EXPECT_FALSE( - DeserializeP4GreTunnelAppDbEntry(kInvalidAppDbKey, attributes).ok()); +TEST_F(GreTunnelManagerTest, DeserializeP4GreTunnelAppDbEntryShouldReturnNullPointerForInvalidKey) +{ + std::vector attributes = { + {p4orch::kAction, p4orch::kTunnelAction}, + {prependParamField(p4orch::kRouterInterfaceId), kP4GreTunnelAppDbEntry1.router_interface_id}, + {prependParamField(p4orch::kEncapSrcIp), kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}, + {prependParamField(p4orch::kEncapDstIp), kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}}; + constexpr char *kInvalidAppDbKey = R"({"tunnel_id":1})"; + EXPECT_FALSE(DeserializeP4GreTunnelAppDbEntry(kInvalidAppDbKey, attributes).ok()); } -TEST_F(GreTunnelManagerTest, DrainDuplicateSetRequestShouldSucceed) { - auto* p4_tunnel_entry = AddGreTunnelEntry1(); - ASSERT_NE(p4_tunnel_entry, nullptr); +TEST_F(GreTunnelManagerTest, DrainDuplicateSetRequestShouldSucceed) +{ + auto *p4_tunnel_entry = AddGreTunnelEntry1(); + ASSERT_NE(p4_tunnel_entry, nullptr); - nlohmann::json j; - j[prependMatchField(p4orch::kTunnelId)] = kP4GreTunnelAppDbEntry1.tunnel_id; + nlohmann::json j; + j[prependMatchField(p4orch::kTunnelId)] = kP4GreTunnelAppDbEntry1.tunnel_id; - std::vector fvs{ - {p4orch::kAction, p4orch::kTunnelAction}, - {prependParamField(p4orch::kRouterInterfaceId), - kP4GreTunnelAppDbEntry1.router_interface_id}, - {prependParamField(p4orch::kEncapSrcIp), - kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}, - {prependParamField(p4orch::kEncapDstIp), - kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}}; + std::vector fvs{ + {p4orch::kAction, p4orch::kTunnelAction}, + {prependParamField(p4orch::kRouterInterfaceId), kP4GreTunnelAppDbEntry1.router_interface_id}, + {prependParamField(p4orch::kEncapSrcIp), kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}, + {prependParamField(p4orch::kEncapDstIp), kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}}; - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs); + swss::KeyOpFieldsValuesTuple app_db_entry(std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), + SET_COMMAND, fvs); - Enqueue(app_db_entry); - Drain(); + Enqueue(app_db_entry); + Drain(); - // Expect that the update call will fail, so gre tunnel entry's fields stay - // the same. - EXPECT_TRUE(ValidateGreTunnelEntryAdd(kP4GreTunnelAppDbEntry1)); + // Expect that the update call will fail, so gre tunnel entry's fields stay + // the same. + EXPECT_TRUE(ValidateGreTunnelEntryAdd(kP4GreTunnelAppDbEntry1)); } -TEST_F(GreTunnelManagerTest, - DrainDeleteRequestShouldSucceedForExistingGreTunnel) { - auto* p4_tunnel_entry = AddGreTunnelEntry1(); - ASSERT_NE(p4_tunnel_entry, nullptr); - EXPECT_EQ(p4_tunnel_entry->tunnel_oid, kGreTunnelOid1); - - nlohmann::json j; - j[prependMatchField(p4orch::kTunnelId)] = kP4GreTunnelAppDbEntry1.tunnel_id; - - std::vector fvs; - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - DEL_COMMAND, fvs); - EXPECT_CALL(mock_sai_router_intf_, - remove_router_interface(Eq(kOverlayRifOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_tunnel_, remove_tunnel(Eq(p4_tunnel_entry->tunnel_oid))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - Enqueue(app_db_entry); - Drain(); - - // Validate the gre tunnel entry has been deleted in both P4 gre tunnel - // manager and centralized mapper. - const auto gre_tunnel_key = - KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); - p4_tunnel_entry = GetGreTunnelEntry(gre_tunnel_key); - EXPECT_EQ(p4_tunnel_entry, nullptr); - EXPECT_FALSE( - p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key)); +TEST_F(GreTunnelManagerTest, DrainDeleteRequestShouldSucceedForExistingGreTunnel) +{ + auto *p4_tunnel_entry = AddGreTunnelEntry1(); + ASSERT_NE(p4_tunnel_entry, nullptr); + EXPECT_EQ(p4_tunnel_entry->tunnel_oid, kGreTunnelOid1); + + nlohmann::json j; + j[prependMatchField(p4orch::kTunnelId)] = kP4GreTunnelAppDbEntry1.tunnel_id; + + std::vector fvs; + swss::KeyOpFieldsValuesTuple app_db_entry(std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), + DEL_COMMAND, fvs); + EXPECT_CALL(mock_sai_router_intf_, remove_router_interface(Eq(kOverlayRifOid1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_tunnel_, remove_tunnel(Eq(p4_tunnel_entry->tunnel_oid))).WillOnce(Return(SAI_STATUS_SUCCESS)); + + Enqueue(app_db_entry); + Drain(); + + // Validate the gre tunnel entry has been deleted in both P4 gre tunnel + // manager and centralized mapper. + const auto gre_tunnel_key = KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); + p4_tunnel_entry = GetGreTunnelEntry(gre_tunnel_key); + EXPECT_EQ(p4_tunnel_entry, nullptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key)); } -TEST_F(GreTunnelManagerTest, DrainValidAppEntryShouldSucceed) { - nlohmann::json j; - j[prependMatchField(p4orch::kTunnelId)] = kGreTunnelP4AppDbId1; - EXPECT_TRUE(p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), - kRouterInterfaceOid1)); - - std::vector fvs{ - {p4orch::kAction, p4orch::kTunnelAction}, - {prependParamField(p4orch::kRouterInterfaceId), - kP4GreTunnelAppDbEntry1.router_interface_id}, - {prependParamField(p4orch::kEncapSrcIp), - kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}, - {prependParamField(p4orch::kEncapDstIp), - kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}}; - - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs); - - Enqueue(app_db_entry); - EXPECT_CALL( - mock_sai_router_intf_, - create_router_interface(::testing::NotNull(), Eq(gSwitchId), Eq(2), _)) - .WillOnce( - DoAll(SetArgPointee<0>(kOverlayRifOid1), Return(SAI_STATUS_SUCCESS))); - - EXPECT_CALL(mock_sai_tunnel_, create_tunnel(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kGreTunnelOid1), Return(SAI_STATUS_SUCCESS))); - - Drain(); - - EXPECT_TRUE(ValidateGreTunnelEntryAdd(kP4GreTunnelAppDbEntry1)); +TEST_F(GreTunnelManagerTest, DrainValidAppEntryShouldSucceed) +{ + nlohmann::json j; + j[prependMatchField(p4orch::kTunnelId)] = kGreTunnelP4AppDbId1; + EXPECT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), + kRouterInterfaceOid1)); + + std::vector fvs{ + {p4orch::kAction, p4orch::kTunnelAction}, + {prependParamField(p4orch::kRouterInterfaceId), kP4GreTunnelAppDbEntry1.router_interface_id}, + {prependParamField(p4orch::kEncapSrcIp), kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}, + {prependParamField(p4orch::kEncapDstIp), kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}}; + + swss::KeyOpFieldsValuesTuple app_db_entry(std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), + SET_COMMAND, fvs); + + Enqueue(app_db_entry); + EXPECT_CALL(mock_sai_router_intf_, create_router_interface(::testing::NotNull(), Eq(gSwitchId), Eq(2), _)) + .WillOnce(DoAll(SetArgPointee<0>(kOverlayRifOid1), Return(SAI_STATUS_SUCCESS))); + + EXPECT_CALL(mock_sai_tunnel_, create_tunnel(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kGreTunnelOid1), Return(SAI_STATUS_SUCCESS))); + + Drain(); + + EXPECT_TRUE(ValidateGreTunnelEntryAdd(kP4GreTunnelAppDbEntry1)); } -TEST_F(GreTunnelManagerTest, DrainInvalidAppEntryShouldFail) { - nlohmann::json j; - j[prependMatchField(p4orch::kTunnelId)] = kGreTunnelP4AppDbId1; - j[p4orch::kTunnelId] = 1000; - - std::vector fvs{ - {p4orch::kAction, p4orch::kTunnelAction}, - {prependParamField(p4orch::kRouterInterfaceId), - kP4GreTunnelAppDbEntry1.router_interface_id}, - {prependParamField(p4orch::kEncapSrcIp), "1"}, - {prependParamField(p4orch::kEncapDstIp), - kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}}; - - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs); - - Enqueue(app_db_entry); - - Drain(); - EXPECT_EQ(GetGreTunnelEntry(kGreTunnelP4AppDbKey1), nullptr); - EXPECT_FALSE( - p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, kGreTunnelP4AppDbKey1)); - - // Invalid action_str - fvs = {{p4orch::kAction, "set_nexthop"}, - {prependParamField(p4orch::kRouterInterfaceId), - kP4GreTunnelAppDbEntry1.router_interface_id}, - {prependParamField(p4orch::kEncapSrcIp), - kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}, - {prependParamField(p4orch::kEncapDstIp), - kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}}; - - app_db_entry = { - std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs}; - - Enqueue(app_db_entry); - - Drain(); - EXPECT_EQ(GetGreTunnelEntry(kGreTunnelP4AppDbKey1), nullptr); - EXPECT_FALSE( - p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, kGreTunnelP4AppDbKey1)); - - // Miss action - fvs = {{prependParamField(p4orch::kRouterInterfaceId), - kP4GreTunnelAppDbEntry1.router_interface_id}, - {prependParamField(p4orch::kEncapSrcIp), - kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}, - {prependParamField(p4orch::kEncapDstIp), - kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}}; - - app_db_entry = { - std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs}; - - Enqueue(app_db_entry); - - Drain(); - EXPECT_EQ(GetGreTunnelEntry(kGreTunnelP4AppDbKey1), nullptr); - EXPECT_FALSE( - p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, kGreTunnelP4AppDbKey1)); - - // Miss router_interface_id - fvs = {{p4orch::kAction, p4orch::kTunnelAction}, - {prependParamField(p4orch::kEncapSrcIp), - kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}, - {prependParamField(p4orch::kEncapDstIp), - kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}}; - - app_db_entry = { - std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs}; - - Enqueue(app_db_entry); - - Drain(); - EXPECT_EQ(GetGreTunnelEntry(kGreTunnelP4AppDbKey1), nullptr); - EXPECT_FALSE( - p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, kGreTunnelP4AppDbKey1)); - - // Miss encap_src_ip - fvs = {{p4orch::kAction, p4orch::kTunnelAction}, - {prependParamField(p4orch::kRouterInterfaceId), - kP4GreTunnelAppDbEntry1.router_interface_id}, - {prependParamField(p4orch::kEncapDstIp), - kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}}; - - app_db_entry = { - std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs}; - - Enqueue(app_db_entry); - - Drain(); - EXPECT_EQ(GetGreTunnelEntry(kGreTunnelP4AppDbKey1), nullptr); - EXPECT_FALSE( - p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, kGreTunnelP4AppDbKey1)); - - // Miss encap_dst_ip - fvs = {{p4orch::kAction, p4orch::kTunnelAction}, - {prependParamField(p4orch::kRouterInterfaceId), - kP4GreTunnelAppDbEntry1.router_interface_id}, - {prependParamField(p4orch::kEncapSrcIp), - kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}}; - - app_db_entry = { - std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs}; - - Enqueue(app_db_entry); - - Drain(); - EXPECT_EQ(GetGreTunnelEntry(kGreTunnelP4AppDbKey1), nullptr); - EXPECT_FALSE( - p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, kGreTunnelP4AppDbKey1)); +TEST_F(GreTunnelManagerTest, DrainInvalidAppEntryShouldFail) +{ + nlohmann::json j; + j[prependMatchField(p4orch::kTunnelId)] = kGreTunnelP4AppDbId1; + j[p4orch::kTunnelId] = 1000; + + std::vector fvs{ + {p4orch::kAction, p4orch::kTunnelAction}, + {prependParamField(p4orch::kRouterInterfaceId), kP4GreTunnelAppDbEntry1.router_interface_id}, + {prependParamField(p4orch::kEncapSrcIp), "1"}, + {prependParamField(p4orch::kEncapDstIp), kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}}; + + swss::KeyOpFieldsValuesTuple app_db_entry(std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), + SET_COMMAND, fvs); + + Enqueue(app_db_entry); + + Drain(); + EXPECT_EQ(GetGreTunnelEntry(kGreTunnelP4AppDbKey1), nullptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, kGreTunnelP4AppDbKey1)); + + // Invalid action_str + fvs = {{p4orch::kAction, "set_nexthop"}, + {prependParamField(p4orch::kRouterInterfaceId), kP4GreTunnelAppDbEntry1.router_interface_id}, + {prependParamField(p4orch::kEncapSrcIp), kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}, + {prependParamField(p4orch::kEncapDstIp), kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}}; + + app_db_entry = {std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs}; + + Enqueue(app_db_entry); + + Drain(); + EXPECT_EQ(GetGreTunnelEntry(kGreTunnelP4AppDbKey1), nullptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, kGreTunnelP4AppDbKey1)); + + // Miss action + fvs = {{prependParamField(p4orch::kRouterInterfaceId), kP4GreTunnelAppDbEntry1.router_interface_id}, + {prependParamField(p4orch::kEncapSrcIp), kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}, + {prependParamField(p4orch::kEncapDstIp), kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}}; + + app_db_entry = {std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs}; + + Enqueue(app_db_entry); + + Drain(); + EXPECT_EQ(GetGreTunnelEntry(kGreTunnelP4AppDbKey1), nullptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, kGreTunnelP4AppDbKey1)); + + // Miss router_interface_id + fvs = {{p4orch::kAction, p4orch::kTunnelAction}, + {prependParamField(p4orch::kEncapSrcIp), kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}, + {prependParamField(p4orch::kEncapDstIp), kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}}; + + app_db_entry = {std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs}; + + Enqueue(app_db_entry); + + Drain(); + EXPECT_EQ(GetGreTunnelEntry(kGreTunnelP4AppDbKey1), nullptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, kGreTunnelP4AppDbKey1)); + + // Miss encap_src_ip + fvs = {{p4orch::kAction, p4orch::kTunnelAction}, + {prependParamField(p4orch::kRouterInterfaceId), kP4GreTunnelAppDbEntry1.router_interface_id}, + {prependParamField(p4orch::kEncapDstIp), kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}}; + + app_db_entry = {std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs}; + + Enqueue(app_db_entry); + + Drain(); + EXPECT_EQ(GetGreTunnelEntry(kGreTunnelP4AppDbKey1), nullptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, kGreTunnelP4AppDbKey1)); + + // Miss encap_dst_ip + fvs = {{p4orch::kAction, p4orch::kTunnelAction}, + {prependParamField(p4orch::kRouterInterfaceId), kP4GreTunnelAppDbEntry1.router_interface_id}, + {prependParamField(p4orch::kEncapSrcIp), kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}}; + + app_db_entry = {std::string(APP_P4RT_TUNNEL_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs}; + + Enqueue(app_db_entry); + + Drain(); + EXPECT_EQ(GetGreTunnelEntry(kGreTunnelP4AppDbKey1), nullptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_TUNNEL, kGreTunnelP4AppDbKey1)); } -TEST_F(GreTunnelManagerTest, VerifyStateTest) { - auto* p4_tunnel_entry = AddGreTunnelEntry1(); - ASSERT_NE(p4_tunnel_entry, nullptr); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set("SAI_OBJECT_TYPE_TUNNEL:oid:0x11", - std::vector{ - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_TYPE", - "SAI_TUNNEL_TYPE_IPINIP_GRE"}, - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_PEER_MODE", - "SAI_TUNNEL_PEER_MODE_P2P"}, - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_ENCAP_SRC_IP", - "2607:f8b0:8096:3110::1"}, - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_ENCAP_DST_IP", - "2607:f8b0:8096:311a::2"}, - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE", - "oid:0x1"}, - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_OVERLAY_INTERFACE", - "oid:0x101"}}); - - // Overlay router interface - table.set("SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x101", - std::vector{ - swss::FieldValueTuple{ - "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", "oid:0x0"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_TYPE", - "SAI_ROUTER_INTERFACE_TYPE_LOOPBACK"}}); - - // Underlay router interface - table.set( - "SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x1", - std::vector{ - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", - "oid:0x0"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS", - "00:01:02:03:04:05"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_TYPE", - "SAI_ROUTER_INTERFACE_TYPE_PORT"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_PORT_ID", - "oid:0x1234"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_MTU", "9100"}}); - - nlohmann::json j; - j[prependMatchField(p4orch::kTunnelId)] = kGreTunnelP4AppDbId1; - const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + APP_P4RT_TUNNEL_TABLE_NAME + - kTableKeyDelimiter + j.dump(); - std::vector attributes; - - // Verification should succeed with vaild key and value. - attributes.push_back( - swss::FieldValueTuple{p4orch::kAction, p4orch::kTunnelAction}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kRouterInterfaceId), - kP4GreTunnelAppDbEntry1.router_interface_id}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kEncapSrcIp), - kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kEncapDstIp), - kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}); - EXPECT_EQ(VerifyState(db_key, attributes), ""); - - // Invalid key should fail verification. - EXPECT_FALSE(VerifyState("invalid", attributes).empty()); - EXPECT_FALSE(VerifyState("invalid:invalid", attributes).empty()); - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes) - .empty()); - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", - attributes) - .empty()); - EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + - ":FIXED_TUNNEL_TABLE:invalid", - attributes) - .empty()); - - // Verification should fail if entry does not exist. - j[prependMatchField(p4orch::kTunnelId)] = "invalid"; - EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + APP_P4RT_TUNNEL_TABLE_NAME + - kTableKeyDelimiter + j.dump(), - attributes) - .empty()); - - // Verification should fail if router interface name mismatches. - auto saved_router_interface_id = p4_tunnel_entry->router_interface_id; - p4_tunnel_entry->router_interface_id = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_tunnel_entry->router_interface_id = saved_router_interface_id; - - // Verification should fail if tunnel key mismatches. - auto saved_tunnel_key = p4_tunnel_entry->tunnel_key; - p4_tunnel_entry->tunnel_key = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_tunnel_entry->tunnel_key = saved_tunnel_key; - - // Verification should fail if IP mismatches. - auto saved_SRC_IP = p4_tunnel_entry->encap_src_ip; - p4_tunnel_entry->encap_src_ip = swss::IpAddress("1.1.1.1"); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_tunnel_entry->encap_src_ip = saved_SRC_IP; - - // Verification should fail if IP mask mismatches. - auto saved_DST_IP = p4_tunnel_entry->encap_dst_ip; - p4_tunnel_entry->encap_dst_ip = swss::IpAddress("2.2.2.2"); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_tunnel_entry->encap_dst_ip = saved_DST_IP; - - // Verification should fail if IP mask mismatches. - auto saved_NEIGHBOR_ID = p4_tunnel_entry->neighbor_id; - p4_tunnel_entry->neighbor_id = swss::IpAddress("2.2.2.2"); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_tunnel_entry->neighbor_id = saved_NEIGHBOR_ID; - - // Verification should fail if tunnel_id mismatches. - auto saved_tunnel_id = p4_tunnel_entry->tunnel_id; - p4_tunnel_entry->tunnel_id = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_tunnel_entry->tunnel_id = saved_tunnel_id; - - // Verification should fail if OID mapper mismatches. - const auto gre_tunnel_key = - KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); - p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key, kGreTunnelOid1); +TEST_F(GreTunnelManagerTest, VerifyStateTest) +{ + auto *p4_tunnel_entry = AddGreTunnelEntry1(); + ASSERT_NE(p4_tunnel_entry, nullptr); + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set("SAI_OBJECT_TYPE_TUNNEL:oid:0x11", + std::vector{ + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_TYPE", "SAI_TUNNEL_TYPE_IPINIP_GRE"}, + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_PEER_MODE", "SAI_TUNNEL_PEER_MODE_P2P"}, + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_ENCAP_SRC_IP", "2607:f8b0:8096:3110::1"}, + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_ENCAP_DST_IP", "2607:f8b0:8096:311a::2"}, + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE", "oid:0x1"}, + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_OVERLAY_INTERFACE", "oid:0x101"}}); + + // Overlay router interface + table.set("SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x101", + std::vector{ + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", "oid:0x0"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_TYPE", "SAI_ROUTER_INTERFACE_TYPE_LOOPBACK"}}); + + // Underlay router interface + table.set("SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x1", + std::vector{ + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", "oid:0x0"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS", "00:01:02:03:04:05"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_TYPE", "SAI_ROUTER_INTERFACE_TYPE_PORT"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_PORT_ID", "oid:0x1234"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_MTU", "9100"}}); + + nlohmann::json j; + j[prependMatchField(p4orch::kTunnelId)] = kGreTunnelP4AppDbId1; + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_TUNNEL_TABLE_NAME + + kTableKeyDelimiter + j.dump(); + std::vector attributes; + + // Verification should succeed with vaild key and value. + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kTunnelAction}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kRouterInterfaceId), + kP4GreTunnelAppDbEntry1.router_interface_id}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kEncapSrcIp), + kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kEncapDstIp), + kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}); + EXPECT_EQ(VerifyState(db_key, attributes), ""); + + // Invalid key should fail verification. + EXPECT_FALSE(VerifyState("invalid", attributes).empty()); + EXPECT_FALSE(VerifyState("invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":FIXED_TUNNEL_TABLE:invalid", attributes).empty()); + + // Verification should fail if entry does not exist. + j[prependMatchField(p4orch::kTunnelId)] = "invalid"; + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_TUNNEL_TABLE_NAME + + kTableKeyDelimiter + j.dump(), + attributes) + .empty()); + + // Verification should fail if router interface name mismatches. + auto saved_router_interface_id = p4_tunnel_entry->router_interface_id; + p4_tunnel_entry->router_interface_id = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_tunnel_entry->router_interface_id = saved_router_interface_id; + + // Verification should fail if tunnel key mismatches. + auto saved_tunnel_key = p4_tunnel_entry->tunnel_key; + p4_tunnel_entry->tunnel_key = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_tunnel_entry->tunnel_key = saved_tunnel_key; + + // Verification should fail if IP mismatches. + auto saved_SRC_IP = p4_tunnel_entry->encap_src_ip; + p4_tunnel_entry->encap_src_ip = swss::IpAddress("1.1.1.1"); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_tunnel_entry->encap_src_ip = saved_SRC_IP; + + // Verification should fail if IP mask mismatches. + auto saved_DST_IP = p4_tunnel_entry->encap_dst_ip; + p4_tunnel_entry->encap_dst_ip = swss::IpAddress("2.2.2.2"); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_tunnel_entry->encap_dst_ip = saved_DST_IP; + + // Verification should fail if IP mask mismatches. + auto saved_NEIGHBOR_ID = p4_tunnel_entry->neighbor_id; + p4_tunnel_entry->neighbor_id = swss::IpAddress("2.2.2.2"); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_tunnel_entry->neighbor_id = saved_NEIGHBOR_ID; + + // Verification should fail if tunnel_id mismatches. + auto saved_tunnel_id = p4_tunnel_entry->tunnel_id; + p4_tunnel_entry->tunnel_id = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_tunnel_entry->tunnel_id = saved_tunnel_id; + + // Verification should fail if OID mapper mismatches. + const auto gre_tunnel_key = KeyGenerator::generateTunnelKey(kP4GreTunnelAppDbEntry1.tunnel_id); + p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_TUNNEL, gre_tunnel_key, kGreTunnelOid1); } -TEST_F(GreTunnelManagerTest, VerifyStateAsicDbTest) { - auto* p4_tunnel_entry = AddGreTunnelEntry1(); - ASSERT_NE(p4_tunnel_entry, nullptr); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set("SAI_OBJECT_TYPE_TUNNEL:oid:0x11", - std::vector{ - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_TYPE", - "SAI_TUNNEL_TYPE_IPINIP_GRE"}, - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_PEER_MODE", - "SAI_TUNNEL_PEER_MODE_P2P"}, - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_ENCAP_SRC_IP", - "2607:f8b0:8096:3110::1"}, - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_ENCAP_DST_IP", - "2607:f8b0:8096:311a::2"}, - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE", - "oid:0x1"}, - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_OVERLAY_INTERFACE", - "oid:0x101"}}); - - // Overlay router interface - table.set("SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x101", - std::vector{ - swss::FieldValueTuple{ - "SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", "oid:0x0"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_TYPE", - "SAI_ROUTER_INTERFACE_TYPE_LOOPBACK"}}); - - // Underlay router interface - table.set( - "SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x1", - std::vector{ - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", - "oid:0x0"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS", - "00:01:02:03:04:05"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_TYPE", - "SAI_ROUTER_INTERFACE_TYPE_PORT"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_PORT_ID", - "oid:0x1234"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_MTU", "9100"}}); - - nlohmann::json j; - j[prependMatchField(p4orch::kTunnelId)] = kGreTunnelP4AppDbId1; - const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + APP_P4RT_TUNNEL_TABLE_NAME + - kTableKeyDelimiter + j.dump(); - std::vector attributes; - - // Verification should succeed with vaild key and value. - attributes.push_back( - swss::FieldValueTuple{p4orch::kAction, p4orch::kTunnelAction}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kRouterInterfaceId), - kP4GreTunnelAppDbEntry1.router_interface_id}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kEncapSrcIp), - kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kEncapDstIp), - kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}); - EXPECT_EQ(VerifyState(db_key, attributes), ""); - - // Verification should fail if ASIC DB values mismatch. - table.set("SAI_OBJECT_TYPE_TUNNEL:oid:0x11", - std::vector{swss::FieldValueTuple{ - "SAI_TUNNEL_ATTR_ENCAP_SRC_IP", "2607:f8b0:8096:3110::3"}}); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - - // Verification should fail if ASIC DB table is missing. - table.del("SAI_OBJECT_TYPE_TUNNEL:oid:0x11"); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - - table.set("SAI_OBJECT_TYPE_TUNNEL:oid:0x11", - std::vector{ - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_TYPE", - "SAI_TUNNEL_TYPE_IPINIP_GRE"}, - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_PEER_MODE", - "SAI_TUNNEL_PEER_MODE_P2P"}, - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_ENCAP_SRC_IP", - "2607:f8b0:8096:3110::1"}, - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_ENCAP_DST_IP", - "2607:f8b0:8096:311a::2"}, - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE", - "oid:0x1"}, - swss::FieldValueTuple{"SAI_TUNNEL_ATTR_OVERLAY_INTERFACE", - "oid:0x101"}}); - - // Verification should fail if SAI attr cannot be constructed. - p4_tunnel_entry->encap_src_ip = swss::IpAddress("1.2.3.4"); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_tunnel_entry->encap_src_ip = swss::IpAddress("2607:f8b0:8096:3110::1"); +TEST_F(GreTunnelManagerTest, VerifyStateAsicDbTest) +{ + auto *p4_tunnel_entry = AddGreTunnelEntry1(); + ASSERT_NE(p4_tunnel_entry, nullptr); + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set("SAI_OBJECT_TYPE_TUNNEL:oid:0x11", + std::vector{ + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_TYPE", "SAI_TUNNEL_TYPE_IPINIP_GRE"}, + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_PEER_MODE", "SAI_TUNNEL_PEER_MODE_P2P"}, + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_ENCAP_SRC_IP", "2607:f8b0:8096:3110::1"}, + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_ENCAP_DST_IP", "2607:f8b0:8096:311a::2"}, + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE", "oid:0x1"}, + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_OVERLAY_INTERFACE", "oid:0x101"}}); + + // Overlay router interface + table.set("SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x101", + std::vector{ + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", "oid:0x0"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_TYPE", "SAI_ROUTER_INTERFACE_TYPE_LOOPBACK"}}); + + // Underlay router interface + table.set("SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x1", + std::vector{ + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", "oid:0x0"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS", "00:01:02:03:04:05"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_TYPE", "SAI_ROUTER_INTERFACE_TYPE_PORT"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_PORT_ID", "oid:0x1234"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_MTU", "9100"}}); + + nlohmann::json j; + j[prependMatchField(p4orch::kTunnelId)] = kGreTunnelP4AppDbId1; + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_TUNNEL_TABLE_NAME + + kTableKeyDelimiter + j.dump(); + std::vector attributes; + + // Verification should succeed with vaild key and value. + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kTunnelAction}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kRouterInterfaceId), + kP4GreTunnelAppDbEntry1.router_interface_id}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kEncapSrcIp), + kP4GreTunnelAppDbEntry1.encap_src_ip.to_string()}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kEncapDstIp), + kP4GreTunnelAppDbEntry1.encap_dst_ip.to_string()}); + EXPECT_EQ(VerifyState(db_key, attributes), ""); + + // Verification should fail if ASIC DB values mismatch. + table.set("SAI_OBJECT_TYPE_TUNNEL:oid:0x11", std::vector{swss::FieldValueTuple{ + "SAI_TUNNEL_ATTR_ENCAP_SRC_IP", "2607:f8b0:8096:3110::3"}}); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + + // Verification should fail if ASIC DB table is missing. + table.del("SAI_OBJECT_TYPE_TUNNEL:oid:0x11"); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + + table.set("SAI_OBJECT_TYPE_TUNNEL:oid:0x11", + std::vector{ + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_TYPE", "SAI_TUNNEL_TYPE_IPINIP_GRE"}, + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_PEER_MODE", "SAI_TUNNEL_PEER_MODE_P2P"}, + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_ENCAP_SRC_IP", "2607:f8b0:8096:3110::1"}, + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_ENCAP_DST_IP", "2607:f8b0:8096:311a::2"}, + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_UNDERLAY_INTERFACE", "oid:0x1"}, + swss::FieldValueTuple{"SAI_TUNNEL_ATTR_OVERLAY_INTERFACE", "oid:0x101"}}); + + // Verification should fail if SAI attr cannot be constructed. + p4_tunnel_entry->encap_src_ip = swss::IpAddress("1.2.3.4"); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_tunnel_entry->encap_src_ip = swss::IpAddress("2607:f8b0:8096:3110::1"); } diff --git a/orchagent/p4orch/tests/l3_admit_manager_test.cpp b/orchagent/p4orch/tests/l3_admit_manager_test.cpp index f113dabc886..0fa5cb7ac3e 100644 --- a/orchagent/p4orch/tests/l3_admit_manager_test.cpp +++ b/orchagent/p4orch/tests/l3_admit_manager_test.cpp @@ -14,7 +14,8 @@ #include "p4orch/p4orch_util.h" #include "p4orch_util.h" #include "return_code.h" -extern "C" { +extern "C" +{ #include "sai.h" } @@ -29,680 +30,624 @@ using ::testing::StrictMock; using ::testing::Truly; extern sai_object_id_t gSwitchId; -extern sai_my_mac_api_t* sai_my_mac_api; -extern MockSaiMyMac* mock_sai_my_mac; +extern sai_my_mac_api_t *sai_my_mac_api; +extern MockSaiMyMac *mock_sai_my_mac; -namespace { -constexpr char* kPortName1 = "Ethernet1"; +namespace +{ +constexpr char *kPortName1 = "Ethernet1"; constexpr sai_object_id_t kPortOid1 = 0x112233; constexpr uint32_t kMtu1 = 1500; -constexpr char* kPortName2 = "Ethernet2"; +constexpr char *kPortName2 = "Ethernet2"; constexpr sai_object_id_t kPortOid2 = 0x1fed3; constexpr uint32_t kMtu2 = 4500; -constexpr char* kL3AdmitP4AppDbKey1 = - R"({"match/dst_mac":"00:02:03:04:00:00&ff:ff:ff:ff:00:00","priority":2030})"; +constexpr char *kL3AdmitP4AppDbKey1 = R"({"match/dst_mac":"00:02:03:04:00:00&ff:ff:ff:ff:00:00","priority":2030})"; constexpr sai_object_id_t kL3AdmitOid1 = 0x1; constexpr sai_object_id_t kL3AdmitOid2 = 0x2; // APP DB entries for Add request. -const P4L3AdmitAppDbEntry kP4L3AdmitAppDbEntry1{ - /*port_name=*/"", - /*mac_address_data=*/swss::MacAddress("00:02:03:04:00:00"), - /*mac_address_mask=*/swss::MacAddress("ff:ff:ff:ff:00:00"), - /*priority=*/2030}; - -const P4L3AdmitAppDbEntry kP4L3AdmitAppDbEntry2{ - /*port_name=*/kPortName1, - /*mac_address_data=*/swss::MacAddress("00:02:03:04:05:00"), - /*mac_address_mask=*/swss::MacAddress("ff:ff:ff:ff:ff:00"), - /*priority=*/2030}; - -std::unordered_map -CreateAttributeListForL3AdmitObject(const P4L3AdmitAppDbEntry& app_entry, - const sai_object_id_t& port_oid) { - std::unordered_map my_mac_attrs; - sai_attribute_t my_mac_attr; - - my_mac_attr.id = SAI_MY_MAC_ATTR_PRIORITY; - my_mac_attr.value.u32 = app_entry.priority; - my_mac_attrs.insert({my_mac_attr.id, my_mac_attr.value}); - - my_mac_attr.id = SAI_MY_MAC_ATTR_MAC_ADDRESS; - memcpy(my_mac_attr.value.mac, app_entry.mac_address_data.getMac(), - sizeof(sai_mac_t)); - my_mac_attrs.insert({my_mac_attr.id, my_mac_attr.value}); - - my_mac_attr.id = SAI_MY_MAC_ATTR_MAC_ADDRESS_MASK; - memcpy(my_mac_attr.value.mac, app_entry.mac_address_mask.getMac(), - sizeof(sai_mac_t)); - my_mac_attrs.insert({my_mac_attr.id, my_mac_attr.value}); - - if (port_oid != SAI_NULL_OBJECT_ID) { - my_mac_attr.id = SAI_MY_MAC_ATTR_PORT_ID; - my_mac_attr.value.oid = port_oid; +const P4L3AdmitAppDbEntry kP4L3AdmitAppDbEntry1{/*port_name=*/"", + /*mac_address_data=*/swss::MacAddress("00:02:03:04:00:00"), + /*mac_address_mask=*/swss::MacAddress("ff:ff:ff:ff:00:00"), + /*priority=*/2030}; + +const P4L3AdmitAppDbEntry kP4L3AdmitAppDbEntry2{/*port_name=*/kPortName1, + /*mac_address_data=*/swss::MacAddress("00:02:03:04:05:00"), + /*mac_address_mask=*/swss::MacAddress("ff:ff:ff:ff:ff:00"), + /*priority=*/2030}; + +std::unordered_map CreateAttributeListForL3AdmitObject( + const P4L3AdmitAppDbEntry &app_entry, const sai_object_id_t &port_oid) +{ + std::unordered_map my_mac_attrs; + sai_attribute_t my_mac_attr; + + my_mac_attr.id = SAI_MY_MAC_ATTR_PRIORITY; + my_mac_attr.value.u32 = app_entry.priority; my_mac_attrs.insert({my_mac_attr.id, my_mac_attr.value}); - } - return my_mac_attrs; + my_mac_attr.id = SAI_MY_MAC_ATTR_MAC_ADDRESS; + memcpy(my_mac_attr.value.mac, app_entry.mac_address_data.getMac(), sizeof(sai_mac_t)); + my_mac_attrs.insert({my_mac_attr.id, my_mac_attr.value}); + + my_mac_attr.id = SAI_MY_MAC_ATTR_MAC_ADDRESS_MASK; + memcpy(my_mac_attr.value.mac, app_entry.mac_address_mask.getMac(), sizeof(sai_mac_t)); + my_mac_attrs.insert({my_mac_attr.id, my_mac_attr.value}); + + if (port_oid != SAI_NULL_OBJECT_ID) + { + my_mac_attr.id = SAI_MY_MAC_ATTR_PORT_ID; + my_mac_attr.value.oid = port_oid; + my_mac_attrs.insert({my_mac_attr.id, my_mac_attr.value}); + } + + return my_mac_attrs; } // Verifies whether the attribute list is the same as expected. // Returns true if they match; otherwise, false. -bool MatchCreateL3AdmitArgAttrList( - const sai_attribute_t* attr_list, - const std::unordered_map& - expected_attr_list) { - if (attr_list == nullptr) { - return false; - } - - // Sanity check for expected_attr_list. - const auto end = expected_attr_list.end(); - if (expected_attr_list.size() < 3 || - expected_attr_list.find(SAI_MY_MAC_ATTR_PRIORITY) == end || - expected_attr_list.find(SAI_MY_MAC_ATTR_MAC_ADDRESS) == end || - expected_attr_list.find(SAI_MY_MAC_ATTR_MAC_ADDRESS_MASK) == end) { - return false; - } - - size_t valid_attrs_num = 0; - for (size_t i = 0; i < expected_attr_list.size(); ++i) { - switch (attr_list[i].id) { - case SAI_MY_MAC_ATTR_PRIORITY: { - if (attr_list[i].value.u32 != - expected_attr_list.at(SAI_MY_MAC_ATTR_PRIORITY).u32) { - return false; +bool MatchCreateL3AdmitArgAttrList(const sai_attribute_t *attr_list, + const std::unordered_map &expected_attr_list) +{ + if (attr_list == nullptr) + { + return false; + } + + // Sanity check for expected_attr_list. + const auto end = expected_attr_list.end(); + if (expected_attr_list.size() < 3 || expected_attr_list.find(SAI_MY_MAC_ATTR_PRIORITY) == end || + expected_attr_list.find(SAI_MY_MAC_ATTR_MAC_ADDRESS) == end || + expected_attr_list.find(SAI_MY_MAC_ATTR_MAC_ADDRESS_MASK) == end) + { + return false; + } + + size_t valid_attrs_num = 0; + for (size_t i = 0; i < expected_attr_list.size(); ++i) + { + switch (attr_list[i].id) + { + case SAI_MY_MAC_ATTR_PRIORITY: { + if (attr_list[i].value.u32 != expected_attr_list.at(SAI_MY_MAC_ATTR_PRIORITY).u32) + { + return false; + } + valid_attrs_num++; + break; } - valid_attrs_num++; - break; - } - case SAI_MY_MAC_ATTR_MAC_ADDRESS: { - auto macaddr = swss::MacAddress(attr_list[i].value.mac); - auto expected_macaddr = swss::MacAddress( - expected_attr_list.at(SAI_MY_MAC_ATTR_MAC_ADDRESS).mac); - if (macaddr != expected_macaddr) { - return false; + case SAI_MY_MAC_ATTR_MAC_ADDRESS: { + auto macaddr = swss::MacAddress(attr_list[i].value.mac); + auto expected_macaddr = swss::MacAddress(expected_attr_list.at(SAI_MY_MAC_ATTR_MAC_ADDRESS).mac); + if (macaddr != expected_macaddr) + { + return false; + } + valid_attrs_num++; + break; } - valid_attrs_num++; - break; - } - case SAI_MY_MAC_ATTR_MAC_ADDRESS_MASK: { - auto macaddr = swss::MacAddress(attr_list[i].value.mac); - auto expected_macaddr = swss::MacAddress( - expected_attr_list.at(SAI_MY_MAC_ATTR_MAC_ADDRESS_MASK).mac); - if (macaddr != expected_macaddr) { - return false; + case SAI_MY_MAC_ATTR_MAC_ADDRESS_MASK: { + auto macaddr = swss::MacAddress(attr_list[i].value.mac); + auto expected_macaddr = swss::MacAddress(expected_attr_list.at(SAI_MY_MAC_ATTR_MAC_ADDRESS_MASK).mac); + if (macaddr != expected_macaddr) + { + return false; + } + valid_attrs_num++; + break; } - valid_attrs_num++; - break; - } - case SAI_MY_MAC_ATTR_PORT_ID: { - if (expected_attr_list.find(SAI_MY_MAC_ATTR_PORT_ID) == end || - expected_attr_list.at(SAI_MY_MAC_ATTR_PORT_ID).oid != - attr_list[i].value.oid) { - return false; + case SAI_MY_MAC_ATTR_PORT_ID: { + if (expected_attr_list.find(SAI_MY_MAC_ATTR_PORT_ID) == end || + expected_attr_list.at(SAI_MY_MAC_ATTR_PORT_ID).oid != attr_list[i].value.oid) + { + return false; + } + valid_attrs_num++; + break; + } + default: + return false; } - valid_attrs_num++; - break; - } - default: - return false; } - } - if (expected_attr_list.size() != valid_attrs_num) { - return false; - } + if (expected_attr_list.size() != valid_attrs_num) + { + return false; + } - return true; + return true; } -} // namespace - -class L3AdmitManagerTest : public ::testing::Test { - protected: - L3AdmitManagerTest() : l3_admit_manager_(&p4_oid_mapper_, &publisher_) {} - - void SetUp() override { - // Set up mock stuff for SAI l3 admit API structure. - mock_sai_my_mac = &mock_sai_my_mac_; - sai_my_mac_api->create_my_mac = mock_create_my_mac; - sai_my_mac_api->remove_my_mac = mock_remove_my_mac; - } - - void Enqueue(const swss::KeyOpFieldsValuesTuple& entry) { - l3_admit_manager_.enqueue(APP_P4RT_L3_ADMIT_TABLE_NAME, entry); - } - - void Drain() { l3_admit_manager_.drain(); } - - std::string VerifyState(const std::string& key, - const std::vector& tuple) { - return l3_admit_manager_.verifyState(key, tuple); - } - - ReturnCode ProcessAddRequest(const P4L3AdmitAppDbEntry& app_db_entry, - const std::string& l3_admit_key) { - return l3_admit_manager_.processAddRequest(app_db_entry, l3_admit_key); - } - - ReturnCode ProcessDeleteRequest(const std::string& my_mac_key) { - return l3_admit_manager_.processDeleteRequest(my_mac_key); - } - - P4L3AdmitEntry* GetL3AdmitEntry(const std::string& my_mac_key) { - return l3_admit_manager_.getL3AdmitEntry(my_mac_key); - } - - ReturnCodeOr DeserializeP4L3AdmitAppDbEntry( - const std::string& key, - const std::vector& attributes) { - return l3_admit_manager_.deserializeP4L3AdmitAppDbEntry(key, attributes); - } - - // Adds the l3 admit entry -- kP4L3AdmitAppDbEntry1, via l3 admit manager's - // ProcessAddRequest (). This function also takes care of all the dependencies - // of the l3 admit entry. - // Returns a valid pointer to l3 admit entry on success. - P4L3AdmitEntry* AddL3AdmitEntry1(); - - // Validates that a P4 App l3 admit entry is correctly added in l3 admit - // manager and centralized mapper. Returns true on success. - bool ValidateL3AdmitEntryAdd(const P4L3AdmitAppDbEntry& app_db_entry); - - // Return true if the specified the object has the expected number of - // reference. - bool ValidateRefCnt(sai_object_type_t object_type, const std::string& key, - uint32_t expected_ref_count) { - uint32_t ref_count; - if (!p4_oid_mapper_.getRefCount(object_type, key, &ref_count)) return false; - return ref_count == expected_ref_count; - } - - StrictMock mock_sai_my_mac_; - MockResponsePublisher publisher_; - P4OidMapper p4_oid_mapper_; - L3AdmitManager l3_admit_manager_; +} // namespace + +class L3AdmitManagerTest : public ::testing::Test +{ + protected: + L3AdmitManagerTest() : l3_admit_manager_(&p4_oid_mapper_, &publisher_) + { + } + + void SetUp() override + { + // Set up mock stuff for SAI l3 admit API structure. + mock_sai_my_mac = &mock_sai_my_mac_; + sai_my_mac_api->create_my_mac = mock_create_my_mac; + sai_my_mac_api->remove_my_mac = mock_remove_my_mac; + } + + void Enqueue(const swss::KeyOpFieldsValuesTuple &entry) + { + l3_admit_manager_.enqueue(APP_P4RT_L3_ADMIT_TABLE_NAME, entry); + } + + void Drain() + { + l3_admit_manager_.drain(); + } + + std::string VerifyState(const std::string &key, const std::vector &tuple) + { + return l3_admit_manager_.verifyState(key, tuple); + } + + ReturnCode ProcessAddRequest(const P4L3AdmitAppDbEntry &app_db_entry, const std::string &l3_admit_key) + { + return l3_admit_manager_.processAddRequest(app_db_entry, l3_admit_key); + } + + ReturnCode ProcessDeleteRequest(const std::string &my_mac_key) + { + return l3_admit_manager_.processDeleteRequest(my_mac_key); + } + + P4L3AdmitEntry *GetL3AdmitEntry(const std::string &my_mac_key) + { + return l3_admit_manager_.getL3AdmitEntry(my_mac_key); + } + + ReturnCodeOr DeserializeP4L3AdmitAppDbEntry( + const std::string &key, const std::vector &attributes) + { + return l3_admit_manager_.deserializeP4L3AdmitAppDbEntry(key, attributes); + } + + // Adds the l3 admit entry -- kP4L3AdmitAppDbEntry1, via l3 admit manager's + // ProcessAddRequest (). This function also takes care of all the dependencies + // of the l3 admit entry. + // Returns a valid pointer to l3 admit entry on success. + P4L3AdmitEntry *AddL3AdmitEntry1(); + + // Validates that a P4 App l3 admit entry is correctly added in l3 admit + // manager and centralized mapper. Returns true on success. + bool ValidateL3AdmitEntryAdd(const P4L3AdmitAppDbEntry &app_db_entry); + + // Return true if the specified the object has the expected number of + // reference. + bool ValidateRefCnt(sai_object_type_t object_type, const std::string &key, uint32_t expected_ref_count) + { + uint32_t ref_count; + if (!p4_oid_mapper_.getRefCount(object_type, key, &ref_count)) + return false; + return ref_count == expected_ref_count; + } + + StrictMock mock_sai_my_mac_; + MockResponsePublisher publisher_; + P4OidMapper p4_oid_mapper_; + L3AdmitManager l3_admit_manager_; }; -P4L3AdmitEntry* L3AdmitManagerTest::AddL3AdmitEntry1() { - const auto l3admit_key = KeyGenerator::generateL3AdmitKey( - kP4L3AdmitAppDbEntry1.mac_address_data, - kP4L3AdmitAppDbEntry1.mac_address_mask, kP4L3AdmitAppDbEntry1.port_name, - kP4L3AdmitAppDbEntry1.priority); - - // Set up mock call. - EXPECT_CALL( - mock_sai_my_mac_, - create_my_mac( - ::testing::NotNull(), Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchCreateL3AdmitArgAttrList, std::placeholders::_1, - CreateAttributeListForL3AdmitObject( - kP4L3AdmitAppDbEntry1, SAI_NULL_OBJECT_ID))))) - .WillOnce( - DoAll(SetArgPointee<0>(kL3AdmitOid1), Return(SAI_STATUS_SUCCESS))); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRequest(kP4L3AdmitAppDbEntry1, l3admit_key)); - - return GetL3AdmitEntry(l3admit_key); +P4L3AdmitEntry *L3AdmitManagerTest::AddL3AdmitEntry1() +{ + const auto l3admit_key = + KeyGenerator::generateL3AdmitKey(kP4L3AdmitAppDbEntry1.mac_address_data, kP4L3AdmitAppDbEntry1.mac_address_mask, + kP4L3AdmitAppDbEntry1.port_name, kP4L3AdmitAppDbEntry1.priority); + + // Set up mock call. + EXPECT_CALL( + mock_sai_my_mac_, + create_my_mac(::testing::NotNull(), Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchCreateL3AdmitArgAttrList, std::placeholders::_1, + CreateAttributeListForL3AdmitObject(kP4L3AdmitAppDbEntry1, SAI_NULL_OBJECT_ID))))) + .WillOnce(DoAll(SetArgPointee<0>(kL3AdmitOid1), Return(SAI_STATUS_SUCCESS))); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRequest(kP4L3AdmitAppDbEntry1, l3admit_key)); + + return GetL3AdmitEntry(l3admit_key); } -bool L3AdmitManagerTest::ValidateL3AdmitEntryAdd( - const P4L3AdmitAppDbEntry& app_db_entry) { - const auto* p4_l3_admit_entry = - GetL3AdmitEntry(KeyGenerator::generateL3AdmitKey( - app_db_entry.mac_address_data, app_db_entry.mac_address_mask, - app_db_entry.port_name, app_db_entry.priority)); - if (p4_l3_admit_entry == nullptr || - p4_l3_admit_entry->mac_address_data != app_db_entry.mac_address_data || - p4_l3_admit_entry->mac_address_mask != app_db_entry.mac_address_mask || - p4_l3_admit_entry->port_name != app_db_entry.port_name || - p4_l3_admit_entry->priority != app_db_entry.priority) { - return false; - } - - return true; +bool L3AdmitManagerTest::ValidateL3AdmitEntryAdd(const P4L3AdmitAppDbEntry &app_db_entry) +{ + const auto *p4_l3_admit_entry = GetL3AdmitEntry(KeyGenerator::generateL3AdmitKey( + app_db_entry.mac_address_data, app_db_entry.mac_address_mask, app_db_entry.port_name, app_db_entry.priority)); + if (p4_l3_admit_entry == nullptr || p4_l3_admit_entry->mac_address_data != app_db_entry.mac_address_data || + p4_l3_admit_entry->mac_address_mask != app_db_entry.mac_address_mask || + p4_l3_admit_entry->port_name != app_db_entry.port_name || p4_l3_admit_entry->priority != app_db_entry.priority) + { + return false; + } + + return true; } -TEST_F(L3AdmitManagerTest, ProcessAddRequestShouldSucceedAddingNewL3Admit) { - AddL3AdmitEntry1(); - EXPECT_TRUE(ValidateL3AdmitEntryAdd(kP4L3AdmitAppDbEntry1)); +TEST_F(L3AdmitManagerTest, ProcessAddRequestShouldSucceedAddingNewL3Admit) +{ + AddL3AdmitEntry1(); + EXPECT_TRUE(ValidateL3AdmitEntryAdd(kP4L3AdmitAppDbEntry1)); } -TEST_F(L3AdmitManagerTest, - ProcessAddRequestShouldFailWhenL3AdmitExistInCentralMapper) { - const auto l3admit_key = KeyGenerator::generateL3AdmitKey( - kP4L3AdmitAppDbEntry1.mac_address_data, - kP4L3AdmitAppDbEntry1.mac_address_mask, kP4L3AdmitAppDbEntry1.port_name, - kP4L3AdmitAppDbEntry1.priority); - ASSERT_EQ(l3admit_key, - "match/dst_mac=00:02:03:04:00:00&ff:ff:ff:ff:00:00:priority=2030"); - ASSERT_TRUE( - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_MY_MAC, l3admit_key, kL3AdmitOid1)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, - ProcessAddRequest(kP4L3AdmitAppDbEntry1, l3admit_key)); +TEST_F(L3AdmitManagerTest, ProcessAddRequestShouldFailWhenL3AdmitExistInCentralMapper) +{ + const auto l3admit_key = + KeyGenerator::generateL3AdmitKey(kP4L3AdmitAppDbEntry1.mac_address_data, kP4L3AdmitAppDbEntry1.mac_address_mask, + kP4L3AdmitAppDbEntry1.port_name, kP4L3AdmitAppDbEntry1.priority); + ASSERT_EQ(l3admit_key, "match/dst_mac=00:02:03:04:00:00&ff:ff:ff:ff:00:00:priority=2030"); + ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_MY_MAC, l3admit_key, kL3AdmitOid1)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, ProcessAddRequest(kP4L3AdmitAppDbEntry1, l3admit_key)); } -TEST_F(L3AdmitManagerTest, - ProcessAddRequestShouldFailWhenDependingPortIsNotPresent) { - const P4L3AdmitAppDbEntry kAppDbEntry{ - /*port_name=*/"Ethernet100", - /*mac_address_data=*/swss::MacAddress("00:02:03:04:00:00"), - /*mac_address_mask=*/swss::MacAddress("ff:ff:ff:ff:00:00"), - /*priority=*/2030}; - const auto l3admit_key = KeyGenerator::generateL3AdmitKey( - kAppDbEntry.mac_address_data, kAppDbEntry.mac_address_mask, - kAppDbEntry.port_name, kAppDbEntry.priority); - - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessAddRequest(kAppDbEntry, l3admit_key)); - - EXPECT_EQ(GetL3AdmitEntry(l3admit_key), nullptr); +TEST_F(L3AdmitManagerTest, ProcessAddRequestShouldFailWhenDependingPortIsNotPresent) +{ + const P4L3AdmitAppDbEntry kAppDbEntry{/*port_name=*/"Ethernet100", + /*mac_address_data=*/swss::MacAddress("00:02:03:04:00:00"), + /*mac_address_mask=*/swss::MacAddress("ff:ff:ff:ff:00:00"), + /*priority=*/2030}; + const auto l3admit_key = KeyGenerator::generateL3AdmitKey( + kAppDbEntry.mac_address_data, kAppDbEntry.mac_address_mask, kAppDbEntry.port_name, kAppDbEntry.priority); + + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessAddRequest(kAppDbEntry, l3admit_key)); + + EXPECT_EQ(GetL3AdmitEntry(l3admit_key), nullptr); } -TEST_F(L3AdmitManagerTest, ProcessAddRequestShouldFailWhenSaiCallFails) { - const auto l3admit_key = KeyGenerator::generateL3AdmitKey( - kP4L3AdmitAppDbEntry1.mac_address_data, - kP4L3AdmitAppDbEntry1.mac_address_mask, kP4L3AdmitAppDbEntry1.port_name, - kP4L3AdmitAppDbEntry1.priority); - // Set up mock call. - EXPECT_CALL( - mock_sai_my_mac_, - create_my_mac( - ::testing::NotNull(), Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchCreateL3AdmitArgAttrList, std::placeholders::_1, - CreateAttributeListForL3AdmitObject( - kP4L3AdmitAppDbEntry1, SAI_NULL_OBJECT_ID))))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - ProcessAddRequest(kP4L3AdmitAppDbEntry1, l3admit_key)); - - // The add request failed for the l3 admit entry. - EXPECT_EQ(GetL3AdmitEntry(l3admit_key), nullptr); +TEST_F(L3AdmitManagerTest, ProcessAddRequestShouldFailWhenSaiCallFails) +{ + const auto l3admit_key = + KeyGenerator::generateL3AdmitKey(kP4L3AdmitAppDbEntry1.mac_address_data, kP4L3AdmitAppDbEntry1.mac_address_mask, + kP4L3AdmitAppDbEntry1.port_name, kP4L3AdmitAppDbEntry1.priority); + // Set up mock call. + EXPECT_CALL( + mock_sai_my_mac_, + create_my_mac(::testing::NotNull(), Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchCreateL3AdmitArgAttrList, std::placeholders::_1, + CreateAttributeListForL3AdmitObject(kP4L3AdmitAppDbEntry1, SAI_NULL_OBJECT_ID))))) + .WillOnce(Return(SAI_STATUS_FAILURE)); + + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddRequest(kP4L3AdmitAppDbEntry1, l3admit_key)); + + // The add request failed for the l3 admit entry. + EXPECT_EQ(GetL3AdmitEntry(l3admit_key), nullptr); } -TEST_F(L3AdmitManagerTest, - ProcessDeleteRequestShouldFailForNonExistingL3Admit) { - const auto l3admit_key = KeyGenerator::generateL3AdmitKey( - kP4L3AdmitAppDbEntry1.mac_address_data, - kP4L3AdmitAppDbEntry1.mac_address_mask, kP4L3AdmitAppDbEntry1.port_name, - kP4L3AdmitAppDbEntry1.priority); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessDeleteRequest(l3admit_key)); +TEST_F(L3AdmitManagerTest, ProcessDeleteRequestShouldFailForNonExistingL3Admit) +{ + const auto l3admit_key = + KeyGenerator::generateL3AdmitKey(kP4L3AdmitAppDbEntry1.mac_address_data, kP4L3AdmitAppDbEntry1.mac_address_mask, + kP4L3AdmitAppDbEntry1.port_name, kP4L3AdmitAppDbEntry1.priority); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessDeleteRequest(l3admit_key)); } -TEST_F(L3AdmitManagerTest, - ProcessDeleteRequestShouldFailIfL3AdmitEntryIsAbsentInCentralMapper) { - auto* p4_my_mac_entry = AddL3AdmitEntry1(); - ASSERT_NE(p4_my_mac_entry, nullptr); +TEST_F(L3AdmitManagerTest, ProcessDeleteRequestShouldFailIfL3AdmitEntryIsAbsentInCentralMapper) +{ + auto *p4_my_mac_entry = AddL3AdmitEntry1(); + ASSERT_NE(p4_my_mac_entry, nullptr); - const auto l3admit_key = KeyGenerator::generateL3AdmitKey( - kP4L3AdmitAppDbEntry1.mac_address_data, - kP4L3AdmitAppDbEntry1.mac_address_mask, kP4L3AdmitAppDbEntry1.port_name, - kP4L3AdmitAppDbEntry1.priority); + const auto l3admit_key = + KeyGenerator::generateL3AdmitKey(kP4L3AdmitAppDbEntry1.mac_address_data, kP4L3AdmitAppDbEntry1.mac_address_mask, + kP4L3AdmitAppDbEntry1.port_name, kP4L3AdmitAppDbEntry1.priority); - ASSERT_TRUE(p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_MY_MAC, l3admit_key)); + ASSERT_TRUE(p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_MY_MAC, l3admit_key)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, ProcessDeleteRequest(l3admit_key)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, ProcessDeleteRequest(l3admit_key)); - // Validate the l3 admit entry is not deleted in P4 l3 admit manager. - p4_my_mac_entry = GetL3AdmitEntry(l3admit_key); - ASSERT_NE(p4_my_mac_entry, nullptr); + // Validate the l3 admit entry is not deleted in P4 l3 admit manager. + p4_my_mac_entry = GetL3AdmitEntry(l3admit_key); + ASSERT_NE(p4_my_mac_entry, nullptr); } -TEST_F(L3AdmitManagerTest, - ProcessDeleteRequestShouldFailIfL3AdmitEntryIsStillReferenced) { - auto* p4_my_mac_entry = AddL3AdmitEntry1(); - ASSERT_NE(p4_my_mac_entry, nullptr); - - const auto l3admit_key = KeyGenerator::generateL3AdmitKey( - kP4L3AdmitAppDbEntry1.mac_address_data, - kP4L3AdmitAppDbEntry1.mac_address_mask, kP4L3AdmitAppDbEntry1.port_name, - kP4L3AdmitAppDbEntry1.priority); - ASSERT_TRUE( - p4_oid_mapper_.increaseRefCount(SAI_OBJECT_TYPE_MY_MAC, l3admit_key)); - - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessDeleteRequest(l3admit_key)); - - // Validate the l3 admit entry is not deleted in either P4 l3 admit manager - // or central mapper. - p4_my_mac_entry = GetL3AdmitEntry(l3admit_key); - ASSERT_NE(p4_my_mac_entry, nullptr); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_MY_MAC, l3admit_key, 1)); +TEST_F(L3AdmitManagerTest, ProcessDeleteRequestShouldFailIfL3AdmitEntryIsStillReferenced) +{ + auto *p4_my_mac_entry = AddL3AdmitEntry1(); + ASSERT_NE(p4_my_mac_entry, nullptr); + + const auto l3admit_key = + KeyGenerator::generateL3AdmitKey(kP4L3AdmitAppDbEntry1.mac_address_data, kP4L3AdmitAppDbEntry1.mac_address_mask, + kP4L3AdmitAppDbEntry1.port_name, kP4L3AdmitAppDbEntry1.priority); + ASSERT_TRUE(p4_oid_mapper_.increaseRefCount(SAI_OBJECT_TYPE_MY_MAC, l3admit_key)); + + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessDeleteRequest(l3admit_key)); + + // Validate the l3 admit entry is not deleted in either P4 l3 admit manager + // or central mapper. + p4_my_mac_entry = GetL3AdmitEntry(l3admit_key); + ASSERT_NE(p4_my_mac_entry, nullptr); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_MY_MAC, l3admit_key, 1)); } -TEST_F(L3AdmitManagerTest, ProcessDeleteRequestShouldFailIfSaiCallFails) { - auto* p4_my_mac_entry = AddL3AdmitEntry1(); - ASSERT_NE(p4_my_mac_entry, nullptr); +TEST_F(L3AdmitManagerTest, ProcessDeleteRequestShouldFailIfSaiCallFails) +{ + auto *p4_my_mac_entry = AddL3AdmitEntry1(); + ASSERT_NE(p4_my_mac_entry, nullptr); - const auto l3admit_key = KeyGenerator::generateL3AdmitKey( - kP4L3AdmitAppDbEntry1.mac_address_data, - kP4L3AdmitAppDbEntry1.mac_address_mask, kP4L3AdmitAppDbEntry1.port_name, - kP4L3AdmitAppDbEntry1.priority); + const auto l3admit_key = + KeyGenerator::generateL3AdmitKey(kP4L3AdmitAppDbEntry1.mac_address_data, kP4L3AdmitAppDbEntry1.mac_address_mask, + kP4L3AdmitAppDbEntry1.port_name, kP4L3AdmitAppDbEntry1.priority); - // Set up mock call. - EXPECT_CALL(mock_sai_my_mac_, - remove_my_mac(Eq(p4_my_mac_entry->l3_admit_oid))) - .WillOnce(Return(SAI_STATUS_FAILURE)); + // Set up mock call. + EXPECT_CALL(mock_sai_my_mac_, remove_my_mac(Eq(p4_my_mac_entry->l3_admit_oid))) + .WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessDeleteRequest(l3admit_key)); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessDeleteRequest(l3admit_key)); - // Validate the l3 admit entry is not deleted in either P4 l3 admit manager - // or central mapper. - p4_my_mac_entry = GetL3AdmitEntry(l3admit_key); - ASSERT_NE(p4_my_mac_entry, nullptr); - EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_MY_MAC, l3admit_key)); + // Validate the l3 admit entry is not deleted in either P4 l3 admit manager + // or central mapper. + p4_my_mac_entry = GetL3AdmitEntry(l3admit_key); + ASSERT_NE(p4_my_mac_entry, nullptr); + EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_MY_MAC, l3admit_key)); } -TEST_F(L3AdmitManagerTest, - GetL3AdmitEntryShouldReturnNullPointerForNonexistingL3Admit) { - const auto l3admit_key = KeyGenerator::generateL3AdmitKey( - kP4L3AdmitAppDbEntry1.mac_address_data, - kP4L3AdmitAppDbEntry1.mac_address_mask, kP4L3AdmitAppDbEntry1.port_name, - kP4L3AdmitAppDbEntry1.priority); - EXPECT_EQ(GetL3AdmitEntry(l3admit_key), nullptr); +TEST_F(L3AdmitManagerTest, GetL3AdmitEntryShouldReturnNullPointerForNonexistingL3Admit) +{ + const auto l3admit_key = + KeyGenerator::generateL3AdmitKey(kP4L3AdmitAppDbEntry1.mac_address_data, kP4L3AdmitAppDbEntry1.mac_address_mask, + kP4L3AdmitAppDbEntry1.port_name, kP4L3AdmitAppDbEntry1.priority); + EXPECT_EQ(GetL3AdmitEntry(l3admit_key), nullptr); } -TEST_F(L3AdmitManagerTest, - DeserializeP4L3AdmitAppDbEntryShouldReturnNullPointerForInvalidAction) { - std::vector attributes = {swss::FieldValueTuple( - p4orch::kAction, "set_nexthop")}; // Invalid action. +TEST_F(L3AdmitManagerTest, DeserializeP4L3AdmitAppDbEntryShouldReturnNullPointerForInvalidAction) +{ + std::vector attributes = { + swss::FieldValueTuple(p4orch::kAction, "set_nexthop")}; // Invalid action. - EXPECT_FALSE( - DeserializeP4L3AdmitAppDbEntry(kL3AdmitP4AppDbKey1, attributes).ok()); + EXPECT_FALSE(DeserializeP4L3AdmitAppDbEntry(kL3AdmitP4AppDbKey1, attributes).ok()); } -TEST_F(L3AdmitManagerTest, - DeserializeP4L3AdmitAppDbEntryShouldReturnNullPointerForInvalidField) { - std::vector attributes = { - swss::FieldValueTuple(p4orch::kAction, p4orch::kL3AdmitAction), - swss::FieldValueTuple("UNKNOWN_FIELD", "UNKOWN")}; +TEST_F(L3AdmitManagerTest, DeserializeP4L3AdmitAppDbEntryShouldReturnNullPointerForInvalidField) +{ + std::vector attributes = {swss::FieldValueTuple(p4orch::kAction, p4orch::kL3AdmitAction), + swss::FieldValueTuple("UNKNOWN_FIELD", "UNKOWN")}; - EXPECT_FALSE( - DeserializeP4L3AdmitAppDbEntry(kL3AdmitP4AppDbKey1, attributes).ok()); + EXPECT_FALSE(DeserializeP4L3AdmitAppDbEntry(kL3AdmitP4AppDbKey1, attributes).ok()); } -TEST_F(L3AdmitManagerTest, - DeserializeP4L3AdmitAppDbEntryShouldReturnNullPointerForInvalidMac) { - std::vector attributes = { - swss::FieldValueTuple(p4orch::kAction, p4orch::kL3AdmitAction)}; - constexpr char* kValidAppDbKey = - R"({"match/dst_mac":"00:02:03:04:00:00","priority":2030})"; - EXPECT_TRUE(DeserializeP4L3AdmitAppDbEntry(kValidAppDbKey, attributes).ok()); - constexpr char* kInvalidAppDbKey = - R"({"match/dst_mac":"123.123.123.123","priority":2030})"; - EXPECT_FALSE( - DeserializeP4L3AdmitAppDbEntry(kInvalidAppDbKey, attributes).ok()); +TEST_F(L3AdmitManagerTest, DeserializeP4L3AdmitAppDbEntryShouldReturnNullPointerForInvalidMac) +{ + std::vector attributes = {swss::FieldValueTuple(p4orch::kAction, p4orch::kL3AdmitAction)}; + constexpr char *kValidAppDbKey = R"({"match/dst_mac":"00:02:03:04:00:00","priority":2030})"; + EXPECT_TRUE(DeserializeP4L3AdmitAppDbEntry(kValidAppDbKey, attributes).ok()); + constexpr char *kInvalidAppDbKey = R"({"match/dst_mac":"123.123.123.123","priority":2030})"; + EXPECT_FALSE(DeserializeP4L3AdmitAppDbEntry(kInvalidAppDbKey, attributes).ok()); } -TEST_F( - L3AdmitManagerTest, - DeserializeP4L3AdmitAppDbEntryShouldReturnNullPointerForInvalidPriority) { - std::vector attributes = { - swss::FieldValueTuple(p4orch::kAction, p4orch::kL3AdmitAction)}; - constexpr char* kInvalidAppDbKey = - R"({"match/dst_mac":"00:02:03:04:00:00","priority":-1})"; - EXPECT_FALSE( - DeserializeP4L3AdmitAppDbEntry(kInvalidAppDbKey, attributes).ok()); +TEST_F(L3AdmitManagerTest, DeserializeP4L3AdmitAppDbEntryShouldReturnNullPointerForInvalidPriority) +{ + std::vector attributes = {swss::FieldValueTuple(p4orch::kAction, p4orch::kL3AdmitAction)}; + constexpr char *kInvalidAppDbKey = R"({"match/dst_mac":"00:02:03:04:00:00","priority":-1})"; + EXPECT_FALSE(DeserializeP4L3AdmitAppDbEntry(kInvalidAppDbKey, attributes).ok()); } -TEST_F(L3AdmitManagerTest, - DeserializeP4L3AdmitAppDbEntryShouldSucceedWithoutDstMac) { - std::vector attributes = { - swss::FieldValueTuple(p4orch::kAction, p4orch::kL3AdmitAction)}; - constexpr char* kValidAppDbKey = R"({"priority":1})"; - EXPECT_TRUE(DeserializeP4L3AdmitAppDbEntry(kValidAppDbKey, attributes).ok()); +TEST_F(L3AdmitManagerTest, DeserializeP4L3AdmitAppDbEntryShouldSucceedWithoutDstMac) +{ + std::vector attributes = {swss::FieldValueTuple(p4orch::kAction, p4orch::kL3AdmitAction)}; + constexpr char *kValidAppDbKey = R"({"priority":1})"; + EXPECT_TRUE(DeserializeP4L3AdmitAppDbEntry(kValidAppDbKey, attributes).ok()); } -TEST_F(L3AdmitManagerTest, DrainDuplicateSetRequestShouldSucceed) { - auto* p4_my_mac_entry = AddL3AdmitEntry1(); - ASSERT_NE(p4_my_mac_entry, nullptr); +TEST_F(L3AdmitManagerTest, DrainDuplicateSetRequestShouldSucceed) +{ + auto *p4_my_mac_entry = AddL3AdmitEntry1(); + ASSERT_NE(p4_my_mac_entry, nullptr); - nlohmann::json j; - j[prependMatchField(p4orch::kDstMac)] = - kP4L3AdmitAppDbEntry1.mac_address_data.to_string() + - p4orch::kDataMaskDelimiter + - kP4L3AdmitAppDbEntry1.mac_address_mask.to_string(); - j[p4orch::kPriority] = kP4L3AdmitAppDbEntry1.priority; + nlohmann::json j; + j[prependMatchField(p4orch::kDstMac)] = kP4L3AdmitAppDbEntry1.mac_address_data.to_string() + + p4orch::kDataMaskDelimiter + + kP4L3AdmitAppDbEntry1.mac_address_mask.to_string(); + j[p4orch::kPriority] = kP4L3AdmitAppDbEntry1.priority; - std::vector fvs{ - {p4orch::kAction, p4orch::kL3AdmitAction}}; + std::vector fvs{{p4orch::kAction, p4orch::kL3AdmitAction}}; - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_L3_ADMIT_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs); + swss::KeyOpFieldsValuesTuple app_db_entry(std::string(APP_P4RT_L3_ADMIT_TABLE_NAME) + kTableKeyDelimiter + j.dump(), + SET_COMMAND, fvs); - Enqueue(app_db_entry); - Drain(); + Enqueue(app_db_entry); + Drain(); - // Expect that the update call will fail, so l3 admit entry's fields stay - // the same. - EXPECT_TRUE(ValidateL3AdmitEntryAdd(kP4L3AdmitAppDbEntry1)); + // Expect that the update call will fail, so l3 admit entry's fields stay + // the same. + EXPECT_TRUE(ValidateL3AdmitEntryAdd(kP4L3AdmitAppDbEntry1)); } -TEST_F(L3AdmitManagerTest, DrainDeleteRequestShouldSucceedForExistingL3Admit) { - auto* p4_my_mac_entry = AddL3AdmitEntry1(); - ASSERT_NE(p4_my_mac_entry, nullptr); - - nlohmann::json j; - j[prependMatchField(p4orch::kDstMac)] = - kP4L3AdmitAppDbEntry1.mac_address_data.to_string() + - p4orch::kDataMaskDelimiter + - kP4L3AdmitAppDbEntry1.mac_address_mask.to_string(); - j[p4orch::kPriority] = kP4L3AdmitAppDbEntry1.priority; - - std::vector fvs; - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - DEL_COMMAND, fvs); - EXPECT_CALL(mock_sai_my_mac_, - remove_my_mac(Eq(p4_my_mac_entry->l3_admit_oid))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - Enqueue(app_db_entry); - Drain(); - - // Validate the l3 admit entry has been deleted in both P4 l3 admit - // manager - // and centralized mapper. - const auto l3admit_key = KeyGenerator::generateL3AdmitKey( - kP4L3AdmitAppDbEntry1.mac_address_data, - kP4L3AdmitAppDbEntry1.mac_address_mask, kP4L3AdmitAppDbEntry1.port_name, - kP4L3AdmitAppDbEntry1.priority); - p4_my_mac_entry = GetL3AdmitEntry(l3admit_key); - EXPECT_EQ(p4_my_mac_entry, nullptr); - EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_MY_MAC, l3admit_key)); +TEST_F(L3AdmitManagerTest, DrainDeleteRequestShouldSucceedForExistingL3Admit) +{ + auto *p4_my_mac_entry = AddL3AdmitEntry1(); + ASSERT_NE(p4_my_mac_entry, nullptr); + + nlohmann::json j; + j[prependMatchField(p4orch::kDstMac)] = kP4L3AdmitAppDbEntry1.mac_address_data.to_string() + + p4orch::kDataMaskDelimiter + + kP4L3AdmitAppDbEntry1.mac_address_mask.to_string(); + j[p4orch::kPriority] = kP4L3AdmitAppDbEntry1.priority; + + std::vector fvs; + swss::KeyOpFieldsValuesTuple app_db_entry(std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), + DEL_COMMAND, fvs); + EXPECT_CALL(mock_sai_my_mac_, remove_my_mac(Eq(p4_my_mac_entry->l3_admit_oid))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + Enqueue(app_db_entry); + Drain(); + + // Validate the l3 admit entry has been deleted in both P4 l3 admit + // manager + // and centralized mapper. + const auto l3admit_key = + KeyGenerator::generateL3AdmitKey(kP4L3AdmitAppDbEntry1.mac_address_data, kP4L3AdmitAppDbEntry1.mac_address_mask, + kP4L3AdmitAppDbEntry1.port_name, kP4L3AdmitAppDbEntry1.priority); + p4_my_mac_entry = GetL3AdmitEntry(l3admit_key); + EXPECT_EQ(p4_my_mac_entry, nullptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_MY_MAC, l3admit_key)); } -TEST_F(L3AdmitManagerTest, DrainValidAppEntryShouldSucceed) { - nlohmann::json j; - j[prependMatchField(p4orch::kDstMac)] = - kP4L3AdmitAppDbEntry2.mac_address_data.to_string() + - p4orch::kDataMaskDelimiter + - kP4L3AdmitAppDbEntry2.mac_address_mask.to_string(); - j[p4orch::kPriority] = kP4L3AdmitAppDbEntry2.priority; - j[prependMatchField(p4orch::kInPort)] = kP4L3AdmitAppDbEntry2.port_name; +TEST_F(L3AdmitManagerTest, DrainValidAppEntryShouldSucceed) +{ + nlohmann::json j; + j[prependMatchField(p4orch::kDstMac)] = kP4L3AdmitAppDbEntry2.mac_address_data.to_string() + + p4orch::kDataMaskDelimiter + + kP4L3AdmitAppDbEntry2.mac_address_mask.to_string(); + j[p4orch::kPriority] = kP4L3AdmitAppDbEntry2.priority; + j[prependMatchField(p4orch::kInPort)] = kP4L3AdmitAppDbEntry2.port_name; - std::vector fvs{ - {p4orch::kAction, p4orch::kL3AdmitAction}}; + std::vector fvs{{p4orch::kAction, p4orch::kL3AdmitAction}}; - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_L3_ADMIT_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs); + swss::KeyOpFieldsValuesTuple app_db_entry(std::string(APP_P4RT_L3_ADMIT_TABLE_NAME) + kTableKeyDelimiter + j.dump(), + SET_COMMAND, fvs); - Enqueue(app_db_entry); - EXPECT_CALL(mock_sai_my_mac_, create_my_mac(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kL3AdmitOid2), Return(SAI_STATUS_SUCCESS))); + Enqueue(app_db_entry); + EXPECT_CALL(mock_sai_my_mac_, create_my_mac(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kL3AdmitOid2), Return(SAI_STATUS_SUCCESS))); - Drain(); + Drain(); - EXPECT_TRUE(ValidateL3AdmitEntryAdd(kP4L3AdmitAppDbEntry2)); + EXPECT_TRUE(ValidateL3AdmitEntryAdd(kP4L3AdmitAppDbEntry2)); } -TEST_F(L3AdmitManagerTest, DrainInValidAppEntryShouldSucceed) { - nlohmann::json j; - j[prependMatchField(p4orch::kDstMac)] = "1"; // Invalid Mac - j[p4orch::kPriority] = 1000; +TEST_F(L3AdmitManagerTest, DrainInValidAppEntryShouldSucceed) +{ + nlohmann::json j; + j[prependMatchField(p4orch::kDstMac)] = "1"; // Invalid Mac + j[p4orch::kPriority] = 1000; - std::vector fvs{ - {p4orch::kAction, p4orch::kL3AdmitAction}}; + std::vector fvs{{p4orch::kAction, p4orch::kL3AdmitAction}}; - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_L3_ADMIT_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs); + swss::KeyOpFieldsValuesTuple app_db_entry(std::string(APP_P4RT_L3_ADMIT_TABLE_NAME) + kTableKeyDelimiter + j.dump(), + SET_COMMAND, fvs); - Enqueue(app_db_entry); + Enqueue(app_db_entry); - Drain(); - constexpr char* kL3AdmitKey = R"({"match/dst_mac":"1","priority":1000})"; - EXPECT_EQ(GetL3AdmitEntry(kL3AdmitKey), nullptr); - EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_MY_MAC, kL3AdmitKey)); + Drain(); + constexpr char *kL3AdmitKey = R"({"match/dst_mac":"1","priority":1000})"; + EXPECT_EQ(GetL3AdmitEntry(kL3AdmitKey), nullptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_MY_MAC, kL3AdmitKey)); } -TEST_F(L3AdmitManagerTest, VerifyStateTest) { - auto* p4_my_mac_entry = AddL3AdmitEntry1(); - ASSERT_NE(p4_my_mac_entry, nullptr); - nlohmann::json j; - j[prependMatchField(p4orch::kDstMac)] = - kP4L3AdmitAppDbEntry1.mac_address_data.to_string() + - p4orch::kDataMaskDelimiter + - kP4L3AdmitAppDbEntry1.mac_address_mask.to_string(); - j[p4orch::kPriority] = kP4L3AdmitAppDbEntry1.priority; - const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + APP_P4RT_L3_ADMIT_TABLE_NAME + - kTableKeyDelimiter + j.dump(); - std::vector attributes; - - // Verification should succeed with vaild key and value. - attributes.push_back( - swss::FieldValueTuple{p4orch::kAction, p4orch::kL3AdmitAction}); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set("SAI_OBJECT_TYPE_MY_MAC:oid:0x1", - std::vector{ - swss::FieldValueTuple{ - "SAI_MY_MAC_ATTR_MAC_ADDRESS", - kP4L3AdmitAppDbEntry1.mac_address_data.to_string()}, - swss::FieldValueTuple{"SAI_MY_MAC_ATTR_MAC_ADDRESS_MASK", - "FF:FF:FF:FF:00:00"}, - swss::FieldValueTuple{"SAI_MY_MAC_ATTR_PRIORITY", "2030"}}); - EXPECT_EQ(VerifyState(db_key, attributes), ""); - - // Invalid key should fail verification. - EXPECT_FALSE(VerifyState("invalid", attributes).empty()); - EXPECT_FALSE(VerifyState("invalid:invalid", attributes).empty()); - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes) - .empty()); - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", - attributes) - .empty()); - EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + - ":FIXED_L3_ADMIT_TABLE:invalid", - attributes) - .empty()); - - // Verification should fail if MAC does not exist. - j[prependMatchField(p4orch::kDstMac)] = - kP4L3AdmitAppDbEntry2.mac_address_data.to_string() + - p4orch::kDataMaskDelimiter + - kP4L3AdmitAppDbEntry2.mac_address_mask.to_string(); - j[p4orch::kPriority] = kP4L3AdmitAppDbEntry1.priority; - EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + - APP_P4RT_L3_ADMIT_TABLE_NAME + - kTableKeyDelimiter + j.dump(), - attributes) - .empty()); - - // Verification should fail if port name mismatches. - auto saved_port_name = p4_my_mac_entry->port_name; - p4_my_mac_entry->port_name = kP4L3AdmitAppDbEntry2.port_name; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_my_mac_entry->port_name = saved_port_name; - - // Verification should fail if MAC mismatches. - auto saved_mac_address_data = p4_my_mac_entry->mac_address_data; - p4_my_mac_entry->mac_address_data = kP4L3AdmitAppDbEntry2.mac_address_data; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_my_mac_entry->mac_address_data = saved_mac_address_data; - - // Verification should fail if MAC mask mismatches. - auto saved_mac_address_mask = p4_my_mac_entry->mac_address_mask; - p4_my_mac_entry->mac_address_mask = kP4L3AdmitAppDbEntry2.mac_address_mask; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_my_mac_entry->mac_address_mask = saved_mac_address_mask; - - // Verification should fail if priority mismatches. - auto saved_priority = p4_my_mac_entry->priority; - p4_my_mac_entry->priority = 1111; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_my_mac_entry->priority = saved_priority; - - // Verification should fail if OID mapper mismatches. - const auto l3admit_key = KeyGenerator::generateL3AdmitKey( - kP4L3AdmitAppDbEntry1.mac_address_data, - kP4L3AdmitAppDbEntry1.mac_address_mask, kP4L3AdmitAppDbEntry1.port_name, - kP4L3AdmitAppDbEntry1.priority); - p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_MY_MAC, l3admit_key); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_MY_MAC, l3admit_key, kL3AdmitOid1); +TEST_F(L3AdmitManagerTest, VerifyStateTest) +{ + auto *p4_my_mac_entry = AddL3AdmitEntry1(); + ASSERT_NE(p4_my_mac_entry, nullptr); + nlohmann::json j; + j[prependMatchField(p4orch::kDstMac)] = kP4L3AdmitAppDbEntry1.mac_address_data.to_string() + + p4orch::kDataMaskDelimiter + + kP4L3AdmitAppDbEntry1.mac_address_mask.to_string(); + j[p4orch::kPriority] = kP4L3AdmitAppDbEntry1.priority; + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_L3_ADMIT_TABLE_NAME + + kTableKeyDelimiter + j.dump(); + std::vector attributes; + + // Verification should succeed with vaild key and value. + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kL3AdmitAction}); + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set( + "SAI_OBJECT_TYPE_MY_MAC:oid:0x1", + std::vector{ + swss::FieldValueTuple{"SAI_MY_MAC_ATTR_MAC_ADDRESS", kP4L3AdmitAppDbEntry1.mac_address_data.to_string()}, + swss::FieldValueTuple{"SAI_MY_MAC_ATTR_MAC_ADDRESS_MASK", "FF:FF:FF:FF:00:00"}, + swss::FieldValueTuple{"SAI_MY_MAC_ATTR_PRIORITY", "2030"}}); + EXPECT_EQ(VerifyState(db_key, attributes), ""); + + // Invalid key should fail verification. + EXPECT_FALSE(VerifyState("invalid", attributes).empty()); + EXPECT_FALSE(VerifyState("invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":FIXED_L3_ADMIT_TABLE:invalid", attributes).empty()); + + // Verification should fail if MAC does not exist. + j[prependMatchField(p4orch::kDstMac)] = kP4L3AdmitAppDbEntry2.mac_address_data.to_string() + + p4orch::kDataMaskDelimiter + + kP4L3AdmitAppDbEntry2.mac_address_mask.to_string(); + j[p4orch::kPriority] = kP4L3AdmitAppDbEntry1.priority; + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_L3_ADMIT_TABLE_NAME + + kTableKeyDelimiter + j.dump(), + attributes) + .empty()); + + // Verification should fail if port name mismatches. + auto saved_port_name = p4_my_mac_entry->port_name; + p4_my_mac_entry->port_name = kP4L3AdmitAppDbEntry2.port_name; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_my_mac_entry->port_name = saved_port_name; + + // Verification should fail if MAC mismatches. + auto saved_mac_address_data = p4_my_mac_entry->mac_address_data; + p4_my_mac_entry->mac_address_data = kP4L3AdmitAppDbEntry2.mac_address_data; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_my_mac_entry->mac_address_data = saved_mac_address_data; + + // Verification should fail if MAC mask mismatches. + auto saved_mac_address_mask = p4_my_mac_entry->mac_address_mask; + p4_my_mac_entry->mac_address_mask = kP4L3AdmitAppDbEntry2.mac_address_mask; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_my_mac_entry->mac_address_mask = saved_mac_address_mask; + + // Verification should fail if priority mismatches. + auto saved_priority = p4_my_mac_entry->priority; + p4_my_mac_entry->priority = 1111; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_my_mac_entry->priority = saved_priority; + + // Verification should fail if OID mapper mismatches. + const auto l3admit_key = + KeyGenerator::generateL3AdmitKey(kP4L3AdmitAppDbEntry1.mac_address_data, kP4L3AdmitAppDbEntry1.mac_address_mask, + kP4L3AdmitAppDbEntry1.port_name, kP4L3AdmitAppDbEntry1.priority); + p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_MY_MAC, l3admit_key); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_MY_MAC, l3admit_key, kL3AdmitOid1); } -TEST_F(L3AdmitManagerTest, VerifyStateAsicDbTest) { - auto* p4_my_mac_entry = AddL3AdmitEntry1(); - ASSERT_NE(p4_my_mac_entry, nullptr); - nlohmann::json j; - j[prependMatchField(p4orch::kDstMac)] = - kP4L3AdmitAppDbEntry1.mac_address_data.to_string() + - p4orch::kDataMaskDelimiter + - kP4L3AdmitAppDbEntry1.mac_address_mask.to_string(); - j[p4orch::kPriority] = kP4L3AdmitAppDbEntry1.priority; - const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + APP_P4RT_L3_ADMIT_TABLE_NAME + - kTableKeyDelimiter + j.dump(); - std::vector attributes; - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set("SAI_OBJECT_TYPE_MY_MAC:oid:0x1", - std::vector{ - swss::FieldValueTuple{ - "SAI_MY_MAC_ATTR_MAC_ADDRESS", - kP4L3AdmitAppDbEntry1.mac_address_data.to_string()}, - swss::FieldValueTuple{"SAI_MY_MAC_ATTR_MAC_ADDRESS_MASK", - "FF:FF:FF:FF:00:00"}, - swss::FieldValueTuple{"SAI_MY_MAC_ATTR_PRIORITY", "2030"}}); - - // Verification should succeed with vaild key and value. - attributes.push_back( - swss::FieldValueTuple{p4orch::kAction, p4orch::kL3AdmitAction}); - - EXPECT_EQ(VerifyState(db_key, attributes), ""); - - // Verification should fail if ASIC DB values mismatch. - table.set("SAI_OBJECT_TYPE_MY_MAC:oid:0x1", - std::vector{ - swss::FieldValueTuple{"SAI_MY_MAC_ATTR_PRIORITY", "1000"}}); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - - // Verification should fail if ASIC DB table is missing. - table.del("SAI_OBJECT_TYPE_MY_MAC:oid:0x1"); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - table.set("SAI_OBJECT_TYPE_MY_MAC:oid:0x1", - std::vector{ - swss::FieldValueTuple{ - "SAI_MY_MAC_ATTR_MAC_ADDRESS", - kP4L3AdmitAppDbEntry1.mac_address_data.to_string()}, - swss::FieldValueTuple{"SAI_MY_MAC_ATTR_MAC_ADDRESS_MASK", - "FF:FF:FF:FF:00:00"}, - swss::FieldValueTuple{"SAI_MY_MAC_ATTR_PRIORITY", "2030"}}); +TEST_F(L3AdmitManagerTest, VerifyStateAsicDbTest) +{ + auto *p4_my_mac_entry = AddL3AdmitEntry1(); + ASSERT_NE(p4_my_mac_entry, nullptr); + nlohmann::json j; + j[prependMatchField(p4orch::kDstMac)] = kP4L3AdmitAppDbEntry1.mac_address_data.to_string() + + p4orch::kDataMaskDelimiter + + kP4L3AdmitAppDbEntry1.mac_address_mask.to_string(); + j[p4orch::kPriority] = kP4L3AdmitAppDbEntry1.priority; + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_L3_ADMIT_TABLE_NAME + + kTableKeyDelimiter + j.dump(); + std::vector attributes; + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set( + "SAI_OBJECT_TYPE_MY_MAC:oid:0x1", + std::vector{ + swss::FieldValueTuple{"SAI_MY_MAC_ATTR_MAC_ADDRESS", kP4L3AdmitAppDbEntry1.mac_address_data.to_string()}, + swss::FieldValueTuple{"SAI_MY_MAC_ATTR_MAC_ADDRESS_MASK", "FF:FF:FF:FF:00:00"}, + swss::FieldValueTuple{"SAI_MY_MAC_ATTR_PRIORITY", "2030"}}); + + // Verification should succeed with vaild key and value. + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kL3AdmitAction}); + + EXPECT_EQ(VerifyState(db_key, attributes), ""); + + // Verification should fail if ASIC DB values mismatch. + table.set("SAI_OBJECT_TYPE_MY_MAC:oid:0x1", + std::vector{swss::FieldValueTuple{"SAI_MY_MAC_ATTR_PRIORITY", "1000"}}); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + + // Verification should fail if ASIC DB table is missing. + table.del("SAI_OBJECT_TYPE_MY_MAC:oid:0x1"); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + table.set( + "SAI_OBJECT_TYPE_MY_MAC:oid:0x1", + std::vector{ + swss::FieldValueTuple{"SAI_MY_MAC_ATTR_MAC_ADDRESS", kP4L3AdmitAppDbEntry1.mac_address_data.to_string()}, + swss::FieldValueTuple{"SAI_MY_MAC_ATTR_MAC_ADDRESS_MASK", "FF:FF:FF:FF:00:00"}, + swss::FieldValueTuple{"SAI_MY_MAC_ATTR_PRIORITY", "2030"}}); } diff --git a/orchagent/p4orch/tests/mirror_session_manager_test.cpp b/orchagent/p4orch/tests/mirror_session_manager_test.cpp index 568f2ddba05..1361fc96b39 100644 --- a/orchagent/p4orch/tests/mirror_session_manager_test.cpp +++ b/orchagent/p4orch/tests/mirror_session_manager_test.cpp @@ -15,15 +15,16 @@ #include "swss/ipaddress.h" #include "swss/macaddress.h" #include "swssnet.h" -extern "C" { +extern "C" +{ #include "sai.h" } using ::p4orch::kTableKeyDelimiter; -extern sai_mirror_api_t* sai_mirror_api; +extern sai_mirror_api_t *sai_mirror_api; extern sai_object_id_t gSwitchId; -extern PortsOrch* gPortsOrch; +extern PortsOrch *gPortsOrch; using ::testing::_; using ::testing::DoAll; @@ -33,1411 +34,1168 @@ using ::testing::SetArgPointee; using ::testing::StrictMock; using ::testing::Truly; -namespace p4orch { -namespace test { -namespace { +namespace p4orch +{ +namespace test +{ +namespace +{ -constexpr char* kMirrorSessionId = "mirror_session1"; +constexpr char *kMirrorSessionId = "mirror_session1"; constexpr sai_object_id_t kMirrorSessionOid = 0x445566; // A physical port set up in test_main.cpp -constexpr char* kPort1 = "Ethernet1"; +constexpr char *kPort1 = "Ethernet1"; constexpr sai_object_id_t kPort1Oid = 0x112233; // A management port set up in test_main.cpp -constexpr char* kPort2 = "Ethernet8"; +constexpr char *kPort2 = "Ethernet8"; // A physical port set up in test_main.cpp -constexpr char* kPort3 = "Ethernet3"; +constexpr char *kPort3 = "Ethernet3"; constexpr sai_object_id_t kPort3Oid = 0xaabbccdd; -constexpr char* kSrcIp1 = "10.206.196.31"; -constexpr char* kSrcIp2 = "10.206.196.32"; -constexpr char* kDstIp1 = "172.20.0.203"; -constexpr char* kDstIp2 = "172.20.0.204"; -constexpr char* kSrcMac1 = "00:02:03:04:05:06"; -constexpr char* kSrcMac2 = "00:02:03:04:05:07"; -constexpr char* kDstMac1 = "00:1a:11:17:5f:80"; -constexpr char* kDstMac2 = "00:1a:11:17:5f:81"; -constexpr char* kTtl1 = "0x40"; -constexpr char* kTtl2 = "0x41"; +constexpr char *kSrcIp1 = "10.206.196.31"; +constexpr char *kSrcIp2 = "10.206.196.32"; +constexpr char *kDstIp1 = "172.20.0.203"; +constexpr char *kDstIp2 = "172.20.0.204"; +constexpr char *kSrcMac1 = "00:02:03:04:05:06"; +constexpr char *kSrcMac2 = "00:02:03:04:05:07"; +constexpr char *kDstMac1 = "00:1a:11:17:5f:80"; +constexpr char *kDstMac2 = "00:1a:11:17:5f:81"; +constexpr char *kTtl1 = "0x40"; +constexpr char *kTtl2 = "0x41"; constexpr uint8_t kTtl1Num = 0x40; constexpr uint8_t kTtl2Num = 0x41; -constexpr char* kTos1 = "0x00"; -constexpr char* kTos2 = "0x01"; +constexpr char *kTos1 = "0x00"; +constexpr char *kTos2 = "0x01"; constexpr uint8_t kTos1Num = 0x00; constexpr uint8_t kTos2Num = 0x01; // Generates attribute list for create_mirror_session(). -std::vector GenerateAttrListForCreate( - sai_object_id_t port_oid, uint8_t ttl, uint8_t tos, - const swss::IpAddress& src_ip, const swss::IpAddress& dst_ip, - const swss::MacAddress& src_mac, const swss::MacAddress& dst_mac) { - std::vector attrs; - sai_attribute_t attr; - - attr.id = SAI_MIRROR_SESSION_ATTR_MONITOR_PORT; - attr.value.oid = port_oid; - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_TYPE; - attr.value.s32 = SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE; - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE; - attr.value.s32 = SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL; - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION; - attr.value.u8 = MIRROR_SESSION_DEFAULT_IP_HDR_VER; - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_TOS; - attr.value.u8 = tos; - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_TTL; - attr.value.u8 = ttl; - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS; - swss::copy(attr.value.ipaddr, src_ip); - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS; - swss::copy(attr.value.ipaddr, dst_ip); - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS; - memcpy(attr.value.mac, src_mac.getMac(), sizeof(sai_mac_t)); - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS; - memcpy(attr.value.mac, dst_mac.getMac(), sizeof(sai_mac_t)); - attrs.push_back(attr); - - attr.id = SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE; - attr.value.u16 = GRE_PROTOCOL_ERSPAN; - attrs.push_back(attr); - - return attrs; +std::vector GenerateAttrListForCreate(sai_object_id_t port_oid, uint8_t ttl, uint8_t tos, + const swss::IpAddress &src_ip, const swss::IpAddress &dst_ip, + const swss::MacAddress &src_mac, const swss::MacAddress &dst_mac) +{ + std::vector attrs; + sai_attribute_t attr; + + attr.id = SAI_MIRROR_SESSION_ATTR_MONITOR_PORT; + attr.value.oid = port_oid; + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_TYPE; + attr.value.s32 = SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE; + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE; + attr.value.s32 = SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL; + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION; + attr.value.u8 = MIRROR_SESSION_DEFAULT_IP_HDR_VER; + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_TOS; + attr.value.u8 = tos; + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_TTL; + attr.value.u8 = ttl; + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS; + swss::copy(attr.value.ipaddr, src_ip); + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS; + swss::copy(attr.value.ipaddr, dst_ip); + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS; + memcpy(attr.value.mac, src_mac.getMac(), sizeof(sai_mac_t)); + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS; + memcpy(attr.value.mac, dst_mac.getMac(), sizeof(sai_mac_t)); + attrs.push_back(attr); + + attr.id = SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE; + attr.value.u16 = GRE_PROTOCOL_ERSPAN; + attrs.push_back(attr); + + return attrs; } // Matcher for attribute list in SAI mirror call. // Returns true if attribute lists have the same values in the same order. -bool MatchSaiCallAttrList( - const sai_attribute_t* attr_list, - const std::vector& expected_attr_list) { - if (attr_list == nullptr) { - return false; - } - - for (uint i = 0; i < expected_attr_list.size(); ++i) { - switch (attr_list[i].id) { - case SAI_MIRROR_SESSION_ATTR_MONITOR_PORT: - if (attr_list[i].value.oid != expected_attr_list[i].value.oid) { - return false; - } - break; +bool MatchSaiCallAttrList(const sai_attribute_t *attr_list, const std::vector &expected_attr_list) +{ + if (attr_list == nullptr) + { + return false; + } - case SAI_MIRROR_SESSION_ATTR_TYPE: - case SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE: - if (attr_list[i].value.s32 != expected_attr_list[i].value.s32) { - return false; + for (uint i = 0; i < expected_attr_list.size(); ++i) + { + switch (attr_list[i].id) + { + case SAI_MIRROR_SESSION_ATTR_MONITOR_PORT: + if (attr_list[i].value.oid != expected_attr_list[i].value.oid) + { + return false; + } + break; + + case SAI_MIRROR_SESSION_ATTR_TYPE: + case SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE: + if (attr_list[i].value.s32 != expected_attr_list[i].value.s32) + { + return false; + } + break; + + case SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION: + case SAI_MIRROR_SESSION_ATTR_TOS: + case SAI_MIRROR_SESSION_ATTR_TTL: + if (attr_list[i].value.u8 != expected_attr_list[i].value.u8) + { + return false; + } + break; + + case SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE: + if (attr_list[i].value.u16 != expected_attr_list[i].value.u16) + { + return false; + } + break; + + case SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS: + case SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS: + if (attr_list[i].value.ipaddr.addr_family != expected_attr_list[i].value.ipaddr.addr_family || + (attr_list[i].value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV4 && + attr_list[i].value.ipaddr.addr.ip4 != expected_attr_list[i].value.ipaddr.addr.ip4) || + (attr_list[i].value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV6 && + memcmp(&attr_list[i].value.ipaddr.addr.ip6, &expected_attr_list[i].value.ipaddr.addr.ip6, + sizeof(sai_ip6_t)) != 0)) + { + return false; + } + break; + + case SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS: + case SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS: + if (memcmp(&attr_list[i].value.mac, &expected_attr_list[i].value.mac, sizeof(sai_mac_t)) != 0) + { + return false; + } + break; + + default: + return false; } - break; + } - case SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION: - case SAI_MIRROR_SESSION_ATTR_TOS: - case SAI_MIRROR_SESSION_ATTR_TTL: - if (attr_list[i].value.u8 != expected_attr_list[i].value.u8) { - return false; - } - break; + return true; +} - case SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE: - if (attr_list[i].value.u16 != expected_attr_list[i].value.u16) { - return false; - } - break; - - case SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS: - case SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS: - if (attr_list[i].value.ipaddr.addr_family != - expected_attr_list[i].value.ipaddr.addr_family || - (attr_list[i].value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV4 && - attr_list[i].value.ipaddr.addr.ip4 != - expected_attr_list[i].value.ipaddr.addr.ip4) || - (attr_list[i].value.ipaddr.addr_family == SAI_IP_ADDR_FAMILY_IPV6 && - memcmp(&attr_list[i].value.ipaddr.addr.ip6, - &expected_attr_list[i].value.ipaddr.addr.ip6, - sizeof(sai_ip6_t)) != 0)) { - return false; - } - break; +} // namespace - case SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS: - case SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS: - if (memcmp(&attr_list[i].value.mac, &expected_attr_list[i].value.mac, - sizeof(sai_mac_t)) != 0) { - return false; - } - break; +class MirrorSessionManagerTest : public ::testing::Test +{ + protected: + MirrorSessionManagerTest() : mirror_session_manager_(&p4_oid_mapper_, &publisher_) + { + } - default: - return false; + void SetUp() override + { + // Set up mock stuff for SAI mirror API structure. + mock_sai_mirror = &mock_sai_mirror_; + sai_mirror_api->create_mirror_session = mock_create_mirror_session; + sai_mirror_api->remove_mirror_session = mock_remove_mirror_session; + sai_mirror_api->set_mirror_session_attribute = mock_set_mirror_session_attribute; + sai_mirror_api->get_mirror_session_attribute = mock_get_mirror_session_attribute; } - } - return true; -} + void Enqueue(const swss::KeyOpFieldsValuesTuple &entry) + { + return mirror_session_manager_.enqueue(APP_P4RT_MIRROR_SESSION_TABLE_NAME, entry); + } -} // namespace - -class MirrorSessionManagerTest : public ::testing::Test { - protected: - MirrorSessionManagerTest() - : mirror_session_manager_(&p4_oid_mapper_, &publisher_) {} - - void SetUp() override { - // Set up mock stuff for SAI mirror API structure. - mock_sai_mirror = &mock_sai_mirror_; - sai_mirror_api->create_mirror_session = mock_create_mirror_session; - sai_mirror_api->remove_mirror_session = mock_remove_mirror_session; - sai_mirror_api->set_mirror_session_attribute = - mock_set_mirror_session_attribute; - sai_mirror_api->get_mirror_session_attribute = - mock_get_mirror_session_attribute; - } - - void Enqueue(const swss::KeyOpFieldsValuesTuple& entry) { - return mirror_session_manager_.enqueue(APP_P4RT_MIRROR_SESSION_TABLE_NAME, - entry); - } - - void Drain() { return mirror_session_manager_.drain(); } - - std::string VerifyState(const std::string& key, - const std::vector& tuple) { - return mirror_session_manager_.verifyState(key, tuple); - } - - ReturnCodeOr DeserializeP4MirrorSessionAppDbEntry( - const std::string& key, - const std::vector& attributes) { - return mirror_session_manager_.deserializeP4MirrorSessionAppDbEntry( - key, attributes); - } - - p4orch::P4MirrorSessionEntry* GetMirrorSessionEntry( - const std::string& mirror_session_key) { - return mirror_session_manager_.getMirrorSessionEntry(mirror_session_key); - } - - ReturnCode ProcessAddRequest(const P4MirrorSessionAppDbEntry& app_db_entry) { - return mirror_session_manager_.processAddRequest(app_db_entry); - } - - ReturnCode CreateMirrorSession( - p4orch::P4MirrorSessionEntry mirror_session_entry) { - return mirror_session_manager_.createMirrorSession(mirror_session_entry); - } - - ReturnCode ProcessUpdateRequest( - const P4MirrorSessionAppDbEntry& app_db_entry, - p4orch::P4MirrorSessionEntry* existing_mirror_session_entry) { - return mirror_session_manager_.processUpdateRequest( - app_db_entry, existing_mirror_session_entry); - } - - ReturnCode SetPort( - const std::string& new_port, - p4orch::P4MirrorSessionEntry* existing_mirror_session_entry) { - return mirror_session_manager_.setPort(new_port, - existing_mirror_session_entry); - } - - ReturnCode SetSrcIp( - const swss::IpAddress& new_src_ip, - p4orch::P4MirrorSessionEntry* existing_mirror_session_entry) { - return mirror_session_manager_.setSrcIp(new_src_ip, - existing_mirror_session_entry); - } - - ReturnCode SetDstIp( - const swss::IpAddress& new_dst_ip, - p4orch::P4MirrorSessionEntry* existing_mirror_session_entry) { - return mirror_session_manager_.setDstIp(new_dst_ip, - existing_mirror_session_entry); - } - - ReturnCode SetSrcMac( - const swss::MacAddress& new_src_mac, - p4orch::P4MirrorSessionEntry* existing_mirror_session_entry) { - return mirror_session_manager_.setSrcMac(new_src_mac, - existing_mirror_session_entry); - } - - ReturnCode SetDstMac( - const swss::MacAddress& new_dst_mac, - p4orch::P4MirrorSessionEntry* existing_mirror_session_entry) { - return mirror_session_manager_.setDstMac(new_dst_mac, - existing_mirror_session_entry); - } - - ReturnCode SetTtl( - uint8_t new_ttl, - p4orch::P4MirrorSessionEntry* existing_mirror_session_entry) { - return mirror_session_manager_.setTtl(new_ttl, - existing_mirror_session_entry); - } - - ReturnCode SetTos( - uint8_t new_tos, - p4orch::P4MirrorSessionEntry* existing_mirror_session_entry) { - return mirror_session_manager_.setTos(new_tos, - existing_mirror_session_entry); - } - - ReturnCode ProcessDeleteRequest(const std::string& mirror_session_key) { - return mirror_session_manager_.processDeleteRequest(mirror_session_key); - } - - void AddDefaultMirrorSection() { - P4MirrorSessionAppDbEntry app_db_entry; - app_db_entry.mirror_session_id = kMirrorSessionId; - app_db_entry.has_port = true; - app_db_entry.port = kPort1; - app_db_entry.has_src_ip = true; - app_db_entry.src_ip = swss::IpAddress(kSrcIp1); - app_db_entry.has_dst_ip = true; - app_db_entry.dst_ip = swss::IpAddress(kDstIp1); - app_db_entry.has_src_mac = true; - app_db_entry.src_mac = swss::MacAddress(kSrcMac1); - app_db_entry.has_dst_mac = true; - app_db_entry.dst_mac = swss::MacAddress(kDstMac1); - app_db_entry.has_ttl = true; - app_db_entry.ttl = kTtl1Num; - app_db_entry.has_tos = true; - app_db_entry.tos = kTos1Num; - EXPECT_CALL( - mock_sai_mirror_, - create_mirror_session( - ::testing::NotNull(), Eq(gSwitchId), Eq(11), - Truly(std::bind( - MatchSaiCallAttrList, std::placeholders::_1, - GenerateAttrListForCreate( - kPort1Oid, kTtl1Num, kTos1Num, swss::IpAddress(kSrcIp1), - swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), - swss::MacAddress(kDstMac1)))))) - .WillOnce(DoAll(SetArgPointee<0>(kMirrorSessionOid), - Return(SAI_STATUS_SUCCESS))); - ASSERT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRequest(app_db_entry)); - } - - StrictMock mock_sai_mirror_; - MockResponsePublisher publisher_; - P4OidMapper p4_oid_mapper_; - p4orch::MirrorSessionManager mirror_session_manager_; + void Drain() + { + return mirror_session_manager_.drain(); + } + + std::string VerifyState(const std::string &key, const std::vector &tuple) + { + return mirror_session_manager_.verifyState(key, tuple); + } + + ReturnCodeOr DeserializeP4MirrorSessionAppDbEntry( + const std::string &key, const std::vector &attributes) + { + return mirror_session_manager_.deserializeP4MirrorSessionAppDbEntry(key, attributes); + } + + p4orch::P4MirrorSessionEntry *GetMirrorSessionEntry(const std::string &mirror_session_key) + { + return mirror_session_manager_.getMirrorSessionEntry(mirror_session_key); + } + + ReturnCode ProcessAddRequest(const P4MirrorSessionAppDbEntry &app_db_entry) + { + return mirror_session_manager_.processAddRequest(app_db_entry); + } + + ReturnCode CreateMirrorSession(p4orch::P4MirrorSessionEntry mirror_session_entry) + { + return mirror_session_manager_.createMirrorSession(mirror_session_entry); + } + + ReturnCode ProcessUpdateRequest(const P4MirrorSessionAppDbEntry &app_db_entry, + p4orch::P4MirrorSessionEntry *existing_mirror_session_entry) + { + return mirror_session_manager_.processUpdateRequest(app_db_entry, existing_mirror_session_entry); + } + + ReturnCode SetPort(const std::string &new_port, p4orch::P4MirrorSessionEntry *existing_mirror_session_entry) + { + return mirror_session_manager_.setPort(new_port, existing_mirror_session_entry); + } + + ReturnCode SetSrcIp(const swss::IpAddress &new_src_ip, p4orch::P4MirrorSessionEntry *existing_mirror_session_entry) + { + return mirror_session_manager_.setSrcIp(new_src_ip, existing_mirror_session_entry); + } + + ReturnCode SetDstIp(const swss::IpAddress &new_dst_ip, p4orch::P4MirrorSessionEntry *existing_mirror_session_entry) + { + return mirror_session_manager_.setDstIp(new_dst_ip, existing_mirror_session_entry); + } + + ReturnCode SetSrcMac(const swss::MacAddress &new_src_mac, + p4orch::P4MirrorSessionEntry *existing_mirror_session_entry) + { + return mirror_session_manager_.setSrcMac(new_src_mac, existing_mirror_session_entry); + } + + ReturnCode SetDstMac(const swss::MacAddress &new_dst_mac, + p4orch::P4MirrorSessionEntry *existing_mirror_session_entry) + { + return mirror_session_manager_.setDstMac(new_dst_mac, existing_mirror_session_entry); + } + + ReturnCode SetTtl(uint8_t new_ttl, p4orch::P4MirrorSessionEntry *existing_mirror_session_entry) + { + return mirror_session_manager_.setTtl(new_ttl, existing_mirror_session_entry); + } + + ReturnCode SetTos(uint8_t new_tos, p4orch::P4MirrorSessionEntry *existing_mirror_session_entry) + { + return mirror_session_manager_.setTos(new_tos, existing_mirror_session_entry); + } + + ReturnCode ProcessDeleteRequest(const std::string &mirror_session_key) + { + return mirror_session_manager_.processDeleteRequest(mirror_session_key); + } + + void AddDefaultMirrorSection() + { + P4MirrorSessionAppDbEntry app_db_entry; + app_db_entry.mirror_session_id = kMirrorSessionId; + app_db_entry.has_port = true; + app_db_entry.port = kPort1; + app_db_entry.has_src_ip = true; + app_db_entry.src_ip = swss::IpAddress(kSrcIp1); + app_db_entry.has_dst_ip = true; + app_db_entry.dst_ip = swss::IpAddress(kDstIp1); + app_db_entry.has_src_mac = true; + app_db_entry.src_mac = swss::MacAddress(kSrcMac1); + app_db_entry.has_dst_mac = true; + app_db_entry.dst_mac = swss::MacAddress(kDstMac1); + app_db_entry.has_ttl = true; + app_db_entry.ttl = kTtl1Num; + app_db_entry.has_tos = true; + app_db_entry.tos = kTos1Num; + EXPECT_CALL(mock_sai_mirror_, + create_mirror_session(::testing::NotNull(), Eq(gSwitchId), Eq(11), + Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, + GenerateAttrListForCreate( + kPort1Oid, kTtl1Num, kTos1Num, swss::IpAddress(kSrcIp1), + swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), + swss::MacAddress(kDstMac1)))))) + .WillOnce(DoAll(SetArgPointee<0>(kMirrorSessionOid), Return(SAI_STATUS_SUCCESS))); + ASSERT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRequest(app_db_entry)); + } + + StrictMock mock_sai_mirror_; + MockResponsePublisher publisher_; + P4OidMapper p4_oid_mapper_; + p4orch::MirrorSessionManager mirror_session_manager_; }; // Do add, update and delete serially. -TEST_F(MirrorSessionManagerTest, SuccessfulEnqueueAndDrain) { - // 1. Add a new entry. - nlohmann::json j; - j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; - - std::vector fvs{ - {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, - {prependParamField(p4orch::kPort), kPort1}, - {prependParamField(p4orch::kSrcIp), kSrcIp1}, - {prependParamField(p4orch::kDstIp), kDstIp1}, - {prependParamField(p4orch::kSrcMac), kSrcMac1}, - {prependParamField(p4orch::kDstMac), kDstMac1}, - {prependParamField(p4orch::kTtl), kTtl1}, - {prependParamField(p4orch::kTos), kTos1}}; - - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + - j.dump(), - SET_COMMAND, fvs); - - Enqueue(app_db_entry); - // Set up mock call. - EXPECT_CALL( - mock_sai_mirror_, - create_mirror_session( - ::testing::NotNull(), Eq(gSwitchId), Eq(11), - Truly(std::bind( - MatchSaiCallAttrList, std::placeholders::_1, - GenerateAttrListForCreate( - kPort1Oid, kTtl1Num, kTos1Num, swss::IpAddress(kSrcIp1), - swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), - swss::MacAddress(kDstMac1)))))) - .WillOnce(DoAll(SetArgPointee<0>(kMirrorSessionOid), - Return(SAI_STATUS_SUCCESS))); - Drain(); - - // Check the added entry. - auto mirror_entry = GetMirrorSessionEntry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - ASSERT_NE(mirror_entry, nullptr); - p4orch::P4MirrorSessionEntry expected_mirror_entry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - kMirrorSessionOid, kMirrorSessionId, kPort1, swss::IpAddress(kSrcIp1), - swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), - swss::MacAddress(kDstMac1), kTtl1Num, kTos1Num); - EXPECT_EQ(*mirror_entry, expected_mirror_entry); - - sai_object_id_t oid_in_mapper = 0; - EXPECT_TRUE(p4_oid_mapper_.getOID( - SAI_OBJECT_TYPE_MIRROR_SESSION, - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - &oid_in_mapper)); - EXPECT_EQ(kMirrorSessionOid, oid_in_mapper); - - // 2. Update the added entry. - fvs = {{p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, - {prependParamField(p4orch::kPort), kPort3}, - {prependParamField(p4orch::kSrcIp), kSrcIp2}, - {prependParamField(p4orch::kDstIp), kDstIp2}, - {prependParamField(p4orch::kSrcMac), kSrcMac2}, - {prependParamField(p4orch::kDstMac), kDstMac2}, - {prependParamField(p4orch::kTtl), kTtl2}, - {prependParamField(p4orch::kTos), kTos2}}; - - app_db_entry = {std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + - kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs}; - - Enqueue(app_db_entry); - // Set up mock call. - sai_attribute_t attr; - attr.id = SAI_MIRROR_SESSION_ATTR_MONITOR_PORT; - attr.value.oid = kPort3Oid; - EXPECT_CALL(mock_sai_mirror_, - set_mirror_session_attribute( - Eq(kMirrorSessionOid), - Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, - std::vector({attr}))))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - attr.id = SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS; - swss::copy(attr.value.ipaddr, swss::IpAddress(kSrcIp2)); - EXPECT_CALL(mock_sai_mirror_, - set_mirror_session_attribute( - Eq(kMirrorSessionOid), - Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, - std::vector({attr}))))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - attr.id = SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS; - swss::copy(attr.value.ipaddr, swss::IpAddress(kDstIp2)); - EXPECT_CALL(mock_sai_mirror_, - set_mirror_session_attribute( - Eq(kMirrorSessionOid), - Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, - std::vector({attr}))))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - attr.id = SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS; - memcpy(attr.value.mac, swss::MacAddress(kSrcMac2).getMac(), - sizeof(sai_mac_t)); - EXPECT_CALL(mock_sai_mirror_, - set_mirror_session_attribute( - Eq(kMirrorSessionOid), - Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, - std::vector({attr}))))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - attr.id = SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS; - memcpy(attr.value.mac, swss::MacAddress(kDstMac2).getMac(), - sizeof(sai_mac_t)); - EXPECT_CALL(mock_sai_mirror_, - set_mirror_session_attribute( - Eq(kMirrorSessionOid), - Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, - std::vector({attr}))))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - attr.id = SAI_MIRROR_SESSION_ATTR_TTL; - attr.value.u8 = kTtl2Num; - EXPECT_CALL(mock_sai_mirror_, - set_mirror_session_attribute( - Eq(kMirrorSessionOid), - Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, - std::vector({attr}))))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - attr.id = SAI_MIRROR_SESSION_ATTR_TOS; - attr.value.u8 = kTos2Num; - EXPECT_CALL(mock_sai_mirror_, - set_mirror_session_attribute( - Eq(kMirrorSessionOid), - Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, - std::vector({attr}))))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - Drain(); - - mirror_entry = GetMirrorSessionEntry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - ASSERT_NE(mirror_entry, nullptr); - expected_mirror_entry.port = kPort3; - expected_mirror_entry.src_ip = swss::IpAddress(kSrcIp2); - expected_mirror_entry.dst_ip = swss::IpAddress(kDstIp2); - expected_mirror_entry.src_mac = swss::MacAddress(kSrcMac2); - expected_mirror_entry.dst_mac = swss::MacAddress(kDstMac2); - expected_mirror_entry.ttl = kTtl2Num; - expected_mirror_entry.tos = kTos2Num; - EXPECT_EQ(*mirror_entry, expected_mirror_entry); - - // 3. Delete the entry. - fvs = {}; - app_db_entry = {std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + - kTableKeyDelimiter + j.dump(), - DEL_COMMAND, fvs}; - - Enqueue(app_db_entry); - // Set up mock call. - EXPECT_CALL(mock_sai_mirror_, remove_mirror_session(Eq(kMirrorSessionOid))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - Drain(); - - mirror_entry = GetMirrorSessionEntry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - EXPECT_EQ(mirror_entry, nullptr); - - EXPECT_FALSE(p4_oid_mapper_.existsOID( - SAI_OBJECT_TYPE_MIRROR_SESSION, - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId))); +TEST_F(MirrorSessionManagerTest, SuccessfulEnqueueAndDrain) +{ + // 1. Add a new entry. + nlohmann::json j; + j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; + + std::vector fvs{ + {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, {prependParamField(p4orch::kPort), kPort1}, + {prependParamField(p4orch::kSrcIp), kSrcIp1}, {prependParamField(p4orch::kDstIp), kDstIp1}, + {prependParamField(p4orch::kSrcMac), kSrcMac1}, {prependParamField(p4orch::kDstMac), kDstMac1}, + {prependParamField(p4orch::kTtl), kTtl1}, {prependParamField(p4orch::kTos), kTos1}}; + + swss::KeyOpFieldsValuesTuple app_db_entry( + std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs); + + Enqueue(app_db_entry); + // Set up mock call. + EXPECT_CALL(mock_sai_mirror_, + create_mirror_session( + ::testing::NotNull(), Eq(gSwitchId), Eq(11), + Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, + GenerateAttrListForCreate(kPort1Oid, kTtl1Num, kTos1Num, swss::IpAddress(kSrcIp1), + swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), + swss::MacAddress(kDstMac1)))))) + .WillOnce(DoAll(SetArgPointee<0>(kMirrorSessionOid), Return(SAI_STATUS_SUCCESS))); + Drain(); + + // Check the added entry. + auto mirror_entry = GetMirrorSessionEntry(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + ASSERT_NE(mirror_entry, nullptr); + p4orch::P4MirrorSessionEntry expected_mirror_entry( + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), kMirrorSessionOid, kMirrorSessionId, kPort1, + swss::IpAddress(kSrcIp1), swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), swss::MacAddress(kDstMac1), + kTtl1Num, kTos1Num); + EXPECT_EQ(*mirror_entry, expected_mirror_entry); + + sai_object_id_t oid_in_mapper = 0; + EXPECT_TRUE(p4_oid_mapper_.getOID(SAI_OBJECT_TYPE_MIRROR_SESSION, + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), &oid_in_mapper)); + EXPECT_EQ(kMirrorSessionOid, oid_in_mapper); + + // 2. Update the added entry. + fvs = {{p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, {prependParamField(p4orch::kPort), kPort3}, + {prependParamField(p4orch::kSrcIp), kSrcIp2}, {prependParamField(p4orch::kDstIp), kDstIp2}, + {prependParamField(p4orch::kSrcMac), kSrcMac2}, {prependParamField(p4orch::kDstMac), kDstMac2}, + {prependParamField(p4orch::kTtl), kTtl2}, {prependParamField(p4orch::kTos), kTos2}}; + + app_db_entry = {std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs}; + + Enqueue(app_db_entry); + // Set up mock call. + sai_attribute_t attr; + attr.id = SAI_MIRROR_SESSION_ATTR_MONITOR_PORT; + attr.value.oid = kPort3Oid; + EXPECT_CALL( + mock_sai_mirror_, + set_mirror_session_attribute(Eq(kMirrorSessionOid), Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, + std::vector({attr}))))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + attr.id = SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS; + swss::copy(attr.value.ipaddr, swss::IpAddress(kSrcIp2)); + EXPECT_CALL( + mock_sai_mirror_, + set_mirror_session_attribute(Eq(kMirrorSessionOid), Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, + std::vector({attr}))))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + attr.id = SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS; + swss::copy(attr.value.ipaddr, swss::IpAddress(kDstIp2)); + EXPECT_CALL( + mock_sai_mirror_, + set_mirror_session_attribute(Eq(kMirrorSessionOid), Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, + std::vector({attr}))))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + attr.id = SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS; + memcpy(attr.value.mac, swss::MacAddress(kSrcMac2).getMac(), sizeof(sai_mac_t)); + EXPECT_CALL( + mock_sai_mirror_, + set_mirror_session_attribute(Eq(kMirrorSessionOid), Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, + std::vector({attr}))))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + attr.id = SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS; + memcpy(attr.value.mac, swss::MacAddress(kDstMac2).getMac(), sizeof(sai_mac_t)); + EXPECT_CALL( + mock_sai_mirror_, + set_mirror_session_attribute(Eq(kMirrorSessionOid), Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, + std::vector({attr}))))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + attr.id = SAI_MIRROR_SESSION_ATTR_TTL; + attr.value.u8 = kTtl2Num; + EXPECT_CALL( + mock_sai_mirror_, + set_mirror_session_attribute(Eq(kMirrorSessionOid), Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, + std::vector({attr}))))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + attr.id = SAI_MIRROR_SESSION_ATTR_TOS; + attr.value.u8 = kTos2Num; + EXPECT_CALL( + mock_sai_mirror_, + set_mirror_session_attribute(Eq(kMirrorSessionOid), Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, + std::vector({attr}))))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + Drain(); + + mirror_entry = GetMirrorSessionEntry(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + ASSERT_NE(mirror_entry, nullptr); + expected_mirror_entry.port = kPort3; + expected_mirror_entry.src_ip = swss::IpAddress(kSrcIp2); + expected_mirror_entry.dst_ip = swss::IpAddress(kDstIp2); + expected_mirror_entry.src_mac = swss::MacAddress(kSrcMac2); + expected_mirror_entry.dst_mac = swss::MacAddress(kDstMac2); + expected_mirror_entry.ttl = kTtl2Num; + expected_mirror_entry.tos = kTos2Num; + EXPECT_EQ(*mirror_entry, expected_mirror_entry); + + // 3. Delete the entry. + fvs = {}; + app_db_entry = {std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + j.dump(), DEL_COMMAND, fvs}; + + Enqueue(app_db_entry); + // Set up mock call. + EXPECT_CALL(mock_sai_mirror_, remove_mirror_session(Eq(kMirrorSessionOid))).WillOnce(Return(SAI_STATUS_SUCCESS)); + Drain(); + + mirror_entry = GetMirrorSessionEntry(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + EXPECT_EQ(mirror_entry, nullptr); + + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_MIRROR_SESSION, + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId))); } -TEST_F(MirrorSessionManagerTest, - DrainShouldFailForInvalidAppDbEntryMatchFiled) { - nlohmann::json j; - j[prependMatchField("invalid_match_field")] = kMirrorSessionId; - - std::vector fvs{ - {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, - {prependParamField(p4orch::kPort), kPort1}, - {prependParamField(p4orch::kSrcIp), kSrcIp1}, - {prependParamField(p4orch::kDstIp), kDstIp1}, - {prependParamField(p4orch::kSrcMac), kSrcMac1}, - {prependParamField(p4orch::kDstMac), kDstMac1}, - {prependParamField(p4orch::kTtl), kTtl1}, - {prependParamField(p4orch::kTos), kTos1}}; - - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + - j.dump(), - SET_COMMAND, fvs); - - Enqueue(app_db_entry); - Drain(); - - // Check the added entry. - auto mirror_entry = GetMirrorSessionEntry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - EXPECT_EQ(mirror_entry, nullptr); +TEST_F(MirrorSessionManagerTest, DrainShouldFailForInvalidAppDbEntryMatchFiled) +{ + nlohmann::json j; + j[prependMatchField("invalid_match_field")] = kMirrorSessionId; + + std::vector fvs{ + {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, {prependParamField(p4orch::kPort), kPort1}, + {prependParamField(p4orch::kSrcIp), kSrcIp1}, {prependParamField(p4orch::kDstIp), kDstIp1}, + {prependParamField(p4orch::kSrcMac), kSrcMac1}, {prependParamField(p4orch::kDstMac), kDstMac1}, + {prependParamField(p4orch::kTtl), kTtl1}, {prependParamField(p4orch::kTos), kTos1}}; + + swss::KeyOpFieldsValuesTuple app_db_entry( + std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs); + + Enqueue(app_db_entry); + Drain(); + + // Check the added entry. + auto mirror_entry = GetMirrorSessionEntry(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + EXPECT_EQ(mirror_entry, nullptr); } -TEST_F(MirrorSessionManagerTest, DrainShouldFailForUnknownOp) { - nlohmann::json j; - j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; - - std::vector fvs{ - {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, - {prependParamField(p4orch::kPort), kPort1}, - {prependParamField(p4orch::kSrcIp), kSrcIp1}, - {prependParamField(p4orch::kDstIp), kDstIp1}, - {prependParamField(p4orch::kSrcMac), kSrcMac1}, - {prependParamField(p4orch::kDstMac), kDstMac1}, - {prependParamField(p4orch::kTtl), kTtl1}, - {prependParamField(p4orch::kTos), kTos1}}; - - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + - j.dump(), - "unknown_op", fvs); - - Enqueue(app_db_entry); - Drain(); - - // Check the added entry. - auto mirror_entry = GetMirrorSessionEntry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - EXPECT_EQ(mirror_entry, nullptr); +TEST_F(MirrorSessionManagerTest, DrainShouldFailForUnknownOp) +{ + nlohmann::json j; + j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; + + std::vector fvs{ + {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, {prependParamField(p4orch::kPort), kPort1}, + {prependParamField(p4orch::kSrcIp), kSrcIp1}, {prependParamField(p4orch::kDstIp), kDstIp1}, + {prependParamField(p4orch::kSrcMac), kSrcMac1}, {prependParamField(p4orch::kDstMac), kDstMac1}, + {prependParamField(p4orch::kTtl), kTtl1}, {prependParamField(p4orch::kTos), kTos1}}; + + swss::KeyOpFieldsValuesTuple app_db_entry( + std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + j.dump(), "unknown_op", fvs); + + Enqueue(app_db_entry); + Drain(); + + // Check the added entry. + auto mirror_entry = GetMirrorSessionEntry(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + EXPECT_EQ(mirror_entry, nullptr); } -TEST_F(MirrorSessionManagerTest, - DrainShouldFailForInvalidAppDbEntryFieldValue) { - nlohmann::json j; - j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; - - std::vector fvs{ - {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, - {prependParamField(p4orch::kPort), kPort1}, - {prependParamField(p4orch::kSrcIp), "0123456789"}, - {prependParamField(p4orch::kDstIp), kDstIp1}, - {prependParamField(p4orch::kSrcMac), kSrcMac1}, - {prependParamField(p4orch::kDstMac), kDstMac1}, - {prependParamField(p4orch::kTtl), kTtl1}, - {prependParamField(p4orch::kTos), kTos1}}; - - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + - j.dump(), - SET_COMMAND, fvs); - - Enqueue(app_db_entry); - Drain(); - - // Check the added entry. - auto mirror_entry = GetMirrorSessionEntry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - EXPECT_EQ(mirror_entry, nullptr); +TEST_F(MirrorSessionManagerTest, DrainShouldFailForInvalidAppDbEntryFieldValue) +{ + nlohmann::json j; + j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; + + std::vector fvs{ + {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, {prependParamField(p4orch::kPort), kPort1}, + {prependParamField(p4orch::kSrcIp), "0123456789"}, {prependParamField(p4orch::kDstIp), kDstIp1}, + {prependParamField(p4orch::kSrcMac), kSrcMac1}, {prependParamField(p4orch::kDstMac), kDstMac1}, + {prependParamField(p4orch::kTtl), kTtl1}, {prependParamField(p4orch::kTos), kTos1}}; + + swss::KeyOpFieldsValuesTuple app_db_entry( + std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs); + + Enqueue(app_db_entry); + Drain(); + + // Check the added entry. + auto mirror_entry = GetMirrorSessionEntry(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + EXPECT_EQ(mirror_entry, nullptr); } -TEST_F(MirrorSessionManagerTest, - DrainShouldFailForUnknownAppDbEntryFieldValue) { - nlohmann::json j; - j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; - - std::vector fvs{ - {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, - {prependParamField(p4orch::kPort), kPort1}, - {prependParamField(p4orch::kSrcIp), kSrcIp1}, - {prependParamField(p4orch::kDstIp), kDstIp1}, - {prependParamField(p4orch::kSrcMac), kSrcMac1}, - {prependParamField(p4orch::kDstMac), kDstMac1}, - {prependParamField(p4orch::kTtl), kTtl1}, - {prependParamField(p4orch::kTos), kTos1}, - {"unknown_field", "unknown_value"}}; - - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + - j.dump(), - SET_COMMAND, fvs); - - Enqueue(app_db_entry); - Drain(); - - // Check the added entry. - auto mirror_entry = GetMirrorSessionEntry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - EXPECT_EQ(mirror_entry, nullptr); +TEST_F(MirrorSessionManagerTest, DrainShouldFailForUnknownAppDbEntryFieldValue) +{ + nlohmann::json j; + j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; + + std::vector fvs{{p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, + {prependParamField(p4orch::kPort), kPort1}, + {prependParamField(p4orch::kSrcIp), kSrcIp1}, + {prependParamField(p4orch::kDstIp), kDstIp1}, + {prependParamField(p4orch::kSrcMac), kSrcMac1}, + {prependParamField(p4orch::kDstMac), kDstMac1}, + {prependParamField(p4orch::kTtl), kTtl1}, + {prependParamField(p4orch::kTos), kTos1}, + {"unknown_field", "unknown_value"}}; + + swss::KeyOpFieldsValuesTuple app_db_entry( + std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs); + + Enqueue(app_db_entry); + Drain(); + + // Check the added entry. + auto mirror_entry = GetMirrorSessionEntry(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + EXPECT_EQ(mirror_entry, nullptr); } -TEST_F(MirrorSessionManagerTest, DrainShouldFailForIncompleteAppDbEntry) { - nlohmann::json j; - j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; - - std::vector fvs_missing_tos{ - {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, - {prependParamField(p4orch::kPort), kPort1}, - {prependParamField(p4orch::kSrcIp), kSrcIp1}, - {prependParamField(p4orch::kDstIp), kDstIp1}, - {prependParamField(p4orch::kSrcMac), kSrcMac1}, - {prependParamField(p4orch::kDstMac), kDstMac1}, - {prependParamField(p4orch::kTtl), kTtl1}}; - - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + - j.dump(), - SET_COMMAND, fvs_missing_tos); - - Enqueue(app_db_entry); - Drain(); - - // Check the added entry. - auto mirror_entry = GetMirrorSessionEntry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - EXPECT_EQ(mirror_entry, nullptr); +TEST_F(MirrorSessionManagerTest, DrainShouldFailForIncompleteAppDbEntry) +{ + nlohmann::json j; + j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; + + std::vector fvs_missing_tos{ + {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, {prependParamField(p4orch::kPort), kPort1}, + {prependParamField(p4orch::kSrcIp), kSrcIp1}, {prependParamField(p4orch::kDstIp), kDstIp1}, + {prependParamField(p4orch::kSrcMac), kSrcMac1}, {prependParamField(p4orch::kDstMac), kDstMac1}, + {prependParamField(p4orch::kTtl), kTtl1}}; + + swss::KeyOpFieldsValuesTuple app_db_entry( + std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs_missing_tos); + + Enqueue(app_db_entry); + Drain(); + + // Check the added entry. + auto mirror_entry = GetMirrorSessionEntry(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + EXPECT_EQ(mirror_entry, nullptr); } -TEST_F(MirrorSessionManagerTest, DrainShouldFailForUnknownPort) { - nlohmann::json j; - j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; - - std::vector fvs{ - {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, - {prependParamField(p4orch::kPort), "unknown_port"}, - {prependParamField(p4orch::kSrcIp), kSrcIp1}, - {prependParamField(p4orch::kDstIp), kDstIp1}, - {prependParamField(p4orch::kSrcMac), kSrcMac1}, - {prependParamField(p4orch::kDstMac), kDstMac1}, - {prependParamField(p4orch::kTtl), kTtl1}, - {prependParamField(p4orch::kTos), kTos1}}; - - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + - j.dump(), - SET_COMMAND, fvs); - - Enqueue(app_db_entry); - Drain(); - - // Check the added entry. - auto mirror_entry = GetMirrorSessionEntry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - EXPECT_EQ(mirror_entry, nullptr); +TEST_F(MirrorSessionManagerTest, DrainShouldFailForUnknownPort) +{ + nlohmann::json j; + j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; + + std::vector fvs{ + {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, {prependParamField(p4orch::kPort), "unknown_port"}, + {prependParamField(p4orch::kSrcIp), kSrcIp1}, {prependParamField(p4orch::kDstIp), kDstIp1}, + {prependParamField(p4orch::kSrcMac), kSrcMac1}, {prependParamField(p4orch::kDstMac), kDstMac1}, + {prependParamField(p4orch::kTtl), kTtl1}, {prependParamField(p4orch::kTos), kTos1}}; + + swss::KeyOpFieldsValuesTuple app_db_entry( + std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs); + + Enqueue(app_db_entry); + Drain(); + + // Check the added entry. + auto mirror_entry = GetMirrorSessionEntry(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + EXPECT_EQ(mirror_entry, nullptr); } -TEST_F(MirrorSessionManagerTest, DrainShouldFailWhenCreateSaiCallFails) { - nlohmann::json j; - j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; - - std::vector fvs{ - {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, - {prependParamField(p4orch::kPort), kPort1}, - {prependParamField(p4orch::kSrcIp), kSrcIp1}, - {prependParamField(p4orch::kDstIp), kDstIp1}, - {prependParamField(p4orch::kSrcMac), kSrcMac1}, - {prependParamField(p4orch::kDstMac), kDstMac1}, - {prependParamField(p4orch::kTtl), kTtl1}, - {prependParamField(p4orch::kTos), kTos1}}; - - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + - j.dump(), - SET_COMMAND, fvs); - - Enqueue(app_db_entry); - EXPECT_CALL( - mock_sai_mirror_, - create_mirror_session( - ::testing::NotNull(), Eq(gSwitchId), Eq(11), - Truly(std::bind( - MatchSaiCallAttrList, std::placeholders::_1, - GenerateAttrListForCreate( - kPort1Oid, kTtl1Num, kTos1Num, swss::IpAddress(kSrcIp1), - swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), - swss::MacAddress(kDstMac1)))))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - Drain(); - - // Check the added entry. - auto mirror_entry = GetMirrorSessionEntry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - EXPECT_EQ(mirror_entry, nullptr); +TEST_F(MirrorSessionManagerTest, DrainShouldFailWhenCreateSaiCallFails) +{ + nlohmann::json j; + j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; + + std::vector fvs{ + {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, {prependParamField(p4orch::kPort), kPort1}, + {prependParamField(p4orch::kSrcIp), kSrcIp1}, {prependParamField(p4orch::kDstIp), kDstIp1}, + {prependParamField(p4orch::kSrcMac), kSrcMac1}, {prependParamField(p4orch::kDstMac), kDstMac1}, + {prependParamField(p4orch::kTtl), kTtl1}, {prependParamField(p4orch::kTos), kTos1}}; + + swss::KeyOpFieldsValuesTuple app_db_entry( + std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs); + + Enqueue(app_db_entry); + EXPECT_CALL(mock_sai_mirror_, + create_mirror_session( + ::testing::NotNull(), Eq(gSwitchId), Eq(11), + Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, + GenerateAttrListForCreate(kPort1Oid, kTtl1Num, kTos1Num, swss::IpAddress(kSrcIp1), + swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), + swss::MacAddress(kDstMac1)))))) + .WillOnce(Return(SAI_STATUS_FAILURE)); + Drain(); + + // Check the added entry. + auto mirror_entry = GetMirrorSessionEntry(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + EXPECT_EQ(mirror_entry, nullptr); } -TEST_F(MirrorSessionManagerTest, DrainShouldFailWhenDeleteSaiCallFails) { - nlohmann::json j; - j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; - - std::vector fvs{ - {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, - {prependParamField(p4orch::kPort), kPort1}, - {prependParamField(p4orch::kSrcIp), kSrcIp1}, - {prependParamField(p4orch::kDstIp), kDstIp1}, - {prependParamField(p4orch::kSrcMac), kSrcMac1}, - {prependParamField(p4orch::kDstMac), kDstMac1}, - {prependParamField(p4orch::kTtl), kTtl1}, - {prependParamField(p4orch::kTos), kTos1}}; - - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + - j.dump(), - SET_COMMAND, fvs); - - Enqueue(app_db_entry); - EXPECT_CALL( - mock_sai_mirror_, - create_mirror_session( - ::testing::NotNull(), Eq(gSwitchId), Eq(11), - Truly(std::bind( - MatchSaiCallAttrList, std::placeholders::_1, - GenerateAttrListForCreate( - kPort1Oid, kTtl1Num, kTos1Num, swss::IpAddress(kSrcIp1), - swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), - swss::MacAddress(kDstMac1)))))) - .WillOnce(DoAll(SetArgPointee<0>(kMirrorSessionOid), - Return(SAI_STATUS_SUCCESS))); - Drain(); - - fvs = {}; - app_db_entry = {std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + - kTableKeyDelimiter + j.dump(), - DEL_COMMAND, fvs}; - - Enqueue(app_db_entry); - EXPECT_CALL(mock_sai_mirror_, remove_mirror_session(Eq(kMirrorSessionOid))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - Drain(); - - // Check entry still exists. - auto mirror_entry = GetMirrorSessionEntry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - ASSERT_NE(mirror_entry, nullptr); +TEST_F(MirrorSessionManagerTest, DrainShouldFailWhenDeleteSaiCallFails) +{ + nlohmann::json j; + j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; + + std::vector fvs{ + {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, {prependParamField(p4orch::kPort), kPort1}, + {prependParamField(p4orch::kSrcIp), kSrcIp1}, {prependParamField(p4orch::kDstIp), kDstIp1}, + {prependParamField(p4orch::kSrcMac), kSrcMac1}, {prependParamField(p4orch::kDstMac), kDstMac1}, + {prependParamField(p4orch::kTtl), kTtl1}, {prependParamField(p4orch::kTos), kTos1}}; + + swss::KeyOpFieldsValuesTuple app_db_entry( + std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs); + + Enqueue(app_db_entry); + EXPECT_CALL(mock_sai_mirror_, + create_mirror_session( + ::testing::NotNull(), Eq(gSwitchId), Eq(11), + Truly(std::bind(MatchSaiCallAttrList, std::placeholders::_1, + GenerateAttrListForCreate(kPort1Oid, kTtl1Num, kTos1Num, swss::IpAddress(kSrcIp1), + swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), + swss::MacAddress(kDstMac1)))))) + .WillOnce(DoAll(SetArgPointee<0>(kMirrorSessionOid), Return(SAI_STATUS_SUCCESS))); + Drain(); + + fvs = {}; + app_db_entry = {std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + j.dump(), DEL_COMMAND, fvs}; + + Enqueue(app_db_entry); + EXPECT_CALL(mock_sai_mirror_, remove_mirror_session(Eq(kMirrorSessionOid))).WillOnce(Return(SAI_STATUS_FAILURE)); + Drain(); + + // Check entry still exists. + auto mirror_entry = GetMirrorSessionEntry(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + ASSERT_NE(mirror_entry, nullptr); } -TEST_F(MirrorSessionManagerTest, DeserializeInvalidValueShouldFail) { - constexpr char* kInalidKey = R"({"invalid_key"})"; - std::vector fvs{ - {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}}; - EXPECT_FALSE(DeserializeP4MirrorSessionAppDbEntry(kInalidKey, fvs).ok()); - - constexpr char* kValidKey = - R"({"match/mirror_session_id":"mirror_session1"})"; - - std::vector invalid_src_ip_value = { - {prependParamField(p4orch::kSrcIp), "0123456789"}}; - EXPECT_FALSE( - DeserializeP4MirrorSessionAppDbEntry(kInalidKey, invalid_src_ip_value) - .ok()); - - std::vector invalid_dst_ip_value = { - {prependParamField(p4orch::kDstIp), "0123456789"}}; - EXPECT_FALSE( - DeserializeP4MirrorSessionAppDbEntry(kValidKey, invalid_dst_ip_value) - .ok()); - - std::vector invalid_src_mac_value = { - {prependParamField(p4orch::kSrcMac), "0123456789"}}; - EXPECT_FALSE( - DeserializeP4MirrorSessionAppDbEntry(kValidKey, invalid_src_mac_value) - .ok()); - - std::vector invalid_dst_mac_value = { - {prependParamField(p4orch::kDstMac), "0123456789"}}; - EXPECT_FALSE( - DeserializeP4MirrorSessionAppDbEntry(kValidKey, invalid_dst_mac_value) - .ok()); - - std::vector invalid_ttl_value = { - {prependParamField(p4orch::kTtl), "gpins"}}; - EXPECT_FALSE( - DeserializeP4MirrorSessionAppDbEntry(kValidKey, invalid_ttl_value).ok()); - - std::vector invalid_tos_value = { - {prependParamField(p4orch::kTos), "xyz"}}; - EXPECT_FALSE( - DeserializeP4MirrorSessionAppDbEntry(kValidKey, invalid_tos_value).ok()); - - std::vector unsupported_port = { - {prependParamField(p4orch::kPort), kPort2}}; - EXPECT_FALSE( - DeserializeP4MirrorSessionAppDbEntry(kValidKey, unsupported_port).ok()); - - std::vector invalid_action_value = { - {p4orch::kAction, "abc"}}; - EXPECT_FALSE( - DeserializeP4MirrorSessionAppDbEntry(kValidKey, invalid_action_value) - .ok()); +TEST_F(MirrorSessionManagerTest, DeserializeInvalidValueShouldFail) +{ + constexpr char *kInalidKey = R"({"invalid_key"})"; + std::vector fvs{{p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}}; + EXPECT_FALSE(DeserializeP4MirrorSessionAppDbEntry(kInalidKey, fvs).ok()); + + constexpr char *kValidKey = R"({"match/mirror_session_id":"mirror_session1"})"; + + std::vector invalid_src_ip_value = {{prependParamField(p4orch::kSrcIp), "0123456789"}}; + EXPECT_FALSE(DeserializeP4MirrorSessionAppDbEntry(kInalidKey, invalid_src_ip_value).ok()); + + std::vector invalid_dst_ip_value = {{prependParamField(p4orch::kDstIp), "0123456789"}}; + EXPECT_FALSE(DeserializeP4MirrorSessionAppDbEntry(kValidKey, invalid_dst_ip_value).ok()); + + std::vector invalid_src_mac_value = {{prependParamField(p4orch::kSrcMac), "0123456789"}}; + EXPECT_FALSE(DeserializeP4MirrorSessionAppDbEntry(kValidKey, invalid_src_mac_value).ok()); + + std::vector invalid_dst_mac_value = {{prependParamField(p4orch::kDstMac), "0123456789"}}; + EXPECT_FALSE(DeserializeP4MirrorSessionAppDbEntry(kValidKey, invalid_dst_mac_value).ok()); + + std::vector invalid_ttl_value = {{prependParamField(p4orch::kTtl), "gpins"}}; + EXPECT_FALSE(DeserializeP4MirrorSessionAppDbEntry(kValidKey, invalid_ttl_value).ok()); + + std::vector invalid_tos_value = {{prependParamField(p4orch::kTos), "xyz"}}; + EXPECT_FALSE(DeserializeP4MirrorSessionAppDbEntry(kValidKey, invalid_tos_value).ok()); + + std::vector unsupported_port = {{prependParamField(p4orch::kPort), kPort2}}; + EXPECT_FALSE(DeserializeP4MirrorSessionAppDbEntry(kValidKey, unsupported_port).ok()); + + std::vector invalid_action_value = {{p4orch::kAction, "abc"}}; + EXPECT_FALSE(DeserializeP4MirrorSessionAppDbEntry(kValidKey, invalid_action_value).ok()); } -TEST_F(MirrorSessionManagerTest, - CreateExistingMirrorSessionInMapperShouldFail) { - p4orch::P4MirrorSessionEntry mirror_session_entry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - kMirrorSessionOid, kMirrorSessionId, kPort1, swss::IpAddress(kSrcIp1), - swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), - swss::MacAddress(kDstMac1), kTtl1Num, kTos1Num); - - // Add this mirror session's oid to centralized mapper. - ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_MIRROR_SESSION, - mirror_session_entry.mirror_session_key, - mirror_session_entry.mirror_session_oid)); - - // TODO: Expect critical state. - EXPECT_FALSE(CreateMirrorSession(mirror_session_entry).ok()); +TEST_F(MirrorSessionManagerTest, CreateExistingMirrorSessionInMapperShouldFail) +{ + p4orch::P4MirrorSessionEntry mirror_session_entry( + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), kMirrorSessionOid, kMirrorSessionId, kPort1, + swss::IpAddress(kSrcIp1), swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), swss::MacAddress(kDstMac1), + kTtl1Num, kTos1Num); + + // Add this mirror session's oid to centralized mapper. + ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_MIRROR_SESSION, mirror_session_entry.mirror_session_key, + mirror_session_entry.mirror_session_oid)); + + // TODO: Expect critical state. + EXPECT_FALSE(CreateMirrorSession(mirror_session_entry).ok()); } -TEST_F(MirrorSessionManagerTest, CreateMirrorSessionWithInvalidPortShouldFail) { - // Non-existing port. - p4orch::P4MirrorSessionEntry mirror_session_entry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - kMirrorSessionOid, kMirrorSessionId, "Non-existing Port", - swss::IpAddress(kSrcIp1), swss::IpAddress(kDstIp1), - swss::MacAddress(kSrcMac1), swss::MacAddress(kDstMac1), kTtl1Num, - kTos1Num); +TEST_F(MirrorSessionManagerTest, CreateMirrorSessionWithInvalidPortShouldFail) +{ + // Non-existing port. + p4orch::P4MirrorSessionEntry mirror_session_entry( + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), kMirrorSessionOid, kMirrorSessionId, + "Non-existing Port", swss::IpAddress(kSrcIp1), swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), + swss::MacAddress(kDstMac1), kTtl1Num, kTos1Num); - EXPECT_FALSE(CreateMirrorSession(mirror_session_entry).ok()); + EXPECT_FALSE(CreateMirrorSession(mirror_session_entry).ok()); - // Unsupported management port. - mirror_session_entry.port = kPort2; - EXPECT_FALSE(CreateMirrorSession(mirror_session_entry).ok()); + // Unsupported management port. + mirror_session_entry.port = kPort2; + EXPECT_FALSE(CreateMirrorSession(mirror_session_entry).ok()); } -TEST_F(MirrorSessionManagerTest, UpdatingNonexistingMirrorSessionShouldFail) { - P4MirrorSessionAppDbEntry app_db_entry; - // Fail because existing_mirror_session_entry is nullptr. - // TODO: Expect critical state. - EXPECT_FALSE(ProcessUpdateRequest(app_db_entry, - /*existing_mirror_session_entry=*/nullptr) - .ok()); - - p4orch::P4MirrorSessionEntry existing_mirror_session_entry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - kMirrorSessionOid, kMirrorSessionId, kPort1, swss::IpAddress(kSrcIp1), - swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), - swss::MacAddress(kDstMac1), kTtl1Num, kTos1Num); - - // Fail because the mirror session is not added into centralized mapper. - // TODO: Expect critical state. - EXPECT_FALSE( - ProcessUpdateRequest(app_db_entry, &existing_mirror_session_entry).ok()); +TEST_F(MirrorSessionManagerTest, UpdatingNonexistingMirrorSessionShouldFail) +{ + P4MirrorSessionAppDbEntry app_db_entry; + // Fail because existing_mirror_session_entry is nullptr. + // TODO: Expect critical state. + EXPECT_FALSE(ProcessUpdateRequest(app_db_entry, + /*existing_mirror_session_entry=*/nullptr) + .ok()); + + p4orch::P4MirrorSessionEntry existing_mirror_session_entry( + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), kMirrorSessionOid, kMirrorSessionId, kPort1, + swss::IpAddress(kSrcIp1), swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), swss::MacAddress(kDstMac1), + kTtl1Num, kTos1Num); + + // Fail because the mirror session is not added into centralized mapper. + // TODO: Expect critical state. + EXPECT_FALSE(ProcessUpdateRequest(app_db_entry, &existing_mirror_session_entry).ok()); } -TEST_F(MirrorSessionManagerTest, UpdatingPortFailureCases) { - p4orch::P4MirrorSessionEntry existing_mirror_session_entry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - kMirrorSessionOid, kMirrorSessionId, kPort1, swss::IpAddress(kSrcIp1), - swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), - swss::MacAddress(kDstMac1), kTtl1Num, kTos1Num); - // Case 1: non-existing port. - EXPECT_FALSE(SetPort("invalid_port", &existing_mirror_session_entry).ok()); - - // Case 2: kPort2 is an unsupported management port. - EXPECT_FALSE(SetPort(kPort2, &existing_mirror_session_entry).ok()); - - // Case 3: SAI call failure. - EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - p4orch::P4MirrorSessionEntry existing_mirror_session_entry_before_update( - existing_mirror_session_entry); - EXPECT_FALSE(SetPort(kPort3, &existing_mirror_session_entry).ok()); - EXPECT_EQ(existing_mirror_session_entry, - existing_mirror_session_entry_before_update); +TEST_F(MirrorSessionManagerTest, UpdatingPortFailureCases) +{ + p4orch::P4MirrorSessionEntry existing_mirror_session_entry( + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), kMirrorSessionOid, kMirrorSessionId, kPort1, + swss::IpAddress(kSrcIp1), swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), swss::MacAddress(kDstMac1), + kTtl1Num, kTos1Num); + // Case 1: non-existing port. + EXPECT_FALSE(SetPort("invalid_port", &existing_mirror_session_entry).ok()); + + // Case 2: kPort2 is an unsupported management port. + EXPECT_FALSE(SetPort(kPort2, &existing_mirror_session_entry).ok()); + + // Case 3: SAI call failure. + EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)).WillOnce(Return(SAI_STATUS_FAILURE)); + p4orch::P4MirrorSessionEntry existing_mirror_session_entry_before_update(existing_mirror_session_entry); + EXPECT_FALSE(SetPort(kPort3, &existing_mirror_session_entry).ok()); + EXPECT_EQ(existing_mirror_session_entry, existing_mirror_session_entry_before_update); } -TEST_F(MirrorSessionManagerTest, UpdatingSrcIpSaiFailure) { - p4orch::P4MirrorSessionEntry existing_mirror_session_entry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - kMirrorSessionOid, kMirrorSessionId, kPort1, swss::IpAddress(kSrcIp1), - swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), - swss::MacAddress(kDstMac1), kTtl1Num, kTos1Num); - EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - p4orch::P4MirrorSessionEntry existing_mirror_session_entry_before_update( - existing_mirror_session_entry); - EXPECT_FALSE( - SetSrcIp(swss::IpAddress(kSrcIp2), &existing_mirror_session_entry).ok()); - EXPECT_EQ(existing_mirror_session_entry, - existing_mirror_session_entry_before_update); +TEST_F(MirrorSessionManagerTest, UpdatingSrcIpSaiFailure) +{ + p4orch::P4MirrorSessionEntry existing_mirror_session_entry( + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), kMirrorSessionOid, kMirrorSessionId, kPort1, + swss::IpAddress(kSrcIp1), swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), swss::MacAddress(kDstMac1), + kTtl1Num, kTos1Num); + EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)).WillOnce(Return(SAI_STATUS_FAILURE)); + p4orch::P4MirrorSessionEntry existing_mirror_session_entry_before_update(existing_mirror_session_entry); + EXPECT_FALSE(SetSrcIp(swss::IpAddress(kSrcIp2), &existing_mirror_session_entry).ok()); + EXPECT_EQ(existing_mirror_session_entry, existing_mirror_session_entry_before_update); } -TEST_F(MirrorSessionManagerTest, UpdatingDstIpSaiFailure) { - p4orch::P4MirrorSessionEntry existing_mirror_session_entry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - kMirrorSessionOid, kMirrorSessionId, kPort1, swss::IpAddress(kSrcIp1), - swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), - swss::MacAddress(kDstMac1), kTtl1Num, kTos1Num); - EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - p4orch::P4MirrorSessionEntry existing_mirror_session_entry_before_update( - existing_mirror_session_entry); - EXPECT_FALSE( - SetDstIp(swss::IpAddress(kDstIp2), &existing_mirror_session_entry).ok()); - EXPECT_EQ(existing_mirror_session_entry, - existing_mirror_session_entry_before_update); +TEST_F(MirrorSessionManagerTest, UpdatingDstIpSaiFailure) +{ + p4orch::P4MirrorSessionEntry existing_mirror_session_entry( + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), kMirrorSessionOid, kMirrorSessionId, kPort1, + swss::IpAddress(kSrcIp1), swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), swss::MacAddress(kDstMac1), + kTtl1Num, kTos1Num); + EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)).WillOnce(Return(SAI_STATUS_FAILURE)); + p4orch::P4MirrorSessionEntry existing_mirror_session_entry_before_update(existing_mirror_session_entry); + EXPECT_FALSE(SetDstIp(swss::IpAddress(kDstIp2), &existing_mirror_session_entry).ok()); + EXPECT_EQ(existing_mirror_session_entry, existing_mirror_session_entry_before_update); } -TEST_F(MirrorSessionManagerTest, UpdatingSrcMacSaiFailure) { - p4orch::P4MirrorSessionEntry existing_mirror_session_entry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - kMirrorSessionOid, kMirrorSessionId, kPort1, swss::IpAddress(kSrcIp1), - swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), - swss::MacAddress(kDstMac1), kTtl1Num, kTos1Num); - EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - p4orch::P4MirrorSessionEntry existing_mirror_session_entry_before_update( - existing_mirror_session_entry); - EXPECT_FALSE( - SetSrcMac(swss::MacAddress(kSrcMac2), &existing_mirror_session_entry) - .ok()); - EXPECT_EQ(existing_mirror_session_entry, - existing_mirror_session_entry_before_update); +TEST_F(MirrorSessionManagerTest, UpdatingSrcMacSaiFailure) +{ + p4orch::P4MirrorSessionEntry existing_mirror_session_entry( + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), kMirrorSessionOid, kMirrorSessionId, kPort1, + swss::IpAddress(kSrcIp1), swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), swss::MacAddress(kDstMac1), + kTtl1Num, kTos1Num); + EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)).WillOnce(Return(SAI_STATUS_FAILURE)); + p4orch::P4MirrorSessionEntry existing_mirror_session_entry_before_update(existing_mirror_session_entry); + EXPECT_FALSE(SetSrcMac(swss::MacAddress(kSrcMac2), &existing_mirror_session_entry).ok()); + EXPECT_EQ(existing_mirror_session_entry, existing_mirror_session_entry_before_update); } -TEST_F(MirrorSessionManagerTest, UpdatingDstMacSaiFailure) { - p4orch::P4MirrorSessionEntry existing_mirror_session_entry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - kMirrorSessionOid, kMirrorSessionId, kPort1, swss::IpAddress(kSrcIp1), - swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), - swss::MacAddress(kDstMac1), kTtl1Num, kTos1Num); - EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - p4orch::P4MirrorSessionEntry existing_mirror_session_entry_before_update( - existing_mirror_session_entry); - EXPECT_FALSE( - SetDstMac(swss::MacAddress(kDstMac2), &existing_mirror_session_entry) - .ok()); - EXPECT_EQ(existing_mirror_session_entry, - existing_mirror_session_entry_before_update); +TEST_F(MirrorSessionManagerTest, UpdatingDstMacSaiFailure) +{ + p4orch::P4MirrorSessionEntry existing_mirror_session_entry( + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), kMirrorSessionOid, kMirrorSessionId, kPort1, + swss::IpAddress(kSrcIp1), swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), swss::MacAddress(kDstMac1), + kTtl1Num, kTos1Num); + EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)).WillOnce(Return(SAI_STATUS_FAILURE)); + p4orch::P4MirrorSessionEntry existing_mirror_session_entry_before_update(existing_mirror_session_entry); + EXPECT_FALSE(SetDstMac(swss::MacAddress(kDstMac2), &existing_mirror_session_entry).ok()); + EXPECT_EQ(existing_mirror_session_entry, existing_mirror_session_entry_before_update); } -TEST_F(MirrorSessionManagerTest, UpdatingTtlSaiFailure) { - p4orch::P4MirrorSessionEntry existing_mirror_session_entry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - kMirrorSessionOid, kMirrorSessionId, kPort1, swss::IpAddress(kSrcIp1), - swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), - swss::MacAddress(kDstMac1), kTtl1Num, kTos1Num); - EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - p4orch::P4MirrorSessionEntry existing_mirror_session_entry_before_update( - existing_mirror_session_entry); - EXPECT_FALSE(SetTtl(kTtl2Num, &existing_mirror_session_entry).ok()); - EXPECT_EQ(existing_mirror_session_entry, - existing_mirror_session_entry_before_update); +TEST_F(MirrorSessionManagerTest, UpdatingTtlSaiFailure) +{ + p4orch::P4MirrorSessionEntry existing_mirror_session_entry( + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), kMirrorSessionOid, kMirrorSessionId, kPort1, + swss::IpAddress(kSrcIp1), swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), swss::MacAddress(kDstMac1), + kTtl1Num, kTos1Num); + EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)).WillOnce(Return(SAI_STATUS_FAILURE)); + p4orch::P4MirrorSessionEntry existing_mirror_session_entry_before_update(existing_mirror_session_entry); + EXPECT_FALSE(SetTtl(kTtl2Num, &existing_mirror_session_entry).ok()); + EXPECT_EQ(existing_mirror_session_entry, existing_mirror_session_entry_before_update); } -TEST_F(MirrorSessionManagerTest, UpdatingTosSaiFailure) { - p4orch::P4MirrorSessionEntry existing_mirror_session_entry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - kMirrorSessionOid, kMirrorSessionId, kPort1, swss::IpAddress(kSrcIp1), - swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), - swss::MacAddress(kDstMac1), kTtl1Num, kTos1Num); - EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - p4orch::P4MirrorSessionEntry existing_mirror_session_entry_before_update( - existing_mirror_session_entry); - EXPECT_FALSE(SetTos(kTos2Num, &existing_mirror_session_entry).ok()); - EXPECT_EQ(existing_mirror_session_entry, - existing_mirror_session_entry_before_update); +TEST_F(MirrorSessionManagerTest, UpdatingTosSaiFailure) +{ + p4orch::P4MirrorSessionEntry existing_mirror_session_entry( + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), kMirrorSessionOid, kMirrorSessionId, kPort1, + swss::IpAddress(kSrcIp1), swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), swss::MacAddress(kDstMac1), + kTtl1Num, kTos1Num); + EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)).WillOnce(Return(SAI_STATUS_FAILURE)); + p4orch::P4MirrorSessionEntry existing_mirror_session_entry_before_update(existing_mirror_session_entry); + EXPECT_FALSE(SetTos(kTos2Num, &existing_mirror_session_entry).ok()); + EXPECT_EQ(existing_mirror_session_entry, existing_mirror_session_entry_before_update); } // The update operation should be atomic -- it either succeeds or fails without // changing anything. This test case verifies that failed update operation // doesn't change existing entry. -TEST_F(MirrorSessionManagerTest, UpdateFailureShouldNotChangeExistingEntry) { - // 1. Add a new entry. - nlohmann::json j; - j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; - - std::vector fvs{ - {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, - {prependParamField(p4orch::kPort), kPort1}, - {prependParamField(p4orch::kSrcIp), kSrcIp1}, - {prependParamField(p4orch::kDstIp), kDstIp1}, - {prependParamField(p4orch::kSrcMac), kSrcMac1}, - {prependParamField(p4orch::kDstMac), kDstMac1}, - {prependParamField(p4orch::kTtl), kTtl1}, - {prependParamField(p4orch::kTos), kTos1}}; - - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + - j.dump(), - SET_COMMAND, fvs); - - Enqueue(app_db_entry); - // Set up mock call. - EXPECT_CALL(mock_sai_mirror_, create_mirror_session(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kMirrorSessionOid), - Return(SAI_STATUS_SUCCESS))); - Drain(); - - // Check the added entry. - auto mirror_entry = GetMirrorSessionEntry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - ASSERT_NE(mirror_entry, nullptr); - p4orch::P4MirrorSessionEntry expected_mirror_entry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - kMirrorSessionOid, kMirrorSessionId, kPort1, swss::IpAddress(kSrcIp1), - swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), - swss::MacAddress(kDstMac1), kTtl1Num, kTos1Num); - EXPECT_EQ(*mirror_entry, expected_mirror_entry); - - sai_object_id_t oid_in_mapper = 0; - EXPECT_TRUE(p4_oid_mapper_.getOID( - SAI_OBJECT_TYPE_MIRROR_SESSION, - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - &oid_in_mapper)); - EXPECT_EQ(kMirrorSessionOid, oid_in_mapper); - - // 2. Update the added entry. - fvs = {{p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, - {prependParamField(p4orch::kPort), kPort3}, - {prependParamField(p4orch::kSrcIp), kSrcIp2}, - {prependParamField(p4orch::kDstIp), kDstIp2}, - {prependParamField(p4orch::kSrcMac), kSrcMac2}, - {prependParamField(p4orch::kDstMac), kDstMac2}, - {prependParamField(p4orch::kTtl), kTtl2}, - {prependParamField(p4orch::kTos), kTos2}}; - - app_db_entry = {std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + - kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs}; - - Enqueue(app_db_entry); - // Set up mock calls. Update entry will trigger 7 attribute updates and each - // attribute update requires a seperate SAI call. Let's pass the first 6 SAI - // calls and fail the last one. When update fails in the middle, 6 successful - // attribute updates will be reverted one by one. So the set SAI call wil be - // called 13 times and actions are 6 successes, 1 failure, 6successes. - EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)) - .Times(13) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_FAILURE)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - - Drain(); - - mirror_entry = GetMirrorSessionEntry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - ASSERT_NE(mirror_entry, nullptr); - EXPECT_EQ(*mirror_entry, expected_mirror_entry); +TEST_F(MirrorSessionManagerTest, UpdateFailureShouldNotChangeExistingEntry) +{ + // 1. Add a new entry. + nlohmann::json j; + j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; + + std::vector fvs{ + {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, {prependParamField(p4orch::kPort), kPort1}, + {prependParamField(p4orch::kSrcIp), kSrcIp1}, {prependParamField(p4orch::kDstIp), kDstIp1}, + {prependParamField(p4orch::kSrcMac), kSrcMac1}, {prependParamField(p4orch::kDstMac), kDstMac1}, + {prependParamField(p4orch::kTtl), kTtl1}, {prependParamField(p4orch::kTos), kTos1}}; + + swss::KeyOpFieldsValuesTuple app_db_entry( + std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs); + + Enqueue(app_db_entry); + // Set up mock call. + EXPECT_CALL(mock_sai_mirror_, create_mirror_session(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kMirrorSessionOid), Return(SAI_STATUS_SUCCESS))); + Drain(); + + // Check the added entry. + auto mirror_entry = GetMirrorSessionEntry(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + ASSERT_NE(mirror_entry, nullptr); + p4orch::P4MirrorSessionEntry expected_mirror_entry( + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), kMirrorSessionOid, kMirrorSessionId, kPort1, + swss::IpAddress(kSrcIp1), swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), swss::MacAddress(kDstMac1), + kTtl1Num, kTos1Num); + EXPECT_EQ(*mirror_entry, expected_mirror_entry); + + sai_object_id_t oid_in_mapper = 0; + EXPECT_TRUE(p4_oid_mapper_.getOID(SAI_OBJECT_TYPE_MIRROR_SESSION, + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), &oid_in_mapper)); + EXPECT_EQ(kMirrorSessionOid, oid_in_mapper); + + // 2. Update the added entry. + fvs = {{p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, {prependParamField(p4orch::kPort), kPort3}, + {prependParamField(p4orch::kSrcIp), kSrcIp2}, {prependParamField(p4orch::kDstIp), kDstIp2}, + {prependParamField(p4orch::kSrcMac), kSrcMac2}, {prependParamField(p4orch::kDstMac), kDstMac2}, + {prependParamField(p4orch::kTtl), kTtl2}, {prependParamField(p4orch::kTos), kTos2}}; + + app_db_entry = {std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs}; + + Enqueue(app_db_entry); + // Set up mock calls. Update entry will trigger 7 attribute updates and each + // attribute update requires a seperate SAI call. Let's pass the first 6 SAI + // calls and fail the last one. When update fails in the middle, 6 successful + // attribute updates will be reverted one by one. So the set SAI call wil be + // called 13 times and actions are 6 successes, 1 failure, 6successes. + EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)) + .Times(13) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_FAILURE)) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + + Drain(); + + mirror_entry = GetMirrorSessionEntry(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + ASSERT_NE(mirror_entry, nullptr); + EXPECT_EQ(*mirror_entry, expected_mirror_entry); } -TEST_F(MirrorSessionManagerTest, - UpdateRecoveryFailureShouldRaiseCriticalState) { - // 1. Add a new entry. - nlohmann::json j; - j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; - - std::vector fvs{ - {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, - {prependParamField(p4orch::kPort), kPort1}, - {prependParamField(p4orch::kSrcIp), kSrcIp1}, - {prependParamField(p4orch::kDstIp), kDstIp1}, - {prependParamField(p4orch::kSrcMac), kSrcMac1}, - {prependParamField(p4orch::kDstMac), kDstMac1}, - {prependParamField(p4orch::kTtl), kTtl1}, - {prependParamField(p4orch::kTos), kTos1}}; - - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + - j.dump(), - SET_COMMAND, fvs); - - Enqueue(app_db_entry); - // Set up mock call. - EXPECT_CALL(mock_sai_mirror_, create_mirror_session(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kMirrorSessionOid), - Return(SAI_STATUS_SUCCESS))); - Drain(); - - // Check the added entry. - auto mirror_entry = GetMirrorSessionEntry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - ASSERT_NE(mirror_entry, nullptr); - p4orch::P4MirrorSessionEntry expected_mirror_entry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - kMirrorSessionOid, kMirrorSessionId, kPort1, swss::IpAddress(kSrcIp1), - swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), - swss::MacAddress(kDstMac1), kTtl1Num, kTos1Num); - EXPECT_EQ(*mirror_entry, expected_mirror_entry); - - sai_object_id_t oid_in_mapper = 0; - EXPECT_TRUE(p4_oid_mapper_.getOID( - SAI_OBJECT_TYPE_MIRROR_SESSION, - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - &oid_in_mapper)); - EXPECT_EQ(kMirrorSessionOid, oid_in_mapper); - - // 2. Update the added entry. - fvs = {{p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, - {prependParamField(p4orch::kPort), kPort3}, - {prependParamField(p4orch::kSrcIp), kSrcIp2}, - {prependParamField(p4orch::kDstIp), kDstIp2}, - {prependParamField(p4orch::kSrcMac), kSrcMac2}, - {prependParamField(p4orch::kDstMac), kDstMac2}, - {prependParamField(p4orch::kTtl), kTtl2}, - {prependParamField(p4orch::kTos), kTos2}}; - - app_db_entry = {std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + - kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs}; - - Enqueue(app_db_entry); - // Set up mock calls. Update entry will trigger 7 attribute updates and each - // attribute update requires a seperate SAI call. Let's pass the first 6 SAI - // calls and fail the last one. When update fails in the middle, 6 successful - // attribute updates will be reverted one by one. We will fail the recovery by - // failing the last revert. - EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)) - .Times(13) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_FAILURE)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_SUCCESS)) - .WillOnce(Return(SAI_STATUS_FAILURE)); - // TODO: Expect critical state. - - Drain(); - - mirror_entry = GetMirrorSessionEntry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - ASSERT_NE(mirror_entry, nullptr); +TEST_F(MirrorSessionManagerTest, UpdateRecoveryFailureShouldRaiseCriticalState) +{ + // 1. Add a new entry. + nlohmann::json j; + j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; + + std::vector fvs{ + {p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, {prependParamField(p4orch::kPort), kPort1}, + {prependParamField(p4orch::kSrcIp), kSrcIp1}, {prependParamField(p4orch::kDstIp), kDstIp1}, + {prependParamField(p4orch::kSrcMac), kSrcMac1}, {prependParamField(p4orch::kDstMac), kDstMac1}, + {prependParamField(p4orch::kTtl), kTtl1}, {prependParamField(p4orch::kTos), kTos1}}; + + swss::KeyOpFieldsValuesTuple app_db_entry( + std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs); + + Enqueue(app_db_entry); + // Set up mock call. + EXPECT_CALL(mock_sai_mirror_, create_mirror_session(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kMirrorSessionOid), Return(SAI_STATUS_SUCCESS))); + Drain(); + + // Check the added entry. + auto mirror_entry = GetMirrorSessionEntry(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + ASSERT_NE(mirror_entry, nullptr); + p4orch::P4MirrorSessionEntry expected_mirror_entry( + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), kMirrorSessionOid, kMirrorSessionId, kPort1, + swss::IpAddress(kSrcIp1), swss::IpAddress(kDstIp1), swss::MacAddress(kSrcMac1), swss::MacAddress(kDstMac1), + kTtl1Num, kTos1Num); + EXPECT_EQ(*mirror_entry, expected_mirror_entry); + + sai_object_id_t oid_in_mapper = 0; + EXPECT_TRUE(p4_oid_mapper_.getOID(SAI_OBJECT_TYPE_MIRROR_SESSION, + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), &oid_in_mapper)); + EXPECT_EQ(kMirrorSessionOid, oid_in_mapper); + + // 2. Update the added entry. + fvs = {{p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}, {prependParamField(p4orch::kPort), kPort3}, + {prependParamField(p4orch::kSrcIp), kSrcIp2}, {prependParamField(p4orch::kDstIp), kDstIp2}, + {prependParamField(p4orch::kSrcMac), kSrcMac2}, {prependParamField(p4orch::kDstMac), kDstMac2}, + {prependParamField(p4orch::kTtl), kTtl2}, {prependParamField(p4orch::kTos), kTos2}}; + + app_db_entry = {std::string(APP_P4RT_MIRROR_SESSION_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs}; + + Enqueue(app_db_entry); + // Set up mock calls. Update entry will trigger 7 attribute updates and each + // attribute update requires a seperate SAI call. Let's pass the first 6 SAI + // calls and fail the last one. When update fails in the middle, 6 successful + // attribute updates will be reverted one by one. We will fail the recovery by + // failing the last revert. + EXPECT_CALL(mock_sai_mirror_, set_mirror_session_attribute(_, _)) + .Times(13) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_FAILURE)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_SUCCESS)) + .WillOnce(Return(SAI_STATUS_FAILURE)); + // TODO: Expect critical state. + + Drain(); + + mirror_entry = GetMirrorSessionEntry(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + ASSERT_NE(mirror_entry, nullptr); } -TEST_F(MirrorSessionManagerTest, DeleteNonExistingMirrorSessionShouldFail) { - ASSERT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessDeleteRequest( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId))); +TEST_F(MirrorSessionManagerTest, DeleteNonExistingMirrorSessionShouldFail) +{ + ASSERT_EQ(StatusCode::SWSS_RC_NOT_FOUND, + ProcessDeleteRequest(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId))); } -TEST_F(MirrorSessionManagerTest, DeleteMirrorSessionWithNonZeroRefShouldFail) { - AddDefaultMirrorSection(); - p4_oid_mapper_.increaseRefCount( - SAI_OBJECT_TYPE_MIRROR_SESSION, - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - ASSERT_EQ(StatusCode::SWSS_RC_IN_USE, - ProcessDeleteRequest( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId))); +TEST_F(MirrorSessionManagerTest, DeleteMirrorSessionWithNonZeroRefShouldFail) +{ + AddDefaultMirrorSection(); + p4_oid_mapper_.increaseRefCount(SAI_OBJECT_TYPE_MIRROR_SESSION, + KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + ASSERT_EQ(StatusCode::SWSS_RC_IN_USE, + ProcessDeleteRequest(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId))); } -TEST_F(MirrorSessionManagerTest, DeleteMirrorSessionNotInMapperShouldFail) { - AddDefaultMirrorSection(); - p4_oid_mapper_.eraseOID( - SAI_OBJECT_TYPE_MIRROR_SESSION, - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - // TODO: Expect critical state. - ASSERT_EQ(StatusCode::SWSS_RC_INTERNAL, - ProcessDeleteRequest( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId))); +TEST_F(MirrorSessionManagerTest, DeleteMirrorSessionNotInMapperShouldFail) +{ + AddDefaultMirrorSection(); + p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_MIRROR_SESSION, KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + // TODO: Expect critical state. + ASSERT_EQ(StatusCode::SWSS_RC_INTERNAL, + ProcessDeleteRequest(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId))); } -TEST_F(MirrorSessionManagerTest, VerifyStateTest) { - AddDefaultMirrorSection(); - nlohmann::json j; - j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; - const std::string db_key = - std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + - APP_P4RT_MIRROR_SESSION_TABLE_NAME + kTableKeyDelimiter + j.dump(); - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set( - "SAI_OBJECT_TYPE_MIRROR_SESSION:oid:0x445566", - std::vector{ - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT", - "oid:0x112233"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TYPE", - "SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE"}, - swss::FieldValueTuple{ - "SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE", - "SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION", "4"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TOS", "0"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TTL", "64"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS", - "10.206.196.31"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS", - "172.20.0.203"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS", - "00:02:03:04:05:06"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS", - "00:1A:11:17:5F:80"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE", - "35006"}, - }); - std::vector attributes; - - // Verification should succeed with vaild key and value. - attributes.push_back( - swss::FieldValueTuple{p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kPort), kPort1}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kSrcIp), kSrcIp1}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kDstIp), kDstIp1}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), kSrcMac1}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kDstMac), kDstMac1}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kTtl), kTtl1}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kTos), kTos1}); - EXPECT_EQ(VerifyState(db_key, attributes), ""); - - // Invalid key should fail verification. - EXPECT_FALSE(VerifyState("invalid", attributes).empty()); - EXPECT_FALSE(VerifyState("invalid:invalid", attributes).empty()); - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes) - .empty()); - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", - attributes) - .empty()); - EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + - ":FIXED_MIRROR_SESSION_TABLE:invalid", - attributes) - .empty()); - - // Verification should fail if entry does not exist. - j[prependMatchField(p4orch::kMirrorSessionId)] = "invalid"; - EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + - APP_P4RT_MIRROR_SESSION_TABLE_NAME + - kTableKeyDelimiter + j.dump(), - attributes) - .empty()); - - auto* mirror_entry = GetMirrorSessionEntry( - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - ASSERT_NE(mirror_entry, nullptr); - - // Verification should fail if mirror section key mismatches. - auto saved_mirror_session_key = mirror_entry->mirror_session_key; - mirror_entry->mirror_session_key = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - mirror_entry->mirror_session_key = saved_mirror_session_key; - - // Verification should fail if mirror section ID mismatches. - auto saved_mirror_session_id = mirror_entry->mirror_session_id; - mirror_entry->mirror_session_id = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - mirror_entry->mirror_session_id = saved_mirror_session_id; - - // Verification should fail if port mismatches. - auto saved_port = mirror_entry->port; - mirror_entry->port = kPort2; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - mirror_entry->port = saved_port; - - // Verification should fail if source IP mismatches. - auto saved_src_ip = mirror_entry->src_ip; - mirror_entry->src_ip = swss::IpAddress(kSrcIp2); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - mirror_entry->src_ip = saved_src_ip; - - // Verification should fail if dest IP mismatches. - auto saved_dst_ip = mirror_entry->dst_ip; - mirror_entry->dst_ip = swss::IpAddress(kDstIp2); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - mirror_entry->dst_ip = saved_dst_ip; - - // Verification should fail if source MAC mismatches. - auto saved_src_mac = mirror_entry->src_mac; - mirror_entry->src_mac = swss::MacAddress(kSrcMac2); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - mirror_entry->src_mac = saved_src_mac; - - // Verification should fail if dest MAC mismatches. - auto saved_dst_mac = mirror_entry->dst_mac; - mirror_entry->dst_mac = swss::MacAddress(kDstMac2); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - mirror_entry->dst_mac = saved_dst_mac; - - // Verification should fail if ttl mismatches. - auto saved_ttl = mirror_entry->ttl; - mirror_entry->ttl = kTtl2Num; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - mirror_entry->ttl = saved_ttl; - - // Verification should fail if tos mismatches. - auto saved_tos = mirror_entry->tos; - mirror_entry->tos = kTos2Num; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - mirror_entry->tos = saved_tos; - - // Verification should fail if OID mapper mismatches. - p4_oid_mapper_.eraseOID( - SAI_OBJECT_TYPE_MIRROR_SESSION, - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_MIRROR_SESSION, - KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), - kMirrorSessionOid); +TEST_F(MirrorSessionManagerTest, VerifyStateTest) +{ + AddDefaultMirrorSection(); + nlohmann::json j; + j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + + APP_P4RT_MIRROR_SESSION_TABLE_NAME + kTableKeyDelimiter + j.dump(); + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set("SAI_OBJECT_TYPE_MIRROR_SESSION:oid:0x445566", + std::vector{ + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT", "oid:0x112233"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TYPE", "SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE", + "SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION", "4"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TOS", "0"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TTL", "64"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS", "10.206.196.31"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS", "172.20.0.203"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS", "00:02:03:04:05:06"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS", "00:1A:11:17:5F:80"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE", "35006"}, + }); + std::vector attributes; + + // Verification should succeed with vaild key and value. + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kPort), kPort1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcIp), kSrcIp1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kDstIp), kDstIp1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), kSrcMac1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kDstMac), kDstMac1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kTtl), kTtl1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kTos), kTos1}); + EXPECT_EQ(VerifyState(db_key, attributes), ""); + + // Invalid key should fail verification. + EXPECT_FALSE(VerifyState("invalid", attributes).empty()); + EXPECT_FALSE(VerifyState("invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", attributes).empty()); + EXPECT_FALSE( + VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":FIXED_MIRROR_SESSION_TABLE:invalid", attributes).empty()); + + // Verification should fail if entry does not exist. + j[prependMatchField(p4orch::kMirrorSessionId)] = "invalid"; + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + + APP_P4RT_MIRROR_SESSION_TABLE_NAME + kTableKeyDelimiter + j.dump(), + attributes) + .empty()); + + auto *mirror_entry = GetMirrorSessionEntry(KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + ASSERT_NE(mirror_entry, nullptr); + + // Verification should fail if mirror section key mismatches. + auto saved_mirror_session_key = mirror_entry->mirror_session_key; + mirror_entry->mirror_session_key = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + mirror_entry->mirror_session_key = saved_mirror_session_key; + + // Verification should fail if mirror section ID mismatches. + auto saved_mirror_session_id = mirror_entry->mirror_session_id; + mirror_entry->mirror_session_id = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + mirror_entry->mirror_session_id = saved_mirror_session_id; + + // Verification should fail if port mismatches. + auto saved_port = mirror_entry->port; + mirror_entry->port = kPort2; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + mirror_entry->port = saved_port; + + // Verification should fail if source IP mismatches. + auto saved_src_ip = mirror_entry->src_ip; + mirror_entry->src_ip = swss::IpAddress(kSrcIp2); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + mirror_entry->src_ip = saved_src_ip; + + // Verification should fail if dest IP mismatches. + auto saved_dst_ip = mirror_entry->dst_ip; + mirror_entry->dst_ip = swss::IpAddress(kDstIp2); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + mirror_entry->dst_ip = saved_dst_ip; + + // Verification should fail if source MAC mismatches. + auto saved_src_mac = mirror_entry->src_mac; + mirror_entry->src_mac = swss::MacAddress(kSrcMac2); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + mirror_entry->src_mac = saved_src_mac; + + // Verification should fail if dest MAC mismatches. + auto saved_dst_mac = mirror_entry->dst_mac; + mirror_entry->dst_mac = swss::MacAddress(kDstMac2); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + mirror_entry->dst_mac = saved_dst_mac; + + // Verification should fail if ttl mismatches. + auto saved_ttl = mirror_entry->ttl; + mirror_entry->ttl = kTtl2Num; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + mirror_entry->ttl = saved_ttl; + + // Verification should fail if tos mismatches. + auto saved_tos = mirror_entry->tos; + mirror_entry->tos = kTos2Num; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + mirror_entry->tos = saved_tos; + + // Verification should fail if OID mapper mismatches. + p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_MIRROR_SESSION, KeyGenerator::generateMirrorSessionKey(kMirrorSessionId)); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_MIRROR_SESSION, KeyGenerator::generateMirrorSessionKey(kMirrorSessionId), + kMirrorSessionOid); } -TEST_F(MirrorSessionManagerTest, VerifyStateAsicDbTest) { - AddDefaultMirrorSection(); - nlohmann::json j; - j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; - const std::string db_key = - std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + - APP_P4RT_MIRROR_SESSION_TABLE_NAME + kTableKeyDelimiter + j.dump(); - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set( - "SAI_OBJECT_TYPE_MIRROR_SESSION:oid:0x445566", - std::vector{ - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT", - "oid:0x112233"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TYPE", - "SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE"}, - swss::FieldValueTuple{ - "SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE", - "SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION", "4"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TOS", "0"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TTL", "64"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS", - "10.206.196.31"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS", - "172.20.0.203"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS", - "00:02:03:04:05:06"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS", - "00:1A:11:17:5F:80"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE", - "35006"}, - }); - - std::vector attributes; - - // Verification should succeed with vaild key and value. - attributes.push_back( - swss::FieldValueTuple{p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kPort), kPort1}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kSrcIp), kSrcIp1}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kDstIp), kDstIp1}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), kSrcMac1}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kDstMac), kDstMac1}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kTtl), kTtl1}); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kTos), kTos1}); - - EXPECT_EQ(VerifyState(db_key, attributes), ""); - - // set differenet SRC IP ADDR and expect the VerifyState to fail - table.set("SAI_OBJECT_TYPE_MIRROR_SESSION:oid:0x445566", - std::vector{swss::FieldValueTuple{ - "SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS", "10.206.196.32"}}); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - - // Delete the ASIC DB entry and expect the VerifyState to fail - table.del("SAI_OBJECT_TYPE_MIRROR_SESSION:oid:0x445566"); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - - // Restore the ASIC DB entry - table.set( - "SAI_OBJECT_TYPE_MIRROR_SESSION:oid:0x445566", - std::vector{ - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT", - "oid:0x112233"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TYPE", - "SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE"}, - swss::FieldValueTuple{ - "SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE", - "SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION", "4"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TOS", "0"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TTL", "64"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS", - "10.206.196.31"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS", - "172.20.0.203"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS", - "00:02:03:04:05:06"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS", - "00:1A:11:17:5F:80"}, - swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE", - "35006"}, - }); +TEST_F(MirrorSessionManagerTest, VerifyStateAsicDbTest) +{ + AddDefaultMirrorSection(); + nlohmann::json j; + j[prependMatchField(p4orch::kMirrorSessionId)] = kMirrorSessionId; + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + + APP_P4RT_MIRROR_SESSION_TABLE_NAME + kTableKeyDelimiter + j.dump(); + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set("SAI_OBJECT_TYPE_MIRROR_SESSION:oid:0x445566", + std::vector{ + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT", "oid:0x112233"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TYPE", "SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE", + "SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION", "4"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TOS", "0"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TTL", "64"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS", "10.206.196.31"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS", "172.20.0.203"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS", "00:02:03:04:05:06"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS", "00:1A:11:17:5F:80"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE", "35006"}, + }); + + std::vector attributes; + + // Verification should succeed with vaild key and value. + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kMirrorAsIpv4Erspan}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kPort), kPort1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcIp), kSrcIp1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kDstIp), kDstIp1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), kSrcMac1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kDstMac), kDstMac1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kTtl), kTtl1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kTos), kTos1}); + + EXPECT_EQ(VerifyState(db_key, attributes), ""); + + // set differenet SRC IP ADDR and expect the VerifyState to fail + table.set("SAI_OBJECT_TYPE_MIRROR_SESSION:oid:0x445566", + std::vector{ + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS", "10.206.196.32"}}); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + + // Delete the ASIC DB entry and expect the VerifyState to fail + table.del("SAI_OBJECT_TYPE_MIRROR_SESSION:oid:0x445566"); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + + // Restore the ASIC DB entry + table.set("SAI_OBJECT_TYPE_MIRROR_SESSION:oid:0x445566", + std::vector{ + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_MONITOR_PORT", "oid:0x112233"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TYPE", "SAI_MIRROR_SESSION_TYPE_ENHANCED_REMOTE"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_ERSPAN_ENCAPSULATION_TYPE", + "SAI_ERSPAN_ENCAPSULATION_TYPE_MIRROR_L3_GRE_TUNNEL"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_IPHDR_VERSION", "4"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TOS", "0"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_TTL", "64"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_SRC_IP_ADDRESS", "10.206.196.31"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_DST_IP_ADDRESS", "172.20.0.203"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_SRC_MAC_ADDRESS", "00:02:03:04:05:06"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_DST_MAC_ADDRESS", "00:1A:11:17:5F:80"}, + swss::FieldValueTuple{"SAI_MIRROR_SESSION_ATTR_GRE_PROTOCOL_TYPE", "35006"}, + }); } -} // namespace test -} // namespace p4orch +} // namespace test +} // namespace p4orch diff --git a/orchagent/p4orch/tests/mock_response_publisher.h b/orchagent/p4orch/tests/mock_response_publisher.h index c17f5223d0e..d163333bd07 100644 --- a/orchagent/p4orch/tests/mock_response_publisher.h +++ b/orchagent/p4orch/tests/mock_response_publisher.h @@ -4,19 +4,16 @@ #include "response_publisher_interface.h" -class MockResponsePublisher : public ResponsePublisherInterface { - public: - MOCK_METHOD6(publish, - void(const std::string& table, const std::string& key, - const std::vector& intent_attrs, - const ReturnCode& status, - const std::vector& state_attrs, - bool replace)); - MOCK_METHOD5(publish, - void(const std::string& table, const std::string& key, - const std::vector& intent_attrs, - const ReturnCode& status, bool replace)); - MOCK_METHOD5(writeToDB, void(const std::string& table, const std::string& key, - const std::vector& values, - const std::string& op, bool replace)); +class MockResponsePublisher : public ResponsePublisherInterface +{ + public: + MOCK_METHOD6(publish, void(const std::string &table, const std::string &key, + const std::vector &intent_attrs, const ReturnCode &status, + const std::vector &state_attrs, bool replace)); + MOCK_METHOD5(publish, + void(const std::string &table, const std::string &key, + const std::vector &intent_attrs, const ReturnCode &status, bool replace)); + MOCK_METHOD5(writeToDB, + void(const std::string &table, const std::string &key, + const std::vector &values, const std::string &op, bool replace)); }; diff --git a/orchagent/p4orch/tests/mock_sai_acl.cpp b/orchagent/p4orch/tests/mock_sai_acl.cpp index 43d39e115c1..531a71b3a5b 100644 --- a/orchagent/p4orch/tests/mock_sai_acl.cpp +++ b/orchagent/p4orch/tests/mock_sai_acl.cpp @@ -1,72 +1,68 @@ #include "mock_sai_acl.h" -MockSaiAcl* mock_sai_acl; +MockSaiAcl *mock_sai_acl; -sai_status_t create_acl_table(sai_object_id_t* acl_table_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list) { - return mock_sai_acl->create_acl_table(acl_table_id, switch_id, attr_count, - attr_list); +sai_status_t create_acl_table(sai_object_id_t *acl_table_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) +{ + return mock_sai_acl->create_acl_table(acl_table_id, switch_id, attr_count, attr_list); } -sai_status_t remove_acl_table(sai_object_id_t acl_table_id) { - return mock_sai_acl->remove_acl_table(acl_table_id); +sai_status_t remove_acl_table(sai_object_id_t acl_table_id) +{ + return mock_sai_acl->remove_acl_table(acl_table_id); } -sai_status_t create_acl_table_group(sai_object_id_t* acl_table_group_id, - sai_object_id_t switch_id, - uint32_t attr_count, - const sai_attribute_t* attr_list) { - return mock_sai_acl->create_acl_table_group(acl_table_group_id, switch_id, - attr_count, attr_list); +sai_status_t create_acl_table_group(sai_object_id_t *acl_table_group_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) +{ + return mock_sai_acl->create_acl_table_group(acl_table_group_id, switch_id, attr_count, attr_list); } -sai_status_t remove_acl_table_group(sai_object_id_t acl_table_group_id) { - return mock_sai_acl->remove_acl_table_group(acl_table_group_id); +sai_status_t remove_acl_table_group(sai_object_id_t acl_table_group_id) +{ + return mock_sai_acl->remove_acl_table_group(acl_table_group_id); } -sai_status_t create_acl_table_group_member( - sai_object_id_t* acl_table_group_member_id, sai_object_id_t switch_id, - uint32_t attr_count, const sai_attribute_t* attr_list) { - return mock_sai_acl->create_acl_table_group_member( - acl_table_group_member_id, switch_id, attr_count, attr_list); +sai_status_t create_acl_table_group_member(sai_object_id_t *acl_table_group_member_id, sai_object_id_t switch_id, + uint32_t attr_count, const sai_attribute_t *attr_list) +{ + return mock_sai_acl->create_acl_table_group_member(acl_table_group_member_id, switch_id, attr_count, attr_list); } -sai_status_t remove_acl_table_group_member( - sai_object_id_t acl_table_group_member_id) { - return mock_sai_acl->remove_acl_table_group_member(acl_table_group_member_id); +sai_status_t remove_acl_table_group_member(sai_object_id_t acl_table_group_member_id) +{ + return mock_sai_acl->remove_acl_table_group_member(acl_table_group_member_id); } -sai_status_t create_acl_entry(sai_object_id_t* acl_entry_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list) { - return mock_sai_acl->create_acl_entry(acl_entry_id, switch_id, attr_count, - attr_list); +sai_status_t create_acl_entry(sai_object_id_t *acl_entry_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) +{ + return mock_sai_acl->create_acl_entry(acl_entry_id, switch_id, attr_count, attr_list); } -sai_status_t remove_acl_entry(sai_object_id_t acl_entry_id) { - return mock_sai_acl->remove_acl_entry(acl_entry_id); +sai_status_t remove_acl_entry(sai_object_id_t acl_entry_id) +{ + return mock_sai_acl->remove_acl_entry(acl_entry_id); } -sai_status_t create_acl_counter(sai_object_id_t* acl_counter_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list) { - return mock_sai_acl->create_acl_counter(acl_counter_id, switch_id, attr_count, - attr_list); +sai_status_t create_acl_counter(sai_object_id_t *acl_counter_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) +{ + return mock_sai_acl->create_acl_counter(acl_counter_id, switch_id, attr_count, attr_list); } -sai_status_t remove_acl_counter(sai_object_id_t acl_counter_id) { - return mock_sai_acl->remove_acl_counter(acl_counter_id); +sai_status_t remove_acl_counter(sai_object_id_t acl_counter_id) +{ + return mock_sai_acl->remove_acl_counter(acl_counter_id); } -sai_status_t get_acl_counter_attribute(sai_object_id_t acl_counter_id, - uint32_t attr_count, - sai_attribute_t* attr_list) { - return mock_sai_acl->get_acl_counter_attribute(acl_counter_id, attr_count, - attr_list); +sai_status_t get_acl_counter_attribute(sai_object_id_t acl_counter_id, uint32_t attr_count, sai_attribute_t *attr_list) +{ + return mock_sai_acl->get_acl_counter_attribute(acl_counter_id, attr_count, attr_list); } -sai_status_t set_acl_entry_attribute(sai_object_id_t acl_entry_id, - const sai_attribute_t* attr) { - return mock_sai_acl->set_acl_entry_attribute(acl_entry_id, attr); +sai_status_t set_acl_entry_attribute(sai_object_id_t acl_entry_id, const sai_attribute_t *attr) +{ + return mock_sai_acl->set_acl_entry_attribute(acl_entry_id, attr); } diff --git a/orchagent/p4orch/tests/mock_sai_acl.h b/orchagent/p4orch/tests/mock_sai_acl.h index ceba57a4a52..252eb1768a8 100644 --- a/orchagent/p4orch/tests/mock_sai_acl.h +++ b/orchagent/p4orch/tests/mock_sai_acl.h @@ -1,121 +1,87 @@ #include -extern "C" { +extern "C" +{ #include "sai.h" #include "saiacl.h" } -class SaiAclInterface { - public: - virtual sai_status_t create_acl_table(sai_object_id_t* acl_table_id, - sai_object_id_t switch_id, - uint32_t attr_count, - const sai_attribute_t* attr_list) = 0; - virtual sai_status_t remove_acl_table(sai_object_id_t acl_table_id) = 0; - virtual sai_status_t create_acl_table_group( - sai_object_id_t* acl_table_group_id, sai_object_id_t switch_id, - uint32_t attr_count, const sai_attribute_t* attr_list) = 0; - virtual sai_status_t remove_acl_table_group( - sai_object_id_t acl_table_group_id) = 0; - virtual sai_status_t create_acl_table_group_member( - sai_object_id_t* acl_table_group_member_id, sai_object_id_t switch_id, - uint32_t attr_count, const sai_attribute_t* attr_list) = 0; - virtual sai_status_t remove_acl_table_group_member( - sai_object_id_t acl_table_group_member_id) = 0; - - virtual sai_status_t create_acl_entry(sai_object_id_t* acl_entry_id, - sai_object_id_t switch_id, - uint32_t attr_count, - const sai_attribute_t* attr_list) = 0; - virtual sai_status_t remove_acl_entry(sai_object_id_t acl_entry_id) = 0; - virtual sai_status_t create_acl_counter(sai_object_id_t* acl_counter_id, - sai_object_id_t switch_id, - uint32_t attr_count, - const sai_attribute_t* attr_list) = 0; - virtual sai_status_t remove_acl_counter(sai_object_id_t acl_counter_id) = 0; - virtual sai_status_t get_acl_counter_attribute( - sai_object_id_t acl_counter_id, uint32_t attr_count, - sai_attribute_t* attr_list) = 0; - virtual sai_status_t set_acl_entry_attribute(sai_object_id_t acl_entry_id, - const sai_attribute_t* attr) = 0; +class SaiAclInterface +{ + public: + virtual sai_status_t create_acl_table(sai_object_id_t *acl_table_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) = 0; + virtual sai_status_t remove_acl_table(sai_object_id_t acl_table_id) = 0; + virtual sai_status_t create_acl_table_group(sai_object_id_t *acl_table_group_id, sai_object_id_t switch_id, + uint32_t attr_count, const sai_attribute_t *attr_list) = 0; + virtual sai_status_t remove_acl_table_group(sai_object_id_t acl_table_group_id) = 0; + virtual sai_status_t create_acl_table_group_member(sai_object_id_t *acl_table_group_member_id, + sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) = 0; + virtual sai_status_t remove_acl_table_group_member(sai_object_id_t acl_table_group_member_id) = 0; + + virtual sai_status_t create_acl_entry(sai_object_id_t *acl_entry_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) = 0; + virtual sai_status_t remove_acl_entry(sai_object_id_t acl_entry_id) = 0; + virtual sai_status_t create_acl_counter(sai_object_id_t *acl_counter_id, sai_object_id_t switch_id, + uint32_t attr_count, const sai_attribute_t *attr_list) = 0; + virtual sai_status_t remove_acl_counter(sai_object_id_t acl_counter_id) = 0; + virtual sai_status_t get_acl_counter_attribute(sai_object_id_t acl_counter_id, uint32_t attr_count, + sai_attribute_t *attr_list) = 0; + virtual sai_status_t set_acl_entry_attribute(sai_object_id_t acl_entry_id, const sai_attribute_t *attr) = 0; }; -class MockSaiAcl : public SaiAclInterface { - public: - MOCK_METHOD4(create_acl_table, - sai_status_t(sai_object_id_t* acl_table_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list)); - MOCK_METHOD1(remove_acl_table, sai_status_t(sai_object_id_t acl_table_id)); - MOCK_METHOD4(create_acl_table_group, - sai_status_t(sai_object_id_t* acl_table_group_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list)); - MOCK_METHOD1(remove_acl_table_group, - sai_status_t(sai_object_id_t acl_table_group_id)); - MOCK_METHOD4(create_acl_table_group_member, - sai_status_t(sai_object_id_t* acl_table_group_member_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list)); - MOCK_METHOD1(remove_acl_table_group_member, - sai_status_t(sai_object_id_t acl_table_group_member_id)); - MOCK_METHOD4(create_acl_entry, - sai_status_t(sai_object_id_t* acl_entry_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list)); - MOCK_METHOD1(remove_acl_entry, sai_status_t(sai_object_id_t acl_entry_id)); - MOCK_METHOD4(create_acl_counter, - sai_status_t(sai_object_id_t* acl_counter_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list)); - MOCK_METHOD1(remove_acl_counter, - sai_status_t(sai_object_id_t acl_counter_id)); - MOCK_METHOD3(get_acl_counter_attribute, - sai_status_t(sai_object_id_t acl_counter_id, uint32_t attr_count, - sai_attribute_t* attr_list)); - MOCK_METHOD2(set_acl_entry_attribute, - sai_status_t(sai_object_id_t acl_entry_id, - const sai_attribute_t* attr)); +class MockSaiAcl : public SaiAclInterface +{ + public: + MOCK_METHOD4(create_acl_table, sai_status_t(sai_object_id_t *acl_table_id, sai_object_id_t switch_id, + uint32_t attr_count, const sai_attribute_t *attr_list)); + MOCK_METHOD1(remove_acl_table, sai_status_t(sai_object_id_t acl_table_id)); + MOCK_METHOD4(create_acl_table_group, sai_status_t(sai_object_id_t *acl_table_group_id, sai_object_id_t switch_id, + uint32_t attr_count, const sai_attribute_t *attr_list)); + MOCK_METHOD1(remove_acl_table_group, sai_status_t(sai_object_id_t acl_table_group_id)); + MOCK_METHOD4(create_acl_table_group_member, + sai_status_t(sai_object_id_t *acl_table_group_member_id, sai_object_id_t switch_id, + uint32_t attr_count, const sai_attribute_t *attr_list)); + MOCK_METHOD1(remove_acl_table_group_member, sai_status_t(sai_object_id_t acl_table_group_member_id)); + MOCK_METHOD4(create_acl_entry, sai_status_t(sai_object_id_t *acl_entry_id, sai_object_id_t switch_id, + uint32_t attr_count, const sai_attribute_t *attr_list)); + MOCK_METHOD1(remove_acl_entry, sai_status_t(sai_object_id_t acl_entry_id)); + MOCK_METHOD4(create_acl_counter, sai_status_t(sai_object_id_t *acl_counter_id, sai_object_id_t switch_id, + uint32_t attr_count, const sai_attribute_t *attr_list)); + MOCK_METHOD1(remove_acl_counter, sai_status_t(sai_object_id_t acl_counter_id)); + MOCK_METHOD3(get_acl_counter_attribute, + sai_status_t(sai_object_id_t acl_counter_id, uint32_t attr_count, sai_attribute_t *attr_list)); + MOCK_METHOD2(set_acl_entry_attribute, sai_status_t(sai_object_id_t acl_entry_id, const sai_attribute_t *attr)); }; -extern MockSaiAcl* mock_sai_acl; +extern MockSaiAcl *mock_sai_acl; -sai_status_t create_acl_table(_Out_ sai_object_id_t* acl_table_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list); +sai_status_t create_acl_table(_Out_ sai_object_id_t *acl_table_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list); sai_status_t remove_acl_table(sai_object_id_t acl_table_id); -sai_status_t create_acl_table_group(sai_object_id_t* acl_table_group_id, - sai_object_id_t switch_id, - uint32_t attr_count, - const sai_attribute_t* attr_list); +sai_status_t create_acl_table_group(sai_object_id_t *acl_table_group_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list); sai_status_t remove_acl_table_group(sai_object_id_t acl_table_group_id); -sai_status_t create_acl_table_group_member( - sai_object_id_t* acl_table_group_member_id, sai_object_id_t switch_id, - uint32_t attr_count, const sai_attribute_t* attr_list); +sai_status_t create_acl_table_group_member(sai_object_id_t *acl_table_group_member_id, sai_object_id_t switch_id, + uint32_t attr_count, const sai_attribute_t *attr_list); -sai_status_t remove_acl_table_group_member( - sai_object_id_t acl_table_group_member_id); +sai_status_t remove_acl_table_group_member(sai_object_id_t acl_table_group_member_id); -sai_status_t create_acl_entry(sai_object_id_t* acl_entry_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list); +sai_status_t create_acl_entry(sai_object_id_t *acl_entry_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list); sai_status_t remove_acl_entry(sai_object_id_t acl_entry_id); -sai_status_t create_acl_counter(sai_object_id_t* acl_counter_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list); +sai_status_t create_acl_counter(sai_object_id_t *acl_counter_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list); sai_status_t remove_acl_counter(sai_object_id_t acl_counter_id); -sai_status_t get_acl_counter_attribute(sai_object_id_t acl_counter_id, - uint32_t attr_count, - sai_attribute_t* attr_list); +sai_status_t get_acl_counter_attribute(sai_object_id_t acl_counter_id, uint32_t attr_count, sai_attribute_t *attr_list); -sai_status_t set_acl_entry_attribute(sai_object_id_t acl_entry_id, - const sai_attribute_t* attr); +sai_status_t set_acl_entry_attribute(sai_object_id_t acl_entry_id, const sai_attribute_t *attr); diff --git a/orchagent/p4orch/tests/mock_sai_hostif.cpp b/orchagent/p4orch/tests/mock_sai_hostif.cpp index f0d2d485a0a..7dcc0f70c2a 100644 --- a/orchagent/p4orch/tests/mock_sai_hostif.cpp +++ b/orchagent/p4orch/tests/mock_sai_hostif.cpp @@ -1,74 +1,67 @@ #include "mock_sai_hostif.h" -MockSaiHostif* mock_sai_hostif; +MockSaiHostif *mock_sai_hostif; -sai_status_t mock_create_hostif_trap_group( - _Out_ sai_object_id_t* hostif_trap_group_id, _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, _In_ const sai_attribute_t* attr_list) { - return mock_sai_hostif->create_hostif_trap_group( - hostif_trap_group_id, switch_id, attr_count, attr_list); +sai_status_t mock_create_hostif_trap_group(_Out_ sai_object_id_t *hostif_trap_group_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) +{ + return mock_sai_hostif->create_hostif_trap_group(hostif_trap_group_id, switch_id, attr_count, attr_list); } -sai_status_t mock_set_hostif_trap_group_attribute( - _In_ sai_object_id_t hostif_trap_group_id, - _In_ const sai_attribute_t* attr) { - return mock_sai_hostif->set_hostif_trap_group_attribute(hostif_trap_group_id, - attr); +sai_status_t mock_set_hostif_trap_group_attribute(_In_ sai_object_id_t hostif_trap_group_id, + _In_ const sai_attribute_t *attr) +{ + return mock_sai_hostif->set_hostif_trap_group_attribute(hostif_trap_group_id, attr); } -sai_status_t mock_remove_hostif_trap_group( - _In_ const sai_object_id_t hostif_trap_group_id) { - return mock_sai_hostif->remove_hostif_trap_group(hostif_trap_group_id); +sai_status_t mock_remove_hostif_trap_group(_In_ const sai_object_id_t hostif_trap_group_id) +{ + return mock_sai_hostif->remove_hostif_trap_group(hostif_trap_group_id); } -sai_status_t mock_create_hostif_table_entry( - _Out_ sai_object_id_t* hostif_table_entry_id, - _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list) { - return mock_sai_hostif->create_hostif_table_entry( - hostif_table_entry_id, switch_id, attr_count, attr_list); +sai_status_t mock_create_hostif_table_entry(_Out_ sai_object_id_t *hostif_table_entry_id, + _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) +{ + return mock_sai_hostif->create_hostif_table_entry(hostif_table_entry_id, switch_id, attr_count, attr_list); } -sai_status_t mock_remove_hostif_table_entry( - _In_ const sai_object_id_t hostif_table_entry_id) { - return mock_sai_hostif->remove_hostif_table_entry(hostif_table_entry_id); +sai_status_t mock_remove_hostif_table_entry(_In_ const sai_object_id_t hostif_table_entry_id) +{ + return mock_sai_hostif->remove_hostif_table_entry(hostif_table_entry_id); } -sai_status_t mock_create_hostif_user_defined_trap( - _Out_ sai_object_id_t* hostif_user_defined_trap_id, - _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list) { - return mock_sai_hostif->create_hostif_user_defined_trap( - hostif_user_defined_trap_id, switch_id, attr_count, attr_list); +sai_status_t mock_create_hostif_user_defined_trap(_Out_ sai_object_id_t *hostif_user_defined_trap_id, + _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) +{ + return mock_sai_hostif->create_hostif_user_defined_trap(hostif_user_defined_trap_id, switch_id, attr_count, + attr_list); } -sai_status_t mock_remove_hostif_user_defined_trap( - _In_ const sai_object_id_t hostif_user_defined_trap_id) { - return mock_sai_hostif->remove_hostif_user_defined_trap( - hostif_user_defined_trap_id); +sai_status_t mock_remove_hostif_user_defined_trap(_In_ const sai_object_id_t hostif_user_defined_trap_id) +{ + return mock_sai_hostif->remove_hostif_user_defined_trap(hostif_user_defined_trap_id); } -sai_status_t mock_create_hostif_trap(_Out_ sai_object_id_t* hostif_trap_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list) { - return mock_sai_hostif->create_hostif_trap(hostif_trap_id, switch_id, - attr_count, attr_list); +sai_status_t mock_create_hostif_trap(_Out_ sai_object_id_t *hostif_trap_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) +{ + return mock_sai_hostif->create_hostif_trap(hostif_trap_id, switch_id, attr_count, attr_list); } -sai_status_t mock_remove_hostif_trap( - _In_ const sai_object_id_t hostif_trap_id) { - return mock_sai_hostif->remove_hostif_trap(hostif_trap_id); +sai_status_t mock_remove_hostif_trap(_In_ const sai_object_id_t hostif_trap_id) +{ + return mock_sai_hostif->remove_hostif_trap(hostif_trap_id); } -sai_status_t mock_create_hostif(_Out_ sai_object_id_t* hostif_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list) { - return mock_sai_hostif->create_hostif(hostif_id, switch_id, attr_count, - attr_list); +sai_status_t mock_create_hostif(_Out_ sai_object_id_t *hostif_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) +{ + return mock_sai_hostif->create_hostif(hostif_id, switch_id, attr_count, attr_list); } -sai_status_t mock_remove_hostif(_In_ const sai_object_id_t hostif_id) { - return mock_sai_hostif->remove_hostif(hostif_id); +sai_status_t mock_remove_hostif(_In_ const sai_object_id_t hostif_id) +{ + return mock_sai_hostif->remove_hostif(hostif_id); } diff --git a/orchagent/p4orch/tests/mock_sai_hostif.h b/orchagent/p4orch/tests/mock_sai_hostif.h index ff7c0fc7dea..0e758aeebdb 100644 --- a/orchagent/p4orch/tests/mock_sai_hostif.h +++ b/orchagent/p4orch/tests/mock_sai_hostif.h @@ -2,101 +2,75 @@ #include -extern "C" { +extern "C" +{ #include "sai.h" } // Mock Class mapping methods to host interface object SAI APIs. -class MockSaiHostif { - public: - MOCK_METHOD4(create_hostif_trap_group, - sai_status_t(_Out_ sai_object_id_t* hostif_trap_group_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list)); - - MOCK_METHOD2(set_hostif_trap_group_attribute, - sai_status_t(_In_ sai_object_id_t hostif_trap_group_id, - _In_ const sai_attribute_t* attr)); - - MOCK_METHOD1(remove_hostif_trap_group, - sai_status_t(_In_ sai_object_id_t hostif_trap_group_id)); - - MOCK_METHOD4(create_hostif_table_entry, - sai_status_t(_Out_ sai_object_id_t* hostif_table_entry_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list)); - - MOCK_METHOD1(remove_hostif_table_entry, - sai_status_t(_In_ sai_object_id_t hostif_table_entry_id)); - - MOCK_METHOD4(create_hostif_user_defined_trap, - sai_status_t(_Out_ sai_object_id_t* hostif_user_defined_trap_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list)); - - MOCK_METHOD1(remove_hostif_user_defined_trap, - sai_status_t(_In_ sai_object_id_t hostif_user_defined_trap_id)); - - MOCK_METHOD4(create_hostif_trap, - sai_status_t(_Out_ sai_object_id_t* hostif_trap_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list)); - - MOCK_METHOD1(remove_hostif_trap, - sai_status_t(_In_ sai_object_id_t hostif_trap_id)); - - MOCK_METHOD4(create_hostif, - sai_status_t(_Out_ sai_object_id_t* hostif_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list)); - - MOCK_METHOD1(remove_hostif, sai_status_t(_In_ sai_object_id_t hostif_id)); +class MockSaiHostif +{ + public: + MOCK_METHOD4(create_hostif_trap_group, + sai_status_t(_Out_ sai_object_id_t *hostif_trap_group_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)); + + MOCK_METHOD2(set_hostif_trap_group_attribute, + sai_status_t(_In_ sai_object_id_t hostif_trap_group_id, _In_ const sai_attribute_t *attr)); + + MOCK_METHOD1(remove_hostif_trap_group, sai_status_t(_In_ sai_object_id_t hostif_trap_group_id)); + + MOCK_METHOD4(create_hostif_table_entry, + sai_status_t(_Out_ sai_object_id_t *hostif_table_entry_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)); + + MOCK_METHOD1(remove_hostif_table_entry, sai_status_t(_In_ sai_object_id_t hostif_table_entry_id)); + + MOCK_METHOD4(create_hostif_user_defined_trap, + sai_status_t(_Out_ sai_object_id_t *hostif_user_defined_trap_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)); + + MOCK_METHOD1(remove_hostif_user_defined_trap, sai_status_t(_In_ sai_object_id_t hostif_user_defined_trap_id)); + + MOCK_METHOD4(create_hostif_trap, sai_status_t(_Out_ sai_object_id_t *hostif_trap_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)); + + MOCK_METHOD1(remove_hostif_trap, sai_status_t(_In_ sai_object_id_t hostif_trap_id)); + + MOCK_METHOD4(create_hostif, sai_status_t(_Out_ sai_object_id_t *hostif_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)); + + MOCK_METHOD1(remove_hostif, sai_status_t(_In_ sai_object_id_t hostif_id)); }; -extern MockSaiHostif* mock_sai_hostif; +extern MockSaiHostif *mock_sai_hostif; -sai_status_t mock_create_hostif_trap_group( - _Out_ sai_object_id_t* hostif_trap_group_id, _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, _In_ const sai_attribute_t* attr_list); +sai_status_t mock_create_hostif_trap_group(_Out_ sai_object_id_t *hostif_trap_group_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list); -sai_status_t mock_set_hostif_trap_group_attribute( - _In_ sai_object_id_t hostif_trap_group_id, - _In_ const sai_attribute_t* attr); +sai_status_t mock_set_hostif_trap_group_attribute(_In_ sai_object_id_t hostif_trap_group_id, + _In_ const sai_attribute_t *attr); -sai_status_t mock_remove_hostif_trap_group( - _In_ const sai_object_id_t hostif_trap_group_id); +sai_status_t mock_remove_hostif_trap_group(_In_ const sai_object_id_t hostif_trap_group_id); -sai_status_t mock_create_hostif_table_entry( - _Out_ sai_object_id_t* hostif_table_entry_id, - _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list); +sai_status_t mock_create_hostif_table_entry(_Out_ sai_object_id_t *hostif_table_entry_id, + _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); -sai_status_t mock_remove_hostif_table_entry( - _In_ const sai_object_id_t hostif_table_entry_id); +sai_status_t mock_remove_hostif_table_entry(_In_ const sai_object_id_t hostif_table_entry_id); -sai_status_t mock_create_hostif_user_defined_trap( - _Out_ sai_object_id_t* hostif_user_defined_trap_id, - _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list); +sai_status_t mock_create_hostif_user_defined_trap(_Out_ sai_object_id_t *hostif_user_defined_trap_id, + _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list); -sai_status_t mock_remove_hostif_user_defined_trap( - _In_ const sai_object_id_t hostif_user_defined_trap_id); +sai_status_t mock_remove_hostif_user_defined_trap(_In_ const sai_object_id_t hostif_user_defined_trap_id); -sai_status_t mock_create_hostif_trap(_Out_ sai_object_id_t* hostif_trap_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list); +sai_status_t mock_create_hostif_trap(_Out_ sai_object_id_t *hostif_trap_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list); sai_status_t mock_remove_hostif_trap(_In_ const sai_object_id_t hostif_trap_id); -sai_status_t mock_create_hostif(_Out_ sai_object_id_t* hostif_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list); +sai_status_t mock_create_hostif(_Out_ sai_object_id_t *hostif_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list); sai_status_t mock_remove_hostif(_In_ const sai_object_id_t hostif_id); diff --git a/orchagent/p4orch/tests/mock_sai_mirror.h b/orchagent/p4orch/tests/mock_sai_mirror.h index 970349bc837..39991d583e8 100644 --- a/orchagent/p4orch/tests/mock_sai_mirror.h +++ b/orchagent/p4orch/tests/mock_sai_mirror.h @@ -3,56 +3,51 @@ #include -extern "C" { +extern "C" +{ #include "sai.h" } // Mock class including mock functions mapping to SAI mirror's functions. -class MockSaiMirror { - public: - MOCK_METHOD4(create_mirror_session, - sai_status_t(_Out_ sai_object_id_t* mirror_session_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list)); - - MOCK_METHOD1(remove_mirror_session, - sai_status_t(_In_ sai_object_id_t mirror_session_id)); - - MOCK_METHOD2(set_mirror_session_attribute, - sai_status_t(_In_ sai_object_id_t mirror_session_id, - _In_ const sai_attribute_t* attr)); - - MOCK_METHOD3(get_mirror_session_attribute, - sai_status_t(_In_ sai_object_id_t mirror_session_id, - _In_ uint32_t attr_count, - _Inout_ sai_attribute_t* attr_list)); +class MockSaiMirror +{ + public: + MOCK_METHOD4(create_mirror_session, + sai_status_t(_Out_ sai_object_id_t *mirror_session_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)); + + MOCK_METHOD1(remove_mirror_session, sai_status_t(_In_ sai_object_id_t mirror_session_id)); + + MOCK_METHOD2(set_mirror_session_attribute, + sai_status_t(_In_ sai_object_id_t mirror_session_id, _In_ const sai_attribute_t *attr)); + + MOCK_METHOD3(get_mirror_session_attribute, + sai_status_t(_In_ sai_object_id_t mirror_session_id, _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list)); }; // Note that before mock functions below are used, mock_sai_mirror must be // initialized to point to an instance of MockSaiMirror. -MockSaiMirror* mock_sai_mirror; +MockSaiMirror *mock_sai_mirror; -sai_status_t mock_create_mirror_session( - _Out_ sai_object_id_t* mirror_session_id, _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, _In_ const sai_attribute_t* attr_list) { - return mock_sai_mirror->create_mirror_session(mirror_session_id, switch_id, - attr_count, attr_list); +sai_status_t mock_create_mirror_session(_Out_ sai_object_id_t *mirror_session_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) +{ + return mock_sai_mirror->create_mirror_session(mirror_session_id, switch_id, attr_count, attr_list); } -sai_status_t mock_remove_mirror_session( - _In_ sai_object_id_t mirror_session_id) { - return mock_sai_mirror->remove_mirror_session(mirror_session_id); +sai_status_t mock_remove_mirror_session(_In_ sai_object_id_t mirror_session_id) +{ + return mock_sai_mirror->remove_mirror_session(mirror_session_id); } -sai_status_t mock_set_mirror_session_attribute( - _In_ sai_object_id_t mirror_session_id, _In_ const sai_attribute_t* attr) { - return mock_sai_mirror->set_mirror_session_attribute(mirror_session_id, attr); +sai_status_t mock_set_mirror_session_attribute(_In_ sai_object_id_t mirror_session_id, _In_ const sai_attribute_t *attr) +{ + return mock_sai_mirror->set_mirror_session_attribute(mirror_session_id, attr); } -sai_status_t mock_get_mirror_session_attribute( - _In_ sai_object_id_t mirror_session_id, _In_ uint32_t attr_count, - _Inout_ sai_attribute_t* attr_list) { - return mock_sai_mirror->get_mirror_session_attribute(mirror_session_id, - attr_count, attr_list); +sai_status_t mock_get_mirror_session_attribute(_In_ sai_object_id_t mirror_session_id, _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list) +{ + return mock_sai_mirror->get_mirror_session_attribute(mirror_session_id, attr_count, attr_list); } diff --git a/orchagent/p4orch/tests/mock_sai_my_mac.h b/orchagent/p4orch/tests/mock_sai_my_mac.h index 913c297af41..e82f38f520d 100644 --- a/orchagent/p4orch/tests/mock_sai_my_mac.h +++ b/orchagent/p4orch/tests/mock_sai_my_mac.h @@ -2,32 +2,30 @@ #include -extern "C" { +extern "C" +{ #include "sai.h" } // Mock Class mapping methods to my_mac object SAI APIs. -class MockSaiMyMac { - public: - MOCK_METHOD4(create_my_mac, - sai_status_t(_Out_ sai_object_id_t* my_mac_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list)); +class MockSaiMyMac +{ + public: + MOCK_METHOD4(create_my_mac, sai_status_t(_Out_ sai_object_id_t *my_mac_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)); - MOCK_METHOD1(remove_my_mac, sai_status_t(_In_ sai_object_id_t my_mac_id)); + MOCK_METHOD1(remove_my_mac, sai_status_t(_In_ sai_object_id_t my_mac_id)); }; -MockSaiMyMac* mock_sai_my_mac; +MockSaiMyMac *mock_sai_my_mac; -sai_status_t mock_create_my_mac(_Out_ sai_object_id_t* my_mac_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list) { - return mock_sai_my_mac->create_my_mac(my_mac_id, switch_id, attr_count, - attr_list); +sai_status_t mock_create_my_mac(_Out_ sai_object_id_t *my_mac_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) +{ + return mock_sai_my_mac->create_my_mac(my_mac_id, switch_id, attr_count, attr_list); } -sai_status_t mock_remove_my_mac(_In_ sai_object_id_t my_mac_id) { - return mock_sai_my_mac->remove_my_mac(my_mac_id); +sai_status_t mock_remove_my_mac(_In_ sai_object_id_t my_mac_id) +{ + return mock_sai_my_mac->remove_my_mac(my_mac_id); } diff --git a/orchagent/p4orch/tests/mock_sai_neighbor.h b/orchagent/p4orch/tests/mock_sai_neighbor.h index ed16a17f5c7..cd8f2aa0a9d 100644 --- a/orchagent/p4orch/tests/mock_sai_neighbor.h +++ b/orchagent/p4orch/tests/mock_sai_neighbor.h @@ -2,54 +2,49 @@ #include -extern "C" { +extern "C" +{ #include "sai.h" } // Mock Class mapping methods to neighbor object SAI APIs. -class MockSaiNeighbor { - public: - MOCK_METHOD3(create_neighbor_entry, - sai_status_t(_In_ const sai_neighbor_entry_t* neighbor_entry, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list)); - - MOCK_METHOD1(remove_neighbor_entry, - sai_status_t(_In_ const sai_neighbor_entry_t* neighbor_entry)); - - MOCK_METHOD2(set_neighbor_entry_attribute, - sai_status_t(_In_ const sai_neighbor_entry_t* neighbor_entry, - _In_ const sai_attribute_t* attr)); - - MOCK_METHOD3(get_neighbor_entry_attribute, - sai_status_t(_In_ const sai_neighbor_entry_t* neighbor_entry, - _In_ uint32_t attr_count, - _Inout_ sai_attribute_t* attr_list)); +class MockSaiNeighbor +{ + public: + MOCK_METHOD3(create_neighbor_entry, sai_status_t(_In_ const sai_neighbor_entry_t *neighbor_entry, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)); + + MOCK_METHOD1(remove_neighbor_entry, sai_status_t(_In_ const sai_neighbor_entry_t *neighbor_entry)); + + MOCK_METHOD2(set_neighbor_entry_attribute, + sai_status_t(_In_ const sai_neighbor_entry_t *neighbor_entry, _In_ const sai_attribute_t *attr)); + + MOCK_METHOD3(get_neighbor_entry_attribute, + sai_status_t(_In_ const sai_neighbor_entry_t *neighbor_entry, _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list)); }; -MockSaiNeighbor* mock_sai_neighbor; +MockSaiNeighbor *mock_sai_neighbor; -sai_status_t mock_create_neighbor_entry( - _In_ const sai_neighbor_entry_t* neighbor_entry, _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list) { - return mock_sai_neighbor->create_neighbor_entry(neighbor_entry, attr_count, - attr_list); +sai_status_t mock_create_neighbor_entry(_In_ const sai_neighbor_entry_t *neighbor_entry, _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) +{ + return mock_sai_neighbor->create_neighbor_entry(neighbor_entry, attr_count, attr_list); } -sai_status_t mock_remove_neighbor_entry( - _In_ const sai_neighbor_entry_t* neighbor_entry) { - return mock_sai_neighbor->remove_neighbor_entry(neighbor_entry); +sai_status_t mock_remove_neighbor_entry(_In_ const sai_neighbor_entry_t *neighbor_entry) +{ + return mock_sai_neighbor->remove_neighbor_entry(neighbor_entry); } -sai_status_t mock_set_neighbor_entry_attribute( - _In_ const sai_neighbor_entry_t* neighbor_entry, - _In_ const sai_attribute_t* attr) { - return mock_sai_neighbor->set_neighbor_entry_attribute(neighbor_entry, attr); +sai_status_t mock_set_neighbor_entry_attribute(_In_ const sai_neighbor_entry_t *neighbor_entry, + _In_ const sai_attribute_t *attr) +{ + return mock_sai_neighbor->set_neighbor_entry_attribute(neighbor_entry, attr); } -sai_status_t mock_get_neighbor_entry_attribute( - _In_ const sai_neighbor_entry_t* neighbor_entry, _In_ uint32_t attr_count, - _Inout_ sai_attribute_t* attr_list) { - return mock_sai_neighbor->get_neighbor_entry_attribute(neighbor_entry, - attr_count, attr_list); +sai_status_t mock_get_neighbor_entry_attribute(_In_ const sai_neighbor_entry_t *neighbor_entry, + _In_ uint32_t attr_count, _Inout_ sai_attribute_t *attr_list) +{ + return mock_sai_neighbor->get_neighbor_entry_attribute(neighbor_entry, attr_count, attr_list); } diff --git a/orchagent/p4orch/tests/mock_sai_next_hop.h b/orchagent/p4orch/tests/mock_sai_next_hop.h index 8eebf97e9f2..83e6e7d506b 100644 --- a/orchagent/p4orch/tests/mock_sai_next_hop.h +++ b/orchagent/p4orch/tests/mock_sai_next_hop.h @@ -3,55 +3,49 @@ #include -extern "C" { +extern "C" +{ #include "sai.h" } // Mock class including mock functions mapping to SAI next hop's functions. -class MockSaiNextHop { - public: - MOCK_METHOD4(create_next_hop, - sai_status_t(_Out_ sai_object_id_t* next_hop_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list)); - - MOCK_METHOD1(remove_next_hop, sai_status_t(_In_ sai_object_id_t next_hop_id)); - - MOCK_METHOD2(set_next_hop_attribute, - sai_status_t(_In_ sai_object_id_t next_hop_id, - _In_ const sai_attribute_t* attr)); - - MOCK_METHOD3(get_next_hop_attribute, - sai_status_t(_In_ sai_object_id_t next_hop_id, - _In_ uint32_t attr_count, - _Inout_ sai_attribute_t* attr_list)); +class MockSaiNextHop +{ + public: + MOCK_METHOD4(create_next_hop, sai_status_t(_Out_ sai_object_id_t *next_hop_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)); + + MOCK_METHOD1(remove_next_hop, sai_status_t(_In_ sai_object_id_t next_hop_id)); + + MOCK_METHOD2(set_next_hop_attribute, + sai_status_t(_In_ sai_object_id_t next_hop_id, _In_ const sai_attribute_t *attr)); + + MOCK_METHOD3(get_next_hop_attribute, sai_status_t(_In_ sai_object_id_t next_hop_id, _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list)); }; // Note that before mock functions below are used, mock_sai_next_hop must be // initialized to point to an instance of MockSaiNextHop. -MockSaiNextHop* mock_sai_next_hop; - -sai_status_t mock_create_next_hop(_Out_ sai_object_id_t* next_hop_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list) { - return mock_sai_next_hop->create_next_hop(next_hop_id, switch_id, attr_count, - attr_list); +MockSaiNextHop *mock_sai_next_hop; + +sai_status_t mock_create_next_hop(_Out_ sai_object_id_t *next_hop_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) +{ + return mock_sai_next_hop->create_next_hop(next_hop_id, switch_id, attr_count, attr_list); } -sai_status_t mock_remove_next_hop(_In_ sai_object_id_t next_hop_id) { - return mock_sai_next_hop->remove_next_hop(next_hop_id); +sai_status_t mock_remove_next_hop(_In_ sai_object_id_t next_hop_id) +{ + return mock_sai_next_hop->remove_next_hop(next_hop_id); } -sai_status_t mock_set_next_hop_attribute(_In_ sai_object_id_t next_hop_id, - _In_ const sai_attribute_t* attr) { - return mock_sai_next_hop->set_next_hop_attribute(next_hop_id, attr); +sai_status_t mock_set_next_hop_attribute(_In_ sai_object_id_t next_hop_id, _In_ const sai_attribute_t *attr) +{ + return mock_sai_next_hop->set_next_hop_attribute(next_hop_id, attr); } -sai_status_t mock_get_next_hop_attribute(_In_ sai_object_id_t next_hop_id, - _In_ uint32_t attr_count, - _Inout_ sai_attribute_t* attr_list) { - return mock_sai_next_hop->get_next_hop_attribute(next_hop_id, attr_count, - attr_list); +sai_status_t mock_get_next_hop_attribute(_In_ sai_object_id_t next_hop_id, _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list) +{ + return mock_sai_next_hop->get_next_hop_attribute(next_hop_id, attr_count, attr_list); } diff --git a/orchagent/p4orch/tests/mock_sai_next_hop_group.h b/orchagent/p4orch/tests/mock_sai_next_hop_group.h index ac1930f6c69..c1ffedc1759 100644 --- a/orchagent/p4orch/tests/mock_sai_next_hop_group.h +++ b/orchagent/p4orch/tests/mock_sai_next_hop_group.h @@ -3,103 +3,88 @@ #include -extern "C" { +extern "C" +{ #include "sai.h" #include "sainexthopgroup.h" } // Mock class including mock functions mapping to SAI next hop group's // functions. -class MockSaiNextHopGroup { - public: - MOCK_METHOD4(create_next_hop_group, - sai_status_t(_Out_ sai_object_id_t* next_hop_group_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list)); - - MOCK_METHOD1(remove_next_hop_group, - sai_status_t(_In_ sai_object_id_t next_hop_group_id)); - - MOCK_METHOD4(create_next_hop_group_member, - sai_status_t(_Out_ sai_object_id_t* next_hop_group_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list)); - - MOCK_METHOD1(remove_next_hop_group_member, - sai_status_t(_In_ sai_object_id_t next_hop_group_member_id)); - - MOCK_METHOD2(set_next_hop_group_member_attribute, - sai_status_t(_In_ sai_object_id_t next_hop_group_member_id, - _In_ const sai_attribute_t* attr)); - - MOCK_METHOD7(create_next_hop_group_members, - sai_status_t(_In_ sai_object_id_t switch_id, - _In_ uint32_t object_count, - _In_ const uint32_t* attr_count, - _In_ const sai_attribute_t** attr_list, - _In_ sai_bulk_op_error_mode_t mode, - _Out_ sai_object_id_t* object_id, - _Out_ sai_status_t* object_statuses)); - - MOCK_METHOD4(remove_next_hop_group_members, - sai_status_t(_In_ uint32_t object_count, - _In_ const sai_object_id_t* object_id, - _In_ sai_bulk_op_error_mode_t mode, - _Out_ sai_status_t* object_statuses)); +class MockSaiNextHopGroup +{ + public: + MOCK_METHOD4(create_next_hop_group, + sai_status_t(_Out_ sai_object_id_t *next_hop_group_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)); + + MOCK_METHOD1(remove_next_hop_group, sai_status_t(_In_ sai_object_id_t next_hop_group_id)); + + MOCK_METHOD4(create_next_hop_group_member, + sai_status_t(_Out_ sai_object_id_t *next_hop_group_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)); + + MOCK_METHOD1(remove_next_hop_group_member, sai_status_t(_In_ sai_object_id_t next_hop_group_member_id)); + + MOCK_METHOD2(set_next_hop_group_member_attribute, + sai_status_t(_In_ sai_object_id_t next_hop_group_member_id, _In_ const sai_attribute_t *attr)); + + MOCK_METHOD7(create_next_hop_group_members, + sai_status_t(_In_ sai_object_id_t switch_id, _In_ uint32_t object_count, + _In_ const uint32_t *attr_count, _In_ const sai_attribute_t **attr_list, + _In_ sai_bulk_op_error_mode_t mode, _Out_ sai_object_id_t *object_id, + _Out_ sai_status_t *object_statuses)); + + MOCK_METHOD4(remove_next_hop_group_members, + sai_status_t(_In_ uint32_t object_count, _In_ const sai_object_id_t *object_id, + _In_ sai_bulk_op_error_mode_t mode, _Out_ sai_status_t *object_statuses)); }; // Note that before mock functions below are used, mock_sai_next_hop_group must // be initialized to point to an instance of MockSaiNextHopGroup. -MockSaiNextHopGroup* mock_sai_next_hop_group; - -sai_status_t create_next_hop_group(_Out_ sai_object_id_t* next_hop_group_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list) { - return mock_sai_next_hop_group->create_next_hop_group( - next_hop_group_id, switch_id, attr_count, attr_list); +MockSaiNextHopGroup *mock_sai_next_hop_group; + +sai_status_t create_next_hop_group(_Out_ sai_object_id_t *next_hop_group_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) +{ + return mock_sai_next_hop_group->create_next_hop_group(next_hop_group_id, switch_id, attr_count, attr_list); } -sai_status_t remove_next_hop_group(_In_ sai_object_id_t next_hop_group_id) { - return mock_sai_next_hop_group->remove_next_hop_group(next_hop_group_id); +sai_status_t remove_next_hop_group(_In_ sai_object_id_t next_hop_group_id) +{ + return mock_sai_next_hop_group->remove_next_hop_group(next_hop_group_id); } -sai_status_t create_next_hop_group_member( - _Out_ sai_object_id_t* next_hop_group_member_id, - _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list) { - return mock_sai_next_hop_group->create_next_hop_group_member( - next_hop_group_member_id, switch_id, attr_count, attr_list); +sai_status_t create_next_hop_group_member(_Out_ sai_object_id_t *next_hop_group_member_id, + _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, + _In_ const sai_attribute_t *attr_list) +{ + return mock_sai_next_hop_group->create_next_hop_group_member(next_hop_group_member_id, switch_id, attr_count, + attr_list); } -sai_status_t remove_next_hop_group_member( - _In_ sai_object_id_t next_hop_group_member_id) { - return mock_sai_next_hop_group->remove_next_hop_group_member( - next_hop_group_member_id); +sai_status_t remove_next_hop_group_member(_In_ sai_object_id_t next_hop_group_member_id) +{ + return mock_sai_next_hop_group->remove_next_hop_group_member(next_hop_group_member_id); } -sai_status_t set_next_hop_group_member_attribute( - _In_ sai_object_id_t next_hop_group_member_id, - _In_ const sai_attribute_t* attr) { - return mock_sai_next_hop_group->set_next_hop_group_member_attribute( - next_hop_group_member_id, attr); +sai_status_t set_next_hop_group_member_attribute(_In_ sai_object_id_t next_hop_group_member_id, + _In_ const sai_attribute_t *attr) +{ + return mock_sai_next_hop_group->set_next_hop_group_member_attribute(next_hop_group_member_id, attr); } -sai_status_t create_next_hop_group_members( - _In_ sai_object_id_t switch_id, _In_ uint32_t object_count, - _In_ const uint32_t* attr_count, _In_ const sai_attribute_t** attr_list, - _In_ sai_bulk_op_error_mode_t mode, _Out_ sai_object_id_t* object_id, - _Out_ sai_status_t* object_statuses) { - return mock_sai_next_hop_group->create_next_hop_group_members( - switch_id, object_count, attr_count, attr_list, mode, object_id, - object_statuses); +sai_status_t create_next_hop_group_members(_In_ sai_object_id_t switch_id, _In_ uint32_t object_count, + _In_ const uint32_t *attr_count, _In_ const sai_attribute_t **attr_list, + _In_ sai_bulk_op_error_mode_t mode, _Out_ sai_object_id_t *object_id, + _Out_ sai_status_t *object_statuses) +{ + return mock_sai_next_hop_group->create_next_hop_group_members(switch_id, object_count, attr_count, attr_list, mode, + object_id, object_statuses); } -sai_status_t remove_next_hop_group_members( - _In_ uint32_t object_count, _In_ const sai_object_id_t* object_id, - _In_ sai_bulk_op_error_mode_t mode, _Out_ sai_status_t* object_statuses) { - return mock_sai_next_hop_group->remove_next_hop_group_members( - object_count, object_id, mode, object_statuses); +sai_status_t remove_next_hop_group_members(_In_ uint32_t object_count, _In_ const sai_object_id_t *object_id, + _In_ sai_bulk_op_error_mode_t mode, _Out_ sai_status_t *object_statuses) +{ + return mock_sai_next_hop_group->remove_next_hop_group_members(object_count, object_id, mode, object_statuses); } diff --git a/orchagent/p4orch/tests/mock_sai_policer.h b/orchagent/p4orch/tests/mock_sai_policer.h index d6f1916e990..351cca14c02 100644 --- a/orchagent/p4orch/tests/mock_sai_policer.h +++ b/orchagent/p4orch/tests/mock_sai_policer.h @@ -1,63 +1,53 @@ #pragma once -extern "C" { +extern "C" +{ #include "sai.h" #include "saipolicer.h" } -class SaiPolicerInterface { - public: - virtual sai_status_t create_policer(sai_object_id_t* policer_id, - sai_object_id_t switch_id, - uint32_t attr_count, - const sai_attribute_t* attr_list) = 0; - virtual sai_status_t remove_policer(sai_object_id_t policer_id) = 0; - virtual sai_status_t get_policer_stats(sai_object_id_t policer_id, - uint32_t number_of_counters, - const sai_stat_id_t* counter_ids, - uint64_t* counters) = 0; - virtual sai_status_t set_policer_attribute(sai_object_id_t policer_id, - const sai_attribute_t* attr) = 0; +class SaiPolicerInterface +{ + public: + virtual sai_status_t create_policer(sai_object_id_t *policer_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) = 0; + virtual sai_status_t remove_policer(sai_object_id_t policer_id) = 0; + virtual sai_status_t get_policer_stats(sai_object_id_t policer_id, uint32_t number_of_counters, + const sai_stat_id_t *counter_ids, uint64_t *counters) = 0; + virtual sai_status_t set_policer_attribute(sai_object_id_t policer_id, const sai_attribute_t *attr) = 0; }; -class MockSaiPolicer : public SaiPolicerInterface { - public: - MOCK_METHOD4(create_policer, - sai_status_t(sai_object_id_t* policer_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list)); - MOCK_METHOD1(remove_policer, sai_status_t(sai_object_id_t policer_id)); - MOCK_METHOD4(get_policer_stats, sai_status_t(sai_object_id_t policer_id, - uint32_t number_of_counters, - const sai_stat_id_t* counter_ids, - uint64_t* counters)); - MOCK_METHOD2(set_policer_attribute, - sai_status_t(sai_object_id_t policer_id, - const sai_attribute_t* attr)); +class MockSaiPolicer : public SaiPolicerInterface +{ + public: + MOCK_METHOD4(create_policer, sai_status_t(sai_object_id_t *policer_id, sai_object_id_t switch_id, + uint32_t attr_count, const sai_attribute_t *attr_list)); + MOCK_METHOD1(remove_policer, sai_status_t(sai_object_id_t policer_id)); + MOCK_METHOD4(get_policer_stats, sai_status_t(sai_object_id_t policer_id, uint32_t number_of_counters, + const sai_stat_id_t *counter_ids, uint64_t *counters)); + MOCK_METHOD2(set_policer_attribute, sai_status_t(sai_object_id_t policer_id, const sai_attribute_t *attr)); }; -MockSaiPolicer* mock_sai_policer; +MockSaiPolicer *mock_sai_policer; -sai_status_t create_policer(sai_object_id_t* policer_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list) { - return mock_sai_policer->create_policer(policer_id, switch_id, attr_count, - attr_list); +sai_status_t create_policer(sai_object_id_t *policer_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) +{ + return mock_sai_policer->create_policer(policer_id, switch_id, attr_count, attr_list); } -sai_status_t remove_policer(sai_object_id_t policer_id) { - return mock_sai_policer->remove_policer(policer_id); +sai_status_t remove_policer(sai_object_id_t policer_id) +{ + return mock_sai_policer->remove_policer(policer_id); } -sai_status_t get_policer_stats(sai_object_id_t policer_id, - uint32_t number_of_counters, - const sai_stat_id_t* counter_ids, - uint64_t* counters) { - return mock_sai_policer->get_policer_stats(policer_id, number_of_counters, - counter_ids, counters); +sai_status_t get_policer_stats(sai_object_id_t policer_id, uint32_t number_of_counters, + const sai_stat_id_t *counter_ids, uint64_t *counters) +{ + return mock_sai_policer->get_policer_stats(policer_id, number_of_counters, counter_ids, counters); } -sai_status_t set_policer_attribute(sai_object_id_t policer_id, - const sai_attribute_t* attr) { - return mock_sai_policer->set_policer_attribute(policer_id, attr); +sai_status_t set_policer_attribute(sai_object_id_t policer_id, const sai_attribute_t *attr) +{ + return mock_sai_policer->set_policer_attribute(policer_id, attr); } diff --git a/orchagent/p4orch/tests/mock_sai_route.h b/orchagent/p4orch/tests/mock_sai_route.h index 07d029f9e38..b40cf6605ee 100644 --- a/orchagent/p4orch/tests/mock_sai_route.h +++ b/orchagent/p4orch/tests/mock_sai_route.h @@ -1,137 +1,108 @@ #pragma once -extern "C" { +extern "C" +{ #include "sai.h" #include "sairoute.h" } -class SaiRouteInterface { - public: - virtual sai_status_t create_route_entry(const sai_route_entry_t* route_entry, - uint32_t attr_count, - const sai_attribute_t* attr_list) = 0; - virtual sai_status_t remove_route_entry( - const sai_route_entry_t* route_entry) = 0; - virtual sai_status_t set_route_entry_attribute( - const sai_route_entry_t* route_entry, const sai_attribute_t* attr) = 0; - virtual sai_status_t get_route_entry_attribute( - const sai_route_entry_t* route_entry, uint32_t attr_count, - sai_attribute_t* attr_list) = 0; - virtual sai_status_t create_route_entries( - uint32_t object_count, const sai_route_entry_t* route_entry, - const uint32_t* attr_count, const sai_attribute_t** attr_list, - sai_bulk_op_error_mode_t mode, sai_status_t* object_statuses) = 0; - virtual sai_status_t remove_route_entries( - uint32_t object_count, const sai_route_entry_t* route_entry, - sai_bulk_op_error_mode_t mode, sai_status_t* object_statuses) = 0; - virtual sai_status_t set_route_entries_attribute( - uint32_t object_count, const sai_route_entry_t* route_entry, - const sai_attribute_t* attr_list, sai_bulk_op_error_mode_t mode, - sai_status_t* object_statuses) = 0; - virtual sai_status_t get_route_entries_attribute( - uint32_t object_count, const sai_route_entry_t* route_entry, - const uint32_t* attr_count, sai_attribute_t** attr_list, - sai_bulk_op_error_mode_t mode, sai_status_t* object_statuses) = 0; +class SaiRouteInterface +{ + public: + virtual sai_status_t create_route_entry(const sai_route_entry_t *route_entry, uint32_t attr_count, + const sai_attribute_t *attr_list) = 0; + virtual sai_status_t remove_route_entry(const sai_route_entry_t *route_entry) = 0; + virtual sai_status_t set_route_entry_attribute(const sai_route_entry_t *route_entry, + const sai_attribute_t *attr) = 0; + virtual sai_status_t get_route_entry_attribute(const sai_route_entry_t *route_entry, uint32_t attr_count, + sai_attribute_t *attr_list) = 0; + virtual sai_status_t create_route_entries(uint32_t object_count, const sai_route_entry_t *route_entry, + const uint32_t *attr_count, const sai_attribute_t **attr_list, + sai_bulk_op_error_mode_t mode, sai_status_t *object_statuses) = 0; + virtual sai_status_t remove_route_entries(uint32_t object_count, const sai_route_entry_t *route_entry, + sai_bulk_op_error_mode_t mode, sai_status_t *object_statuses) = 0; + virtual sai_status_t set_route_entries_attribute(uint32_t object_count, const sai_route_entry_t *route_entry, + const sai_attribute_t *attr_list, sai_bulk_op_error_mode_t mode, + sai_status_t *object_statuses) = 0; + virtual sai_status_t get_route_entries_attribute(uint32_t object_count, const sai_route_entry_t *route_entry, + const uint32_t *attr_count, sai_attribute_t **attr_list, + sai_bulk_op_error_mode_t mode, sai_status_t *object_statuses) = 0; }; -class MockSaiRoute : public SaiRouteInterface { - public: - MOCK_METHOD3(create_route_entry, - sai_status_t(const sai_route_entry_t* route_entry, - uint32_t attr_count, - const sai_attribute_t* attr_list)); - MOCK_METHOD1(remove_route_entry, - sai_status_t(const sai_route_entry_t* route_entry)); - MOCK_METHOD2(set_route_entry_attribute, - sai_status_t(const sai_route_entry_t* route_entry, - const sai_attribute_t* attr)); - MOCK_METHOD3(get_route_entry_attribute, - sai_status_t(const sai_route_entry_t* route_entry, - uint32_t attr_count, sai_attribute_t* attr_list)); - MOCK_METHOD6(create_route_entries, - sai_status_t(uint32_t object_count, - const sai_route_entry_t* route_entry, - const uint32_t* attr_count, - const sai_attribute_t** attr_list, - sai_bulk_op_error_mode_t mode, - sai_status_t* object_statuses)); - MOCK_METHOD4(remove_route_entries, - sai_status_t(uint32_t object_count, - const sai_route_entry_t* route_entry, - sai_bulk_op_error_mode_t mode, - sai_status_t* object_statuses)); - MOCK_METHOD5(set_route_entries_attribute, - sai_status_t(uint32_t object_count, - const sai_route_entry_t* route_entry, - const sai_attribute_t* attr_list, - sai_bulk_op_error_mode_t mode, - sai_status_t* object_statuses)); - MOCK_METHOD6(get_route_entries_attribute, - sai_status_t(uint32_t object_count, - const sai_route_entry_t* route_entry, - const uint32_t* attr_count, - sai_attribute_t** attr_list, - sai_bulk_op_error_mode_t mode, - sai_status_t* object_statuses)); +class MockSaiRoute : public SaiRouteInterface +{ + public: + MOCK_METHOD3(create_route_entry, sai_status_t(const sai_route_entry_t *route_entry, uint32_t attr_count, + const sai_attribute_t *attr_list)); + MOCK_METHOD1(remove_route_entry, sai_status_t(const sai_route_entry_t *route_entry)); + MOCK_METHOD2(set_route_entry_attribute, + sai_status_t(const sai_route_entry_t *route_entry, const sai_attribute_t *attr)); + MOCK_METHOD3(get_route_entry_attribute, + sai_status_t(const sai_route_entry_t *route_entry, uint32_t attr_count, sai_attribute_t *attr_list)); + MOCK_METHOD6(create_route_entries, sai_status_t(uint32_t object_count, const sai_route_entry_t *route_entry, + const uint32_t *attr_count, const sai_attribute_t **attr_list, + sai_bulk_op_error_mode_t mode, sai_status_t *object_statuses)); + MOCK_METHOD4(remove_route_entries, sai_status_t(uint32_t object_count, const sai_route_entry_t *route_entry, + sai_bulk_op_error_mode_t mode, sai_status_t *object_statuses)); + MOCK_METHOD5(set_route_entries_attribute, + sai_status_t(uint32_t object_count, const sai_route_entry_t *route_entry, + const sai_attribute_t *attr_list, sai_bulk_op_error_mode_t mode, + sai_status_t *object_statuses)); + MOCK_METHOD6(get_route_entries_attribute, + sai_status_t(uint32_t object_count, const sai_route_entry_t *route_entry, const uint32_t *attr_count, + sai_attribute_t **attr_list, sai_bulk_op_error_mode_t mode, + sai_status_t *object_statuses)); }; -MockSaiRoute* mock_sai_route; +MockSaiRoute *mock_sai_route; -sai_status_t create_route_entry(const sai_route_entry_t* route_entry, - uint32_t attr_count, - const sai_attribute_t* attr_list) { - return mock_sai_route->create_route_entry(route_entry, attr_count, attr_list); +sai_status_t create_route_entry(const sai_route_entry_t *route_entry, uint32_t attr_count, + const sai_attribute_t *attr_list) +{ + return mock_sai_route->create_route_entry(route_entry, attr_count, attr_list); } -sai_status_t remove_route_entry(const sai_route_entry_t* route_entry) { - return mock_sai_route->remove_route_entry(route_entry); +sai_status_t remove_route_entry(const sai_route_entry_t *route_entry) +{ + return mock_sai_route->remove_route_entry(route_entry); } -sai_status_t set_route_entry_attribute(const sai_route_entry_t* route_entry, - const sai_attribute_t* attr) { - return mock_sai_route->set_route_entry_attribute(route_entry, attr); +sai_status_t set_route_entry_attribute(const sai_route_entry_t *route_entry, const sai_attribute_t *attr) +{ + return mock_sai_route->set_route_entry_attribute(route_entry, attr); } -sai_status_t get_route_entry_attribute(const sai_route_entry_t* route_entry, - uint32_t attr_count, - sai_attribute_t* attr_list) { - return mock_sai_route->get_route_entry_attribute(route_entry, attr_count, - attr_list); +sai_status_t get_route_entry_attribute(const sai_route_entry_t *route_entry, uint32_t attr_count, + sai_attribute_t *attr_list) +{ + return mock_sai_route->get_route_entry_attribute(route_entry, attr_count, attr_list); } -sai_status_t create_route_entries(uint32_t object_count, - const sai_route_entry_t* route_entry, - const uint32_t* attr_count, - const sai_attribute_t** attr_list, - sai_bulk_op_error_mode_t mode, - sai_status_t* object_statuses) { - return mock_sai_route->create_route_entries( - object_count, route_entry, attr_count, attr_list, mode, object_statuses); +sai_status_t create_route_entries(uint32_t object_count, const sai_route_entry_t *route_entry, + const uint32_t *attr_count, const sai_attribute_t **attr_list, + sai_bulk_op_error_mode_t mode, sai_status_t *object_statuses) +{ + return mock_sai_route->create_route_entries(object_count, route_entry, attr_count, attr_list, mode, + object_statuses); } -sai_status_t remove_route_entries(uint32_t object_count, - const sai_route_entry_t* route_entry, - sai_bulk_op_error_mode_t mode, - sai_status_t* object_statuses) { - return mock_sai_route->remove_route_entries(object_count, route_entry, mode, - object_statuses); +sai_status_t remove_route_entries(uint32_t object_count, const sai_route_entry_t *route_entry, + sai_bulk_op_error_mode_t mode, sai_status_t *object_statuses) +{ + return mock_sai_route->remove_route_entries(object_count, route_entry, mode, object_statuses); } -sai_status_t set_route_entries_attribute(uint32_t object_count, - const sai_route_entry_t* route_entry, - const sai_attribute_t* attr_list, - sai_bulk_op_error_mode_t mode, - sai_status_t* object_statuses) { - return mock_sai_route->set_route_entries_attribute( - object_count, route_entry, attr_list, mode, object_statuses); +sai_status_t set_route_entries_attribute(uint32_t object_count, const sai_route_entry_t *route_entry, + const sai_attribute_t *attr_list, sai_bulk_op_error_mode_t mode, + sai_status_t *object_statuses) +{ + return mock_sai_route->set_route_entries_attribute(object_count, route_entry, attr_list, mode, object_statuses); } -sai_status_t get_route_entries_attribute(uint32_t object_count, - const sai_route_entry_t* route_entry, - const uint32_t* attr_count, - sai_attribute_t** attr_list, - sai_bulk_op_error_mode_t mode, - sai_status_t* object_statuses) { - return mock_sai_route->get_route_entries_attribute( - object_count, route_entry, attr_count, attr_list, mode, object_statuses); +sai_status_t get_route_entries_attribute(uint32_t object_count, const sai_route_entry_t *route_entry, + const uint32_t *attr_count, sai_attribute_t **attr_list, + sai_bulk_op_error_mode_t mode, sai_status_t *object_statuses) +{ + return mock_sai_route->get_route_entries_attribute(object_count, route_entry, attr_count, attr_list, mode, + object_statuses); } diff --git a/orchagent/p4orch/tests/mock_sai_router_interface.cpp b/orchagent/p4orch/tests/mock_sai_router_interface.cpp index f98afeb656d..8fbc4af16d8 100644 --- a/orchagent/p4orch/tests/mock_sai_router_interface.cpp +++ b/orchagent/p4orch/tests/mock_sai_router_interface.cpp @@ -1,29 +1,26 @@ #include "mock_sai_router_interface.h" -MockSaiRouterInterface* mock_sai_router_intf; +MockSaiRouterInterface *mock_sai_router_intf; -sai_status_t mock_create_router_interface( - _Out_ sai_object_id_t* router_interface_id, _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, _In_ const sai_attribute_t* attr_list) { - return mock_sai_router_intf->create_router_interface( - router_interface_id, switch_id, attr_count, attr_list); +sai_status_t mock_create_router_interface(_Out_ sai_object_id_t *router_interface_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) +{ + return mock_sai_router_intf->create_router_interface(router_interface_id, switch_id, attr_count, attr_list); } -sai_status_t mock_remove_router_interface( - _In_ sai_object_id_t router_interface_id) { - return mock_sai_router_intf->remove_router_interface(router_interface_id); +sai_status_t mock_remove_router_interface(_In_ sai_object_id_t router_interface_id) +{ + return mock_sai_router_intf->remove_router_interface(router_interface_id); } -sai_status_t mock_set_router_interface_attribute( - _In_ sai_object_id_t router_interface_id, - _In_ const sai_attribute_t* attr) { - return mock_sai_router_intf->set_router_interface_attribute( - router_interface_id, attr); +sai_status_t mock_set_router_interface_attribute(_In_ sai_object_id_t router_interface_id, + _In_ const sai_attribute_t *attr) +{ + return mock_sai_router_intf->set_router_interface_attribute(router_interface_id, attr); } -sai_status_t mock_get_router_interface_attribute( - _In_ sai_object_id_t router_interface_id, _In_ uint32_t attr_count, - _Inout_ sai_attribute_t* attr_list) { - return mock_sai_router_intf->get_router_interface_attribute( - router_interface_id, attr_count, attr_list); +sai_status_t mock_get_router_interface_attribute(_In_ sai_object_id_t router_interface_id, _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list) +{ + return mock_sai_router_intf->get_router_interface_attribute(router_interface_id, attr_count, attr_list); } \ No newline at end of file diff --git a/orchagent/p4orch/tests/mock_sai_router_interface.h b/orchagent/p4orch/tests/mock_sai_router_interface.h index 1c255ba5b4f..5d7b7e11724 100644 --- a/orchagent/p4orch/tests/mock_sai_router_interface.h +++ b/orchagent/p4orch/tests/mock_sai_router_interface.h @@ -2,44 +2,38 @@ #include -extern "C" { +extern "C" +{ #include "sai.h" } // Mock Class mapping methods to router interface SAI APIs. -class MockSaiRouterInterface { - public: - MOCK_METHOD4(create_router_interface, - sai_status_t(_Out_ sai_object_id_t* router_interface_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list)); - - MOCK_METHOD1(remove_router_interface, - sai_status_t(_In_ sai_object_id_t router_interface_id)); - - MOCK_METHOD2(set_router_interface_attribute, - sai_status_t(_In_ sai_object_id_t router_interface_id, - _In_ const sai_attribute_t* attr)); - - MOCK_METHOD3(get_router_interface_attribute, - sai_status_t(_In_ sai_object_id_t router_interface_id, - _In_ uint32_t attr_count, - _Inout_ sai_attribute_t* attr_list)); +class MockSaiRouterInterface +{ + public: + MOCK_METHOD4(create_router_interface, + sai_status_t(_Out_ sai_object_id_t *router_interface_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)); + + MOCK_METHOD1(remove_router_interface, sai_status_t(_In_ sai_object_id_t router_interface_id)); + + MOCK_METHOD2(set_router_interface_attribute, + sai_status_t(_In_ sai_object_id_t router_interface_id, _In_ const sai_attribute_t *attr)); + + MOCK_METHOD3(get_router_interface_attribute, + sai_status_t(_In_ sai_object_id_t router_interface_id, _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list)); }; -extern MockSaiRouterInterface* mock_sai_router_intf; +extern MockSaiRouterInterface *mock_sai_router_intf; -sai_status_t mock_create_router_interface( - _Out_ sai_object_id_t* router_interface_id, _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, _In_ const sai_attribute_t* attr_list); +sai_status_t mock_create_router_interface(_Out_ sai_object_id_t *router_interface_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list); -sai_status_t mock_remove_router_interface( - _In_ sai_object_id_t router_interface_id); +sai_status_t mock_remove_router_interface(_In_ sai_object_id_t router_interface_id); -sai_status_t mock_set_router_interface_attribute( - _In_ sai_object_id_t router_interface_id, _In_ const sai_attribute_t* attr); +sai_status_t mock_set_router_interface_attribute(_In_ sai_object_id_t router_interface_id, + _In_ const sai_attribute_t *attr); -sai_status_t mock_get_router_interface_attribute( - _In_ sai_object_id_t router_interface_id, _In_ uint32_t attr_count, - _Inout_ sai_attribute_t* attr_list); +sai_status_t mock_get_router_interface_attribute(_In_ sai_object_id_t router_interface_id, _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list); diff --git a/orchagent/p4orch/tests/mock_sai_serialize.cpp b/orchagent/p4orch/tests/mock_sai_serialize.cpp index 032cf293226..ada42acf021 100644 --- a/orchagent/p4orch/tests/mock_sai_serialize.cpp +++ b/orchagent/p4orch/tests/mock_sai_serialize.cpp @@ -1,11 +1,13 @@ #include "mock_sai_serialize.h" -MockSaiSerialize* mock_sai_serialize; +MockSaiSerialize *mock_sai_serialize; -inline std::string sai_serialize_object_id(sai_object_id_t oid) { - return mock_sai_serialize->sai_serialize_object_id(oid); +inline std::string sai_serialize_object_id(sai_object_id_t oid) +{ + return mock_sai_serialize->sai_serialize_object_id(oid); } -inline std::string sai_serialize_object_type(sai_object_type_t object_type) { - return mock_sai_serialize->sai_serialize_object_type(object_type); +inline std::string sai_serialize_object_type(sai_object_type_t object_type) +{ + return mock_sai_serialize->sai_serialize_object_type(object_type); } diff --git a/orchagent/p4orch/tests/mock_sai_serialize.h b/orchagent/p4orch/tests/mock_sai_serialize.h index 7bb886f1017..4e4ae505739 100644 --- a/orchagent/p4orch/tests/mock_sai_serialize.h +++ b/orchagent/p4orch/tests/mock_sai_serialize.h @@ -4,21 +4,21 @@ #include "sai_serialize.h" -class SaiSerializeInterface { - public: - virtual std::string sai_serialize_object_id(sai_object_id_t oid) = 0; - virtual std::string sai_serialize_object_type( - sai_object_type_t object_type) = 0; +class SaiSerializeInterface +{ + public: + virtual std::string sai_serialize_object_id(sai_object_id_t oid) = 0; + virtual std::string sai_serialize_object_type(sai_object_type_t object_type) = 0; }; -class MockSaiSerialize : public SaiSerializeInterface { - public: - MOCK_METHOD1(sai_serialize_object_id, std::string(sai_object_id_t oid)); - MOCK_METHOD1(sai_serialize_object_type, - std::string(sai_object_type_t object_type)); +class MockSaiSerialize : public SaiSerializeInterface +{ + public: + MOCK_METHOD1(sai_serialize_object_id, std::string(sai_object_id_t oid)); + MOCK_METHOD1(sai_serialize_object_type, std::string(sai_object_type_t object_type)); }; -extern MockSaiSerialize* mock_sai_serialize; +extern MockSaiSerialize *mock_sai_serialize; std::string sai_serialize_object_id(sai_object_id_t oid); diff --git a/orchagent/p4orch/tests/mock_sai_switch.cpp b/orchagent/p4orch/tests/mock_sai_switch.cpp index ac7c16e3e5d..180de2d6f93 100644 --- a/orchagent/p4orch/tests/mock_sai_switch.cpp +++ b/orchagent/p4orch/tests/mock_sai_switch.cpp @@ -1,15 +1,14 @@ #include "mock_sai_switch.h" -MockSaiSwitch* mock_sai_switch; +MockSaiSwitch *mock_sai_switch; -sai_status_t mock_get_switch_attribute(_In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _Inout_ sai_attribute_t* attr_list) { - return mock_sai_switch->get_switch_attribute(switch_id, attr_count, - attr_list); +sai_status_t mock_get_switch_attribute(_In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list) +{ + return mock_sai_switch->get_switch_attribute(switch_id, attr_count, attr_list); } -sai_status_t mock_set_switch_attribute(_In_ sai_object_id_t switch_id, - _In_ const sai_attribute_t* attr) { - return mock_sai_switch->set_switch_attribute(switch_id, attr); +sai_status_t mock_set_switch_attribute(_In_ sai_object_id_t switch_id, _In_ const sai_attribute_t *attr) +{ + return mock_sai_switch->set_switch_attribute(switch_id, attr); } diff --git a/orchagent/p4orch/tests/mock_sai_switch.h b/orchagent/p4orch/tests/mock_sai_switch.h index b125d68fef8..2883178ea34 100644 --- a/orchagent/p4orch/tests/mock_sai_switch.h +++ b/orchagent/p4orch/tests/mock_sai_switch.h @@ -2,27 +2,23 @@ #include -extern "C" { +extern "C" +{ #include "sai.h" } // Mock Class mapping methods to switch object SAI APIs. -class MockSaiSwitch { - public: - MOCK_METHOD3(get_switch_attribute, - sai_status_t(_In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _Inout_ sai_attribute_t* attr_list)); - MOCK_METHOD2(set_switch_attribute, - sai_status_t(_In_ sai_object_id_t switch_id, - _In_ const sai_attribute_t* attr)); +class MockSaiSwitch +{ + public: + MOCK_METHOD3(get_switch_attribute, sai_status_t(_In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list)); + MOCK_METHOD2(set_switch_attribute, sai_status_t(_In_ sai_object_id_t switch_id, _In_ const sai_attribute_t *attr)); }; -extern MockSaiSwitch* mock_sai_switch; +extern MockSaiSwitch *mock_sai_switch; -sai_status_t mock_get_switch_attribute(_In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _Inout_ sai_attribute_t* attr_list); +sai_status_t mock_get_switch_attribute(_In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list); -sai_status_t mock_set_switch_attribute(_In_ sai_object_id_t switch_id, - _In_ const sai_attribute_t* attr); +sai_status_t mock_set_switch_attribute(_In_ sai_object_id_t switch_id, _In_ const sai_attribute_t *attr); diff --git a/orchagent/p4orch/tests/mock_sai_tunnel.h b/orchagent/p4orch/tests/mock_sai_tunnel.h index 4c5ae913a76..5a2a165b025 100644 --- a/orchagent/p4orch/tests/mock_sai_tunnel.h +++ b/orchagent/p4orch/tests/mock_sai_tunnel.h @@ -2,32 +2,30 @@ #include -extern "C" { +extern "C" +{ #include "sai.h" } // Mock Class mapping methods to tunnel object SAI APIs. -class MockSaiTunnel { - public: - MOCK_METHOD4(create_tunnel, - sai_status_t(_Out_ sai_object_id_t* tunnel_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list)); +class MockSaiTunnel +{ + public: + MOCK_METHOD4(create_tunnel, sai_status_t(_Out_ sai_object_id_t *tunnel_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)); - MOCK_METHOD1(remove_tunnel, sai_status_t(_In_ sai_object_id_t tunnel_id)); + MOCK_METHOD1(remove_tunnel, sai_status_t(_In_ sai_object_id_t tunnel_id)); }; -MockSaiTunnel* mock_sai_tunnel; +MockSaiTunnel *mock_sai_tunnel; -sai_status_t mock_create_tunnel(_Out_ sai_object_id_t* tunnel_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list) { - return mock_sai_tunnel->create_tunnel(tunnel_id, switch_id, attr_count, - attr_list); +sai_status_t mock_create_tunnel(_Out_ sai_object_id_t *tunnel_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) +{ + return mock_sai_tunnel->create_tunnel(tunnel_id, switch_id, attr_count, attr_list); } -sai_status_t mock_remove_tunnel(_In_ sai_object_id_t tunnel_id) { - return mock_sai_tunnel->remove_tunnel(tunnel_id); +sai_status_t mock_remove_tunnel(_In_ sai_object_id_t tunnel_id) +{ + return mock_sai_tunnel->remove_tunnel(tunnel_id); } diff --git a/orchagent/p4orch/tests/mock_sai_udf.cpp b/orchagent/p4orch/tests/mock_sai_udf.cpp index 358696bd324..4133988c8b0 100644 --- a/orchagent/p4orch/tests/mock_sai_udf.cpp +++ b/orchagent/p4orch/tests/mock_sai_udf.cpp @@ -1,34 +1,36 @@ #include "mock_sai_udf.h" -MockSaiUdf* mock_sai_udf; +MockSaiUdf *mock_sai_udf; -sai_status_t create_udf(sai_object_id_t* udf_id, sai_object_id_t switch_id, - uint32_t attr_count, const sai_attribute_t* attr_list) { - return mock_sai_udf->create_udf(udf_id, switch_id, attr_count, attr_list); +sai_status_t create_udf(sai_object_id_t *udf_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) +{ + return mock_sai_udf->create_udf(udf_id, switch_id, attr_count, attr_list); } -sai_status_t remove_udf(sai_object_id_t udf_id) { - return mock_sai_udf->remove_udf(udf_id); +sai_status_t remove_udf(sai_object_id_t udf_id) +{ + return mock_sai_udf->remove_udf(udf_id); } -sai_status_t create_udf_group(sai_object_id_t* udf_group_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list) { - return mock_sai_udf->create_udf_group(udf_group_id, switch_id, attr_count, - attr_list); +sai_status_t create_udf_group(sai_object_id_t *udf_group_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) +{ + return mock_sai_udf->create_udf_group(udf_group_id, switch_id, attr_count, attr_list); } -sai_status_t remove_udf_group(sai_object_id_t udf_group_id) { - return mock_sai_udf->remove_udf_group(udf_group_id); +sai_status_t remove_udf_group(sai_object_id_t udf_group_id) +{ + return mock_sai_udf->remove_udf_group(udf_group_id); } -sai_status_t create_udf_match(sai_object_id_t* udf_match_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list) { - return mock_sai_udf->create_udf_match(udf_match_id, switch_id, attr_count, - attr_list); +sai_status_t create_udf_match(sai_object_id_t *udf_match_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) +{ + return mock_sai_udf->create_udf_match(udf_match_id, switch_id, attr_count, attr_list); } -sai_status_t remove_udf_match(sai_object_id_t udf_match_id) { - return mock_sai_udf->remove_udf_match(udf_match_id); +sai_status_t remove_udf_match(sai_object_id_t udf_match_id) +{ + return mock_sai_udf->remove_udf_match(udf_match_id); } diff --git a/orchagent/p4orch/tests/mock_sai_udf.h b/orchagent/p4orch/tests/mock_sai_udf.h index 4e4bf9f531d..251f8c2b1a5 100644 --- a/orchagent/p4orch/tests/mock_sai_udf.h +++ b/orchagent/p4orch/tests/mock_sai_udf.h @@ -2,64 +2,53 @@ #include -extern "C" { +extern "C" +{ #include "sai.h" #include "saiudf.h" } -class SaiUdfInterface { - public: - virtual sai_status_t create_udf(sai_object_id_t* udf_id, - sai_object_id_t switch_id, - uint32_t attr_count, - const sai_attribute_t* attr_list) = 0; - virtual sai_status_t remove_udf(sai_object_id_t udf_id) = 0; - virtual sai_status_t create_udf_group(sai_object_id_t* udf_group_id, - sai_object_id_t switch_id, - uint32_t attr_count, - const sai_attribute_t* attr_list) = 0; - virtual sai_status_t remove_udf_group(sai_object_id_t udf_group_id) = 0; - virtual sai_status_t create_udf_match(sai_object_id_t* udf_match_id, - sai_object_id_t switch_id, - uint32_t attr_count, - const sai_attribute_t* attr_list) = 0; - virtual sai_status_t remove_udf_match(sai_object_id_t udf_match_id) = 0; +class SaiUdfInterface +{ + public: + virtual sai_status_t create_udf(sai_object_id_t *udf_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) = 0; + virtual sai_status_t remove_udf(sai_object_id_t udf_id) = 0; + virtual sai_status_t create_udf_group(sai_object_id_t *udf_group_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) = 0; + virtual sai_status_t remove_udf_group(sai_object_id_t udf_group_id) = 0; + virtual sai_status_t create_udf_match(sai_object_id_t *udf_match_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list) = 0; + virtual sai_status_t remove_udf_match(sai_object_id_t udf_match_id) = 0; }; -class MockSaiUdf : public SaiUdfInterface { - public: - MOCK_METHOD4(create_udf, - sai_status_t(sai_object_id_t* udf_id, sai_object_id_t switch_id, - uint32_t attr_count, - const sai_attribute_t* attr_list)); - MOCK_METHOD1(remove_udf, sai_status_t(sai_object_id_t udf_id)); - MOCK_METHOD4(create_udf_group, - sai_status_t(sai_object_id_t* udf_group_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list)); - MOCK_METHOD1(remove_udf_group, sai_status_t(sai_object_id_t udf_group_id)); - MOCK_METHOD4(create_udf_match, - sai_status_t(sai_object_id_t* udf_match_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list)); - MOCK_METHOD1(remove_udf_match, sai_status_t(sai_object_id_t udf_match_id)); +class MockSaiUdf : public SaiUdfInterface +{ + public: + MOCK_METHOD4(create_udf, sai_status_t(sai_object_id_t *udf_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list)); + MOCK_METHOD1(remove_udf, sai_status_t(sai_object_id_t udf_id)); + MOCK_METHOD4(create_udf_group, sai_status_t(sai_object_id_t *udf_group_id, sai_object_id_t switch_id, + uint32_t attr_count, const sai_attribute_t *attr_list)); + MOCK_METHOD1(remove_udf_group, sai_status_t(sai_object_id_t udf_group_id)); + MOCK_METHOD4(create_udf_match, sai_status_t(sai_object_id_t *udf_match_id, sai_object_id_t switch_id, + uint32_t attr_count, const sai_attribute_t *attr_list)); + MOCK_METHOD1(remove_udf_match, sai_status_t(sai_object_id_t udf_match_id)); }; -extern MockSaiUdf* mock_sai_udf; +extern MockSaiUdf *mock_sai_udf; -sai_status_t create_udf(sai_object_id_t* udf_id, sai_object_id_t switch_id, - uint32_t attr_count, const sai_attribute_t* attr_list); +sai_status_t create_udf(sai_object_id_t *udf_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list); sai_status_t remove_udf(sai_object_id_t udf_id); -sai_status_t create_udf_group(sai_object_id_t* udf_group_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list); +sai_status_t create_udf_group(sai_object_id_t *udf_group_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list); sai_status_t remove_udf_group(sai_object_id_t udf_group_id); -sai_status_t create_udf_match(sai_object_id_t* udf_match_id, - sai_object_id_t switch_id, uint32_t attr_count, - const sai_attribute_t* attr_list); +sai_status_t create_udf_match(sai_object_id_t *udf_match_id, sai_object_id_t switch_id, uint32_t attr_count, + const sai_attribute_t *attr_list); sai_status_t remove_udf_match(sai_object_id_t udf_match_id); diff --git a/orchagent/p4orch/tests/mock_sai_virtual_router.h b/orchagent/p4orch/tests/mock_sai_virtual_router.h index 4187a908bae..943b9b4828c 100644 --- a/orchagent/p4orch/tests/mock_sai_virtual_router.h +++ b/orchagent/p4orch/tests/mock_sai_virtual_router.h @@ -2,55 +2,49 @@ #include -extern "C" { +extern "C" +{ #include "sai.h" } // Mock Class mapping methods to router interface SAI APIs. -class MockSaiVirtualRouter { - public: - MOCK_METHOD4(create_virtual_router, - sai_status_t(_Out_ sai_object_id_t* virtual_router_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list)); - - MOCK_METHOD1(remove_virtual_router, - sai_status_t(_In_ sai_object_id_t virtual_router_id)); - - MOCK_METHOD2(set_virtual_router_attribute, - sai_status_t(_In_ sai_object_id_t virtual_router_id, - _In_ const sai_attribute_t* attr)); - - MOCK_METHOD3(get_virtual_router_attribute, - sai_status_t(_In_ sai_object_id_t virtual_router_id, - _In_ uint32_t attr_count, - _Inout_ sai_attribute_t* attr_list)); +class MockSaiVirtualRouter +{ + public: + MOCK_METHOD4(create_virtual_router, + sai_status_t(_Out_ sai_object_id_t *virtual_router_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list)); + + MOCK_METHOD1(remove_virtual_router, sai_status_t(_In_ sai_object_id_t virtual_router_id)); + + MOCK_METHOD2(set_virtual_router_attribute, + sai_status_t(_In_ sai_object_id_t virtual_router_id, _In_ const sai_attribute_t *attr)); + + MOCK_METHOD3(get_virtual_router_attribute, + sai_status_t(_In_ sai_object_id_t virtual_router_id, _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list)); }; -MockSaiVirtualRouter* mock_sai_virtual_router; +MockSaiVirtualRouter *mock_sai_virtual_router; -sai_status_t create_virtual_router(_Out_ sai_object_id_t* virtual_router_id, - _In_ sai_object_id_t switch_id, - _In_ uint32_t attr_count, - _In_ const sai_attribute_t* attr_list) { - return mock_sai_virtual_router->create_virtual_router( - virtual_router_id, switch_id, attr_count, attr_list); +sai_status_t create_virtual_router(_Out_ sai_object_id_t *virtual_router_id, _In_ sai_object_id_t switch_id, + _In_ uint32_t attr_count, _In_ const sai_attribute_t *attr_list) +{ + return mock_sai_virtual_router->create_virtual_router(virtual_router_id, switch_id, attr_count, attr_list); } -sai_status_t remove_virtual_router(_In_ sai_object_id_t virtual_router_id) { - return mock_sai_virtual_router->remove_virtual_router(virtual_router_id); +sai_status_t remove_virtual_router(_In_ sai_object_id_t virtual_router_id) +{ + return mock_sai_virtual_router->remove_virtual_router(virtual_router_id); } -sai_status_t set_virtual_router_attribute( - _In_ sai_object_id_t virtual_router_id, _In_ const sai_attribute_t* attr) { - return mock_sai_virtual_router->set_virtual_router_attribute( - virtual_router_id, attr); +sai_status_t set_virtual_router_attribute(_In_ sai_object_id_t virtual_router_id, _In_ const sai_attribute_t *attr) +{ + return mock_sai_virtual_router->set_virtual_router_attribute(virtual_router_id, attr); } -sai_status_t get_virtual_router_attribute( - _In_ sai_object_id_t virtual_router_id, _In_ uint32_t attr_count, - _Inout_ sai_attribute_t* attr_list) { - return mock_sai_virtual_router->get_virtual_router_attribute( - virtual_router_id, attr_count, attr_list); +sai_status_t get_virtual_router_attribute(_In_ sai_object_id_t virtual_router_id, _In_ uint32_t attr_count, + _Inout_ sai_attribute_t *attr_list) +{ + return mock_sai_virtual_router->get_virtual_router_attribute(virtual_router_id, attr_count, attr_list); } diff --git a/orchagent/p4orch/tests/neighbor_manager_test.cpp b/orchagent/p4orch/tests/neighbor_manager_test.cpp index cd8389a96c4..4db1db873ea 100644 --- a/orchagent/p4orch/tests/neighbor_manager_test.cpp +++ b/orchagent/p4orch/tests/neighbor_manager_test.cpp @@ -23,14 +23,15 @@ using ::testing::StrictMock; using ::testing::Truly; extern sai_object_id_t gSwitchId; -extern sai_neighbor_api_t* sai_neighbor_api; +extern sai_neighbor_api_t *sai_neighbor_api; -namespace { +namespace +{ -constexpr char* kRouterInterfaceId1 = "intf-3/4"; +constexpr char *kRouterInterfaceId1 = "intf-3/4"; constexpr sai_object_id_t kRouterInterfaceOid1 = 0x295100; -constexpr char* kRouterInterfaceId2 = "Ethernet20"; +constexpr char *kRouterInterfaceId2 = "Ethernet20"; constexpr sai_object_id_t kRouterInterfaceOid2 = 0x51411; const swss::IpAddress kNeighborId1("10.0.0.22"); @@ -39,995 +40,901 @@ const swss::MacAddress kMacAddress1("00:01:02:03:04:05"); const swss::IpAddress kNeighborId2("fe80::21a:11ff:fe17:5f80"); const swss::MacAddress kMacAddress2("00:ff:ee:dd:cc:bb"); -bool MatchNeighborEntry(const sai_neighbor_entry_t* neigh_entry, - const sai_neighbor_entry_t& expected_neigh_entry) { - if (neigh_entry == nullptr) return false; - - if ((neigh_entry->switch_id != expected_neigh_entry.switch_id) || - (neigh_entry->rif_id != expected_neigh_entry.rif_id) || - (neigh_entry->ip_address.addr_family != - expected_neigh_entry.ip_address.addr_family)) - return false; - - if ((neigh_entry->ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV4) && - (neigh_entry->ip_address.addr.ip4 != - expected_neigh_entry.ip_address.addr.ip4)) { - return false; - } else if ((neigh_entry->ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV6) && - (memcmp(neigh_entry->ip_address.addr.ip6, - expected_neigh_entry.ip_address.addr.ip6, 16))) { - return false; - } - - return true; +bool MatchNeighborEntry(const sai_neighbor_entry_t *neigh_entry, const sai_neighbor_entry_t &expected_neigh_entry) +{ + if (neigh_entry == nullptr) + return false; + + if ((neigh_entry->switch_id != expected_neigh_entry.switch_id) || + (neigh_entry->rif_id != expected_neigh_entry.rif_id) || + (neigh_entry->ip_address.addr_family != expected_neigh_entry.ip_address.addr_family)) + return false; + + if ((neigh_entry->ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV4) && + (neigh_entry->ip_address.addr.ip4 != expected_neigh_entry.ip_address.addr.ip4)) + { + return false; + } + else if ((neigh_entry->ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV6) && + (memcmp(neigh_entry->ip_address.addr.ip6, expected_neigh_entry.ip_address.addr.ip6, 16))) + { + return false; + } + + return true; } -bool MatchNeighborCreateAttributeList(const sai_attribute_t* attr_list, - const swss::MacAddress& dst_mac_address) { - if (attr_list == nullptr) return false; +bool MatchNeighborCreateAttributeList(const sai_attribute_t *attr_list, const swss::MacAddress &dst_mac_address) +{ + if (attr_list == nullptr) + return false; - std::unordered_set attrs; + std::unordered_set attrs; - for (int i = 0; i < 2; ++i) { - if (attrs.count(attr_list[i].id) != 0) { - // Repeated attribute. - return false; - } - switch (attr_list[i].id) { - case SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS: - if (memcmp(attr_list[i].value.mac, dst_mac_address.getMac(), - sizeof(sai_mac_t)) != 0) { - return false; + for (int i = 0; i < 2; ++i) + { + if (attrs.count(attr_list[i].id) != 0) + { + // Repeated attribute. + return false; } - break; - case SAI_NEIGHBOR_ENTRY_ATTR_NO_HOST_ROUTE: - if (!attr_list[i].value.booldata) { - return false; + switch (attr_list[i].id) + { + case SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS: + if (memcmp(attr_list[i].value.mac, dst_mac_address.getMac(), sizeof(sai_mac_t)) != 0) + { + return false; + } + break; + case SAI_NEIGHBOR_ENTRY_ATTR_NO_HOST_ROUTE: + if (!attr_list[i].value.booldata) + { + return false; + } + break; + default: + return false; } - break; - default: - return false; + attrs.insert(attr_list[i].id); } - attrs.insert(attr_list[i].id); - } - return true; + return true; } -bool MatchNeighborSetAttributeList(const sai_attribute_t* attr_list, - const swss::MacAddress& dst_mac_address) { - if (attr_list == nullptr) return false; +bool MatchNeighborSetAttributeList(const sai_attribute_t *attr_list, const swss::MacAddress &dst_mac_address) +{ + if (attr_list == nullptr) + return false; - return (attr_list[0].id == SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS && - memcmp(attr_list[0].value.mac, dst_mac_address.getMac(), - sizeof(sai_mac_t)) == 0); + return (attr_list[0].id == SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS && + memcmp(attr_list[0].value.mac, dst_mac_address.getMac(), sizeof(sai_mac_t)) == 0); } -} // namespace - -class NeighborManagerTest : public ::testing::Test { - protected: - NeighborManagerTest() : neighbor_manager_(&p4_oid_mapper_, &publisher_) {} - - void SetUp() override { - mock_sai_neighbor = &mock_sai_neighbor_; - sai_neighbor_api->create_neighbor_entry = mock_create_neighbor_entry; - sai_neighbor_api->remove_neighbor_entry = mock_remove_neighbor_entry; - sai_neighbor_api->set_neighbor_entry_attribute = - mock_set_neighbor_entry_attribute; - sai_neighbor_api->get_neighbor_entry_attribute = - mock_get_neighbor_entry_attribute; - } - - void Enqueue(const swss::KeyOpFieldsValuesTuple& entry) { - neighbor_manager_.enqueue(APP_P4RT_NEIGHBOR_TABLE_NAME, entry); - } - - void Drain() { neighbor_manager_.drain(); } - - std::string VerifyState(const std::string& key, - const std::vector& tuple) { - return neighbor_manager_.verifyState(key, tuple); - } - - ReturnCodeOr DeserializeNeighborEntry( - const std::string& key, - const std::vector& attributes) { - return neighbor_manager_.deserializeNeighborEntry(key, attributes); - } - - ReturnCode ValidateNeighborAppDbEntry( - const P4NeighborAppDbEntry& app_db_entry) { - return neighbor_manager_.validateNeighborAppDbEntry(app_db_entry); - } - - ReturnCode CreateNeighbor(P4NeighborEntry& neighbor_entry) { - return neighbor_manager_.createNeighbor(neighbor_entry); - } - - ReturnCode RemoveNeighbor(const std::string& neighbor_key) { - return neighbor_manager_.removeNeighbor(neighbor_key); - } - - ReturnCode SetDstMacAddress(P4NeighborEntry* neighbor_entry, - const swss::MacAddress& mac_address) { - return neighbor_manager_.setDstMacAddress(neighbor_entry, mac_address); - } - - ReturnCode ProcessAddRequest(const P4NeighborAppDbEntry& app_db_entry, - const std::string& neighbor_key) { - return neighbor_manager_.processAddRequest(app_db_entry, neighbor_key); - } - - ReturnCode ProcessUpdateRequest(const P4NeighborAppDbEntry& app_db_entry, - P4NeighborEntry* neighbor_entry) { - return neighbor_manager_.processUpdateRequest(app_db_entry, neighbor_entry); - } - - ReturnCode ProcessDeleteRequest(const std::string& neighbor_key) { - return neighbor_manager_.processDeleteRequest(neighbor_key); - } - - P4NeighborEntry* GetNeighborEntry(const std::string& neighbor_key) { - return neighbor_manager_.getNeighborEntry(neighbor_key); - } - - void ValidateNeighborEntry(const P4NeighborEntry& expected_entry, - const uint32_t router_intf_ref_count) { - auto neighbor_entry = GetNeighborEntry(expected_entry.neighbor_key); - - EXPECT_NE(nullptr, neighbor_entry); - EXPECT_EQ(expected_entry.router_intf_id, neighbor_entry->router_intf_id); - EXPECT_EQ(expected_entry.neighbor_id, neighbor_entry->neighbor_id); - EXPECT_EQ(expected_entry.dst_mac_address, neighbor_entry->dst_mac_address); - EXPECT_EQ(expected_entry.router_intf_key, neighbor_entry->router_intf_key); - EXPECT_EQ(expected_entry.neighbor_key, neighbor_entry->neighbor_key); - - EXPECT_TRUE(MatchNeighborEntry(&neighbor_entry->neigh_entry, - expected_entry.neigh_entry)); - - EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, - expected_entry.neighbor_key)); - - uint32_t ref_count; - ASSERT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - expected_entry.router_intf_key, - &ref_count)); - EXPECT_EQ(router_intf_ref_count, ref_count); - } - - void ValidateNeighborEntryNotPresent( - const P4NeighborEntry& neighbor_entry, bool check_ref_count, - const uint32_t router_intf_ref_count = 0) { - auto current_entry = GetNeighborEntry(neighbor_entry.neighbor_key); - EXPECT_EQ(current_entry, nullptr); - EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, - neighbor_entry.neighbor_key)); - - if (check_ref_count) { - uint32_t ref_count; - ASSERT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - neighbor_entry.router_intf_key, - &ref_count)); - EXPECT_EQ(ref_count, router_intf_ref_count); +} // namespace + +class NeighborManagerTest : public ::testing::Test +{ + protected: + NeighborManagerTest() : neighbor_manager_(&p4_oid_mapper_, &publisher_) + { } - } - void AddNeighborEntry(P4NeighborEntry& neighbor_entry, - const sai_object_id_t router_intf_oid) { - sai_neighbor_entry_t neigh_entry; - neigh_entry.switch_id = gSwitchId; - copy(neigh_entry.ip_address, neighbor_entry.neighbor_id); - neigh_entry.rif_id = router_intf_oid; + void SetUp() override + { + mock_sai_neighbor = &mock_sai_neighbor_; + sai_neighbor_api->create_neighbor_entry = mock_create_neighbor_entry; + sai_neighbor_api->remove_neighbor_entry = mock_remove_neighbor_entry; + sai_neighbor_api->set_neighbor_entry_attribute = mock_set_neighbor_entry_attribute; + sai_neighbor_api->get_neighbor_entry_attribute = mock_get_neighbor_entry_attribute; + } - EXPECT_CALL(mock_sai_neighbor_, - create_neighbor_entry( - Truly(std::bind(MatchNeighborEntry, std::placeholders::_1, - neigh_entry)), - Eq(2), - Truly(std::bind(MatchNeighborCreateAttributeList, - std::placeholders::_1, - neighbor_entry.dst_mac_address)))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); + void Enqueue(const swss::KeyOpFieldsValuesTuple &entry) + { + neighbor_manager_.enqueue(APP_P4RT_NEIGHBOR_TABLE_NAME, entry); + } - ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - neighbor_entry.router_intf_key, - router_intf_oid)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, CreateNeighbor(neighbor_entry)); - } - - std::string CreateNeighborAppDbKey(const std::string router_interface_id, - const swss::IpAddress neighbor_id) { - nlohmann::json j; - j[prependMatchField(p4orch::kRouterInterfaceId)] = router_interface_id; - j[prependMatchField(p4orch::kNeighborId)] = neighbor_id.to_string(); - return j.dump(); - } - - StrictMock mock_sai_neighbor_; - MockResponsePublisher publisher_; - P4OidMapper p4_oid_mapper_; - NeighborManager neighbor_manager_; + void Drain() + { + neighbor_manager_.drain(); + } + + std::string VerifyState(const std::string &key, const std::vector &tuple) + { + return neighbor_manager_.verifyState(key, tuple); + } + + ReturnCodeOr DeserializeNeighborEntry(const std::string &key, + const std::vector &attributes) + { + return neighbor_manager_.deserializeNeighborEntry(key, attributes); + } + + ReturnCode ValidateNeighborAppDbEntry(const P4NeighborAppDbEntry &app_db_entry) + { + return neighbor_manager_.validateNeighborAppDbEntry(app_db_entry); + } + + ReturnCode CreateNeighbor(P4NeighborEntry &neighbor_entry) + { + return neighbor_manager_.createNeighbor(neighbor_entry); + } + + ReturnCode RemoveNeighbor(const std::string &neighbor_key) + { + return neighbor_manager_.removeNeighbor(neighbor_key); + } + + ReturnCode SetDstMacAddress(P4NeighborEntry *neighbor_entry, const swss::MacAddress &mac_address) + { + return neighbor_manager_.setDstMacAddress(neighbor_entry, mac_address); + } + + ReturnCode ProcessAddRequest(const P4NeighborAppDbEntry &app_db_entry, const std::string &neighbor_key) + { + return neighbor_manager_.processAddRequest(app_db_entry, neighbor_key); + } + + ReturnCode ProcessUpdateRequest(const P4NeighborAppDbEntry &app_db_entry, P4NeighborEntry *neighbor_entry) + { + return neighbor_manager_.processUpdateRequest(app_db_entry, neighbor_entry); + } + + ReturnCode ProcessDeleteRequest(const std::string &neighbor_key) + { + return neighbor_manager_.processDeleteRequest(neighbor_key); + } + + P4NeighborEntry *GetNeighborEntry(const std::string &neighbor_key) + { + return neighbor_manager_.getNeighborEntry(neighbor_key); + } + + void ValidateNeighborEntry(const P4NeighborEntry &expected_entry, const uint32_t router_intf_ref_count) + { + auto neighbor_entry = GetNeighborEntry(expected_entry.neighbor_key); + + EXPECT_NE(nullptr, neighbor_entry); + EXPECT_EQ(expected_entry.router_intf_id, neighbor_entry->router_intf_id); + EXPECT_EQ(expected_entry.neighbor_id, neighbor_entry->neighbor_id); + EXPECT_EQ(expected_entry.dst_mac_address, neighbor_entry->dst_mac_address); + EXPECT_EQ(expected_entry.router_intf_key, neighbor_entry->router_intf_key); + EXPECT_EQ(expected_entry.neighbor_key, neighbor_entry->neighbor_key); + + EXPECT_TRUE(MatchNeighborEntry(&neighbor_entry->neigh_entry, expected_entry.neigh_entry)); + + EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, expected_entry.neighbor_key)); + + uint32_t ref_count; + ASSERT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, expected_entry.router_intf_key, &ref_count)); + EXPECT_EQ(router_intf_ref_count, ref_count); + } + + void ValidateNeighborEntryNotPresent(const P4NeighborEntry &neighbor_entry, bool check_ref_count, + const uint32_t router_intf_ref_count = 0) + { + auto current_entry = GetNeighborEntry(neighbor_entry.neighbor_key); + EXPECT_EQ(current_entry, nullptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_entry.neighbor_key)); + + if (check_ref_count) + { + uint32_t ref_count; + ASSERT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, neighbor_entry.router_intf_key, + &ref_count)); + EXPECT_EQ(ref_count, router_intf_ref_count); + } + } + + void AddNeighborEntry(P4NeighborEntry &neighbor_entry, const sai_object_id_t router_intf_oid) + { + sai_neighbor_entry_t neigh_entry; + neigh_entry.switch_id = gSwitchId; + copy(neigh_entry.ip_address, neighbor_entry.neighbor_id); + neigh_entry.rif_id = router_intf_oid; + + EXPECT_CALL(mock_sai_neighbor_, + create_neighbor_entry(Truly(std::bind(MatchNeighborEntry, std::placeholders::_1, neigh_entry)), + Eq(2), + Truly(std::bind(MatchNeighborCreateAttributeList, std::placeholders::_1, + neighbor_entry.dst_mac_address)))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + ASSERT_TRUE( + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, neighbor_entry.router_intf_key, router_intf_oid)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, CreateNeighbor(neighbor_entry)); + } + + std::string CreateNeighborAppDbKey(const std::string router_interface_id, const swss::IpAddress neighbor_id) + { + nlohmann::json j; + j[prependMatchField(p4orch::kRouterInterfaceId)] = router_interface_id; + j[prependMatchField(p4orch::kNeighborId)] = neighbor_id.to_string(); + return j.dump(); + } + + StrictMock mock_sai_neighbor_; + MockResponsePublisher publisher_; + P4OidMapper p4_oid_mapper_; + NeighborManager neighbor_manager_; }; -TEST_F(NeighborManagerTest, CreateNeighborValidAttributes) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, - kMacAddress1); - AddNeighborEntry(neighbor_entry, kRouterInterfaceOid1); +TEST_F(NeighborManagerTest, CreateNeighborValidAttributes) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, kMacAddress1); + AddNeighborEntry(neighbor_entry, kRouterInterfaceOid1); - ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); + ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); } -TEST_F(NeighborManagerTest, CreateNeighborEntryExistsInManager) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, - kMacAddress1); - AddNeighborEntry(neighbor_entry, kRouterInterfaceOid1); +TEST_F(NeighborManagerTest, CreateNeighborEntryExistsInManager) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, kMacAddress1); + AddNeighborEntry(neighbor_entry, kRouterInterfaceOid1); - // Same neighbor key with different destination mac address. - P4NeighborEntry new_entry(kRouterInterfaceId1, kNeighborId1, kMacAddress2); - EXPECT_EQ(StatusCode::SWSS_RC_EXISTS, CreateNeighbor(new_entry)); + // Same neighbor key with different destination mac address. + P4NeighborEntry new_entry(kRouterInterfaceId1, kNeighborId1, kMacAddress2); + EXPECT_EQ(StatusCode::SWSS_RC_EXISTS, CreateNeighbor(new_entry)); - // Validate that entry in Manager has not changed. - ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); + // Validate that entry in Manager has not changed. + ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); } -TEST_F(NeighborManagerTest, CreateNeighborEntryExistsInP4OidMapper) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, - kMacAddress2); - p4_oid_mapper_.setDummyOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, - neighbor_entry.neighbor_key); +TEST_F(NeighborManagerTest, CreateNeighborEntryExistsInP4OidMapper) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, kMacAddress2); + p4_oid_mapper_.setDummyOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_entry.neighbor_key); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, CreateNeighbor(neighbor_entry)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, CreateNeighbor(neighbor_entry)); - auto current_entry = GetNeighborEntry(neighbor_entry.neighbor_key); - EXPECT_EQ(current_entry, nullptr); + auto current_entry = GetNeighborEntry(neighbor_entry.neighbor_key); + EXPECT_EQ(current_entry, nullptr); - // Validate that dummyOID still exists in Centralized Mapper. - EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, - neighbor_entry.neighbor_key)); + // Validate that dummyOID still exists in Centralized Mapper. + EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_entry.neighbor_key)); } -TEST_F(NeighborManagerTest, CreateNeighborNonExistentRouterIntf) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, - kMacAddress2); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, CreateNeighbor(neighbor_entry)); +TEST_F(NeighborManagerTest, CreateNeighborNonExistentRouterIntf) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, kMacAddress2); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, CreateNeighbor(neighbor_entry)); - ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/false); + ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/false); } -TEST_F(NeighborManagerTest, CreateNeighborSaiApiFails) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, - kMacAddress1); +TEST_F(NeighborManagerTest, CreateNeighborSaiApiFails) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, kMacAddress1); - ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - neighbor_entry.router_intf_key, - kRouterInterfaceOid1)); - EXPECT_CALL(mock_sai_neighbor_, create_neighbor_entry(_, _, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); + ASSERT_TRUE( + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, neighbor_entry.router_intf_key, kRouterInterfaceOid1)); + EXPECT_CALL(mock_sai_neighbor_, create_neighbor_entry(_, _, _)).WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, CreateNeighbor(neighbor_entry)); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, CreateNeighbor(neighbor_entry)); - ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/true); + ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/true); } -TEST_F(NeighborManagerTest, RemoveNeighborExistingNeighborEntry) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, - kMacAddress2); - AddNeighborEntry(neighbor_entry, kRouterInterfaceOid2); +TEST_F(NeighborManagerTest, RemoveNeighborExistingNeighborEntry) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, kMacAddress2); + AddNeighborEntry(neighbor_entry, kRouterInterfaceOid2); - sai_neighbor_entry_t neigh_entry; - neigh_entry.switch_id = gSwitchId; - copy(neigh_entry.ip_address, neighbor_entry.neighbor_id); - neigh_entry.rif_id = kRouterInterfaceOid2; + sai_neighbor_entry_t neigh_entry; + neigh_entry.switch_id = gSwitchId; + copy(neigh_entry.ip_address, neighbor_entry.neighbor_id); + neigh_entry.rif_id = kRouterInterfaceOid2; - EXPECT_CALL(mock_sai_neighbor_, - remove_neighbor_entry(Truly(std::bind( - MatchNeighborEntry, std::placeholders::_1, neigh_entry)))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_neighbor_, + remove_neighbor_entry(Truly(std::bind(MatchNeighborEntry, std::placeholders::_1, neigh_entry)))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - RemoveNeighbor(neighbor_entry.neighbor_key)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, RemoveNeighbor(neighbor_entry.neighbor_key)); - ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/true); + ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/true); } -TEST_F(NeighborManagerTest, RemoveNeighborNonExistingNeighborEntry) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, - kMacAddress2); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - RemoveNeighbor(neighbor_entry.neighbor_key)); +TEST_F(NeighborManagerTest, RemoveNeighborNonExistingNeighborEntry) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, kMacAddress2); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, RemoveNeighbor(neighbor_entry.neighbor_key)); } -TEST_F(NeighborManagerTest, RemoveNeighborNotExistInMapper) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, - kMacAddress2); - AddNeighborEntry(neighbor_entry, kRouterInterfaceOid2); +TEST_F(NeighborManagerTest, RemoveNeighborNotExistInMapper) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, kMacAddress2); + AddNeighborEntry(neighbor_entry, kRouterInterfaceOid2); - ASSERT_TRUE(p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, - neighbor_entry.neighbor_key)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, - RemoveNeighbor(neighbor_entry.neighbor_key)); + ASSERT_TRUE(p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_entry.neighbor_key)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, RemoveNeighbor(neighbor_entry.neighbor_key)); } -TEST_F(NeighborManagerTest, RemoveNeighborNonZeroRefCount) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, - kMacAddress2); - AddNeighborEntry(neighbor_entry, kRouterInterfaceOid2); +TEST_F(NeighborManagerTest, RemoveNeighborNonZeroRefCount) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, kMacAddress2); + AddNeighborEntry(neighbor_entry, kRouterInterfaceOid2); - ASSERT_TRUE(p4_oid_mapper_.increaseRefCount(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, - neighbor_entry.neighbor_key)); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - RemoveNeighbor(neighbor_entry.neighbor_key)); + ASSERT_TRUE(p4_oid_mapper_.increaseRefCount(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_entry.neighbor_key)); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, RemoveNeighbor(neighbor_entry.neighbor_key)); - ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); + ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); } -TEST_F(NeighborManagerTest, RemoveNeighborSaiApiFails) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, - kMacAddress2); - AddNeighborEntry(neighbor_entry, kRouterInterfaceOid2); +TEST_F(NeighborManagerTest, RemoveNeighborSaiApiFails) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, kMacAddress2); + AddNeighborEntry(neighbor_entry, kRouterInterfaceOid2); - EXPECT_CALL(mock_sai_neighbor_, remove_neighbor_entry(_)) - .WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_neighbor_, remove_neighbor_entry(_)).WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - RemoveNeighbor(neighbor_entry.neighbor_key)); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, RemoveNeighbor(neighbor_entry.neighbor_key)); - ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); + ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); } -TEST_F(NeighborManagerTest, SetDstMacAddressModifyMacAddress) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, - kMacAddress2); - AddNeighborEntry(neighbor_entry, kRouterInterfaceOid2); - - sai_neighbor_entry_t neigh_entry; - neigh_entry.switch_id = gSwitchId; - copy(neigh_entry.ip_address, neighbor_entry.neighbor_id); - neigh_entry.rif_id = kRouterInterfaceOid2; - - EXPECT_CALL(mock_sai_neighbor_, - set_neighbor_entry_attribute( - Truly(std::bind(MatchNeighborEntry, std::placeholders::_1, - neigh_entry)), - Truly(std::bind(MatchNeighborSetAttributeList, - std::placeholders::_1, kMacAddress1)))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - SetDstMacAddress(&neighbor_entry, kMacAddress1)); - EXPECT_EQ(neighbor_entry.dst_mac_address, kMacAddress1); +TEST_F(NeighborManagerTest, SetDstMacAddressModifyMacAddress) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, kMacAddress2); + AddNeighborEntry(neighbor_entry, kRouterInterfaceOid2); + + sai_neighbor_entry_t neigh_entry; + neigh_entry.switch_id = gSwitchId; + copy(neigh_entry.ip_address, neighbor_entry.neighbor_id); + neigh_entry.rif_id = kRouterInterfaceOid2; + + EXPECT_CALL(mock_sai_neighbor_, + set_neighbor_entry_attribute( + Truly(std::bind(MatchNeighborEntry, std::placeholders::_1, neigh_entry)), + Truly(std::bind(MatchNeighborSetAttributeList, std::placeholders::_1, kMacAddress1)))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, SetDstMacAddress(&neighbor_entry, kMacAddress1)); + EXPECT_EQ(neighbor_entry.dst_mac_address, kMacAddress1); } -TEST_F(NeighborManagerTest, SetDstMacAddressIdempotent) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, - kMacAddress2); +TEST_F(NeighborManagerTest, SetDstMacAddressIdempotent) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, kMacAddress2); - // SAI API not being called makes the operation idempotent. - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - SetDstMacAddress(&neighbor_entry, kMacAddress2)); - EXPECT_EQ(neighbor_entry.dst_mac_address, kMacAddress2); + // SAI API not being called makes the operation idempotent. + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, SetDstMacAddress(&neighbor_entry, kMacAddress2)); + EXPECT_EQ(neighbor_entry.dst_mac_address, kMacAddress2); } -TEST_F(NeighborManagerTest, SetDstMacAddressSaiApiFails) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, - kMacAddress2); +TEST_F(NeighborManagerTest, SetDstMacAddressSaiApiFails) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId2, kNeighborId2, kMacAddress2); - EXPECT_CALL(mock_sai_neighbor_, set_neighbor_entry_attribute(_, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_neighbor_, set_neighbor_entry_attribute(_, _)).WillOnce(Return(SAI_STATUS_FAILURE)); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - SetDstMacAddress(&neighbor_entry, kMacAddress1)); - EXPECT_EQ(neighbor_entry.dst_mac_address, kMacAddress2); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, SetDstMacAddress(&neighbor_entry, kMacAddress1)); + EXPECT_EQ(neighbor_entry.dst_mac_address, kMacAddress2); } -TEST_F(NeighborManagerTest, ProcessAddRequestValidAppDbParams) { - const P4NeighborAppDbEntry app_db_entry = { - .router_intf_id = kRouterInterfaceId1, - .neighbor_id = kNeighborId1, - .dst_mac_address = kMacAddress1, - .is_set_dst_mac = true}; - - P4NeighborEntry neighbor_entry(app_db_entry.router_intf_id, - app_db_entry.neighbor_id, - app_db_entry.dst_mac_address); - neighbor_entry.neigh_entry.switch_id = gSwitchId; - copy(neighbor_entry.neigh_entry.ip_address, app_db_entry.neighbor_id); - neighbor_entry.neigh_entry.rif_id = kRouterInterfaceOid1; - - EXPECT_CALL(mock_sai_neighbor_, - create_neighbor_entry( - Truly(std::bind(MatchNeighborEntry, std::placeholders::_1, - neighbor_entry.neigh_entry)), - Eq(2), - Truly(std::bind(MatchNeighborCreateAttributeList, - std::placeholders::_1, - app_db_entry.dst_mac_address)))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - ASSERT_TRUE(p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_intf_id), - neighbor_entry.neigh_entry.rif_id)); - - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - app_db_entry.router_intf_id, app_db_entry.neighbor_id); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRequest(app_db_entry, neighbor_key)); - - ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); +TEST_F(NeighborManagerTest, ProcessAddRequestValidAppDbParams) +{ + const P4NeighborAppDbEntry app_db_entry = {.router_intf_id = kRouterInterfaceId1, + .neighbor_id = kNeighborId1, + .dst_mac_address = kMacAddress1, + .is_set_dst_mac = true}; + + P4NeighborEntry neighbor_entry(app_db_entry.router_intf_id, app_db_entry.neighbor_id, app_db_entry.dst_mac_address); + neighbor_entry.neigh_entry.switch_id = gSwitchId; + copy(neighbor_entry.neigh_entry.ip_address, app_db_entry.neighbor_id); + neighbor_entry.neigh_entry.rif_id = kRouterInterfaceOid1; + + EXPECT_CALL( + mock_sai_neighbor_, + create_neighbor_entry( + Truly(std::bind(MatchNeighborEntry, std::placeholders::_1, neighbor_entry.neigh_entry)), Eq(2), + Truly(std::bind(MatchNeighborCreateAttributeList, std::placeholders::_1, app_db_entry.dst_mac_address)))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_intf_id), + neighbor_entry.neigh_entry.rif_id)); + + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(app_db_entry.router_intf_id, app_db_entry.neighbor_id); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRequest(app_db_entry, neighbor_key)); + + ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); } -TEST_F(NeighborManagerTest, ProcessAddRequesDstMacAddressNotSet) { - const P4NeighborAppDbEntry app_db_entry = { - .router_intf_id = kRouterInterfaceId1, - .neighbor_id = kNeighborId1, - .dst_mac_address = swss::MacAddress(), - .is_set_dst_mac = false}; - - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - app_db_entry.router_intf_id, app_db_entry.neighbor_id); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRequest(app_db_entry, neighbor_key)); - - P4NeighborEntry neighbor_entry(app_db_entry.router_intf_id, - app_db_entry.neighbor_id, - app_db_entry.dst_mac_address); - ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/false); +TEST_F(NeighborManagerTest, ProcessAddRequesDstMacAddressNotSet) +{ + const P4NeighborAppDbEntry app_db_entry = {.router_intf_id = kRouterInterfaceId1, + .neighbor_id = kNeighborId1, + .dst_mac_address = swss::MacAddress(), + .is_set_dst_mac = false}; + + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(app_db_entry.router_intf_id, app_db_entry.neighbor_id); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRequest(app_db_entry, neighbor_key)); + + P4NeighborEntry neighbor_entry(app_db_entry.router_intf_id, app_db_entry.neighbor_id, app_db_entry.dst_mac_address); + ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/false); } -TEST_F(NeighborManagerTest, ProcessAddRequestInvalidRouterInterface) { - const P4NeighborAppDbEntry app_db_entry = { - .router_intf_id = kRouterInterfaceId1, - .neighbor_id = kNeighborId1, - .dst_mac_address = kMacAddress1, - .is_set_dst_mac = true}; - - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - app_db_entry.router_intf_id, app_db_entry.neighbor_id); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessAddRequest(app_db_entry, neighbor_key)); - - P4NeighborEntry neighbor_entry(app_db_entry.router_intf_id, - app_db_entry.neighbor_id, - app_db_entry.dst_mac_address); - ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/false); +TEST_F(NeighborManagerTest, ProcessAddRequestInvalidRouterInterface) +{ + const P4NeighborAppDbEntry app_db_entry = {.router_intf_id = kRouterInterfaceId1, + .neighbor_id = kNeighborId1, + .dst_mac_address = kMacAddress1, + .is_set_dst_mac = true}; + + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(app_db_entry.router_intf_id, app_db_entry.neighbor_id); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessAddRequest(app_db_entry, neighbor_key)); + + P4NeighborEntry neighbor_entry(app_db_entry.router_intf_id, app_db_entry.neighbor_id, app_db_entry.dst_mac_address); + ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/false); } -TEST_F(NeighborManagerTest, ProcessUpdateRequestSetDstMacAddress) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, - kMacAddress1); - AddNeighborEntry(neighbor_entry, kRouterInterfaceOid1); - - neighbor_entry.neigh_entry.switch_id = gSwitchId; - copy(neighbor_entry.neigh_entry.ip_address, neighbor_entry.neighbor_id); - neighbor_entry.neigh_entry.rif_id = kRouterInterfaceOid1; - - EXPECT_CALL(mock_sai_neighbor_, - set_neighbor_entry_attribute( - Truly(std::bind(MatchNeighborEntry, std::placeholders::_1, - neighbor_entry.neigh_entry)), - Truly(std::bind(MatchNeighborSetAttributeList, - std::placeholders::_1, kMacAddress2)))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - const P4NeighborAppDbEntry app_db_entry = { - .router_intf_id = kRouterInterfaceId1, - .neighbor_id = kNeighborId1, - .dst_mac_address = kMacAddress2, - .is_set_dst_mac = true}; - - // Update neighbor entry present in the Manager. - auto current_entry = GetNeighborEntry(neighbor_entry.neighbor_key); - ASSERT_NE(current_entry, nullptr); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRequest(app_db_entry, current_entry)); - - // Validate that neighbor entry present in the Manager has the updated - // MacAddress. - neighbor_entry.dst_mac_address = kMacAddress2; - ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); +TEST_F(NeighborManagerTest, ProcessUpdateRequestSetDstMacAddress) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, kMacAddress1); + AddNeighborEntry(neighbor_entry, kRouterInterfaceOid1); + + neighbor_entry.neigh_entry.switch_id = gSwitchId; + copy(neighbor_entry.neigh_entry.ip_address, neighbor_entry.neighbor_id); + neighbor_entry.neigh_entry.rif_id = kRouterInterfaceOid1; + + EXPECT_CALL(mock_sai_neighbor_, + set_neighbor_entry_attribute( + Truly(std::bind(MatchNeighborEntry, std::placeholders::_1, neighbor_entry.neigh_entry)), + Truly(std::bind(MatchNeighborSetAttributeList, std::placeholders::_1, kMacAddress2)))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + const P4NeighborAppDbEntry app_db_entry = {.router_intf_id = kRouterInterfaceId1, + .neighbor_id = kNeighborId1, + .dst_mac_address = kMacAddress2, + .is_set_dst_mac = true}; + + // Update neighbor entry present in the Manager. + auto current_entry = GetNeighborEntry(neighbor_entry.neighbor_key); + ASSERT_NE(current_entry, nullptr); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRequest(app_db_entry, current_entry)); + + // Validate that neighbor entry present in the Manager has the updated + // MacAddress. + neighbor_entry.dst_mac_address = kMacAddress2; + ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); } -TEST_F(NeighborManagerTest, ProcessUpdateRequestSetDstMacAddressFails) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, - kMacAddress1); - AddNeighborEntry(neighbor_entry, kRouterInterfaceOid1); +TEST_F(NeighborManagerTest, ProcessUpdateRequestSetDstMacAddressFails) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, kMacAddress1); + AddNeighborEntry(neighbor_entry, kRouterInterfaceOid1); - EXPECT_CALL(mock_sai_neighbor_, set_neighbor_entry_attribute(_, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); + EXPECT_CALL(mock_sai_neighbor_, set_neighbor_entry_attribute(_, _)).WillOnce(Return(SAI_STATUS_FAILURE)); - const P4NeighborAppDbEntry app_db_entry = { - .router_intf_id = kRouterInterfaceId1, - .neighbor_id = kNeighborId1, - .dst_mac_address = kMacAddress2, - .is_set_dst_mac = true}; + const P4NeighborAppDbEntry app_db_entry = {.router_intf_id = kRouterInterfaceId1, + .neighbor_id = kNeighborId1, + .dst_mac_address = kMacAddress2, + .is_set_dst_mac = true}; - // Update neighbor entry present in the Manager. - auto current_entry = GetNeighborEntry(neighbor_entry.neighbor_key); - ASSERT_NE(current_entry, nullptr); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - ProcessUpdateRequest(app_db_entry, current_entry)); + // Update neighbor entry present in the Manager. + auto current_entry = GetNeighborEntry(neighbor_entry.neighbor_key); + ASSERT_NE(current_entry, nullptr); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessUpdateRequest(app_db_entry, current_entry)); - // Validate that neighbor entry present in the Manager has not changed. - ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); + // Validate that neighbor entry present in the Manager has not changed. + ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); } -TEST_F(NeighborManagerTest, ProcessDeleteRequestExistingNeighborEntry) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, - kMacAddress1); - AddNeighborEntry(neighbor_entry, kRouterInterfaceOid1); +TEST_F(NeighborManagerTest, ProcessDeleteRequestExistingNeighborEntry) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, kMacAddress1); + AddNeighborEntry(neighbor_entry, kRouterInterfaceOid1); - neighbor_entry.neigh_entry.switch_id = gSwitchId; - copy(neighbor_entry.neigh_entry.ip_address, neighbor_entry.neighbor_id); - neighbor_entry.neigh_entry.rif_id = kRouterInterfaceOid1; + neighbor_entry.neigh_entry.switch_id = gSwitchId; + copy(neighbor_entry.neigh_entry.ip_address, neighbor_entry.neighbor_id); + neighbor_entry.neigh_entry.rif_id = kRouterInterfaceOid1; - EXPECT_CALL(mock_sai_neighbor_, remove_neighbor_entry(Truly(std::bind( - MatchNeighborEntry, std::placeholders::_1, - neighbor_entry.neigh_entry)))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_neighbor_, remove_neighbor_entry(Truly(std::bind(MatchNeighborEntry, std::placeholders::_1, + neighbor_entry.neigh_entry)))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRequest(neighbor_entry.neighbor_key)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRequest(neighbor_entry.neighbor_key)); - ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/true); + ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/true); } -TEST_F(NeighborManagerTest, ProcessDeleteRequestNonExistingNeighborEntry) { - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessDeleteRequest(KeyGenerator::generateNeighborKey( - kRouterInterfaceId1, kNeighborId1))); +TEST_F(NeighborManagerTest, ProcessDeleteRequestNonExistingNeighborEntry) +{ + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, + ProcessDeleteRequest(KeyGenerator::generateNeighborKey(kRouterInterfaceId1, kNeighborId1))); } -TEST_F(NeighborManagerTest, DeserializeNeighborEntryValidAttributes) { - const std::vector attributes = { - swss::FieldValueTuple(p4orch::kAction, "set_dst_mac"), - swss::FieldValueTuple(prependParamField(p4orch::kDstMac), - kMacAddress2.to_string()), - }; - - auto app_db_entry_or = DeserializeNeighborEntry( - CreateNeighborAppDbKey(kRouterInterfaceId2, kNeighborId2), attributes); - EXPECT_TRUE(app_db_entry_or.ok()); - auto& app_db_entry = *app_db_entry_or; - EXPECT_EQ(app_db_entry.router_intf_id, kRouterInterfaceId2); - EXPECT_EQ(app_db_entry.neighbor_id, kNeighborId2); - EXPECT_EQ(app_db_entry.dst_mac_address, kMacAddress2); - EXPECT_TRUE(app_db_entry.is_set_dst_mac); +TEST_F(NeighborManagerTest, DeserializeNeighborEntryValidAttributes) +{ + const std::vector attributes = { + swss::FieldValueTuple(p4orch::kAction, "set_dst_mac"), + swss::FieldValueTuple(prependParamField(p4orch::kDstMac), kMacAddress2.to_string()), + }; + + auto app_db_entry_or = + DeserializeNeighborEntry(CreateNeighborAppDbKey(kRouterInterfaceId2, kNeighborId2), attributes); + EXPECT_TRUE(app_db_entry_or.ok()); + auto &app_db_entry = *app_db_entry_or; + EXPECT_EQ(app_db_entry.router_intf_id, kRouterInterfaceId2); + EXPECT_EQ(app_db_entry.neighbor_id, kNeighborId2); + EXPECT_EQ(app_db_entry.dst_mac_address, kMacAddress2); + EXPECT_TRUE(app_db_entry.is_set_dst_mac); } -TEST_F(NeighborManagerTest, DeserializeNeighborEntryInvalidKeyFormat) { - const std::vector attributes = { - swss::FieldValueTuple(p4orch::kAction, "set_dst_mac"), - swss::FieldValueTuple(prependParamField(p4orch::kDstMac), - kMacAddress2.to_string()), - }; - - // Ensure that the following key is valid. It shall be modified to construct - // invalid key in rest of the test case. - std::string valid_key = - R"({"match/router_interface_id":"intf-3/4","match/neighbor_id":"10.0.0.1"})"; - EXPECT_TRUE(DeserializeNeighborEntry(valid_key, attributes).ok()); - - // Invalid json format. - std::string invalid_key = - R"({"match/router_interface_id:intf-3/4,match/neighbor_id:10.0.0.1"})"; - EXPECT_FALSE(DeserializeNeighborEntry(invalid_key, attributes).ok()); - - // Invalid json format. - invalid_key = - R"([{"match/router_interface_id":"intf-3/4","match/neighbor_id":"10.0.0.1"}])"; - EXPECT_FALSE(DeserializeNeighborEntry(invalid_key, attributes).ok()); - - // Invalid json format. - invalid_key = - R"(["match/router_interface_id","intf-3/4","match/neighbor_id","10.0.0.1"])"; - EXPECT_FALSE(DeserializeNeighborEntry(invalid_key, attributes).ok()); - - // Invalid json format. - invalid_key = - R"({"match/router_interface_id":"intf-3/4","match/neighbor_id:10.0.0.1"})"; - EXPECT_FALSE(DeserializeNeighborEntry(invalid_key, attributes).ok()); - - // Invalid router interface id field name. - invalid_key = - R"({"match/router_interface":"intf-3/4","match/neighbor_id":"10.0.0.1"})"; - EXPECT_FALSE(DeserializeNeighborEntry(invalid_key, attributes).ok()); - - // Invalid neighbor id field name. - invalid_key = - R"({"match/router_interface_id":"intf-3/4","match/neighbor":"10.0.0.1"})"; - EXPECT_FALSE(DeserializeNeighborEntry(invalid_key, attributes).ok()); +TEST_F(NeighborManagerTest, DeserializeNeighborEntryInvalidKeyFormat) +{ + const std::vector attributes = { + swss::FieldValueTuple(p4orch::kAction, "set_dst_mac"), + swss::FieldValueTuple(prependParamField(p4orch::kDstMac), kMacAddress2.to_string()), + }; + + // Ensure that the following key is valid. It shall be modified to construct + // invalid key in rest of the test case. + std::string valid_key = R"({"match/router_interface_id":"intf-3/4","match/neighbor_id":"10.0.0.1"})"; + EXPECT_TRUE(DeserializeNeighborEntry(valid_key, attributes).ok()); + + // Invalid json format. + std::string invalid_key = R"({"match/router_interface_id:intf-3/4,match/neighbor_id:10.0.0.1"})"; + EXPECT_FALSE(DeserializeNeighborEntry(invalid_key, attributes).ok()); + + // Invalid json format. + invalid_key = R"([{"match/router_interface_id":"intf-3/4","match/neighbor_id":"10.0.0.1"}])"; + EXPECT_FALSE(DeserializeNeighborEntry(invalid_key, attributes).ok()); + + // Invalid json format. + invalid_key = R"(["match/router_interface_id","intf-3/4","match/neighbor_id","10.0.0.1"])"; + EXPECT_FALSE(DeserializeNeighborEntry(invalid_key, attributes).ok()); + + // Invalid json format. + invalid_key = R"({"match/router_interface_id":"intf-3/4","match/neighbor_id:10.0.0.1"})"; + EXPECT_FALSE(DeserializeNeighborEntry(invalid_key, attributes).ok()); + + // Invalid router interface id field name. + invalid_key = R"({"match/router_interface":"intf-3/4","match/neighbor_id":"10.0.0.1"})"; + EXPECT_FALSE(DeserializeNeighborEntry(invalid_key, attributes).ok()); + + // Invalid neighbor id field name. + invalid_key = R"({"match/router_interface_id":"intf-3/4","match/neighbor":"10.0.0.1"})"; + EXPECT_FALSE(DeserializeNeighborEntry(invalid_key, attributes).ok()); } -TEST_F(NeighborManagerTest, DeserializeNeighborEntryMissingAction) { - const std::vector attributes = { - swss::FieldValueTuple(prependParamField(p4orch::kDstMac), - kMacAddress2.to_string()), - }; - - auto app_db_entry_or = DeserializeNeighborEntry( - CreateNeighborAppDbKey(kRouterInterfaceId2, kNeighborId2), attributes); - EXPECT_TRUE(app_db_entry_or.ok()); - auto& app_db_entry = *app_db_entry_or; - EXPECT_EQ(app_db_entry.router_intf_id, kRouterInterfaceId2); - EXPECT_EQ(app_db_entry.neighbor_id, kNeighborId2); - EXPECT_EQ(app_db_entry.dst_mac_address, kMacAddress2); - EXPECT_TRUE(app_db_entry.is_set_dst_mac); +TEST_F(NeighborManagerTest, DeserializeNeighborEntryMissingAction) +{ + const std::vector attributes = { + swss::FieldValueTuple(prependParamField(p4orch::kDstMac), kMacAddress2.to_string()), + }; + + auto app_db_entry_or = + DeserializeNeighborEntry(CreateNeighborAppDbKey(kRouterInterfaceId2, kNeighborId2), attributes); + EXPECT_TRUE(app_db_entry_or.ok()); + auto &app_db_entry = *app_db_entry_or; + EXPECT_EQ(app_db_entry.router_intf_id, kRouterInterfaceId2); + EXPECT_EQ(app_db_entry.neighbor_id, kNeighborId2); + EXPECT_EQ(app_db_entry.dst_mac_address, kMacAddress2); + EXPECT_TRUE(app_db_entry.is_set_dst_mac); } -TEST_F(NeighborManagerTest, DeserializeNeighborEntryNoAttributes) { - const std::vector attributes; - - auto app_db_entry_or = DeserializeNeighborEntry( - CreateNeighborAppDbKey(kRouterInterfaceId2, kNeighborId2), attributes); - EXPECT_TRUE(app_db_entry_or.ok()); - auto& app_db_entry = *app_db_entry_or; - EXPECT_EQ(app_db_entry.router_intf_id, kRouterInterfaceId2); - EXPECT_EQ(app_db_entry.neighbor_id, kNeighborId2); - EXPECT_EQ(app_db_entry.dst_mac_address, swss::MacAddress()); - EXPECT_FALSE(app_db_entry.is_set_dst_mac); +TEST_F(NeighborManagerTest, DeserializeNeighborEntryNoAttributes) +{ + const std::vector attributes; + + auto app_db_entry_or = + DeserializeNeighborEntry(CreateNeighborAppDbKey(kRouterInterfaceId2, kNeighborId2), attributes); + EXPECT_TRUE(app_db_entry_or.ok()); + auto &app_db_entry = *app_db_entry_or; + EXPECT_EQ(app_db_entry.router_intf_id, kRouterInterfaceId2); + EXPECT_EQ(app_db_entry.neighbor_id, kNeighborId2); + EXPECT_EQ(app_db_entry.dst_mac_address, swss::MacAddress()); + EXPECT_FALSE(app_db_entry.is_set_dst_mac); } -TEST_F(NeighborManagerTest, DeserializeNeighborEntryInvalidField) { - const std::vector attributes = { - swss::FieldValueTuple("invalid_field", "invalid_value")}; +TEST_F(NeighborManagerTest, DeserializeNeighborEntryInvalidField) +{ + const std::vector attributes = {swss::FieldValueTuple("invalid_field", "invalid_value")}; - EXPECT_FALSE( - DeserializeNeighborEntry( - CreateNeighborAppDbKey(kRouterInterfaceId2, kNeighborId2), attributes) - .ok()); + EXPECT_FALSE(DeserializeNeighborEntry(CreateNeighborAppDbKey(kRouterInterfaceId2, kNeighborId2), attributes).ok()); } -TEST_F(NeighborManagerTest, DeserializeNeighborEntryInvalidIpAddrValue) { - const std::vector attributes; +TEST_F(NeighborManagerTest, DeserializeNeighborEntryInvalidIpAddrValue) +{ + const std::vector attributes; - // Invalid IPv4 address. - std::string invalid_key = - R"({"match/router_interface_id":"intf-3/4","match/neighbor_id":"10.0.0.x"})"; - EXPECT_FALSE(DeserializeNeighborEntry(invalid_key, attributes).ok()); + // Invalid IPv4 address. + std::string invalid_key = R"({"match/router_interface_id":"intf-3/4","match/neighbor_id":"10.0.0.x"})"; + EXPECT_FALSE(DeserializeNeighborEntry(invalid_key, attributes).ok()); - // Invalid IPv6 address. - invalid_key = - R"({"match/router_interface_id":"intf-3/4","match/neighbor_id":"fe80::fe17:5f8g"})"; - EXPECT_FALSE(DeserializeNeighborEntry(invalid_key, attributes).ok()); + // Invalid IPv6 address. + invalid_key = R"({"match/router_interface_id":"intf-3/4","match/neighbor_id":"fe80::fe17:5f8g"})"; + EXPECT_FALSE(DeserializeNeighborEntry(invalid_key, attributes).ok()); } -TEST_F(NeighborManagerTest, DeserializeNeighborEntryInvalidMacAddrValue) { - const std::vector attributes = {swss::FieldValueTuple( - prependParamField(p4orch::kDstMac), "11:22:33:44:55")}; +TEST_F(NeighborManagerTest, DeserializeNeighborEntryInvalidMacAddrValue) +{ + const std::vector attributes = { + swss::FieldValueTuple(prependParamField(p4orch::kDstMac), "11:22:33:44:55")}; - EXPECT_FALSE( - DeserializeNeighborEntry( - CreateNeighborAppDbKey(kRouterInterfaceId2, kNeighborId2), attributes) - .ok()); + EXPECT_FALSE(DeserializeNeighborEntry(CreateNeighborAppDbKey(kRouterInterfaceId2, kNeighborId2), attributes).ok()); } -TEST_F(NeighborManagerTest, ValidateNeighborAppDbEntryValidEntry) { - const P4NeighborAppDbEntry app_db_entry = { - .router_intf_id = kRouterInterfaceId1, - .neighbor_id = kNeighborId1, - .dst_mac_address = kMacAddress1, - .is_set_dst_mac = true}; +TEST_F(NeighborManagerTest, ValidateNeighborAppDbEntryValidEntry) +{ + const P4NeighborAppDbEntry app_db_entry = {.router_intf_id = kRouterInterfaceId1, + .neighbor_id = kNeighborId1, + .dst_mac_address = kMacAddress1, + .is_set_dst_mac = true}; - ASSERT_TRUE(p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_intf_id), - kRouterInterfaceOid1)); + ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_intf_id), + kRouterInterfaceOid1)); - EXPECT_TRUE(ValidateNeighborAppDbEntry(app_db_entry).ok()); + EXPECT_TRUE(ValidateNeighborAppDbEntry(app_db_entry).ok()); } -TEST_F(NeighborManagerTest, - ValidateNeighborAppDbEntryNonExistentRouterInterface) { - const P4NeighborAppDbEntry app_db_entry = { - .router_intf_id = kRouterInterfaceId1, - .neighbor_id = kNeighborId1, - .dst_mac_address = kMacAddress1, - .is_set_dst_mac = true}; +TEST_F(NeighborManagerTest, ValidateNeighborAppDbEntryNonExistentRouterInterface) +{ + const P4NeighborAppDbEntry app_db_entry = {.router_intf_id = kRouterInterfaceId1, + .neighbor_id = kNeighborId1, + .dst_mac_address = kMacAddress1, + .is_set_dst_mac = true}; - EXPECT_FALSE(ValidateNeighborAppDbEntry(app_db_entry).ok()); + EXPECT_FALSE(ValidateNeighborAppDbEntry(app_db_entry).ok()); } -TEST_F(NeighborManagerTest, ValidateNeighborAppDbEntryZeroMacAddress) { - const P4NeighborAppDbEntry app_db_entry = { - .router_intf_id = kRouterInterfaceId1, - .neighbor_id = kNeighborId1, - .dst_mac_address = swss::MacAddress(), - .is_set_dst_mac = true}; +TEST_F(NeighborManagerTest, ValidateNeighborAppDbEntryZeroMacAddress) +{ + const P4NeighborAppDbEntry app_db_entry = {.router_intf_id = kRouterInterfaceId1, + .neighbor_id = kNeighborId1, + .dst_mac_address = swss::MacAddress(), + .is_set_dst_mac = true}; - ASSERT_TRUE(p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_intf_id), - kRouterInterfaceOid1)); + ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_intf_id), + kRouterInterfaceOid1)); - EXPECT_FALSE(ValidateNeighborAppDbEntry(app_db_entry).ok()); + EXPECT_FALSE(ValidateNeighborAppDbEntry(app_db_entry).ok()); } -TEST_F(NeighborManagerTest, ValidateNeighborAppDbEntryMacAddressNotPresent) { - const P4NeighborAppDbEntry app_db_entry = { - .router_intf_id = kRouterInterfaceId1, - .neighbor_id = kNeighborId1, - .dst_mac_address = swss::MacAddress(), - .is_set_dst_mac = false}; +TEST_F(NeighborManagerTest, ValidateNeighborAppDbEntryMacAddressNotPresent) +{ + const P4NeighborAppDbEntry app_db_entry = {.router_intf_id = kRouterInterfaceId1, + .neighbor_id = kNeighborId1, + .dst_mac_address = swss::MacAddress(), + .is_set_dst_mac = false}; - ASSERT_TRUE(p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_intf_id), - kRouterInterfaceOid1)); + ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_intf_id), + kRouterInterfaceOid1)); - EXPECT_TRUE(ValidateNeighborAppDbEntry(app_db_entry).ok()); + EXPECT_TRUE(ValidateNeighborAppDbEntry(app_db_entry).ok()); } -TEST_F(NeighborManagerTest, DrainValidAttributes) { - ASSERT_TRUE(p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), - kRouterInterfaceOid1)); - - const std::string appl_db_key = - std::string(APP_P4RT_NEIGHBOR_TABLE_NAME) + kTableKeyDelimiter + - CreateNeighborAppDbKey(kRouterInterfaceId1, kNeighborId1); - - // Enqueue entry for create operation. - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kDstMac), - kMacAddress1.to_string()}); - Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); - - EXPECT_CALL(mock_sai_neighbor_, create_neighbor_entry(_, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - Drain(); - - P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, - kMacAddress1); - neighbor_entry.neigh_entry.switch_id = gSwitchId; - copy(neighbor_entry.neigh_entry.ip_address, neighbor_entry.neighbor_id); - neighbor_entry.neigh_entry.rif_id = kRouterInterfaceOid1; - ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); - - // Enqueue entry for update operation. - attributes.clear(); - attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kDstMac), - kMacAddress2.to_string()}); - Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); - - EXPECT_CALL(mock_sai_neighbor_, set_neighbor_entry_attribute(_, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - Drain(); - - neighbor_entry.dst_mac_address = kMacAddress2; - ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); - - // Enqueue entry for delete operation. - attributes.clear(); - Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, DEL_COMMAND, attributes)); - - EXPECT_CALL(mock_sai_neighbor_, remove_neighbor_entry(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - Drain(); - - ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/true); -} +TEST_F(NeighborManagerTest, DrainValidAttributes) +{ + ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), + kRouterInterfaceOid1)); -TEST_F(NeighborManagerTest, DrainInvalidAppDbEntryKey) { - ASSERT_TRUE(p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), - kRouterInterfaceOid1)); - - // create invalid neighbor key with router interface id as kRouterInterfaceId1 - // and neighbor id as kNeighborId1 - const std::string invalid_neighbor_key = - R"({"match/router_interface_id:intf-3/4,match/neighbor_id:10.0.0.22"})"; - const std::string appl_db_key = std::string(APP_P4RT_NEIGHBOR_TABLE_NAME) + - kTableKeyDelimiter + invalid_neighbor_key; - - // Enqueue entry for create operation. - std::vector attributes; - Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); - Drain(); - - P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, - kMacAddress1); - ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/true); -} + const std::string appl_db_key = std::string(APP_P4RT_NEIGHBOR_TABLE_NAME) + kTableKeyDelimiter + + CreateNeighborAppDbKey(kRouterInterfaceId1, kNeighborId1); + + // Enqueue entry for create operation. + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kDstMac), kMacAddress1.to_string()}); + Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); -TEST_F(NeighborManagerTest, DrainInvalidAppDbEntryAttributes) { - ASSERT_TRUE(p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), - kRouterInterfaceOid1)); - - // Non-existent router interface id in neighbor key. - std::string appl_db_key = - std::string(APP_P4RT_NEIGHBOR_TABLE_NAME) + kTableKeyDelimiter + - CreateNeighborAppDbKey(kRouterInterfaceId2, kNeighborId1); - - std::vector attributes; - Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); - - appl_db_key = std::string(APP_P4RT_NEIGHBOR_TABLE_NAME) + kTableKeyDelimiter + - CreateNeighborAppDbKey(kRouterInterfaceId1, kNeighborId1); - // Invalid destination mac address attribute. - attributes.clear(); - attributes.push_back( - swss::FieldValueTuple{p4orch::kDstMac, swss::MacAddress().to_string()}); - Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); - - Drain(); - - // Validate that first create operation did not create a neighbor entry. - P4NeighborEntry neighbor_entry1(kRouterInterfaceId2, kNeighborId1, - kMacAddress1); - ValidateNeighborEntryNotPresent(neighbor_entry1, /*check_ref_count=*/false); - - // Validate that second create operation did not create a neighbor entry. - P4NeighborEntry neighbor_entry2(kRouterInterfaceId1, kNeighborId1, - kMacAddress1); - ValidateNeighborEntryNotPresent(neighbor_entry2, /*check_ref_count=*/true); + EXPECT_CALL(mock_sai_neighbor_, create_neighbor_entry(_, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + Drain(); + + P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, kMacAddress1); + neighbor_entry.neigh_entry.switch_id = gSwitchId; + copy(neighbor_entry.neigh_entry.ip_address, neighbor_entry.neighbor_id); + neighbor_entry.neigh_entry.rif_id = kRouterInterfaceOid1; + ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); + + // Enqueue entry for update operation. + attributes.clear(); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kDstMac), kMacAddress2.to_string()}); + Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); + + EXPECT_CALL(mock_sai_neighbor_, set_neighbor_entry_attribute(_, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + Drain(); + + neighbor_entry.dst_mac_address = kMacAddress2; + ValidateNeighborEntry(neighbor_entry, /*router_intf_ref_count=*/1); + + // Enqueue entry for delete operation. + attributes.clear(); + Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, DEL_COMMAND, attributes)); + + EXPECT_CALL(mock_sai_neighbor_, remove_neighbor_entry(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + Drain(); + + ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/true); } -TEST_F(NeighborManagerTest, DrainInvalidOperation) { - ASSERT_TRUE(p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), - kRouterInterfaceOid1)); +TEST_F(NeighborManagerTest, DrainInvalidAppDbEntryKey) +{ + ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), + kRouterInterfaceOid1)); - const std::string appl_db_key = - std::string(APP_P4RT_NEIGHBOR_TABLE_NAME) + kTableKeyDelimiter + - CreateNeighborAppDbKey(kRouterInterfaceId1, kNeighborId1); + // create invalid neighbor key with router interface id as kRouterInterfaceId1 + // and neighbor id as kNeighborId1 + const std::string invalid_neighbor_key = R"({"match/router_interface_id:intf-3/4,match/neighbor_id:10.0.0.22"})"; + const std::string appl_db_key = + std::string(APP_P4RT_NEIGHBOR_TABLE_NAME) + kTableKeyDelimiter + invalid_neighbor_key; - std::vector attributes; - Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, "INVALID", attributes)); - Drain(); + // Enqueue entry for create operation. + std::vector attributes; + Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); + Drain(); - P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, - kMacAddress1); - ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/true); + P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, kMacAddress1); + ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/true); } -TEST_F(NeighborManagerTest, VerifyStateTest) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, - kMacAddress1); - AddNeighborEntry(neighbor_entry, kRouterInterfaceOid1); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set( - "SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:{\"ip\":\"10.0.0.22\",\"rif\":\"oid:" - "0x295100\",\"switch_id\":\"oid:0x0\"}", - std::vector{ - swss::FieldValueTuple{"SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS", - "00:01:02:03:04:05"}, - swss::FieldValueTuple{"SAI_NEIGHBOR_ENTRY_ATTR_NO_HOST_ROUTE", - "true"}}); - - const std::string db_key = - std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + - APP_P4RT_NEIGHBOR_TABLE_NAME + kTableKeyDelimiter + - CreateNeighborAppDbKey(kRouterInterfaceId1, kNeighborId1); - std::vector attributes; - - // Verification should succeed with vaild key and value. - attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kDstMac), - kMacAddress1.to_string()}); - EXPECT_EQ(VerifyState(db_key, attributes), ""); - - // Invalid key should fail verification. - EXPECT_FALSE(VerifyState("invalid", attributes).empty()); - EXPECT_FALSE(VerifyState("invalid:invalid", attributes).empty()); - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes) - .empty()); - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", - attributes) - .empty()); - EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + - ":FIXED_NEIGHBOR_TABLE:invalid", - attributes) - .empty()); - - // Non-existing router intf should fail verification. - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + - APP_P4RT_NEIGHBOR_TABLE_NAME + kTableKeyDelimiter + - CreateNeighborAppDbKey(kRouterInterfaceId2, kNeighborId1), - attributes) - .empty()); - - // Non-existing entry should fail verification. - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + - APP_P4RT_NEIGHBOR_TABLE_NAME + kTableKeyDelimiter + - CreateNeighborAppDbKey(kRouterInterfaceId1, kNeighborId2), - attributes) - .empty()); - - auto* current_entry = GetNeighborEntry( - KeyGenerator::generateNeighborKey(kRouterInterfaceId1, kNeighborId1)); - EXPECT_NE(current_entry, nullptr); - - // Verification should fail if ritf ID mismatches. - auto saved_router_intf_id = current_entry->router_intf_id; - current_entry->router_intf_id = kRouterInterfaceId2; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - current_entry->router_intf_id = saved_router_intf_id; - - // Verification should fail if neighbor ID mismatches. - auto saved_neighbor_id = current_entry->neighbor_id; - current_entry->neighbor_id = kNeighborId2; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - current_entry->neighbor_id = saved_neighbor_id; - - // Verification should fail if dest MAC mismatches. - auto saved_dst_mac_address = current_entry->dst_mac_address; - current_entry->dst_mac_address = kMacAddress2; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - current_entry->dst_mac_address = saved_dst_mac_address; - - // Verification should fail if router intf key mismatches. - auto saved_router_intf_key = current_entry->router_intf_key; - current_entry->router_intf_key = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - current_entry->router_intf_key = saved_router_intf_key; - - // Verification should fail if neighbor key mismatches. - auto saved_neighbor_key = current_entry->neighbor_key; - current_entry->neighbor_key = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - current_entry->neighbor_key = saved_neighbor_key; +TEST_F(NeighborManagerTest, DrainInvalidAppDbEntryAttributes) +{ + ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), + kRouterInterfaceOid1)); + + // Non-existent router interface id in neighbor key. + std::string appl_db_key = std::string(APP_P4RT_NEIGHBOR_TABLE_NAME) + kTableKeyDelimiter + + CreateNeighborAppDbKey(kRouterInterfaceId2, kNeighborId1); + + std::vector attributes; + Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); + + appl_db_key = std::string(APP_P4RT_NEIGHBOR_TABLE_NAME) + kTableKeyDelimiter + + CreateNeighborAppDbKey(kRouterInterfaceId1, kNeighborId1); + // Invalid destination mac address attribute. + attributes.clear(); + attributes.push_back(swss::FieldValueTuple{p4orch::kDstMac, swss::MacAddress().to_string()}); + Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); + + Drain(); + + // Validate that first create operation did not create a neighbor entry. + P4NeighborEntry neighbor_entry1(kRouterInterfaceId2, kNeighborId1, kMacAddress1); + ValidateNeighborEntryNotPresent(neighbor_entry1, /*check_ref_count=*/false); + + // Validate that second create operation did not create a neighbor entry. + P4NeighborEntry neighbor_entry2(kRouterInterfaceId1, kNeighborId1, kMacAddress1); + ValidateNeighborEntryNotPresent(neighbor_entry2, /*check_ref_count=*/true); } -TEST_F(NeighborManagerTest, VerifyStateAsicDbTest) { - P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, - kMacAddress1); - AddNeighborEntry(neighbor_entry, kRouterInterfaceOid1); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set( - "SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:{\"ip\":\"10.0.0.22\",\"rif\":\"oid:" - "0x295100\",\"switch_id\":\"oid:0x0\"}", - std::vector{ - swss::FieldValueTuple{"SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS", - "00:01:02:03:04:05"}, - swss::FieldValueTuple{"SAI_NEIGHBOR_ENTRY_ATTR_NO_HOST_ROUTE", - "true"}}); - - const std::string db_key = - std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + - APP_P4RT_NEIGHBOR_TABLE_NAME + kTableKeyDelimiter + - CreateNeighborAppDbKey(kRouterInterfaceId1, kNeighborId1); - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kDstMac), - kMacAddress1.to_string()}); - - // Verification should succeed with correct ASIC DB values. - EXPECT_EQ(VerifyState(db_key, attributes), ""); - - // Verification should fail if ASIC DB values mismatch. - table.set( - "SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:{\"ip\":\"10.0.0.22\",\"rif\":\"oid:" - "0x295100\",\"switch_id\":\"oid:0x0\"}", - std::vector{swss::FieldValueTuple{ - "SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS", "00:ff:ee:dd:cc:bb"}}); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - - // Verification should fail if ASIC DB table is missing. - table.del( - "SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:{\"ip\":\"10.0.0.22\",\"rif\":\"oid:" - "0x295100\",\"switch_id\":\"oid:0x0\"}"); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - table.set( - "SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:{\"ip\":\"10.0.0.22\",\"rif\":\"oid:" - "0x295100\",\"switch_id\":\"oid:0x0\"}", - std::vector{ - swss::FieldValueTuple{"SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS", - "00:01:02:03:04:05"}, - swss::FieldValueTuple{"SAI_NEIGHBOR_ENTRY_ATTR_NO_HOST_ROUTE", - "true"}}); +TEST_F(NeighborManagerTest, DrainInvalidOperation) +{ + ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1), + kRouterInterfaceOid1)); + + const std::string appl_db_key = std::string(APP_P4RT_NEIGHBOR_TABLE_NAME) + kTableKeyDelimiter + + CreateNeighborAppDbKey(kRouterInterfaceId1, kNeighborId1); + + std::vector attributes; + Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, "INVALID", attributes)); + Drain(); + + P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, kMacAddress1); + ValidateNeighborEntryNotPresent(neighbor_entry, /*check_ref_count=*/true); +} + +TEST_F(NeighborManagerTest, VerifyStateTest) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, kMacAddress1); + AddNeighborEntry(neighbor_entry, kRouterInterfaceOid1); + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set("SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:{\"ip\":\"10.0.0.22\",\"rif\":\"oid:" + "0x295100\",\"switch_id\":\"oid:0x0\"}", + std::vector{ + swss::FieldValueTuple{"SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS", "00:01:02:03:04:05"}, + swss::FieldValueTuple{"SAI_NEIGHBOR_ENTRY_ATTR_NO_HOST_ROUTE", "true"}}); + + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_NEIGHBOR_TABLE_NAME + + kTableKeyDelimiter + CreateNeighborAppDbKey(kRouterInterfaceId1, kNeighborId1); + std::vector attributes; + + // Verification should succeed with vaild key and value. + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kDstMac), kMacAddress1.to_string()}); + EXPECT_EQ(VerifyState(db_key, attributes), ""); + + // Invalid key should fail verification. + EXPECT_FALSE(VerifyState("invalid", attributes).empty()); + EXPECT_FALSE(VerifyState("invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":FIXED_NEIGHBOR_TABLE:invalid", attributes).empty()); + + // Non-existing router intf should fail verification. + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_NEIGHBOR_TABLE_NAME + + kTableKeyDelimiter + CreateNeighborAppDbKey(kRouterInterfaceId2, kNeighborId1), + attributes) + .empty()); + + // Non-existing entry should fail verification. + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_NEIGHBOR_TABLE_NAME + + kTableKeyDelimiter + CreateNeighborAppDbKey(kRouterInterfaceId1, kNeighborId2), + attributes) + .empty()); + + auto *current_entry = GetNeighborEntry(KeyGenerator::generateNeighborKey(kRouterInterfaceId1, kNeighborId1)); + EXPECT_NE(current_entry, nullptr); + + // Verification should fail if ritf ID mismatches. + auto saved_router_intf_id = current_entry->router_intf_id; + current_entry->router_intf_id = kRouterInterfaceId2; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + current_entry->router_intf_id = saved_router_intf_id; + + // Verification should fail if neighbor ID mismatches. + auto saved_neighbor_id = current_entry->neighbor_id; + current_entry->neighbor_id = kNeighborId2; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + current_entry->neighbor_id = saved_neighbor_id; + + // Verification should fail if dest MAC mismatches. + auto saved_dst_mac_address = current_entry->dst_mac_address; + current_entry->dst_mac_address = kMacAddress2; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + current_entry->dst_mac_address = saved_dst_mac_address; + + // Verification should fail if router intf key mismatches. + auto saved_router_intf_key = current_entry->router_intf_key; + current_entry->router_intf_key = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + current_entry->router_intf_key = saved_router_intf_key; + + // Verification should fail if neighbor key mismatches. + auto saved_neighbor_key = current_entry->neighbor_key; + current_entry->neighbor_key = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + current_entry->neighbor_key = saved_neighbor_key; +} + +TEST_F(NeighborManagerTest, VerifyStateAsicDbTest) +{ + P4NeighborEntry neighbor_entry(kRouterInterfaceId1, kNeighborId1, kMacAddress1); + AddNeighborEntry(neighbor_entry, kRouterInterfaceOid1); + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set("SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:{\"ip\":\"10.0.0.22\",\"rif\":\"oid:" + "0x295100\",\"switch_id\":\"oid:0x0\"}", + std::vector{ + swss::FieldValueTuple{"SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS", "00:01:02:03:04:05"}, + swss::FieldValueTuple{"SAI_NEIGHBOR_ENTRY_ATTR_NO_HOST_ROUTE", "true"}}); + + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_NEIGHBOR_TABLE_NAME + + kTableKeyDelimiter + CreateNeighborAppDbKey(kRouterInterfaceId1, kNeighborId1); + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kDstMac), kMacAddress1.to_string()}); + + // Verification should succeed with correct ASIC DB values. + EXPECT_EQ(VerifyState(db_key, attributes), ""); + + // Verification should fail if ASIC DB values mismatch. + table.set("SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:{\"ip\":\"10.0.0.22\",\"rif\":\"oid:" + "0x295100\",\"switch_id\":\"oid:0x0\"}", + std::vector{ + swss::FieldValueTuple{"SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS", "00:ff:ee:dd:cc:bb"}}); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + + // Verification should fail if ASIC DB table is missing. + table.del("SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:{\"ip\":\"10.0.0.22\",\"rif\":\"oid:" + "0x295100\",\"switch_id\":\"oid:0x0\"}"); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + table.set("SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:{\"ip\":\"10.0.0.22\",\"rif\":\"oid:" + "0x295100\",\"switch_id\":\"oid:0x0\"}", + std::vector{ + swss::FieldValueTuple{"SAI_NEIGHBOR_ENTRY_ATTR_DST_MAC_ADDRESS", "00:01:02:03:04:05"}, + swss::FieldValueTuple{"SAI_NEIGHBOR_ENTRY_ATTR_NO_HOST_ROUTE", "true"}}); } diff --git a/orchagent/p4orch/tests/next_hop_manager_test.cpp b/orchagent/p4orch/tests/next_hop_manager_test.cpp index e1f554c636e..7a2e714bbce 100644 --- a/orchagent/p4orch/tests/next_hop_manager_test.cpp +++ b/orchagent/p4orch/tests/next_hop_manager_test.cpp @@ -18,7 +18,8 @@ #include "p4orch.h" #include "return_code.h" #include "swssnet.h" -extern "C" { +extern "C" +{ #include "sai.h" } @@ -33,71 +34,66 @@ using ::testing::StrictMock; using ::testing::Truly; extern sai_object_id_t gSwitchId; -extern MockSaiNextHop* mock_sai_next_hop; -extern P4Orch* gP4Orch; -extern VRFOrch* gVrfOrch; -extern swss::DBConnector* gAppDb; -extern sai_hostif_api_t* sai_hostif_api; -extern sai_switch_api_t* sai_switch_api; -extern sai_next_hop_api_t* sai_next_hop_api; - -namespace { - -constexpr char* kNextHopId = "8"; -constexpr char* kNextHopP4AppDbKey = R"({"match/nexthop_id":"8"})"; +extern MockSaiNextHop *mock_sai_next_hop; +extern P4Orch *gP4Orch; +extern VRFOrch *gVrfOrch; +extern swss::DBConnector *gAppDb; +extern sai_hostif_api_t *sai_hostif_api; +extern sai_switch_api_t *sai_switch_api; +extern sai_next_hop_api_t *sai_next_hop_api; + +namespace +{ + +constexpr char *kNextHopId = "8"; +constexpr char *kNextHopP4AppDbKey = R"({"match/nexthop_id":"8"})"; constexpr sai_object_id_t kNextHopOid = 101; -constexpr char* kTunnelNextHopId = "tunnel-nexthop-1"; -constexpr char* kTunnelNextHopP4AppDbKey = - R"({"match/nexthop_id":"tunnel-nexthop-1"})"; +constexpr char *kTunnelNextHopId = "tunnel-nexthop-1"; +constexpr char *kTunnelNextHopP4AppDbKey = R"({"match/nexthop_id":"tunnel-nexthop-1"})"; constexpr sai_object_id_t kTunnelNextHopOid = 102; -constexpr char* kRouterInterfaceId1 = "16"; -constexpr char* kRouterInterfaceId2 = "17"; +constexpr char *kRouterInterfaceId1 = "16"; +constexpr char *kRouterInterfaceId2 = "17"; constexpr sai_object_id_t kRouterInterfaceOid1 = 1; constexpr sai_object_id_t kRouterInterfaceOid2 = 2; -constexpr char* kTunnelId1 = "tunnel-1"; -constexpr char* kTunnelId2 = "tunnel-2"; +constexpr char *kTunnelId1 = "tunnel-1"; +constexpr char *kTunnelId2 = "tunnel-2"; constexpr sai_object_id_t kTunnelOid1 = 11; constexpr sai_object_id_t kTunnelOid2 = 12; -constexpr char* kNeighborId1 = "10.0.0.1"; -constexpr char* kNeighborId2 = "fe80::21a:11ff:fe17:5f80"; +constexpr char *kNeighborId1 = "10.0.0.1"; +constexpr char *kNeighborId2 = "fe80::21a:11ff:fe17:5f80"; // APP DB entries for Add and Update request. -const P4NextHopAppDbEntry kP4NextHopAppDbEntry1{ - /*next_hop_id=*/kNextHopId, - /*router_interface_id=*/kRouterInterfaceId1, - /*gre_tunnel_id=*/"", - /*neighbor_id=*/swss::IpAddress(kNeighborId1), - /*action_str=*/"set_ip_nexthop"}; - -const P4NextHopAppDbEntry kP4NextHopAppDbEntry2{ - /*next_hop_id=*/kNextHopId, - /*router_interface_id=*/kRouterInterfaceId2, - /*gre_tunnel_id=*/"", - /*neighbor_id=*/swss::IpAddress(kNeighborId2), - /*action_str=*/"set_ip_nexthop"}; +const P4NextHopAppDbEntry kP4NextHopAppDbEntry1{/*next_hop_id=*/kNextHopId, + /*router_interface_id=*/kRouterInterfaceId1, + /*gre_tunnel_id=*/"", + /*neighbor_id=*/swss::IpAddress(kNeighborId1), + /*action_str=*/"set_ip_nexthop"}; + +const P4NextHopAppDbEntry kP4NextHopAppDbEntry2{/*next_hop_id=*/kNextHopId, + /*router_interface_id=*/kRouterInterfaceId2, + /*gre_tunnel_id=*/"", + /*neighbor_id=*/swss::IpAddress(kNeighborId2), + /*action_str=*/"set_ip_nexthop"}; // APP DB entries for Delete request. -const P4NextHopAppDbEntry kP4NextHopAppDbEntry3{ - /*next_hop_id=*/kNextHopId, - /*router_interface_id=*/"", - /*gre_tunnel_id=*/"", - /*neighbor_id=*/swss::IpAddress(), - /*action_str=*/""}; +const P4NextHopAppDbEntry kP4NextHopAppDbEntry3{/*next_hop_id=*/kNextHopId, + /*router_interface_id=*/"", + /*gre_tunnel_id=*/"", + /*neighbor_id=*/swss::IpAddress(), + /*action_str=*/""}; // APP DB entry for tunnel next hop entry -const P4NextHopAppDbEntry kP4TunnelNextHopAppDbEntry1{ - /*next_hop_id=*/kTunnelNextHopId, - /*router_interface_id=*/"", - /*gre_tunnel_id=*/kTunnelId1, - /*neighbor_id=*/swss::IpAddress("0.0.0.0"), - /*action_str=*/"set_p2p_tunnel_encap_nexthop"}; - -const P4NextHopAppDbEntry kP4TunnelNextHopAppDbEntry2{ - /*next_hop_id=*/kTunnelNextHopId, - /*router_interface_id=*/"", - /*gre_tunnel_id=*/kTunnelId2, - /*neighbor_id=*/swss::IpAddress("0.0.0.0"), - /*action_str=*/"set_p2p_tunnel_encap_nexthop"}; +const P4NextHopAppDbEntry kP4TunnelNextHopAppDbEntry1{/*next_hop_id=*/kTunnelNextHopId, + /*router_interface_id=*/"", + /*gre_tunnel_id=*/kTunnelId1, + /*neighbor_id=*/swss::IpAddress("0.0.0.0"), + /*action_str=*/"set_p2p_tunnel_encap_nexthop"}; + +const P4NextHopAppDbEntry kP4TunnelNextHopAppDbEntry2{/*next_hop_id=*/kTunnelNextHopId, + /*router_interface_id=*/"", + /*gre_tunnel_id=*/kTunnelId2, + /*neighbor_id=*/swss::IpAddress("0.0.0.0"), + /*action_str=*/"set_p2p_tunnel_encap_nexthop"}; const P4GreTunnelEntry kP4TunnelEntry1( /*tunnel_id=*/kTunnelId1, @@ -113,1247 +109,1090 @@ const P4GreTunnelEntry kP4TunnelEntry2( /*encap_dst_ip=*/swss::IpAddress(kNeighborId2), /*neighbor_id=*/swss::IpAddress(kNeighborId2)); -std::unordered_map -CreateAttributeListForNextHopObject( - const P4NextHopAppDbEntry& app_entry, const sai_object_id_t& oid, - const swss::IpAddress& neighbor_id = swss::IpAddress("0.0.0.0")) { - std::unordered_map next_hop_attrs; - sai_attribute_t next_hop_attr; +std::unordered_map CreateAttributeListForNextHopObject( + const P4NextHopAppDbEntry &app_entry, const sai_object_id_t &oid, + const swss::IpAddress &neighbor_id = swss::IpAddress("0.0.0.0")) +{ + std::unordered_map next_hop_attrs; + sai_attribute_t next_hop_attr; + + if (app_entry.action_str == p4orch::kSetTunnelNexthop) + { + next_hop_attr.id = SAI_NEXT_HOP_ATTR_TYPE; + next_hop_attr.value.s32 = SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP; + next_hop_attrs.insert({next_hop_attr.id, next_hop_attr.value}); + next_hop_attr.id = SAI_NEXT_HOP_ATTR_TUNNEL_ID; + next_hop_attr.value.oid = oid; + next_hop_attrs.insert({next_hop_attr.id, next_hop_attr.value}); + } + else + { + next_hop_attr.id = SAI_NEXT_HOP_ATTR_TYPE; + next_hop_attr.value.s32 = SAI_NEXT_HOP_TYPE_IP; + next_hop_attrs.insert({next_hop_attr.id, next_hop_attr.value}); + next_hop_attr.id = SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID; + next_hop_attr.value.oid = oid; + next_hop_attrs.insert({next_hop_attr.id, next_hop_attr.value}); + } - if (app_entry.action_str == p4orch::kSetTunnelNexthop) { - next_hop_attr.id = SAI_NEXT_HOP_ATTR_TYPE; - next_hop_attr.value.s32 = SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP; - next_hop_attrs.insert({next_hop_attr.id, next_hop_attr.value}); - next_hop_attr.id = SAI_NEXT_HOP_ATTR_TUNNEL_ID; - next_hop_attr.value.oid = oid; - next_hop_attrs.insert({next_hop_attr.id, next_hop_attr.value}); - } else { - next_hop_attr.id = SAI_NEXT_HOP_ATTR_TYPE; - next_hop_attr.value.s32 = SAI_NEXT_HOP_TYPE_IP; - next_hop_attrs.insert({next_hop_attr.id, next_hop_attr.value}); - next_hop_attr.id = SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID; - next_hop_attr.value.oid = oid; + next_hop_attr.id = SAI_NEXT_HOP_ATTR_IP; + if (!neighbor_id.isZero()) + { + swss::copy(next_hop_attr.value.ipaddr, neighbor_id); + } + else + { + swss::copy(next_hop_attr.value.ipaddr, app_entry.neighbor_id); + } next_hop_attrs.insert({next_hop_attr.id, next_hop_attr.value}); - } - - next_hop_attr.id = SAI_NEXT_HOP_ATTR_IP; - if (!neighbor_id.isZero()) { - swss::copy(next_hop_attr.value.ipaddr, neighbor_id); - } else { - swss::copy(next_hop_attr.value.ipaddr, app_entry.neighbor_id); - } - next_hop_attrs.insert({next_hop_attr.id, next_hop_attr.value}); - return next_hop_attrs; + return next_hop_attrs; } // Verifies whether the attribute list is the same as expected for SAI next // hop's create_next_hop(). // Returns true if they match; otherwise, false. -bool MatchCreateNextHopArgAttrList( - const sai_attribute_t* attr_list, - const std::unordered_map& - expected_attr_list) { - if (attr_list == nullptr) { - return false; - } - - // Sanity check for expected_attr_list. - const auto end = expected_attr_list.end(); - if (expected_attr_list.size() != 3 || - expected_attr_list.find(SAI_NEXT_HOP_ATTR_TYPE) == end || - expected_attr_list.find(SAI_NEXT_HOP_ATTR_IP) == end || - (expected_attr_list.find(SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID) == end && - expected_attr_list.find(SAI_NEXT_HOP_ATTR_TUNNEL_ID) == end)) { - return false; - } - - for (int i = 0; i < 3; ++i) { - switch (attr_list[i].id) { - case SAI_NEXT_HOP_ATTR_TYPE: - if (attr_list[i].value.s32 != - expected_attr_list.at(SAI_NEXT_HOP_ATTR_TYPE).s32) - return false; - break; - case SAI_NEXT_HOP_ATTR_IP: { - auto construct_ip_addr = - [](const sai_ip_address_t& sai_ip_address) -> swss::IpAddress { - swss::ip_addr_t ipaddr; - if (sai_ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV4) { - ipaddr.family = AF_INET; - ipaddr.ip_addr.ipv4_addr = sai_ip_address.addr.ip4; - } else { - ipaddr.family = AF_INET6; - memcpy(&ipaddr.ip_addr.ipv6_addr, &sai_ip_address.addr.ip6, - sizeof(ipaddr.ip_addr.ipv6_addr)); - } - - return swss::IpAddress(ipaddr); - }; - - auto ipaddr = construct_ip_addr(attr_list[i].value.ipaddr); - auto expected_ipaddr = construct_ip_addr( - expected_attr_list.at(SAI_NEXT_HOP_ATTR_IP).ipaddr); - if (ipaddr != expected_ipaddr) { - return false; - } - break; - } - case SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID: - if (attr_list[i].value.oid != - expected_attr_list.at(SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID).oid) { - return false; +bool MatchCreateNextHopArgAttrList(const sai_attribute_t *attr_list, + const std::unordered_map &expected_attr_list) +{ + if (attr_list == nullptr) + { + return false; + } + + // Sanity check for expected_attr_list. + const auto end = expected_attr_list.end(); + if (expected_attr_list.size() != 3 || expected_attr_list.find(SAI_NEXT_HOP_ATTR_TYPE) == end || + expected_attr_list.find(SAI_NEXT_HOP_ATTR_IP) == end || + (expected_attr_list.find(SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID) == end && + expected_attr_list.find(SAI_NEXT_HOP_ATTR_TUNNEL_ID) == end)) + { + return false; + } + + for (int i = 0; i < 3; ++i) + { + switch (attr_list[i].id) + { + case SAI_NEXT_HOP_ATTR_TYPE: + if (attr_list[i].value.s32 != expected_attr_list.at(SAI_NEXT_HOP_ATTR_TYPE).s32) + return false; + break; + case SAI_NEXT_HOP_ATTR_IP: { + auto construct_ip_addr = [](const sai_ip_address_t &sai_ip_address) -> swss::IpAddress { + swss::ip_addr_t ipaddr; + if (sai_ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV4) + { + ipaddr.family = AF_INET; + ipaddr.ip_addr.ipv4_addr = sai_ip_address.addr.ip4; + } + else + { + ipaddr.family = AF_INET6; + memcpy(&ipaddr.ip_addr.ipv6_addr, &sai_ip_address.addr.ip6, sizeof(ipaddr.ip_addr.ipv6_addr)); + } + + return swss::IpAddress(ipaddr); + }; + + auto ipaddr = construct_ip_addr(attr_list[i].value.ipaddr); + auto expected_ipaddr = construct_ip_addr(expected_attr_list.at(SAI_NEXT_HOP_ATTR_IP).ipaddr); + if (ipaddr != expected_ipaddr) + { + return false; + } + break; } - break; - case SAI_NEXT_HOP_ATTR_TUNNEL_ID: - if (attr_list[i].value.oid != - expected_attr_list.at(SAI_NEXT_HOP_ATTR_TUNNEL_ID).oid) { - return false; + case SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID: + if (attr_list[i].value.oid != expected_attr_list.at(SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID).oid) + { + return false; + } + break; + case SAI_NEXT_HOP_ATTR_TUNNEL_ID: + if (attr_list[i].value.oid != expected_attr_list.at(SAI_NEXT_HOP_ATTR_TUNNEL_ID).oid) + { + return false; + } + break; + default: + // Invalid attribute ID in next hop's attribute list. + return false; } - break; - default: - // Invalid attribute ID in next hop's attribute list. - return false; } - } - return true; + return true; } -} // namespace - -class NextHopManagerTest : public ::testing::Test { - protected: - NextHopManagerTest() : next_hop_manager_(&p4_oid_mapper_, &publisher_) { - mock_sai_hostif = &mock_sai_hostif_; - mock_sai_switch = &mock_sai_switch_; - sai_switch_api->get_switch_attribute = mock_get_switch_attribute; - sai_hostif_api->create_hostif_trap = mock_create_hostif_trap; - sai_hostif_api->create_hostif_table_entry = mock_create_hostif_table_entry; - EXPECT_CALL(mock_sai_hostif_, create_hostif_table_entry(_, _, _, _)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_hostif_, create_hostif_trap(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_switch_, get_switch_attribute(_, _, _)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - copp_orch_ = new CoppOrch(gAppDb, APP_COPP_TABLE_NAME); - std::vector p4_tables; - gP4Orch = new P4Orch(gAppDb, p4_tables, gVrfOrch, copp_orch_); - } - - ~NextHopManagerTest() { - delete gP4Orch; - delete copp_orch_; - } - - void SetUp() override { - // Set up mock stuff for SAI next hop API structure. - mock_sai_next_hop = &mock_sai_next_hop_; - sai_next_hop_api->create_next_hop = mock_create_next_hop; - sai_next_hop_api->remove_next_hop = mock_remove_next_hop; - sai_next_hop_api->set_next_hop_attribute = mock_set_next_hop_attribute; - sai_next_hop_api->get_next_hop_attribute = mock_get_next_hop_attribute; - } - - void TearDown() override { - gP4Orch->getGreTunnelManager()->m_greTunnelTable.clear(); - } - - void Enqueue(const swss::KeyOpFieldsValuesTuple& entry) { - next_hop_manager_.enqueue(APP_P4RT_NEXTHOP_TABLE_NAME, entry); - } - - void Drain() { next_hop_manager_.drain(); } - - std::string VerifyState(const std::string& key, - const std::vector& tuple) { - return next_hop_manager_.verifyState(key, tuple); - } - - ReturnCode ProcessAddRequest(const P4NextHopAppDbEntry& app_db_entry) { - return next_hop_manager_.processAddRequest(app_db_entry); - } - - ReturnCode ProcessUpdateRequest(const P4NextHopAppDbEntry& app_db_entry, - P4NextHopEntry* next_hop_entry) { - return next_hop_manager_.processUpdateRequest(app_db_entry, next_hop_entry); - } - - ReturnCode ProcessDeleteRequest(const std::string& next_hop_key) { - return next_hop_manager_.processDeleteRequest(next_hop_key); - } - - P4NextHopEntry* GetNextHopEntry(const std::string& next_hop_key) { - return next_hop_manager_.getNextHopEntry(next_hop_key); - } - - ReturnCodeOr DeserializeP4NextHopAppDbEntry( - const std::string& key, - const std::vector& attributes) { - return next_hop_manager_.deserializeP4NextHopAppDbEntry(key, attributes); - } - - // Resolves the dependency of a next hop entry by adding depended router - // interface/tunnel and neighbor into centralized mapper. - // Returns true on succuess. - bool ResolveNextHopEntryDependency(const P4NextHopAppDbEntry& app_db_entry, - const sai_object_id_t& rif_oid); - - // Adds the next hop entry -- kP4NextHopAppDbEntry1, via next hop manager's - // ProcessAddRequest (). This function also takes care of all the dependencies - // of the next hop entry. - // Returns a valid pointer to next hop entry on success. - P4NextHopEntry* AddNextHopEntry1(); - - // Adds the next hop entry -- kP4TunnelNextHopAppDbEntry1, via next hop - // manager's ProcessAddRequest (). This function also takes care of all the - // dependencies of the next hop entry. Returns a valid pointer to next hop - // entry on success. - P4NextHopEntry* AddTunnelNextHopEntry1(); - - // Validates that a P4 App next hop entry is correctly added in next hop - // manager and centralized mapper. Returns true on success. - bool ValidateNextHopEntryAdd(const P4NextHopAppDbEntry& app_db_entry, - const sai_object_id_t& expected_next_hop_oid); - - // Return true if the specified the object has the expected number of - // reference. - bool ValidateRefCnt(sai_object_type_t object_type, const std::string& key, - uint32_t expected_ref_count) { - uint32_t ref_count; - if (!p4_oid_mapper_.getRefCount(object_type, key, &ref_count)) return false; - return ref_count == expected_ref_count; - } - - StrictMock mock_sai_next_hop_; - MockResponsePublisher publisher_; - P4OidMapper p4_oid_mapper_; - NextHopManager next_hop_manager_; - StrictMock mock_sai_hostif_; - StrictMock mock_sai_switch_; - CoppOrch* copp_orch_; +} // namespace + +class NextHopManagerTest : public ::testing::Test +{ + protected: + NextHopManagerTest() : next_hop_manager_(&p4_oid_mapper_, &publisher_) + { + mock_sai_hostif = &mock_sai_hostif_; + mock_sai_switch = &mock_sai_switch_; + sai_switch_api->get_switch_attribute = mock_get_switch_attribute; + sai_hostif_api->create_hostif_trap = mock_create_hostif_trap; + sai_hostif_api->create_hostif_table_entry = mock_create_hostif_table_entry; + EXPECT_CALL(mock_sai_hostif_, create_hostif_table_entry(_, _, _, _)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_hostif_, create_hostif_trap(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_switch_, get_switch_attribute(_, _, _)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + copp_orch_ = new CoppOrch(gAppDb, APP_COPP_TABLE_NAME); + std::vector p4_tables; + gP4Orch = new P4Orch(gAppDb, p4_tables, gVrfOrch, copp_orch_); + } + + ~NextHopManagerTest() + { + delete gP4Orch; + delete copp_orch_; + } + + void SetUp() override + { + // Set up mock stuff for SAI next hop API structure. + mock_sai_next_hop = &mock_sai_next_hop_; + sai_next_hop_api->create_next_hop = mock_create_next_hop; + sai_next_hop_api->remove_next_hop = mock_remove_next_hop; + sai_next_hop_api->set_next_hop_attribute = mock_set_next_hop_attribute; + sai_next_hop_api->get_next_hop_attribute = mock_get_next_hop_attribute; + } + + void TearDown() override + { + gP4Orch->getGreTunnelManager()->m_greTunnelTable.clear(); + } + + void Enqueue(const swss::KeyOpFieldsValuesTuple &entry) + { + next_hop_manager_.enqueue(APP_P4RT_NEXTHOP_TABLE_NAME, entry); + } + + void Drain() + { + next_hop_manager_.drain(); + } + + std::string VerifyState(const std::string &key, const std::vector &tuple) + { + return next_hop_manager_.verifyState(key, tuple); + } + + ReturnCode ProcessAddRequest(const P4NextHopAppDbEntry &app_db_entry) + { + return next_hop_manager_.processAddRequest(app_db_entry); + } + + ReturnCode ProcessUpdateRequest(const P4NextHopAppDbEntry &app_db_entry, P4NextHopEntry *next_hop_entry) + { + return next_hop_manager_.processUpdateRequest(app_db_entry, next_hop_entry); + } + + ReturnCode ProcessDeleteRequest(const std::string &next_hop_key) + { + return next_hop_manager_.processDeleteRequest(next_hop_key); + } + + P4NextHopEntry *GetNextHopEntry(const std::string &next_hop_key) + { + return next_hop_manager_.getNextHopEntry(next_hop_key); + } + + ReturnCodeOr DeserializeP4NextHopAppDbEntry( + const std::string &key, const std::vector &attributes) + { + return next_hop_manager_.deserializeP4NextHopAppDbEntry(key, attributes); + } + + // Resolves the dependency of a next hop entry by adding depended router + // interface/tunnel and neighbor into centralized mapper. + // Returns true on succuess. + bool ResolveNextHopEntryDependency(const P4NextHopAppDbEntry &app_db_entry, const sai_object_id_t &rif_oid); + + // Adds the next hop entry -- kP4NextHopAppDbEntry1, via next hop manager's + // ProcessAddRequest (). This function also takes care of all the dependencies + // of the next hop entry. + // Returns a valid pointer to next hop entry on success. + P4NextHopEntry *AddNextHopEntry1(); + + // Adds the next hop entry -- kP4TunnelNextHopAppDbEntry1, via next hop + // manager's ProcessAddRequest (). This function also takes care of all the + // dependencies of the next hop entry. Returns a valid pointer to next hop + // entry on success. + P4NextHopEntry *AddTunnelNextHopEntry1(); + + // Validates that a P4 App next hop entry is correctly added in next hop + // manager and centralized mapper. Returns true on success. + bool ValidateNextHopEntryAdd(const P4NextHopAppDbEntry &app_db_entry, const sai_object_id_t &expected_next_hop_oid); + + // Return true if the specified the object has the expected number of + // reference. + bool ValidateRefCnt(sai_object_type_t object_type, const std::string &key, uint32_t expected_ref_count) + { + uint32_t ref_count; + if (!p4_oid_mapper_.getRefCount(object_type, key, &ref_count)) + return false; + return ref_count == expected_ref_count; + } + + StrictMock mock_sai_next_hop_; + MockResponsePublisher publisher_; + P4OidMapper p4_oid_mapper_; + NextHopManager next_hop_manager_; + StrictMock mock_sai_hostif_; + StrictMock mock_sai_switch_; + CoppOrch *copp_orch_; }; -bool NextHopManagerTest::ResolveNextHopEntryDependency( - const P4NextHopAppDbEntry& app_db_entry, const sai_object_id_t& oid) { - std::string rif_id = app_db_entry.router_interface_id; - auto neighbor_id = app_db_entry.neighbor_id; - if (app_db_entry.action_str == p4orch::kSetTunnelNexthop) { - const std::string tunnel_key = - KeyGenerator::generateTunnelKey(app_db_entry.gre_tunnel_id); - if (!p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_TUNNEL, tunnel_key, oid)) { - return false; +bool NextHopManagerTest::ResolveNextHopEntryDependency(const P4NextHopAppDbEntry &app_db_entry, + const sai_object_id_t &oid) +{ + std::string rif_id = app_db_entry.router_interface_id; + auto neighbor_id = app_db_entry.neighbor_id; + if (app_db_entry.action_str == p4orch::kSetTunnelNexthop) + { + const std::string tunnel_key = KeyGenerator::generateTunnelKey(app_db_entry.gre_tunnel_id); + if (!p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_TUNNEL, tunnel_key, oid)) + { + return false; + } + gP4Orch->getGreTunnelManager()->m_greTunnelTable.emplace( + tunnel_key, app_db_entry.gre_tunnel_id == kTunnelId1 ? kP4TunnelEntry1 : kP4TunnelEntry2); + auto gre_tunnel_or = gP4Orch->getGreTunnelManager()->getConstGreTunnelEntry(tunnel_key); + EXPECT_TRUE(gre_tunnel_or.ok()); + rif_id = (*gre_tunnel_or).router_interface_id; + auto rif_oid = rif_id == kRouterInterfaceId1 ? kRouterInterfaceOid1 : kRouterInterfaceOid2; + neighbor_id = (*gre_tunnel_or).neighbor_id; + const std::string rif_key = KeyGenerator::generateRouterInterfaceKey(rif_id); + if (!p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, rif_oid)) + { + return false; + } } - gP4Orch->getGreTunnelManager()->m_greTunnelTable.emplace( - tunnel_key, app_db_entry.gre_tunnel_id == kTunnelId1 ? kP4TunnelEntry1 - : kP4TunnelEntry2); - auto gre_tunnel_or = - gP4Orch->getGreTunnelManager()->getConstGreTunnelEntry(tunnel_key); - EXPECT_TRUE(gre_tunnel_or.ok()); - rif_id = (*gre_tunnel_or).router_interface_id; - auto rif_oid = rif_id == kRouterInterfaceId1 ? kRouterInterfaceOid1 - : kRouterInterfaceOid2; - neighbor_id = (*gre_tunnel_or).neighbor_id; - const std::string rif_key = - KeyGenerator::generateRouterInterfaceKey(rif_id); - if (!p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, - rif_oid)) { - return false; + else + { + const std::string rif_key = KeyGenerator::generateRouterInterfaceKey(rif_id); + if (!p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, oid)) + { + return false; + } } - } else { - const std::string rif_key = - KeyGenerator::generateRouterInterfaceKey(rif_id); - if (!p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, - oid)) { - return false; + + const std::string neighbor_key = KeyGenerator::generateNeighborKey(rif_id, neighbor_id); + if (!p4_oid_mapper_.setDummyOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key)) + { + return false; } - } - - const std::string neighbor_key = - KeyGenerator::generateNeighborKey(rif_id, neighbor_id); - if (!p4_oid_mapper_.setDummyOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, - neighbor_key)) { - return false; - } - return true; + return true; } -P4NextHopEntry* NextHopManagerTest::AddNextHopEntry1() { - if (!ResolveNextHopEntryDependency(kP4NextHopAppDbEntry1, - kRouterInterfaceOid1)) { - return nullptr; - } - - // Set up mock call. - EXPECT_CALL( - mock_sai_next_hop_, - create_next_hop( - ::testing::NotNull(), Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchCreateNextHopArgAttrList, std::placeholders::_1, - CreateAttributeListForNextHopObject( - kP4NextHopAppDbEntry1, kRouterInterfaceOid1))))) - .WillOnce( - DoAll(SetArgPointee<0>(kNextHopOid), Return(SAI_STATUS_SUCCESS))); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRequest(kP4NextHopAppDbEntry1)); - - return GetNextHopEntry( - KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)); +P4NextHopEntry *NextHopManagerTest::AddNextHopEntry1() +{ + if (!ResolveNextHopEntryDependency(kP4NextHopAppDbEntry1, kRouterInterfaceOid1)) + { + return nullptr; + } + + // Set up mock call. + EXPECT_CALL(mock_sai_next_hop_, + create_next_hop( + ::testing::NotNull(), Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchCreateNextHopArgAttrList, std::placeholders::_1, + CreateAttributeListForNextHopObject(kP4NextHopAppDbEntry1, kRouterInterfaceOid1))))) + .WillOnce(DoAll(SetArgPointee<0>(kNextHopOid), Return(SAI_STATUS_SUCCESS))); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRequest(kP4NextHopAppDbEntry1)); + + return GetNextHopEntry(KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)); } -P4NextHopEntry* NextHopManagerTest::AddTunnelNextHopEntry1() { - if (!ResolveNextHopEntryDependency(kP4TunnelNextHopAppDbEntry1, - kTunnelOid1)) { - return nullptr; - } - - // Set up mock call. - EXPECT_CALL( - mock_sai_next_hop_, - create_next_hop( - ::testing::NotNull(), Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchCreateNextHopArgAttrList, std::placeholders::_1, - CreateAttributeListForNextHopObject( - kP4TunnelNextHopAppDbEntry1, kTunnelOid1, - swss::IpAddress(kNeighborId1)))))) - .WillOnce(DoAll(SetArgPointee<0>(kTunnelNextHopOid), - Return(SAI_STATUS_SUCCESS))); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRequest(kP4TunnelNextHopAppDbEntry1)); - - return GetNextHopEntry(KeyGenerator::generateNextHopKey( - kP4TunnelNextHopAppDbEntry1.next_hop_id)); +P4NextHopEntry *NextHopManagerTest::AddTunnelNextHopEntry1() +{ + if (!ResolveNextHopEntryDependency(kP4TunnelNextHopAppDbEntry1, kTunnelOid1)) + { + return nullptr; + } + + // Set up mock call. + EXPECT_CALL( + mock_sai_next_hop_, + create_next_hop(::testing::NotNull(), Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchCreateNextHopArgAttrList, std::placeholders::_1, + CreateAttributeListForNextHopObject(kP4TunnelNextHopAppDbEntry1, kTunnelOid1, + swss::IpAddress(kNeighborId1)))))) + .WillOnce(DoAll(SetArgPointee<0>(kTunnelNextHopOid), Return(SAI_STATUS_SUCCESS))); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRequest(kP4TunnelNextHopAppDbEntry1)); + + return GetNextHopEntry(KeyGenerator::generateNextHopKey(kP4TunnelNextHopAppDbEntry1.next_hop_id)); } -bool NextHopManagerTest::ValidateNextHopEntryAdd( - const P4NextHopAppDbEntry& app_db_entry, - const sai_object_id_t& expected_next_hop_oid) { - const auto* p4_next_hop_entry = GetNextHopEntry( - KeyGenerator::generateNextHopKey(app_db_entry.next_hop_id)); - if (p4_next_hop_entry == nullptr || - p4_next_hop_entry->next_hop_id != app_db_entry.next_hop_id || - p4_next_hop_entry->next_hop_oid != expected_next_hop_oid) { - return false; - } - - if (app_db_entry.action_str == p4orch::kSetTunnelNexthop && - p4_next_hop_entry->gre_tunnel_id != app_db_entry.gre_tunnel_id) { - return false; - } - - if (app_db_entry.action_str == p4orch::kSetIpNexthop && - (p4_next_hop_entry->router_interface_id != - app_db_entry.router_interface_id || - p4_next_hop_entry->neighbor_id != app_db_entry.neighbor_id)) { - return false; - } - - sai_object_id_t next_hop_oid; - if (!p4_oid_mapper_.getOID(SAI_OBJECT_TYPE_NEXT_HOP, - p4_next_hop_entry->next_hop_key, &next_hop_oid) || - next_hop_oid != expected_next_hop_oid) { - return false; - } - - return true; +bool NextHopManagerTest::ValidateNextHopEntryAdd(const P4NextHopAppDbEntry &app_db_entry, + const sai_object_id_t &expected_next_hop_oid) +{ + const auto *p4_next_hop_entry = GetNextHopEntry(KeyGenerator::generateNextHopKey(app_db_entry.next_hop_id)); + if (p4_next_hop_entry == nullptr || p4_next_hop_entry->next_hop_id != app_db_entry.next_hop_id || + p4_next_hop_entry->next_hop_oid != expected_next_hop_oid) + { + return false; + } + + if (app_db_entry.action_str == p4orch::kSetTunnelNexthop && + p4_next_hop_entry->gre_tunnel_id != app_db_entry.gre_tunnel_id) + { + return false; + } + + if (app_db_entry.action_str == p4orch::kSetIpNexthop && + (p4_next_hop_entry->router_interface_id != app_db_entry.router_interface_id || + p4_next_hop_entry->neighbor_id != app_db_entry.neighbor_id)) + { + return false; + } + + sai_object_id_t next_hop_oid; + if (!p4_oid_mapper_.getOID(SAI_OBJECT_TYPE_NEXT_HOP, p4_next_hop_entry->next_hop_key, &next_hop_oid) || + next_hop_oid != expected_next_hop_oid) + { + return false; + } + + return true; } -TEST_F(NextHopManagerTest, ProcessAddRequestShouldSucceedAddingNewNextHop) { - ASSERT_TRUE(ResolveNextHopEntryDependency(kP4NextHopAppDbEntry1, - kRouterInterfaceOid1)); - - const std::string rif_key = KeyGenerator::generateRouterInterfaceKey( - kP4NextHopAppDbEntry1.router_interface_id); - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - kP4NextHopAppDbEntry1.router_interface_id, - kP4NextHopAppDbEntry1.neighbor_id); - uint32_t original_rif_ref_count; - ASSERT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - rif_key, &original_rif_ref_count)); - uint32_t original_neighbor_ref_count; - ASSERT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, - neighbor_key, - &original_neighbor_ref_count)); - - // Set up mock call. - EXPECT_CALL( - mock_sai_next_hop_, - create_next_hop( - ::testing::NotNull(), Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchCreateNextHopArgAttrList, std::placeholders::_1, - CreateAttributeListForNextHopObject( - kP4NextHopAppDbEntry1, kRouterInterfaceOid1))))) - .WillOnce( - DoAll(SetArgPointee<0>(kNextHopOid), Return(SAI_STATUS_SUCCESS))); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRequest(kP4NextHopAppDbEntry1)); - - EXPECT_TRUE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry1, kNextHopOid)); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, - original_rif_ref_count + 1)); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, - original_neighbor_ref_count + 1)); +TEST_F(NextHopManagerTest, ProcessAddRequestShouldSucceedAddingNewNextHop) +{ + ASSERT_TRUE(ResolveNextHopEntryDependency(kP4NextHopAppDbEntry1, kRouterInterfaceOid1)); + + const std::string rif_key = KeyGenerator::generateRouterInterfaceKey(kP4NextHopAppDbEntry1.router_interface_id); + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(kP4NextHopAppDbEntry1.router_interface_id, kP4NextHopAppDbEntry1.neighbor_id); + uint32_t original_rif_ref_count; + ASSERT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, &original_rif_ref_count)); + uint32_t original_neighbor_ref_count; + ASSERT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, &original_neighbor_ref_count)); + + // Set up mock call. + EXPECT_CALL(mock_sai_next_hop_, + create_next_hop( + ::testing::NotNull(), Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchCreateNextHopArgAttrList, std::placeholders::_1, + CreateAttributeListForNextHopObject(kP4NextHopAppDbEntry1, kRouterInterfaceOid1))))) + .WillOnce(DoAll(SetArgPointee<0>(kNextHopOid), Return(SAI_STATUS_SUCCESS))); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRequest(kP4NextHopAppDbEntry1)); + + EXPECT_TRUE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry1, kNextHopOid)); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, original_rif_ref_count + 1)); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, original_neighbor_ref_count + 1)); } -TEST_F(NextHopManagerTest, - ProcessAddRequestShouldFailWhenNextHopExistInCentralMapper) { - ASSERT_TRUE(ResolveNextHopEntryDependency(kP4NextHopAppDbEntry1, - kRouterInterfaceOid1)); - ASSERT_TRUE(p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id), - kNextHopOid)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, - ProcessAddRequest(kP4NextHopAppDbEntry1)); +TEST_F(NextHopManagerTest, ProcessAddRequestShouldFailWhenNextHopExistInCentralMapper) +{ + ASSERT_TRUE(ResolveNextHopEntryDependency(kP4NextHopAppDbEntry1, kRouterInterfaceOid1)); + ASSERT_TRUE(p4_oid_mapper_.setOID( + SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id), kNextHopOid)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, ProcessAddRequest(kP4NextHopAppDbEntry1)); } -TEST_F(NextHopManagerTest, - ProcessAddRequestShouldFailWhenDependingRifIsAbsentInCentralMapper) { - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - kP4NextHopAppDbEntry1.router_interface_id, - kP4NextHopAppDbEntry1.neighbor_id); - ASSERT_TRUE( - p4_oid_mapper_.setDummyOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key)); +TEST_F(NextHopManagerTest, ProcessAddRequestShouldFailWhenDependingRifIsAbsentInCentralMapper) +{ + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(kP4NextHopAppDbEntry1.router_interface_id, kP4NextHopAppDbEntry1.neighbor_id); + ASSERT_TRUE(p4_oid_mapper_.setDummyOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key)); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessAddRequest(kP4NextHopAppDbEntry1)); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessAddRequest(kP4NextHopAppDbEntry1)); - EXPECT_EQ(GetNextHopEntry(KeyGenerator::generateNextHopKey( - kP4NextHopAppDbEntry1.next_hop_id)), - nullptr); + EXPECT_EQ(GetNextHopEntry(KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)), nullptr); } -TEST_F(NextHopManagerTest, - ProcessAddRequestShouldFailWhenDependingTunnelIsAbsentInCentralMapper) { - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - kP4TunnelNextHopAppDbEntry1.router_interface_id, - kP4TunnelEntry1.neighbor_id); - ASSERT_TRUE( - p4_oid_mapper_.setDummyOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key)); +TEST_F(NextHopManagerTest, ProcessAddRequestShouldFailWhenDependingTunnelIsAbsentInCentralMapper) +{ + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(kP4TunnelNextHopAppDbEntry1.router_interface_id, kP4TunnelEntry1.neighbor_id); + ASSERT_TRUE(p4_oid_mapper_.setDummyOID(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key)); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessAddRequest(kP4TunnelNextHopAppDbEntry1)); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessAddRequest(kP4TunnelNextHopAppDbEntry1)); - EXPECT_EQ(GetNextHopEntry(KeyGenerator::generateNextHopKey( - kP4TunnelNextHopAppDbEntry1.next_hop_id)), - nullptr); + EXPECT_EQ(GetNextHopEntry(KeyGenerator::generateNextHopKey(kP4TunnelNextHopAppDbEntry1.next_hop_id)), nullptr); } -TEST_F(NextHopManagerTest, - ProcessAddRequestShouldFailWhenDependingNeigherIsAbsentInCentralMapper) { - const std::string rif_key = KeyGenerator::generateRouterInterfaceKey( - kP4NextHopAppDbEntry1.router_interface_id); - ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, - kRouterInterfaceOid1)); +TEST_F(NextHopManagerTest, ProcessAddRequestShouldFailWhenDependingNeigherIsAbsentInCentralMapper) +{ + const std::string rif_key = KeyGenerator::generateRouterInterfaceKey(kP4NextHopAppDbEntry1.router_interface_id); + ASSERT_TRUE(p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, kRouterInterfaceOid1)); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessAddRequest(kP4NextHopAppDbEntry1)); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessAddRequest(kP4NextHopAppDbEntry1)); - EXPECT_EQ(GetNextHopEntry(KeyGenerator::generateNextHopKey( - kP4NextHopAppDbEntry1.next_hop_id)), - nullptr); + EXPECT_EQ(GetNextHopEntry(KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)), nullptr); } -TEST_F(NextHopManagerTest, ProcessAddRequestShouldFailWhenSaiCallFails) { - ASSERT_TRUE(ResolveNextHopEntryDependency(kP4NextHopAppDbEntry1, - kRouterInterfaceOid1)); - - // Set up mock call. - EXPECT_CALL( - mock_sai_next_hop_, - create_next_hop( - ::testing::NotNull(), Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchCreateNextHopArgAttrList, std::placeholders::_1, - CreateAttributeListForNextHopObject( - kP4NextHopAppDbEntry1, kRouterInterfaceOid1))))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - ProcessAddRequest(kP4NextHopAppDbEntry1)); - - // The add request failed for the next hop entry. - EXPECT_EQ(GetNextHopEntry(KeyGenerator::generateNextHopKey( - kP4NextHopAppDbEntry1.next_hop_id)), - nullptr); +TEST_F(NextHopManagerTest, ProcessAddRequestShouldFailWhenSaiCallFails) +{ + ASSERT_TRUE(ResolveNextHopEntryDependency(kP4NextHopAppDbEntry1, kRouterInterfaceOid1)); + + // Set up mock call. + EXPECT_CALL(mock_sai_next_hop_, + create_next_hop( + ::testing::NotNull(), Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchCreateNextHopArgAttrList, std::placeholders::_1, + CreateAttributeListForNextHopObject(kP4NextHopAppDbEntry1, kRouterInterfaceOid1))))) + .WillOnce(Return(SAI_STATUS_FAILURE)); + + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddRequest(kP4NextHopAppDbEntry1)); + + // The add request failed for the next hop entry. + EXPECT_EQ(GetNextHopEntry(KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)), nullptr); } -TEST_F(NextHopManagerTest, - ProcessAddRequestShouldDoNoOpForDuplicateAddRequest) { - ASSERT_NE(AddNextHopEntry1(), nullptr); - - // Add the same next hop entry again. - EXPECT_EQ(StatusCode::SWSS_RC_EXISTS, - ProcessAddRequest(kP4NextHopAppDbEntry1)); - - // Adding the same next hop entry multiple times should have the same outcome - // as adding it once. - EXPECT_TRUE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry1, kNextHopOid)); - const std::string rif_key = KeyGenerator::generateRouterInterfaceKey( - kP4NextHopAppDbEntry1.router_interface_id); - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - kP4NextHopAppDbEntry1.router_interface_id, - kP4NextHopAppDbEntry1.neighbor_id); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, 1)); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 1)); +TEST_F(NextHopManagerTest, ProcessAddRequestShouldDoNoOpForDuplicateAddRequest) +{ + ASSERT_NE(AddNextHopEntry1(), nullptr); + + // Add the same next hop entry again. + EXPECT_EQ(StatusCode::SWSS_RC_EXISTS, ProcessAddRequest(kP4NextHopAppDbEntry1)); + + // Adding the same next hop entry multiple times should have the same outcome + // as adding it once. + EXPECT_TRUE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry1, kNextHopOid)); + const std::string rif_key = KeyGenerator::generateRouterInterfaceKey(kP4NextHopAppDbEntry1.router_interface_id); + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(kP4NextHopAppDbEntry1.router_interface_id, kP4NextHopAppDbEntry1.neighbor_id); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, 1)); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 1)); } -TEST_F(NextHopManagerTest, ProcessAddRequestShouldSuccessForTunnelNexthop) { - ASSERT_TRUE( - ResolveNextHopEntryDependency(kP4TunnelNextHopAppDbEntry1, kTunnelOid1)); - - // Set up mock call. - EXPECT_CALL( - mock_sai_next_hop_, - create_next_hop( - ::testing::NotNull(), Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchCreateNextHopArgAttrList, std::placeholders::_1, - CreateAttributeListForNextHopObject( - kP4TunnelNextHopAppDbEntry1, kTunnelOid1, - swss::IpAddress(kNeighborId1)))))) - .WillOnce(DoAll(SetArgPointee<0>(kTunnelNextHopOid), - Return(SAI_STATUS_SUCCESS))); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRequest(kP4TunnelNextHopAppDbEntry1)); - - EXPECT_NE(GetNextHopEntry(KeyGenerator::generateNextHopKey( - kP4TunnelNextHopAppDbEntry1.next_hop_id)), - nullptr); - - // Add the same next hop entry again. - EXPECT_EQ(StatusCode::SWSS_RC_EXISTS, - ProcessAddRequest(kP4TunnelNextHopAppDbEntry1)); - - // Adding the same next hop entry multiple times should have the same outcome - // as adding it once. - EXPECT_TRUE( - ValidateNextHopEntryAdd(kP4TunnelNextHopAppDbEntry1, kTunnelNextHopOid)); - const std::string tunnel_key = KeyGenerator::generateTunnelKey( - kP4TunnelNextHopAppDbEntry1.gre_tunnel_id); - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - kP4TunnelEntry1.router_interface_id, kP4TunnelEntry1.neighbor_id); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_TUNNEL, tunnel_key, 1)); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 1)); +TEST_F(NextHopManagerTest, ProcessAddRequestShouldSuccessForTunnelNexthop) +{ + ASSERT_TRUE(ResolveNextHopEntryDependency(kP4TunnelNextHopAppDbEntry1, kTunnelOid1)); + + // Set up mock call. + EXPECT_CALL( + mock_sai_next_hop_, + create_next_hop(::testing::NotNull(), Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchCreateNextHopArgAttrList, std::placeholders::_1, + CreateAttributeListForNextHopObject(kP4TunnelNextHopAppDbEntry1, kTunnelOid1, + swss::IpAddress(kNeighborId1)))))) + .WillOnce(DoAll(SetArgPointee<0>(kTunnelNextHopOid), Return(SAI_STATUS_SUCCESS))); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRequest(kP4TunnelNextHopAppDbEntry1)); + + EXPECT_NE(GetNextHopEntry(KeyGenerator::generateNextHopKey(kP4TunnelNextHopAppDbEntry1.next_hop_id)), nullptr); + + // Add the same next hop entry again. + EXPECT_EQ(StatusCode::SWSS_RC_EXISTS, ProcessAddRequest(kP4TunnelNextHopAppDbEntry1)); + + // Adding the same next hop entry multiple times should have the same outcome + // as adding it once. + EXPECT_TRUE(ValidateNextHopEntryAdd(kP4TunnelNextHopAppDbEntry1, kTunnelNextHopOid)); + const std::string tunnel_key = KeyGenerator::generateTunnelKey(kP4TunnelNextHopAppDbEntry1.gre_tunnel_id); + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(kP4TunnelEntry1.router_interface_id, kP4TunnelEntry1.neighbor_id); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_TUNNEL, tunnel_key, 1)); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 1)); } -TEST_F(NextHopManagerTest, ProcessUpdateRequestShouldFailAsItIsUnsupported) { - auto* p4_next_hop_entry = AddNextHopEntry1(); - ASSERT_NE(p4_next_hop_entry, nullptr); - - EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, - ProcessUpdateRequest(kP4NextHopAppDbEntry2, p4_next_hop_entry)); - - // Expect that the update call will fail, so next hop entry's fields stay the - // same. - EXPECT_TRUE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry1, kNextHopOid)); - - // Validate ref count stay the same. - const std::string rif_key = KeyGenerator::generateRouterInterfaceKey( - kP4NextHopAppDbEntry1.router_interface_id); - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - kP4NextHopAppDbEntry1.router_interface_id, - kP4NextHopAppDbEntry1.neighbor_id); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, 1)); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 1)); +TEST_F(NextHopManagerTest, ProcessUpdateRequestShouldFailAsItIsUnsupported) +{ + auto *p4_next_hop_entry = AddNextHopEntry1(); + ASSERT_NE(p4_next_hop_entry, nullptr); + + EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, ProcessUpdateRequest(kP4NextHopAppDbEntry2, p4_next_hop_entry)); + + // Expect that the update call will fail, so next hop entry's fields stay the + // same. + EXPECT_TRUE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry1, kNextHopOid)); + + // Validate ref count stay the same. + const std::string rif_key = KeyGenerator::generateRouterInterfaceKey(kP4NextHopAppDbEntry1.router_interface_id); + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(kP4NextHopAppDbEntry1.router_interface_id, kP4NextHopAppDbEntry1.neighbor_id); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, 1)); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 1)); } -TEST_F(NextHopManagerTest, - ProcessDeleteRequestShouldSucceedForExistingNextHop) { - auto* p4_next_hop_entry = AddNextHopEntry1(); - ASSERT_NE(p4_next_hop_entry, nullptr); - - // Set up mock call. - EXPECT_CALL(mock_sai_next_hop_, - remove_next_hop(Eq(p4_next_hop_entry->next_hop_oid))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRequest(p4_next_hop_entry->next_hop_key)); - - // Validate the next hop entry has been deleted in both P4 next hop manager - // and centralized mapper. - p4_next_hop_entry = GetNextHopEntry( - KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)); - EXPECT_EQ(p4_next_hop_entry, nullptr); - EXPECT_FALSE(p4_oid_mapper_.existsOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id))); - - // Validate ref count decrement. - const std::string rif_key = KeyGenerator::generateRouterInterfaceKey( - kP4NextHopAppDbEntry1.router_interface_id); - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - kP4NextHopAppDbEntry1.router_interface_id, - kP4NextHopAppDbEntry1.neighbor_id); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, 0)); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 0)); +TEST_F(NextHopManagerTest, ProcessDeleteRequestShouldSucceedForExistingNextHop) +{ + auto *p4_next_hop_entry = AddNextHopEntry1(); + ASSERT_NE(p4_next_hop_entry, nullptr); + + // Set up mock call. + EXPECT_CALL(mock_sai_next_hop_, remove_next_hop(Eq(p4_next_hop_entry->next_hop_oid))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessDeleteRequest(p4_next_hop_entry->next_hop_key)); + + // Validate the next hop entry has been deleted in both P4 next hop manager + // and centralized mapper. + p4_next_hop_entry = GetNextHopEntry(KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)); + EXPECT_EQ(p4_next_hop_entry, nullptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_NEXT_HOP, + KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id))); + + // Validate ref count decrement. + const std::string rif_key = KeyGenerator::generateRouterInterfaceKey(kP4NextHopAppDbEntry1.router_interface_id); + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(kP4NextHopAppDbEntry1.router_interface_id, kP4NextHopAppDbEntry1.neighbor_id); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, 0)); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 0)); } -TEST_F(NextHopManagerTest, - ProcessDeleteRequestShouldFailForNonExistingNextHop) { - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessDeleteRequest(KeyGenerator::generateNextHopKey( - kP4NextHopAppDbEntry1.next_hop_id))); +TEST_F(NextHopManagerTest, ProcessDeleteRequestShouldFailForNonExistingNextHop) +{ + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, + ProcessDeleteRequest(KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id))); } -TEST_F(NextHopManagerTest, - ProcessDeleteRequestShouldFailIfNextHopEntryIsAbsentInCentralMapper) { - auto* p4_next_hop_entry = AddNextHopEntry1(); - ASSERT_NE(p4_next_hop_entry, nullptr); - - ASSERT_TRUE(p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_NEXT_HOP, - p4_next_hop_entry->next_hop_key)); - - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, - ProcessDeleteRequest(p4_next_hop_entry->next_hop_key)); - - // Validate the next hop entry is not deleted in P4 next hop manager. - p4_next_hop_entry = GetNextHopEntry( - KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)); - ASSERT_NE(p4_next_hop_entry, nullptr); - - // Validate ref count remains the same. - const std::string rif_key = KeyGenerator::generateRouterInterfaceKey( - kP4NextHopAppDbEntry1.router_interface_id); - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - kP4NextHopAppDbEntry1.router_interface_id, - kP4NextHopAppDbEntry1.neighbor_id); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, 1)); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 1)); +TEST_F(NextHopManagerTest, ProcessDeleteRequestShouldFailIfNextHopEntryIsAbsentInCentralMapper) +{ + auto *p4_next_hop_entry = AddNextHopEntry1(); + ASSERT_NE(p4_next_hop_entry, nullptr); + + ASSERT_TRUE(p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_NEXT_HOP, p4_next_hop_entry->next_hop_key)); + + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, ProcessDeleteRequest(p4_next_hop_entry->next_hop_key)); + + // Validate the next hop entry is not deleted in P4 next hop manager. + p4_next_hop_entry = GetNextHopEntry(KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)); + ASSERT_NE(p4_next_hop_entry, nullptr); + + // Validate ref count remains the same. + const std::string rif_key = KeyGenerator::generateRouterInterfaceKey(kP4NextHopAppDbEntry1.router_interface_id); + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(kP4NextHopAppDbEntry1.router_interface_id, kP4NextHopAppDbEntry1.neighbor_id); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, 1)); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 1)); } -TEST_F(NextHopManagerTest, - ProcessDeleteRequestShouldFailIfNextHopEntryIsStillReferenced) { - auto* p4_next_hop_entry = AddNextHopEntry1(); - ASSERT_NE(p4_next_hop_entry, nullptr); - - ASSERT_TRUE(p4_oid_mapper_.increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - p4_next_hop_entry->next_hop_key)); - - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessDeleteRequest(p4_next_hop_entry->next_hop_key)); - - // Validate the next hop entry is not deleted in either P4 next hop manager or - // central mapper. - p4_next_hop_entry = GetNextHopEntry( - KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)); - ASSERT_NE(p4_next_hop_entry, nullptr); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEXT_HOP, - p4_next_hop_entry->next_hop_key, 1)); - - // Validate ref count remains the same. - const std::string rif_key = KeyGenerator::generateRouterInterfaceKey( - kP4NextHopAppDbEntry1.router_interface_id); - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - kP4NextHopAppDbEntry1.router_interface_id, - kP4NextHopAppDbEntry1.neighbor_id); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, 1)); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 1)); +TEST_F(NextHopManagerTest, ProcessDeleteRequestShouldFailIfNextHopEntryIsStillReferenced) +{ + auto *p4_next_hop_entry = AddNextHopEntry1(); + ASSERT_NE(p4_next_hop_entry, nullptr); + + ASSERT_TRUE(p4_oid_mapper_.increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, p4_next_hop_entry->next_hop_key)); + + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessDeleteRequest(p4_next_hop_entry->next_hop_key)); + + // Validate the next hop entry is not deleted in either P4 next hop manager or + // central mapper. + p4_next_hop_entry = GetNextHopEntry(KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)); + ASSERT_NE(p4_next_hop_entry, nullptr); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEXT_HOP, p4_next_hop_entry->next_hop_key, 1)); + + // Validate ref count remains the same. + const std::string rif_key = KeyGenerator::generateRouterInterfaceKey(kP4NextHopAppDbEntry1.router_interface_id); + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(kP4NextHopAppDbEntry1.router_interface_id, kP4NextHopAppDbEntry1.neighbor_id); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, 1)); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 1)); } -TEST_F(NextHopManagerTest, ProcessDeleteRequestShouldFailIfSaiCallFails) { - auto* p4_next_hop_entry = AddNextHopEntry1(); - ASSERT_NE(p4_next_hop_entry, nullptr); - - // Set up mock call. - EXPECT_CALL(mock_sai_next_hop_, - remove_next_hop(Eq(p4_next_hop_entry->next_hop_oid))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - ProcessDeleteRequest(p4_next_hop_entry->next_hop_key)); - - // Validate the next hop entry is not deleted in either P4 next hop manager or - // central mapper. - p4_next_hop_entry = GetNextHopEntry( - KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)); - ASSERT_NE(p4_next_hop_entry, nullptr); - EXPECT_TRUE(p4_oid_mapper_.existsOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id))); - - // Validate ref count remains the same. - const std::string rif_key = KeyGenerator::generateRouterInterfaceKey( - kP4NextHopAppDbEntry1.router_interface_id); - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - kP4NextHopAppDbEntry1.router_interface_id, - kP4NextHopAppDbEntry1.neighbor_id); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, 1)); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 1)); +TEST_F(NextHopManagerTest, ProcessDeleteRequestShouldFailIfSaiCallFails) +{ + auto *p4_next_hop_entry = AddNextHopEntry1(); + ASSERT_NE(p4_next_hop_entry, nullptr); + + // Set up mock call. + EXPECT_CALL(mock_sai_next_hop_, remove_next_hop(Eq(p4_next_hop_entry->next_hop_oid))) + .WillOnce(Return(SAI_STATUS_FAILURE)); + + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessDeleteRequest(p4_next_hop_entry->next_hop_key)); + + // Validate the next hop entry is not deleted in either P4 next hop manager or + // central mapper. + p4_next_hop_entry = GetNextHopEntry(KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)); + ASSERT_NE(p4_next_hop_entry, nullptr); + EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_NEXT_HOP, + KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id))); + + // Validate ref count remains the same. + const std::string rif_key = KeyGenerator::generateRouterInterfaceKey(kP4NextHopAppDbEntry1.router_interface_id); + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(kP4NextHopAppDbEntry1.router_interface_id, kP4NextHopAppDbEntry1.neighbor_id); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, 1)); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 1)); } -TEST_F(NextHopManagerTest, - GetNextHopEntryShouldReturnValidPointerForAddedNextHop) { - ASSERT_TRUE(ResolveNextHopEntryDependency(kP4NextHopAppDbEntry1, - kRouterInterfaceOid1)); - - // Set up mock call. - EXPECT_CALL( - mock_sai_next_hop_, - create_next_hop( - ::testing::NotNull(), Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchCreateNextHopArgAttrList, std::placeholders::_1, - CreateAttributeListForNextHopObject( - kP4NextHopAppDbEntry1, kRouterInterfaceOid1))))) - .WillOnce( - DoAll(SetArgPointee<0>(kNextHopOid), Return(SAI_STATUS_SUCCESS))); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRequest(kP4NextHopAppDbEntry1)); - - EXPECT_NE(GetNextHopEntry(KeyGenerator::generateNextHopKey( - kP4NextHopAppDbEntry1.next_hop_id)), - nullptr); +TEST_F(NextHopManagerTest, GetNextHopEntryShouldReturnValidPointerForAddedNextHop) +{ + ASSERT_TRUE(ResolveNextHopEntryDependency(kP4NextHopAppDbEntry1, kRouterInterfaceOid1)); + + // Set up mock call. + EXPECT_CALL(mock_sai_next_hop_, + create_next_hop( + ::testing::NotNull(), Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchCreateNextHopArgAttrList, std::placeholders::_1, + CreateAttributeListForNextHopObject(kP4NextHopAppDbEntry1, kRouterInterfaceOid1))))) + .WillOnce(DoAll(SetArgPointee<0>(kNextHopOid), Return(SAI_STATUS_SUCCESS))); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRequest(kP4NextHopAppDbEntry1)); + + EXPECT_NE(GetNextHopEntry(KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)), nullptr); } -TEST_F(NextHopManagerTest, - GetNextHopEntryShouldReturnNullPointerForNonexistingNextHop) { - EXPECT_EQ(GetNextHopEntry(KeyGenerator::generateNextHopKey( - kP4NextHopAppDbEntry1.next_hop_id)), - nullptr); +TEST_F(NextHopManagerTest, GetNextHopEntryShouldReturnNullPointerForNonexistingNextHop) +{ + EXPECT_EQ(GetNextHopEntry(KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)), nullptr); } -TEST_F(NextHopManagerTest, - DeserializeP4NextHopAppDbEntryShouldSucceedForValidNextHopSetEntry) { - std::vector attributes = { - swss::FieldValueTuple(p4orch::kAction, "set_ip_nexthop"), - swss::FieldValueTuple(prependParamField(p4orch::kRouterInterfaceId), - kRouterInterfaceId1), - swss::FieldValueTuple(prependParamField(p4orch::kNeighborId), - kNeighborId1)}; - - auto app_db_entry_or = - DeserializeP4NextHopAppDbEntry(kNextHopP4AppDbKey, attributes); - EXPECT_TRUE(app_db_entry_or.ok()); - auto& app_db_entry = *app_db_entry_or; - EXPECT_EQ(app_db_entry.next_hop_id, kNextHopId); - EXPECT_FALSE(app_db_entry.router_interface_id.empty()); - EXPECT_EQ(app_db_entry.router_interface_id, kRouterInterfaceId1); - EXPECT_FALSE(app_db_entry.neighbor_id.isZero()); - EXPECT_EQ(app_db_entry.neighbor_id, swss::IpAddress(kNeighborId1)); +TEST_F(NextHopManagerTest, DeserializeP4NextHopAppDbEntryShouldSucceedForValidNextHopSetEntry) +{ + std::vector attributes = { + swss::FieldValueTuple(p4orch::kAction, "set_ip_nexthop"), + swss::FieldValueTuple(prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId1), + swss::FieldValueTuple(prependParamField(p4orch::kNeighborId), kNeighborId1)}; + + auto app_db_entry_or = DeserializeP4NextHopAppDbEntry(kNextHopP4AppDbKey, attributes); + EXPECT_TRUE(app_db_entry_or.ok()); + auto &app_db_entry = *app_db_entry_or; + EXPECT_EQ(app_db_entry.next_hop_id, kNextHopId); + EXPECT_FALSE(app_db_entry.router_interface_id.empty()); + EXPECT_EQ(app_db_entry.router_interface_id, kRouterInterfaceId1); + EXPECT_FALSE(app_db_entry.neighbor_id.isZero()); + EXPECT_EQ(app_db_entry.neighbor_id, swss::IpAddress(kNeighborId1)); } -TEST_F(NextHopManagerTest, - DeserializeP4NextHopAppDbEntryShouldSucceedForValidNextHopDeleteEntry) { - auto app_db_entry_or = DeserializeP4NextHopAppDbEntry( - kNextHopP4AppDbKey, std::vector()); - EXPECT_TRUE(app_db_entry_or.ok()); - auto& app_db_entry = *app_db_entry_or; - EXPECT_EQ(app_db_entry.next_hop_id, kNextHopId); - EXPECT_TRUE(app_db_entry.router_interface_id.empty()); - EXPECT_TRUE(app_db_entry.neighbor_id.isZero()); +TEST_F(NextHopManagerTest, DeserializeP4NextHopAppDbEntryShouldSucceedForValidNextHopDeleteEntry) +{ + auto app_db_entry_or = DeserializeP4NextHopAppDbEntry(kNextHopP4AppDbKey, std::vector()); + EXPECT_TRUE(app_db_entry_or.ok()); + auto &app_db_entry = *app_db_entry_or; + EXPECT_EQ(app_db_entry.next_hop_id, kNextHopId); + EXPECT_TRUE(app_db_entry.router_interface_id.empty()); + EXPECT_TRUE(app_db_entry.neighbor_id.isZero()); } -TEST_F( - NextHopManagerTest, - DeserializeP4NextHopAppDbEntryShouldReturnNullPointerWhenFailToDeserializeNextHopId) { - // Incorrect format of P4 App next hop entry key - std::string key = R"({"nexthop":"8"})"; - std::vector attributes; +TEST_F(NextHopManagerTest, DeserializeP4NextHopAppDbEntryShouldReturnNullPointerWhenFailToDeserializeNextHopId) +{ + // Incorrect format of P4 App next hop entry key + std::string key = R"({"nexthop":"8"})"; + std::vector attributes; - EXPECT_FALSE(DeserializeP4NextHopAppDbEntry(key, attributes).ok()); + EXPECT_FALSE(DeserializeP4NextHopAppDbEntry(key, attributes).ok()); } -TEST_F(NextHopManagerTest, - DeserializeP4NextHopAppDbEntryShouldReturnNullPointerForInvalidIpAddr) { - std::vector attributes = { - swss::FieldValueTuple(p4orch::kAction, "set_ip_nexthop"), - swss::FieldValueTuple(prependParamField(p4orch::kRouterInterfaceId), - kRouterInterfaceId1), - swss::FieldValueTuple(prependParamField(p4orch::kNeighborId), - "0.0.0.0.0.0")}; // Invalid IP address. - - EXPECT_FALSE( - DeserializeP4NextHopAppDbEntry(kNextHopP4AppDbKey, attributes).ok()); +TEST_F(NextHopManagerTest, DeserializeP4NextHopAppDbEntryShouldReturnNullPointerForInvalidIpAddr) +{ + std::vector attributes = { + swss::FieldValueTuple(p4orch::kAction, "set_ip_nexthop"), + swss::FieldValueTuple(prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId1), + swss::FieldValueTuple(prependParamField(p4orch::kNeighborId), "0.0.0.0.0.0")}; // Invalid IP address. + + EXPECT_FALSE(DeserializeP4NextHopAppDbEntry(kNextHopP4AppDbKey, attributes).ok()); } -TEST_F( - NextHopManagerTest, - DeserializeP4NextHopAppDbEntryShouldReturnNullPointerDueToUnexpectedField) { - std::vector attributes = { - swss::FieldValueTuple(p4orch::kAction, "set_ip_nexthop"), - swss::FieldValueTuple(p4orch::kRouterInterfaceId, kRouterInterfaceId1), - swss::FieldValueTuple("unexpected_field", "unexpected_value")}; +TEST_F(NextHopManagerTest, DeserializeP4NextHopAppDbEntryShouldReturnNullPointerDueToUnexpectedField) +{ + std::vector attributes = { + swss::FieldValueTuple(p4orch::kAction, "set_ip_nexthop"), + swss::FieldValueTuple(p4orch::kRouterInterfaceId, kRouterInterfaceId1), + swss::FieldValueTuple("unexpected_field", "unexpected_value")}; - EXPECT_FALSE( - DeserializeP4NextHopAppDbEntry(kNextHopP4AppDbKey, attributes).ok()); + EXPECT_FALSE(DeserializeP4NextHopAppDbEntry(kNextHopP4AppDbKey, attributes).ok()); } -TEST_F(NextHopManagerTest, DrainValidAppEntryShouldSucceed) { - nlohmann::json j; - j[prependMatchField(p4orch::kNexthopId)] = kNextHopId; +TEST_F(NextHopManagerTest, DrainValidAppEntryShouldSucceed) +{ + nlohmann::json j; + j[prependMatchField(p4orch::kNexthopId)] = kNextHopId; - std::vector fvs{ - {p4orch::kAction, p4orch::kSetIpNexthop}, - {prependParamField(p4orch::kNeighborId), kNeighborId2}, - {prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId2}}; + std::vector fvs{{p4orch::kAction, p4orch::kSetIpNexthop}, + {prependParamField(p4orch::kNeighborId), kNeighborId2}, + {prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId2}}; - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs); + swss::KeyOpFieldsValuesTuple app_db_entry(std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), + SET_COMMAND, fvs); - Enqueue(app_db_entry); + Enqueue(app_db_entry); - EXPECT_TRUE(ResolveNextHopEntryDependency(kP4NextHopAppDbEntry2, - kRouterInterfaceOid2)); - EXPECT_CALL(mock_sai_next_hop_, create_next_hop(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kNextHopOid), Return(SAI_STATUS_SUCCESS))); + EXPECT_TRUE(ResolveNextHopEntryDependency(kP4NextHopAppDbEntry2, kRouterInterfaceOid2)); + EXPECT_CALL(mock_sai_next_hop_, create_next_hop(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kNextHopOid), Return(SAI_STATUS_SUCCESS))); - Drain(); + Drain(); - EXPECT_TRUE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry2, kNextHopOid)); + EXPECT_TRUE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry2, kNextHopOid)); } -TEST_F(NextHopManagerTest, DrainValidTunnelNexthopAppEntryShouldSucceed) { - nlohmann::json tunnel_j; - tunnel_j[prependMatchField(p4orch::kNexthopId)] = kTunnelNextHopId; - std::vector tunnel_fvs = { - {p4orch::kAction, p4orch::kSetTunnelNexthop}, - {prependParamField(p4orch::kNeighborId), kNeighborId2}, - {prependParamField(p4orch::kTunnelId), kTunnelId2}}; - - swss::KeyOpFieldsValuesTuple tunnel_app_db_entry( - std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + - tunnel_j.dump(), - SET_COMMAND, tunnel_fvs); - - Enqueue(tunnel_app_db_entry); - - EXPECT_TRUE( - ResolveNextHopEntryDependency(kP4TunnelNextHopAppDbEntry2, kTunnelOid2)); - EXPECT_CALL(mock_sai_next_hop_, create_next_hop(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kTunnelNextHopOid), - Return(SAI_STATUS_SUCCESS))); - - Drain(); - - EXPECT_TRUE( - ValidateNextHopEntryAdd(kP4TunnelNextHopAppDbEntry2, kTunnelNextHopOid)); - - nlohmann::json j; - j[prependMatchField(p4orch::kNexthopId)] = kTunnelNextHopId; - std::vector fvs; - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - DEL_COMMAND, fvs); - EXPECT_CALL(mock_sai_next_hop_, remove_next_hop(Eq(kTunnelNextHopOid))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - Enqueue(app_db_entry); - Drain(); - - // Validate the next hop entry has been deleted in both P4 next hop manager - // and centralized mapper. - auto p4_next_hop_entry = GetNextHopEntry(KeyGenerator::generateNextHopKey( - kP4TunnelNextHopAppDbEntry2.next_hop_id)); - EXPECT_EQ(p4_next_hop_entry, nullptr); - EXPECT_FALSE(p4_oid_mapper_.existsOID( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey( - kP4TunnelNextHopAppDbEntry2.next_hop_id))); - - // Validate ref count decrement. - const std::string tunnel_key = KeyGenerator::generateTunnelKey( - kP4TunnelNextHopAppDbEntry2.gre_tunnel_id); - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - kP4TunnelEntry2.router_interface_id, kP4TunnelEntry2.neighbor_id); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_TUNNEL, tunnel_key, 0)); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 0)); +TEST_F(NextHopManagerTest, DrainValidTunnelNexthopAppEntryShouldSucceed) +{ + nlohmann::json tunnel_j; + tunnel_j[prependMatchField(p4orch::kNexthopId)] = kTunnelNextHopId; + std::vector tunnel_fvs = {{p4orch::kAction, p4orch::kSetTunnelNexthop}, + {prependParamField(p4orch::kNeighborId), kNeighborId2}, + {prependParamField(p4orch::kTunnelId), kTunnelId2}}; + + swss::KeyOpFieldsValuesTuple tunnel_app_db_entry( + std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + tunnel_j.dump(), SET_COMMAND, tunnel_fvs); + + Enqueue(tunnel_app_db_entry); + + EXPECT_TRUE(ResolveNextHopEntryDependency(kP4TunnelNextHopAppDbEntry2, kTunnelOid2)); + EXPECT_CALL(mock_sai_next_hop_, create_next_hop(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kTunnelNextHopOid), Return(SAI_STATUS_SUCCESS))); + + Drain(); + + EXPECT_TRUE(ValidateNextHopEntryAdd(kP4TunnelNextHopAppDbEntry2, kTunnelNextHopOid)); + + nlohmann::json j; + j[prependMatchField(p4orch::kNexthopId)] = kTunnelNextHopId; + std::vector fvs; + swss::KeyOpFieldsValuesTuple app_db_entry(std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), + DEL_COMMAND, fvs); + EXPECT_CALL(mock_sai_next_hop_, remove_next_hop(Eq(kTunnelNextHopOid))).WillOnce(Return(SAI_STATUS_SUCCESS)); + + Enqueue(app_db_entry); + Drain(); + + // Validate the next hop entry has been deleted in both P4 next hop manager + // and centralized mapper. + auto p4_next_hop_entry = GetNextHopEntry(KeyGenerator::generateNextHopKey(kP4TunnelNextHopAppDbEntry2.next_hop_id)); + EXPECT_EQ(p4_next_hop_entry, nullptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_NEXT_HOP, + KeyGenerator::generateNextHopKey(kP4TunnelNextHopAppDbEntry2.next_hop_id))); + + // Validate ref count decrement. + const std::string tunnel_key = KeyGenerator::generateTunnelKey(kP4TunnelNextHopAppDbEntry2.gre_tunnel_id); + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(kP4TunnelEntry2.router_interface_id, kP4TunnelEntry2.neighbor_id); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_TUNNEL, tunnel_key, 0)); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 0)); } -TEST_F(NextHopManagerTest, DrainAppEntryWithInvalidOpShouldBeNoOp) { - nlohmann::json j; - j[prependMatchField(p4orch::kNexthopId)] = kNextHopId; +TEST_F(NextHopManagerTest, DrainAppEntryWithInvalidOpShouldBeNoOp) +{ + nlohmann::json j; + j[prependMatchField(p4orch::kNexthopId)] = kNextHopId; - std::vector fvs{ - {prependParamField(p4orch::kNeighborId), kNeighborId2}, - {prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId2}}; + std::vector fvs{{prependParamField(p4orch::kNeighborId), kNeighborId2}, + {prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId2}}; - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - "INVALID_OP", fvs); + swss::KeyOpFieldsValuesTuple app_db_entry(std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), + "INVALID_OP", fvs); - Enqueue(app_db_entry); + Enqueue(app_db_entry); - EXPECT_TRUE(ResolveNextHopEntryDependency(kP4NextHopAppDbEntry2, - kRouterInterfaceOid2)); + EXPECT_TRUE(ResolveNextHopEntryDependency(kP4NextHopAppDbEntry2, kRouterInterfaceOid2)); - Drain(); + Drain(); - EXPECT_FALSE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry2, kNextHopOid)); + EXPECT_FALSE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry2, kNextHopOid)); } -TEST_F(NextHopManagerTest, DrainAppEntryWithInvalidFieldShouldBeNoOp) { - nlohmann::json j; - j[prependMatchField(p4orch::kNexthopId)] = kNextHopId; +TEST_F(NextHopManagerTest, DrainAppEntryWithInvalidFieldShouldBeNoOp) +{ + nlohmann::json j; + j[prependMatchField(p4orch::kNexthopId)] = kNextHopId; - std::vector fvs{ - {prependParamField(p4orch::kNeighborId), kNeighborId2}, - {prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId2}, - {"unexpected_field", "unexpected_value"}}; + std::vector fvs{{prependParamField(p4orch::kNeighborId), kNeighborId2}, + {prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId2}, + {"unexpected_field", "unexpected_value"}}; - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs); + swss::KeyOpFieldsValuesTuple app_db_entry(std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), + SET_COMMAND, fvs); - Enqueue(app_db_entry); + Enqueue(app_db_entry); - Drain(); - EXPECT_FALSE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry2, kNextHopOid)); + Drain(); + EXPECT_FALSE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry2, kNextHopOid)); - // Missing action field - fvs = {{prependParamField(p4orch::kNeighborId), kNeighborId2}, - {prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId2}}; - app_db_entry = { - std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs}; + // Missing action field + fvs = {{prependParamField(p4orch::kNeighborId), kNeighborId2}, + {prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId2}}; + app_db_entry = {std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs}; - Enqueue(app_db_entry); + Enqueue(app_db_entry); - Drain(); - EXPECT_FALSE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry2, kNextHopOid)); + Drain(); + EXPECT_FALSE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry2, kNextHopOid)); - // Missing neighbor field - fvs = {{p4orch::kAction, p4orch::kSetIpNexthop}, - {prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId2}}; - app_db_entry = { - std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs}; + // Missing neighbor field + fvs = {{p4orch::kAction, p4orch::kSetIpNexthop}, + {prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId2}}; + app_db_entry = {std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs}; - Enqueue(app_db_entry); + Enqueue(app_db_entry); - Drain(); - EXPECT_FALSE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry2, kNextHopOid)); + Drain(); + EXPECT_FALSE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry2, kNextHopOid)); - // set_ip_nexthop + missing router_interface_id - fvs = {{p4orch::kAction, p4orch::kSetIpNexthop}, - {prependParamField(p4orch::kNeighborId), kNeighborId2}}; - app_db_entry = { - std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs}; + // set_ip_nexthop + missing router_interface_id + fvs = {{p4orch::kAction, p4orch::kSetIpNexthop}, {prependParamField(p4orch::kNeighborId), kNeighborId2}}; + app_db_entry = {std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs}; - Enqueue(app_db_entry); + Enqueue(app_db_entry); - Drain(); - EXPECT_FALSE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry2, kNextHopOid)); + Drain(); + EXPECT_FALSE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry2, kNextHopOid)); - // set_ip_nexthop + invalid param/tunnel_id - fvs = {{p4orch::kAction, p4orch::kSetIpNexthop}, - {prependParamField(p4orch::kNeighborId), kNeighborId2}, - {prependParamField(p4orch::kTunnelId), kTunnelId1}}; - app_db_entry = { - std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs}; + // set_ip_nexthop + invalid param/tunnel_id + fvs = {{p4orch::kAction, p4orch::kSetIpNexthop}, + {prependParamField(p4orch::kNeighborId), kNeighborId2}, + {prependParamField(p4orch::kTunnelId), kTunnelId1}}; + app_db_entry = {std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs}; - Enqueue(app_db_entry); + Enqueue(app_db_entry); - Drain(); - EXPECT_FALSE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry2, kNextHopOid)); + Drain(); + EXPECT_FALSE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry2, kNextHopOid)); - // set_p2p_tunnel_encap_nexthop + invalid router_interface_id - fvs = {{p4orch::kAction, p4orch::kSetTunnelNexthop}, - {prependParamField(p4orch::kNeighborId), kNeighborId2}, - {prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId1}}; - app_db_entry = { - std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs}; + // set_p2p_tunnel_encap_nexthop + invalid router_interface_id + fvs = {{p4orch::kAction, p4orch::kSetTunnelNexthop}, + {prependParamField(p4orch::kNeighborId), kNeighborId2}, + {prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId1}}; + app_db_entry = {std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs}; - Enqueue(app_db_entry); + Enqueue(app_db_entry); - Drain(); - EXPECT_FALSE( - ValidateNextHopEntryAdd(kP4TunnelNextHopAppDbEntry2, kNextHopOid)); + Drain(); + EXPECT_FALSE(ValidateNextHopEntryAdd(kP4TunnelNextHopAppDbEntry2, kNextHopOid)); - // set_p2p_tunnel_encap_nexthop + missing tunnel_id - fvs = {{p4orch::kAction, p4orch::kSetTunnelNexthop}, - {prependParamField(p4orch::kNeighborId), kNeighborId2}}; - app_db_entry = { - std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs}; + // set_p2p_tunnel_encap_nexthop + missing tunnel_id + fvs = {{p4orch::kAction, p4orch::kSetTunnelNexthop}, {prependParamField(p4orch::kNeighborId), kNeighborId2}}; + app_db_entry = {std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), SET_COMMAND, fvs}; - Enqueue(app_db_entry); + Enqueue(app_db_entry); - Drain(); - EXPECT_FALSE( - ValidateNextHopEntryAdd(kP4TunnelNextHopAppDbEntry2, kNextHopOid)); + Drain(); + EXPECT_FALSE(ValidateNextHopEntryAdd(kP4TunnelNextHopAppDbEntry2, kNextHopOid)); } -TEST_F(NextHopManagerTest, DrainUpdateRequestShouldBeUnsupported) { - auto* p4_next_hop_entry = AddNextHopEntry1(); - ASSERT_NE(p4_next_hop_entry, nullptr); - - nlohmann::json j; - j[prependMatchField(p4orch::kNexthopId)] = kNextHopId; - std::vector fvs{ - {prependParamField(p4orch::kNeighborId), kNeighborId2}, - {prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId2}}; - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - SET_COMMAND, fvs); - - Enqueue(app_db_entry); - EXPECT_TRUE(ResolveNextHopEntryDependency(kP4NextHopAppDbEntry2, - kRouterInterfaceOid2)); - Drain(); - - // Expect that the update call will fail, so next hop entry's fields stay the - // same. - EXPECT_TRUE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry1, kNextHopOid)); - - // Validate ref count stay the same. - const std::string rif_key = KeyGenerator::generateRouterInterfaceKey( - kP4NextHopAppDbEntry1.router_interface_id); - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - kP4NextHopAppDbEntry1.router_interface_id, - kP4NextHopAppDbEntry1.neighbor_id); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, 1)); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 1)); +TEST_F(NextHopManagerTest, DrainUpdateRequestShouldBeUnsupported) +{ + auto *p4_next_hop_entry = AddNextHopEntry1(); + ASSERT_NE(p4_next_hop_entry, nullptr); + + nlohmann::json j; + j[prependMatchField(p4orch::kNexthopId)] = kNextHopId; + std::vector fvs{{prependParamField(p4orch::kNeighborId), kNeighborId2}, + {prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId2}}; + swss::KeyOpFieldsValuesTuple app_db_entry(std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), + SET_COMMAND, fvs); + + Enqueue(app_db_entry); + EXPECT_TRUE(ResolveNextHopEntryDependency(kP4NextHopAppDbEntry2, kRouterInterfaceOid2)); + Drain(); + + // Expect that the update call will fail, so next hop entry's fields stay the + // same. + EXPECT_TRUE(ValidateNextHopEntryAdd(kP4NextHopAppDbEntry1, kNextHopOid)); + + // Validate ref count stay the same. + const std::string rif_key = KeyGenerator::generateRouterInterfaceKey(kP4NextHopAppDbEntry1.router_interface_id); + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(kP4NextHopAppDbEntry1.router_interface_id, kP4NextHopAppDbEntry1.neighbor_id); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, 1)); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 1)); } -TEST_F(NextHopManagerTest, DrainDeleteRequestShouldSucceedForExistingNextHop) { - auto* p4_next_hop_entry = AddNextHopEntry1(); - ASSERT_NE(p4_next_hop_entry, nullptr); - - nlohmann::json j; - j[prependMatchField(p4orch::kNexthopId)] = kNextHopId; - std::vector fvs; - swss::KeyOpFieldsValuesTuple app_db_entry( - std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), - DEL_COMMAND, fvs); - EXPECT_CALL(mock_sai_next_hop_, - remove_next_hop(Eq(p4_next_hop_entry->next_hop_oid))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - Enqueue(app_db_entry); - Drain(); - - // Validate the next hop entry has been deleted in both P4 next hop manager - // and centralized mapper. - p4_next_hop_entry = GetNextHopEntry( - KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)); - EXPECT_EQ(p4_next_hop_entry, nullptr); - EXPECT_FALSE(p4_oid_mapper_.existsOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id))); - - // Validate ref count decrement. - const std::string rif_key = KeyGenerator::generateRouterInterfaceKey( - kP4NextHopAppDbEntry1.router_interface_id); - const std::string neighbor_key = KeyGenerator::generateNeighborKey( - kP4NextHopAppDbEntry1.router_interface_id, - kP4NextHopAppDbEntry1.neighbor_id); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, 0)); - EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 0)); +TEST_F(NextHopManagerTest, DrainDeleteRequestShouldSucceedForExistingNextHop) +{ + auto *p4_next_hop_entry = AddNextHopEntry1(); + ASSERT_NE(p4_next_hop_entry, nullptr); + + nlohmann::json j; + j[prependMatchField(p4orch::kNexthopId)] = kNextHopId; + std::vector fvs; + swss::KeyOpFieldsValuesTuple app_db_entry(std::string(APP_P4RT_NEXTHOP_TABLE_NAME) + kTableKeyDelimiter + j.dump(), + DEL_COMMAND, fvs); + EXPECT_CALL(mock_sai_next_hop_, remove_next_hop(Eq(p4_next_hop_entry->next_hop_oid))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + Enqueue(app_db_entry); + Drain(); + + // Validate the next hop entry has been deleted in both P4 next hop manager + // and centralized mapper. + p4_next_hop_entry = GetNextHopEntry(KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id)); + EXPECT_EQ(p4_next_hop_entry, nullptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_NEXT_HOP, + KeyGenerator::generateNextHopKey(kP4NextHopAppDbEntry1.next_hop_id))); + + // Validate ref count decrement. + const std::string rif_key = KeyGenerator::generateRouterInterfaceKey(kP4NextHopAppDbEntry1.router_interface_id); + const std::string neighbor_key = + KeyGenerator::generateNeighborKey(kP4NextHopAppDbEntry1.router_interface_id, kP4NextHopAppDbEntry1.neighbor_id); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_ROUTER_INTERFACE, rif_key, 0)); + EXPECT_TRUE(ValidateRefCnt(SAI_OBJECT_TYPE_NEIGHBOR_ENTRY, neighbor_key, 0)); } -TEST_F(NextHopManagerTest, VerifyIpNextHopStateTest) { - auto* p4_next_hop_entry = AddNextHopEntry1(); - ASSERT_NE(p4_next_hop_entry, nullptr); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set("SAI_OBJECT_TYPE_NEXT_HOP:oid:0x65", - std::vector{ - swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_TYPE", - "SAI_NEXT_HOP_TYPE_IP"}, - swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_IP", "10.0.0.1"}, - swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID", - "oid:0x1"}}); - - nlohmann::json j; - j[prependMatchField(p4orch::kNexthopId)] = kNextHopId; - const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + APP_P4RT_NEXTHOP_TABLE_NAME + - kTableKeyDelimiter + j.dump(); - std::vector attributes; - - // Verification should succeed with vaild key and value. - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kNeighborId), kNeighborId1}); - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId1}); - EXPECT_EQ(VerifyState(db_key, attributes), ""); - - // Invalid key should fail verification. - EXPECT_FALSE(VerifyState("invalid", attributes).empty()); - EXPECT_FALSE(VerifyState("invalid:invalid", attributes).empty()); - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes) - .empty()); - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", - attributes) - .empty()); - EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + - ":FIXED_NEXTHOP_TABLE:invalid", - attributes) - .empty()); - - // Verification should fail with non-existing nexthop. - j[prependMatchField(p4orch::kNexthopId)] = "invalid"; - EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + - APP_P4RT_NEXTHOP_TABLE_NAME + - kTableKeyDelimiter + j.dump(), - attributes) - .empty()); - - // Verification should fail if nexthop key mismatches. - auto saved_next_hop_key = p4_next_hop_entry->next_hop_key; - p4_next_hop_entry->next_hop_key = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_next_hop_entry->next_hop_key = saved_next_hop_key; - - // Verification should fail if nexthop ID mismatches. - auto saved_next_hop_id = p4_next_hop_entry->next_hop_id; - p4_next_hop_entry->next_hop_id = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_next_hop_entry->next_hop_id = saved_next_hop_id; - - // Verification should fail if ritf ID mismatches. - auto saved_router_interface_id = p4_next_hop_entry->router_interface_id; - p4_next_hop_entry->router_interface_id = kRouterInterfaceId2; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_next_hop_entry->router_interface_id = saved_router_interface_id; - - // Verification should fail if neighbor ID mismatches. - auto saved_neighbor_id = p4_next_hop_entry->neighbor_id; - p4_next_hop_entry->neighbor_id = swss::IpAddress(kNeighborId2); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_next_hop_entry->neighbor_id = saved_neighbor_id; - - // Verification should fail if tunnel ID mismatches. - auto saved_gre_tunnel_id = p4_next_hop_entry->gre_tunnel_id; - p4_next_hop_entry->gre_tunnel_id = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_next_hop_entry->gre_tunnel_id = saved_gre_tunnel_id; +TEST_F(NextHopManagerTest, VerifyIpNextHopStateTest) +{ + auto *p4_next_hop_entry = AddNextHopEntry1(); + ASSERT_NE(p4_next_hop_entry, nullptr); + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set( + "SAI_OBJECT_TYPE_NEXT_HOP:oid:0x65", + std::vector{swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_TYPE", "SAI_NEXT_HOP_TYPE_IP"}, + swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_IP", "10.0.0.1"}, + swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID", "oid:0x1"}}); + + nlohmann::json j; + j[prependMatchField(p4orch::kNexthopId)] = kNextHopId; + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_NEXTHOP_TABLE_NAME + + kTableKeyDelimiter + j.dump(); + std::vector attributes; + + // Verification should succeed with vaild key and value. + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kNeighborId), kNeighborId1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId1}); + EXPECT_EQ(VerifyState(db_key, attributes), ""); + + // Invalid key should fail verification. + EXPECT_FALSE(VerifyState("invalid", attributes).empty()); + EXPECT_FALSE(VerifyState("invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":FIXED_NEXTHOP_TABLE:invalid", attributes).empty()); + + // Verification should fail with non-existing nexthop. + j[prependMatchField(p4orch::kNexthopId)] = "invalid"; + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_NEXTHOP_TABLE_NAME + + kTableKeyDelimiter + j.dump(), + attributes) + .empty()); + + // Verification should fail if nexthop key mismatches. + auto saved_next_hop_key = p4_next_hop_entry->next_hop_key; + p4_next_hop_entry->next_hop_key = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_next_hop_entry->next_hop_key = saved_next_hop_key; + + // Verification should fail if nexthop ID mismatches. + auto saved_next_hop_id = p4_next_hop_entry->next_hop_id; + p4_next_hop_entry->next_hop_id = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_next_hop_entry->next_hop_id = saved_next_hop_id; + + // Verification should fail if ritf ID mismatches. + auto saved_router_interface_id = p4_next_hop_entry->router_interface_id; + p4_next_hop_entry->router_interface_id = kRouterInterfaceId2; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_next_hop_entry->router_interface_id = saved_router_interface_id; + + // Verification should fail if neighbor ID mismatches. + auto saved_neighbor_id = p4_next_hop_entry->neighbor_id; + p4_next_hop_entry->neighbor_id = swss::IpAddress(kNeighborId2); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_next_hop_entry->neighbor_id = saved_neighbor_id; + + // Verification should fail if tunnel ID mismatches. + auto saved_gre_tunnel_id = p4_next_hop_entry->gre_tunnel_id; + p4_next_hop_entry->gre_tunnel_id = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_next_hop_entry->gre_tunnel_id = saved_gre_tunnel_id; } -TEST_F(NextHopManagerTest, VerifyTunnelNextHopStateTest) { - ASSERT_TRUE( - ResolveNextHopEntryDependency(kP4TunnelNextHopAppDbEntry1, kTunnelOid1)); - - // Set up mock call. - EXPECT_CALL( - mock_sai_next_hop_, - create_next_hop( - ::testing::NotNull(), Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchCreateNextHopArgAttrList, std::placeholders::_1, - CreateAttributeListForNextHopObject( - kP4TunnelNextHopAppDbEntry1, kTunnelOid1, - swss::IpAddress(kNeighborId1)))))) - .WillOnce(DoAll(SetArgPointee<0>(kTunnelNextHopOid), - Return(SAI_STATUS_SUCCESS))); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRequest(kP4TunnelNextHopAppDbEntry1)); - - auto p4_next_hop_entry = GetNextHopEntry(KeyGenerator::generateNextHopKey( - kP4TunnelNextHopAppDbEntry1.next_hop_id)); - ASSERT_NE(p4_next_hop_entry, nullptr); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set( - "SAI_OBJECT_TYPE_NEXT_HOP:oid:0x66", - std::vector{ - swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_TYPE", - "SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP"}, - swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_IP", "10.0.0.1"}, - swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_TUNNEL_ID", "oid:0xb"}}); - - nlohmann::json j; - j[prependMatchField(p4orch::kNexthopId)] = kTunnelNextHopId; - const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + APP_P4RT_NEXTHOP_TABLE_NAME + - kTableKeyDelimiter + j.dump(); - std::vector attributes; - - // Verification should succeed with vaild key and value. - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kNeighborId), kNeighborId1}); - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId1}); - EXPECT_EQ(VerifyState(db_key, attributes), ""); - - // Verification should fail if nexthop key mismatches. - auto saved_next_hop_key = p4_next_hop_entry->next_hop_key; - p4_next_hop_entry->next_hop_key = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_next_hop_entry->next_hop_key = saved_next_hop_key; - - // Verification should fail if nexthop ID mismatches. - auto saved_next_hop_id = p4_next_hop_entry->next_hop_id; - p4_next_hop_entry->next_hop_id = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_next_hop_entry->next_hop_id = saved_next_hop_id; - - // Verification should fail if ritf ID mismatches. - auto saved_router_interface_id = p4_next_hop_entry->router_interface_id; - p4_next_hop_entry->router_interface_id = kRouterInterfaceId2; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_next_hop_entry->router_interface_id = saved_router_interface_id; - - // Verification should fail if neighbor ID mismatches. - auto saved_neighbor_id = p4_next_hop_entry->neighbor_id; - p4_next_hop_entry->neighbor_id = swss::IpAddress(kNeighborId2); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_next_hop_entry->neighbor_id = saved_neighbor_id; - - // Verification should fail if tunnel ID mismatches. - auto saved_gre_tunnel_id = p4_next_hop_entry->gre_tunnel_id; - p4_next_hop_entry->gre_tunnel_id = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_next_hop_entry->gre_tunnel_id = saved_gre_tunnel_id; +TEST_F(NextHopManagerTest, VerifyTunnelNextHopStateTest) +{ + ASSERT_TRUE(ResolveNextHopEntryDependency(kP4TunnelNextHopAppDbEntry1, kTunnelOid1)); + + // Set up mock call. + EXPECT_CALL( + mock_sai_next_hop_, + create_next_hop(::testing::NotNull(), Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchCreateNextHopArgAttrList, std::placeholders::_1, + CreateAttributeListForNextHopObject(kP4TunnelNextHopAppDbEntry1, kTunnelOid1, + swss::IpAddress(kNeighborId1)))))) + .WillOnce(DoAll(SetArgPointee<0>(kTunnelNextHopOid), Return(SAI_STATUS_SUCCESS))); + + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRequest(kP4TunnelNextHopAppDbEntry1)); + + auto p4_next_hop_entry = GetNextHopEntry(KeyGenerator::generateNextHopKey(kP4TunnelNextHopAppDbEntry1.next_hop_id)); + ASSERT_NE(p4_next_hop_entry, nullptr); + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set("SAI_OBJECT_TYPE_NEXT_HOP:oid:0x66", + std::vector{ + swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_TYPE", "SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP"}, + swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_IP", "10.0.0.1"}, + swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_TUNNEL_ID", "oid:0xb"}}); + + nlohmann::json j; + j[prependMatchField(p4orch::kNexthopId)] = kTunnelNextHopId; + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_NEXTHOP_TABLE_NAME + + kTableKeyDelimiter + j.dump(); + std::vector attributes; + + // Verification should succeed with vaild key and value. + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kNeighborId), kNeighborId1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId1}); + EXPECT_EQ(VerifyState(db_key, attributes), ""); + + // Verification should fail if nexthop key mismatches. + auto saved_next_hop_key = p4_next_hop_entry->next_hop_key; + p4_next_hop_entry->next_hop_key = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_next_hop_entry->next_hop_key = saved_next_hop_key; + + // Verification should fail if nexthop ID mismatches. + auto saved_next_hop_id = p4_next_hop_entry->next_hop_id; + p4_next_hop_entry->next_hop_id = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_next_hop_entry->next_hop_id = saved_next_hop_id; + + // Verification should fail if ritf ID mismatches. + auto saved_router_interface_id = p4_next_hop_entry->router_interface_id; + p4_next_hop_entry->router_interface_id = kRouterInterfaceId2; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_next_hop_entry->router_interface_id = saved_router_interface_id; + + // Verification should fail if neighbor ID mismatches. + auto saved_neighbor_id = p4_next_hop_entry->neighbor_id; + p4_next_hop_entry->neighbor_id = swss::IpAddress(kNeighborId2); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_next_hop_entry->neighbor_id = saved_neighbor_id; + + // Verification should fail if tunnel ID mismatches. + auto saved_gre_tunnel_id = p4_next_hop_entry->gre_tunnel_id; + p4_next_hop_entry->gre_tunnel_id = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_next_hop_entry->gre_tunnel_id = saved_gre_tunnel_id; } -TEST_F(NextHopManagerTest, VerifyStateAsicDbTest) { - auto* p4_next_hop_entry = AddNextHopEntry1(); - ASSERT_NE(p4_next_hop_entry, nullptr); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set("SAI_OBJECT_TYPE_NEXT_HOP:oid:0x65", - std::vector{ - swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_TYPE", - "SAI_NEXT_HOP_TYPE_IP"}, - swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_IP", "10.0.0.1"}, - swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID", - "oid:0x1"}}); - - nlohmann::json j; - j[prependMatchField(p4orch::kNexthopId)] = kNextHopId; - const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + APP_P4RT_NEXTHOP_TABLE_NAME + - kTableKeyDelimiter + j.dump(); - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kNeighborId), kNeighborId1}); - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId1}); - - // Verification should succeed with correct ASIC DB values. - EXPECT_EQ(VerifyState(db_key, attributes), ""); - - // Verification should fail if ASIC DB values mismatch. - table.set("SAI_OBJECT_TYPE_NEXT_HOP:oid:0x65", - std::vector{swss::FieldValueTuple{ - "SAI_NEXT_HOP_ATTR_IP", "fe80::21a:11ff:fe17:5f80"}}); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - - // Verification should fail if ASIC DB table is missing. - table.del("SAI_OBJECT_TYPE_NEXT_HOP:oid:0x65"); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - table.set("SAI_OBJECT_TYPE_NEXT_HOP:oid:0x65", - std::vector{ - swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_TYPE", - "SAI_NEXT_HOP_TYPE_IP"}, - swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_IP", "10.0.0.1"}, - swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID", - "oid:0x1"}}); +TEST_F(NextHopManagerTest, VerifyStateAsicDbTest) +{ + auto *p4_next_hop_entry = AddNextHopEntry1(); + ASSERT_NE(p4_next_hop_entry, nullptr); + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set( + "SAI_OBJECT_TYPE_NEXT_HOP:oid:0x65", + std::vector{swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_TYPE", "SAI_NEXT_HOP_TYPE_IP"}, + swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_IP", "10.0.0.1"}, + swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID", "oid:0x1"}}); + + nlohmann::json j; + j[prependMatchField(p4orch::kNexthopId)] = kNextHopId; + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_NEXTHOP_TABLE_NAME + + kTableKeyDelimiter + j.dump(); + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kNeighborId), kNeighborId1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kRouterInterfaceId), kRouterInterfaceId1}); + + // Verification should succeed with correct ASIC DB values. + EXPECT_EQ(VerifyState(db_key, attributes), ""); + + // Verification should fail if ASIC DB values mismatch. + table.set("SAI_OBJECT_TYPE_NEXT_HOP:oid:0x65", std::vector{swss::FieldValueTuple{ + "SAI_NEXT_HOP_ATTR_IP", "fe80::21a:11ff:fe17:5f80"}}); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + + // Verification should fail if ASIC DB table is missing. + table.del("SAI_OBJECT_TYPE_NEXT_HOP:oid:0x65"); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + table.set( + "SAI_OBJECT_TYPE_NEXT_HOP:oid:0x65", + std::vector{swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_TYPE", "SAI_NEXT_HOP_TYPE_IP"}, + swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_IP", "10.0.0.1"}, + swss::FieldValueTuple{"SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID", "oid:0x1"}}); } diff --git a/orchagent/p4orch/tests/p4oidmapper_test.cpp b/orchagent/p4orch/tests/p4oidmapper_test.cpp index 08ab0e172d3..bde2ee656bd 100644 --- a/orchagent/p4orch/tests/p4oidmapper_test.cpp +++ b/orchagent/p4orch/tests/p4oidmapper_test.cpp @@ -6,192 +6,153 @@ #include "sai_serialize.h" -extern "C" { +extern "C" +{ #include "sai.h" } -namespace { +namespace +{ -constexpr char* kNextHopObject1 = "NextHop1"; -constexpr char* kNextHopObject2 = "NextHop2"; -constexpr char* kRouteObject1 = "Route1"; -constexpr char* kRouteObject2 = "Route2"; +constexpr char *kNextHopObject1 = "NextHop1"; +constexpr char *kNextHopObject2 = "NextHop2"; +constexpr char *kRouteObject1 = "Route1"; +constexpr char *kRouteObject2 = "Route2"; constexpr sai_object_id_t kOid1 = 1; constexpr sai_object_id_t kOid2 = 2; -std::string convertToDBField(_In_ const sai_object_type_t object_type, - _In_ const std::string& key) { - return sai_serialize_object_type(object_type) + ":" + key; +std::string convertToDBField(_In_ const sai_object_type_t object_type, _In_ const std::string &key) +{ + return sai_serialize_object_type(object_type) + ":" + key; } -TEST(P4OidMapperTest, MapperTest) { - P4OidMapper mapper; - EXPECT_TRUE(mapper.setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid1)); - EXPECT_TRUE(mapper.setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, kOid2, - /*ref_count=*/100)); - EXPECT_TRUE(mapper.setDummyOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject1)); - EXPECT_TRUE(mapper.setDummyOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2, - /*ref_count=*/200)); - - EXPECT_EQ(2, mapper.getNumEntries(SAI_OBJECT_TYPE_NEXT_HOP)); - EXPECT_EQ(2, mapper.getNumEntries(SAI_OBJECT_TYPE_ROUTE_ENTRY)); - EXPECT_TRUE(mapper.existsOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1)); - EXPECT_TRUE(mapper.existsOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2)); - EXPECT_TRUE(mapper.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject1)); - EXPECT_TRUE(mapper.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2)); - - sai_object_id_t oid; - EXPECT_TRUE(mapper.getOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, &oid)); - EXPECT_EQ(kOid1, oid); - EXPECT_TRUE(mapper.getOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, &oid)); - EXPECT_EQ(kOid2, oid); - EXPECT_TRUE( - mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid1) - .empty()); - EXPECT_TRUE( - mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, kOid2) - .empty()); - EXPECT_FALSE( - mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid2) - .empty()); - EXPECT_FALSE( - mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, kOid1) - .empty()); - - uint32_t ref_count; - EXPECT_TRUE(mapper.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, - &ref_count)); - EXPECT_EQ(0, ref_count); - EXPECT_TRUE(mapper.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, - &ref_count)); - EXPECT_EQ(100, ref_count); - EXPECT_TRUE(mapper.getRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject1, - &ref_count)); - EXPECT_EQ(0, ref_count); - EXPECT_TRUE(mapper.getRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2, - &ref_count)); - EXPECT_EQ(200, ref_count); - EXPECT_TRUE( - mapper.increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1)); - EXPECT_TRUE(mapper.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, - &ref_count)); - EXPECT_EQ(1, ref_count); - EXPECT_TRUE( - mapper.decreaseRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2)); - EXPECT_TRUE(mapper.getRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2, - &ref_count)); - EXPECT_EQ(199, ref_count); - - EXPECT_TRUE( - mapper.decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1)); - EXPECT_TRUE(mapper.eraseOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1)); - EXPECT_EQ(1, mapper.getNumEntries(SAI_OBJECT_TYPE_NEXT_HOP)); - EXPECT_EQ(2, mapper.getNumEntries(SAI_OBJECT_TYPE_ROUTE_ENTRY)); - EXPECT_FALSE(mapper.existsOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1)); - EXPECT_TRUE(mapper.existsOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2)); - EXPECT_TRUE(mapper.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject1)); - EXPECT_TRUE(mapper.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2)); - - mapper.eraseAllOIDs(SAI_OBJECT_TYPE_ROUTE_ENTRY); - EXPECT_EQ(1, mapper.getNumEntries(SAI_OBJECT_TYPE_NEXT_HOP)); - EXPECT_EQ(0, mapper.getNumEntries(SAI_OBJECT_TYPE_ROUTE_ENTRY)); - EXPECT_FALSE(mapper.existsOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1)); - EXPECT_TRUE(mapper.existsOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2)); - EXPECT_FALSE(mapper.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject1)); - EXPECT_FALSE(mapper.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2)); - EXPECT_FALSE( - mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid1) - .empty()); - EXPECT_FALSE( - mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, kOid2) - .empty()); +TEST(P4OidMapperTest, MapperTest) +{ + P4OidMapper mapper; + EXPECT_TRUE(mapper.setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid1)); + EXPECT_TRUE(mapper.setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, kOid2, + /*ref_count=*/100)); + EXPECT_TRUE(mapper.setDummyOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject1)); + EXPECT_TRUE(mapper.setDummyOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2, + /*ref_count=*/200)); + + EXPECT_EQ(2, mapper.getNumEntries(SAI_OBJECT_TYPE_NEXT_HOP)); + EXPECT_EQ(2, mapper.getNumEntries(SAI_OBJECT_TYPE_ROUTE_ENTRY)); + EXPECT_TRUE(mapper.existsOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1)); + EXPECT_TRUE(mapper.existsOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2)); + EXPECT_TRUE(mapper.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject1)); + EXPECT_TRUE(mapper.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2)); + + sai_object_id_t oid; + EXPECT_TRUE(mapper.getOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, &oid)); + EXPECT_EQ(kOid1, oid); + EXPECT_TRUE(mapper.getOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, &oid)); + EXPECT_EQ(kOid2, oid); + EXPECT_TRUE(mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid1).empty()); + EXPECT_TRUE(mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, kOid2).empty()); + EXPECT_FALSE(mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid2).empty()); + EXPECT_FALSE(mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, kOid1).empty()); + + uint32_t ref_count; + EXPECT_TRUE(mapper.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, &ref_count)); + EXPECT_EQ(0, ref_count); + EXPECT_TRUE(mapper.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, &ref_count)); + EXPECT_EQ(100, ref_count); + EXPECT_TRUE(mapper.getRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject1, &ref_count)); + EXPECT_EQ(0, ref_count); + EXPECT_TRUE(mapper.getRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2, &ref_count)); + EXPECT_EQ(200, ref_count); + EXPECT_TRUE(mapper.increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1)); + EXPECT_TRUE(mapper.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, &ref_count)); + EXPECT_EQ(1, ref_count); + EXPECT_TRUE(mapper.decreaseRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2)); + EXPECT_TRUE(mapper.getRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2, &ref_count)); + EXPECT_EQ(199, ref_count); + + EXPECT_TRUE(mapper.decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1)); + EXPECT_TRUE(mapper.eraseOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1)); + EXPECT_EQ(1, mapper.getNumEntries(SAI_OBJECT_TYPE_NEXT_HOP)); + EXPECT_EQ(2, mapper.getNumEntries(SAI_OBJECT_TYPE_ROUTE_ENTRY)); + EXPECT_FALSE(mapper.existsOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1)); + EXPECT_TRUE(mapper.existsOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2)); + EXPECT_TRUE(mapper.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject1)); + EXPECT_TRUE(mapper.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2)); + + mapper.eraseAllOIDs(SAI_OBJECT_TYPE_ROUTE_ENTRY); + EXPECT_EQ(1, mapper.getNumEntries(SAI_OBJECT_TYPE_NEXT_HOP)); + EXPECT_EQ(0, mapper.getNumEntries(SAI_OBJECT_TYPE_ROUTE_ENTRY)); + EXPECT_FALSE(mapper.existsOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1)); + EXPECT_TRUE(mapper.existsOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2)); + EXPECT_FALSE(mapper.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject1)); + EXPECT_FALSE(mapper.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2)); + EXPECT_FALSE(mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid1).empty()); + EXPECT_FALSE(mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, kOid2).empty()); } -TEST(P4OidMapperTest, ErrorTest) { - P4OidMapper mapper; - EXPECT_TRUE(mapper.setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid1)); - EXPECT_TRUE(mapper.setDummyOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2, - std::numeric_limits::max())); +TEST(P4OidMapperTest, ErrorTest) +{ + P4OidMapper mapper; + EXPECT_TRUE(mapper.setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid1)); + EXPECT_TRUE(mapper.setDummyOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2, std::numeric_limits::max())); - // Set existing OID should fail. - EXPECT_FALSE(mapper.setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid2)); - EXPECT_FALSE(mapper.setDummyOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2)); + // Set existing OID should fail. + EXPECT_FALSE(mapper.setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid2)); + EXPECT_FALSE(mapper.setDummyOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2)); - // Get non-existing OID should fail. - sai_object_id_t oid; - EXPECT_FALSE(mapper.getOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, &oid)); + // Get non-existing OID should fail. + sai_object_id_t oid; + EXPECT_FALSE(mapper.getOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, &oid)); - // Get OID with nullptr should fail. - EXPECT_FALSE( - mapper.getOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, nullptr)); + // Get OID with nullptr should fail. + EXPECT_FALSE(mapper.getOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, nullptr)); - // Get non-existing ref count should fail. - uint32_t ref_count; - EXPECT_FALSE(mapper.getRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject1, - &ref_count)); + // Get non-existing ref count should fail. + uint32_t ref_count; + EXPECT_FALSE(mapper.getRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject1, &ref_count)); - // Get ref count with nullptr should fail. - EXPECT_FALSE( - mapper.getRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2, nullptr)); + // Get ref count with nullptr should fail. + EXPECT_FALSE(mapper.getRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2, nullptr)); - // Erase non-existing OID should fail. - EXPECT_FALSE(mapper.eraseOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2)); + // Erase non-existing OID should fail. + EXPECT_FALSE(mapper.eraseOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2)); - // Erase OID with non-zero ref count should fail. - EXPECT_FALSE(mapper.eraseOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2)); + // Erase OID with non-zero ref count should fail. + EXPECT_FALSE(mapper.eraseOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2)); - // Increase max ref count should fail. - EXPECT_FALSE( - mapper.increaseRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2)); + // Increase max ref count should fail. + EXPECT_FALSE(mapper.increaseRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject2)); - // Increase non-existing ref count should fail. - EXPECT_FALSE( - mapper.increaseRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject1)); + // Increase non-existing ref count should fail. + EXPECT_FALSE(mapper.increaseRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject1)); - // Decrease zero ref count should fail. - EXPECT_FALSE( - mapper.decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1)); + // Decrease zero ref count should fail. + EXPECT_FALSE(mapper.decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1)); - // Decrease non-existing ref count should fail. - EXPECT_FALSE( - mapper.decreaseRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject1)); + // Decrease non-existing ref count should fail. + EXPECT_FALSE(mapper.decreaseRefCount(SAI_OBJECT_TYPE_ROUTE_ENTRY, kRouteObject1)); } -TEST(P4OidMapperTest, VerifyMapperTest) { - P4OidMapper mapper; - swss::Table table(nullptr, "P4RT_KEY_TO_OID"); - EXPECT_TRUE(mapper.setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid1)); - EXPECT_TRUE(mapper.setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, kOid2, - /*ref_count=*/100)); - - EXPECT_TRUE( - mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid1) - .empty()); - EXPECT_TRUE( - mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, kOid2) - .empty()); - EXPECT_FALSE( - mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid2) - .empty()); - EXPECT_FALSE( - mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, kOid1) - .empty()); - EXPECT_FALSE( - mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, "invalid", kOid1) - .empty()); - - // Verification should fail if OID in DB mismatches. - table.hset("", convertToDBField(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1), - sai_serialize_object_id(kOid2)); - EXPECT_FALSE( - mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid1) - .empty()); - - // Verification should fail if OID in DB is not found. - table.hdel("", convertToDBField(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1)); - EXPECT_FALSE( - mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid1) - .empty()); +TEST(P4OidMapperTest, VerifyMapperTest) +{ + P4OidMapper mapper; + swss::Table table(nullptr, "P4RT_KEY_TO_OID"); + EXPECT_TRUE(mapper.setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid1)); + EXPECT_TRUE(mapper.setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, kOid2, + /*ref_count=*/100)); + + EXPECT_TRUE(mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid1).empty()); + EXPECT_TRUE(mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, kOid2).empty()); + EXPECT_FALSE(mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid2).empty()); + EXPECT_FALSE(mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject2, kOid1).empty()); + EXPECT_FALSE(mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, "invalid", kOid1).empty()); + + // Verification should fail if OID in DB mismatches. + table.hset("", convertToDBField(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1), sai_serialize_object_id(kOid2)); + EXPECT_FALSE(mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid1).empty()); + + // Verification should fail if OID in DB is not found. + table.hdel("", convertToDBField(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1)); + EXPECT_FALSE(mapper.verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP, kNextHopObject1, kOid1).empty()); } -} // namespace +} // namespace diff --git a/orchagent/p4orch/tests/p4orch_util_test.cpp b/orchagent/p4orch/tests/p4orch_util_test.cpp index c62512fba38..ba86624d4c4 100644 --- a/orchagent/p4orch/tests/p4orch_util_test.cpp +++ b/orchagent/p4orch/tests/p4orch_util_test.cpp @@ -7,146 +7,127 @@ #include "ipprefix.h" #include "swssnet.h" -namespace { +namespace +{ -TEST(P4OrchUtilTest, KeyGeneratorTest) { - std::string intf_key = - KeyGenerator::generateRouterInterfaceKey("intf-qe-3/7"); - EXPECT_EQ("router_interface_id=intf-qe-3/7", intf_key); - std::string neighbor_key = KeyGenerator::generateNeighborKey( - "intf-qe-3/7", swss::IpAddress("10.0.0.22")); - EXPECT_EQ("neighbor_id=10.0.0.22:router_interface_id=intf-qe-3/7", - neighbor_key); - std::string nexthop_key = - KeyGenerator::generateNextHopKey("ju1u32m1.atl11:qe-3/7"); - EXPECT_EQ("nexthop_id=ju1u32m1.atl11:qe-3/7", nexthop_key); - std::string wcmp_group_key = KeyGenerator::generateWcmpGroupKey("group-1"); - EXPECT_EQ("wcmp_group_id=group-1", wcmp_group_key); - std::string ipv4_route_key = KeyGenerator::generateRouteKey( - "b4-traffic", swss::IpPrefix("10.11.12.0/24")); - EXPECT_EQ("ipv4_dst=10.11.12.0/24:vrf_id=b4-traffic", ipv4_route_key); - ipv4_route_key = - KeyGenerator::generateRouteKey("b4-traffic", swss::IpPrefix("0.0.0.0/0")); - EXPECT_EQ("ipv4_dst=0.0.0.0/0:vrf_id=b4-traffic", ipv4_route_key); - std::string ipv6_route_key = KeyGenerator::generateRouteKey( - "b4-traffic", swss::IpPrefix("2001:db8:1::/32")); - EXPECT_EQ("ipv6_dst=2001:db8:1::/32:vrf_id=b4-traffic", ipv6_route_key); - ipv6_route_key = - KeyGenerator::generateRouteKey("b4-traffic", swss::IpPrefix("::/0")); - EXPECT_EQ("ipv6_dst=::/0:vrf_id=b4-traffic", ipv6_route_key); +TEST(P4OrchUtilTest, KeyGeneratorTest) +{ + std::string intf_key = KeyGenerator::generateRouterInterfaceKey("intf-qe-3/7"); + EXPECT_EQ("router_interface_id=intf-qe-3/7", intf_key); + std::string neighbor_key = KeyGenerator::generateNeighborKey("intf-qe-3/7", swss::IpAddress("10.0.0.22")); + EXPECT_EQ("neighbor_id=10.0.0.22:router_interface_id=intf-qe-3/7", neighbor_key); + std::string nexthop_key = KeyGenerator::generateNextHopKey("ju1u32m1.atl11:qe-3/7"); + EXPECT_EQ("nexthop_id=ju1u32m1.atl11:qe-3/7", nexthop_key); + std::string wcmp_group_key = KeyGenerator::generateWcmpGroupKey("group-1"); + EXPECT_EQ("wcmp_group_id=group-1", wcmp_group_key); + std::string ipv4_route_key = KeyGenerator::generateRouteKey("b4-traffic", swss::IpPrefix("10.11.12.0/24")); + EXPECT_EQ("ipv4_dst=10.11.12.0/24:vrf_id=b4-traffic", ipv4_route_key); + ipv4_route_key = KeyGenerator::generateRouteKey("b4-traffic", swss::IpPrefix("0.0.0.0/0")); + EXPECT_EQ("ipv4_dst=0.0.0.0/0:vrf_id=b4-traffic", ipv4_route_key); + std::string ipv6_route_key = KeyGenerator::generateRouteKey("b4-traffic", swss::IpPrefix("2001:db8:1::/32")); + EXPECT_EQ("ipv6_dst=2001:db8:1::/32:vrf_id=b4-traffic", ipv6_route_key); + ipv6_route_key = KeyGenerator::generateRouteKey("b4-traffic", swss::IpPrefix("::/0")); + EXPECT_EQ("ipv6_dst=::/0:vrf_id=b4-traffic", ipv6_route_key); - // Test with special characters. - neighbor_key = - KeyGenerator::generateNeighborKey("::===::", swss::IpAddress("::1")); - EXPECT_EQ("neighbor_id=::1:router_interface_id=::===::", neighbor_key); + // Test with special characters. + neighbor_key = KeyGenerator::generateNeighborKey("::===::", swss::IpAddress("::1")); + EXPECT_EQ("neighbor_id=::1:router_interface_id=::===::", neighbor_key); - std::map match_fvs; - match_fvs["ether_type"] = "0x0800"; - match_fvs["ipv6_dst"] = "fdf8:f53b:82e4::53 & fdf8:f53b:82e4::53"; - auto acl_rule_key = KeyGenerator::generateAclRuleKey(match_fvs, "15"); - EXPECT_EQ( - "match/ether_type=0x0800:match/" - "ipv6_dst=fdf8:f53b:82e4::53 & fdf8:f53b:82e4::53:priority=15", - acl_rule_key); + std::map match_fvs; + match_fvs["ether_type"] = "0x0800"; + match_fvs["ipv6_dst"] = "fdf8:f53b:82e4::53 & fdf8:f53b:82e4::53"; + auto acl_rule_key = KeyGenerator::generateAclRuleKey(match_fvs, "15"); + EXPECT_EQ("match/ether_type=0x0800:match/" + "ipv6_dst=fdf8:f53b:82e4::53 & fdf8:f53b:82e4::53:priority=15", + acl_rule_key); } -TEST(P4OrchUtilTest, ParseP4RTKeyTest) { - std::string table; - std::string key; - parseP4RTKey("table:key", &table, &key); - EXPECT_EQ("table", table); - EXPECT_EQ("key", key); - parseP4RTKey("|||::::", &table, &key); - EXPECT_EQ("|||", table); - EXPECT_EQ(":::", key); - parseP4RTKey("invalid", &table, &key); - EXPECT_TRUE(table.empty()); - EXPECT_TRUE(key.empty()); +TEST(P4OrchUtilTest, ParseP4RTKeyTest) +{ + std::string table; + std::string key; + parseP4RTKey("table:key", &table, &key); + EXPECT_EQ("table", table); + EXPECT_EQ("key", key); + parseP4RTKey("|||::::", &table, &key); + EXPECT_EQ("|||", table); + EXPECT_EQ(":::", key); + parseP4RTKey("invalid", &table, &key); + EXPECT_TRUE(table.empty()); + EXPECT_TRUE(key.empty()); } -TEST(P4OrchUtilTest, PrependMatchFieldShouldSucceed) { - EXPECT_EQ(prependMatchField("str"), "match/str"); +TEST(P4OrchUtilTest, PrependMatchFieldShouldSucceed) +{ + EXPECT_EQ(prependMatchField("str"), "match/str"); } -TEST(P4OrchUtilTest, PrependParamFieldShouldSucceed) { - EXPECT_EQ(prependParamField("str"), "param/str"); +TEST(P4OrchUtilTest, PrependParamFieldShouldSucceed) +{ + EXPECT_EQ(prependParamField("str"), "param/str"); } -TEST(P4OrchUtilTest, QuotedVarTest) { - std::string foo("Hello World"); - std::string bar("a string has 'quote'"); - EXPECT_EQ(QuotedVar(foo), "'Hello World'"); - EXPECT_EQ(QuotedVar(foo.c_str()), "'Hello World'"); - EXPECT_EQ(QuotedVar(bar), "'a string has \\\'quote\\\''"); - EXPECT_EQ(QuotedVar(bar.c_str()), "'a string has \\\'quote\\\''"); +TEST(P4OrchUtilTest, QuotedVarTest) +{ + std::string foo("Hello World"); + std::string bar("a string has 'quote'"); + EXPECT_EQ(QuotedVar(foo), "'Hello World'"); + EXPECT_EQ(QuotedVar(foo.c_str()), "'Hello World'"); + EXPECT_EQ(QuotedVar(bar), "'a string has \\\'quote\\\''"); + EXPECT_EQ(QuotedVar(bar.c_str()), "'a string has \\\'quote\\\''"); } -TEST(P4OrchUtilTest, VerifyAttrsTest) { - EXPECT_TRUE( - verifyAttrs( - std::vector{swss::FieldValueTuple{"k1", "v1"}}, - std::vector{swss::FieldValueTuple{"k1", "v1"}}, - std::vector{}, - /*allow_unknown=*/false) - .empty()); - EXPECT_FALSE( - verifyAttrs( - std::vector{swss::FieldValueTuple{"k1", "v1"}, - swss::FieldValueTuple{"k2", "v2"}}, - std::vector{swss::FieldValueTuple{"k1", "v1"}}, - std::vector{}, - /*allow_unknown=*/false) - .empty()); - EXPECT_TRUE( - verifyAttrs( - std::vector{swss::FieldValueTuple{"k1", "v1"}, - swss::FieldValueTuple{"k2", "v2"}}, - std::vector{swss::FieldValueTuple{"k1", "v1"}}, - std::vector{}, - /*allow_unknown=*/true) - .empty()); - EXPECT_TRUE( - verifyAttrs( - std::vector{swss::FieldValueTuple{"k1", "v1"}, - swss::FieldValueTuple{"k2", "v2"}}, - std::vector{swss::FieldValueTuple{"k1", "v1"}}, - std::vector{swss::FieldValueTuple{"k2", "v2"}}, - /*allow_unknown=*/false) - .empty()); - EXPECT_FALSE( - verifyAttrs( - std::vector{swss::FieldValueTuple{"k1", "v1"}, - swss::FieldValueTuple{"k2", "v2"}}, - std::vector{swss::FieldValueTuple{"k1", "v3"}}, - std::vector{swss::FieldValueTuple{"k2", "v2"}}, - /*allow_unknown=*/false) - .empty()); - EXPECT_FALSE( - verifyAttrs( - std::vector{swss::FieldValueTuple{"k1", "v1"}, - swss::FieldValueTuple{"k2", "v2"}}, - std::vector{swss::FieldValueTuple{"k1", "v1"}}, - std::vector{swss::FieldValueTuple{"k2", "v3"}}, - /*allow_unknown=*/false) - .empty()); - EXPECT_FALSE( - verifyAttrs( - std::vector{swss::FieldValueTuple{"k1", "v1"}, - swss::FieldValueTuple{"k2", "v2"}}, - std::vector{swss::FieldValueTuple{"k1", "v1"}, - swss::FieldValueTuple{"k3", "v3"}}, - std::vector{swss::FieldValueTuple{"k2", "v2"}}, - /*allow_unknown=*/true) - .empty()); - EXPECT_TRUE( - verifyAttrs( - std::vector{swss::FieldValueTuple{"k1", "v1"}, - swss::FieldValueTuple{"k2", "v2"}}, - std::vector{swss::FieldValueTuple{"k1", "v1"}}, - std::vector{swss::FieldValueTuple{"k2", "v2"}, - swss::FieldValueTuple{"k3", "v3"}}, - /*allow_unknown=*/false) - .empty()); +TEST(P4OrchUtilTest, VerifyAttrsTest) +{ + EXPECT_TRUE(verifyAttrs(std::vector{swss::FieldValueTuple{"k1", "v1"}}, + std::vector{swss::FieldValueTuple{"k1", "v1"}}, + std::vector{}, + /*allow_unknown=*/false) + .empty()); + EXPECT_FALSE(verifyAttrs(std::vector{swss::FieldValueTuple{"k1", "v1"}, + swss::FieldValueTuple{"k2", "v2"}}, + std::vector{swss::FieldValueTuple{"k1", "v1"}}, + std::vector{}, + /*allow_unknown=*/false) + .empty()); + EXPECT_TRUE(verifyAttrs(std::vector{swss::FieldValueTuple{"k1", "v1"}, + swss::FieldValueTuple{"k2", "v2"}}, + std::vector{swss::FieldValueTuple{"k1", "v1"}}, + std::vector{}, + /*allow_unknown=*/true) + .empty()); + EXPECT_TRUE(verifyAttrs(std::vector{swss::FieldValueTuple{"k1", "v1"}, + swss::FieldValueTuple{"k2", "v2"}}, + std::vector{swss::FieldValueTuple{"k1", "v1"}}, + std::vector{swss::FieldValueTuple{"k2", "v2"}}, + /*allow_unknown=*/false) + .empty()); + EXPECT_FALSE(verifyAttrs(std::vector{swss::FieldValueTuple{"k1", "v1"}, + swss::FieldValueTuple{"k2", "v2"}}, + std::vector{swss::FieldValueTuple{"k1", "v3"}}, + std::vector{swss::FieldValueTuple{"k2", "v2"}}, + /*allow_unknown=*/false) + .empty()); + EXPECT_FALSE(verifyAttrs(std::vector{swss::FieldValueTuple{"k1", "v1"}, + swss::FieldValueTuple{"k2", "v2"}}, + std::vector{swss::FieldValueTuple{"k1", "v1"}}, + std::vector{swss::FieldValueTuple{"k2", "v3"}}, + /*allow_unknown=*/false) + .empty()); + EXPECT_FALSE( + verifyAttrs( + std::vector{swss::FieldValueTuple{"k1", "v1"}, swss::FieldValueTuple{"k2", "v2"}}, + std::vector{swss::FieldValueTuple{"k1", "v1"}, swss::FieldValueTuple{"k3", "v3"}}, + std::vector{swss::FieldValueTuple{"k2", "v2"}}, + /*allow_unknown=*/true) + .empty()); + EXPECT_TRUE( + verifyAttrs( + std::vector{swss::FieldValueTuple{"k1", "v1"}, swss::FieldValueTuple{"k2", "v2"}}, + std::vector{swss::FieldValueTuple{"k1", "v1"}}, + std::vector{swss::FieldValueTuple{"k2", "v2"}, swss::FieldValueTuple{"k3", "v3"}}, + /*allow_unknown=*/false) + .empty()); } -} // namespace +} // namespace diff --git a/orchagent/p4orch/tests/return_code_test.cpp b/orchagent/p4orch/tests/return_code_test.cpp index 15585ad33b8..6ee73b74f9c 100644 --- a/orchagent/p4orch/tests/return_code_test.cpp +++ b/orchagent/p4orch/tests/return_code_test.cpp @@ -6,192 +6,210 @@ #include #include -extern "C" { +extern "C" +{ #include "sai.h" } -namespace { - -TEST(ReturnCodeTest, SuccessCode) { - auto return_code = ReturnCode(); - EXPECT_TRUE(return_code.ok()); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, return_code); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, return_code.code()); - EXPECT_EQ("SWSS_RC_SUCCESS", return_code.codeStr()); - EXPECT_EQ("SWSS_RC_SUCCESS", return_code.message()); - EXPECT_EQ("SWSS_RC_SUCCESS:SWSS_RC_SUCCESS", return_code.toString()); - EXPECT_FALSE(return_code.isSai()); +namespace +{ + +TEST(ReturnCodeTest, SuccessCode) +{ + auto return_code = ReturnCode(); + EXPECT_TRUE(return_code.ok()); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, return_code); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, return_code.code()); + EXPECT_EQ("SWSS_RC_SUCCESS", return_code.codeStr()); + EXPECT_EQ("SWSS_RC_SUCCESS", return_code.message()); + EXPECT_EQ("SWSS_RC_SUCCESS:SWSS_RC_SUCCESS", return_code.toString()); + EXPECT_FALSE(return_code.isSai()); } -TEST(ReturnCodeTest, SuccessSaiCode) { - auto return_code = ReturnCode(SAI_STATUS_SUCCESS); - EXPECT_TRUE(return_code.ok()); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, return_code); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, return_code.code()); - EXPECT_EQ("SWSS_RC_SUCCESS", return_code.codeStr()); - EXPECT_EQ("SWSS_RC_SUCCESS", return_code.message()); - EXPECT_EQ("SWSS_RC_SUCCESS:SWSS_RC_SUCCESS", return_code.toString()); - EXPECT_TRUE(return_code.isSai()); +TEST(ReturnCodeTest, SuccessSaiCode) +{ + auto return_code = ReturnCode(SAI_STATUS_SUCCESS); + EXPECT_TRUE(return_code.ok()); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, return_code); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, return_code.code()); + EXPECT_EQ("SWSS_RC_SUCCESS", return_code.codeStr()); + EXPECT_EQ("SWSS_RC_SUCCESS", return_code.message()); + EXPECT_EQ("SWSS_RC_SUCCESS:SWSS_RC_SUCCESS", return_code.toString()); + EXPECT_TRUE(return_code.isSai()); } -TEST(ReturnCodeTest, ErrorStatusCode) { - auto return_code = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid arguments."; - EXPECT_FALSE(return_code.ok()); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, return_code); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, return_code.code()); - EXPECT_EQ("SWSS_RC_INVALID_PARAM", return_code.codeStr()); - EXPECT_EQ("Invalid arguments.", return_code.message()); - EXPECT_EQ("SWSS_RC_INVALID_PARAM:Invalid arguments.", return_code.toString()); - EXPECT_FALSE(return_code.isSai()); +TEST(ReturnCodeTest, ErrorStatusCode) +{ + auto return_code = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Invalid arguments."; + EXPECT_FALSE(return_code.ok()); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, return_code); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, return_code.code()); + EXPECT_EQ("SWSS_RC_INVALID_PARAM", return_code.codeStr()); + EXPECT_EQ("Invalid arguments.", return_code.message()); + EXPECT_EQ("SWSS_RC_INVALID_PARAM:Invalid arguments.", return_code.toString()); + EXPECT_FALSE(return_code.isSai()); } -TEST(ReturnCodeTest, ErrorSaiCode) { - sai_status_t sai_statue = SAI_STATUS_NOT_IMPLEMENTED; - auto return_code = ReturnCode(sai_statue) << "SAI error: " << sai_statue; - EXPECT_FALSE(return_code.ok()); - EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, return_code); - EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, return_code.code()); - EXPECT_EQ("SWSS_RC_UNIMPLEMENTED", return_code.codeStr()); - EXPECT_EQ("SAI error: -15", return_code.message()); - EXPECT_EQ("SWSS_RC_UNIMPLEMENTED:SAI error: -15", return_code.toString()); - EXPECT_TRUE(return_code.isSai()); +TEST(ReturnCodeTest, ErrorSaiCode) +{ + sai_status_t sai_statue = SAI_STATUS_NOT_IMPLEMENTED; + auto return_code = ReturnCode(sai_statue) << "SAI error: " << sai_statue; + EXPECT_FALSE(return_code.ok()); + EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, return_code); + EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, return_code.code()); + EXPECT_EQ("SWSS_RC_UNIMPLEMENTED", return_code.codeStr()); + EXPECT_EQ("SAI error: -15", return_code.message()); + EXPECT_EQ("SWSS_RC_UNIMPLEMENTED:SAI error: -15", return_code.toString()); + EXPECT_TRUE(return_code.isSai()); } -TEST(ReturnCodeTest, ReturnCodeCopy) { - ReturnCode return_code_1 = ReturnCode() << "SUCCESS"; - ReturnCode return_code_2 = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid arguments."; - return_code_1 = return_code_2; - EXPECT_FALSE(return_code_1.ok()); - EXPECT_EQ(return_code_1, StatusCode::SWSS_RC_INVALID_PARAM); - EXPECT_EQ(return_code_1.code(), StatusCode::SWSS_RC_INVALID_PARAM); - EXPECT_EQ("SWSS_RC_INVALID_PARAM", return_code_1.codeStr()); - EXPECT_EQ("Invalid arguments.", return_code_1.message()); - EXPECT_EQ("SWSS_RC_INVALID_PARAM:Invalid arguments.", - return_code_1.toString()); - EXPECT_EQ(return_code_1, return_code_2); - EXPECT_FALSE(return_code_1 != return_code_2); +TEST(ReturnCodeTest, ReturnCodeCopy) +{ + ReturnCode return_code_1 = ReturnCode() << "SUCCESS"; + ReturnCode return_code_2 = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Invalid arguments."; + return_code_1 = return_code_2; + EXPECT_FALSE(return_code_1.ok()); + EXPECT_EQ(return_code_1, StatusCode::SWSS_RC_INVALID_PARAM); + EXPECT_EQ(return_code_1.code(), StatusCode::SWSS_RC_INVALID_PARAM); + EXPECT_EQ("SWSS_RC_INVALID_PARAM", return_code_1.codeStr()); + EXPECT_EQ("Invalid arguments.", return_code_1.message()); + EXPECT_EQ("SWSS_RC_INVALID_PARAM:Invalid arguments.", return_code_1.toString()); + EXPECT_EQ(return_code_1, return_code_2); + EXPECT_FALSE(return_code_1 != return_code_2); } -TEST(ReturnCodeTest, PrependStringInMsg) { - auto return_code = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Detailed reasons."; - return_code.prepend("General statement - "); - EXPECT_FALSE(return_code.ok()); - EXPECT_FALSE(StatusCode::SWSS_RC_INVALID_PARAM != return_code); - EXPECT_FALSE(return_code != StatusCode::SWSS_RC_INVALID_PARAM); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, return_code.code()); - EXPECT_EQ("SWSS_RC_INVALID_PARAM", return_code.codeStr()); - EXPECT_EQ("General statement - Detailed reasons.", return_code.message()); - EXPECT_EQ("SWSS_RC_INVALID_PARAM:General statement - Detailed reasons.", - return_code.toString()); +TEST(ReturnCodeTest, PrependStringInMsg) +{ + auto return_code = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Detailed reasons."; + return_code.prepend("General statement - "); + EXPECT_FALSE(return_code.ok()); + EXPECT_FALSE(StatusCode::SWSS_RC_INVALID_PARAM != return_code); + EXPECT_FALSE(return_code != StatusCode::SWSS_RC_INVALID_PARAM); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, return_code.code()); + EXPECT_EQ("SWSS_RC_INVALID_PARAM", return_code.codeStr()); + EXPECT_EQ("General statement - Detailed reasons.", return_code.message()); + EXPECT_EQ("SWSS_RC_INVALID_PARAM:General statement - Detailed reasons.", return_code.toString()); } -TEST(ReturnCodeTest, CopyAndAppendStringInMsg) { - ReturnCode return_code; - return_code = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Detailed reasons."; - EXPECT_EQ("Detailed reasons.", return_code.message()); - return_code << " More details."; - EXPECT_FALSE(return_code.ok()); - EXPECT_FALSE(StatusCode::SWSS_RC_INVALID_PARAM != return_code); - EXPECT_FALSE(return_code != StatusCode::SWSS_RC_INVALID_PARAM); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, return_code.code()); - EXPECT_EQ("SWSS_RC_INVALID_PARAM", return_code.codeStr()); - EXPECT_EQ("Detailed reasons. More details.", return_code.message()); - EXPECT_EQ("SWSS_RC_INVALID_PARAM:Detailed reasons. More details.", - return_code.toString()); +TEST(ReturnCodeTest, CopyAndAppendStringInMsg) +{ + ReturnCode return_code; + return_code = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Detailed reasons."; + EXPECT_EQ("Detailed reasons.", return_code.message()); + return_code << " More details."; + EXPECT_FALSE(return_code.ok()); + EXPECT_FALSE(StatusCode::SWSS_RC_INVALID_PARAM != return_code); + EXPECT_FALSE(return_code != StatusCode::SWSS_RC_INVALID_PARAM); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, return_code.code()); + EXPECT_EQ("SWSS_RC_INVALID_PARAM", return_code.codeStr()); + EXPECT_EQ("Detailed reasons. More details.", return_code.message()); + EXPECT_EQ("SWSS_RC_INVALID_PARAM:Detailed reasons. More details.", return_code.toString()); } -TEST(ReturnCodeTest, SaiCodeToReturnCodeMapping) { - std::unordered_map expect_mapping = { - {SAI_STATUS_SUCCESS, StatusCode::SWSS_RC_SUCCESS}, - {SAI_STATUS_NOT_SUPPORTED, StatusCode::SWSS_RC_UNIMPLEMENTED}, - {SAI_STATUS_NO_MEMORY, StatusCode::SWSS_RC_NO_MEMORY}, - {SAI_STATUS_INSUFFICIENT_RESOURCES, StatusCode::SWSS_RC_FULL}, - {SAI_STATUS_INVALID_PARAMETER, StatusCode::SWSS_RC_INVALID_PARAM}, - {SAI_STATUS_ITEM_ALREADY_EXISTS, StatusCode::SWSS_RC_EXISTS}, - {SAI_STATUS_ITEM_NOT_FOUND, StatusCode::SWSS_RC_NOT_FOUND}, - {SAI_STATUS_TABLE_FULL, StatusCode::SWSS_RC_FULL}, - {SAI_STATUS_NOT_IMPLEMENTED, StatusCode::SWSS_RC_UNIMPLEMENTED}, - {SAI_STATUS_OBJECT_IN_USE, StatusCode::SWSS_RC_IN_USE}, - {SAI_STATUS_NOT_EXECUTED, StatusCode::SWSS_RC_NOT_EXECUTED}, - {SAI_STATUS_FAILURE, StatusCode::SWSS_RC_UNKNOWN}, - {SAI_STATUS_INVALID_ATTRIBUTE_0, StatusCode::SWSS_RC_INVALID_PARAM}, - {SAI_STATUS_INVALID_ATTRIBUTE_10, StatusCode::SWSS_RC_INVALID_PARAM}, - {SAI_STATUS_INVALID_ATTRIBUTE_MAX, StatusCode::SWSS_RC_INVALID_PARAM}, - {SAI_STATUS_INVALID_ATTR_VALUE_0, StatusCode::SWSS_RC_INVALID_PARAM}, - {SAI_STATUS_INVALID_ATTR_VALUE_10, StatusCode::SWSS_RC_INVALID_PARAM}, - {SAI_STATUS_INVALID_ATTR_VALUE_MAX, StatusCode::SWSS_RC_INVALID_PARAM}, - {SAI_STATUS_ATTR_NOT_IMPLEMENTED_0, StatusCode::SWSS_RC_UNIMPLEMENTED}, - {SAI_STATUS_ATTR_NOT_IMPLEMENTED_10, StatusCode::SWSS_RC_UNIMPLEMENTED}, - {SAI_STATUS_ATTR_NOT_IMPLEMENTED_MAX, StatusCode::SWSS_RC_UNIMPLEMENTED}, - {SAI_STATUS_UNKNOWN_ATTRIBUTE_0, StatusCode::SWSS_RC_INVALID_PARAM}, - {SAI_STATUS_UNKNOWN_ATTRIBUTE_10, StatusCode::SWSS_RC_INVALID_PARAM}, - {SAI_STATUS_UNKNOWN_ATTRIBUTE_MAX, StatusCode::SWSS_RC_INVALID_PARAM}, - {SAI_STATUS_ATTR_NOT_SUPPORTED_0, StatusCode::SWSS_RC_UNIMPLEMENTED}, - {SAI_STATUS_ATTR_NOT_SUPPORTED_10, StatusCode::SWSS_RC_UNIMPLEMENTED}, - {SAI_STATUS_ATTR_NOT_SUPPORTED_MAX, StatusCode::SWSS_RC_UNIMPLEMENTED}, - }; - for (const auto& it : expect_mapping) { - ReturnCode return_code(it.first); - EXPECT_EQ(return_code, it.second); - } +TEST(ReturnCodeTest, SaiCodeToReturnCodeMapping) +{ + std::unordered_map expect_mapping = { + {SAI_STATUS_SUCCESS, StatusCode::SWSS_RC_SUCCESS}, + {SAI_STATUS_NOT_SUPPORTED, StatusCode::SWSS_RC_UNIMPLEMENTED}, + {SAI_STATUS_NO_MEMORY, StatusCode::SWSS_RC_NO_MEMORY}, + {SAI_STATUS_INSUFFICIENT_RESOURCES, StatusCode::SWSS_RC_FULL}, + {SAI_STATUS_INVALID_PARAMETER, StatusCode::SWSS_RC_INVALID_PARAM}, + {SAI_STATUS_ITEM_ALREADY_EXISTS, StatusCode::SWSS_RC_EXISTS}, + {SAI_STATUS_ITEM_NOT_FOUND, StatusCode::SWSS_RC_NOT_FOUND}, + {SAI_STATUS_TABLE_FULL, StatusCode::SWSS_RC_FULL}, + {SAI_STATUS_NOT_IMPLEMENTED, StatusCode::SWSS_RC_UNIMPLEMENTED}, + {SAI_STATUS_OBJECT_IN_USE, StatusCode::SWSS_RC_IN_USE}, + {SAI_STATUS_NOT_EXECUTED, StatusCode::SWSS_RC_NOT_EXECUTED}, + {SAI_STATUS_FAILURE, StatusCode::SWSS_RC_UNKNOWN}, + {SAI_STATUS_INVALID_ATTRIBUTE_0, StatusCode::SWSS_RC_INVALID_PARAM}, + {SAI_STATUS_INVALID_ATTRIBUTE_10, StatusCode::SWSS_RC_INVALID_PARAM}, + {SAI_STATUS_INVALID_ATTRIBUTE_MAX, StatusCode::SWSS_RC_INVALID_PARAM}, + {SAI_STATUS_INVALID_ATTR_VALUE_0, StatusCode::SWSS_RC_INVALID_PARAM}, + {SAI_STATUS_INVALID_ATTR_VALUE_10, StatusCode::SWSS_RC_INVALID_PARAM}, + {SAI_STATUS_INVALID_ATTR_VALUE_MAX, StatusCode::SWSS_RC_INVALID_PARAM}, + {SAI_STATUS_ATTR_NOT_IMPLEMENTED_0, StatusCode::SWSS_RC_UNIMPLEMENTED}, + {SAI_STATUS_ATTR_NOT_IMPLEMENTED_10, StatusCode::SWSS_RC_UNIMPLEMENTED}, + {SAI_STATUS_ATTR_NOT_IMPLEMENTED_MAX, StatusCode::SWSS_RC_UNIMPLEMENTED}, + {SAI_STATUS_UNKNOWN_ATTRIBUTE_0, StatusCode::SWSS_RC_INVALID_PARAM}, + {SAI_STATUS_UNKNOWN_ATTRIBUTE_10, StatusCode::SWSS_RC_INVALID_PARAM}, + {SAI_STATUS_UNKNOWN_ATTRIBUTE_MAX, StatusCode::SWSS_RC_INVALID_PARAM}, + {SAI_STATUS_ATTR_NOT_SUPPORTED_0, StatusCode::SWSS_RC_UNIMPLEMENTED}, + {SAI_STATUS_ATTR_NOT_SUPPORTED_10, StatusCode::SWSS_RC_UNIMPLEMENTED}, + {SAI_STATUS_ATTR_NOT_SUPPORTED_MAX, StatusCode::SWSS_RC_UNIMPLEMENTED}, + }; + for (const auto &it : expect_mapping) + { + ReturnCode return_code(it.first); + EXPECT_EQ(return_code, it.second); + } } -TEST(ReturnCodeTest, ReturnCodeOrHasInt) { - ReturnCodeOr return_code_or = 42; - EXPECT_TRUE(return_code_or.ok()); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, return_code_or.status()); - EXPECT_EQ(42, return_code_or.value()); - EXPECT_EQ(42, *return_code_or); +TEST(ReturnCodeTest, ReturnCodeOrHasInt) +{ + ReturnCodeOr return_code_or = 42; + EXPECT_TRUE(return_code_or.ok()); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, return_code_or.status()); + EXPECT_EQ(42, return_code_or.value()); + EXPECT_EQ(42, *return_code_or); } -TEST(ReturnCodeTest, ReturnCodeOrHasCopyableObject) { - class TestObj { - public: - TestObj(int value) : value_(value) {} - int GetValue() { return value_; } - - private: - int value_ = 0; - }; - - ReturnCodeOr return_code_or = TestObj(42); - EXPECT_TRUE(return_code_or.ok()); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, return_code_or.status()); - EXPECT_EQ(42, return_code_or.value().GetValue()); - EXPECT_EQ(42, (*return_code_or).GetValue()); - EXPECT_EQ(42, return_code_or->GetValue()); +TEST(ReturnCodeTest, ReturnCodeOrHasCopyableObject) +{ + class TestObj + { + public: + TestObj(int value) : value_(value) + { + } + int GetValue() + { + return value_; + } + + private: + int value_ = 0; + }; + + ReturnCodeOr return_code_or = TestObj(42); + EXPECT_TRUE(return_code_or.ok()); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, return_code_or.status()); + EXPECT_EQ(42, return_code_or.value().GetValue()); + EXPECT_EQ(42, (*return_code_or).GetValue()); + EXPECT_EQ(42, return_code_or->GetValue()); } -TEST(ReturnCodeTest, ReturnCodeOrHasMoveableObject) { - class TestObj { - public: - TestObj(int value) : value_(value) {} - int GetValue() { return value_; } - - private: - int value_ = 0; - }; - - ReturnCodeOr> return_code_or = - std::make_unique(42); - EXPECT_TRUE(return_code_or.ok()); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, return_code_or.status()); - EXPECT_EQ(42, return_code_or.value()->GetValue()); - EXPECT_EQ(42, (*return_code_or)->GetValue()); - EXPECT_EQ(42, return_code_or->get()->GetValue()); - std::unique_ptr test_obj = std::move(*return_code_or); - EXPECT_EQ(42, test_obj->GetValue()); +TEST(ReturnCodeTest, ReturnCodeOrHasMoveableObject) +{ + class TestObj + { + public: + TestObj(int value) : value_(value) + { + } + int GetValue() + { + return value_; + } + + private: + int value_ = 0; + }; + + ReturnCodeOr> return_code_or = std::make_unique(42); + EXPECT_TRUE(return_code_or.ok()); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, return_code_or.status()); + EXPECT_EQ(42, return_code_or.value()->GetValue()); + EXPECT_EQ(42, (*return_code_or)->GetValue()); + EXPECT_EQ(42, return_code_or->get()->GetValue()); + std::unique_ptr test_obj = std::move(*return_code_or); + EXPECT_EQ(42, test_obj->GetValue()); } -TEST(ReturnCodeTest, ReturnCodeOrHasReturnCode) { - ReturnCodeOr return_code_or = - ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM); - EXPECT_FALSE(return_code_or.ok()); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, return_code_or.status()); +TEST(ReturnCodeTest, ReturnCodeOrHasReturnCode) +{ + ReturnCodeOr return_code_or = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM); + EXPECT_FALSE(return_code_or.ok()); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, return_code_or.status()); } -} // namespace +} // namespace diff --git a/orchagent/p4orch/tests/route_manager_test.cpp b/orchagent/p4orch/tests/route_manager_test.cpp index d2b84008fe1..6229f69c360 100644 --- a/orchagent/p4orch/tests/route_manager_test.cpp +++ b/orchagent/p4orch/tests/route_manager_test.cpp @@ -30,3896 +30,3259 @@ using ::testing::StrictMock; extern sai_object_id_t gSwitchId; extern sai_object_id_t gVirtualRouterId; extern sai_object_id_t gVrfOid; -extern char* gVrfName; +extern char *gVrfName; extern size_t gMaxBulkSize; -extern sai_route_api_t* sai_route_api; -extern VRFOrch* gVrfOrch; +extern sai_route_api_t *sai_route_api; +extern VRFOrch *gVrfOrch; -namespace { +namespace +{ -constexpr char* kIpv4Prefix = "10.11.12.0/24"; -constexpr char* kIpv4Prefix2 = "10.12.12.0/24"; -constexpr char* kIpv6Prefix = "2001:db8:1::/32"; -constexpr char* kNexthopId1 = "ju1u32m1.atl11:qe-3/7"; +constexpr char *kIpv4Prefix = "10.11.12.0/24"; +constexpr char *kIpv4Prefix2 = "10.12.12.0/24"; +constexpr char *kIpv6Prefix = "2001:db8:1::/32"; +constexpr char *kNexthopId1 = "ju1u32m1.atl11:qe-3/7"; constexpr sai_object_id_t kNexthopOid1 = 1; -constexpr char* kNexthopId2 = "ju1u32m2.atl11:qe-3/7"; +constexpr char *kNexthopId2 = "ju1u32m2.atl11:qe-3/7"; constexpr sai_object_id_t kNexthopOid2 = 2; -constexpr char* kWcmpGroup1 = "wcmp-group-1"; +constexpr char *kWcmpGroup1 = "wcmp-group-1"; constexpr sai_object_id_t kWcmpGroupOid1 = 3; -constexpr char* kWcmpGroup2 = "wcmp-group-2"; +constexpr char *kWcmpGroup2 = "wcmp-group-2"; constexpr sai_object_id_t kWcmpGroupOid2 = 4; -constexpr char* kMetadata1 = "1"; -constexpr char* kMetadata2 = "2"; +constexpr char *kMetadata1 = "1"; +constexpr char *kMetadata2 = "2"; uint32_t kMetadataInt1 = 1; uint32_t kMetadataInt2 = 2; // Returns true if the two prefixes are equal. False otherwise. // Arguments must be non-nullptr. -bool PrefixCmp(const sai_ip_prefix_t* x, const sai_ip_prefix_t* y) { - if (x->addr_family != y->addr_family) { - return false; - } - if (x->addr_family == SAI_IP_ADDR_FAMILY_IPV4) { - return memcmp(&x->addr.ip4, &y->addr.ip4, sizeof(sai_ip4_t)) == 0 && - memcmp(&x->mask.ip4, &y->mask.ip4, sizeof(sai_ip4_t)) == 0; - } - return memcmp(&x->addr.ip6, &y->addr.ip6, sizeof(sai_ip6_t)) == 0 && - memcmp(&x->mask.ip6, &y->mask.ip6, sizeof(sai_ip6_t)) == 0; +bool PrefixCmp(const sai_ip_prefix_t *x, const sai_ip_prefix_t *y) +{ + if (x->addr_family != y->addr_family) + { + return false; + } + if (x->addr_family == SAI_IP_ADDR_FAMILY_IPV4) + { + return memcmp(&x->addr.ip4, &y->addr.ip4, sizeof(sai_ip4_t)) == 0 && + memcmp(&x->mask.ip4, &y->mask.ip4, sizeof(sai_ip4_t)) == 0; + } + return memcmp(&x->addr.ip6, &y->addr.ip6, sizeof(sai_ip6_t)) == 0 && + memcmp(&x->mask.ip6, &y->mask.ip6, sizeof(sai_ip6_t)) == 0; } // Matches two SAI route entries. -bool MatchSaiRouteEntry(const sai_route_entry_t& route_entry, - const sai_route_entry_t& exp_route_entry) { - if (route_entry.switch_id != exp_route_entry.switch_id) { - return false; - } - if (route_entry.vr_id != exp_route_entry.vr_id) { - return false; - } - if (!PrefixCmp(&route_entry.destination, &exp_route_entry.destination)) { - return false; - } - return true; +bool MatchSaiRouteEntry(const sai_route_entry_t &route_entry, const sai_route_entry_t &exp_route_entry) +{ + if (route_entry.switch_id != exp_route_entry.switch_id) + { + return false; + } + if (route_entry.vr_id != exp_route_entry.vr_id) + { + return false; + } + if (!PrefixCmp(&route_entry.destination, &exp_route_entry.destination)) + { + return false; + } + return true; } // Matches two SAI attributes. -bool MatchSaiAttribute(const sai_attribute_t& attr, - const sai_attribute_t& exp_attr) { - if (exp_attr.id == SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION) { - if (attr.id != SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION || - attr.value.s32 != exp_attr.value.s32) { - return false; +bool MatchSaiAttribute(const sai_attribute_t &attr, const sai_attribute_t &exp_attr) +{ + if (exp_attr.id == SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION) + { + if (attr.id != SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION || attr.value.s32 != exp_attr.value.s32) + { + return false; + } } - } - if (exp_attr.id == SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID) { - if (attr.id != SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID || - attr.value.oid != exp_attr.value.oid) { - return false; + if (exp_attr.id == SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID) + { + if (attr.id != SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID || attr.value.oid != exp_attr.value.oid) + { + return false; + } } - } - if (exp_attr.id == SAI_ROUTE_ENTRY_ATTR_META_DATA) { - if (attr.id != SAI_ROUTE_ENTRY_ATTR_META_DATA || - attr.value.u32 != exp_attr.value.u32) { - return false; + if (exp_attr.id == SAI_ROUTE_ENTRY_ATTR_META_DATA) + { + if (attr.id != SAI_ROUTE_ENTRY_ATTR_META_DATA || attr.value.u32 != exp_attr.value.u32) + { + return false; + } } - } - return true; + return true; } -MATCHER_P(ArrayEq, array, "") { - for (size_t i = 0; i < array.size(); ++i) { - if (arg[i] != array[i]) { - return false; +MATCHER_P(ArrayEq, array, "") +{ + for (size_t i = 0; i < array.size(); ++i) + { + if (arg[i] != array[i]) + { + return false; + } } - } - return true; + return true; } -MATCHER_P(RouteEntryArrayEq, array, "") { - for (size_t i = 0; i < array.size(); ++i) { - if (!MatchSaiRouteEntry(arg[i], array[i])) { - return false; +MATCHER_P(RouteEntryArrayEq, array, "") +{ + for (size_t i = 0; i < array.size(); ++i) + { + if (!MatchSaiRouteEntry(arg[i], array[i])) + { + return false; + } } - } - return true; + return true; } -MATCHER_P(AttrArrayEq, array, "") { - for (size_t i = 0; i < array.size(); ++i) { - if (!MatchSaiAttribute(arg[i], array[i])) { - return false; +MATCHER_P(AttrArrayEq, array, "") +{ + for (size_t i = 0; i < array.size(); ++i) + { + if (!MatchSaiAttribute(arg[i], array[i])) + { + return false; + } } - } - return true; + return true; +} + +MATCHER_P(AttrArrayArrayEq, array, "") +{ + for (size_t i = 0; i < array.size(); ++i) + { + for (size_t j = 0; j < array[i].size(); j++) + { + if (!MatchSaiAttribute(arg[i][j], array[i][j])) + { + return false; + } + } + } + return true; +} + +MATCHER_P(FieldValueTupleArrayEq, array, "") +{ + for (size_t i = 0; i < array.size(); ++i) + { + if (fvField(arg[i]) != fvField(array[i])) + { + return false; + } + if (fvValue(arg[i]) != fvValue(array[i])) + { + return false; + } + } + return true; } -MATCHER_P(AttrArrayArrayEq, array, "") { - for (size_t i = 0; i < array.size(); ++i) { - for (size_t j = 0; j < array[i].size(); j++) { - if (!MatchSaiAttribute(arg[i][j], array[i][j])) { - return false; - } +} // namespace + +class RouteManagerTest : public ::testing::Test +{ + protected: + RouteManagerTest() : route_manager_(&p4_oid_mapper_, gVrfOrch, &publisher_) + { } - } - return true; -} -MATCHER_P(FieldValueTupleArrayEq, array, "") { - for (size_t i = 0; i < array.size(); ++i) { - if (fvField(arg[i]) != fvField(array[i])) { - return false; + void SetUp() override + { + mock_sai_route = &mock_sai_route_; + sai_route_api->create_route_entry = create_route_entry; + sai_route_api->remove_route_entry = remove_route_entry; + sai_route_api->set_route_entry_attribute = set_route_entry_attribute; + sai_route_api->get_route_entry_attribute = get_route_entry_attribute; + sai_route_api->create_route_entries = create_route_entries; + sai_route_api->remove_route_entries = remove_route_entries; + sai_route_api->set_route_entries_attribute = set_route_entries_attribute; + sai_route_api->get_route_entries_attribute = get_route_entries_attribute; } - if (fvValue(arg[i]) != fvValue(array[i])) { - return false; + + bool MergeRouteEntry(const P4RouteEntry &dest, const P4RouteEntry &src, P4RouteEntry *ret) + { + return route_manager_.mergeRouteEntry(dest, src, ret); } - } - return true; -} - -} // namespace - -class RouteManagerTest : public ::testing::Test { - protected: - RouteManagerTest() : route_manager_(&p4_oid_mapper_, gVrfOrch, &publisher_) {} - - void SetUp() override { - mock_sai_route = &mock_sai_route_; - sai_route_api->create_route_entry = create_route_entry; - sai_route_api->remove_route_entry = remove_route_entry; - sai_route_api->set_route_entry_attribute = set_route_entry_attribute; - sai_route_api->get_route_entry_attribute = get_route_entry_attribute; - sai_route_api->create_route_entries = create_route_entries; - sai_route_api->remove_route_entries = remove_route_entries; - sai_route_api->set_route_entries_attribute = set_route_entries_attribute; - sai_route_api->get_route_entries_attribute = get_route_entries_attribute; - } - - bool MergeRouteEntry(const P4RouteEntry& dest, const P4RouteEntry& src, - P4RouteEntry* ret) { - return route_manager_.mergeRouteEntry(dest, src, ret); - } - - ReturnCodeOr DeserializeRouteEntry( - const std::string& key, - const std::vector& attributes, - const std::string& table_name) { - return route_manager_.deserializeRouteEntry(key, attributes, table_name); - } - - P4RouteEntry* GetRouteEntry(const std::string& route_entry_key) { - return route_manager_.getRouteEntry(route_entry_key); - } - - ReturnCode ValidateRouteEntry(const P4RouteEntry& route_entry, - const std::string& operation) { - return route_manager_.validateRouteEntry(route_entry, operation); - } - - std::vector CreateRouteEntries( - const std::vector& route_entries) { - return route_manager_.createRouteEntries(route_entries); - } - - std::vector UpdateRouteEntries( - const std::vector& route_entries) { - return route_manager_.updateRouteEntries(route_entries); - } - - std::vector DeleteRouteEntries( - const std::vector& route_entries) { - return route_manager_.deleteRouteEntries(route_entries); - } - - void Enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) { - route_manager_.enqueue(table_name, entry); - } - - void Drain() { route_manager_.drain(); } - - std::string VerifyState(const std::string& key, - const std::vector& tuple) { - return route_manager_.verifyState(key, tuple); - } - - // Generates a KeyOpFieldsValuesTuple. - swss::KeyOpFieldsValuesTuple GenerateKeyOpFieldsValuesTuple( - const std::string& vrf_id, const swss::IpPrefix& route_prefix, - const std::string& command, const std::string& action, - const std::string& action_param, const std::string& route_metadata = "") { - nlohmann::json j; - std::string key_prefix; - j[prependMatchField(p4orch::kVrfId)] = vrf_id; - if (route_prefix.isV4()) { - j[prependMatchField(p4orch::kIpv4Dst)] = route_prefix.to_string(); - key_prefix = std::string(APP_P4RT_IPV4_TABLE_NAME) + kTableKeyDelimiter; - } else { - j[prependMatchField(p4orch::kIpv6Dst)] = route_prefix.to_string(); - key_prefix = std::string(APP_P4RT_IPV6_TABLE_NAME) + kTableKeyDelimiter; + + ReturnCodeOr DeserializeRouteEntry(const std::string &key, + const std::vector &attributes, + const std::string &table_name) + { + return route_manager_.deserializeRouteEntry(key, attributes, table_name); } - std::vector attributes; - if (command == SET_COMMAND) { - attributes.push_back(swss::FieldValueTuple{p4orch::kAction, action}); - if (action == p4orch::kSetNexthopId || p4orch::kSetNexthopIdAndMetadata) { - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kNexthopId), action_param}); - } else if (action == p4orch::kSetWcmpGroupId || - action == p4orch::kSetWcmpGroupIdAndMetadata) { - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kWcmpGroupId), action_param}); - } - if (action == p4orch::kSetNexthopIdAndMetadata || - action == p4orch::kSetWcmpGroupIdAndMetadata || - action == p4orch::kSetMetadataAndDrop) { - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kRouteMetadata), route_metadata}); - } + + P4RouteEntry *GetRouteEntry(const std::string &route_entry_key) + { + return route_manager_.getRouteEntry(route_entry_key); } - return swss::KeyOpFieldsValuesTuple(key_prefix + j.dump(), command, - attributes); - } - - // Generates a P4RouteEntry. - P4RouteEntry GenerateP4RouteEntry(const std::string& vrf_id, - const swss::IpPrefix& route_prefix, - const std::string& action, - const std::string& action_param, - const std::string& route_metadata = "") { - P4RouteEntry route_entry = {}; - route_entry.vrf_id = vrf_id; - route_entry.route_prefix = route_prefix; - route_entry.route_metadata = route_metadata; - route_entry.action = action; - if (action == p4orch::kSetNexthopId || - action == p4orch::kSetNexthopIdAndMetadata) { - route_entry.nexthop_id = action_param; - } else if (action == p4orch::kSetWcmpGroupId || - action == p4orch::kSetWcmpGroupIdAndMetadata) { - route_entry.wcmp_group = action_param; + + ReturnCode ValidateRouteEntry(const P4RouteEntry &route_entry, const std::string &operation) + { + return route_manager_.validateRouteEntry(route_entry, operation); } - route_entry.route_entry_key = KeyGenerator::generateRouteKey( - route_entry.vrf_id, route_entry.route_prefix); - return route_entry; - } - - // Sets up a nexthop route entry for test. - void SetupNexthopIdRouteEntry(const std::string& vrf_id, - const swss::IpPrefix& route_prefix, - const std::string& nexthop_id, - sai_object_id_t nexthop_oid, - const std::string& metadata = "") { - auto route_entry = GenerateP4RouteEntry( - vrf_id, route_prefix, - (metadata.empty()) ? p4orch::kSetNexthopId - : p4orch::kSetNexthopIdAndMetadata, - nexthop_id, metadata); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), nexthop_oid); - std::vector exp_status{SAI_STATUS_SUCCESS}; + std::vector CreateRouteEntries(const std::vector &route_entries) + { + return route_manager_.createRouteEntries(route_entries); + } + + std::vector UpdateRouteEntries(const std::vector &route_entries) + { + return route_manager_.updateRouteEntries(route_entries); + } + + std::vector DeleteRouteEntries(const std::vector &route_entries) + { + return route_manager_.deleteRouteEntries(route_entries); + } + + void Enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) + { + route_manager_.enqueue(table_name, entry); + } + + void Drain() + { + route_manager_.drain(); + } + + std::string VerifyState(const std::string &key, const std::vector &tuple) + { + return route_manager_.verifyState(key, tuple); + } + + // Generates a KeyOpFieldsValuesTuple. + swss::KeyOpFieldsValuesTuple GenerateKeyOpFieldsValuesTuple(const std::string &vrf_id, + const swss::IpPrefix &route_prefix, + const std::string &command, const std::string &action, + const std::string &action_param, + const std::string &route_metadata = "") + { + nlohmann::json j; + std::string key_prefix; + j[prependMatchField(p4orch::kVrfId)] = vrf_id; + if (route_prefix.isV4()) + { + j[prependMatchField(p4orch::kIpv4Dst)] = route_prefix.to_string(); + key_prefix = std::string(APP_P4RT_IPV4_TABLE_NAME) + kTableKeyDelimiter; + } + else + { + j[prependMatchField(p4orch::kIpv6Dst)] = route_prefix.to_string(); + key_prefix = std::string(APP_P4RT_IPV6_TABLE_NAME) + kTableKeyDelimiter; + } + std::vector attributes; + if (command == SET_COMMAND) + { + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, action}); + if (action == p4orch::kSetNexthopId || p4orch::kSetNexthopIdAndMetadata) + { + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kNexthopId), action_param}); + } + else if (action == p4orch::kSetWcmpGroupId || action == p4orch::kSetWcmpGroupIdAndMetadata) + { + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kWcmpGroupId), action_param}); + } + if (action == p4orch::kSetNexthopIdAndMetadata || action == p4orch::kSetWcmpGroupIdAndMetadata || + action == p4orch::kSetMetadataAndDrop) + { + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kRouteMetadata), route_metadata}); + } + } + return swss::KeyOpFieldsValuesTuple(key_prefix + j.dump(), command, attributes); + } + + // Generates a P4RouteEntry. + P4RouteEntry GenerateP4RouteEntry(const std::string &vrf_id, const swss::IpPrefix &route_prefix, + const std::string &action, const std::string &action_param, + const std::string &route_metadata = "") + { + P4RouteEntry route_entry = {}; + route_entry.vrf_id = vrf_id; + route_entry.route_prefix = route_prefix; + route_entry.route_metadata = route_metadata; + route_entry.action = action; + if (action == p4orch::kSetNexthopId || action == p4orch::kSetNexthopIdAndMetadata) + { + route_entry.nexthop_id = action_param; + } + else if (action == p4orch::kSetWcmpGroupId || action == p4orch::kSetWcmpGroupIdAndMetadata) + { + route_entry.wcmp_group = action_param; + } + route_entry.route_entry_key = KeyGenerator::generateRouteKey(route_entry.vrf_id, route_entry.route_prefix); + return route_entry; + } + + // Sets up a nexthop route entry for test. + void SetupNexthopIdRouteEntry(const std::string &vrf_id, const swss::IpPrefix &route_prefix, + const std::string &nexthop_id, sai_object_id_t nexthop_oid, + const std::string &metadata = "") + { + auto route_entry = GenerateP4RouteEntry( + vrf_id, route_prefix, (metadata.empty()) ? p4orch::kSetNexthopId : p4orch::kSetNexthopIdAndMetadata, + nexthop_id, metadata); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + nexthop_oid); + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + } + + // Sets up a wcmp route entry for test. + void SetupWcmpGroupRouteEntry(const std::string &vrf_id, const swss::IpPrefix &route_prefix, + const std::string &wcmp_group_id, sai_object_id_t wcmp_group_oid, + const std::string &metadata = "") + { + auto route_entry = GenerateP4RouteEntry( + vrf_id, route_prefix, (metadata.empty()) ? p4orch::kSetWcmpGroupId : p4orch::kSetWcmpGroupIdAndMetadata, + wcmp_group_id, metadata); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), wcmp_group_oid); + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + } + + // Sets up a drop route entry for test. + void SetupDropRouteEntry(const std::string &vrf_id, const swss::IpPrefix &route_prefix) + { + auto route_entry = GenerateP4RouteEntry(vrf_id, route_prefix, p4orch::kDrop, ""); + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + } + + // Sets up a trap route entry for test. + void SetupTrapRouteEntry(const std::string &vrf_id, const swss::IpPrefix &route_prefix) + { + auto route_entry = GenerateP4RouteEntry(vrf_id, route_prefix, p4orch::kTrap, ""); + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + } + + // Verifies the two given route entries are identical. + void VerifyRouteEntriesEq(const P4RouteEntry &x, const P4RouteEntry &y) + { + EXPECT_EQ(x.route_entry_key, y.route_entry_key); + EXPECT_EQ(x.vrf_id, y.vrf_id); + EXPECT_EQ(x.route_prefix, y.route_prefix); + EXPECT_EQ(x.action, y.action); + EXPECT_EQ(x.nexthop_id, y.nexthop_id); + EXPECT_EQ(x.wcmp_group, y.wcmp_group); + EXPECT_EQ(x.route_metadata, y.route_metadata); + EXPECT_EQ(x.sai_route_entry.vr_id, y.sai_route_entry.vr_id); + EXPECT_EQ(x.sai_route_entry.switch_id, y.sai_route_entry.switch_id); + EXPECT_TRUE(PrefixCmp(&x.sai_route_entry.destination, &y.sai_route_entry.destination)); + } + + // Verifies the given route entry exists and matches. + void VerifyRouteEntry(const P4RouteEntry &route_entry, const sai_ip_prefix_t &sai_route_prefix, + const sai_object_id_t vrf_oid) + { + auto *route_entry_ptr = GetRouteEntry(route_entry.route_entry_key); + P4RouteEntry expect_entry = route_entry; + expect_entry.sai_route_entry.vr_id = vrf_oid; + expect_entry.sai_route_entry.switch_id = gSwitchId; + expect_entry.sai_route_entry.destination = sai_route_prefix; + VerifyRouteEntriesEq(expect_entry, *route_entry_ptr); + EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, route_entry.route_entry_key)); + } + + StrictMock mock_sai_route_; + StrictMock publisher_; + P4OidMapper p4_oid_mapper_; + RouteManager route_manager_; +}; + +TEST_F(RouteManagerTest, MergeRouteEntryWithNexthopIdActionDestTest) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto dest = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + dest.sai_route_entry.vr_id = gVrfOid; + dest.sai_route_entry.switch_id = gSwitchId; + copy(dest.sai_route_entry.destination, swss_ipv4_route_prefix); + + // Source is identical to destination. + auto src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + P4RouteEntry ret = {}; + EXPECT_FALSE(MergeRouteEntry(dest, src, &ret)); + VerifyRouteEntriesEq(dest, ret); + + // Source has different nexthop ID. + src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId2); + EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); + P4RouteEntry expect_entry = dest; + expect_entry.nexthop_id = kNexthopId2; + VerifyRouteEntriesEq(expect_entry, ret); + + // Source has set nexthop ID and metadata action and dest has set nexthop ID + // action. + src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopIdAndMetadata, kNexthopId1, + kMetadata1); + EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); + expect_entry = dest; + expect_entry.action = p4orch::kSetNexthopIdAndMetadata; + expect_entry.route_metadata = kMetadata1; + VerifyRouteEntriesEq(expect_entry, ret); + + // Source has wcmp group action and dest has nexhop ID action. + src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); + EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); + expect_entry = dest; + expect_entry.nexthop_id = ""; + expect_entry.action = p4orch::kSetWcmpGroupId; + expect_entry.wcmp_group = kWcmpGroup1; + VerifyRouteEntriesEq(expect_entry, ret); + + // Source has drop action and dest has nexhop ID action. + src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); + EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); + expect_entry = dest; + expect_entry.nexthop_id = ""; + expect_entry.action = p4orch::kDrop; + VerifyRouteEntriesEq(expect_entry, ret); +} + +TEST_F(RouteManagerTest, MergeRouteEntryWithNexthopIdAndMetadataActionDestTest) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto dest = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopIdAndMetadata, kNexthopId1, + kMetadata1); + dest.sai_route_entry.vr_id = gVrfOid; + dest.sai_route_entry.switch_id = gSwitchId; + copy(dest.sai_route_entry.destination, swss_ipv4_route_prefix); + + // Source is identical to destination. + auto src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopIdAndMetadata, kNexthopId1, + kMetadata1); + P4RouteEntry ret = {}; + EXPECT_FALSE(MergeRouteEntry(dest, src, &ret)); + VerifyRouteEntriesEq(dest, ret); + + // Source has different metadata. + src.route_metadata = kMetadata2; + EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); + P4RouteEntry expect_entry = dest; + expect_entry.route_metadata = kMetadata2; + VerifyRouteEntriesEq(expect_entry, ret); + + // Source has different nexthop ID and metadata. + src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopIdAndMetadata, kNexthopId2, + kMetadata2); + EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); + expect_entry = dest; + expect_entry.nexthop_id = kNexthopId2; + expect_entry.route_metadata = kMetadata2; + VerifyRouteEntriesEq(expect_entry, ret); + + // Source has wcmp group action and dest has nexhop ID and metadata action. + src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); + EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); + expect_entry = dest; + expect_entry.nexthop_id = ""; + expect_entry.action = p4orch::kSetWcmpGroupId; + expect_entry.wcmp_group = kWcmpGroup1; + expect_entry.route_metadata = ""; + VerifyRouteEntriesEq(expect_entry, ret); + + // Source has drop action and dest has nexhop ID and metadata action. + src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); + EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); + expect_entry = dest; + expect_entry.nexthop_id = ""; + expect_entry.action = p4orch::kDrop; + expect_entry.route_metadata = ""; + VerifyRouteEntriesEq(expect_entry, ret); + + // Source has wcmp group and metadata action and dest has nexhop ID and + // metadata action. + src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupIdAndMetadata, kWcmpGroup1, + kMetadata2); + EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); + expect_entry = dest; + expect_entry.nexthop_id = ""; + expect_entry.action = p4orch::kSetWcmpGroupIdAndMetadata; + expect_entry.wcmp_group = kWcmpGroup1; + expect_entry.route_metadata = kMetadata2; + VerifyRouteEntriesEq(expect_entry, ret); +} + +TEST_F(RouteManagerTest, MergeRouteEntryWithWcmpGroupActionDestTest) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto dest = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); + dest.sai_route_entry.vr_id = gVrfOid; + dest.sai_route_entry.switch_id = gSwitchId; + copy(dest.sai_route_entry.destination, swss_ipv4_route_prefix); + + // Source is identical to destination. + auto src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); + P4RouteEntry ret = {}; + EXPECT_FALSE(MergeRouteEntry(dest, src, &ret)); + VerifyRouteEntriesEq(dest, ret); + + // Source has different wcmp group. + src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup2); + EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); + P4RouteEntry expect_entry = dest; + expect_entry.wcmp_group = kWcmpGroup2; + VerifyRouteEntriesEq(expect_entry, ret); + + // Source has nexthop ID action and dest has wcmp group action. + src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); + expect_entry = dest; + expect_entry.wcmp_group = ""; + expect_entry.action = p4orch::kSetNexthopId; + expect_entry.nexthop_id = kNexthopId1; + VerifyRouteEntriesEq(expect_entry, ret); + + // Source has drop action and dest has wcmp group action. + src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); + EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); + expect_entry = dest; + expect_entry.wcmp_group = ""; + expect_entry.action = p4orch::kDrop; + VerifyRouteEntriesEq(expect_entry, ret); +} + +TEST_F(RouteManagerTest, MergeRouteEntryWithDropActionDestTest) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto dest = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); + dest.sai_route_entry.vr_id = gVrfOid; + dest.sai_route_entry.switch_id = gSwitchId; + copy(dest.sai_route_entry.destination, swss_ipv4_route_prefix); + + // Source is identical to destination. + auto src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); + P4RouteEntry ret = {}; + EXPECT_FALSE(MergeRouteEntry(dest, src, &ret)); + VerifyRouteEntriesEq(dest, ret); + + // Source has nexthop ID action and dest has drop action. + src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); + P4RouteEntry expect_entry = dest; + expect_entry.action = p4orch::kSetNexthopId; + expect_entry.nexthop_id = kNexthopId1; + VerifyRouteEntriesEq(expect_entry, ret); + + // Source has wcmp group and metadata action and dest has drop action. + src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupIdAndMetadata, kWcmpGroup1, + kMetadata1); + EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); + expect_entry = dest; + expect_entry.action = p4orch::kSetWcmpGroupIdAndMetadata; + expect_entry.nexthop_id = ""; + expect_entry.wcmp_group = kWcmpGroup1; + expect_entry.route_metadata = kMetadata1; + VerifyRouteEntriesEq(expect_entry, ret); +} + +TEST_F(RouteManagerTest, MergeRouteEntryWithTrapActionDestTest) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto dest = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kTrap, ""); + dest.sai_route_entry.vr_id = gVrfOid; + dest.sai_route_entry.switch_id = gSwitchId; + copy(dest.sai_route_entry.destination, swss_ipv4_route_prefix); + + // Source is identical to destination. + auto src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kTrap, ""); + P4RouteEntry ret = {}; + EXPECT_FALSE(MergeRouteEntry(dest, src, &ret)); + VerifyRouteEntriesEq(dest, ret); + + // Source has nexthop ID action and dest has trap action. + src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); + P4RouteEntry expect_entry = dest; + expect_entry.action = p4orch::kSetNexthopId; + expect_entry.nexthop_id = kNexthopId1; + VerifyRouteEntriesEq(expect_entry, ret); + + // Source has wcmp group action and dest has trap action. + src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); + EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); + expect_entry = dest; + expect_entry.action = p4orch::kSetWcmpGroupId; + expect_entry.wcmp_group = kWcmpGroup1; + VerifyRouteEntriesEq(expect_entry, ret); +} + +TEST_F(RouteManagerTest, DeserializeRouteEntryWithNexthopIdActionTest) +{ + std::string key = R"({"match/vrf_id":"b4-traffic","match/ipv4_dst":"10.11.12.0/24"})"; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kSetNexthopId}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kNexthopId), kNexthopId1}); + auto route_entry_or = DeserializeRouteEntry(key, attributes, APP_P4RT_IPV4_TABLE_NAME); + EXPECT_TRUE(route_entry_or.ok()); + auto &route_entry = *route_entry_or; + auto expect_entry = + GenerateP4RouteEntry("b4-traffic", swss::IpPrefix("10.11.12.0/24"), p4orch::kSetNexthopId, kNexthopId1); + VerifyRouteEntriesEq(expect_entry, route_entry); +} + +TEST_F(RouteManagerTest, DeserializeRouteEntryWithWcmpGroupActionTest) +{ + std::string key = R"({"match/vrf_id":"b4-traffic","match/ipv4_dst":"10.11.12.0/24"})"; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kSetWcmpGroupId}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kWcmpGroupId), kWcmpGroup1}); + auto route_entry_or = DeserializeRouteEntry(key, attributes, APP_P4RT_IPV4_TABLE_NAME); + EXPECT_TRUE(route_entry_or.ok()); + auto &route_entry = *route_entry_or; + auto expect_entry = + GenerateP4RouteEntry("b4-traffic", swss::IpPrefix("10.11.12.0/24"), p4orch::kSetWcmpGroupId, kWcmpGroup1); + VerifyRouteEntriesEq(expect_entry, route_entry); +} + +TEST_F(RouteManagerTest, DeserializeRouteEntryWithNexthopIdAdnMetadataActionTest) +{ + std::string key = R"({"match/vrf_id":"b4-traffic","match/ipv4_dst":"10.11.12.0/24"})"; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kSetNexthopIdAndMetadata}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kNexthopId), kNexthopId1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kRouteMetadata), kMetadata1}); + auto route_entry_or = DeserializeRouteEntry(key, attributes, APP_P4RT_IPV4_TABLE_NAME); + EXPECT_TRUE(route_entry_or.ok()); + auto &route_entry = *route_entry_or; + auto expect_entry = GenerateP4RouteEntry("b4-traffic", swss::IpPrefix("10.11.12.0/24"), + p4orch::kSetNexthopIdAndMetadata, kNexthopId1, kMetadata1); + VerifyRouteEntriesEq(expect_entry, route_entry); +} + +TEST_F(RouteManagerTest, DeserializeRouteEntryWithWcmpGroupAndMetadataActionTest) +{ + std::string key = R"({"match/vrf_id":"b4-traffic","match/ipv4_dst":"10.11.12.0/24"})"; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kSetWcmpGroupIdAndMetadata}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kWcmpGroupId), kWcmpGroup1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kRouteMetadata), kMetadata1}); + auto route_entry_or = DeserializeRouteEntry(key, attributes, APP_P4RT_IPV4_TABLE_NAME); + EXPECT_TRUE(route_entry_or.ok()); + auto &route_entry = *route_entry_or; + auto expect_entry = GenerateP4RouteEntry("b4-traffic", swss::IpPrefix("10.11.12.0/24"), + p4orch::kSetWcmpGroupIdAndMetadata, kWcmpGroup1, kMetadata1); + VerifyRouteEntriesEq(expect_entry, route_entry); +} + +TEST_F(RouteManagerTest, DeserializeRouteEntryWithDropActionTest) +{ + std::string key = R"({"match/vrf_id":"b4-traffic","match/ipv6_dst":"2001:db8:1::/32"})"; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kDrop}); + auto route_entry_or = DeserializeRouteEntry(key, attributes, APP_P4RT_IPV6_TABLE_NAME); + EXPECT_TRUE(route_entry_or.ok()); + auto &route_entry = *route_entry_or; + auto expect_entry = GenerateP4RouteEntry("b4-traffic", swss::IpPrefix("2001:db8:1::/32"), p4orch::kDrop, ""); + VerifyRouteEntriesEq(expect_entry, route_entry); +} + +TEST_F(RouteManagerTest, DeserializeRouteEntryWithTrapActionTest) +{ + std::string key = R"({"match/vrf_id":"b4-traffic","match/ipv6_dst":"2001:db8:1::/32"})"; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kTrap}); + auto route_entry_or = DeserializeRouteEntry(key, attributes, APP_P4RT_IPV6_TABLE_NAME); + EXPECT_TRUE(route_entry_or.ok()); + auto &route_entry = *route_entry_or; + auto expect_entry = GenerateP4RouteEntry("b4-traffic", swss::IpPrefix("2001:db8:1::/32"), p4orch::kTrap, ""); + VerifyRouteEntriesEq(expect_entry, route_entry); +} + +TEST_F(RouteManagerTest, DeserializeRouteEntryWithInvalidKeyShouldFail) +{ + std::string key = "{{{{{{{{{{{{"; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kDrop}); + auto route_entry_or = DeserializeRouteEntry(key, attributes, APP_P4RT_IPV6_TABLE_NAME); + EXPECT_FALSE(route_entry_or.ok()); +} + +TEST_F(RouteManagerTest, DeserializeRouteEntryWithInvalidFieldShouldFail) +{ + std::string key = R"({"match/vrf_id":"b4-traffic","match/ipv6_dst":"2001:db8:1::/32"})"; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{"invalid", "invalid"}); + auto route_entry_or = DeserializeRouteEntry(key, attributes, APP_P4RT_IPV6_TABLE_NAME); + EXPECT_FALSE(route_entry_or.ok()); +} + +TEST_F(RouteManagerTest, DeserializeRouteEntryWithInvalidRouteShouldFail) +{ + std::string key = R"({"match/vrf_id":"b4-traffic","match/ipv6_dst":"invalid"})"; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kDrop}); + auto route_entry_or = DeserializeRouteEntry(key, attributes, APP_P4RT_IPV6_TABLE_NAME); + EXPECT_FALSE(route_entry_or.ok()); +} + +TEST_F(RouteManagerTest, DeserializeRouteEntryWithoutIpv4WildcardLpmMatchShouldSucceed) +{ + std::string key = R"({"match/vrf_id":"b4-traffic"})"; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kDrop}); + auto route_entry_or = DeserializeRouteEntry(key, attributes, APP_P4RT_IPV4_TABLE_NAME); + EXPECT_TRUE(route_entry_or.ok()); + auto &route_entry = *route_entry_or; + auto expect_entry = GenerateP4RouteEntry("b4-traffic", swss::IpPrefix("0.0.0.0/0"), p4orch::kDrop, ""); + VerifyRouteEntriesEq(expect_entry, route_entry); +} + +TEST_F(RouteManagerTest, DeserializeRouteEntryWithoutIpv6WildcardLpmMatchShouldSucceed) +{ + std::string key = R"({"match/vrf_id":"b4-traffic"})"; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kDrop}); + auto route_entry_or = DeserializeRouteEntry(key, attributes, APP_P4RT_IPV6_TABLE_NAME); + EXPECT_TRUE(route_entry_or.ok()); + auto &route_entry = *route_entry_or; + auto expect_entry = GenerateP4RouteEntry("b4-traffic", swss::IpPrefix("::/0"), p4orch::kDrop, ""); + VerifyRouteEntriesEq(expect_entry, route_entry); +} + +TEST_F(RouteManagerTest, ValidateRouteEntryNexthopActionWithInvalidNexthopShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateRouteEntryNexthopActionWithValidNexthopShouldSucceed) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid1); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateRouteEntryWcmpGroupActionWithInvalidWcmpGroupShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateRouteEntryWcmpGroupActionWithValidWcmpGroupShouldSucceed) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), + kWcmpGroupOid1); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateRouteEntryWithInvalidCommandShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, "invalid")); +} + +TEST_F(RouteManagerTest, ValidateSetRouteEntryDoesNotExistInManagerShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + route_entry.action = ""; + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid1); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateSetRouteEntryExistsInMapperDoesNotExistInManagerShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid1); + p4_oid_mapper_.setDummyOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, route_entry.route_entry_key); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateSetRouteEntryExistsInManagerDoesNotExistInMapperShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, route_entry.route_entry_key); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateSetRouteEntryNexthopIdActionWithoutNexthopIdShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, ""); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateSetRouteEntryNexthopIdActionWithWcmpGroupShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + route_entry.wcmp_group = kWcmpGroup1; + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), + kWcmpGroupOid1); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateSetRouteEntryWcmpGroupActionWithoutWcmpGroupShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, ""); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateSetRouteEntryWcmpGroupActionWithNexthopIdShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); + route_entry.nexthop_id = kNexthopId1; + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), + kWcmpGroupOid1); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateSetRouteEntryDropActionWithNexthopIdShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); + route_entry.nexthop_id = kNexthopId1; + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid1); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateSetRouteEntryWcmpGroupActionWithNonemptyMetadataShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = + GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1, kMetadata1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), + kWcmpGroupOid1); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateSetRouteEntryNexthopIdAndMetadataActionWithEmptyMetadataShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = + GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopIdAndMetadata, kNexthopId1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid1); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateSetRouteEntryNexthopIdAndMetadataActionWithInvalidMetadataShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopIdAndMetadata, + kNexthopId1, "invalid_int"); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid1); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateSetRouteEntryDropActionWithWcmpGroupShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); + route_entry.wcmp_group = kWcmpGroup1; + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), + kWcmpGroupOid1); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateSetRouteEntryTrapActionWithNexthopIdShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kTrap, ""); + route_entry.nexthop_id = kNexthopId1; + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid1); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateSetRouteEntryTrapActionWithWcmpGroupShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kTrap, ""); + route_entry.wcmp_group = kWcmpGroup1; + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), + kWcmpGroupOid1); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateSetRouteEntryInvalidActionShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); + route_entry.action = "invalid"; + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateSetRouteEntrySucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId2); + route_entry.action = ""; + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid2); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ValidateRouteEntry(route_entry, SET_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateDelRouteEntryDoesNotExistInManagerShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, "", ""); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ValidateRouteEntry(route_entry, DEL_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateDelRouteEntryDoesNotExistInMapperShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, "", ""); + p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, route_entry.route_entry_key); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, ValidateRouteEntry(route_entry, DEL_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateDelRouteEntryHasActionShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, ""); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, DEL_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateDelRouteEntryHasNexthopIdShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + route_entry.action = ""; + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid1); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, DEL_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateDelRouteEntryHasWcmpGroupShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); + route_entry.action = ""; + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), + kWcmpGroupOid1); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, DEL_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateDelRouteEntryHasMetadataShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, "", "", kMetadata1); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ValidateRouteEntry(route_entry, DEL_COMMAND)); +} + +TEST_F(RouteManagerTest, ValidateDelRouteEntrySucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, "", ""); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ValidateRouteEntry(route_entry, DEL_COMMAND)); +} + +TEST_F(RouteManagerTest, CreateRouteEntryWithSaiErrorShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); + + std::vector exp_status{SAI_STATUS_FAILURE}; EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); + .Times(3) + .WillRepeatedly(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_FAILURE))); + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); + + route_entry.action = p4orch::kSetNexthopId; + route_entry.nexthop_id = kNexthopId1; + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid1); + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); + + route_entry.action = p4orch::kSetWcmpGroupId; + route_entry.wcmp_group = kWcmpGroup1; + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), + kWcmpGroupOid1); + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); +} + +TEST_F(RouteManagerTest, CreateNexthopIdIpv4RouteSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid1); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kNexthopOid1; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, + create_route_entries(Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + ArrayEq(std::vector{1}), + AttrArrayArrayEq(std::vector>{{exp_sai_attr}}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - } - - // Sets up a wcmp route entry for test. - void SetupWcmpGroupRouteEntry(const std::string& vrf_id, - const swss::IpPrefix& route_prefix, - const std::string& wcmp_group_id, - sai_object_id_t wcmp_group_oid, - const std::string& metadata = "") { - auto route_entry = GenerateP4RouteEntry( - vrf_id, route_prefix, - (metadata.empty()) ? p4orch::kSetWcmpGroupId - : p4orch::kSetWcmpGroupIdAndMetadata, - wcmp_group_id, metadata); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - wcmp_group_oid); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, CreateNexthopIdIpv6RouteSucceeds) +{ + auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); + sai_ip_prefix_t sai_ipv6_route_prefix; + copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid1); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv6_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kNexthopOid1; std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_route_, + create_route_entries(Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + ArrayEq(std::vector{1}), + AttrArrayArrayEq(std::vector>{{exp_sai_attr}}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - } + VerifyRouteEntry(route_entry, sai_ipv6_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, CreateNexthopIdWithMetadataIpv4RouteSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopIdAndMetadata, + kNexthopId1, kMetadata1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid1); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + std::vector exp_sai_attrs; + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kNexthopOid1; + exp_sai_attrs.push_back(exp_sai_attr); + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; + exp_sai_attr.value.u32 = kMetadataInt1; + exp_sai_attrs.push_back(exp_sai_attr); - // Sets up a drop route entry for test. - void SetupDropRouteEntry(const std::string& vrf_id, - const swss::IpPrefix& route_prefix) { + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, + create_route_entries(Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + ArrayEq(std::vector{static_cast(exp_sai_attrs.size())}), + AttrArrayArrayEq(std::vector>{exp_sai_attrs}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, CreateDropSetMetadataRouteSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); auto route_entry = - GenerateP4RouteEntry(vrf_id, route_prefix, p4orch::kDrop, ""); + GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetMetadataAndDrop, "", kMetadata1); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + std::vector exp_sai_attrs; + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + exp_sai_attr.value.s32 = SAI_PACKET_ACTION_DROP; + exp_sai_attrs.push_back(exp_sai_attr); + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; + exp_sai_attr.value.u32 = kMetadataInt1; + exp_sai_attrs.push_back(exp_sai_attr); std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_route_, + create_route_entries(Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + ArrayEq(std::vector{static_cast(exp_sai_attrs.size())}), + AttrArrayArrayEq(std::vector>{exp_sai_attrs}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); +} + +TEST_F(RouteManagerTest, CreateDropIpv4RouteSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + exp_sai_attr.value.s32 = SAI_PACKET_ACTION_DROP; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, + create_route_entries(Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + ArrayEq(std::vector{1}), + AttrArrayArrayEq(std::vector>{{exp_sai_attr}}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); +} + +TEST_F(RouteManagerTest, CreateDropIpv6RouteSucceeds) +{ + auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); + sai_ip_prefix_t sai_ipv6_route_prefix; + copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kDrop, ""); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv6_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + exp_sai_attr.value.s32 = SAI_PACKET_ACTION_DROP; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, + create_route_entries(Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + ArrayEq(std::vector{1}), + AttrArrayArrayEq(std::vector>{{exp_sai_attr}}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv6_route_prefix, gVrfOid); +} + +TEST_F(RouteManagerTest, CreateTrapIpv4RouteSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kTrap, ""); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + exp_sai_attr.value.s32 = SAI_PACKET_ACTION_TRAP; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, + create_route_entries(Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + ArrayEq(std::vector{1}), + AttrArrayArrayEq(std::vector>{{exp_sai_attr}}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); +} + +TEST_F(RouteManagerTest, CreateTrapIpv6RouteSucceeds) +{ + auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); + sai_ip_prefix_t sai_ipv6_route_prefix; + copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kTrap, ""); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv6_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + exp_sai_attr.value.s32 = SAI_PACKET_ACTION_TRAP; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, + create_route_entries(Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + ArrayEq(std::vector{1}), + AttrArrayArrayEq(std::vector>{{exp_sai_attr}}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv6_route_prefix, gVrfOid); +} + +TEST_F(RouteManagerTest, CreateWcmpIpv4RouteSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), + kWcmpGroupOid1); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kWcmpGroupOid1; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, + create_route_entries(Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + ArrayEq(std::vector{1}), + AttrArrayArrayEq(std::vector>{{exp_sai_attr}}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - } + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, CreateWcmpIpv6RouteSucceeds) +{ + auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); + sai_ip_prefix_t sai_ipv6_route_prefix; + copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), + kWcmpGroupOid1); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv6_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kWcmpGroupOid1; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, + create_route_entries(Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + ArrayEq(std::vector{1}), + AttrArrayArrayEq(std::vector>{{exp_sai_attr}}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv6_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, CreateWcmpWithMetadataIpv6RouteSucceeds) +{ + auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); + sai_ip_prefix_t sai_ipv6_route_prefix; + copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kSetWcmpGroupIdAndMetadata, + kWcmpGroup1, kMetadata1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), + kWcmpGroupOid1); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv6_route_prefix; + + std::vector exp_sai_attrs; + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kWcmpGroupOid1; + exp_sai_attrs.push_back(exp_sai_attr); + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; + exp_sai_attr.value.u32 = kMetadataInt1; + exp_sai_attrs.push_back(exp_sai_attr); + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, + create_route_entries(Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + ArrayEq(std::vector{static_cast(exp_sai_attrs.size())}), + AttrArrayArrayEq(std::vector>{exp_sai_attrs}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv6_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateRouteEntryWcmpWithSaiErrorShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupWcmpGroupRouteEntry(gVrfName, swss_ipv4_route_prefix, kWcmpGroup1, kWcmpGroupOid1); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup2); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), + kWcmpGroupOid2); + std::vector exp_status{SAI_STATUS_FAILURE}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_FAILURE))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); +} + +TEST_F(RouteManagerTest, UpdateRouteEntryWcmpNotExistInMapperShouldRaiseCriticalState) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupWcmpGroupRouteEntry(gVrfName, swss_ipv4_route_prefix, kWcmpGroup1, kWcmpGroupOid1); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup2); + std::vector exp_status{SAI_STATUS_FAILURE}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_FAILURE))); + // TODO: Expect critical state. + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); +} + +TEST_F(RouteManagerTest, UpdateRouteFromSetWcmpToSetNextHopSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupWcmpGroupRouteEntry(gVrfName, swss_ipv4_route_prefix, kWcmpGroup1, kWcmpGroupOid1); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId2); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid2); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kNexthopOid2; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateRouteFromSetWcmpToSetNextHopAndMetadataSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupWcmpGroupRouteEntry(gVrfName, swss_ipv4_route_prefix, kWcmpGroup1, kWcmpGroupOid1); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopIdAndMetadata, + kNexthopId2, kMetadata2); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid2); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; + exp_sai_attr.value.u32 = kMetadataInt2; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kNexthopOid2; + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateRouteFromSetNexthopIdToSetWcmpSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup2); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), + kWcmpGroupOid2); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kWcmpGroupOid2; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + route_entry.action = p4orch::kSetWcmpGroupId; + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup2), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateRouteFromSetNexthopIdAndMetadataToSetWcmpSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1, kMetadata2); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup2); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), + kWcmpGroupOid2); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; + exp_sai_attr.value.u32 = 0; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kWcmpGroupOid2; + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup2), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateRouteEntryNexthopIdWithSaiErrorShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId2); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid2); + std::vector exp_failure_status{SAI_STATUS_FAILURE}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); +} + +TEST_F(RouteManagerTest, UpdateRouteEntryNexthopIdNotExistInMapperShouldRaiseCriticalState) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId2); + std::vector exp_failure_status{SAI_STATUS_FAILURE}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))); + // TODO: Expect critical state. + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); +} + +TEST_F(RouteManagerTest, UpdateRouteEntryDropWithSaiErrorShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); + std::vector exp_failure_status{SAI_STATUS_FAILURE}; + std::vector exp_success_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))); + // TODO: Expect critical state. + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); +} + +TEST_F(RouteManagerTest, UpdateRouteEntryTrapWithSaiErrorShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kTrap, ""); + std::vector exp_failure_status{SAI_STATUS_FAILURE}; + std::vector exp_success_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))); + // TODO: Expect critical state. + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); +} + +TEST_F(RouteManagerTest, UpdateRouteWithDifferentNexthopIdsSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId2); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid2); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kNexthopOid2; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + route_entry.action = p4orch::kSetNexthopId; + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateRouteWithDifferentNexthopIdsAndMetadatasSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1, kMetadata1); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopIdAndMetadata, + kNexthopId2, kMetadata2); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid2); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; + exp_sai_attr.value.u32 = kMetadataInt2; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kNexthopOid2; + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateRouteFromNexthopIdToDropSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + exp_sai_attr.value.s32 = SAI_PACKET_ACTION_DROP; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = SAI_NULL_OBJECT_ID; + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateRouteFromNexthopIdToRouteMetadataSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + + auto route_entry = + GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetMetadataAndDrop, "", kMetadata1); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; + exp_sai_attr.value.s32 = kMetadataInt1; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = SAI_NULL_OBJECT_ID; + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + exp_sai_attr.value.s32 = SAI_PACKET_ACTION_DROP; + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateRouteFromNexthopIdAndMetadataToDropSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1, kMetadata2); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + exp_sai_attr.value.s32 = SAI_PACKET_ACTION_DROP; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = SAI_NULL_OBJECT_ID; + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; + exp_sai_attr.value.u32 = 0; + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateRouteFromDropToNexthopIdSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupDropRouteEntry(gVrfName, swss_ipv4_route_prefix); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId2); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid2); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kNexthopOid2; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + exp_sai_attr.value.s32 = SAI_PACKET_ACTION_FORWARD; + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateRouteFromDropToWcmpWithMetadataSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupDropRouteEntry(gVrfName, swss_ipv4_route_prefix); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupIdAndMetadata, + kWcmpGroup1, kMetadata2); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), + kWcmpGroupOid1); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; + exp_sai_attr.value.u32 = kMetadataInt2; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kWcmpGroupOid1; + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + exp_sai_attr.value.s32 = SAI_PACKET_ACTION_FORWARD; + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateRouteFromTrapToDropAndSetMetadataSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupTrapRouteEntry(gVrfName, swss_ipv4_route_prefix); + + auto route_entry = + GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetMetadataAndDrop, "", kMetadata2); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + exp_sai_attr.value.s32 = SAI_PACKET_ACTION_DROP; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; + exp_sai_attr.value.u32 = kMetadataInt2; + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); +} + +TEST_F(RouteManagerTest, UpdateRouteFromTrapToDropSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupTrapRouteEntry(gVrfName, swss_ipv4_route_prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + exp_sai_attr.value.s32 = SAI_PACKET_ACTION_DROP; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); +} + +TEST_F(RouteManagerTest, UpdateRouteFromDropToTrapSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupDropRouteEntry(gVrfName, swss_ipv4_route_prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kTrap, ""); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + exp_sai_attr.value.s32 = SAI_PACKET_ACTION_TRAP; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); +} + +TEST_F(RouteManagerTest, UpdateRouteFromNexthopIdToTrapSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kTrap, ""); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + exp_sai_attr.value.s32 = SAI_PACKET_ACTION_TRAP; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = SAI_NULL_OBJECT_ID; + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateRouteFromTrapToNexthopIdSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupTrapRouteEntry(gVrfName, swss_ipv4_route_prefix); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId2); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid2); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; - // Sets up a trap route entry for test. - void SetupTrapRouteEntry(const std::string& vrf_id, - const swss::IpPrefix& route_prefix) { + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kNexthopOid2; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + exp_sai_attr.value.s32 = SAI_PACKET_ACTION_FORWARD; + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateRouteFromTrapToNexthopIdAndMetadataRecoverFailureShouldRaiseCriticalState) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupTrapRouteEntry(gVrfName, swss_ipv4_route_prefix); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopIdAndMetadata, + kNexthopId2, kMetadata1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid2); + std::vector exp_failure_status{SAI_STATUS_FAILURE}; + std::vector exp_success_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))); + // TODO: Expect critical state. + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); +} + +TEST_F(RouteManagerTest, UpdateRouteWithDifferentWcmpGroupsSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupWcmpGroupRouteEntry(gVrfName, swss_ipv4_route_prefix, kWcmpGroup1, kWcmpGroupOid1); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup2); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), + kWcmpGroupOid2); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kWcmpGroupOid2; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + AttrArrayEq(std::vector{exp_sai_attr}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + route_entry.action = p4orch::kSetWcmpGroupId; + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup2), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateNexthopIdRouteWithNoChangeSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateRouteFromNexthopIdAndMetadataToDropRecoverFailureShouldRaiseCriticalState) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1, kMetadata2); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); + + std::vector exp_failure_status{SAI_STATUS_FAILURE}; + std::vector exp_success_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))); + // TODO: Expect critical state. + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); +} + +TEST_F(RouteManagerTest, UpdateRouteFromDifferentNexthopIdAndMetadataRecoverFailureShouldRaiseCriticalState) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1, kMetadata1); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopIdAndMetadata, + kNexthopId2, kMetadata2); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry.nexthop_id), + kNexthopOid2); + + std::vector exp_failure_status{SAI_STATUS_FAILURE}; + std::vector exp_success_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); + + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), exp_success_status.end()), + Return(SAI_STATUS_SUCCESS))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))) + .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), exp_failure_status.end()), + Return(SAI_STATUS_FAILURE))); + // TODO: Expect critical state. + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); +} + +TEST_F(RouteManagerTest, DeleteRouteEntryWithSaiErrorShouldFail) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + + std::vector exp_status{SAI_STATUS_FAILURE}; + EXPECT_CALL(mock_sai_route_, remove_route_entries(_, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<3>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_FAILURE))); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, "", ""); + EXPECT_THAT(DeleteRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); +} + +TEST_F(RouteManagerTest, DeleteIpv4RouteSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, + remove_route_entries(Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<3>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, "", ""); + EXPECT_THAT(DeleteRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + auto *route_entry_ptr = GetRouteEntry(route_entry.route_entry_key); + EXPECT_EQ(nullptr, route_entry_ptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, route_entry.route_entry_key)); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); +} + +TEST_F(RouteManagerTest, DeleteIpv6RouteSucceeds) +{ + auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); + sai_ip_prefix_t sai_ipv6_route_prefix; + copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); + SetupWcmpGroupRouteEntry(gVrfName, swss_ipv6_route_prefix, kWcmpGroup1, kWcmpGroupOid1); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVrfOid; + exp_sai_route_entry.destination = sai_ipv6_route_prefix; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, + remove_route_entries(Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<3>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, "", ""); + EXPECT_THAT(DeleteRouteEntries(std::vector{route_entry}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); + auto *route_entry_ptr = GetRouteEntry(route_entry.route_entry_key); + EXPECT_EQ(nullptr, route_entry_ptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, route_entry.route_entry_key)); + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); +} + +TEST_F(RouteManagerTest, RouteCreateAndUpdateInDrainSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), kNexthopOid1); + auto key_op_fvs_1 = GenerateKeyOpFieldsValuesTuple(gVrfName, swss_ipv4_route_prefix, SET_COMMAND, + p4orch::kSetNexthopId, kNexthopId1); + Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_1); + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(publisher_, publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_1)), + FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_1)), + Eq(StatusCode::SWSS_RC_SUCCESS), Eq(true))) + .Times(1); + Drain(); + + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), kNexthopOid2); + auto key_op_fvs_2 = GenerateKeyOpFieldsValuesTuple(gVrfName, swss_ipv4_route_prefix, SET_COMMAND, + p4orch::kSetNexthopId, kNexthopId2); + Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_2); + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(publisher_, publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_2)), + FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_2)), + Eq(StatusCode::SWSS_RC_SUCCESS), Eq(true))) + .Times(1); + Drain(); + + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId2); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + auto key_op_fvs_3 = GenerateKeyOpFieldsValuesTuple(gVrfName, swss_ipv4_route_prefix, SET_COMMAND, + p4orch::kSetMetadataAndDrop, "", kMetadata1); + Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_3); + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) + .WillRepeatedly(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(publisher_, publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_3)), + FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_3)), + Eq(StatusCode::SWSS_RC_SUCCESS), Eq(true))) + .Times(1); + Drain(); + + route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetMetadataAndDrop, "", kMetadata1); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); +} + +TEST_F(RouteManagerTest, RouteCreateAndDeleteInDrainSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), kNexthopOid1); + auto key_op_fvs_1 = GenerateKeyOpFieldsValuesTuple(gVrfName, swss_ipv4_route_prefix, SET_COMMAND, + p4orch::kSetNexthopId, kNexthopId1); + Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_1); + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(publisher_, publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_1)), + FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_1)), + Eq(StatusCode::SWSS_RC_SUCCESS), Eq(true))) + .Times(1); + Drain(); + + auto key_op_fvs_2 = GenerateKeyOpFieldsValuesTuple(gVrfName, swss_ipv4_route_prefix, DEL_COMMAND, "", ""); + Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_2); + EXPECT_CALL(mock_sai_route_, remove_route_entries(_, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<3>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(publisher_, publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_2)), + FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_2)), + Eq(StatusCode::SWSS_RC_SUCCESS), Eq(true))) + .Times(1); + Drain(); + + std::string key = KeyGenerator::generateRouteKey(gVrfName, swss_ipv4_route_prefix); + auto *route_entry_ptr = GetRouteEntry(key); + EXPECT_EQ(nullptr, route_entry_ptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, key)); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); +} + +TEST_F(RouteManagerTest, UpdateFailsWhenCreateAndUpdateTheSameRouteInDrain) +{ + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), kNexthopOid1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), kNexthopOid2); + auto key_op_fvs_1 = GenerateKeyOpFieldsValuesTuple(gVrfName, swss::IpPrefix(kIpv4Prefix), SET_COMMAND, + p4orch::kSetNexthopId, kNexthopId1); + Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_1); + auto key_op_fvs_2 = GenerateKeyOpFieldsValuesTuple(gVrfName, swss::IpPrefix(kIpv4Prefix), SET_COMMAND, + p4orch::kSetNexthopId, kNexthopId2); + Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_2); + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(publisher_, publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_1)), + FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_1)), + Eq(StatusCode::SWSS_RC_SUCCESS), Eq(true))) + .Times(1); + EXPECT_CALL(publisher_, publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_2)), + FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_2)), + Eq(StatusCode::SWSS_RC_INVALID_PARAM), Eq(true))) + .Times(1); + + Drain(); + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); +} + +TEST_F(RouteManagerTest, DeleteFailsWhenCreateAndDeleteTheSameRouteInDrain) +{ + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), kNexthopOid1); + auto key_op_fvs_1 = GenerateKeyOpFieldsValuesTuple(gVrfName, swss::IpPrefix(kIpv4Prefix), SET_COMMAND, + p4orch::kSetNexthopId, kNexthopId1); + Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_1); + auto key_op_fvs_2 = GenerateKeyOpFieldsValuesTuple(gVrfName, swss::IpPrefix(kIpv4Prefix), DEL_COMMAND, "", ""); + Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_2); + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(publisher_, publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_1)), + FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_1)), + Eq(StatusCode::SWSS_RC_SUCCESS), Eq(true))) + .Times(1); + EXPECT_CALL(publisher_, publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_2)), + FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_2)), + Eq(StatusCode::SWSS_RC_INVALID_PARAM), Eq(true))) + .Times(1); + Drain(); + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, RouteCreateInDrainSucceedsWhenVrfIsEmpty) +{ + const std::string kDefaultVrfName = ""; // Default Vrf + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), kNexthopOid1); + auto key_op_fvs = GenerateKeyOpFieldsValuesTuple(kDefaultVrfName, swss::IpPrefix(kIpv4Prefix), SET_COMMAND, + p4orch::kSetNexthopId, kNexthopId1); + Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs); + + sai_route_entry_t exp_sai_route_entry; + exp_sai_route_entry.switch_id = gSwitchId; + exp_sai_route_entry.vr_id = gVirtualRouterId; + exp_sai_route_entry.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr; + exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr.value.oid = kNexthopOid1; + + std::vector exp_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, + create_route_entries(Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry}), + ArrayEq(std::vector{1}), + AttrArrayArrayEq(std::vector>{{exp_sai_attr}}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(publisher_, + publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs)), + FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs)), Eq(StatusCode::SWSS_RC_SUCCESS), Eq(true))) + .Times(1); + + Drain(); + std::string key = KeyGenerator::generateRouteKey(kDefaultVrfName, swss::IpPrefix(kIpv4Prefix)); + auto *route_entry_ptr = GetRouteEntry(key); + EXPECT_NE(nullptr, route_entry_ptr); + EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, key)); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, DeserializeRouteEntryInDrainFails) +{ + const std::string kKeyPrefix = std::string(APP_P4RT_IPV4_TABLE_NAME) + kTableKeyDelimiter; + auto key_op_fvs = + swss::KeyOpFieldsValuesTuple(kKeyPrefix + "{{{{{{{{{{{{", SET_COMMAND, std::vector{}); + Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs); + EXPECT_CALL(publisher_, publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs)), + FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs)), + Eq(StatusCode::SWSS_RC_INVALID_PARAM), Eq(true))) + .Times(1); + Drain(); +} + +TEST_F(RouteManagerTest, ValidateRouteEntryInDrainFailsWhenVrfDoesNotExist) +{ + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), kNexthopOid1); + auto key_op_fvs = GenerateKeyOpFieldsValuesTuple("Invalid-Vrf", swss::IpPrefix(kIpv4Prefix), SET_COMMAND, + p4orch::kSetNexthopId, kNexthopId1); + Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs); + EXPECT_CALL(publisher_, publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs)), + FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs)), + Eq(StatusCode::SWSS_RC_NOT_FOUND), Eq(true))) + .Times(1); + Drain(); +} + +TEST_F(RouteManagerTest, ValidateRouteEntryInDrainFailsWhenNexthopDoesNotExist) +{ + auto key_op_fvs = GenerateKeyOpFieldsValuesTuple(gVrfName, swss::IpPrefix(kIpv4Prefix), SET_COMMAND, + p4orch::kSetNexthopId, kNexthopId1); + Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs); + EXPECT_CALL(publisher_, publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs)), + FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs)), + Eq(StatusCode::SWSS_RC_NOT_FOUND), Eq(true))) + .Times(1); + Drain(); +} + +TEST_F(RouteManagerTest, InvalidateSetRouteEntryInDrainFails) +{ + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), kNexthopOid1); + // No nexthop ID with kSetNexthopId action. + auto key_op_fvs = + GenerateKeyOpFieldsValuesTuple(gVrfName, swss::IpPrefix(kIpv4Prefix), SET_COMMAND, p4orch::kSetNexthopId, ""); + Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs); + EXPECT_CALL(publisher_, publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs)), + FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs)), + Eq(StatusCode::SWSS_RC_INVALID_PARAM), Eq(true))) + .Times(1); + Drain(); +} + +TEST_F(RouteManagerTest, InvalidateDelRouteEntryInDrainFails) +{ + // Route does not exist. + auto key_op_fvs = GenerateKeyOpFieldsValuesTuple(gVrfName, swss::IpPrefix(kIpv4Prefix), DEL_COMMAND, + p4orch::kSetNexthopId, kNexthopId1); + Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs); + EXPECT_CALL(publisher_, publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs)), + FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs)), + Eq(StatusCode::SWSS_RC_NOT_FOUND), Eq(true))) + .Times(1); + Drain(); +} + +TEST_F(RouteManagerTest, InvalidCommandInDrainFails) +{ + const std::string kKeyPrefix = std::string(APP_P4RT_IPV4_TABLE_NAME) + kTableKeyDelimiter; + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), kNexthopOid1); + nlohmann::json j; + j[prependMatchField(p4orch::kVrfId)] = gVrfName; + j[prependMatchField(p4orch::kIpv4Dst)] = kIpv4Prefix; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kSetNexthopId}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kNexthopId), kNexthopId1}); + auto key_op_fvs = swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), "INVALID_COMMAND", attributes); + Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs); + EXPECT_CALL(publisher_, publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs)), + FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs)), + Eq(StatusCode::SWSS_RC_INVALID_PARAM), Eq(true))) + .Times(1); + Drain(); +} + +TEST_F(RouteManagerTest, BatchedCreateSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + auto route_entry_ipv4 = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry_ipv4.nexthop_id), + kNexthopOid1); + + auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); + sai_ip_prefix_t sai_ipv6_route_prefix; + copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); + auto route_entry_ipv6 = + GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(route_entry_ipv6.wcmp_group), kWcmpGroupOid1); + + sai_route_entry_t exp_sai_route_entry_ipv4; + exp_sai_route_entry_ipv4.switch_id = gSwitchId; + exp_sai_route_entry_ipv4.vr_id = gVrfOid; + exp_sai_route_entry_ipv4.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr_ipv4; + exp_sai_attr_ipv4.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr_ipv4.value.oid = kNexthopOid1; + + sai_route_entry_t exp_sai_route_entry_ipv6; + exp_sai_route_entry_ipv6.switch_id = gSwitchId; + exp_sai_route_entry_ipv6.vr_id = gVrfOid; + exp_sai_route_entry_ipv6.destination = sai_ipv6_route_prefix; + + sai_attribute_t exp_sai_attr_ipv6; + exp_sai_attr_ipv6.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr_ipv6.value.oid = kWcmpGroupOid1; + + std::vector exp_status{SAI_STATUS_SUCCESS, SAI_STATUS_SUCCESS}; + EXPECT_CALL( + mock_sai_route_, + create_route_entries( + Eq(2), + RouteEntryArrayEq(std::vector{exp_sai_route_entry_ipv6, exp_sai_route_entry_ipv4}), + ArrayEq(std::vector{1, 1}), + AttrArrayArrayEq(std::vector>{{exp_sai_attr_ipv6}, {exp_sai_attr_ipv4}}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry_ipv4, route_entry_ipv6}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS, StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry_ipv4, sai_ipv4_route_prefix, gVrfOid); + VerifyRouteEntry(route_entry_ipv6, sai_ipv6_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, BatchedCreatePartiallySucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + auto route_entry_ipv4 = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(route_entry_ipv4.nexthop_id), + kNexthopOid1); + + auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); + sai_ip_prefix_t sai_ipv6_route_prefix; + copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); + auto route_entry_ipv6 = + GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(route_entry_ipv6.wcmp_group), kWcmpGroupOid1); + + sai_route_entry_t exp_sai_route_entry_ipv4; + exp_sai_route_entry_ipv4.switch_id = gSwitchId; + exp_sai_route_entry_ipv4.vr_id = gVrfOid; + exp_sai_route_entry_ipv4.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr_ipv4; + exp_sai_attr_ipv4.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr_ipv4.value.oid = kNexthopOid1; + + sai_route_entry_t exp_sai_route_entry_ipv6; + exp_sai_route_entry_ipv6.switch_id = gSwitchId; + exp_sai_route_entry_ipv6.vr_id = gVrfOid; + exp_sai_route_entry_ipv6.destination = sai_ipv6_route_prefix; + + sai_attribute_t exp_sai_attr_ipv6; + exp_sai_attr_ipv6.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr_ipv6.value.oid = kWcmpGroupOid1; + + std::vector exp_status{SAI_STATUS_FAILURE, SAI_STATUS_SUCCESS}; + EXPECT_CALL( + mock_sai_route_, + create_route_entries( + Eq(2), + RouteEntryArrayEq(std::vector{exp_sai_route_entry_ipv6, exp_sai_route_entry_ipv4}), + ArrayEq(std::vector{1, 1}), + AttrArrayArrayEq(std::vector>{{exp_sai_attr_ipv6}, {exp_sai_attr_ipv4}}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_FAILURE))); + EXPECT_THAT(CreateRouteEntries(std::vector{route_entry_ipv4, route_entry_ipv6}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS, StatusCode::SWSS_RC_UNKNOWN})); + VerifyRouteEntry(route_entry_ipv4, sai_ipv4_route_prefix, gVrfOid); + auto *route_entry_ptr_ipv6 = GetRouteEntry(route_entry_ipv6.route_entry_key); + EXPECT_EQ(nullptr, route_entry_ptr_ipv6); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, route_entry_ipv6.route_entry_key)); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); +} + +TEST_F(RouteManagerTest, BatchedUpdateSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + auto route_entry_ipv4 = + GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), + kWcmpGroupOid1); + + auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); + sai_ip_prefix_t sai_ipv6_route_prefix; + copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); + auto route_entry_ipv6 = + GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup2); + SetupDropRouteEntry(gVrfName, swss_ipv6_route_prefix); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(kWcmpGroup2), + kWcmpGroupOid2); + + sai_route_entry_t exp_sai_route_entry_ipv4; + exp_sai_route_entry_ipv4.switch_id = gSwitchId; + exp_sai_route_entry_ipv4.vr_id = gVrfOid; + exp_sai_route_entry_ipv4.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr_ipv4; + exp_sai_attr_ipv4.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr_ipv4.value.oid = kWcmpGroupOid1; + + sai_route_entry_t exp_sai_route_entry_ipv6; + exp_sai_route_entry_ipv6.switch_id = gSwitchId; + exp_sai_route_entry_ipv6.vr_id = gVrfOid; + exp_sai_route_entry_ipv6.destination = sai_ipv6_route_prefix; + + sai_attribute_t exp_sai_attr_ipv6; + exp_sai_attr_ipv6.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr_ipv6.value.oid = kWcmpGroupOid2; + + std::vector exp_status_1{SAI_STATUS_SUCCESS, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(2), + RouteEntryArrayEq(std::vector{exp_sai_route_entry_ipv6, + exp_sai_route_entry_ipv4}), + AttrArrayEq(std::vector{exp_sai_attr_ipv6, exp_sai_attr_ipv4}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status_1.begin(), exp_status_1.end()), Return(SAI_STATUS_SUCCESS))); + + sai_attribute_t exp_sai_attr_ipv6_2; + exp_sai_attr_ipv6_2.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; + exp_sai_attr_ipv6_2.value.s32 = SAI_PACKET_ACTION_FORWARD; + + std::vector exp_status_2{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(1), RouteEntryArrayEq(std::vector{exp_sai_route_entry_ipv6}), + AttrArrayEq(std::vector{exp_sai_attr_ipv6_2}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status_2.begin(), exp_status_2.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry_ipv4, route_entry_ipv6}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS, StatusCode::SWSS_RC_SUCCESS})); + VerifyRouteEntry(route_entry_ipv4, sai_ipv4_route_prefix, gVrfOid); + VerifyRouteEntry(route_entry_ipv6, sai_ipv6_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup2), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); +} + +TEST_F(RouteManagerTest, BatchedUpdatePartiallySucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + auto route_entry_ipv4 = + GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), + kWcmpGroupOid1); + + auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); + sai_ip_prefix_t sai_ipv6_route_prefix; + copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); + auto route_entry_ipv6 = + GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup2); + SetupDropRouteEntry(gVrfName, swss_ipv6_route_prefix); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(kWcmpGroup2), + kWcmpGroupOid2); + + sai_route_entry_t exp_sai_route_entry_ipv4; + exp_sai_route_entry_ipv4.switch_id = gSwitchId; + exp_sai_route_entry_ipv4.vr_id = gVrfOid; + exp_sai_route_entry_ipv4.destination = sai_ipv4_route_prefix; + + sai_attribute_t exp_sai_attr_ipv4; + exp_sai_attr_ipv4.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr_ipv4.value.oid = kWcmpGroupOid1; + + sai_route_entry_t exp_sai_route_entry_ipv6; + exp_sai_route_entry_ipv6.switch_id = gSwitchId; + exp_sai_route_entry_ipv6.vr_id = gVrfOid; + exp_sai_route_entry_ipv6.destination = sai_ipv6_route_prefix; + + sai_attribute_t exp_sai_attr_ipv6; + exp_sai_attr_ipv6.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; + exp_sai_attr_ipv6.value.oid = kWcmpGroupOid2; + + std::vector exp_status_1{SAI_STATUS_FAILURE, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, set_route_entries_attribute( + Eq(2), + RouteEntryArrayEq(std::vector{exp_sai_route_entry_ipv6, + exp_sai_route_entry_ipv4}), + AttrArrayEq(std::vector{exp_sai_attr_ipv6, exp_sai_attr_ipv4}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<4>(exp_status_1.begin(), exp_status_1.end()), Return(SAI_STATUS_FAILURE))); + EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry_ipv4, route_entry_ipv6}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS, StatusCode::SWSS_RC_UNKNOWN})); + VerifyRouteEntry(route_entry_ipv4, sai_ipv4_route_prefix, gVrfOid); + route_entry_ipv6 = GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kDrop, ""); + VerifyRouteEntry(route_entry_ipv6, sai_ipv6_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + EXPECT_TRUE(p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, + KeyGenerator::generateWcmpGroupKey(kWcmpGroup2), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); +} + +TEST_F(RouteManagerTest, BatchedDeleteSucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + auto route_entry_ipv4 = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + + auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); + sai_ip_prefix_t sai_ipv6_route_prefix; + copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); + auto route_entry_ipv6 = GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kDrop, ""); + SetupDropRouteEntry(gVrfName, swss_ipv6_route_prefix); + + sai_route_entry_t exp_sai_route_entry_ipv4; + exp_sai_route_entry_ipv4.switch_id = gSwitchId; + exp_sai_route_entry_ipv4.vr_id = gVrfOid; + exp_sai_route_entry_ipv4.destination = sai_ipv4_route_prefix; + + sai_route_entry_t exp_sai_route_entry_ipv6; + exp_sai_route_entry_ipv6.switch_id = gSwitchId; + exp_sai_route_entry_ipv6.vr_id = gVrfOid; + exp_sai_route_entry_ipv6.destination = sai_ipv6_route_prefix; + + std::vector exp_status{SAI_STATUS_SUCCESS, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, remove_route_entries(Eq(2), + RouteEntryArrayEq(std::vector{ + exp_sai_route_entry_ipv6, exp_sai_route_entry_ipv4}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<3>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_THAT(DeleteRouteEntries(std::vector{route_entry_ipv4, route_entry_ipv6}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS, StatusCode::SWSS_RC_SUCCESS})); + auto *route_entry_ptr_ipv4 = GetRouteEntry(route_entry_ipv4.route_entry_key); + EXPECT_EQ(nullptr, route_entry_ptr_ipv4); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, route_entry_ipv4.route_entry_key)); + auto *route_entry_ptr_ipv6 = GetRouteEntry(route_entry_ipv6.route_entry_key); + EXPECT_EQ(nullptr, route_entry_ptr_ipv6); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, route_entry_ipv6.route_entry_key)); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); +} + +TEST_F(RouteManagerTest, BatchedDeletePartiallySucceeds) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + sai_ip_prefix_t sai_ipv4_route_prefix; + copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); + auto route_entry_ipv4 = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + + auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); + sai_ip_prefix_t sai_ipv6_route_prefix; + copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); + auto route_entry_ipv6 = GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kDrop, ""); + SetupDropRouteEntry(gVrfName, swss_ipv6_route_prefix); + + sai_route_entry_t exp_sai_route_entry_ipv4; + exp_sai_route_entry_ipv4.switch_id = gSwitchId; + exp_sai_route_entry_ipv4.vr_id = gVrfOid; + exp_sai_route_entry_ipv4.destination = sai_ipv4_route_prefix; + + sai_route_entry_t exp_sai_route_entry_ipv6; + exp_sai_route_entry_ipv6.switch_id = gSwitchId; + exp_sai_route_entry_ipv6.vr_id = gVrfOid; + exp_sai_route_entry_ipv6.destination = sai_ipv6_route_prefix; + + std::vector exp_status{SAI_STATUS_FAILURE, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_route_, remove_route_entries(Eq(2), + RouteEntryArrayEq(std::vector{ + exp_sai_route_entry_ipv6, exp_sai_route_entry_ipv4}), + Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<3>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_FAILURE))); + EXPECT_THAT(DeleteRouteEntries(std::vector{route_entry_ipv4, route_entry_ipv6}), + ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS, StatusCode::SWSS_RC_UNKNOWN})); + auto *route_entry_ptr_ipv4 = GetRouteEntry(route_entry_ipv4.route_entry_key); + EXPECT_EQ(nullptr, route_entry_ptr_ipv4); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, route_entry_ipv4.route_entry_key)); + VerifyRouteEntry(route_entry_ipv6, sai_ipv6_route_prefix, gVrfOid); + uint32_t ref_cnt; + EXPECT_TRUE( + p4_oid_mapper_.getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), &ref_cnt)); + EXPECT_EQ(0, ref_cnt); +} + +TEST_F(RouteManagerTest, VerifyStateTest) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, kNexthopOid1); + auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set("SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"10.11.12.0/" + "24\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}", + std::vector{swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID", "oid:0x1"}}); + + nlohmann::json j; + j[prependMatchField(p4orch::kVrfId)] = gVrfName; + j[prependMatchField(p4orch::kIpv4Dst)] = kIpv4Prefix; + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_IPV4_TABLE_NAME + + kTableKeyDelimiter + j.dump(); + std::vector attributes; + + // Verification should succeed with vaild key and value. + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kSetNexthopId}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kNexthopId), kNexthopId1}); + EXPECT_EQ(VerifyState(db_key, attributes), ""); + + // TODO: Expect critical state. + + // Invalid key should fail verification. + EXPECT_FALSE(VerifyState("invalid", attributes).empty()); + EXPECT_FALSE(VerifyState("invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":FIXED_IPV4_TABLE:invalid", attributes).empty()); + + // Verification should fail if nexthop ID does not exist. + attributes.clear(); + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kSetNexthopId}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kNexthopId), kNexthopId2}); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + attributes.clear(); + attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kSetNexthopId}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kNexthopId), kNexthopId1}); + + // Verification should fail if entry does not exist. + j[prependMatchField(p4orch::kIpv4Dst)] = "1.1.1.0/24"; + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_IPV4_TABLE_NAME + + kTableKeyDelimiter + j.dump(), + attributes) + .empty()); + + auto *route_entry_ptr = GetRouteEntry(KeyGenerator::generateRouteKey(gVrfName, swss_ipv4_route_prefix)); + EXPECT_NE(route_entry_ptr, nullptr); + + // Verification should fail if route entry key mismatches. + auto saved_route_entry_key = route_entry_ptr->route_entry_key; + route_entry_ptr->route_entry_key = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + route_entry_ptr->route_entry_key = saved_route_entry_key; + + // Verification should fail if VRF ID mismatches. + auto saved_vrf_id = route_entry_ptr->vrf_id; + route_entry_ptr->vrf_id = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + route_entry_ptr->vrf_id = saved_vrf_id; + + // Verification should fail if route prefix mismatches. + auto saved_route_prefix = route_entry_ptr->route_prefix; + route_entry_ptr->route_prefix = swss::IpPrefix(kIpv6Prefix); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + route_entry_ptr->route_prefix = saved_route_prefix; + + // Verification should fail if action mismatches. + auto saved_action = route_entry_ptr->action; + route_entry_ptr->action = p4orch::kSetWcmpGroupId; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + route_entry_ptr->action = saved_action; + + // Verification should fail if nexthop ID mismatches. + auto saved_nexthop_id = route_entry_ptr->nexthop_id; + route_entry_ptr->nexthop_id = kNexthopId2; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + route_entry_ptr->nexthop_id = saved_nexthop_id; + + // Verification should fail if WCMP group mismatches. + auto saved_wcmp_group = route_entry_ptr->wcmp_group; + route_entry_ptr->wcmp_group = kWcmpGroup1; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + route_entry_ptr->wcmp_group = saved_wcmp_group; + + // Verification should fail if WCMP group mismatches. + auto saved_route_metadata = route_entry_ptr->route_metadata; + route_entry_ptr->route_metadata = kMetadata1; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + route_entry_ptr->route_metadata = saved_route_metadata; +} + +TEST_F(RouteManagerTest, VerifyStateAsicDbTest) +{ + auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); + SetupDropRouteEntry(gVrfName, swss_ipv4_route_prefix); + auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); + SetupNexthopIdRouteEntry(gVrfName, swss_ipv6_route_prefix, kNexthopId1, kNexthopOid1, kMetadata1); + + auto swss_ipv4_route_prefix2 = swss::IpPrefix(kIpv4Prefix2); auto route_entry = - GenerateP4RouteEntry(vrf_id, route_prefix, p4orch::kTrap, ""); + GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix2, p4orch::kSetMetadataAndDrop, "", kMetadata2); std::vector exp_status{SAI_STATUS_SUCCESS}; EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); + .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - } - - // Verifies the two given route entries are identical. - void VerifyRouteEntriesEq(const P4RouteEntry& x, const P4RouteEntry& y) { - EXPECT_EQ(x.route_entry_key, y.route_entry_key); - EXPECT_EQ(x.vrf_id, y.vrf_id); - EXPECT_EQ(x.route_prefix, y.route_prefix); - EXPECT_EQ(x.action, y.action); - EXPECT_EQ(x.nexthop_id, y.nexthop_id); - EXPECT_EQ(x.wcmp_group, y.wcmp_group); - EXPECT_EQ(x.route_metadata, y.route_metadata); - EXPECT_EQ(x.sai_route_entry.vr_id, y.sai_route_entry.vr_id); - EXPECT_EQ(x.sai_route_entry.switch_id, y.sai_route_entry.switch_id); - EXPECT_TRUE(PrefixCmp(&x.sai_route_entry.destination, - &y.sai_route_entry.destination)); - } - - // Verifies the given route entry exists and matches. - void VerifyRouteEntry(const P4RouteEntry& route_entry, - const sai_ip_prefix_t& sai_route_prefix, - const sai_object_id_t vrf_oid) { - auto* route_entry_ptr = GetRouteEntry(route_entry.route_entry_key); - P4RouteEntry expect_entry = route_entry; - expect_entry.sai_route_entry.vr_id = vrf_oid; - expect_entry.sai_route_entry.switch_id = gSwitchId; - expect_entry.sai_route_entry.destination = sai_route_prefix; - VerifyRouteEntriesEq(expect_entry, *route_entry_ptr); - EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, - route_entry.route_entry_key)); - } - - StrictMock mock_sai_route_; - StrictMock publisher_; - P4OidMapper p4_oid_mapper_; - RouteManager route_manager_; -}; -TEST_F(RouteManagerTest, MergeRouteEntryWithNexthopIdActionDestTest) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto dest = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - dest.sai_route_entry.vr_id = gVrfOid; - dest.sai_route_entry.switch_id = gSwitchId; - copy(dest.sai_route_entry.destination, swss_ipv4_route_prefix); - - // Source is identical to destination. - auto src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - P4RouteEntry ret = {}; - EXPECT_FALSE(MergeRouteEntry(dest, src, &ret)); - VerifyRouteEntriesEq(dest, ret); - - // Source has different nexthop ID. - src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId2); - EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); - P4RouteEntry expect_entry = dest; - expect_entry.nexthop_id = kNexthopId2; - VerifyRouteEntriesEq(expect_entry, ret); - - // Source has set nexthop ID and metadata action and dest has set nexthop ID - // action. - src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopIdAndMetadata, kNexthopId1, - kMetadata1); - EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); - expect_entry = dest; - expect_entry.action = p4orch::kSetNexthopIdAndMetadata; - expect_entry.route_metadata = kMetadata1; - VerifyRouteEntriesEq(expect_entry, ret); - - // Source has wcmp group action and dest has nexhop ID action. - src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup1); - EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); - expect_entry = dest; - expect_entry.nexthop_id = ""; - expect_entry.action = p4orch::kSetWcmpGroupId; - expect_entry.wcmp_group = kWcmpGroup1; - VerifyRouteEntriesEq(expect_entry, ret); - - // Source has drop action and dest has nexhop ID action. - src = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); - EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); - expect_entry = dest; - expect_entry.nexthop_id = ""; - expect_entry.action = p4orch::kDrop; - VerifyRouteEntriesEq(expect_entry, ret); -} - -TEST_F(RouteManagerTest, - MergeRouteEntryWithNexthopIdAndMetadataActionDestTest) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto dest = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopIdAndMetadata, - kNexthopId1, kMetadata1); - dest.sai_route_entry.vr_id = gVrfOid; - dest.sai_route_entry.switch_id = gSwitchId; - copy(dest.sai_route_entry.destination, swss_ipv4_route_prefix); - - // Source is identical to destination. - auto src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopIdAndMetadata, kNexthopId1, - kMetadata1); - P4RouteEntry ret = {}; - EXPECT_FALSE(MergeRouteEntry(dest, src, &ret)); - VerifyRouteEntriesEq(dest, ret); - - // Source has different metadata. - src.route_metadata = kMetadata2; - EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); - P4RouteEntry expect_entry = dest; - expect_entry.route_metadata = kMetadata2; - VerifyRouteEntriesEq(expect_entry, ret); - - // Source has different nexthop ID and metadata. - src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopIdAndMetadata, kNexthopId2, - kMetadata2); - EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); - expect_entry = dest; - expect_entry.nexthop_id = kNexthopId2; - expect_entry.route_metadata = kMetadata2; - VerifyRouteEntriesEq(expect_entry, ret); - - // Source has wcmp group action and dest has nexhop ID and metadata action. - src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup1); - EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); - expect_entry = dest; - expect_entry.nexthop_id = ""; - expect_entry.action = p4orch::kSetWcmpGroupId; - expect_entry.wcmp_group = kWcmpGroup1; - expect_entry.route_metadata = ""; - VerifyRouteEntriesEq(expect_entry, ret); - - // Source has drop action and dest has nexhop ID and metadata action. - src = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); - EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); - expect_entry = dest; - expect_entry.nexthop_id = ""; - expect_entry.action = p4orch::kDrop; - expect_entry.route_metadata = ""; - VerifyRouteEntriesEq(expect_entry, ret); - - // Source has wcmp group and metadata action and dest has nexhop ID and - // metadata action. - src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupIdAndMetadata, kWcmpGroup1, - kMetadata2); - EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); - expect_entry = dest; - expect_entry.nexthop_id = ""; - expect_entry.action = p4orch::kSetWcmpGroupIdAndMetadata; - expect_entry.wcmp_group = kWcmpGroup1; - expect_entry.route_metadata = kMetadata2; - VerifyRouteEntriesEq(expect_entry, ret); -} - -TEST_F(RouteManagerTest, MergeRouteEntryWithWcmpGroupActionDestTest) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto dest = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup1); - dest.sai_route_entry.vr_id = gVrfOid; - dest.sai_route_entry.switch_id = gSwitchId; - copy(dest.sai_route_entry.destination, swss_ipv4_route_prefix); - - // Source is identical to destination. - auto src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup1); - P4RouteEntry ret = {}; - EXPECT_FALSE(MergeRouteEntry(dest, src, &ret)); - VerifyRouteEntriesEq(dest, ret); - - // Source has different wcmp group. - src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup2); - EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); - P4RouteEntry expect_entry = dest; - expect_entry.wcmp_group = kWcmpGroup2; - VerifyRouteEntriesEq(expect_entry, ret); - - // Source has nexthop ID action and dest has wcmp group action. - src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); - expect_entry = dest; - expect_entry.wcmp_group = ""; - expect_entry.action = p4orch::kSetNexthopId; - expect_entry.nexthop_id = kNexthopId1; - VerifyRouteEntriesEq(expect_entry, ret); - - // Source has drop action and dest has wcmp group action. - src = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); - EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); - expect_entry = dest; - expect_entry.wcmp_group = ""; - expect_entry.action = p4orch::kDrop; - VerifyRouteEntriesEq(expect_entry, ret); -} - -TEST_F(RouteManagerTest, MergeRouteEntryWithDropActionDestTest) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto dest = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); - dest.sai_route_entry.vr_id = gVrfOid; - dest.sai_route_entry.switch_id = gSwitchId; - copy(dest.sai_route_entry.destination, swss_ipv4_route_prefix); - - // Source is identical to destination. - auto src = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); - P4RouteEntry ret = {}; - EXPECT_FALSE(MergeRouteEntry(dest, src, &ret)); - VerifyRouteEntriesEq(dest, ret); - - // Source has nexthop ID action and dest has drop action. - src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); - P4RouteEntry expect_entry = dest; - expect_entry.action = p4orch::kSetNexthopId; - expect_entry.nexthop_id = kNexthopId1; - VerifyRouteEntriesEq(expect_entry, ret); - - // Source has wcmp group and metadata action and dest has drop action. - src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupIdAndMetadata, kWcmpGroup1, - kMetadata1); - EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); - expect_entry = dest; - expect_entry.action = p4orch::kSetWcmpGroupIdAndMetadata; - expect_entry.nexthop_id = ""; - expect_entry.wcmp_group = kWcmpGroup1; - expect_entry.route_metadata = kMetadata1; - VerifyRouteEntriesEq(expect_entry, ret); -} - -TEST_F(RouteManagerTest, MergeRouteEntryWithTrapActionDestTest) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto dest = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kTrap, ""); - dest.sai_route_entry.vr_id = gVrfOid; - dest.sai_route_entry.switch_id = gSwitchId; - copy(dest.sai_route_entry.destination, swss_ipv4_route_prefix); - - // Source is identical to destination. - auto src = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kTrap, ""); - P4RouteEntry ret = {}; - EXPECT_FALSE(MergeRouteEntry(dest, src, &ret)); - VerifyRouteEntriesEq(dest, ret); - - // Source has nexthop ID action and dest has trap action. - src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); - P4RouteEntry expect_entry = dest; - expect_entry.action = p4orch::kSetNexthopId; - expect_entry.nexthop_id = kNexthopId1; - VerifyRouteEntriesEq(expect_entry, ret); - - // Source has wcmp group action and dest has trap action. - src = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup1); - EXPECT_TRUE(MergeRouteEntry(dest, src, &ret)); - expect_entry = dest; - expect_entry.action = p4orch::kSetWcmpGroupId; - expect_entry.wcmp_group = kWcmpGroup1; - VerifyRouteEntriesEq(expect_entry, ret); -} - -TEST_F(RouteManagerTest, DeserializeRouteEntryWithNexthopIdActionTest) { - std::string key = - R"({"match/vrf_id":"b4-traffic","match/ipv4_dst":"10.11.12.0/24"})"; - std::vector attributes; - attributes.push_back( - swss::FieldValueTuple{p4orch::kAction, p4orch::kSetNexthopId}); - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kNexthopId), kNexthopId1}); - auto route_entry_or = - DeserializeRouteEntry(key, attributes, APP_P4RT_IPV4_TABLE_NAME); - EXPECT_TRUE(route_entry_or.ok()); - auto& route_entry = *route_entry_or; - auto expect_entry = - GenerateP4RouteEntry("b4-traffic", swss::IpPrefix("10.11.12.0/24"), - p4orch::kSetNexthopId, kNexthopId1); - VerifyRouteEntriesEq(expect_entry, route_entry); -} - -TEST_F(RouteManagerTest, DeserializeRouteEntryWithWcmpGroupActionTest) { - std::string key = - R"({"match/vrf_id":"b4-traffic","match/ipv4_dst":"10.11.12.0/24"})"; - std::vector attributes; - attributes.push_back( - swss::FieldValueTuple{p4orch::kAction, p4orch::kSetWcmpGroupId}); - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kWcmpGroupId), kWcmpGroup1}); - auto route_entry_or = - DeserializeRouteEntry(key, attributes, APP_P4RT_IPV4_TABLE_NAME); - EXPECT_TRUE(route_entry_or.ok()); - auto& route_entry = *route_entry_or; - auto expect_entry = - GenerateP4RouteEntry("b4-traffic", swss::IpPrefix("10.11.12.0/24"), - p4orch::kSetWcmpGroupId, kWcmpGroup1); - VerifyRouteEntriesEq(expect_entry, route_entry); -} - -TEST_F(RouteManagerTest, - DeserializeRouteEntryWithNexthopIdAdnMetadataActionTest) { - std::string key = - R"({"match/vrf_id":"b4-traffic","match/ipv4_dst":"10.11.12.0/24"})"; - std::vector attributes; - attributes.push_back( - swss::FieldValueTuple{p4orch::kAction, p4orch::kSetNexthopIdAndMetadata}); - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kNexthopId), kNexthopId1}); - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kRouteMetadata), kMetadata1}); - auto route_entry_or = - DeserializeRouteEntry(key, attributes, APP_P4RT_IPV4_TABLE_NAME); - EXPECT_TRUE(route_entry_or.ok()); - auto& route_entry = *route_entry_or; - auto expect_entry = GenerateP4RouteEntry( - "b4-traffic", swss::IpPrefix("10.11.12.0/24"), - p4orch::kSetNexthopIdAndMetadata, kNexthopId1, kMetadata1); - VerifyRouteEntriesEq(expect_entry, route_entry); -} - -TEST_F(RouteManagerTest, - DeserializeRouteEntryWithWcmpGroupAndMetadataActionTest) { - std::string key = - R"({"match/vrf_id":"b4-traffic","match/ipv4_dst":"10.11.12.0/24"})"; - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{ - p4orch::kAction, p4orch::kSetWcmpGroupIdAndMetadata}); - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kWcmpGroupId), kWcmpGroup1}); - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kRouteMetadata), kMetadata1}); - auto route_entry_or = - DeserializeRouteEntry(key, attributes, APP_P4RT_IPV4_TABLE_NAME); - EXPECT_TRUE(route_entry_or.ok()); - auto& route_entry = *route_entry_or; - auto expect_entry = GenerateP4RouteEntry( - "b4-traffic", swss::IpPrefix("10.11.12.0/24"), - p4orch::kSetWcmpGroupIdAndMetadata, kWcmpGroup1, kMetadata1); - VerifyRouteEntriesEq(expect_entry, route_entry); -} - -TEST_F(RouteManagerTest, DeserializeRouteEntryWithDropActionTest) { - std::string key = - R"({"match/vrf_id":"b4-traffic","match/ipv6_dst":"2001:db8:1::/32"})"; - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kDrop}); - auto route_entry_or = - DeserializeRouteEntry(key, attributes, APP_P4RT_IPV6_TABLE_NAME); - EXPECT_TRUE(route_entry_or.ok()); - auto& route_entry = *route_entry_or; - auto expect_entry = GenerateP4RouteEntry( - "b4-traffic", swss::IpPrefix("2001:db8:1::/32"), p4orch::kDrop, ""); - VerifyRouteEntriesEq(expect_entry, route_entry); -} - -TEST_F(RouteManagerTest, DeserializeRouteEntryWithTrapActionTest) { - std::string key = - R"({"match/vrf_id":"b4-traffic","match/ipv6_dst":"2001:db8:1::/32"})"; - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kTrap}); - auto route_entry_or = - DeserializeRouteEntry(key, attributes, APP_P4RT_IPV6_TABLE_NAME); - EXPECT_TRUE(route_entry_or.ok()); - auto& route_entry = *route_entry_or; - auto expect_entry = GenerateP4RouteEntry( - "b4-traffic", swss::IpPrefix("2001:db8:1::/32"), p4orch::kTrap, ""); - VerifyRouteEntriesEq(expect_entry, route_entry); -} - -TEST_F(RouteManagerTest, DeserializeRouteEntryWithInvalidKeyShouldFail) { - std::string key = "{{{{{{{{{{{{"; - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kDrop}); - auto route_entry_or = - DeserializeRouteEntry(key, attributes, APP_P4RT_IPV6_TABLE_NAME); - EXPECT_FALSE(route_entry_or.ok()); -} - -TEST_F(RouteManagerTest, DeserializeRouteEntryWithInvalidFieldShouldFail) { - std::string key = - R"({"match/vrf_id":"b4-traffic","match/ipv6_dst":"2001:db8:1::/32"})"; - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{"invalid", "invalid"}); - auto route_entry_or = - DeserializeRouteEntry(key, attributes, APP_P4RT_IPV6_TABLE_NAME); - EXPECT_FALSE(route_entry_or.ok()); -} - -TEST_F(RouteManagerTest, DeserializeRouteEntryWithInvalidRouteShouldFail) { - std::string key = - R"({"match/vrf_id":"b4-traffic","match/ipv6_dst":"invalid"})"; - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kDrop}); - auto route_entry_or = - DeserializeRouteEntry(key, attributes, APP_P4RT_IPV6_TABLE_NAME); - EXPECT_FALSE(route_entry_or.ok()); -} - -TEST_F(RouteManagerTest, - DeserializeRouteEntryWithoutIpv4WildcardLpmMatchShouldSucceed) { - std::string key = R"({"match/vrf_id":"b4-traffic"})"; - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kDrop}); - auto route_entry_or = - DeserializeRouteEntry(key, attributes, APP_P4RT_IPV4_TABLE_NAME); - EXPECT_TRUE(route_entry_or.ok()); - auto& route_entry = *route_entry_or; - auto expect_entry = GenerateP4RouteEntry( - "b4-traffic", swss::IpPrefix("0.0.0.0/0"), p4orch::kDrop, ""); - VerifyRouteEntriesEq(expect_entry, route_entry); -} - -TEST_F(RouteManagerTest, - DeserializeRouteEntryWithoutIpv6WildcardLpmMatchShouldSucceed) { - std::string key = R"({"match/vrf_id":"b4-traffic"})"; - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kDrop}); - auto route_entry_or = - DeserializeRouteEntry(key, attributes, APP_P4RT_IPV6_TABLE_NAME); - EXPECT_TRUE(route_entry_or.ok()); - auto& route_entry = *route_entry_or; - auto expect_entry = GenerateP4RouteEntry("b4-traffic", swss::IpPrefix("::/0"), - p4orch::kDrop, ""); - VerifyRouteEntriesEq(expect_entry, route_entry); -} - -TEST_F(RouteManagerTest, - ValidateRouteEntryNexthopActionWithInvalidNexthopShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, - ValidateRouteEntryNexthopActionWithValidNexthopShouldSucceed) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid1); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, - ValidateRouteEntryWcmpGroupActionWithInvalidWcmpGroupShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup1); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, - ValidateRouteEntryWcmpGroupActionWithValidWcmpGroupShouldSucceed) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - kWcmpGroupOid1); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, ValidateRouteEntryWithInvalidCommandShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, "invalid")); -} - -TEST_F(RouteManagerTest, ValidateSetRouteEntryDoesNotExistInManagerShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - route_entry.action = ""; - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid1); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, - ValidateSetRouteEntryExistsInMapperDoesNotExistInManagerShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid1); - p4_oid_mapper_.setDummyOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, - route_entry.route_entry_key); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, - ValidateSetRouteEntryExistsInManagerDoesNotExistInMapperShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, - route_entry.route_entry_key); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, - ValidateSetRouteEntryNexthopIdActionWithoutNexthopIdShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, ""); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, - ValidateSetRouteEntryNexthopIdActionWithWcmpGroupShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - route_entry.wcmp_group = kWcmpGroup1; - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - kWcmpGroupOid1); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, - ValidateSetRouteEntryWcmpGroupActionWithoutWcmpGroupShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, ""); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, - ValidateSetRouteEntryWcmpGroupActionWithNexthopIdShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup1); - route_entry.nexthop_id = kNexthopId1; - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - kWcmpGroupOid1); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, - ValidateSetRouteEntryDropActionWithNexthopIdShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); - route_entry.nexthop_id = kNexthopId1; - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid1); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, - ValidateSetRouteEntryWcmpGroupActionWithNonemptyMetadataShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup1, kMetadata1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - kWcmpGroupOid1); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F( - RouteManagerTest, - ValidateSetRouteEntryNexthopIdAndMetadataActionWithEmptyMetadataShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopIdAndMetadata, kNexthopId1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid1); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F( - RouteManagerTest, - ValidateSetRouteEntryNexthopIdAndMetadataActionWithInvalidMetadataShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopIdAndMetadata, - kNexthopId1, "invalid_int"); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid1); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, - ValidateSetRouteEntryDropActionWithWcmpGroupShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); - route_entry.wcmp_group = kWcmpGroup1; - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - kWcmpGroupOid1); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, - ValidateSetRouteEntryTrapActionWithNexthopIdShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kTrap, ""); - route_entry.nexthop_id = kNexthopId1; - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid1); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, - ValidateSetRouteEntryTrapActionWithWcmpGroupShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kTrap, ""); - route_entry.wcmp_group = kWcmpGroup1; - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - kWcmpGroupOid1); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, ValidateSetRouteEntryInvalidActionShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); - route_entry.action = "invalid"; - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, ValidateSetRouteEntrySucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId2); - route_entry.action = ""; - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid2); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ValidateRouteEntry(route_entry, SET_COMMAND)); -} - -TEST_F(RouteManagerTest, ValidateDelRouteEntryDoesNotExistInManagerShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, "", ""); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ValidateRouteEntry(route_entry, DEL_COMMAND)); -} - -TEST_F(RouteManagerTest, ValidateDelRouteEntryDoesNotExistInMapperShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, "", ""); - p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, - route_entry.route_entry_key); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, - ValidateRouteEntry(route_entry, DEL_COMMAND)); -} - -TEST_F(RouteManagerTest, ValidateDelRouteEntryHasActionShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, ""); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, DEL_COMMAND)); -} - -TEST_F(RouteManagerTest, ValidateDelRouteEntryHasNexthopIdShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - route_entry.action = ""; - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid1); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, DEL_COMMAND)); -} - -TEST_F(RouteManagerTest, ValidateDelRouteEntryHasWcmpGroupShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup1); - route_entry.action = ""; - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - kWcmpGroupOid1); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, DEL_COMMAND)); -} - -TEST_F(RouteManagerTest, ValidateDelRouteEntryHasMetadataShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, "", - "", kMetadata1); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ValidateRouteEntry(route_entry, DEL_COMMAND)); -} - -TEST_F(RouteManagerTest, ValidateDelRouteEntrySucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, "", ""); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ValidateRouteEntry(route_entry, DEL_COMMAND)); -} - -TEST_F(RouteManagerTest, CreateRouteEntryWithSaiErrorShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); - - std::vector exp_status{SAI_STATUS_FAILURE}; - EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) - .Times(3) - .WillRepeatedly( - DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_FAILURE))); - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); - - route_entry.action = p4orch::kSetNexthopId; - route_entry.nexthop_id = kNexthopId1; - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid1); - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); - - route_entry.action = p4orch::kSetWcmpGroupId; - route_entry.wcmp_group = kWcmpGroup1; - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - kWcmpGroupOid1); - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); -} - -TEST_F(RouteManagerTest, CreateNexthopIdIpv4RouteSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid1); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kNexthopOid1; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - create_route_entries( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - ArrayEq(std::vector{1}), - AttrArrayArrayEq(std::vector>{ - {exp_sai_attr}}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, CreateNexthopIdIpv6RouteSucceeds) { - auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); - sai_ip_prefix_t sai_ipv6_route_prefix; - copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid1); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv6_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kNexthopOid1; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - create_route_entries( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - ArrayEq(std::vector{1}), - AttrArrayArrayEq(std::vector>{ - {exp_sai_attr}}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv6_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, CreateNexthopIdWithMetadataIpv4RouteSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopIdAndMetadata, - kNexthopId1, kMetadata1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid1); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - std::vector exp_sai_attrs; - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kNexthopOid1; - exp_sai_attrs.push_back(exp_sai_attr); - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; - exp_sai_attr.value.u32 = kMetadataInt1; - exp_sai_attrs.push_back(exp_sai_attr); - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - create_route_entries( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - ArrayEq(std::vector{ - static_cast(exp_sai_attrs.size())}), - AttrArrayArrayEq( - std::vector>{exp_sai_attrs}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, CreateDropSetMetadataRouteSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetMetadataAndDrop, "", kMetadata1); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - std::vector exp_sai_attrs; - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - exp_sai_attr.value.s32 = SAI_PACKET_ACTION_DROP; - exp_sai_attrs.push_back(exp_sai_attr); - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; - exp_sai_attr.value.u32 = kMetadataInt1; - exp_sai_attrs.push_back(exp_sai_attr); - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - create_route_entries( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - ArrayEq(std::vector{ - static_cast(exp_sai_attrs.size())}), - AttrArrayArrayEq( - std::vector>{exp_sai_attrs}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); -} - -TEST_F(RouteManagerTest, CreateDropIpv4RouteSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - exp_sai_attr.value.s32 = SAI_PACKET_ACTION_DROP; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - create_route_entries( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - ArrayEq(std::vector{1}), - AttrArrayArrayEq(std::vector>{ - {exp_sai_attr}}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); -} - -TEST_F(RouteManagerTest, CreateDropIpv6RouteSucceeds) { - auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); - sai_ip_prefix_t sai_ipv6_route_prefix; - copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kDrop, ""); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv6_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - exp_sai_attr.value.s32 = SAI_PACKET_ACTION_DROP; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - create_route_entries( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - ArrayEq(std::vector{1}), - AttrArrayArrayEq(std::vector>{ - {exp_sai_attr}}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv6_route_prefix, gVrfOid); -} - -TEST_F(RouteManagerTest, CreateTrapIpv4RouteSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kTrap, ""); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - exp_sai_attr.value.s32 = SAI_PACKET_ACTION_TRAP; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - create_route_entries( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - ArrayEq(std::vector{1}), - AttrArrayArrayEq(std::vector>{ - {exp_sai_attr}}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); -} - -TEST_F(RouteManagerTest, CreateTrapIpv6RouteSucceeds) { - auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); - sai_ip_prefix_t sai_ipv6_route_prefix; - copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kTrap, ""); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv6_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - exp_sai_attr.value.s32 = SAI_PACKET_ACTION_TRAP; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - create_route_entries( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - ArrayEq(std::vector{1}), - AttrArrayArrayEq(std::vector>{ - {exp_sai_attr}}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv6_route_prefix, gVrfOid); -} - -TEST_F(RouteManagerTest, CreateWcmpIpv4RouteSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - kWcmpGroupOid1); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kWcmpGroupOid1; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - create_route_entries( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - ArrayEq(std::vector{1}), - AttrArrayArrayEq(std::vector>{ - {exp_sai_attr}}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, CreateWcmpIpv6RouteSucceeds) { - auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); - sai_ip_prefix_t sai_ipv6_route_prefix; - copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - kWcmpGroupOid1); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv6_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kWcmpGroupOid1; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - create_route_entries( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - ArrayEq(std::vector{1}), - AttrArrayArrayEq(std::vector>{ - {exp_sai_attr}}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv6_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, CreateWcmpWithMetadataIpv6RouteSucceeds) { - auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); - sai_ip_prefix_t sai_ipv6_route_prefix; - copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, - p4orch::kSetWcmpGroupIdAndMetadata, - kWcmpGroup1, kMetadata1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - kWcmpGroupOid1); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv6_route_prefix; - - std::vector exp_sai_attrs; - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kWcmpGroupOid1; - exp_sai_attrs.push_back(exp_sai_attr); - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; - exp_sai_attr.value.u32 = kMetadataInt1; - exp_sai_attrs.push_back(exp_sai_attr); - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - create_route_entries( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - ArrayEq(std::vector{ - static_cast(exp_sai_attrs.size())}), - AttrArrayArrayEq( - std::vector>{exp_sai_attrs}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv6_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, UpdateRouteEntryWcmpWithSaiErrorShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupWcmpGroupRouteEntry(gVrfName, swss_ipv4_route_prefix, kWcmpGroup1, - kWcmpGroupOid1); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup2); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - kWcmpGroupOid2); - std::vector exp_status{SAI_STATUS_FAILURE}; - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_FAILURE))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); -} - -TEST_F(RouteManagerTest, - UpdateRouteEntryWcmpNotExistInMapperShouldRaiseCriticalState) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupWcmpGroupRouteEntry(gVrfName, swss_ipv4_route_prefix, kWcmpGroup1, - kWcmpGroupOid1); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup2); - std::vector exp_status{SAI_STATUS_FAILURE}; - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_FAILURE))); - // TODO: Expect critical state. - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); -} - -TEST_F(RouteManagerTest, UpdateRouteFromSetWcmpToSetNextHopSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupWcmpGroupRouteEntry(gVrfName, swss_ipv4_route_prefix, kWcmpGroup1, - kWcmpGroupOid1); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId2); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid2); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kNexthopOid2; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), - &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, - UpdateRouteFromSetWcmpToSetNextHopAndMetadataSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupWcmpGroupRouteEntry(gVrfName, swss_ipv4_route_prefix, kWcmpGroup1, - kWcmpGroupOid1); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopIdAndMetadata, - kNexthopId2, kMetadata2); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid2); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; - exp_sai_attr.value.u32 = kMetadataInt2; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kNexthopOid2; - - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), - &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, UpdateRouteFromSetNexthopIdToSetWcmpSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup2); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - kWcmpGroupOid2); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kWcmpGroupOid2; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - route_entry.action = p4orch::kSetWcmpGroupId; - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup2), &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, - UpdateRouteFromSetNexthopIdAndMetadataToSetWcmpSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1, kMetadata2); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup2); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - kWcmpGroupOid2); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; - exp_sai_attr.value.u32 = 0; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kWcmpGroupOid2; - - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup2), &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, UpdateRouteEntryNexthopIdWithSaiErrorShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId2); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid2); - std::vector exp_failure_status{SAI_STATUS_FAILURE}; - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); -} - -TEST_F(RouteManagerTest, - UpdateRouteEntryNexthopIdNotExistInMapperShouldRaiseCriticalState) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId2); - std::vector exp_failure_status{SAI_STATUS_FAILURE}; - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))); - // TODO: Expect critical state. - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); -} - -TEST_F(RouteManagerTest, UpdateRouteEntryDropWithSaiErrorShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); - std::vector exp_failure_status{SAI_STATUS_FAILURE}; - std::vector exp_success_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))); - // TODO: Expect critical state. - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); -} - -TEST_F(RouteManagerTest, UpdateRouteEntryTrapWithSaiErrorShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kTrap, ""); - std::vector exp_failure_status{SAI_STATUS_FAILURE}; - std::vector exp_success_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))); - // TODO: Expect critical state. - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); -} - -TEST_F(RouteManagerTest, UpdateRouteWithDifferentNexthopIdsSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId2); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid2); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kNexthopOid2; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - route_entry.action = p4orch::kSetNexthopId; - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), - &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, - UpdateRouteWithDifferentNexthopIdsAndMetadatasSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1, kMetadata1); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopIdAndMetadata, - kNexthopId2, kMetadata2); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid2); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; - exp_sai_attr.value.u32 = kMetadataInt2; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kNexthopOid2; - - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), - &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, UpdateRouteFromNexthopIdToDropSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - exp_sai_attr.value.s32 = SAI_PACKET_ACTION_DROP; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = SAI_NULL_OBJECT_ID; - - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); -} - -TEST_F(RouteManagerTest, UpdateRouteFromNexthopIdToRouteMetadataSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetMetadataAndDrop, "", kMetadata1); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; - exp_sai_attr.value.s32 = kMetadataInt1; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = SAI_NULL_OBJECT_ID; - - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - exp_sai_attr.value.s32 = SAI_PACKET_ACTION_DROP; - - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); -} - -TEST_F(RouteManagerTest, UpdateRouteFromNexthopIdAndMetadataToDropSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1, kMetadata2); - - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - exp_sai_attr.value.s32 = SAI_PACKET_ACTION_DROP; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = SAI_NULL_OBJECT_ID; - - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; - exp_sai_attr.value.u32 = 0; - - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); -} - -TEST_F(RouteManagerTest, UpdateRouteFromDropToNexthopIdSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupDropRouteEntry(gVrfName, swss_ipv4_route_prefix); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId2); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid2); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kNexthopOid2; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - exp_sai_attr.value.s32 = SAI_PACKET_ACTION_FORWARD; - - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), - &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, UpdateRouteFromDropToWcmpWithMetadataSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupDropRouteEntry(gVrfName, swss_ipv4_route_prefix); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupIdAndMetadata, - kWcmpGroup1, kMetadata2); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - kWcmpGroupOid1); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; - exp_sai_attr.value.u32 = kMetadataInt2; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kWcmpGroupOid1; - - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - exp_sai_attr.value.s32 = SAI_PACKET_ACTION_FORWARD; - - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, UpdateRouteFromTrapToDropAndSetMetadataSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupTrapRouteEntry(gVrfName, swss_ipv4_route_prefix); - - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetMetadataAndDrop, "", kMetadata2); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - exp_sai_attr.value.s32 = SAI_PACKET_ACTION_DROP; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_META_DATA; - exp_sai_attr.value.u32 = kMetadataInt2; - - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); -} - -TEST_F(RouteManagerTest, UpdateRouteFromTrapToDropSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupTrapRouteEntry(gVrfName, swss_ipv4_route_prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - exp_sai_attr.value.s32 = SAI_PACKET_ACTION_DROP; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); -} - -TEST_F(RouteManagerTest, UpdateRouteFromDropToTrapSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupDropRouteEntry(gVrfName, swss_ipv4_route_prefix); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kTrap, ""); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - exp_sai_attr.value.s32 = SAI_PACKET_ACTION_TRAP; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); -} - -TEST_F(RouteManagerTest, UpdateRouteFromNexthopIdToTrapSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kTrap, ""); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - exp_sai_attr.value.s32 = SAI_PACKET_ACTION_TRAP; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = SAI_NULL_OBJECT_ID; - - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); -} - -TEST_F(RouteManagerTest, UpdateRouteFromTrapToNexthopIdSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupTrapRouteEntry(gVrfName, swss_ipv4_route_prefix); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId2); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid2); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kNexthopOid2; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - exp_sai_attr.value.s32 = SAI_PACKET_ACTION_FORWARD; - - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), - &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F( - RouteManagerTest, - UpdateRouteFromTrapToNexthopIdAndMetadataRecoverFailureShouldRaiseCriticalState) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupTrapRouteEntry(gVrfName, swss_ipv4_route_prefix); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopIdAndMetadata, - kNexthopId2, kMetadata1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid2); - std::vector exp_failure_status{SAI_STATUS_FAILURE}; - std::vector exp_success_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); - - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))); - // TODO: Expect critical state. - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); -} - -TEST_F(RouteManagerTest, UpdateRouteWithDifferentWcmpGroupsSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupWcmpGroupRouteEntry(gVrfName, swss_ipv4_route_prefix, kWcmpGroup1, - kWcmpGroupOid1); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetWcmpGroupId, kWcmpGroup2); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry.wcmp_group), - kWcmpGroupOid2); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kWcmpGroupOid2; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - AttrArrayEq(std::vector{exp_sai_attr}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - route_entry.action = p4orch::kSetWcmpGroupId; - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup2), &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, UpdateNexthopIdRouteWithNoChangeSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F( - RouteManagerTest, - UpdateRouteFromNexthopIdAndMetadataToDropRecoverFailureShouldRaiseCriticalState) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1, kMetadata2); - - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, p4orch::kDrop, ""); - - std::vector exp_failure_status{SAI_STATUS_FAILURE}; - std::vector exp_success_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); - - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))); - // TODO: Expect critical state. - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); -} - -TEST_F( - RouteManagerTest, - UpdateRouteFromDifferentNexthopIdAndMetadataRecoverFailureShouldRaiseCriticalState) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1, kMetadata1); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopIdAndMetadata, - kNexthopId2, kMetadata2); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry.nexthop_id), kNexthopOid2); - - std::vector exp_failure_status{SAI_STATUS_FAILURE}; - std::vector exp_success_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); - - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_success_status.begin(), - exp_success_status.end()), - Return(SAI_STATUS_SUCCESS))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))) - .WillOnce(DoAll(SetArrayArgument<4>(exp_failure_status.begin(), - exp_failure_status.end()), - Return(SAI_STATUS_FAILURE))); - // TODO: Expect critical state. - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); -} - -TEST_F(RouteManagerTest, DeleteRouteEntryWithSaiErrorShouldFail) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - - std::vector exp_status{SAI_STATUS_FAILURE}; - EXPECT_CALL(mock_sai_route_, remove_route_entries(_, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_FAILURE))); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, "", ""); - EXPECT_THAT(DeleteRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_UNKNOWN})); -} - -TEST_F(RouteManagerTest, DeleteIpv4RouteSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_route_, - remove_route_entries(Eq(1), - RouteEntryArrayEq(std::vector{ - exp_sai_route_entry}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, "", ""); - EXPECT_THAT(DeleteRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - auto* route_entry_ptr = GetRouteEntry(route_entry.route_entry_key); - EXPECT_EQ(nullptr, route_entry_ptr); - EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, - route_entry.route_entry_key)); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); -} - -TEST_F(RouteManagerTest, DeleteIpv6RouteSucceeds) { - auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); - sai_ip_prefix_t sai_ipv6_route_prefix; - copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); - SetupWcmpGroupRouteEntry(gVrfName, swss_ipv6_route_prefix, kWcmpGroup1, - kWcmpGroupOid1); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVrfOid; - exp_sai_route_entry.destination = sai_ipv6_route_prefix; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_route_, - remove_route_entries(Eq(1), - RouteEntryArrayEq(std::vector{ - exp_sai_route_entry}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, "", ""); - EXPECT_THAT(DeleteRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - auto* route_entry_ptr = GetRouteEntry(route_entry.route_entry_key); - EXPECT_EQ(nullptr, route_entry_ptr); - EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, - route_entry.route_entry_key)); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); - EXPECT_EQ(0, ref_cnt); -} - -TEST_F(RouteManagerTest, RouteCreateAndUpdateInDrainSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(kNexthopId1), - kNexthopOid1); - auto key_op_fvs_1 = GenerateKeyOpFieldsValuesTuple( - gVrfName, swss_ipv4_route_prefix, SET_COMMAND, p4orch::kSetNexthopId, - kNexthopId1); - Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_1); - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(publisher_, - publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_1)), - FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_1)), - Eq(StatusCode::SWSS_RC_SUCCESS), Eq(true))) - .Times(1); - Drain(); - - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(kNexthopId2), - kNexthopOid2); - auto key_op_fvs_2 = GenerateKeyOpFieldsValuesTuple( - gVrfName, swss_ipv4_route_prefix, SET_COMMAND, p4orch::kSetNexthopId, - kNexthopId2); - Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_2); - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(publisher_, - publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_2)), - FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_2)), - Eq(StatusCode::SWSS_RC_SUCCESS), Eq(true))) - .Times(1); - Drain(); - - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId2); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), - &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - auto key_op_fvs_3 = GenerateKeyOpFieldsValuesTuple( - gVrfName, swss_ipv4_route_prefix, SET_COMMAND, - p4orch::kSetMetadataAndDrop, "", kMetadata1); - Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_3); - EXPECT_CALL(mock_sai_route_, set_route_entries_attribute(_, _, _, _, _)) - .WillRepeatedly( - DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(publisher_, - publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_3)), - FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_3)), - Eq(StatusCode::SWSS_RC_SUCCESS), Eq(true))) - .Times(1); - Drain(); - - route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetMetadataAndDrop, "", kMetadata1); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); -} - -TEST_F(RouteManagerTest, RouteCreateAndDeleteInDrainSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(kNexthopId1), - kNexthopOid1); - auto key_op_fvs_1 = GenerateKeyOpFieldsValuesTuple( - gVrfName, swss_ipv4_route_prefix, SET_COMMAND, p4orch::kSetNexthopId, - kNexthopId1); - Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_1); - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(publisher_, - publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_1)), - FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_1)), - Eq(StatusCode::SWSS_RC_SUCCESS), Eq(true))) - .Times(1); - Drain(); - - auto key_op_fvs_2 = GenerateKeyOpFieldsValuesTuple( - gVrfName, swss_ipv4_route_prefix, DEL_COMMAND, "", ""); - Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_2); - EXPECT_CALL(mock_sai_route_, remove_route_entries(_, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(publisher_, - publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_2)), - FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_2)), - Eq(StatusCode::SWSS_RC_SUCCESS), Eq(true))) - .Times(1); - Drain(); - - std::string key = - KeyGenerator::generateRouteKey(gVrfName, swss_ipv4_route_prefix); - auto* route_entry_ptr = GetRouteEntry(key); - EXPECT_EQ(nullptr, route_entry_ptr); - EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, key)); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); -} - -TEST_F(RouteManagerTest, UpdateFailsWhenCreateAndUpdateTheSameRouteInDrain) { - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(kNexthopId1), - kNexthopOid1); - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(kNexthopId2), - kNexthopOid2); - auto key_op_fvs_1 = GenerateKeyOpFieldsValuesTuple( - gVrfName, swss::IpPrefix(kIpv4Prefix), SET_COMMAND, p4orch::kSetNexthopId, - kNexthopId1); - Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_1); - auto key_op_fvs_2 = GenerateKeyOpFieldsValuesTuple( - gVrfName, swss::IpPrefix(kIpv4Prefix), SET_COMMAND, p4orch::kSetNexthopId, - kNexthopId2); - Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_2); - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(publisher_, - publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_1)), - FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_1)), - Eq(StatusCode::SWSS_RC_SUCCESS), Eq(true))) - .Times(1); - EXPECT_CALL(publisher_, - publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_2)), - FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_2)), - Eq(StatusCode::SWSS_RC_INVALID_PARAM), Eq(true))) - .Times(1); - - Drain(); - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId2), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); -} - -TEST_F(RouteManagerTest, DeleteFailsWhenCreateAndDeleteTheSameRouteInDrain) { - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(kNexthopId1), - kNexthopOid1); - auto key_op_fvs_1 = GenerateKeyOpFieldsValuesTuple( - gVrfName, swss::IpPrefix(kIpv4Prefix), SET_COMMAND, p4orch::kSetNexthopId, - kNexthopId1); - Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_1); - auto key_op_fvs_2 = GenerateKeyOpFieldsValuesTuple( - gVrfName, swss::IpPrefix(kIpv4Prefix), DEL_COMMAND, "", ""); - Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs_2); - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(publisher_, - publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_1)), - FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_1)), - Eq(StatusCode::SWSS_RC_SUCCESS), Eq(true))) - .Times(1); - EXPECT_CALL(publisher_, - publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs_2)), - FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs_2)), - Eq(StatusCode::SWSS_RC_INVALID_PARAM), Eq(true))) - .Times(1); - Drain(); - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - VerifyRouteEntry(route_entry, sai_ipv4_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, RouteCreateInDrainSucceedsWhenVrfIsEmpty) { - const std::string kDefaultVrfName = ""; // Default Vrf - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(kNexthopId1), - kNexthopOid1); - auto key_op_fvs = GenerateKeyOpFieldsValuesTuple( - kDefaultVrfName, swss::IpPrefix(kIpv4Prefix), SET_COMMAND, - p4orch::kSetNexthopId, kNexthopId1); - Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs); - - sai_route_entry_t exp_sai_route_entry; - exp_sai_route_entry.switch_id = gSwitchId; - exp_sai_route_entry.vr_id = gVirtualRouterId; - exp_sai_route_entry.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr; - exp_sai_attr.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr.value.oid = kNexthopOid1; - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - create_route_entries( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry}), - ArrayEq(std::vector{1}), - AttrArrayArrayEq(std::vector>{ - {exp_sai_attr}}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(publisher_, - publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs)), - FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs)), - Eq(StatusCode::SWSS_RC_SUCCESS), Eq(true))) - .Times(1); - - Drain(); - std::string key = KeyGenerator::generateRouteKey(kDefaultVrfName, - swss::IpPrefix(kIpv4Prefix)); - auto* route_entry_ptr = GetRouteEntry(key); - EXPECT_NE(nullptr, route_entry_ptr); - EXPECT_TRUE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, key)); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, DeserializeRouteEntryInDrainFails) { - const std::string kKeyPrefix = - std::string(APP_P4RT_IPV4_TABLE_NAME) + kTableKeyDelimiter; - auto key_op_fvs = - swss::KeyOpFieldsValuesTuple(kKeyPrefix + "{{{{{{{{{{{{", SET_COMMAND, - std::vector{}); - Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs); - EXPECT_CALL(publisher_, - publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs)), - FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs)), - Eq(StatusCode::SWSS_RC_INVALID_PARAM), Eq(true))) - .Times(1); - Drain(); -} - -TEST_F(RouteManagerTest, ValidateRouteEntryInDrainFailsWhenVrfDoesNotExist) { - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(kNexthopId1), - kNexthopOid1); - auto key_op_fvs = GenerateKeyOpFieldsValuesTuple( - "Invalid-Vrf", swss::IpPrefix(kIpv4Prefix), SET_COMMAND, - p4orch::kSetNexthopId, kNexthopId1); - Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs); - EXPECT_CALL(publisher_, - publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs)), - FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs)), - Eq(StatusCode::SWSS_RC_NOT_FOUND), Eq(true))) - .Times(1); - Drain(); -} - -TEST_F(RouteManagerTest, - ValidateRouteEntryInDrainFailsWhenNexthopDoesNotExist) { - auto key_op_fvs = GenerateKeyOpFieldsValuesTuple( - gVrfName, swss::IpPrefix(kIpv4Prefix), SET_COMMAND, p4orch::kSetNexthopId, - kNexthopId1); - Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs); - EXPECT_CALL(publisher_, - publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs)), - FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs)), - Eq(StatusCode::SWSS_RC_NOT_FOUND), Eq(true))) - .Times(1); - Drain(); -} - -TEST_F(RouteManagerTest, InvalidateSetRouteEntryInDrainFails) { - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(kNexthopId1), - kNexthopOid1); - // No nexthop ID with kSetNexthopId action. - auto key_op_fvs = - GenerateKeyOpFieldsValuesTuple(gVrfName, swss::IpPrefix(kIpv4Prefix), - SET_COMMAND, p4orch::kSetNexthopId, ""); - Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs); - EXPECT_CALL(publisher_, - publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs)), - FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs)), - Eq(StatusCode::SWSS_RC_INVALID_PARAM), Eq(true))) - .Times(1); - Drain(); -} - -TEST_F(RouteManagerTest, InvalidateDelRouteEntryInDrainFails) { - // Route does not exist. - auto key_op_fvs = GenerateKeyOpFieldsValuesTuple( - gVrfName, swss::IpPrefix(kIpv4Prefix), DEL_COMMAND, p4orch::kSetNexthopId, - kNexthopId1); - Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs); - EXPECT_CALL(publisher_, - publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs)), - FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs)), - Eq(StatusCode::SWSS_RC_NOT_FOUND), Eq(true))) - .Times(1); - Drain(); -} - -TEST_F(RouteManagerTest, InvalidCommandInDrainFails) { - const std::string kKeyPrefix = - std::string(APP_P4RT_IPV4_TABLE_NAME) + kTableKeyDelimiter; - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(kNexthopId1), - kNexthopOid1); - nlohmann::json j; - j[prependMatchField(p4orch::kVrfId)] = gVrfName; - j[prependMatchField(p4orch::kIpv4Dst)] = kIpv4Prefix; - std::vector attributes; - attributes.push_back( - swss::FieldValueTuple{p4orch::kAction, p4orch::kSetNexthopId}); - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kNexthopId), kNexthopId1}); - auto key_op_fvs = swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), - "INVALID_COMMAND", attributes); - Enqueue(APP_P4RT_IPV4_TABLE_NAME, key_op_fvs); - EXPECT_CALL(publisher_, - publish(Eq(APP_P4RT_TABLE_NAME), Eq(kfvKey(key_op_fvs)), - FieldValueTupleArrayEq(kfvFieldsValues(key_op_fvs)), - Eq(StatusCode::SWSS_RC_INVALID_PARAM), Eq(true))) - .Times(1); - Drain(); -} - -TEST_F(RouteManagerTest, BatchedCreateSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - auto route_entry_ipv4 = GenerateP4RouteEntry( - gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry_ipv4.nexthop_id), - kNexthopOid1); - - auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); - sai_ip_prefix_t sai_ipv6_route_prefix; - copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); - auto route_entry_ipv6 = GenerateP4RouteEntry( - gVrfName, swss_ipv6_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry_ipv6.wcmp_group), - kWcmpGroupOid1); - - sai_route_entry_t exp_sai_route_entry_ipv4; - exp_sai_route_entry_ipv4.switch_id = gSwitchId; - exp_sai_route_entry_ipv4.vr_id = gVrfOid; - exp_sai_route_entry_ipv4.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr_ipv4; - exp_sai_attr_ipv4.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr_ipv4.value.oid = kNexthopOid1; - - sai_route_entry_t exp_sai_route_entry_ipv6; - exp_sai_route_entry_ipv6.switch_id = gSwitchId; - exp_sai_route_entry_ipv6.vr_id = gVrfOid; - exp_sai_route_entry_ipv6.destination = sai_ipv6_route_prefix; - - sai_attribute_t exp_sai_attr_ipv6; - exp_sai_attr_ipv6.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr_ipv6.value.oid = kWcmpGroupOid1; - - std::vector exp_status{SAI_STATUS_SUCCESS, SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - create_route_entries( - Eq(2), - RouteEntryArrayEq(std::vector{ - exp_sai_route_entry_ipv6, exp_sai_route_entry_ipv4}), - ArrayEq(std::vector{1, 1}), - AttrArrayArrayEq(std::vector>{ - {exp_sai_attr_ipv6}, {exp_sai_attr_ipv4}}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry_ipv4, - route_entry_ipv6}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS, - StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry_ipv4, sai_ipv4_route_prefix, gVrfOid); - VerifyRouteEntry(route_entry_ipv6, sai_ipv6_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, BatchedCreatePartiallySucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - auto route_entry_ipv4 = GenerateP4RouteEntry( - gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(route_entry_ipv4.nexthop_id), - kNexthopOid1); - - auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); - sai_ip_prefix_t sai_ipv6_route_prefix; - copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); - auto route_entry_ipv6 = GenerateP4RouteEntry( - gVrfName, swss_ipv6_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); - p4_oid_mapper_.setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(route_entry_ipv6.wcmp_group), - kWcmpGroupOid1); - - sai_route_entry_t exp_sai_route_entry_ipv4; - exp_sai_route_entry_ipv4.switch_id = gSwitchId; - exp_sai_route_entry_ipv4.vr_id = gVrfOid; - exp_sai_route_entry_ipv4.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr_ipv4; - exp_sai_attr_ipv4.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr_ipv4.value.oid = kNexthopOid1; - - sai_route_entry_t exp_sai_route_entry_ipv6; - exp_sai_route_entry_ipv6.switch_id = gSwitchId; - exp_sai_route_entry_ipv6.vr_id = gVrfOid; - exp_sai_route_entry_ipv6.destination = sai_ipv6_route_prefix; - - sai_attribute_t exp_sai_attr_ipv6; - exp_sai_attr_ipv6.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr_ipv6.value.oid = kWcmpGroupOid1; - - std::vector exp_status{SAI_STATUS_FAILURE, SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - create_route_entries( - Eq(2), - RouteEntryArrayEq(std::vector{ - exp_sai_route_entry_ipv6, exp_sai_route_entry_ipv4}), - ArrayEq(std::vector{1, 1}), - AttrArrayArrayEq(std::vector>{ - {exp_sai_attr_ipv6}, {exp_sai_attr_ipv4}}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_FAILURE))); - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry_ipv4, - route_entry_ipv6}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS, - StatusCode::SWSS_RC_UNKNOWN})); - VerifyRouteEntry(route_entry_ipv4, sai_ipv4_route_prefix, gVrfOid); - auto* route_entry_ptr_ipv6 = GetRouteEntry(route_entry_ipv6.route_entry_key); - EXPECT_EQ(nullptr, route_entry_ptr_ipv6); - EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, - route_entry_ipv6.route_entry_key)); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); - EXPECT_EQ(0, ref_cnt); -} - -TEST_F(RouteManagerTest, BatchedUpdateSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - auto route_entry_ipv4 = GenerateP4RouteEntry( - gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), - kWcmpGroupOid1); - - auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); - sai_ip_prefix_t sai_ipv6_route_prefix; - copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); - auto route_entry_ipv6 = GenerateP4RouteEntry( - gVrfName, swss_ipv6_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup2); - SetupDropRouteEntry(gVrfName, swss_ipv6_route_prefix); - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup2), - kWcmpGroupOid2); - - sai_route_entry_t exp_sai_route_entry_ipv4; - exp_sai_route_entry_ipv4.switch_id = gSwitchId; - exp_sai_route_entry_ipv4.vr_id = gVrfOid; - exp_sai_route_entry_ipv4.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr_ipv4; - exp_sai_attr_ipv4.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr_ipv4.value.oid = kWcmpGroupOid1; - - sai_route_entry_t exp_sai_route_entry_ipv6; - exp_sai_route_entry_ipv6.switch_id = gSwitchId; - exp_sai_route_entry_ipv6.vr_id = gVrfOid; - exp_sai_route_entry_ipv6.destination = sai_ipv6_route_prefix; - - sai_attribute_t exp_sai_attr_ipv6; - exp_sai_attr_ipv6.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr_ipv6.value.oid = kWcmpGroupOid2; - - std::vector exp_status_1{SAI_STATUS_SUCCESS, - SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(2), - RouteEntryArrayEq(std::vector{ - exp_sai_route_entry_ipv6, exp_sai_route_entry_ipv4}), - AttrArrayEq(std::vector{exp_sai_attr_ipv6, - exp_sai_attr_ipv4}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce( - DoAll(SetArrayArgument<4>(exp_status_1.begin(), exp_status_1.end()), - Return(SAI_STATUS_SUCCESS))); - - sai_attribute_t exp_sai_attr_ipv6_2; - exp_sai_attr_ipv6_2.id = SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION; - exp_sai_attr_ipv6_2.value.s32 = SAI_PACKET_ACTION_FORWARD; - - std::vector exp_status_2{SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_route_, - set_route_entries_attribute( - Eq(1), - RouteEntryArrayEq( - std::vector{exp_sai_route_entry_ipv6}), - AttrArrayEq(std::vector{exp_sai_attr_ipv6_2}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce( - DoAll(SetArrayArgument<4>(exp_status_2.begin(), exp_status_2.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry_ipv4, - route_entry_ipv6}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS, - StatusCode::SWSS_RC_SUCCESS})); - VerifyRouteEntry(route_entry_ipv4, sai_ipv4_route_prefix, gVrfOid); - VerifyRouteEntry(route_entry_ipv6, sai_ipv6_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup2), &ref_cnt)); - EXPECT_EQ(1, ref_cnt); -} - -TEST_F(RouteManagerTest, BatchedUpdatePartiallySucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - auto route_entry_ipv4 = GenerateP4RouteEntry( - gVrfName, swss_ipv4_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup1); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), - kWcmpGroupOid1); - - auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); - sai_ip_prefix_t sai_ipv6_route_prefix; - copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); - auto route_entry_ipv6 = GenerateP4RouteEntry( - gVrfName, swss_ipv6_route_prefix, p4orch::kSetWcmpGroupId, kWcmpGroup2); - SetupDropRouteEntry(gVrfName, swss_ipv6_route_prefix); - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup2), - kWcmpGroupOid2); - - sai_route_entry_t exp_sai_route_entry_ipv4; - exp_sai_route_entry_ipv4.switch_id = gSwitchId; - exp_sai_route_entry_ipv4.vr_id = gVrfOid; - exp_sai_route_entry_ipv4.destination = sai_ipv4_route_prefix; - - sai_attribute_t exp_sai_attr_ipv4; - exp_sai_attr_ipv4.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr_ipv4.value.oid = kWcmpGroupOid1; - - sai_route_entry_t exp_sai_route_entry_ipv6; - exp_sai_route_entry_ipv6.switch_id = gSwitchId; - exp_sai_route_entry_ipv6.vr_id = gVrfOid; - exp_sai_route_entry_ipv6.destination = sai_ipv6_route_prefix; - - sai_attribute_t exp_sai_attr_ipv6; - exp_sai_attr_ipv6.id = SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID; - exp_sai_attr_ipv6.value.oid = kWcmpGroupOid2; - - std::vector exp_status_1{SAI_STATUS_FAILURE, - SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - set_route_entries_attribute( - Eq(2), - RouteEntryArrayEq(std::vector{ - exp_sai_route_entry_ipv6, exp_sai_route_entry_ipv4}), - AttrArrayEq(std::vector{exp_sai_attr_ipv6, - exp_sai_attr_ipv4}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce( - DoAll(SetArrayArgument<4>(exp_status_1.begin(), exp_status_1.end()), - Return(SAI_STATUS_FAILURE))); - EXPECT_THAT(UpdateRouteEntries(std::vector{route_entry_ipv4, - route_entry_ipv6}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS, - StatusCode::SWSS_RC_UNKNOWN})); - VerifyRouteEntry(route_entry_ipv4, sai_ipv4_route_prefix, gVrfOid); - route_entry_ipv6 = - GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kDrop, ""); - VerifyRouteEntry(route_entry_ipv6, sai_ipv6_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup1), &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroup2), &ref_cnt)); - EXPECT_EQ(0, ref_cnt); -} - -TEST_F(RouteManagerTest, BatchedDeleteSucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - auto route_entry_ipv4 = GenerateP4RouteEntry( - gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - - auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); - sai_ip_prefix_t sai_ipv6_route_prefix; - copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); - auto route_entry_ipv6 = - GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kDrop, ""); - SetupDropRouteEntry(gVrfName, swss_ipv6_route_prefix); - - sai_route_entry_t exp_sai_route_entry_ipv4; - exp_sai_route_entry_ipv4.switch_id = gSwitchId; - exp_sai_route_entry_ipv4.vr_id = gVrfOid; - exp_sai_route_entry_ipv4.destination = sai_ipv4_route_prefix; - - sai_route_entry_t exp_sai_route_entry_ipv6; - exp_sai_route_entry_ipv6.switch_id = gSwitchId; - exp_sai_route_entry_ipv6.vr_id = gVrfOid; - exp_sai_route_entry_ipv6.destination = sai_ipv6_route_prefix; - - std::vector exp_status{SAI_STATUS_SUCCESS, SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - remove_route_entries( - Eq(2), - RouteEntryArrayEq(std::vector{ - exp_sai_route_entry_ipv6, exp_sai_route_entry_ipv4}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(DeleteRouteEntries(std::vector{route_entry_ipv4, - route_entry_ipv6}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS, - StatusCode::SWSS_RC_SUCCESS})); - auto* route_entry_ptr_ipv4 = GetRouteEntry(route_entry_ipv4.route_entry_key); - EXPECT_EQ(nullptr, route_entry_ptr_ipv4); - EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, - route_entry_ipv4.route_entry_key)); - auto* route_entry_ptr_ipv6 = GetRouteEntry(route_entry_ipv6.route_entry_key); - EXPECT_EQ(nullptr, route_entry_ptr_ipv6); - EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, - route_entry_ipv6.route_entry_key)); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); -} - -TEST_F(RouteManagerTest, BatchedDeletePartiallySucceeds) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - sai_ip_prefix_t sai_ipv4_route_prefix; - copy(sai_ipv4_route_prefix, swss_ipv4_route_prefix); - auto route_entry_ipv4 = GenerateP4RouteEntry( - gVrfName, swss_ipv4_route_prefix, p4orch::kSetNexthopId, kNexthopId1); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - - auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); - sai_ip_prefix_t sai_ipv6_route_prefix; - copy(sai_ipv6_route_prefix, swss_ipv6_route_prefix); - auto route_entry_ipv6 = - GenerateP4RouteEntry(gVrfName, swss_ipv6_route_prefix, p4orch::kDrop, ""); - SetupDropRouteEntry(gVrfName, swss_ipv6_route_prefix); - - sai_route_entry_t exp_sai_route_entry_ipv4; - exp_sai_route_entry_ipv4.switch_id = gSwitchId; - exp_sai_route_entry_ipv4.vr_id = gVrfOid; - exp_sai_route_entry_ipv4.destination = sai_ipv4_route_prefix; - - sai_route_entry_t exp_sai_route_entry_ipv6; - exp_sai_route_entry_ipv6.switch_id = gSwitchId; - exp_sai_route_entry_ipv6.vr_id = gVrfOid; - exp_sai_route_entry_ipv6.destination = sai_ipv6_route_prefix; - - std::vector exp_status{SAI_STATUS_FAILURE, SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, - remove_route_entries( - Eq(2), - RouteEntryArrayEq(std::vector{ - exp_sai_route_entry_ipv6, exp_sai_route_entry_ipv4}), - Eq(SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_FAILURE))); - EXPECT_THAT(DeleteRouteEntries(std::vector{route_entry_ipv4, - route_entry_ipv6}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS, - StatusCode::SWSS_RC_UNKNOWN})); - auto* route_entry_ptr_ipv4 = GetRouteEntry(route_entry_ipv4.route_entry_key); - EXPECT_EQ(nullptr, route_entry_ptr_ipv4); - EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTE_ENTRY, - route_entry_ipv4.route_entry_key)); - VerifyRouteEntry(route_entry_ipv6, sai_ipv6_route_prefix, gVrfOid); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_.getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(kNexthopId1), - &ref_cnt)); - EXPECT_EQ(0, ref_cnt); -} - -TEST_F(RouteManagerTest, VerifyStateTest) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv4_route_prefix, kNexthopId1, - kNexthopOid1); - auto route_entry = GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix, - p4orch::kSetNexthopId, kNexthopId1); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set( - "SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"10.11.12.0/" - "24\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}", - std::vector{swss::FieldValueTuple{ - "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID", "oid:0x1"}}); - - nlohmann::json j; - j[prependMatchField(p4orch::kVrfId)] = gVrfName; - j[prependMatchField(p4orch::kIpv4Dst)] = kIpv4Prefix; - const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + APP_P4RT_IPV4_TABLE_NAME + - kTableKeyDelimiter + j.dump(); - std::vector attributes; - - // Verification should succeed with vaild key and value. - attributes.push_back( - swss::FieldValueTuple{p4orch::kAction, p4orch::kSetNexthopId}); - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kNexthopId), kNexthopId1}); - EXPECT_EQ(VerifyState(db_key, attributes), ""); - - // TODO: Expect critical state. - - // Invalid key should fail verification. - EXPECT_FALSE(VerifyState("invalid", attributes).empty()); - EXPECT_FALSE(VerifyState("invalid:invalid", attributes).empty()); - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes) - .empty()); - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", - attributes) - .empty()); - EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + - ":FIXED_IPV4_TABLE:invalid", - attributes) - .empty()); - - // Verification should fail if nexthop ID does not exist. - attributes.clear(); - attributes.push_back( - swss::FieldValueTuple{p4orch::kAction, p4orch::kSetNexthopId}); - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kNexthopId), kNexthopId2}); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - attributes.clear(); - attributes.push_back( - swss::FieldValueTuple{p4orch::kAction, p4orch::kSetNexthopId}); - attributes.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kNexthopId), kNexthopId1}); - - // Verification should fail if entry does not exist. - j[prependMatchField(p4orch::kIpv4Dst)] = "1.1.1.0/24"; - EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + APP_P4RT_IPV4_TABLE_NAME + - kTableKeyDelimiter + j.dump(), - attributes) - .empty()); - - auto* route_entry_ptr = GetRouteEntry( - KeyGenerator::generateRouteKey(gVrfName, swss_ipv4_route_prefix)); - EXPECT_NE(route_entry_ptr, nullptr); - - // Verification should fail if route entry key mismatches. - auto saved_route_entry_key = route_entry_ptr->route_entry_key; - route_entry_ptr->route_entry_key = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - route_entry_ptr->route_entry_key = saved_route_entry_key; - - // Verification should fail if VRF ID mismatches. - auto saved_vrf_id = route_entry_ptr->vrf_id; - route_entry_ptr->vrf_id = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - route_entry_ptr->vrf_id = saved_vrf_id; - - // Verification should fail if route prefix mismatches. - auto saved_route_prefix = route_entry_ptr->route_prefix; - route_entry_ptr->route_prefix = swss::IpPrefix(kIpv6Prefix); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - route_entry_ptr->route_prefix = saved_route_prefix; - - // Verification should fail if action mismatches. - auto saved_action = route_entry_ptr->action; - route_entry_ptr->action = p4orch::kSetWcmpGroupId; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - route_entry_ptr->action = saved_action; - - // Verification should fail if nexthop ID mismatches. - auto saved_nexthop_id = route_entry_ptr->nexthop_id; - route_entry_ptr->nexthop_id = kNexthopId2; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - route_entry_ptr->nexthop_id = saved_nexthop_id; - - // Verification should fail if WCMP group mismatches. - auto saved_wcmp_group = route_entry_ptr->wcmp_group; - route_entry_ptr->wcmp_group = kWcmpGroup1; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - route_entry_ptr->wcmp_group = saved_wcmp_group; - - // Verification should fail if WCMP group mismatches. - auto saved_route_metadata = route_entry_ptr->route_metadata; - route_entry_ptr->route_metadata = kMetadata1; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - route_entry_ptr->route_metadata = saved_route_metadata; -} - -TEST_F(RouteManagerTest, VerifyStateAsicDbTest) { - auto swss_ipv4_route_prefix = swss::IpPrefix(kIpv4Prefix); - SetupDropRouteEntry(gVrfName, swss_ipv4_route_prefix); - auto swss_ipv6_route_prefix = swss::IpPrefix(kIpv6Prefix); - SetupNexthopIdRouteEntry(gVrfName, swss_ipv6_route_prefix, kNexthopId1, - kNexthopOid1, kMetadata1); - - auto swss_ipv4_route_prefix2 = swss::IpPrefix(kIpv4Prefix2); - auto route_entry = - GenerateP4RouteEntry(gVrfName, swss_ipv4_route_prefix2, - p4orch::kSetMetadataAndDrop, "", kMetadata2); - - std::vector exp_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_route_, create_route_entries(_, _, _, _, _, _)) - .WillOnce(DoAll(SetArrayArgument<5>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_THAT(CreateRouteEntries(std::vector{route_entry}), - ArrayEq(std::vector{StatusCode::SWSS_RC_SUCCESS})); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set( - "SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"10.11.12.0/" - "24\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}", - std::vector{ - swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION", - "SAI_PACKET_ACTION_DROP"}, - swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID", - "oid:0x0"}}); - table.set( - "SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"2001:db8:1::/" - "32\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}", - std::vector{ - swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID", "oid:0x1"}, - swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_META_DATA", "1"}}); - - table.set( - "SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"10.12.12.0/" - "24\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}", - std::vector{ - swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION", - "SAI_PACKET_ACTION_DROP"}, - swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_META_DATA", "2"}}); - - nlohmann::json j_1; - j_1[prependMatchField(p4orch::kVrfId)] = gVrfName; - j_1[prependMatchField(p4orch::kIpv4Dst)] = kIpv4Prefix; - const std::string db_key_1 = std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + APP_P4RT_IPV4_TABLE_NAME + - kTableKeyDelimiter + j_1.dump(); - std::vector attributes_1; - attributes_1.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kDrop}); - nlohmann::json j_2; - j_2[prependMatchField(p4orch::kVrfId)] = gVrfName; - j_2[prependMatchField(p4orch::kIpv6Dst)] = kIpv6Prefix; - const std::string db_key_2 = std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + APP_P4RT_IPV6_TABLE_NAME + - kTableKeyDelimiter + j_2.dump(); - std::vector attributes_2; - attributes_2.push_back( - swss::FieldValueTuple{p4orch::kAction, p4orch::kSetNexthopIdAndMetadata}); - attributes_2.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kNexthopId), kNexthopId1}); - attributes_2.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kRouteMetadata), kMetadata1}); - - nlohmann::json j_3; - j_3[prependMatchField(p4orch::kVrfId)] = gVrfName; - j_3[prependMatchField(p4orch::kIpv6Dst)] = kIpv4Prefix2; - const std::string db_key_3 = std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + APP_P4RT_IPV6_TABLE_NAME + - kTableKeyDelimiter + j_3.dump(); - std::vector attributes_3; - attributes_3.push_back( - swss::FieldValueTuple{p4orch::kAction, p4orch::kSetMetadataAndDrop}); - attributes_3.push_back(swss::FieldValueTuple{ - prependParamField(p4orch::kRouteMetadata), kMetadata2}); - - // Verification should succeed with correct ASIC DB values. - EXPECT_EQ(VerifyState(db_key_1, attributes_1), ""); - EXPECT_EQ(VerifyState(db_key_2, attributes_2), ""); - EXPECT_EQ(VerifyState(db_key_3, attributes_3), ""); - - // Verification should fail if ASIC DB values mismatch. - table.set( - "SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"10.11.12.0/" - "24\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}", - std::vector{swss::FieldValueTuple{ - "SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION", "SAI_PACKET_ACTION_FORWARD"}}); - table.set( - "SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"2001:db8:1::/" - "32\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}", - std::vector{ - swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_META_DATA", "2"}}); - EXPECT_FALSE(VerifyState(db_key_1, attributes_1).empty()); - EXPECT_FALSE(VerifyState(db_key_2, attributes_2).empty()); - - // Verification should fail if ASIC DB table is missing. - table.del( - "SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"10.11.12.0/" - "24\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}"); - table.del( - "SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"2001:db8:1::/" - "32\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}"); - EXPECT_FALSE(VerifyState(db_key_1, attributes_1).empty()); - EXPECT_FALSE(VerifyState(db_key_2, attributes_2).empty()); - table.set( - "SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"10.11.12.0/" - "24\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}", - std::vector{ - swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION", - "SAI_PACKET_ACTION_DROP"}, - swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID", - "oid:0x0"}}); - table.set( - "SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"2001:db8:1::/" - "32\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}", - std::vector{ - swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID", "oid:0x1"}, - swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_META_DATA", "1"}}); + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set("SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"10.11.12.0/" + "24\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}", + std::vector{ + swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION", "SAI_PACKET_ACTION_DROP"}, + swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID", "oid:0x0"}}); + table.set("SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"2001:db8:1::/" + "32\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}", + std::vector{swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID", "oid:0x1"}, + swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_META_DATA", "1"}}); + + table.set("SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"10.12.12.0/" + "24\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}", + std::vector{ + swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION", "SAI_PACKET_ACTION_DROP"}, + swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_META_DATA", "2"}}); + + nlohmann::json j_1; + j_1[prependMatchField(p4orch::kVrfId)] = gVrfName; + j_1[prependMatchField(p4orch::kIpv4Dst)] = kIpv4Prefix; + const std::string db_key_1 = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_IPV4_TABLE_NAME + + kTableKeyDelimiter + j_1.dump(); + std::vector attributes_1; + attributes_1.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kDrop}); + nlohmann::json j_2; + j_2[prependMatchField(p4orch::kVrfId)] = gVrfName; + j_2[prependMatchField(p4orch::kIpv6Dst)] = kIpv6Prefix; + const std::string db_key_2 = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_IPV6_TABLE_NAME + + kTableKeyDelimiter + j_2.dump(); + std::vector attributes_2; + attributes_2.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kSetNexthopIdAndMetadata}); + attributes_2.push_back(swss::FieldValueTuple{prependParamField(p4orch::kNexthopId), kNexthopId1}); + attributes_2.push_back(swss::FieldValueTuple{prependParamField(p4orch::kRouteMetadata), kMetadata1}); + + nlohmann::json j_3; + j_3[prependMatchField(p4orch::kVrfId)] = gVrfName; + j_3[prependMatchField(p4orch::kIpv6Dst)] = kIpv4Prefix2; + const std::string db_key_3 = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_IPV6_TABLE_NAME + + kTableKeyDelimiter + j_3.dump(); + std::vector attributes_3; + attributes_3.push_back(swss::FieldValueTuple{p4orch::kAction, p4orch::kSetMetadataAndDrop}); + attributes_3.push_back(swss::FieldValueTuple{prependParamField(p4orch::kRouteMetadata), kMetadata2}); + + // Verification should succeed with correct ASIC DB values. + EXPECT_EQ(VerifyState(db_key_1, attributes_1), ""); + EXPECT_EQ(VerifyState(db_key_2, attributes_2), ""); + EXPECT_EQ(VerifyState(db_key_3, attributes_3), ""); + + // Verification should fail if ASIC DB values mismatch. + table.set("SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"10.11.12.0/" + "24\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}", + std::vector{ + swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION", "SAI_PACKET_ACTION_FORWARD"}}); + table.set("SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"2001:db8:1::/" + "32\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}", + std::vector{swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_META_DATA", "2"}}); + EXPECT_FALSE(VerifyState(db_key_1, attributes_1).empty()); + EXPECT_FALSE(VerifyState(db_key_2, attributes_2).empty()); + + // Verification should fail if ASIC DB table is missing. + table.del("SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"10.11.12.0/" + "24\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}"); + table.del("SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"2001:db8:1::/" + "32\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}"); + EXPECT_FALSE(VerifyState(db_key_1, attributes_1).empty()); + EXPECT_FALSE(VerifyState(db_key_2, attributes_2).empty()); + table.set("SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"10.11.12.0/" + "24\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}", + std::vector{ + swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION", "SAI_PACKET_ACTION_DROP"}, + swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID", "oid:0x0"}}); + table.set("SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"2001:db8:1::/" + "32\",\"switch_id\":\"oid:0x0\",\"vr\":\"oid:0x6f\"}", + std::vector{swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID", "oid:0x1"}, + swss::FieldValueTuple{"SAI_ROUTE_ENTRY_ATTR_META_DATA", "1"}}); } diff --git a/orchagent/p4orch/tests/router_interface_manager_test.cpp b/orchagent/p4orch/tests/router_interface_manager_test.cpp index 202d14c89bf..d1c7330cc77 100644 --- a/orchagent/p4orch/tests/router_interface_manager_test.cpp +++ b/orchagent/p4orch/tests/router_interface_manager_test.cpp @@ -24,1081 +24,945 @@ using ::testing::SetArgPointee; using ::testing::StrictMock; using ::testing::Truly; -extern PortsOrch* gPortsOrch; +extern PortsOrch *gPortsOrch; extern sai_object_id_t gSwitchId; extern sai_object_id_t gVirtualRouterId; -extern sai_router_interface_api_t* sai_router_intfs_api; +extern sai_router_interface_api_t *sai_router_intfs_api; -namespace { +namespace +{ -constexpr char* kPortName1 = "Ethernet1"; +constexpr char *kPortName1 = "Ethernet1"; constexpr sai_object_id_t kPortOid1 = 0x112233; constexpr uint32_t kMtu1 = 1500; -constexpr char* kPortName2 = "Ethernet2"; +constexpr char *kPortName2 = "Ethernet2"; constexpr sai_object_id_t kPortOid2 = 0x1fed3; constexpr uint32_t kMtu2 = 4500; -constexpr char* kRouterInterfaceId1 = "intf-3/4"; +constexpr char *kRouterInterfaceId1 = "intf-3/4"; constexpr sai_object_id_t kRouterInterfaceOid1 = 0x295100; const swss::MacAddress kMacAddress1("00:01:02:03:04:05"); -constexpr char* kRouterInterfaceId2 = "Ethernet20"; +constexpr char *kRouterInterfaceId2 = "Ethernet20"; constexpr sai_object_id_t kRouterInterfaceOid2 = 0x51411; const swss::MacAddress kMacAddress2("00:ff:ee:dd:cc:bb"); const swss::MacAddress kZeroMacAddress("00:00:00:00:00:00"); -constexpr char* kRouterIntfAppDbKey = - R"({"match/router_interface_id":"intf-3/4"})"; +constexpr char *kRouterIntfAppDbKey = R"({"match/router_interface_id":"intf-3/4"})"; -std::unordered_map -CreateRouterInterfaceAttributeList(const sai_object_id_t& virtual_router_oid, - const swss::MacAddress mac_address, - const sai_object_id_t& port_oid, - const uint32_t mtu) { - std::unordered_map attr_list; - sai_attribute_value_t attr_value; +std::unordered_map CreateRouterInterfaceAttributeList( + const sai_object_id_t &virtual_router_oid, const swss::MacAddress mac_address, const sai_object_id_t &port_oid, + const uint32_t mtu) +{ + std::unordered_map attr_list; + sai_attribute_value_t attr_value; - attr_value.oid = virtual_router_oid; - attr_list[SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID] = attr_value; + attr_value.oid = virtual_router_oid; + attr_list[SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID] = attr_value; - if (mac_address != kZeroMacAddress) { - memcpy(attr_value.mac, mac_address.getMac(), sizeof(sai_mac_t)); - attr_list[SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS] = attr_value; - } + if (mac_address != kZeroMacAddress) + { + memcpy(attr_value.mac, mac_address.getMac(), sizeof(sai_mac_t)); + attr_list[SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS] = attr_value; + } - attr_value.s32 = SAI_ROUTER_INTERFACE_TYPE_PORT; - attr_list[SAI_ROUTER_INTERFACE_ATTR_TYPE] = attr_value; + attr_value.s32 = SAI_ROUTER_INTERFACE_TYPE_PORT; + attr_list[SAI_ROUTER_INTERFACE_ATTR_TYPE] = attr_value; - attr_value.oid = port_oid; - attr_list[SAI_ROUTER_INTERFACE_ATTR_PORT_ID] = attr_value; + attr_value.oid = port_oid; + attr_list[SAI_ROUTER_INTERFACE_ATTR_PORT_ID] = attr_value; - attr_value.u32 = mtu; - attr_list[SAI_ROUTER_INTERFACE_ATTR_MTU] = attr_value; + attr_value.u32 = mtu; + attr_list[SAI_ROUTER_INTERFACE_ATTR_MTU] = attr_value; - return attr_list; + return attr_list; } bool MatchCreateRouterInterfaceAttributeList( - const sai_attribute_t* attr_list, - const std::unordered_map& - expected_attr_list) { - if (attr_list == nullptr) return false; - - int matched_attr_num = 0; - const int attr_list_length = (int)expected_attr_list.size(); - for (int i = 0; i < attr_list_length; i++) { - switch (attr_list[i].id) { - case SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID: - if (attr_list[i].value.oid != - expected_attr_list.at(SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID) - .oid) { - return false; - } - matched_attr_num++; - break; - - case SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS: - if (memcmp( - attr_list[i].value.mac, - expected_attr_list.at(SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS) - .mac, - sizeof(sai_mac_t))) { - return false; - } - matched_attr_num++; - break; + const sai_attribute_t *attr_list, + const std::unordered_map &expected_attr_list) +{ + if (attr_list == nullptr) + return false; - case SAI_ROUTER_INTERFACE_ATTR_TYPE: - if (attr_list[i].value.s32 != - expected_attr_list.at(SAI_ROUTER_INTERFACE_ATTR_TYPE).s32) { - return false; + int matched_attr_num = 0; + const int attr_list_length = (int)expected_attr_list.size(); + for (int i = 0; i < attr_list_length; i++) + { + switch (attr_list[i].id) + { + case SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID: + if (attr_list[i].value.oid != expected_attr_list.at(SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID).oid) + { + return false; + } + matched_attr_num++; + break; + + case SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS: + if (memcmp(attr_list[i].value.mac, expected_attr_list.at(SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS).mac, + sizeof(sai_mac_t))) + { + return false; + } + matched_attr_num++; + break; + + case SAI_ROUTER_INTERFACE_ATTR_TYPE: + if (attr_list[i].value.s32 != expected_attr_list.at(SAI_ROUTER_INTERFACE_ATTR_TYPE).s32) + { + return false; + } + matched_attr_num++; + break; + + case SAI_ROUTER_INTERFACE_ATTR_PORT_ID: + if (attr_list[i].value.oid != expected_attr_list.at(SAI_ROUTER_INTERFACE_ATTR_PORT_ID).oid) + { + return false; + } + matched_attr_num++; + break; + + case SAI_ROUTER_INTERFACE_ATTR_MTU: + if (attr_list[i].value.u32 != expected_attr_list.at(SAI_ROUTER_INTERFACE_ATTR_MTU).u32) + { + return false; + } + matched_attr_num++; + break; + + default: + // Unexpected attribute present in attribute list + return false; } - matched_attr_num++; - break; + } - case SAI_ROUTER_INTERFACE_ATTR_PORT_ID: - if (attr_list[i].value.oid != - expected_attr_list.at(SAI_ROUTER_INTERFACE_ATTR_PORT_ID).oid) { - return false; - } - matched_attr_num++; - break; + return (matched_attr_num == attr_list_length); +} - case SAI_ROUTER_INTERFACE_ATTR_MTU: - if (attr_list[i].value.u32 != - expected_attr_list.at(SAI_ROUTER_INTERFACE_ATTR_MTU).u32) { - return false; - } - matched_attr_num++; - break; +} // namespace - default: - // Unexpected attribute present in attribute list - return false; +class RouterInterfaceManagerTest : public ::testing::Test +{ + protected: + RouterInterfaceManagerTest() : router_intf_manager_(&p4_oid_mapper_, &publisher_) + { } - } - - return (matched_attr_num == attr_list_length); -} -} // namespace - -class RouterInterfaceManagerTest : public ::testing::Test { - protected: - RouterInterfaceManagerTest() - : router_intf_manager_(&p4_oid_mapper_, &publisher_) {} - - void SetUp() override { - mock_sai_router_intf = &mock_sai_router_intf_; - sai_router_intfs_api->create_router_interface = - mock_create_router_interface; - sai_router_intfs_api->remove_router_interface = - mock_remove_router_interface; - sai_router_intfs_api->set_router_interface_attribute = - mock_set_router_interface_attribute; - sai_router_intfs_api->get_router_interface_attribute = - mock_get_router_interface_attribute; - } - - void Enqueue(const swss::KeyOpFieldsValuesTuple& entry) { - router_intf_manager_.enqueue(APP_P4RT_ROUTER_INTERFACE_TABLE_NAME, entry); - } - - void Drain() { router_intf_manager_.drain(); } - - std::string VerifyState(const std::string& key, - const std::vector& tuple) { - return router_intf_manager_.verifyState(key, tuple); - } - - ReturnCodeOr DeserializeRouterIntfEntry( - const std::string& key, - const std::vector& attributes) { - return router_intf_manager_.deserializeRouterIntfEntry(key, attributes); - } - - ReturnCode CreateRouterInterface(const std::string& router_intf_key, - P4RouterInterfaceEntry& router_intf_entry) { - return router_intf_manager_.createRouterInterface(router_intf_key, - router_intf_entry); - } - - ReturnCode RemoveRouterInterface(const std::string& router_intf_key) { - return router_intf_manager_.removeRouterInterface(router_intf_key); - } - - ReturnCode SetSourceMacAddress(P4RouterInterfaceEntry* router_intf_entry, - const swss::MacAddress& mac_address) { - return router_intf_manager_.setSourceMacAddress(router_intf_entry, - mac_address); - } - - ReturnCode ProcessAddRequest(const P4RouterInterfaceAppDbEntry& app_db_entry, - const std::string& router_intf_key) { - return router_intf_manager_.processAddRequest(app_db_entry, - router_intf_key); - } - - ReturnCode ProcessUpdateRequest( - const P4RouterInterfaceAppDbEntry& app_db_entry, - P4RouterInterfaceEntry* router_intf_entry) { - return router_intf_manager_.processUpdateRequest(app_db_entry, - router_intf_entry); - } - - ReturnCode ProcessDeleteRequest(const std::string& router_intf_key) { - return router_intf_manager_.processDeleteRequest(router_intf_key); - } - - P4RouterInterfaceEntry* GetRouterInterfaceEntry( - const std::string& router_intf_key) { - return router_intf_manager_.getRouterInterfaceEntry(router_intf_key); - } - - void ValidateRouterInterfaceEntry( - const P4RouterInterfaceEntry& expected_entry) { - const std::string router_intf_key = - KeyGenerator::generateRouterInterfaceKey( - expected_entry.router_interface_id); - auto router_intf_entry = GetRouterInterfaceEntry(router_intf_key); - - EXPECT_NE(nullptr, router_intf_entry); - EXPECT_EQ(expected_entry.router_interface_id, - router_intf_entry->router_interface_id); - EXPECT_EQ(expected_entry.port_name, router_intf_entry->port_name); - EXPECT_EQ(expected_entry.src_mac_address, - router_intf_entry->src_mac_address); - EXPECT_EQ(expected_entry.router_interface_oid, - router_intf_entry->router_interface_oid); - - sai_object_id_t p4_mapper_oid; - ASSERT_TRUE(p4_oid_mapper_.getOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - router_intf_key, &p4_mapper_oid)); - EXPECT_EQ(expected_entry.router_interface_oid, p4_mapper_oid); - } - - void ValidateRouterInterfaceEntryNotPresent( - const std::string router_interface_id) { - const std::string router_intf_key = - KeyGenerator::generateRouterInterfaceKey(router_interface_id); - auto current_entry = GetRouterInterfaceEntry(router_intf_key); - EXPECT_EQ(current_entry, nullptr); - EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - router_intf_key)); - } - - void AddRouterInterfaceEntry(P4RouterInterfaceEntry& router_intf_entry, - const sai_object_id_t port_oid, - const uint32_t mtu) { - EXPECT_CALL( - mock_sai_router_intf_, - create_router_interface( - ::testing::NotNull(), Eq(gSwitchId), Eq(5), - Truly(std::bind( - MatchCreateRouterInterfaceAttributeList, std::placeholders::_1, - CreateRouterInterfaceAttributeList( - gVirtualRouterId, router_intf_entry.src_mac_address, - port_oid, mtu))))) - .WillOnce( - DoAll(SetArgPointee<0>(router_intf_entry.router_interface_oid), - Return(SAI_STATUS_SUCCESS))); - - const std::string router_intf_key = - KeyGenerator::generateRouterInterfaceKey( - router_intf_entry.router_interface_id); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - CreateRouterInterface(router_intf_key, router_intf_entry)); - } + void SetUp() override + { + mock_sai_router_intf = &mock_sai_router_intf_; + sai_router_intfs_api->create_router_interface = mock_create_router_interface; + sai_router_intfs_api->remove_router_interface = mock_remove_router_interface; + sai_router_intfs_api->set_router_interface_attribute = mock_set_router_interface_attribute; + sai_router_intfs_api->get_router_interface_attribute = mock_get_router_interface_attribute; + } - StrictMock mock_sai_router_intf_; - MockResponsePublisher publisher_; - P4OidMapper p4_oid_mapper_; - RouterInterfaceManager router_intf_manager_; -}; + void Enqueue(const swss::KeyOpFieldsValuesTuple &entry) + { + router_intf_manager_.enqueue(APP_P4RT_ROUTER_INTERFACE_TABLE_NAME, entry); + } -TEST_F(RouterInterfaceManagerTest, CreateRouterInterfaceValidAttributes) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, - kMacAddress1); - AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); + void Drain() + { + router_intf_manager_.drain(); + } - ValidateRouterInterfaceEntry(router_intf_entry); -} + std::string VerifyState(const std::string &key, const std::vector &tuple) + { + return router_intf_manager_.verifyState(key, tuple); + } -TEST_F(RouterInterfaceManagerTest, CreateRouterInterfaceEntryExistsInManager) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, - kMacAddress1); - router_intf_entry.router_interface_oid = kRouterInterfaceOid1; - AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); - - // Same router interface key with different attributes - P4RouterInterfaceEntry new_entry(router_intf_entry.router_interface_id, - kPortName2, kMacAddress2); - const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey( - router_intf_entry.router_interface_id); - EXPECT_EQ(StatusCode::SWSS_RC_EXISTS, - CreateRouterInterface(router_intf_key, new_entry)); - - // Validate that entry in Manager and Centralized Mapper has not changed - ValidateRouterInterfaceEntry(router_intf_entry); -} + ReturnCodeOr DeserializeRouterIntfEntry( + const std::string &key, const std::vector &attributes) + { + return router_intf_manager_.deserializeRouterIntfEntry(key, attributes); + } -TEST_F(RouterInterfaceManagerTest, - CreateRouterInterfaceEntryExistsInP4OidMapper) { - const std::string router_intf_key = - KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId2); - p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key, - kRouterInterfaceOid2); - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId2, kPortName2, - kMacAddress2); - - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, - CreateRouterInterface(router_intf_key, router_intf_entry)); - - auto current_entry = GetRouterInterfaceEntry(router_intf_key); - EXPECT_EQ(current_entry, nullptr); - - // Validate that OID doesn't change in Centralized Mapper - sai_object_id_t mapper_oid; - ASSERT_TRUE(p4_oid_mapper_.getOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - router_intf_key, &mapper_oid)); - EXPECT_EQ(mapper_oid, kRouterInterfaceOid2); -} + ReturnCode CreateRouterInterface(const std::string &router_intf_key, P4RouterInterfaceEntry &router_intf_entry) + { + return router_intf_manager_.createRouterInterface(router_intf_key, router_intf_entry); + } -TEST_F(RouterInterfaceManagerTest, CreateRouterInterfaceInvalidPort) { - const std::string invalid_port_name = "xyz"; - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId2, - invalid_port_name, kMacAddress2); + ReturnCode RemoveRouterInterface(const std::string &router_intf_key) + { + return router_intf_manager_.removeRouterInterface(router_intf_key); + } - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - CreateRouterInterface( - KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId2), - router_intf_entry)); + ReturnCode SetSourceMacAddress(P4RouterInterfaceEntry *router_intf_entry, const swss::MacAddress &mac_address) + { + return router_intf_manager_.setSourceMacAddress(router_intf_entry, mac_address); + } - ValidateRouterInterfaceEntryNotPresent(kRouterInterfaceId2); -} + ReturnCode ProcessAddRequest(const P4RouterInterfaceAppDbEntry &app_db_entry, const std::string &router_intf_key) + { + return router_intf_manager_.processAddRequest(app_db_entry, router_intf_key); + } -TEST_F(RouterInterfaceManagerTest, CreateRouterInterfaceNoMacAddress) { - P4RouterInterfaceEntry router_intf_entry; - router_intf_entry.router_interface_id = kRouterInterfaceId1; - router_intf_entry.port_name = kPortName1; - - EXPECT_CALL( - mock_sai_router_intf_, - create_router_interface( - ::testing::NotNull(), Eq(gSwitchId), Eq(4), - Truly(std::bind( - MatchCreateRouterInterfaceAttributeList, std::placeholders::_1, - CreateRouterInterfaceAttributeList( - gVirtualRouterId, kZeroMacAddress, kPortOid1, kMtu1))))) - .WillOnce(DoAll(SetArgPointee<0>(kRouterInterfaceOid1), - Return(SAI_STATUS_SUCCESS))); - - const std::string router_intf_key = - KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - CreateRouterInterface(router_intf_key, router_intf_entry)); - - ValidateRouterInterfaceEntry(router_intf_entry); -} + ReturnCode ProcessUpdateRequest(const P4RouterInterfaceAppDbEntry &app_db_entry, + P4RouterInterfaceEntry *router_intf_entry) + { + return router_intf_manager_.processUpdateRequest(app_db_entry, router_intf_entry); + } -TEST_F(RouterInterfaceManagerTest, CreateRouterInterfaceSaiApiFails) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, - kMacAddress1); - EXPECT_CALL(mock_sai_router_intf_, create_router_interface(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_FAILURE)); + ReturnCode ProcessDeleteRequest(const std::string &router_intf_key) + { + return router_intf_manager_.processDeleteRequest(router_intf_key); + } - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - CreateRouterInterface(KeyGenerator::generateRouterInterfaceKey( - router_intf_entry.router_interface_id), - router_intf_entry)); + P4RouterInterfaceEntry *GetRouterInterfaceEntry(const std::string &router_intf_key) + { + return router_intf_manager_.getRouterInterfaceEntry(router_intf_key); + } - ValidateRouterInterfaceEntryNotPresent(router_intf_entry.router_interface_id); -} + void ValidateRouterInterfaceEntry(const P4RouterInterfaceEntry &expected_entry) + { + const std::string router_intf_key = + KeyGenerator::generateRouterInterfaceKey(expected_entry.router_interface_id); + auto router_intf_entry = GetRouterInterfaceEntry(router_intf_key); + + EXPECT_NE(nullptr, router_intf_entry); + EXPECT_EQ(expected_entry.router_interface_id, router_intf_entry->router_interface_id); + EXPECT_EQ(expected_entry.port_name, router_intf_entry->port_name); + EXPECT_EQ(expected_entry.src_mac_address, router_intf_entry->src_mac_address); + EXPECT_EQ(expected_entry.router_interface_oid, router_intf_entry->router_interface_oid); + + sai_object_id_t p4_mapper_oid; + ASSERT_TRUE(p4_oid_mapper_.getOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key, &p4_mapper_oid)); + EXPECT_EQ(expected_entry.router_interface_oid, p4_mapper_oid); + } -TEST_F(RouterInterfaceManagerTest, RemoveRouterInterfaceExistingInterface) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId2, kPortName2, - kMacAddress2); - router_intf_entry.router_interface_oid = kRouterInterfaceOid2; - AddRouterInterfaceEntry(router_intf_entry, kPortOid2, kMtu2); + void ValidateRouterInterfaceEntryNotPresent(const std::string router_interface_id) + { + const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey(router_interface_id); + auto current_entry = GetRouterInterfaceEntry(router_intf_key); + EXPECT_EQ(current_entry, nullptr); + EXPECT_FALSE(p4_oid_mapper_.existsOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key)); + } - EXPECT_CALL( - mock_sai_router_intf_, - remove_router_interface(Eq(router_intf_entry.router_interface_oid))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); + void AddRouterInterfaceEntry(P4RouterInterfaceEntry &router_intf_entry, const sai_object_id_t port_oid, + const uint32_t mtu) + { + EXPECT_CALL(mock_sai_router_intf_, + create_router_interface( + ::testing::NotNull(), Eq(gSwitchId), Eq(5), + Truly(std::bind(MatchCreateRouterInterfaceAttributeList, std::placeholders::_1, + CreateRouterInterfaceAttributeList( + gVirtualRouterId, router_intf_entry.src_mac_address, port_oid, mtu))))) + .WillOnce(DoAll(SetArgPointee<0>(router_intf_entry.router_interface_oid), Return(SAI_STATUS_SUCCESS))); + + const std::string router_intf_key = + KeyGenerator::generateRouterInterfaceKey(router_intf_entry.router_interface_id); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, CreateRouterInterface(router_intf_key, router_intf_entry)); + } - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - RemoveRouterInterface(KeyGenerator::generateRouterInterfaceKey( - router_intf_entry.router_interface_id))); + StrictMock mock_sai_router_intf_; + MockResponsePublisher publisher_; + P4OidMapper p4_oid_mapper_; + RouterInterfaceManager router_intf_manager_; +}; - ValidateRouterInterfaceEntryNotPresent(router_intf_entry.router_interface_id); -} +TEST_F(RouterInterfaceManagerTest, CreateRouterInterfaceValidAttributes) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, kMacAddress1); + AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); -TEST_F(RouterInterfaceManagerTest, RemoveRouterInterfaceNonExistingInterface) { - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - RemoveRouterInterface( - KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId2))); + ValidateRouterInterfaceEntry(router_intf_entry); } -TEST_F(RouterInterfaceManagerTest, RemoveRouterInterfaceNonZeroRefCount) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId2, kPortName2, - kMacAddress2); - router_intf_entry.router_interface_oid = kRouterInterfaceOid2; - AddRouterInterfaceEntry(router_intf_entry, kPortOid2, kMtu2); +TEST_F(RouterInterfaceManagerTest, CreateRouterInterfaceEntryExistsInManager) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, kMacAddress1); + router_intf_entry.router_interface_oid = kRouterInterfaceOid1; + AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); - const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey( - router_intf_entry.router_interface_id); - ASSERT_TRUE(p4_oid_mapper_.increaseRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - router_intf_key)); + // Same router interface key with different attributes + P4RouterInterfaceEntry new_entry(router_intf_entry.router_interface_id, kPortName2, kMacAddress2); + const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey(router_intf_entry.router_interface_id); + EXPECT_EQ(StatusCode::SWSS_RC_EXISTS, CreateRouterInterface(router_intf_key, new_entry)); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - RemoveRouterInterface(router_intf_key)); - - ValidateRouterInterfaceEntry(router_intf_entry); + // Validate that entry in Manager and Centralized Mapper has not changed + ValidateRouterInterfaceEntry(router_intf_entry); } -TEST_F(RouterInterfaceManagerTest, RemoveRouterInterfaceSaiApiFails) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId2, kPortName2, - kMacAddress2); - router_intf_entry.router_interface_oid = kRouterInterfaceOid2; - AddRouterInterfaceEntry(router_intf_entry, kPortOid2, kMtu2); +TEST_F(RouterInterfaceManagerTest, CreateRouterInterfaceEntryExistsInP4OidMapper) +{ + const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId2); + p4_oid_mapper_.setOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key, kRouterInterfaceOid2); + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId2, kPortName2, kMacAddress2); - EXPECT_CALL( - mock_sai_router_intf_, - remove_router_interface(Eq(router_intf_entry.router_interface_oid))) - .WillOnce(Return(SAI_STATUS_FAILURE)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, CreateRouterInterface(router_intf_key, router_intf_entry)); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - RemoveRouterInterface(KeyGenerator::generateRouterInterfaceKey( - router_intf_entry.router_interface_id))); + auto current_entry = GetRouterInterfaceEntry(router_intf_key); + EXPECT_EQ(current_entry, nullptr); - ValidateRouterInterfaceEntry(router_intf_entry); + // Validate that OID doesn't change in Centralized Mapper + sai_object_id_t mapper_oid; + ASSERT_TRUE(p4_oid_mapper_.getOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key, &mapper_oid)); + EXPECT_EQ(mapper_oid, kRouterInterfaceOid2); } -TEST_F(RouterInterfaceManagerTest, SetSourceMacAddressModifyMacAddress) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, - kMacAddress1); - router_intf_entry.router_interface_oid = kRouterInterfaceOid1; - - sai_attribute_value_t attr_value; - memcpy(attr_value.mac, kMacAddress2.getMac(), sizeof(sai_mac_t)); - std::unordered_map attr_list = { - {SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS, attr_value}}; - EXPECT_CALL(mock_sai_router_intf_, - set_router_interface_attribute( - Eq(router_intf_entry.router_interface_oid), - Truly(std::bind(MatchCreateRouterInterfaceAttributeList, - std::placeholders::_1, attr_list)))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - SetSourceMacAddress(&router_intf_entry, kMacAddress2)); - EXPECT_EQ(router_intf_entry.src_mac_address, kMacAddress2); -} +TEST_F(RouterInterfaceManagerTest, CreateRouterInterfaceInvalidPort) +{ + const std::string invalid_port_name = "xyz"; + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId2, invalid_port_name, kMacAddress2); -TEST_F(RouterInterfaceManagerTest, SetSourceMacAddressIdempotent) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, - kMacAddress1); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, + CreateRouterInterface(KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId2), router_intf_entry)); - // SAI API not being called makes the operation idempotent. - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - SetSourceMacAddress(&router_intf_entry, kMacAddress1)); - EXPECT_EQ(router_intf_entry.src_mac_address, kMacAddress1); + ValidateRouterInterfaceEntryNotPresent(kRouterInterfaceId2); } -TEST_F(RouterInterfaceManagerTest, SetSourceMacAddressSaiApiFails) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, - kMacAddress1); - router_intf_entry.router_interface_oid = kRouterInterfaceOid1; - - sai_attribute_value_t attr_value; - memcpy(attr_value.mac, kMacAddress2.getMac(), sizeof(sai_mac_t)); - std::unordered_map attr_list = { - {SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS, attr_value}}; - EXPECT_CALL(mock_sai_router_intf_, - set_router_interface_attribute( - Eq(router_intf_entry.router_interface_oid), - Truly(std::bind(MatchCreateRouterInterfaceAttributeList, - std::placeholders::_1, attr_list)))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - SetSourceMacAddress(&router_intf_entry, kMacAddress2)); - EXPECT_EQ(router_intf_entry.src_mac_address, kMacAddress1); -} +TEST_F(RouterInterfaceManagerTest, CreateRouterInterfaceNoMacAddress) +{ + P4RouterInterfaceEntry router_intf_entry; + router_intf_entry.router_interface_id = kRouterInterfaceId1; + router_intf_entry.port_name = kPortName1; -TEST_F(RouterInterfaceManagerTest, ProcessAddRequestValidAppDbParams) { - const P4RouterInterfaceAppDbEntry app_db_entry = { - .router_interface_id = kRouterInterfaceId1, - .port_name = kPortName1, - .src_mac_address = kMacAddress1, - .is_set_port_name = true, - .is_set_src_mac = true}; - - EXPECT_CALL( - mock_sai_router_intf_, - create_router_interface( - ::testing::NotNull(), Eq(gSwitchId), Eq(5), - Truly(std::bind( - MatchCreateRouterInterfaceAttributeList, std::placeholders::_1, - CreateRouterInterfaceAttributeList(gVirtualRouterId, kMacAddress1, - kPortOid1, kMtu1))))) - .WillOnce(DoAll(SetArgPointee<0>(kRouterInterfaceOid1), - Return(SAI_STATUS_SUCCESS))); - - const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey( - app_db_entry.router_interface_id); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessAddRequest(app_db_entry, router_intf_key)); - - P4RouterInterfaceEntry router_intf_entry(app_db_entry.router_interface_id, - app_db_entry.port_name, - app_db_entry.src_mac_address); - router_intf_entry.router_interface_oid = kRouterInterfaceOid1; - ValidateRouterInterfaceEntry(router_intf_entry); -} + EXPECT_CALL(mock_sai_router_intf_, + create_router_interface(::testing::NotNull(), Eq(gSwitchId), Eq(4), + Truly(std::bind(MatchCreateRouterInterfaceAttributeList, std::placeholders::_1, + CreateRouterInterfaceAttributeList( + gVirtualRouterId, kZeroMacAddress, kPortOid1, kMtu1))))) + .WillOnce(DoAll(SetArgPointee<0>(kRouterInterfaceOid1), Return(SAI_STATUS_SUCCESS))); -TEST_F(RouterInterfaceManagerTest, ProcessAddRequestPortNameMissing) { - const P4RouterInterfaceAppDbEntry app_db_entry = { - .router_interface_id = kRouterInterfaceId1, - .port_name = "", - .src_mac_address = kMacAddress1, - .is_set_port_name = false, - .is_set_src_mac = true}; - - const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey( - app_db_entry.router_interface_id); - EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, - ProcessAddRequest(app_db_entry, router_intf_key)); -} + const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, CreateRouterInterface(router_intf_key, router_intf_entry)); -TEST_F(RouterInterfaceManagerTest, ProcessAddRequestInvalidPortName) { - const P4RouterInterfaceAppDbEntry app_db_entry = { - .router_interface_id = kRouterInterfaceId1, - .port_name = "", - .src_mac_address = kMacAddress1, - .is_set_port_name = true, - .is_set_src_mac = true}; - - const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey( - app_db_entry.router_interface_id); - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessAddRequest(app_db_entry, router_intf_key)); + ValidateRouterInterfaceEntry(router_intf_entry); } -TEST_F(RouterInterfaceManagerTest, ProcessUpdateRequestSetSourceMacAddress) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, - kMacAddress1); - router_intf_entry.router_interface_oid = kRouterInterfaceOid1; - AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); - - sai_attribute_value_t attr_value; - memcpy(attr_value.mac, kMacAddress2.getMac(), sizeof(sai_mac_t)); - std::unordered_map attr_list = { - {SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS, attr_value}}; - EXPECT_CALL(mock_sai_router_intf_, - set_router_interface_attribute( - Eq(router_intf_entry.router_interface_oid), - Truly(std::bind(MatchCreateRouterInterfaceAttributeList, - std::placeholders::_1, attr_list)))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - const P4RouterInterfaceAppDbEntry app_db_entry = { - .router_interface_id = router_intf_entry.router_interface_id, - .port_name = "", - .src_mac_address = kMacAddress2, - .is_set_port_name = false, - .is_set_src_mac = true}; - - // Update router interface entry present in the Manager. - auto current_entry = - GetRouterInterfaceEntry(KeyGenerator::generateRouterInterfaceKey( - router_intf_entry.router_interface_id)); - ASSERT_NE(current_entry, nullptr); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRequest(app_db_entry, current_entry)); - - // Validate that router interface entry present in the Manager has the updated - // MacAddress. - router_intf_entry.src_mac_address = kMacAddress2; - ValidateRouterInterfaceEntry(router_intf_entry); -} +TEST_F(RouterInterfaceManagerTest, CreateRouterInterfaceSaiApiFails) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, kMacAddress1); + EXPECT_CALL(mock_sai_router_intf_, create_router_interface(_, _, _, _)).WillOnce(Return(SAI_STATUS_FAILURE)); -TEST_F(RouterInterfaceManagerTest, ProcessUpdateRequestSetPortNameIdempotent) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, - kMacAddress1); - router_intf_entry.router_interface_oid = kRouterInterfaceOid1; - AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); - - const P4RouterInterfaceAppDbEntry app_db_entry = { - .router_interface_id = router_intf_entry.router_interface_id, - .port_name = kPortName1, - .src_mac_address = swss::MacAddress(), - .is_set_port_name = true, - .is_set_src_mac = false}; - - // Update router interface entry present in the Manager. - auto current_entry = - GetRouterInterfaceEntry(KeyGenerator::generateRouterInterfaceKey( - router_intf_entry.router_interface_id)); - ASSERT_NE(current_entry, nullptr); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRequest(app_db_entry, current_entry)); - - // Validate that router interface entry present in the Manager has not - // changed. - ValidateRouterInterfaceEntry(router_intf_entry); -} + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, + CreateRouterInterface(KeyGenerator::generateRouterInterfaceKey(router_intf_entry.router_interface_id), + router_intf_entry)); -TEST_F(RouterInterfaceManagerTest, ProcessUpdateRequestSetPortName) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, - kMacAddress1); - router_intf_entry.router_interface_oid = kRouterInterfaceOid1; - AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); - - const P4RouterInterfaceAppDbEntry app_db_entry = { - .router_interface_id = router_intf_entry.router_interface_id, - .port_name = kPortName2, - .src_mac_address = swss::MacAddress(), - .is_set_port_name = true, - .is_set_src_mac = false}; - - // Update router interface entry present in the Manager. - auto current_entry = - GetRouterInterfaceEntry(KeyGenerator::generateRouterInterfaceKey( - router_intf_entry.router_interface_id)); - ASSERT_NE(current_entry, nullptr); - EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, - ProcessUpdateRequest(app_db_entry, current_entry)); - - // Validate that router interface entry present in the Manager has not - // changed. - ValidateRouterInterfaceEntry(router_intf_entry); + ValidateRouterInterfaceEntryNotPresent(router_intf_entry.router_interface_id); } -TEST_F(RouterInterfaceManagerTest, ProcessUpdateRequestMacAddrAndPort) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, - kMacAddress1); - router_intf_entry.router_interface_oid = kRouterInterfaceOid1; - AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); - - const P4RouterInterfaceAppDbEntry app_db_entry = { - .router_interface_id = router_intf_entry.router_interface_id, - .port_name = kPortName2, - .src_mac_address = kMacAddress2, - .is_set_port_name = true, - .is_set_src_mac = true}; - - // Update router interface entry present in the Manager. - auto current_entry = - GetRouterInterfaceEntry(KeyGenerator::generateRouterInterfaceKey( - router_intf_entry.router_interface_id)); - ASSERT_NE(current_entry, nullptr); - // Update port name not supported, hence ProcessUpdateRequest should fail. - EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, - ProcessUpdateRequest(app_db_entry, current_entry)); - - // Validate that router interface entry present in the Manager does not - // changed. - ValidateRouterInterfaceEntry(router_intf_entry); -} +TEST_F(RouterInterfaceManagerTest, RemoveRouterInterfaceExistingInterface) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId2, kPortName2, kMacAddress2); + router_intf_entry.router_interface_oid = kRouterInterfaceOid2; + AddRouterInterfaceEntry(router_intf_entry, kPortOid2, kMtu2); -TEST_F(RouterInterfaceManagerTest, ProcessDeleteRequestExistingInterface) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, - kMacAddress1); - router_intf_entry.router_interface_oid = kRouterInterfaceOid1; - AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); + EXPECT_CALL(mock_sai_router_intf_, remove_router_interface(Eq(router_intf_entry.router_interface_oid))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL( - mock_sai_router_intf_, - remove_router_interface(Eq(router_intf_entry.router_interface_oid))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessDeleteRequest(KeyGenerator::generateRouterInterfaceKey( - router_intf_entry.router_interface_id))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, + RemoveRouterInterface(KeyGenerator::generateRouterInterfaceKey(router_intf_entry.router_interface_id))); - ValidateRouterInterfaceEntryNotPresent(router_intf_entry.router_interface_id); + ValidateRouterInterfaceEntryNotPresent(router_intf_entry.router_interface_id); } -TEST_F(RouterInterfaceManagerTest, ProcessDeleteRequestNonExistingInterface) { - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, - ProcessDeleteRequest( - KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1))); +TEST_F(RouterInterfaceManagerTest, RemoveRouterInterfaceNonExistingInterface) +{ + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, + RemoveRouterInterface(KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId2))); } -TEST_F(RouterInterfaceManagerTest, - ProcessDeleteRequestInterfaceNotExistInMapper) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, - kMacAddress1); - router_intf_entry.router_interface_oid = kRouterInterfaceOid1; - AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); - - p4_oid_mapper_.eraseOID( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1)); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, - ProcessDeleteRequest(KeyGenerator::generateRouterInterfaceKey( - router_intf_entry.router_interface_id))); -} +TEST_F(RouterInterfaceManagerTest, RemoveRouterInterfaceNonZeroRefCount) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId2, kPortName2, kMacAddress2); + router_intf_entry.router_interface_oid = kRouterInterfaceOid2; + AddRouterInterfaceEntry(router_intf_entry, kPortOid2, kMtu2); -TEST_F(RouterInterfaceManagerTest, DeserializeRouterIntfEntryValidAttributes) { - const std::vector attributes = { - swss::FieldValueTuple(p4orch::kAction, "set_port_and_src_mac"), - swss::FieldValueTuple(prependParamField(p4orch::kPort), kPortName1), - swss::FieldValueTuple(prependParamField(p4orch::kSrcMac), - kMacAddress1.to_string()), - }; - - auto app_db_entry_or = - DeserializeRouterIntfEntry(kRouterIntfAppDbKey, attributes); - EXPECT_TRUE(app_db_entry_or.ok()); - auto& app_db_entry = *app_db_entry_or; - EXPECT_EQ(app_db_entry.router_interface_id, kRouterInterfaceId1); - EXPECT_EQ(app_db_entry.port_name, kPortName1); - EXPECT_EQ(app_db_entry.src_mac_address, kMacAddress1); - EXPECT_TRUE(app_db_entry.is_set_port_name); - EXPECT_TRUE(app_db_entry.is_set_src_mac); -} + const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey(router_intf_entry.router_interface_id); + ASSERT_TRUE(p4_oid_mapper_.increaseRefCount(SAI_OBJECT_TYPE_ROUTER_INTERFACE, router_intf_key)); -TEST_F(RouterInterfaceManagerTest, DeserializeRouterIntfEntryInvalidKeyFormat) { - const std::vector attributes = { - swss::FieldValueTuple(p4orch::kAction, "set_port_and_src_mac"), - swss::FieldValueTuple(prependParamField(p4orch::kPort), kPortName1), - swss::FieldValueTuple(prependParamField(p4orch::kSrcMac), - kMacAddress1.to_string()), - }; - - // Invalid json format. - std::string invalid_key = R"({"match/router_interface_id:intf-3/4"})"; - auto app_db_entry_or = DeserializeRouterIntfEntry(invalid_key, attributes); - EXPECT_FALSE(app_db_entry_or.ok()); - - // Invalid json format. - invalid_key = R"([{"match/router_interface_id":"intf-3/4"}])"; - app_db_entry_or = DeserializeRouterIntfEntry(invalid_key, attributes); - EXPECT_FALSE(app_db_entry_or.ok()); - - // Invalid json format. - invalid_key = R"(["match/router_interface_id","intf-3/4"])"; - app_db_entry_or = DeserializeRouterIntfEntry(invalid_key, attributes); - EXPECT_FALSE(app_db_entry_or.ok()); - - // Invalid field name. - invalid_key = R"({"router_interface_id":"intf-3/4"})"; - app_db_entry_or = DeserializeRouterIntfEntry(invalid_key, attributes); - EXPECT_FALSE(app_db_entry_or.ok()); -} + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, RemoveRouterInterface(router_intf_key)); -TEST_F(RouterInterfaceManagerTest, DeserializeRouterIntfEntryMissingAction) { - const std::vector attributes = { - swss::FieldValueTuple(prependParamField(p4orch::kPort), kPortName1), - swss::FieldValueTuple(prependParamField(p4orch::kSrcMac), - kMacAddress1.to_string()), - }; - - auto app_db_entry_or = - DeserializeRouterIntfEntry(kRouterIntfAppDbKey, attributes); - EXPECT_TRUE(app_db_entry_or.ok()); - auto& app_db_entry = *app_db_entry_or; - EXPECT_EQ(app_db_entry.router_interface_id, kRouterInterfaceId1); - EXPECT_EQ(app_db_entry.port_name, kPortName1); - EXPECT_EQ(app_db_entry.src_mac_address, kMacAddress1); - EXPECT_TRUE(app_db_entry.is_set_port_name); - EXPECT_TRUE(app_db_entry.is_set_src_mac); + ValidateRouterInterfaceEntry(router_intf_entry); } -TEST_F(RouterInterfaceManagerTest, - DeserializeRouterIntfEntryOnlyPortNameAttribute) { - const std::vector attributes = { - swss::FieldValueTuple(prependParamField(p4orch::kPort), kPortName1)}; - - auto app_db_entry_or = - DeserializeRouterIntfEntry(kRouterIntfAppDbKey, attributes); - EXPECT_TRUE(app_db_entry_or.ok()); - auto& app_db_entry = *app_db_entry_or; - EXPECT_EQ(app_db_entry.router_interface_id, kRouterInterfaceId1); - EXPECT_EQ(app_db_entry.port_name, kPortName1); - EXPECT_EQ(app_db_entry.src_mac_address, kZeroMacAddress); - EXPECT_TRUE(app_db_entry.is_set_port_name); - EXPECT_FALSE(app_db_entry.is_set_src_mac); -} +TEST_F(RouterInterfaceManagerTest, RemoveRouterInterfaceSaiApiFails) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId2, kPortName2, kMacAddress2); + router_intf_entry.router_interface_oid = kRouterInterfaceOid2; + AddRouterInterfaceEntry(router_intf_entry, kPortOid2, kMtu2); -TEST_F(RouterInterfaceManagerTest, - DeserializeRouterIntfEntryOnlyMacAddrAttribute) { - const std::vector attributes = {swss::FieldValueTuple( - prependParamField(p4orch::kSrcMac), kMacAddress1.to_string())}; - - auto app_db_entry_or = - DeserializeRouterIntfEntry(kRouterIntfAppDbKey, attributes); - EXPECT_TRUE(app_db_entry_or.ok()); - auto& app_db_entry = *app_db_entry_or; - EXPECT_EQ(app_db_entry.router_interface_id, kRouterInterfaceId1); - EXPECT_EQ(app_db_entry.port_name, ""); - EXPECT_EQ(app_db_entry.src_mac_address, kMacAddress1); - EXPECT_FALSE(app_db_entry.is_set_port_name); - EXPECT_TRUE(app_db_entry.is_set_src_mac); -} + EXPECT_CALL(mock_sai_router_intf_, remove_router_interface(Eq(router_intf_entry.router_interface_oid))) + .WillOnce(Return(SAI_STATUS_FAILURE)); -TEST_F(RouterInterfaceManagerTest, DeserializeRouterIntfEntryNoAttributes) { - const std::vector attributes; - - auto app_db_entry_or = - DeserializeRouterIntfEntry(kRouterIntfAppDbKey, attributes); - EXPECT_TRUE(app_db_entry_or.ok()); - auto& app_db_entry = *app_db_entry_or; - EXPECT_EQ(app_db_entry.router_interface_id, kRouterInterfaceId1); - EXPECT_EQ(app_db_entry.port_name, ""); - EXPECT_EQ(app_db_entry.src_mac_address, kZeroMacAddress); - EXPECT_FALSE(app_db_entry.is_set_port_name); - EXPECT_FALSE(app_db_entry.is_set_src_mac); -} + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, + RemoveRouterInterface(KeyGenerator::generateRouterInterfaceKey(router_intf_entry.router_interface_id))); -TEST_F(RouterInterfaceManagerTest, DeserializeRouterIntfEntryInvalidField) { - const std::vector attributes = { - swss::FieldValueTuple("invalid_field", "invalid_value")}; - - auto app_db_entry_or = - DeserializeRouterIntfEntry(kRouterIntfAppDbKey, attributes); - EXPECT_FALSE(app_db_entry_or.ok()); + ValidateRouterInterfaceEntry(router_intf_entry); } -TEST_F(RouterInterfaceManagerTest, - DeserializeRouterIntfEntryInvalidMacAddrValue) { - const std::vector attributes = {swss::FieldValueTuple( - prependParamField(p4orch::kSrcMac), "00:11:22:33:44")}; +TEST_F(RouterInterfaceManagerTest, SetSourceMacAddressModifyMacAddress) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, kMacAddress1); + router_intf_entry.router_interface_oid = kRouterInterfaceOid1; + + sai_attribute_value_t attr_value; + memcpy(attr_value.mac, kMacAddress2.getMac(), sizeof(sai_mac_t)); + std::unordered_map attr_list = { + {SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS, attr_value}}; + EXPECT_CALL(mock_sai_router_intf_, + set_router_interface_attribute( + Eq(router_intf_entry.router_interface_oid), + Truly(std::bind(MatchCreateRouterInterfaceAttributeList, std::placeholders::_1, attr_list)))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); - auto app_db_entry_or = - DeserializeRouterIntfEntry(kRouterIntfAppDbKey, attributes); - EXPECT_FALSE(app_db_entry_or.ok()); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, SetSourceMacAddress(&router_intf_entry, kMacAddress2)); + EXPECT_EQ(router_intf_entry.src_mac_address, kMacAddress2); } -TEST_F(RouterInterfaceManagerTest, DrainValidAttributes) { - const std::string appl_db_key = - std::string(APP_P4RT_ROUTER_INTERFACE_TABLE_NAME) + kTableKeyDelimiter + - std::string(kRouterIntfAppDbKey); - - // Enqueue entry for create operation. - std::vector attributes; - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kPort), kPortName1}); - attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), - kMacAddress1.to_string()}); - Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); - - EXPECT_CALL(mock_sai_router_intf_, create_router_interface(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(kRouterInterfaceOid1), - Return(SAI_STATUS_SUCCESS))); - Drain(); - - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, - kMacAddress1); - router_intf_entry.router_interface_oid = kRouterInterfaceOid1; - ValidateRouterInterfaceEntry(router_intf_entry); - - // Enqueue entry for update operation. - attributes.clear(); - attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), - kMacAddress2.to_string()}); - Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); - - EXPECT_CALL(mock_sai_router_intf_, set_router_interface_attribute(_, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - Drain(); - - router_intf_entry.src_mac_address = kMacAddress2; - ValidateRouterInterfaceEntry(router_intf_entry); - - // Enqueue entry for delete operation. - attributes.clear(); - Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, DEL_COMMAND, attributes)); - - EXPECT_CALL(mock_sai_router_intf_, remove_router_interface(_)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - Drain(); - - ValidateRouterInterfaceEntryNotPresent(router_intf_entry.router_interface_id); +TEST_F(RouterInterfaceManagerTest, SetSourceMacAddressIdempotent) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, kMacAddress1); + + // SAI API not being called makes the operation idempotent. + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, SetSourceMacAddress(&router_intf_entry, kMacAddress1)); + EXPECT_EQ(router_intf_entry.src_mac_address, kMacAddress1); } -TEST_F(RouterInterfaceManagerTest, DrainInvalidAppDbEntryKey) { - // Create invalid json key with router interface id as kRouterInterfaceId1. - const std::string invalid_router_intf_key = - R"({"match/router_interface_id:intf-3/4"})"; - const std::string appl_db_key = - std::string(APP_P4RT_ROUTER_INTERFACE_TABLE_NAME) + kTableKeyDelimiter + - invalid_router_intf_key; +TEST_F(RouterInterfaceManagerTest, SetSourceMacAddressSaiApiFails) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, kMacAddress1); + router_intf_entry.router_interface_oid = kRouterInterfaceOid1; - // Enqueue entry for create operation. - std::vector attributes; - Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); - Drain(); + sai_attribute_value_t attr_value; + memcpy(attr_value.mac, kMacAddress2.getMac(), sizeof(sai_mac_t)); + std::unordered_map attr_list = { + {SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS, attr_value}}; + EXPECT_CALL(mock_sai_router_intf_, + set_router_interface_attribute( + Eq(router_intf_entry.router_interface_oid), + Truly(std::bind(MatchCreateRouterInterfaceAttributeList, std::placeholders::_1, attr_list)))) + .WillOnce(Return(SAI_STATUS_FAILURE)); - ValidateRouterInterfaceEntryNotPresent(kRouterInterfaceId1); -} + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, SetSourceMacAddress(&router_intf_entry, kMacAddress2)); + EXPECT_EQ(router_intf_entry.src_mac_address, kMacAddress1); +} -TEST_F(RouterInterfaceManagerTest, DrainInvalidAppDbEntryAttributes) { - const std::string appl_db_key = - std::string(APP_P4RT_ROUTER_INTERFACE_TABLE_NAME) + kTableKeyDelimiter + - std::string(kRouterIntfAppDbKey); - - // Invalid port attribute. - std::vector attributes; - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kPort), "xyz"}); - Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); - - // Zero mac address attribute. - attributes.clear(); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kPort), kPortName1}); - attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), - kZeroMacAddress.to_string()}); - Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); - - Drain(); - ValidateRouterInterfaceEntryNotPresent(kRouterInterfaceId1); -} +TEST_F(RouterInterfaceManagerTest, ProcessAddRequestValidAppDbParams) +{ + const P4RouterInterfaceAppDbEntry app_db_entry = {.router_interface_id = kRouterInterfaceId1, + .port_name = kPortName1, + .src_mac_address = kMacAddress1, + .is_set_port_name = true, + .is_set_src_mac = true}; -TEST_F(RouterInterfaceManagerTest, DrainInvalidOperation) { - const std::string appl_db_key = - std::string(APP_P4RT_ROUTER_INTERFACE_TABLE_NAME) + kTableKeyDelimiter + - std::string(kRouterIntfAppDbKey); - - // Enqueue entry for invalid operation. - std::vector attributes; - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kPort), kPortName1}); - attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), - kMacAddress1.to_string()}); - Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, "INVALID", attributes)); - Drain(); - - ValidateRouterInterfaceEntryNotPresent(kRouterInterfaceId1); -} + EXPECT_CALL(mock_sai_router_intf_, + create_router_interface(::testing::NotNull(), Eq(gSwitchId), Eq(5), + Truly(std::bind(MatchCreateRouterInterfaceAttributeList, std::placeholders::_1, + CreateRouterInterfaceAttributeList( + gVirtualRouterId, kMacAddress1, kPortOid1, kMtu1))))) + .WillOnce(DoAll(SetArgPointee<0>(kRouterInterfaceOid1), Return(SAI_STATUS_SUCCESS))); + + const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_interface_id); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRequest(app_db_entry, router_intf_key)); + + P4RouterInterfaceEntry router_intf_entry(app_db_entry.router_interface_id, app_db_entry.port_name, + app_db_entry.src_mac_address); + router_intf_entry.router_interface_oid = kRouterInterfaceOid1; + ValidateRouterInterfaceEntry(router_intf_entry); +} + +TEST_F(RouterInterfaceManagerTest, ProcessAddRequestPortNameMissing) +{ + const P4RouterInterfaceAppDbEntry app_db_entry = {.router_interface_id = kRouterInterfaceId1, + .port_name = "", + .src_mac_address = kMacAddress1, + .is_set_port_name = false, + .is_set_src_mac = true}; + + const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_interface_id); + EXPECT_EQ(StatusCode::SWSS_RC_INVALID_PARAM, ProcessAddRequest(app_db_entry, router_intf_key)); +} + +TEST_F(RouterInterfaceManagerTest, ProcessAddRequestInvalidPortName) +{ + const P4RouterInterfaceAppDbEntry app_db_entry = {.router_interface_id = kRouterInterfaceId1, + .port_name = "", + .src_mac_address = kMacAddress1, + .is_set_port_name = true, + .is_set_src_mac = true}; + + const std::string router_intf_key = KeyGenerator::generateRouterInterfaceKey(app_db_entry.router_interface_id); + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, ProcessAddRequest(app_db_entry, router_intf_key)); +} + +TEST_F(RouterInterfaceManagerTest, ProcessUpdateRequestSetSourceMacAddress) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, kMacAddress1); + router_intf_entry.router_interface_oid = kRouterInterfaceOid1; + AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); + + sai_attribute_value_t attr_value; + memcpy(attr_value.mac, kMacAddress2.getMac(), sizeof(sai_mac_t)); + std::unordered_map attr_list = { + {SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS, attr_value}}; + EXPECT_CALL(mock_sai_router_intf_, + set_router_interface_attribute( + Eq(router_intf_entry.router_interface_oid), + Truly(std::bind(MatchCreateRouterInterfaceAttributeList, std::placeholders::_1, attr_list)))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + const P4RouterInterfaceAppDbEntry app_db_entry = {.router_interface_id = router_intf_entry.router_interface_id, + .port_name = "", + .src_mac_address = kMacAddress2, + .is_set_port_name = false, + .is_set_src_mac = true}; + + // Update router interface entry present in the Manager. + auto current_entry = + GetRouterInterfaceEntry(KeyGenerator::generateRouterInterfaceKey(router_intf_entry.router_interface_id)); + ASSERT_NE(current_entry, nullptr); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRequest(app_db_entry, current_entry)); + + // Validate that router interface entry present in the Manager has the updated + // MacAddress. + router_intf_entry.src_mac_address = kMacAddress2; + ValidateRouterInterfaceEntry(router_intf_entry); +} + +TEST_F(RouterInterfaceManagerTest, ProcessUpdateRequestSetPortNameIdempotent) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, kMacAddress1); + router_intf_entry.router_interface_oid = kRouterInterfaceOid1; + AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); + + const P4RouterInterfaceAppDbEntry app_db_entry = {.router_interface_id = router_intf_entry.router_interface_id, + .port_name = kPortName1, + .src_mac_address = swss::MacAddress(), + .is_set_port_name = true, + .is_set_src_mac = false}; + + // Update router interface entry present in the Manager. + auto current_entry = + GetRouterInterfaceEntry(KeyGenerator::generateRouterInterfaceKey(router_intf_entry.router_interface_id)); + ASSERT_NE(current_entry, nullptr); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRequest(app_db_entry, current_entry)); + + // Validate that router interface entry present in the Manager has not + // changed. + ValidateRouterInterfaceEntry(router_intf_entry); +} + +TEST_F(RouterInterfaceManagerTest, ProcessUpdateRequestSetPortName) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, kMacAddress1); + router_intf_entry.router_interface_oid = kRouterInterfaceOid1; + AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); + + const P4RouterInterfaceAppDbEntry app_db_entry = {.router_interface_id = router_intf_entry.router_interface_id, + .port_name = kPortName2, + .src_mac_address = swss::MacAddress(), + .is_set_port_name = true, + .is_set_src_mac = false}; + + // Update router interface entry present in the Manager. + auto current_entry = + GetRouterInterfaceEntry(KeyGenerator::generateRouterInterfaceKey(router_intf_entry.router_interface_id)); + ASSERT_NE(current_entry, nullptr); + EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, ProcessUpdateRequest(app_db_entry, current_entry)); + + // Validate that router interface entry present in the Manager has not + // changed. + ValidateRouterInterfaceEntry(router_intf_entry); +} + +TEST_F(RouterInterfaceManagerTest, ProcessUpdateRequestMacAddrAndPort) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, kMacAddress1); + router_intf_entry.router_interface_oid = kRouterInterfaceOid1; + AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); + + const P4RouterInterfaceAppDbEntry app_db_entry = {.router_interface_id = router_intf_entry.router_interface_id, + .port_name = kPortName2, + .src_mac_address = kMacAddress2, + .is_set_port_name = true, + .is_set_src_mac = true}; + + // Update router interface entry present in the Manager. + auto current_entry = + GetRouterInterfaceEntry(KeyGenerator::generateRouterInterfaceKey(router_intf_entry.router_interface_id)); + ASSERT_NE(current_entry, nullptr); + // Update port name not supported, hence ProcessUpdateRequest should fail. + EXPECT_EQ(StatusCode::SWSS_RC_UNIMPLEMENTED, ProcessUpdateRequest(app_db_entry, current_entry)); + + // Validate that router interface entry present in the Manager does not + // changed. + ValidateRouterInterfaceEntry(router_intf_entry); +} + +TEST_F(RouterInterfaceManagerTest, ProcessDeleteRequestExistingInterface) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, kMacAddress1); + router_intf_entry.router_interface_oid = kRouterInterfaceOid1; + AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); + + EXPECT_CALL(mock_sai_router_intf_, remove_router_interface(Eq(router_intf_entry.router_interface_oid))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); -TEST_F(RouterInterfaceManagerTest, VerifyStateTest) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, - kMacAddress1); - router_intf_entry.router_interface_oid = kRouterInterfaceOid1; - AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set( - "SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x295100", - std::vector{ - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", - "oid:0x0"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS", - "00:01:02:03:04:05"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_TYPE", - "SAI_ROUTER_INTERFACE_TYPE_PORT"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_PORT_ID", - "oid:0x112233"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_MTU", "1500"}}); - - const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + - APP_P4RT_ROUTER_INTERFACE_TABLE_NAME + - kTableKeyDelimiter + kRouterIntfAppDbKey; - std::vector attributes; - - // Verification should succeed with vaild key and value. - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kPort), kPortName1}); - attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), - kMacAddress1.to_string()}); - EXPECT_EQ(VerifyState(db_key, attributes), ""); - - // Invalid key should fail verification. - EXPECT_FALSE(VerifyState("invalid", attributes).empty()); - EXPECT_FALSE(VerifyState("invalid:invalid", attributes).empty()); - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes) - .empty()); - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", - attributes) - .empty()); - EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + - ":FIXED_ROUTER_INTERFACE_TABLE:invalid", - attributes) - .empty()); - EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + - ":FIXED_ROUTER_INTERFACE_TABLE:{\"match/" - "router_interface_id\":\"invalid\"}", - attributes) - .empty()); - - // Invalid attributes should fail verification. - attributes.clear(); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kPort), kPortName2}); - attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), - kMacAddress1.to_string()}); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - - attributes.clear(); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kPort), kPortName1}); - attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), - kMacAddress2.to_string()}); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - - // Invalid port should fail verification. - attributes.clear(); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kPort), "invalid"}); - attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), - kMacAddress1.to_string()}); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - - // Verification should fail if interface IDs mismatch. - attributes.clear(); - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kPort), kPortName1}); - attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), - kMacAddress1.to_string()}); - auto* router_intf_entry_ptr = - GetRouterInterfaceEntry(KeyGenerator::generateRouterInterfaceKey( - router_intf_entry.router_interface_id)); - auto saved_ritf_id = router_intf_entry_ptr->router_interface_id; - router_intf_entry_ptr->router_interface_id = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - router_intf_entry_ptr->router_interface_id = saved_ritf_id; - - // Verification should fail if OID mapper mismatches. - p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, - KeyGenerator::generateRouterInterfaceKey( - router_intf_entry.router_interface_id)); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, + ProcessDeleteRequest(KeyGenerator::generateRouterInterfaceKey(router_intf_entry.router_interface_id))); + + ValidateRouterInterfaceEntryNotPresent(router_intf_entry.router_interface_id); +} + +TEST_F(RouterInterfaceManagerTest, ProcessDeleteRequestNonExistingInterface) +{ + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, + ProcessDeleteRequest(KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1))); +} + +TEST_F(RouterInterfaceManagerTest, ProcessDeleteRequestInterfaceNotExistInMapper) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, kMacAddress1); + router_intf_entry.router_interface_oid = kRouterInterfaceOid1; + AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); + + p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(kRouterInterfaceId1)); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_INTERNAL, + ProcessDeleteRequest(KeyGenerator::generateRouterInterfaceKey(router_intf_entry.router_interface_id))); +} + +TEST_F(RouterInterfaceManagerTest, DeserializeRouterIntfEntryValidAttributes) +{ + const std::vector attributes = { + swss::FieldValueTuple(p4orch::kAction, "set_port_and_src_mac"), + swss::FieldValueTuple(prependParamField(p4orch::kPort), kPortName1), + swss::FieldValueTuple(prependParamField(p4orch::kSrcMac), kMacAddress1.to_string()), + }; + + auto app_db_entry_or = DeserializeRouterIntfEntry(kRouterIntfAppDbKey, attributes); + EXPECT_TRUE(app_db_entry_or.ok()); + auto &app_db_entry = *app_db_entry_or; + EXPECT_EQ(app_db_entry.router_interface_id, kRouterInterfaceId1); + EXPECT_EQ(app_db_entry.port_name, kPortName1); + EXPECT_EQ(app_db_entry.src_mac_address, kMacAddress1); + EXPECT_TRUE(app_db_entry.is_set_port_name); + EXPECT_TRUE(app_db_entry.is_set_src_mac); +} + +TEST_F(RouterInterfaceManagerTest, DeserializeRouterIntfEntryInvalidKeyFormat) +{ + const std::vector attributes = { + swss::FieldValueTuple(p4orch::kAction, "set_port_and_src_mac"), + swss::FieldValueTuple(prependParamField(p4orch::kPort), kPortName1), + swss::FieldValueTuple(prependParamField(p4orch::kSrcMac), kMacAddress1.to_string()), + }; + + // Invalid json format. + std::string invalid_key = R"({"match/router_interface_id:intf-3/4"})"; + auto app_db_entry_or = DeserializeRouterIntfEntry(invalid_key, attributes); + EXPECT_FALSE(app_db_entry_or.ok()); + + // Invalid json format. + invalid_key = R"([{"match/router_interface_id":"intf-3/4"}])"; + app_db_entry_or = DeserializeRouterIntfEntry(invalid_key, attributes); + EXPECT_FALSE(app_db_entry_or.ok()); + + // Invalid json format. + invalid_key = R"(["match/router_interface_id","intf-3/4"])"; + app_db_entry_or = DeserializeRouterIntfEntry(invalid_key, attributes); + EXPECT_FALSE(app_db_entry_or.ok()); + + // Invalid field name. + invalid_key = R"({"router_interface_id":"intf-3/4"})"; + app_db_entry_or = DeserializeRouterIntfEntry(invalid_key, attributes); + EXPECT_FALSE(app_db_entry_or.ok()); +} + +TEST_F(RouterInterfaceManagerTest, DeserializeRouterIntfEntryMissingAction) +{ + const std::vector attributes = { + swss::FieldValueTuple(prependParamField(p4orch::kPort), kPortName1), + swss::FieldValueTuple(prependParamField(p4orch::kSrcMac), kMacAddress1.to_string()), + }; + + auto app_db_entry_or = DeserializeRouterIntfEntry(kRouterIntfAppDbKey, attributes); + EXPECT_TRUE(app_db_entry_or.ok()); + auto &app_db_entry = *app_db_entry_or; + EXPECT_EQ(app_db_entry.router_interface_id, kRouterInterfaceId1); + EXPECT_EQ(app_db_entry.port_name, kPortName1); + EXPECT_EQ(app_db_entry.src_mac_address, kMacAddress1); + EXPECT_TRUE(app_db_entry.is_set_port_name); + EXPECT_TRUE(app_db_entry.is_set_src_mac); +} + +TEST_F(RouterInterfaceManagerTest, DeserializeRouterIntfEntryOnlyPortNameAttribute) +{ + const std::vector attributes = { + swss::FieldValueTuple(prependParamField(p4orch::kPort), kPortName1)}; + + auto app_db_entry_or = DeserializeRouterIntfEntry(kRouterIntfAppDbKey, attributes); + EXPECT_TRUE(app_db_entry_or.ok()); + auto &app_db_entry = *app_db_entry_or; + EXPECT_EQ(app_db_entry.router_interface_id, kRouterInterfaceId1); + EXPECT_EQ(app_db_entry.port_name, kPortName1); + EXPECT_EQ(app_db_entry.src_mac_address, kZeroMacAddress); + EXPECT_TRUE(app_db_entry.is_set_port_name); + EXPECT_FALSE(app_db_entry.is_set_src_mac); +} + +TEST_F(RouterInterfaceManagerTest, DeserializeRouterIntfEntryOnlyMacAddrAttribute) +{ + const std::vector attributes = { + swss::FieldValueTuple(prependParamField(p4orch::kSrcMac), kMacAddress1.to_string())}; + + auto app_db_entry_or = DeserializeRouterIntfEntry(kRouterIntfAppDbKey, attributes); + EXPECT_TRUE(app_db_entry_or.ok()); + auto &app_db_entry = *app_db_entry_or; + EXPECT_EQ(app_db_entry.router_interface_id, kRouterInterfaceId1); + EXPECT_EQ(app_db_entry.port_name, ""); + EXPECT_EQ(app_db_entry.src_mac_address, kMacAddress1); + EXPECT_FALSE(app_db_entry.is_set_port_name); + EXPECT_TRUE(app_db_entry.is_set_src_mac); +} + +TEST_F(RouterInterfaceManagerTest, DeserializeRouterIntfEntryNoAttributes) +{ + const std::vector attributes; + + auto app_db_entry_or = DeserializeRouterIntfEntry(kRouterIntfAppDbKey, attributes); + EXPECT_TRUE(app_db_entry_or.ok()); + auto &app_db_entry = *app_db_entry_or; + EXPECT_EQ(app_db_entry.router_interface_id, kRouterInterfaceId1); + EXPECT_EQ(app_db_entry.port_name, ""); + EXPECT_EQ(app_db_entry.src_mac_address, kZeroMacAddress); + EXPECT_FALSE(app_db_entry.is_set_port_name); + EXPECT_FALSE(app_db_entry.is_set_src_mac); +} + +TEST_F(RouterInterfaceManagerTest, DeserializeRouterIntfEntryInvalidField) +{ + const std::vector attributes = {swss::FieldValueTuple("invalid_field", "invalid_value")}; + + auto app_db_entry_or = DeserializeRouterIntfEntry(kRouterIntfAppDbKey, attributes); + EXPECT_FALSE(app_db_entry_or.ok()); } -TEST_F(RouterInterfaceManagerTest, VerifyStateAsicDbTest) { - P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, "Ethernet7", - kMacAddress1); - router_intf_entry.router_interface_oid = kRouterInterfaceOid1; - AddRouterInterfaceEntry(router_intf_entry, 0x1234, 9100); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set( - "SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x295100", - std::vector{ - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", - "oid:0x0"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS", - "00:01:02:03:04:05"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_TYPE", - "SAI_ROUTER_INTERFACE_TYPE_PORT"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_PORT_ID", - "oid:0x1234"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_MTU", "9100"}}); - - const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + - APP_P4RT_ROUTER_INTERFACE_TABLE_NAME + - kTableKeyDelimiter + kRouterIntfAppDbKey; - std::vector attributes; - attributes.push_back( - swss::FieldValueTuple{prependParamField(p4orch::kPort), "Ethernet7"}); - attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), - kMacAddress1.to_string()}); - - // Verification should succeed with correct ASIC DB values. - EXPECT_EQ(VerifyState(db_key, attributes), ""); - - // Verification should fail if ASIC DB values mismatch. - table.set("SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x295100", - std::vector{swss::FieldValueTuple{ - "SAI_ROUTER_INTERFACE_ATTR_MTU", "1500"}}); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - - // Verification should fail if ASIC DB table is missing. - table.del("SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x295100"); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - table.set( - "SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x295100", - std::vector{ - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", - "oid:0x0"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS", - "00:01:02:03:04:05"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_TYPE", - "SAI_ROUTER_INTERFACE_TYPE_PORT"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_PORT_ID", - "oid:0x1234"}, - swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_MTU", "9100"}}); - - // Verification should fail if SAI attr cannot be constructed. - auto* router_intf_entry_ptr = - GetRouterInterfaceEntry(KeyGenerator::generateRouterInterfaceKey( - router_intf_entry.router_interface_id)); - router_intf_entry_ptr->port_name = "Ethernet8"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - router_intf_entry_ptr->port_name = "Ethernet7"; +TEST_F(RouterInterfaceManagerTest, DeserializeRouterIntfEntryInvalidMacAddrValue) +{ + const std::vector attributes = { + swss::FieldValueTuple(prependParamField(p4orch::kSrcMac), "00:11:22:33:44")}; + + auto app_db_entry_or = DeserializeRouterIntfEntry(kRouterIntfAppDbKey, attributes); + EXPECT_FALSE(app_db_entry_or.ok()); +} + +TEST_F(RouterInterfaceManagerTest, DrainValidAttributes) +{ + const std::string appl_db_key = + std::string(APP_P4RT_ROUTER_INTERFACE_TABLE_NAME) + kTableKeyDelimiter + std::string(kRouterIntfAppDbKey); + + // Enqueue entry for create operation. + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kPort), kPortName1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), kMacAddress1.to_string()}); + Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); + + EXPECT_CALL(mock_sai_router_intf_, create_router_interface(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kRouterInterfaceOid1), Return(SAI_STATUS_SUCCESS))); + Drain(); + + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, kMacAddress1); + router_intf_entry.router_interface_oid = kRouterInterfaceOid1; + ValidateRouterInterfaceEntry(router_intf_entry); + + // Enqueue entry for update operation. + attributes.clear(); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), kMacAddress2.to_string()}); + Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); + + EXPECT_CALL(mock_sai_router_intf_, set_router_interface_attribute(_, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + Drain(); + + router_intf_entry.src_mac_address = kMacAddress2; + ValidateRouterInterfaceEntry(router_intf_entry); + + // Enqueue entry for delete operation. + attributes.clear(); + Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, DEL_COMMAND, attributes)); + + EXPECT_CALL(mock_sai_router_intf_, remove_router_interface(_)).WillOnce(Return(SAI_STATUS_SUCCESS)); + Drain(); + + ValidateRouterInterfaceEntryNotPresent(router_intf_entry.router_interface_id); +} + +TEST_F(RouterInterfaceManagerTest, DrainInvalidAppDbEntryKey) +{ + // Create invalid json key with router interface id as kRouterInterfaceId1. + const std::string invalid_router_intf_key = R"({"match/router_interface_id:intf-3/4"})"; + const std::string appl_db_key = + std::string(APP_P4RT_ROUTER_INTERFACE_TABLE_NAME) + kTableKeyDelimiter + invalid_router_intf_key; + + // Enqueue entry for create operation. + std::vector attributes; + Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); + Drain(); + + ValidateRouterInterfaceEntryNotPresent(kRouterInterfaceId1); +} + +TEST_F(RouterInterfaceManagerTest, DrainInvalidAppDbEntryAttributes) +{ + const std::string appl_db_key = + std::string(APP_P4RT_ROUTER_INTERFACE_TABLE_NAME) + kTableKeyDelimiter + std::string(kRouterIntfAppDbKey); + + // Invalid port attribute. + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kPort), "xyz"}); + Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); + + // Zero mac address attribute. + attributes.clear(); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kPort), kPortName1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), kZeroMacAddress.to_string()}); + Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, SET_COMMAND, attributes)); + + Drain(); + ValidateRouterInterfaceEntryNotPresent(kRouterInterfaceId1); +} + +TEST_F(RouterInterfaceManagerTest, DrainInvalidOperation) +{ + const std::string appl_db_key = + std::string(APP_P4RT_ROUTER_INTERFACE_TABLE_NAME) + kTableKeyDelimiter + std::string(kRouterIntfAppDbKey); + + // Enqueue entry for invalid operation. + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kPort), kPortName1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), kMacAddress1.to_string()}); + Enqueue(swss::KeyOpFieldsValuesTuple(appl_db_key, "INVALID", attributes)); + Drain(); + + ValidateRouterInterfaceEntryNotPresent(kRouterInterfaceId1); +} + +TEST_F(RouterInterfaceManagerTest, VerifyStateTest) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, kPortName1, kMacAddress1); + router_intf_entry.router_interface_oid = kRouterInterfaceOid1; + AddRouterInterfaceEntry(router_intf_entry, kPortOid1, kMtu1); + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set("SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x295100", + std::vector{ + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", "oid:0x0"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS", "00:01:02:03:04:05"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_TYPE", "SAI_ROUTER_INTERFACE_TYPE_PORT"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_PORT_ID", "oid:0x112233"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_MTU", "1500"}}); + + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + + APP_P4RT_ROUTER_INTERFACE_TABLE_NAME + kTableKeyDelimiter + kRouterIntfAppDbKey; + std::vector attributes; + + // Verification should succeed with vaild key and value. + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kPort), kPortName1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), kMacAddress1.to_string()}); + EXPECT_EQ(VerifyState(db_key, attributes), ""); + + // Invalid key should fail verification. + EXPECT_FALSE(VerifyState("invalid", attributes).empty()); + EXPECT_FALSE(VerifyState("invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", attributes).empty()); + EXPECT_FALSE( + VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":FIXED_ROUTER_INTERFACE_TABLE:invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":FIXED_ROUTER_INTERFACE_TABLE:{\"match/" + "router_interface_id\":\"invalid\"}", + attributes) + .empty()); + + // Invalid attributes should fail verification. + attributes.clear(); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kPort), kPortName2}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), kMacAddress1.to_string()}); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + + attributes.clear(); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kPort), kPortName1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), kMacAddress2.to_string()}); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + + // Invalid port should fail verification. + attributes.clear(); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kPort), "invalid"}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), kMacAddress1.to_string()}); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + + // Verification should fail if interface IDs mismatch. + attributes.clear(); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kPort), kPortName1}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), kMacAddress1.to_string()}); + auto *router_intf_entry_ptr = + GetRouterInterfaceEntry(KeyGenerator::generateRouterInterfaceKey(router_intf_entry.router_interface_id)); + auto saved_ritf_id = router_intf_entry_ptr->router_interface_id; + router_intf_entry_ptr->router_interface_id = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + router_intf_entry_ptr->router_interface_id = saved_ritf_id; + + // Verification should fail if OID mapper mismatches. + p4_oid_mapper_.eraseOID(SAI_OBJECT_TYPE_ROUTER_INTERFACE, + KeyGenerator::generateRouterInterfaceKey(router_intf_entry.router_interface_id)); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); +} + +TEST_F(RouterInterfaceManagerTest, VerifyStateAsicDbTest) +{ + P4RouterInterfaceEntry router_intf_entry(kRouterInterfaceId1, "Ethernet7", kMacAddress1); + router_intf_entry.router_interface_oid = kRouterInterfaceOid1; + AddRouterInterfaceEntry(router_intf_entry, 0x1234, 9100); + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set("SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x295100", + std::vector{ + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", "oid:0x0"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS", "00:01:02:03:04:05"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_TYPE", "SAI_ROUTER_INTERFACE_TYPE_PORT"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_PORT_ID", "oid:0x1234"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_MTU", "9100"}}); + + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + + APP_P4RT_ROUTER_INTERFACE_TABLE_NAME + kTableKeyDelimiter + kRouterIntfAppDbKey; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kPort), "Ethernet7"}); + attributes.push_back(swss::FieldValueTuple{prependParamField(p4orch::kSrcMac), kMacAddress1.to_string()}); + + // Verification should succeed with correct ASIC DB values. + EXPECT_EQ(VerifyState(db_key, attributes), ""); + + // Verification should fail if ASIC DB values mismatch. + table.set("SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x295100", + std::vector{swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_MTU", "1500"}}); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + + // Verification should fail if ASIC DB table is missing. + table.del("SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x295100"); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + table.set("SAI_OBJECT_TYPE_ROUTER_INTERFACE:oid:0x295100", + std::vector{ + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_VIRTUAL_ROUTER_ID", "oid:0x0"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS", "00:01:02:03:04:05"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_TYPE", "SAI_ROUTER_INTERFACE_TYPE_PORT"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_PORT_ID", "oid:0x1234"}, + swss::FieldValueTuple{"SAI_ROUTER_INTERFACE_ATTR_MTU", "9100"}}); + + // Verification should fail if SAI attr cannot be constructed. + auto *router_intf_entry_ptr = + GetRouterInterfaceEntry(KeyGenerator::generateRouterInterfaceKey(router_intf_entry.router_interface_id)); + router_intf_entry_ptr->port_name = "Ethernet8"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + router_intf_entry_ptr->port_name = "Ethernet7"; } diff --git a/orchagent/p4orch/tests/test_main.cpp b/orchagent/p4orch/tests/test_main.cpp index f8300a89393..0170588a425 100644 --- a/orchagent/p4orch/tests/test_main.cpp +++ b/orchagent/p4orch/tests/test_main.cpp @@ -1,4 +1,5 @@ -extern "C" { +extern "C" +{ #include "sai.h" } @@ -11,13 +12,13 @@ extern "C" { #include "dbconnector.h" #include "directory.h" #include "flowcounterrouteorch.h" -#include "gtest/gtest.h" #include "mock_sai_virtual_router.h" #include "p4orch.h" #include "portsorch.h" #include "sai_serialize.h" #include "switchorch.h" #include "vrforch.h" +#include "gtest/gtest.h" using ::testing::StrictMock; @@ -28,10 +29,10 @@ sai_object_id_t gVrfOid = 111; sai_object_id_t gTrapGroupStartOid = 20; sai_object_id_t gHostifStartOid = 30; sai_object_id_t gUserDefinedTrapStartOid = 40; -char* gVrfName = "b4-traffic"; -char* gMirrorSession1 = "mirror-session-1"; +char *gVrfName = "b4-traffic"; +char *gMirrorSession1 = "mirror-session-1"; sai_object_id_t kMirrorSessionOid1 = 9001; -char* gMirrorSession2 = "mirror-session-2"; +char *gMirrorSession2 = "mirror-session-2"; sai_object_id_t kMirrorSessionOid2 = 9002; sai_object_id_t gUnderlayIfId; @@ -42,60 +43,64 @@ size_t gMaxBulkSize = DEFAULT_MAX_BULK_SIZE; bool gSyncMode = false; bool gIsNatSupported = false; -PortsOrch* gPortsOrch; -CrmOrch* gCrmOrch; -P4Orch* gP4Orch; -VRFOrch* gVrfOrch; -FlowCounterRouteOrch* gFlowCounterRouteOrch; -SwitchOrch* gSwitchOrch; -Directory gDirectory; -swss::DBConnector* gAppDb; -swss::DBConnector* gStateDb; -swss::DBConnector* gConfigDb; -swss::DBConnector* gCountersDb; +PortsOrch *gPortsOrch; +CrmOrch *gCrmOrch; +P4Orch *gP4Orch; +VRFOrch *gVrfOrch; +FlowCounterRouteOrch *gFlowCounterRouteOrch; +SwitchOrch *gSwitchOrch; +Directory gDirectory; +swss::DBConnector *gAppDb; +swss::DBConnector *gStateDb; +swss::DBConnector *gConfigDb; +swss::DBConnector *gCountersDb; MacAddress gVxlanMacAddress; -sai_router_interface_api_t* sai_router_intfs_api; -sai_neighbor_api_t* sai_neighbor_api; -sai_next_hop_api_t* sai_next_hop_api; -sai_next_hop_group_api_t* sai_next_hop_group_api; -sai_route_api_t* sai_route_api; -sai_acl_api_t* sai_acl_api; -sai_policer_api_t* sai_policer_api; -sai_virtual_router_api_t* sai_virtual_router_api; -sai_hostif_api_t* sai_hostif_api; -sai_hash_api_t* sai_hash_api; -sai_switch_api_t* sai_switch_api; -sai_mirror_api_t* sai_mirror_api; -sai_udf_api_t* sai_udf_api; -sai_tunnel_api_t* sai_tunnel_api; -sai_my_mac_api_t* sai_my_mac_api; -sai_counter_api_t* sai_counter_api; -sai_generic_programmable_api_t* sai_generic_programmable_api; - -task_process_status handleSaiCreateStatus(sai_api_t api, sai_status_t status, - void* context) { - return task_success; +sai_router_interface_api_t *sai_router_intfs_api; +sai_neighbor_api_t *sai_neighbor_api; +sai_next_hop_api_t *sai_next_hop_api; +sai_next_hop_group_api_t *sai_next_hop_group_api; +sai_route_api_t *sai_route_api; +sai_acl_api_t *sai_acl_api; +sai_policer_api_t *sai_policer_api; +sai_virtual_router_api_t *sai_virtual_router_api; +sai_hostif_api_t *sai_hostif_api; +sai_hash_api_t *sai_hash_api; +sai_switch_api_t *sai_switch_api; +sai_mirror_api_t *sai_mirror_api; +sai_udf_api_t *sai_udf_api; +sai_tunnel_api_t *sai_tunnel_api; +sai_my_mac_api_t *sai_my_mac_api; +sai_counter_api_t *sai_counter_api; +sai_generic_programmable_api_t *sai_generic_programmable_api; + +task_process_status handleSaiCreateStatus(sai_api_t api, sai_status_t status, void *context) +{ + return task_success; } -task_process_status handleSaiSetStatus(sai_api_t api, sai_status_t status, - void* context) { - return task_success; +task_process_status handleSaiSetStatus(sai_api_t api, sai_status_t status, void *context) +{ + return task_success; } -task_process_status handleSaiRemoveStatus(sai_api_t api, sai_status_t status, - void* context) { - return task_success; +task_process_status handleSaiRemoveStatus(sai_api_t api, sai_status_t status, void *context) +{ + return task_success; } -task_process_status handleSaiGetStatus(sai_api_t api, sai_status_t status, - void* context) { - return task_success; +task_process_status handleSaiGetStatus(sai_api_t api, sai_status_t status, void *context) +{ + return task_success; } -bool parseHandleSaiStatusFailure(task_process_status status) { return true; } +bool parseHandleSaiStatusFailure(task_process_status status) +{ + return true; +} -namespace { +namespace +{ using ::testing::_; using ::testing::DoAll; @@ -103,135 +108,134 @@ using ::testing::Return; using ::testing::SetArgPointee; using ::testing::StrictMock; -void CreatePort( - const std::string port_name, const uint32_t speed, const uint32_t mtu, - const sai_object_id_t port_oid, Port::Type port_type = Port::PHY, - const sai_port_oper_status_t oper_status = SAI_PORT_OPER_STATUS_DOWN, - const sai_object_id_t vrouter_id = gVirtualRouterId, - const bool admin_state_up = true) { - Port port(port_name, port_type); - port.m_speed = speed; - port.m_mtu = mtu; - if (port_type == Port::LAG) { - port.m_lag_id = port_oid; - } else { - port.m_port_id = port_oid; - } - port.m_vr_id = vrouter_id; - port.m_admin_state_up = admin_state_up; - port.m_oper_status = oper_status; - - gPortsOrch->setPort(port_name, port); +void CreatePort(const std::string port_name, const uint32_t speed, const uint32_t mtu, const sai_object_id_t port_oid, + Port::Type port_type = Port::PHY, const sai_port_oper_status_t oper_status = SAI_PORT_OPER_STATUS_DOWN, + const sai_object_id_t vrouter_id = gVirtualRouterId, const bool admin_state_up = true) +{ + Port port(port_name, port_type); + port.m_speed = speed; + port.m_mtu = mtu; + if (port_type == Port::LAG) + { + port.m_lag_id = port_oid; + } + else + { + port.m_port_id = port_oid; + } + port.m_vr_id = vrouter_id; + port.m_admin_state_up = admin_state_up; + port.m_oper_status = oper_status; + + gPortsOrch->setPort(port_name, port); } -void SetupPorts() { - CreatePort(/*port_name=*/"Ethernet1", /*speed=*/100000, - /*mtu=*/1500, /*port_oid=*/0x112233); - CreatePort(/*port_name=*/"Ethernet2", /*speed=*/400000, - /*mtu=*/4500, /*port_oid=*/0x1fed3); - CreatePort(/*port_name=*/"Ethernet3", /*speed=*/50000, - /*mtu=*/9100, /*port_oid=*/0xaabbccdd); - CreatePort(/*port_name=*/"Ethernet4", /*speed=*/100000, - /*mtu=*/1500, /*port_oid=*/0x9988); - CreatePort(/*port_name=*/"Ethernet5", /*speed=*/400000, - /*mtu=*/4500, /*port_oid=*/0x56789abcdef); - CreatePort(/*port_name=*/"Ethernet6", /*speed=*/50000, - /*mtu=*/9100, /*port_oid=*/0x56789abcdff, Port::PHY, - SAI_PORT_OPER_STATUS_UP); - CreatePort(/*port_name=*/"Ethernet7", /*speed=*/100000, - /*mtu=*/9100, /*port_oid=*/0x1234, /*port_type*/ Port::LAG); - CreatePort(/*port_name=*/"Ethernet8", /*speed=*/100000, - /*mtu=*/9100, /*port_oid=*/0x5678, /*port_type*/ Port::MGMT); - CreatePort(/*port_name=*/"Ethernet9", /*speed=*/50000, - /*mtu=*/9100, /*port_oid=*/0x56789abcfff, Port::PHY, - SAI_PORT_OPER_STATUS_UNKNOWN); +void SetupPorts() +{ + CreatePort(/*port_name=*/"Ethernet1", /*speed=*/100000, + /*mtu=*/1500, /*port_oid=*/0x112233); + CreatePort(/*port_name=*/"Ethernet2", /*speed=*/400000, + /*mtu=*/4500, /*port_oid=*/0x1fed3); + CreatePort(/*port_name=*/"Ethernet3", /*speed=*/50000, + /*mtu=*/9100, /*port_oid=*/0xaabbccdd); + CreatePort(/*port_name=*/"Ethernet4", /*speed=*/100000, + /*mtu=*/1500, /*port_oid=*/0x9988); + CreatePort(/*port_name=*/"Ethernet5", /*speed=*/400000, + /*mtu=*/4500, /*port_oid=*/0x56789abcdef); + CreatePort(/*port_name=*/"Ethernet6", /*speed=*/50000, + /*mtu=*/9100, /*port_oid=*/0x56789abcdff, Port::PHY, SAI_PORT_OPER_STATUS_UP); + CreatePort(/*port_name=*/"Ethernet7", /*speed=*/100000, + /*mtu=*/9100, /*port_oid=*/0x1234, /*port_type*/ Port::LAG); + CreatePort(/*port_name=*/"Ethernet8", /*speed=*/100000, + /*mtu=*/9100, /*port_oid=*/0x5678, /*port_type*/ Port::MGMT); + CreatePort(/*port_name=*/"Ethernet9", /*speed=*/50000, + /*mtu=*/9100, /*port_oid=*/0x56789abcfff, Port::PHY, SAI_PORT_OPER_STATUS_UNKNOWN); } -void AddVrf() { - Table app_vrf_table(gAppDb, APP_VRF_TABLE_NAME); - std::vector attributes; - app_vrf_table.set(gVrfName, attributes); - - StrictMock mock_sai_virtual_router_; - mock_sai_virtual_router = &mock_sai_virtual_router_; - sai_virtual_router_api->create_virtual_router = create_virtual_router; - sai_virtual_router_api->remove_virtual_router = remove_virtual_router; - sai_virtual_router_api->set_virtual_router_attribute = - set_virtual_router_attribute; - EXPECT_CALL(mock_sai_virtual_router_, create_virtual_router(_, _, _, _)) - .WillOnce(DoAll(SetArgPointee<0>(gVrfOid), Return(SAI_STATUS_SUCCESS))); - gVrfOrch->addExistingData(&app_vrf_table); - static_cast(gVrfOrch)->doTask(); +void AddVrf() +{ + Table app_vrf_table(gAppDb, APP_VRF_TABLE_NAME); + std::vector attributes; + app_vrf_table.set(gVrfName, attributes); + + StrictMock mock_sai_virtual_router_; + mock_sai_virtual_router = &mock_sai_virtual_router_; + sai_virtual_router_api->create_virtual_router = create_virtual_router; + sai_virtual_router_api->remove_virtual_router = remove_virtual_router; + sai_virtual_router_api->set_virtual_router_attribute = set_virtual_router_attribute; + EXPECT_CALL(mock_sai_virtual_router_, create_virtual_router(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(gVrfOid), Return(SAI_STATUS_SUCCESS))); + gVrfOrch->addExistingData(&app_vrf_table); + static_cast(gVrfOrch)->doTask(); } -} // namespace - -int main(int argc, char* argv[]) { - gBatchSize = DEFAULT_BATCH_SIZE; - testing::InitGoogleTest(&argc, argv); - - sai_router_interface_api_t router_intfs_api; - sai_neighbor_api_t neighbor_api; - sai_next_hop_api_t next_hop_api; - sai_next_hop_group_api_t next_hop_group_api; - sai_route_api_t route_api; - sai_acl_api_t acl_api; - sai_policer_api_t policer_api; - sai_virtual_router_api_t virtual_router_api; - sai_hostif_api_t hostif_api; - sai_hash_api_t hash_api; - sai_switch_api_t switch_api; - sai_mirror_api_t mirror_api; - sai_udf_api_t udf_api; - sai_my_mac_api_t my_mac_api; - sai_tunnel_api_t tunnel_api; - sai_counter_api_t counter_api; - sai_generic_programmable_api_t generic_programmable_api; - sai_router_intfs_api = &router_intfs_api; - sai_neighbor_api = &neighbor_api; - sai_next_hop_api = &next_hop_api; - sai_next_hop_group_api = &next_hop_group_api; - sai_route_api = &route_api; - sai_acl_api = &acl_api; - sai_policer_api = &policer_api; - sai_virtual_router_api = &virtual_router_api; - sai_hostif_api = &hostif_api; - sai_hash_api = &hash_api; - sai_switch_api = &switch_api; - sai_mirror_api = &mirror_api; - sai_udf_api = &udf_api; - sai_my_mac_api = &my_mac_api; - sai_tunnel_api = &tunnel_api; - sai_counter_api = &counter_api; - sai_generic_programmable_api = &generic_programmable_api; - - swss::DBConnector appl_db("APPL_DB", 0); - swss::DBConnector state_db("STATE_DB", 0); - swss::DBConnector config_db("CONFIG_DB", 0); - swss::DBConnector counters_db("COUNTERS_DB", 0); - gAppDb = &appl_db; - gStateDb = &state_db; - gConfigDb = &config_db; - gCountersDb = &counters_db; - std::vector ports_tables; - PortsOrch ports_orch(gAppDb, gStateDb, ports_tables, gAppDb); - gPortsOrch = &ports_orch; - CrmOrch crm_orch(gConfigDb, CFG_CRM_TABLE_NAME); - - gCrmOrch = &crm_orch; - VRFOrch vrf_orch(gAppDb, APP_VRF_TABLE_NAME, gStateDb, - STATE_VRF_OBJECT_TABLE_NAME); - gVrfOrch = &vrf_orch; - gDirectory.set(static_cast(&vrf_orch)); - - FlowCounterRouteOrch flow_counter_route_orch(gConfigDb, - std::vector{}); - gFlowCounterRouteOrch = &flow_counter_route_orch; - gDirectory.set(static_cast(&flow_counter_route_orch)); - - // Setup ports for all tests. - SetupPorts(); - AddVrf(); - - return RUN_ALL_TESTS(); +} // namespace + +int main(int argc, char *argv[]) +{ + gBatchSize = DEFAULT_BATCH_SIZE; + testing::InitGoogleTest(&argc, argv); + + sai_router_interface_api_t router_intfs_api; + sai_neighbor_api_t neighbor_api; + sai_next_hop_api_t next_hop_api; + sai_next_hop_group_api_t next_hop_group_api; + sai_route_api_t route_api; + sai_acl_api_t acl_api; + sai_policer_api_t policer_api; + sai_virtual_router_api_t virtual_router_api; + sai_hostif_api_t hostif_api; + sai_hash_api_t hash_api; + sai_switch_api_t switch_api; + sai_mirror_api_t mirror_api; + sai_udf_api_t udf_api; + sai_my_mac_api_t my_mac_api; + sai_tunnel_api_t tunnel_api; + sai_counter_api_t counter_api; + sai_generic_programmable_api_t generic_programmable_api; + sai_router_intfs_api = &router_intfs_api; + sai_neighbor_api = &neighbor_api; + sai_next_hop_api = &next_hop_api; + sai_next_hop_group_api = &next_hop_group_api; + sai_route_api = &route_api; + sai_acl_api = &acl_api; + sai_policer_api = &policer_api; + sai_virtual_router_api = &virtual_router_api; + sai_hostif_api = &hostif_api; + sai_hash_api = &hash_api; + sai_switch_api = &switch_api; + sai_mirror_api = &mirror_api; + sai_udf_api = &udf_api; + sai_my_mac_api = &my_mac_api; + sai_tunnel_api = &tunnel_api; + sai_counter_api = &counter_api; + sai_generic_programmable_api = &generic_programmable_api; + + swss::DBConnector appl_db("APPL_DB", 0); + swss::DBConnector state_db("STATE_DB", 0); + swss::DBConnector config_db("CONFIG_DB", 0); + swss::DBConnector counters_db("COUNTERS_DB", 0); + gAppDb = &appl_db; + gStateDb = &state_db; + gConfigDb = &config_db; + gCountersDb = &counters_db; + std::vector ports_tables; + PortsOrch ports_orch(gAppDb, gStateDb, ports_tables, gAppDb); + gPortsOrch = &ports_orch; + CrmOrch crm_orch(gConfigDb, CFG_CRM_TABLE_NAME); + + gCrmOrch = &crm_orch; + VRFOrch vrf_orch(gAppDb, APP_VRF_TABLE_NAME, gStateDb, STATE_VRF_OBJECT_TABLE_NAME); + gVrfOrch = &vrf_orch; + gDirectory.set(static_cast(&vrf_orch)); + + FlowCounterRouteOrch flow_counter_route_orch(gConfigDb, std::vector{}); + gFlowCounterRouteOrch = &flow_counter_route_orch; + gDirectory.set(static_cast(&flow_counter_route_orch)); + + // Setup ports for all tests. + SetupPorts(); + AddVrf(); + + return RUN_ALL_TESTS(); } diff --git a/orchagent/p4orch/tests/wcmp_manager_test.cpp b/orchagent/p4orch/tests/wcmp_manager_test.cpp index 38f74046b60..088264bba40 100644 --- a/orchagent/p4orch/tests/wcmp_manager_test.cpp +++ b/orchagent/p4orch/tests/wcmp_manager_test.cpp @@ -18,24 +18,27 @@ #include "p4orch_util.h" #include "return_code.h" #include "sai_serialize.h" -extern "C" { +extern "C" +{ #include "sai.h" } using ::p4orch::kTableKeyDelimiter; -extern P4Orch* gP4Orch; -extern VRFOrch* gVrfOrch; -extern swss::DBConnector* gAppDb; +extern P4Orch *gP4Orch; +extern VRFOrch *gVrfOrch; +extern swss::DBConnector *gAppDb; extern sai_object_id_t gSwitchId; -extern sai_next_hop_group_api_t* sai_next_hop_group_api; -extern sai_hostif_api_t* sai_hostif_api; -extern sai_switch_api_t* sai_switch_api; +extern sai_next_hop_group_api_t *sai_next_hop_group_api; +extern sai_hostif_api_t *sai_hostif_api; +extern sai_switch_api_t *sai_switch_api; extern sai_object_id_t gSwitchId; -extern sai_acl_api_t* sai_acl_api; +extern sai_acl_api_t *sai_acl_api; -namespace p4orch { -namespace test { +namespace p4orch +{ +namespace test +{ using ::testing::_; using ::testing::DoAll; @@ -46,3052 +49,2473 @@ using ::testing::SetArrayArgument; using ::testing::StrictMock; using ::testing::Truly; -namespace { +namespace +{ -constexpr char* kWcmpGroupId1 = "group-1"; -constexpr char* kWcmpGroupId2 = "group-2"; +constexpr char *kWcmpGroupId1 = "group-1"; +constexpr char *kWcmpGroupId2 = "group-2"; constexpr sai_object_id_t kWcmpGroupOid1 = 10; -constexpr char* kNexthopId1 = "ju1u32m1.atl11:qe-3/7"; +constexpr char *kNexthopId1 = "ju1u32m1.atl11:qe-3/7"; constexpr sai_object_id_t kNexthopOid1 = 1; constexpr sai_object_id_t kWcmpGroupMemberOid1 = 11; -constexpr char* kNexthopId2 = "ju1u32m2.atl11:qe-3/7"; +constexpr char *kNexthopId2 = "ju1u32m2.atl11:qe-3/7"; constexpr sai_object_id_t kNexthopOid2 = 2; constexpr sai_object_id_t kWcmpGroupMemberOid2 = 12; -constexpr char* kNexthopId3 = "ju1u32m3.atl11:qe-3/7"; +constexpr char *kNexthopId3 = "ju1u32m3.atl11:qe-3/7"; constexpr sai_object_id_t kNexthopOid3 = 3; constexpr sai_object_id_t kWcmpGroupMemberOid3 = 13; constexpr sai_object_id_t kWcmpGroupMemberOid4 = 14; constexpr sai_object_id_t kWcmpGroupMemberOid5 = 15; -const std::string kWcmpGroupKey1 = - KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); +const std::string kWcmpGroupKey1 = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); const std::string kNexthopKey1 = KeyGenerator::generateNextHopKey(kNexthopId1); const std::string kNexthopKey2 = KeyGenerator::generateNextHopKey(kNexthopId2); const std::string kNexthopKey3 = KeyGenerator::generateNextHopKey(kNexthopId3); // Matches two SAI attributes. -bool MatchSaiAttribute(const sai_attribute_t& attr, - const sai_attribute_t& exp_attr) { - if (exp_attr.id == SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID) { - if (attr.id != SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID || - attr.value.oid != exp_attr.value.oid) { - return false; +bool MatchSaiAttribute(const sai_attribute_t &attr, const sai_attribute_t &exp_attr) +{ + if (exp_attr.id == SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID) + { + if (attr.id != SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID || attr.value.oid != exp_attr.value.oid) + { + return false; + } } - } - if (exp_attr.id == SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID) { - if (attr.id != SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID || - attr.value.oid != exp_attr.value.oid) { - return false; + if (exp_attr.id == SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID) + { + if (attr.id != SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID || attr.value.oid != exp_attr.value.oid) + { + return false; + } } - } - if (exp_attr.id == SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT) { - if (attr.id != SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT || - attr.value.u32 != exp_attr.value.u32) { - return false; + if (exp_attr.id == SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT) + { + if (attr.id != SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT || attr.value.u32 != exp_attr.value.u32) + { + return false; + } } - } - return true; + return true; } -MATCHER_P(ArrayEq, array, "") { - for (size_t i = 0; i < array.size(); ++i) { - if (arg[i] != array[i]) { - return false; +MATCHER_P(ArrayEq, array, "") +{ + for (size_t i = 0; i < array.size(); ++i) + { + if (arg[i] != array[i]) + { + return false; + } } - } - return true; + return true; } -MATCHER_P(AttrArrayArrayEq, array, "") { - for (size_t i = 0; i < array.size(); ++i) { - for (size_t j = 0; j < array[i].size(); j++) { - if (!MatchSaiAttribute(arg[i][j], array[i][j])) { - return false; - } +MATCHER_P(AttrArrayArrayEq, array, "") +{ + for (size_t i = 0; i < array.size(); ++i) + { + for (size_t j = 0; j < array[i].size(); j++) + { + if (!MatchSaiAttribute(arg[i][j], array[i][j])) + { + return false; + } + } } - } - return true; + return true; } // Matches the next hop group type sai_attribute_t argument. -bool MatchSaiNextHopGroupAttribute(const sai_attribute_t* attr) { - if (attr == nullptr || attr->id != SAI_NEXT_HOP_GROUP_ATTR_TYPE || - attr->value.s32 != SAI_NEXT_HOP_GROUP_TYPE_ECMP) { - return false; - } - return true; +bool MatchSaiNextHopGroupAttribute(const sai_attribute_t *attr) +{ + if (attr == nullptr || attr->id != SAI_NEXT_HOP_GROUP_ATTR_TYPE || attr->value.s32 != SAI_NEXT_HOP_GROUP_TYPE_ECMP) + { + return false; + } + return true; } // Matches the action type sai_attribute_t argument. -bool MatchSaiNextHopGroupMemberAttribute( - const sai_object_id_t expected_next_hop_oid, const int expected_weight, - const sai_object_id_t expected_wcmp_group_oid, - const sai_attribute_t* attr_list) { - if (attr_list == nullptr) { - return false; - } - for (int i = 0; i < 3; ++i) { - switch (attr_list[i].id) { - case SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID: - if (attr_list[i].value.oid != expected_wcmp_group_oid) { - return false; - } - break; - case SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID: - if (attr_list[i].value.oid != expected_next_hop_oid) { - return false; - } - break; - case SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT: - if (attr_list[i].value.u32 != (uint32_t)expected_weight) { - return false; +bool MatchSaiNextHopGroupMemberAttribute(const sai_object_id_t expected_next_hop_oid, const int expected_weight, + const sai_object_id_t expected_wcmp_group_oid, + const sai_attribute_t *attr_list) +{ + if (attr_list == nullptr) + { + return false; + } + for (int i = 0; i < 3; ++i) + { + switch (attr_list[i].id) + { + case SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID: + if (attr_list[i].value.oid != expected_wcmp_group_oid) + { + return false; + } + break; + case SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID: + if (attr_list[i].value.oid != expected_next_hop_oid) + { + return false; + } + break; + case SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT: + if (attr_list[i].value.u32 != (uint32_t)expected_weight) + { + return false; + } + break; + default: + break; } - break; - default: - break; } - } - return true; + return true; } -std::vector GetSaiNextHopGroupMemberAttribute( - sai_object_id_t next_hop_oid, uint32_t weight, sai_object_id_t group_oid) { - std::vector attrs; - sai_attribute_t attr; - attr.id = SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID; - attr.value.oid = group_oid; - attrs.push_back(attr); +std::vector GetSaiNextHopGroupMemberAttribute(sai_object_id_t next_hop_oid, uint32_t weight, + sai_object_id_t group_oid) +{ + std::vector attrs; + sai_attribute_t attr; + attr.id = SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID; + attr.value.oid = group_oid; + attrs.push_back(attr); - attr.id = SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID; - attr.value.oid = next_hop_oid; - attrs.push_back(attr); + attr.id = SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID; + attr.value.oid = next_hop_oid; + attrs.push_back(attr); - attr.id = SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT; - attr.value.u32 = weight; - attrs.push_back(attr); + attr.id = SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT; + attr.value.u32 = weight; + attrs.push_back(attr); - return attrs; + return attrs; } -void VerifyWcmpGroupMemberEntry( - const std::string& expected_next_hop_id, const int expected_weight, - std::shared_ptr wcmp_gm_entry) { - EXPECT_EQ(expected_next_hop_id, wcmp_gm_entry->next_hop_id); - EXPECT_EQ(expected_weight, (int)wcmp_gm_entry->weight); +void VerifyWcmpGroupMemberEntry(const std::string &expected_next_hop_id, const int expected_weight, + std::shared_ptr wcmp_gm_entry) +{ + EXPECT_EQ(expected_next_hop_id, wcmp_gm_entry->next_hop_id); + EXPECT_EQ(expected_weight, (int)wcmp_gm_entry->weight); } -void VerifyWcmpGroupEntry(const P4WcmpGroupEntry& expect_entry, - const P4WcmpGroupEntry& wcmp_entry) { - EXPECT_EQ(expect_entry.wcmp_group_id, wcmp_entry.wcmp_group_id); - ASSERT_EQ(expect_entry.wcmp_group_members.size(), - wcmp_entry.wcmp_group_members.size()); - for (size_t i = 0; i < expect_entry.wcmp_group_members.size(); i++) { - ASSERT_LE(i, wcmp_entry.wcmp_group_members.size()); - auto gm = expect_entry.wcmp_group_members[i]; - VerifyWcmpGroupMemberEntry(gm->next_hop_id, gm->weight, - wcmp_entry.wcmp_group_members[i]); - } +void VerifyWcmpGroupEntry(const P4WcmpGroupEntry &expect_entry, const P4WcmpGroupEntry &wcmp_entry) +{ + EXPECT_EQ(expect_entry.wcmp_group_id, wcmp_entry.wcmp_group_id); + ASSERT_EQ(expect_entry.wcmp_group_members.size(), wcmp_entry.wcmp_group_members.size()); + for (size_t i = 0; i < expect_entry.wcmp_group_members.size(); i++) + { + ASSERT_LE(i, wcmp_entry.wcmp_group_members.size()); + auto gm = expect_entry.wcmp_group_members[i]; + VerifyWcmpGroupMemberEntry(gm->next_hop_id, gm->weight, wcmp_entry.wcmp_group_members[i]); + } } -} // namespace - -class WcmpManagerTest : public ::testing::Test { - protected: - WcmpManagerTest() { - setUpMockApi(); - setUpP4Orch(); - wcmp_group_manager_ = gP4Orch->getWcmpManager(); - p4_oid_mapper_ = wcmp_group_manager_->m_p4OidMapper; - } - - ~WcmpManagerTest() { - EXPECT_CALL(mock_sai_switch_, set_switch_attribute(Eq(gSwitchId), _)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_acl_, remove_acl_table_group(_)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - delete gP4Orch; - delete copp_orch_; - } - - void setUpMockApi() { - // Set up mock stuff for SAI next hop group API structure. - mock_sai_next_hop_group = &mock_sai_next_hop_group_; - mock_sai_switch = &mock_sai_switch_; - mock_sai_hostif = &mock_sai_hostif_; - mock_sai_serialize = &mock_sai_serialize_; - mock_sai_acl = &mock_sai_acl_; - - sai_next_hop_group_api->create_next_hop_group = create_next_hop_group; - sai_next_hop_group_api->remove_next_hop_group = remove_next_hop_group; - sai_next_hop_group_api->create_next_hop_group_member = - create_next_hop_group_member; - sai_next_hop_group_api->remove_next_hop_group_member = - remove_next_hop_group_member; - sai_next_hop_group_api->set_next_hop_group_member_attribute = - set_next_hop_group_member_attribute; - sai_next_hop_group_api->create_next_hop_group_members = - create_next_hop_group_members; - sai_next_hop_group_api->remove_next_hop_group_members = - remove_next_hop_group_members; - - sai_hostif_api->create_hostif_table_entry = mock_create_hostif_table_entry; - sai_hostif_api->create_hostif_trap = mock_create_hostif_trap; - sai_switch_api->get_switch_attribute = mock_get_switch_attribute; - sai_switch_api->set_switch_attribute = mock_set_switch_attribute; - sai_acl_api->create_acl_table_group = create_acl_table_group; - sai_acl_api->remove_acl_table_group = remove_acl_table_group; - } - - void setUpP4Orch() { - // init copp orch - EXPECT_CALL(mock_sai_hostif_, create_hostif_table_entry(_, _, _, _)) - .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_hostif_, create_hostif_trap(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_CALL(mock_sai_switch_, get_switch_attribute(_, _, _)) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - copp_orch_ = new CoppOrch(gAppDb, APP_COPP_TABLE_NAME); - - // init P4 orch - std::vector p4_tables; - gP4Orch = new P4Orch(gAppDb, p4_tables, gVrfOrch, copp_orch_); - } - - void Enqueue(const swss::KeyOpFieldsValuesTuple& entry) { - wcmp_group_manager_->enqueue(APP_P4RT_WCMP_GROUP_TABLE_NAME, entry); - } - - void Drain() { wcmp_group_manager_->drain(); } - - std::string VerifyState(const std::string& key, - const std::vector& tuple) { - return wcmp_group_manager_->verifyState(key, tuple); - } - - ReturnCode ProcessAddRequest(P4WcmpGroupEntry* app_db_entry) { - return wcmp_group_manager_->processAddRequest(app_db_entry); - } - - void HandlePortStatusChangeNotification(const std::string& op, - const std::string& data) { - gP4Orch->handlePortStatusChangeNotification(op, data); - } - - void PruneNextHops(const std::string& port) { - wcmp_group_manager_->pruneNextHops(port); - } - - void RestorePrunedNextHops(const std::string& port) { - wcmp_group_manager_->restorePrunedNextHops(port); - } - - bool VerifyWcmpGroupMemberInPortMap( - std::shared_ptr gm, bool expected_member_present, - long unsigned int expected_set_size) { - auto it = wcmp_group_manager_->port_name_to_wcmp_group_member_map.find( - gm->watch_port); - if (it != wcmp_group_manager_->port_name_to_wcmp_group_member_map.end()) { - auto& s = wcmp_group_manager_ - ->port_name_to_wcmp_group_member_map[gm->watch_port]; - if (s.size() != expected_set_size) return false; - return expected_member_present ? (s.count(gm) > 0) : (s.count(gm) == 0); - } else { - return !expected_member_present; +} // namespace + +class WcmpManagerTest : public ::testing::Test +{ + protected: + WcmpManagerTest() + { + setUpMockApi(); + setUpP4Orch(); + wcmp_group_manager_ = gP4Orch->getWcmpManager(); + p4_oid_mapper_ = wcmp_group_manager_->m_p4OidMapper; + } + + ~WcmpManagerTest() + { + EXPECT_CALL(mock_sai_switch_, set_switch_attribute(Eq(gSwitchId), _)) + .WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_acl_, remove_acl_table_group(_)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + delete gP4Orch; + delete copp_orch_; } - return false; - } - - ReturnCode ProcessUpdateRequest(P4WcmpGroupEntry* app_db_entry) { - return wcmp_group_manager_->processUpdateRequest(app_db_entry); - } - - ReturnCode RemoveWcmpGroup(const std::string& wcmp_group_id) { - return wcmp_group_manager_->removeWcmpGroup(wcmp_group_id); - } - - P4WcmpGroupEntry* GetWcmpGroupEntry(const std::string& wcmp_group_id) { - return wcmp_group_manager_->getWcmpGroupEntry(wcmp_group_id); - } - - ReturnCodeOr DeserializeP4WcmpGroupAppDbEntry( - const std::string& key, - const std::vector& attributes) { - return wcmp_group_manager_->deserializeP4WcmpGroupAppDbEntry(key, - attributes); - } - - // Adds the WCMP group entry via WcmpManager::ProcessAddRequest(). This - // function also takes care of all the dependencies of the WCMP group entry. - // Returns a valid pointer to WCMP group entry on success. - P4WcmpGroupEntry AddWcmpGroupEntry1(); - P4WcmpGroupEntry AddWcmpGroupEntryWithWatchport(const std::string& port, - const bool oper_up = false); - P4WcmpGroupEntry getDefaultWcmpGroupEntryForTest(); - std::shared_ptr createWcmpGroupMemberEntry( - const std::string& next_hop_id, const int weight); - std::shared_ptr - createWcmpGroupMemberEntryWithWatchport(const std::string& next_hop_id, - const int weight, - const std::string& watch_port, - const std::string& wcmp_group_id, - const sai_object_id_t next_hop_oid); - - StrictMock mock_sai_next_hop_group_; - StrictMock mock_sai_switch_; - StrictMock mock_sai_hostif_; - StrictMock mock_sai_serialize_; - StrictMock mock_sai_acl_; - P4OidMapper* p4_oid_mapper_; - WcmpManager* wcmp_group_manager_; - CoppOrch* copp_orch_; + + void setUpMockApi() + { + // Set up mock stuff for SAI next hop group API structure. + mock_sai_next_hop_group = &mock_sai_next_hop_group_; + mock_sai_switch = &mock_sai_switch_; + mock_sai_hostif = &mock_sai_hostif_; + mock_sai_serialize = &mock_sai_serialize_; + mock_sai_acl = &mock_sai_acl_; + + sai_next_hop_group_api->create_next_hop_group = create_next_hop_group; + sai_next_hop_group_api->remove_next_hop_group = remove_next_hop_group; + sai_next_hop_group_api->create_next_hop_group_member = create_next_hop_group_member; + sai_next_hop_group_api->remove_next_hop_group_member = remove_next_hop_group_member; + sai_next_hop_group_api->set_next_hop_group_member_attribute = set_next_hop_group_member_attribute; + sai_next_hop_group_api->create_next_hop_group_members = create_next_hop_group_members; + sai_next_hop_group_api->remove_next_hop_group_members = remove_next_hop_group_members; + + sai_hostif_api->create_hostif_table_entry = mock_create_hostif_table_entry; + sai_hostif_api->create_hostif_trap = mock_create_hostif_trap; + sai_switch_api->get_switch_attribute = mock_get_switch_attribute; + sai_switch_api->set_switch_attribute = mock_set_switch_attribute; + sai_acl_api->create_acl_table_group = create_acl_table_group; + sai_acl_api->remove_acl_table_group = remove_acl_table_group; + } + + void setUpP4Orch() + { + // init copp orch + EXPECT_CALL(mock_sai_hostif_, create_hostif_table_entry(_, _, _, _)).WillRepeatedly(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_hostif_, create_hostif_trap(_, _, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_CALL(mock_sai_switch_, get_switch_attribute(_, _, _)).WillOnce(Return(SAI_STATUS_SUCCESS)); + copp_orch_ = new CoppOrch(gAppDb, APP_COPP_TABLE_NAME); + + // init P4 orch + std::vector p4_tables; + gP4Orch = new P4Orch(gAppDb, p4_tables, gVrfOrch, copp_orch_); + } + + void Enqueue(const swss::KeyOpFieldsValuesTuple &entry) + { + wcmp_group_manager_->enqueue(APP_P4RT_WCMP_GROUP_TABLE_NAME, entry); + } + + void Drain() + { + wcmp_group_manager_->drain(); + } + + std::string VerifyState(const std::string &key, const std::vector &tuple) + { + return wcmp_group_manager_->verifyState(key, tuple); + } + + ReturnCode ProcessAddRequest(P4WcmpGroupEntry *app_db_entry) + { + return wcmp_group_manager_->processAddRequest(app_db_entry); + } + + void HandlePortStatusChangeNotification(const std::string &op, const std::string &data) + { + gP4Orch->handlePortStatusChangeNotification(op, data); + } + + void PruneNextHops(const std::string &port) + { + wcmp_group_manager_->pruneNextHops(port); + } + + void RestorePrunedNextHops(const std::string &port) + { + wcmp_group_manager_->restorePrunedNextHops(port); + } + + bool VerifyWcmpGroupMemberInPortMap(std::shared_ptr gm, bool expected_member_present, + long unsigned int expected_set_size) + { + auto it = wcmp_group_manager_->port_name_to_wcmp_group_member_map.find(gm->watch_port); + if (it != wcmp_group_manager_->port_name_to_wcmp_group_member_map.end()) + { + auto &s = wcmp_group_manager_->port_name_to_wcmp_group_member_map[gm->watch_port]; + if (s.size() != expected_set_size) + return false; + return expected_member_present ? (s.count(gm) > 0) : (s.count(gm) == 0); + } + else + { + return !expected_member_present; + } + return false; + } + + ReturnCode ProcessUpdateRequest(P4WcmpGroupEntry *app_db_entry) + { + return wcmp_group_manager_->processUpdateRequest(app_db_entry); + } + + ReturnCode RemoveWcmpGroup(const std::string &wcmp_group_id) + { + return wcmp_group_manager_->removeWcmpGroup(wcmp_group_id); + } + + P4WcmpGroupEntry *GetWcmpGroupEntry(const std::string &wcmp_group_id) + { + return wcmp_group_manager_->getWcmpGroupEntry(wcmp_group_id); + } + + ReturnCodeOr DeserializeP4WcmpGroupAppDbEntry( + const std::string &key, const std::vector &attributes) + { + return wcmp_group_manager_->deserializeP4WcmpGroupAppDbEntry(key, attributes); + } + + // Adds the WCMP group entry via WcmpManager::ProcessAddRequest(). This + // function also takes care of all the dependencies of the WCMP group entry. + // Returns a valid pointer to WCMP group entry on success. + P4WcmpGroupEntry AddWcmpGroupEntry1(); + P4WcmpGroupEntry AddWcmpGroupEntryWithWatchport(const std::string &port, const bool oper_up = false); + P4WcmpGroupEntry getDefaultWcmpGroupEntryForTest(); + std::shared_ptr createWcmpGroupMemberEntry(const std::string &next_hop_id, + const int weight); + std::shared_ptr createWcmpGroupMemberEntryWithWatchport(const std::string &next_hop_id, + const int weight, + const std::string &watch_port, + const std::string &wcmp_group_id, + const sai_object_id_t next_hop_oid); + + StrictMock mock_sai_next_hop_group_; + StrictMock mock_sai_switch_; + StrictMock mock_sai_hostif_; + StrictMock mock_sai_serialize_; + StrictMock mock_sai_acl_; + P4OidMapper *p4_oid_mapper_; + WcmpManager *wcmp_group_manager_; + CoppOrch *copp_orch_; }; -P4WcmpGroupEntry WcmpManagerTest::getDefaultWcmpGroupEntryForTest() { - P4WcmpGroupEntry app_db_entry; - app_db_entry.wcmp_group_id = kWcmpGroupId1; - std::shared_ptr gm1 = - std::make_shared(); - gm1->wcmp_group_id = kWcmpGroupId1; - gm1->next_hop_id = kNexthopId1; - gm1->weight = 2; - app_db_entry.wcmp_group_members.push_back(gm1); - std::shared_ptr gm2 = - std::make_shared(); - gm2->wcmp_group_id = kWcmpGroupId1; - gm2->next_hop_id = kNexthopId2; - gm2->weight = 1; - app_db_entry.wcmp_group_members.push_back(gm2); - return app_db_entry; +P4WcmpGroupEntry WcmpManagerTest::getDefaultWcmpGroupEntryForTest() +{ + P4WcmpGroupEntry app_db_entry; + app_db_entry.wcmp_group_id = kWcmpGroupId1; + std::shared_ptr gm1 = std::make_shared(); + gm1->wcmp_group_id = kWcmpGroupId1; + gm1->next_hop_id = kNexthopId1; + gm1->weight = 2; + app_db_entry.wcmp_group_members.push_back(gm1); + std::shared_ptr gm2 = std::make_shared(); + gm2->wcmp_group_id = kWcmpGroupId1; + gm2->next_hop_id = kNexthopId2; + gm2->weight = 1; + app_db_entry.wcmp_group_members.push_back(gm2); + return app_db_entry; } -P4WcmpGroupEntry WcmpManagerTest::AddWcmpGroupEntryWithWatchport( - const std::string& port, const bool oper_up) { - P4WcmpGroupEntry app_db_entry; - app_db_entry.wcmp_group_id = kWcmpGroupId1; - std::shared_ptr gm1 = - std::make_shared(); - gm1->next_hop_id = kNexthopId1; - gm1->weight = 2; - gm1->watch_port = port; - gm1->wcmp_group_id = kWcmpGroupId1; - app_db_entry.wcmp_group_members.push_back(gm1); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); - EXPECT_CALL( - mock_sai_next_hop_group_, - create_next_hop_group(_, Eq(gSwitchId), Eq(1), - Truly(std::bind(MatchSaiNextHopGroupAttribute, - std::placeholders::_1)))) - .WillOnce( - DoAll(SetArgPointee<0>(kWcmpGroupOid1), Return(SAI_STATUS_SUCCESS))); - // For members with non empty watchport field, member creation in SAI happens - // for operationally up ports only.. - std::vector return_oids{kWcmpGroupMemberOid1}; - std::vector exp_status{SAI_STATUS_SUCCESS}; - if (oper_up) { - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - } - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRequest(&app_db_entry)); - EXPECT_NE(nullptr, GetWcmpGroupEntry(kWcmpGroupId1)); - return app_db_entry; +P4WcmpGroupEntry WcmpManagerTest::AddWcmpGroupEntryWithWatchport(const std::string &port, const bool oper_up) +{ + P4WcmpGroupEntry app_db_entry; + app_db_entry.wcmp_group_id = kWcmpGroupId1; + std::shared_ptr gm1 = std::make_shared(); + gm1->next_hop_id = kNexthopId1; + gm1->weight = 2; + gm1->watch_port = port; + gm1->wcmp_group_id = kWcmpGroupId1; + app_db_entry.wcmp_group_members.push_back(gm1); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group(_, Eq(gSwitchId), Eq(1), + Truly(std::bind(MatchSaiNextHopGroupAttribute, std::placeholders::_1)))) + .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupOid1), Return(SAI_STATUS_SUCCESS))); + // For members with non empty watchport field, member creation in SAI happens + // for operationally up ports only.. + std::vector return_oids{kWcmpGroupMemberOid1}; + std::vector exp_status{SAI_STATUS_SUCCESS}; + if (oper_up) + { + EXPECT_CALL( + mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + } + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRequest(&app_db_entry)); + EXPECT_NE(nullptr, GetWcmpGroupEntry(kWcmpGroupId1)); + return app_db_entry; } -P4WcmpGroupEntry WcmpManagerTest::AddWcmpGroupEntry1() { - P4WcmpGroupEntry app_db_entry = getDefaultWcmpGroupEntryForTest(); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, kNexthopOid2); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey3, kNexthopOid3); - EXPECT_CALL( - mock_sai_next_hop_group_, - create_next_hop_group(_, Eq(gSwitchId), Eq(1), - Truly(std::bind(MatchSaiNextHopGroupAttribute, - std::placeholders::_1)))) - .WillOnce( - DoAll(SetArgPointee<0>(kWcmpGroupOid1), Return(SAI_STATUS_SUCCESS))); - std::vector return_oids{kWcmpGroupMemberOid1, - kWcmpGroupMemberOid2}; - std::vector exp_status{SAI_STATUS_SUCCESS, SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, - kWcmpGroupOid1), - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_status.begin(), exp_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRequest(&app_db_entry)); - EXPECT_NE(nullptr, GetWcmpGroupEntry(kWcmpGroupId1)); - return app_db_entry; +P4WcmpGroupEntry WcmpManagerTest::AddWcmpGroupEntry1() +{ + P4WcmpGroupEntry app_db_entry = getDefaultWcmpGroupEntryForTest(); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, kNexthopOid2); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey3, kNexthopOid3); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group(_, Eq(gSwitchId), Eq(1), + Truly(std::bind(MatchSaiNextHopGroupAttribute, std::placeholders::_1)))) + .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupOid1), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids{kWcmpGroupMemberOid1, kWcmpGroupMemberOid2}; + std::vector exp_status{SAI_STATUS_SUCCESS, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, kWcmpGroupOid1), + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessAddRequest(&app_db_entry)); + EXPECT_NE(nullptr, GetWcmpGroupEntry(kWcmpGroupId1)); + return app_db_entry; } // Create a WCMP group member with the requested attributes -std::shared_ptr -WcmpManagerTest::createWcmpGroupMemberEntry(const std::string& next_hop_id, - const int weight) { - std::shared_ptr gm = - std::make_shared(); - gm->next_hop_id = next_hop_id; - gm->weight = weight; - return gm; +std::shared_ptr WcmpManagerTest::createWcmpGroupMemberEntry(const std::string &next_hop_id, + const int weight) +{ + std::shared_ptr gm = std::make_shared(); + gm->next_hop_id = next_hop_id; + gm->weight = weight; + return gm; } // Create a WCMP group member that uses a watchport with the requested // attributes -std::shared_ptr -WcmpManagerTest::createWcmpGroupMemberEntryWithWatchport( - const std::string& next_hop_id, const int weight, - const std::string& watch_port, const std::string& wcmp_group_id, - const sai_object_id_t next_hop_oid) { - std::shared_ptr gm = - std::make_shared(); - gm->next_hop_id = next_hop_id; - gm->weight = weight; - gm->watch_port = watch_port; - gm->wcmp_group_id = wcmp_group_id; - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(next_hop_id), - next_hop_oid); - return gm; +std::shared_ptr WcmpManagerTest::createWcmpGroupMemberEntryWithWatchport( + const std::string &next_hop_id, const int weight, const std::string &watch_port, const std::string &wcmp_group_id, + const sai_object_id_t next_hop_oid) +{ + std::shared_ptr gm = std::make_shared(); + gm->next_hop_id = next_hop_id; + gm->weight = weight; + gm->watch_port = watch_port; + gm->wcmp_group_id = wcmp_group_id; + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(next_hop_id), next_hop_oid); + return gm; } -TEST_F(WcmpManagerTest, CreateWcmpGroup) { - AddWcmpGroupEntry1(); - P4WcmpGroupEntry expect_entry = {.wcmp_group_id = kWcmpGroupId1, - .wcmp_group_members = {}}; - std::shared_ptr gm_entry1 = - createWcmpGroupMemberEntry(kNexthopId1, 2); - expect_entry.wcmp_group_members.push_back(gm_entry1); - std::shared_ptr gm_entry2 = - createWcmpGroupMemberEntry(kNexthopId2, 1); - expect_entry.wcmp_group_members.push_back(gm_entry2); - VerifyWcmpGroupEntry(expect_entry, *GetWcmpGroupEntry(kWcmpGroupId1)); +TEST_F(WcmpManagerTest, CreateWcmpGroup) +{ + AddWcmpGroupEntry1(); + P4WcmpGroupEntry expect_entry = {.wcmp_group_id = kWcmpGroupId1, .wcmp_group_members = {}}; + std::shared_ptr gm_entry1 = createWcmpGroupMemberEntry(kNexthopId1, 2); + expect_entry.wcmp_group_members.push_back(gm_entry1); + std::shared_ptr gm_entry2 = createWcmpGroupMemberEntry(kNexthopId2, 1); + expect_entry.wcmp_group_members.push_back(gm_entry2); + VerifyWcmpGroupEntry(expect_entry, *GetWcmpGroupEntry(kWcmpGroupId1)); } -TEST_F(WcmpManagerTest, CreateWcmpGroupFailsWhenCreateGroupMemberSaiCallFails) { - P4WcmpGroupEntry app_db_entry = getDefaultWcmpGroupEntryForTest(); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, kNexthopOid2); - // WCMP group creation fails when one of the group member creation fails - EXPECT_CALL(mock_sai_next_hop_group_, create_next_hop_group(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kWcmpGroupOid1), Return(SAI_STATUS_SUCCESS))); - std::vector return_oids{kWcmpGroupMemberOid1, - SAI_NULL_OBJECT_ID}; - std::vector exp_create_status{SAI_STATUS_SUCCESS, - SAI_STATUS_ITEM_NOT_FOUND}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, - kWcmpGroupOid1), - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_ITEM_NOT_FOUND))); - std::vector exp_remove_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group(Eq(kWcmpGroupOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddRequest(&app_db_entry)); - std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); - auto* wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); - EXPECT_EQ(nullptr, wcmp_group_entry_ptr); - EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &ref_cnt)); - EXPECT_EQ(0, ref_cnt); +TEST_F(WcmpManagerTest, CreateWcmpGroupFailsWhenCreateGroupMemberSaiCallFails) +{ + P4WcmpGroupEntry app_db_entry = getDefaultWcmpGroupEntryForTest(); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, kNexthopOid2); + // WCMP group creation fails when one of the group member creation fails + EXPECT_CALL(mock_sai_next_hop_group_, create_next_hop_group(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupOid1), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids{kWcmpGroupMemberOid1, SAI_NULL_OBJECT_ID}; + std::vector exp_create_status{SAI_STATUS_SUCCESS, SAI_STATUS_ITEM_NOT_FOUND}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, kWcmpGroupOid1), + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_ITEM_NOT_FOUND))); + std::vector exp_remove_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group(Eq(kWcmpGroupOid1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddRequest(&app_db_entry)); + std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); + auto *wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); + EXPECT_EQ(nullptr, wcmp_group_entry_ptr); + EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &ref_cnt)); + EXPECT_EQ(0, ref_cnt); } -TEST_F( - WcmpManagerTest, - CreateWcmpGroupFailsWhenCreateGroupMemberSaiCallFailsPlusGroupMemberRecoveryFails) { - P4WcmpGroupEntry app_db_entry = getDefaultWcmpGroupEntryForTest(); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, kNexthopOid2); - // WCMP group creation fails when one of the group member creation fails - EXPECT_CALL(mock_sai_next_hop_group_, create_next_hop_group(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kWcmpGroupOid1), Return(SAI_STATUS_SUCCESS))); - std::vector return_oids{kWcmpGroupMemberOid1, - SAI_NULL_OBJECT_ID}; - std::vector exp_create_status{SAI_STATUS_SUCCESS, - SAI_STATUS_ITEM_NOT_FOUND}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, - kWcmpGroupOid1), - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_ITEM_NOT_FOUND))); - std::vector exp_remove_status{SAI_STATUS_FAILURE}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_FAILURE))); - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group(Eq(kWcmpGroupOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddRequest(&app_db_entry)); +TEST_F(WcmpManagerTest, CreateWcmpGroupFailsWhenCreateGroupMemberSaiCallFailsPlusGroupMemberRecoveryFails) +{ + P4WcmpGroupEntry app_db_entry = getDefaultWcmpGroupEntryForTest(); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, kNexthopOid2); + // WCMP group creation fails when one of the group member creation fails + EXPECT_CALL(mock_sai_next_hop_group_, create_next_hop_group(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupOid1), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids{kWcmpGroupMemberOid1, SAI_NULL_OBJECT_ID}; + std::vector exp_create_status{SAI_STATUS_SUCCESS, SAI_STATUS_ITEM_NOT_FOUND}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, kWcmpGroupOid1), + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_ITEM_NOT_FOUND))); + std::vector exp_remove_status{SAI_STATUS_FAILURE}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_FAILURE))); + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group(Eq(kWcmpGroupOid1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddRequest(&app_db_entry)); } -TEST_F( - WcmpManagerTest, - CreateWcmpGroupFailsWhenCreateGroupMemberSaiCallFailsPlusGroupRecoveryFails) { - P4WcmpGroupEntry app_db_entry = getDefaultWcmpGroupEntryForTest(); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, kNexthopOid2); - // WCMP group creation fails when one of the group member creation fails - EXPECT_CALL(mock_sai_next_hop_group_, create_next_hop_group(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kWcmpGroupOid1), Return(SAI_STATUS_SUCCESS))); - std::vector return_oids{kWcmpGroupMemberOid1, - SAI_NULL_OBJECT_ID}; - std::vector exp_create_status{SAI_STATUS_SUCCESS, - SAI_STATUS_ITEM_NOT_FOUND}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, - kWcmpGroupOid1), - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_ITEM_NOT_FOUND))); - std::vector exp_remove_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group(Eq(kWcmpGroupOid1))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddRequest(&app_db_entry)); +TEST_F(WcmpManagerTest, CreateWcmpGroupFailsWhenCreateGroupMemberSaiCallFailsPlusGroupRecoveryFails) +{ + P4WcmpGroupEntry app_db_entry = getDefaultWcmpGroupEntryForTest(); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, kNexthopOid2); + // WCMP group creation fails when one of the group member creation fails + EXPECT_CALL(mock_sai_next_hop_group_, create_next_hop_group(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupOid1), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids{kWcmpGroupMemberOid1, SAI_NULL_OBJECT_ID}; + std::vector exp_create_status{SAI_STATUS_SUCCESS, SAI_STATUS_ITEM_NOT_FOUND}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, kWcmpGroupOid1), + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_ITEM_NOT_FOUND))); + std::vector exp_remove_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group(Eq(kWcmpGroupOid1))) + .WillOnce(Return(SAI_STATUS_FAILURE)); + + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddRequest(&app_db_entry)); } -TEST_F(WcmpManagerTest, CreateWcmpGroupFailsWhenCreateGroupSaiCallFails) { - P4WcmpGroupEntry app_db_entry = getDefaultWcmpGroupEntryForTest(); - app_db_entry.wcmp_group_members.pop_back(); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); - // WCMP group creation fails when one of the group member creation fails - EXPECT_CALL(mock_sai_next_hop_group_, create_next_hop_group(_, _, _, _)) - .WillOnce(Return(SAI_STATUS_TABLE_FULL)); - - EXPECT_EQ(StatusCode::SWSS_RC_FULL, ProcessAddRequest(&app_db_entry)); - std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); - auto* wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); - EXPECT_EQ(nullptr, wcmp_group_entry_ptr); - EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(0, ref_cnt); +TEST_F(WcmpManagerTest, CreateWcmpGroupFailsWhenCreateGroupSaiCallFails) +{ + P4WcmpGroupEntry app_db_entry = getDefaultWcmpGroupEntryForTest(); + app_db_entry.wcmp_group_members.pop_back(); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); + // WCMP group creation fails when one of the group member creation fails + EXPECT_CALL(mock_sai_next_hop_group_, create_next_hop_group(_, _, _, _)).WillOnce(Return(SAI_STATUS_TABLE_FULL)); + + EXPECT_EQ(StatusCode::SWSS_RC_FULL, ProcessAddRequest(&app_db_entry)); + std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); + auto *wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); + EXPECT_EQ(nullptr, wcmp_group_entry_ptr); + EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(0, ref_cnt); } -TEST_F(WcmpManagerTest, RemoveWcmpGroupFailsWhenRefcountIsGtThanZero) { - AddWcmpGroupEntry1(); - p4_oid_mapper_->increaseRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1)); - EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, RemoveWcmpGroup(kWcmpGroupId1)); - EXPECT_NE(nullptr, GetWcmpGroupEntry(kWcmpGroupId1)); +TEST_F(WcmpManagerTest, RemoveWcmpGroupFailsWhenRefcountIsGtThanZero) +{ + AddWcmpGroupEntry1(); + p4_oid_mapper_->increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1)); + EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, RemoveWcmpGroup(kWcmpGroupId1)); + EXPECT_NE(nullptr, GetWcmpGroupEntry(kWcmpGroupId1)); } -TEST_F(WcmpManagerTest, RemoveWcmpGroupFailsWhenNotExist) { - EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, RemoveWcmpGroup(kWcmpGroupId1)); +TEST_F(WcmpManagerTest, RemoveWcmpGroupFailsWhenNotExist) +{ + EXPECT_EQ(StatusCode::SWSS_RC_NOT_FOUND, RemoveWcmpGroup(kWcmpGroupId1)); } -TEST_F(WcmpManagerTest, RemoveWcmpGroupFailsWhenSaiCallFails) { - P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntry1(); - std::vector exp_remove_status{SAI_STATUS_SUCCESS, - SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(2), - ArrayEq(std::vector{kWcmpGroupMemberOid2, - kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group(Eq(kWcmpGroupOid1))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - std::vector return_oids{kWcmpGroupMemberOid1, - kWcmpGroupMemberOid2}; - std::vector exp_create_status{SAI_STATUS_SUCCESS, - SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, - kWcmpGroupOid1), - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, RemoveWcmpGroup(kWcmpGroupId1)); +TEST_F(WcmpManagerTest, RemoveWcmpGroupFailsWhenSaiCallFails) +{ + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntry1(); + std::vector exp_remove_status{SAI_STATUS_SUCCESS, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members( + Eq(2), ArrayEq(std::vector{kWcmpGroupMemberOid2, kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group(Eq(kWcmpGroupOid1))) + .WillOnce(Return(SAI_STATUS_FAILURE)); + std::vector return_oids{kWcmpGroupMemberOid1, kWcmpGroupMemberOid2}; + std::vector exp_create_status{SAI_STATUS_SUCCESS, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, kWcmpGroupOid1), + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, RemoveWcmpGroup(kWcmpGroupId1)); } -TEST_F(WcmpManagerTest, RemoveWcmpGroupFailsWhenMemberRemovalFails) { - P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntry1(); - std::vector exp_remove_status{SAI_STATUS_FAILURE, - SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(2), - ArrayEq(std::vector{kWcmpGroupMemberOid2, - kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_FAILURE))); - std::vector return_oids{kWcmpGroupMemberOid1}; - std::vector exp_create_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, RemoveWcmpGroup(kWcmpGroupId1)); +TEST_F(WcmpManagerTest, RemoveWcmpGroupFailsWhenMemberRemovalFails) +{ + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntry1(); + std::vector exp_remove_status{SAI_STATUS_FAILURE, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members( + Eq(2), ArrayEq(std::vector{kWcmpGroupMemberOid2, kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_FAILURE))); + std::vector return_oids{kWcmpGroupMemberOid1}; + std::vector exp_create_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, RemoveWcmpGroup(kWcmpGroupId1)); } -TEST_F(WcmpManagerTest, - RemoveWcmpGroupFailsWhenMemberRemovalFailsPlusRecoveryFails) { - P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntry1(); - std::vector exp_remove_status{SAI_STATUS_FAILURE, - SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(2), - ArrayEq(std::vector{kWcmpGroupMemberOid2, - kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_FAILURE))); - std::vector return_oids{SAI_NULL_OBJECT_ID}; - std::vector exp_create_status{SAI_STATUS_FAILURE}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_FAILURE))); - // TODO: Expect critical state. - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, RemoveWcmpGroup(kWcmpGroupId1)); +TEST_F(WcmpManagerTest, RemoveWcmpGroupFailsWhenMemberRemovalFailsPlusRecoveryFails) +{ + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntry1(); + std::vector exp_remove_status{SAI_STATUS_FAILURE, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members( + Eq(2), ArrayEq(std::vector{kWcmpGroupMemberOid2, kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_FAILURE))); + std::vector return_oids{SAI_NULL_OBJECT_ID}; + std::vector exp_create_status{SAI_STATUS_FAILURE}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_FAILURE))); + // TODO: Expect critical state. + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, RemoveWcmpGroup(kWcmpGroupId1)); } -TEST_F(WcmpManagerTest, UpdateWcmpGroupMembersSucceed) { - AddWcmpGroupEntry1(); - // Update WCMP group member with nexthop_id=kNexthopId1 weight to 3, - // nexthop_id=kNexthopId2 weight to 15. - P4WcmpGroupEntry wcmp_group = {.wcmp_group_id = kWcmpGroupId1, - .wcmp_group_members = {}}; - std::shared_ptr gm1 = - createWcmpGroupMemberEntry(kNexthopId1, 3); - std::shared_ptr gm2 = - createWcmpGroupMemberEntry(kNexthopId2, 15); - wcmp_group.wcmp_group_members.push_back(gm1); - wcmp_group.wcmp_group_members.push_back(gm2); - std::vector exp_remove_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid2}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - std::vector return_oids_4{kWcmpGroupMemberOid4}; - std::vector return_oids_5{kWcmpGroupMemberOid5}; - std::vector exp_create_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 3, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_4.begin(), return_oids_4.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 15, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_5.begin(), return_oids_5.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_TRUE(ProcessUpdateRequest(&wcmp_group).ok()); - VerifyWcmpGroupEntry(wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); - uint32_t wcmp_group_refcount = 0; - uint32_t nexthop_refcount = 0; - ASSERT_TRUE(p4_oid_mapper_->getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); - EXPECT_EQ(2, wcmp_group_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - // Remove group member with nexthop_id=kNexthopId1 - wcmp_group.wcmp_group_members.clear(); - gm2 = createWcmpGroupMemberEntry(kNexthopId2, 15); - wcmp_group.wcmp_group_members.push_back(gm2); - exp_remove_status = {SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid4}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid5}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - std::vector return_oids_2{kWcmpGroupMemberOid2}; - exp_create_status = {SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 15, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_2.begin(), return_oids_2.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_TRUE(ProcessUpdateRequest(&wcmp_group).ok()); - VerifyWcmpGroupEntry(wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); - ASSERT_TRUE(p4_oid_mapper_->getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); - EXPECT_EQ(1, wcmp_group_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &nexthop_refcount)); - EXPECT_EQ(0, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - // Add group member with nexthop_id=kNexthopId1 and weight=20 - wcmp_group.wcmp_group_members.clear(); - std::shared_ptr updated_gm2 = - createWcmpGroupMemberEntry(kNexthopId2, 15); - std::shared_ptr updated_gm1 = - createWcmpGroupMemberEntry(kNexthopId1, 20); - wcmp_group.wcmp_group_members.push_back(updated_gm1); - wcmp_group.wcmp_group_members.push_back(updated_gm2); - exp_remove_status = {SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid2}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - std::vector return_oids_1{kWcmpGroupMemberOid1}; - exp_create_status = {SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 20, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_1.begin(), return_oids_1.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 15, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_5.begin(), return_oids_5.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_TRUE(ProcessUpdateRequest(&wcmp_group).ok()); - VerifyWcmpGroupEntry(wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); - ASSERT_TRUE(p4_oid_mapper_->getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); - EXPECT_EQ(2, wcmp_group_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - - // Update WCMP without group members - wcmp_group.wcmp_group_members.clear(); - exp_remove_status = {SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid5}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_TRUE(ProcessUpdateRequest(&wcmp_group).ok()); - VerifyWcmpGroupEntry(wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); - ASSERT_TRUE(p4_oid_mapper_->getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); - EXPECT_EQ(0, wcmp_group_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &nexthop_refcount)); - EXPECT_EQ(0, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &nexthop_refcount)); - EXPECT_EQ(0, nexthop_refcount); +TEST_F(WcmpManagerTest, UpdateWcmpGroupMembersSucceed) +{ + AddWcmpGroupEntry1(); + // Update WCMP group member with nexthop_id=kNexthopId1 weight to 3, + // nexthop_id=kNexthopId2 weight to 15. + P4WcmpGroupEntry wcmp_group = {.wcmp_group_id = kWcmpGroupId1, .wcmp_group_members = {}}; + std::shared_ptr gm1 = createWcmpGroupMemberEntry(kNexthopId1, 3); + std::shared_ptr gm2 = createWcmpGroupMemberEntry(kNexthopId2, 15); + wcmp_group.wcmp_group_members.push_back(gm1); + wcmp_group.wcmp_group_members.push_back(gm2); + std::vector exp_remove_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid2}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids_4{kWcmpGroupMemberOid4}; + std::vector return_oids_5{kWcmpGroupMemberOid5}; + std::vector exp_create_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 3, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_4.begin(), return_oids_4.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 15, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_5.begin(), return_oids_5.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_TRUE(ProcessUpdateRequest(&wcmp_group).ok()); + VerifyWcmpGroupEntry(wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); + uint32_t wcmp_group_refcount = 0; + uint32_t nexthop_refcount = 0; + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); + EXPECT_EQ(2, wcmp_group_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + // Remove group member with nexthop_id=kNexthopId1 + wcmp_group.wcmp_group_members.clear(); + gm2 = createWcmpGroupMemberEntry(kNexthopId2, 15); + wcmp_group.wcmp_group_members.push_back(gm2); + exp_remove_status = {SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid4}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid5}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids_2{kWcmpGroupMemberOid2}; + exp_create_status = {SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 15, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_2.begin(), return_oids_2.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_TRUE(ProcessUpdateRequest(&wcmp_group).ok()); + VerifyWcmpGroupEntry(wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); + EXPECT_EQ(1, wcmp_group_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &nexthop_refcount)); + EXPECT_EQ(0, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + // Add group member with nexthop_id=kNexthopId1 and weight=20 + wcmp_group.wcmp_group_members.clear(); + std::shared_ptr updated_gm2 = createWcmpGroupMemberEntry(kNexthopId2, 15); + std::shared_ptr updated_gm1 = createWcmpGroupMemberEntry(kNexthopId1, 20); + wcmp_group.wcmp_group_members.push_back(updated_gm1); + wcmp_group.wcmp_group_members.push_back(updated_gm2); + exp_remove_status = {SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid2}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids_1{kWcmpGroupMemberOid1}; + exp_create_status = {SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 20, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_1.begin(), return_oids_1.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 15, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_5.begin(), return_oids_5.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_TRUE(ProcessUpdateRequest(&wcmp_group).ok()); + VerifyWcmpGroupEntry(wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); + EXPECT_EQ(2, wcmp_group_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + + // Update WCMP without group members + wcmp_group.wcmp_group_members.clear(); + exp_remove_status = {SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid5}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_TRUE(ProcessUpdateRequest(&wcmp_group).ok()); + VerifyWcmpGroupEntry(wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); + EXPECT_EQ(0, wcmp_group_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &nexthop_refcount)); + EXPECT_EQ(0, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &nexthop_refcount)); + EXPECT_EQ(0, nexthop_refcount); } -TEST_F(WcmpManagerTest, UpdateWcmpGroupFailsWhenRemoveGroupMemberSaiCallFails) { - AddWcmpGroupEntry1(); - // Add WCMP group member with nexthop_id=kNexthopId1, weight=3 and - // nexthop_id=kNexthopId3, weight=30, update nexthop_id=kNexthopId2 - // weight to 10. - P4WcmpGroupEntry wcmp_group = {.wcmp_group_id = kWcmpGroupId1, - .wcmp_group_members = {}}; - std::shared_ptr gm1 = - createWcmpGroupMemberEntry(kNexthopId1, 3); - std::shared_ptr gm2 = - createWcmpGroupMemberEntry(kNexthopId2, 10); - std::shared_ptr gm3 = - createWcmpGroupMemberEntry(kNexthopId3, 30); - - wcmp_group.wcmp_group_members.push_back(gm1); - wcmp_group.wcmp_group_members.push_back(gm2); - wcmp_group.wcmp_group_members.push_back(gm3); - std::vector return_oids_4{kWcmpGroupMemberOid4}; - std::vector return_oids_5_6{kWcmpGroupMemberOid5, - kWcmpGroupMemberOid3}; - std::vector exp_create_status_1{SAI_STATUS_SUCCESS}; - std::vector exp_create_status_2{SAI_STATUS_SUCCESS, - SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 3, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_4.begin(), return_oids_4.end()), - SetArrayArgument<6>(exp_create_status_1.begin(), - exp_create_status_1.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 10, - kWcmpGroupOid1), - GetSaiNextHopGroupMemberAttribute(kNexthopOid3, 30, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce(DoAll( - SetArrayArgument<5>(return_oids_5_6.begin(), return_oids_5_6.end()), - SetArrayArgument<6>(exp_create_status_2.begin(), - exp_create_status_2.end()), - Return(SAI_STATUS_SUCCESS))); - std::vector exp_remove_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid2}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_TRUE(ProcessUpdateRequest(&wcmp_group).ok()); - VerifyWcmpGroupEntry(wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); - uint32_t wcmp_group_refcount = 0; - uint32_t nexthop_refcount = 0; - ASSERT_TRUE(p4_oid_mapper_->getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); - EXPECT_EQ(3, wcmp_group_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey3, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - // Remove WCMP group member with nexthop_id=kNexthopId1 and - // nexthop_id=kNexthopId3(fail) - succeed to clean up - wcmp_group.wcmp_group_members.clear(); - wcmp_group.wcmp_group_members.push_back(gm1); - wcmp_group.wcmp_group_members.push_back(gm3); - exp_remove_status = {SAI_STATUS_OBJECT_IN_USE, SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(2), - ArrayEq(std::vector{kWcmpGroupMemberOid3, - kWcmpGroupMemberOid5}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_OBJECT_IN_USE))); - // Clean up - revert deletions -success - std::vector return_oids_5{kWcmpGroupMemberOid5}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 10, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_5.begin(), return_oids_5.end()), - SetArrayArgument<6>(exp_create_status_1.begin(), - exp_create_status_1.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, ProcessUpdateRequest(&wcmp_group)); - P4WcmpGroupEntry expected_wcmp_group = {.wcmp_group_id = kWcmpGroupId1, - .wcmp_group_members = {}}; - expected_wcmp_group.wcmp_group_members.push_back(gm1); - expected_wcmp_group.wcmp_group_members.push_back(gm2); - expected_wcmp_group.wcmp_group_members.push_back(gm3); - // WCMP group remains as the old one - VerifyWcmpGroupEntry(expected_wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); - ASSERT_TRUE(p4_oid_mapper_->getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); - EXPECT_EQ(3, wcmp_group_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey3, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - - // Remove WCMP group member with nexthop_id=kNexthopId1 and - // nexthop_id=kNexthopId3(fail) - fail to clean up - exp_remove_status = {SAI_STATUS_OBJECT_IN_USE, SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(2), - ArrayEq(std::vector{kWcmpGroupMemberOid3, - kWcmpGroupMemberOid5}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_OBJECT_IN_USE))); - // Clean up - revert deletions -failure - std::vector return_oids{SAI_NULL_OBJECT_ID}; - std::vector exp_create_status{SAI_STATUS_TABLE_FULL}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 10, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_TABLE_FULL))); - // TODO: Expect critical state. - EXPECT_EQ("Failed to delete WCMP group member: 'ju1u32m3.atl11:qe-3/7'", - ProcessUpdateRequest(&wcmp_group).message()); - // WCMP group is as expected, but refcounts are not - VerifyWcmpGroupEntry(expected_wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); - ASSERT_TRUE(p4_oid_mapper_->getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); - EXPECT_EQ(2, wcmp_group_refcount); - // WCMP group is corrupt due to clean up failure - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &nexthop_refcount)); - EXPECT_EQ(0, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey3, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); +TEST_F(WcmpManagerTest, UpdateWcmpGroupFailsWhenRemoveGroupMemberSaiCallFails) +{ + AddWcmpGroupEntry1(); + // Add WCMP group member with nexthop_id=kNexthopId1, weight=3 and + // nexthop_id=kNexthopId3, weight=30, update nexthop_id=kNexthopId2 + // weight to 10. + P4WcmpGroupEntry wcmp_group = {.wcmp_group_id = kWcmpGroupId1, .wcmp_group_members = {}}; + std::shared_ptr gm1 = createWcmpGroupMemberEntry(kNexthopId1, 3); + std::shared_ptr gm2 = createWcmpGroupMemberEntry(kNexthopId2, 10); + std::shared_ptr gm3 = createWcmpGroupMemberEntry(kNexthopId3, 30); + + wcmp_group.wcmp_group_members.push_back(gm1); + wcmp_group.wcmp_group_members.push_back(gm2); + wcmp_group.wcmp_group_members.push_back(gm3); + std::vector return_oids_4{kWcmpGroupMemberOid4}; + std::vector return_oids_5_6{kWcmpGroupMemberOid5, kWcmpGroupMemberOid3}; + std::vector exp_create_status_1{SAI_STATUS_SUCCESS}; + std::vector exp_create_status_2{SAI_STATUS_SUCCESS, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 3, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_4.begin(), return_oids_4.end()), + SetArrayArgument<6>(exp_create_status_1.begin(), exp_create_status_1.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 10, kWcmpGroupOid1), + GetSaiNextHopGroupMemberAttribute(kNexthopOid3, 30, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_5_6.begin(), return_oids_5_6.end()), + SetArrayArgument<6>(exp_create_status_2.begin(), exp_create_status_2.end()), + Return(SAI_STATUS_SUCCESS))); + std::vector exp_remove_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid2}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_TRUE(ProcessUpdateRequest(&wcmp_group).ok()); + VerifyWcmpGroupEntry(wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); + uint32_t wcmp_group_refcount = 0; + uint32_t nexthop_refcount = 0; + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); + EXPECT_EQ(3, wcmp_group_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey3, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + // Remove WCMP group member with nexthop_id=kNexthopId1 and + // nexthop_id=kNexthopId3(fail) - succeed to clean up + wcmp_group.wcmp_group_members.clear(); + wcmp_group.wcmp_group_members.push_back(gm1); + wcmp_group.wcmp_group_members.push_back(gm3); + exp_remove_status = {SAI_STATUS_OBJECT_IN_USE, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members( + Eq(2), ArrayEq(std::vector{kWcmpGroupMemberOid3, kWcmpGroupMemberOid5}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), + Return(SAI_STATUS_OBJECT_IN_USE))); + // Clean up - revert deletions -success + std::vector return_oids_5{kWcmpGroupMemberOid5}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 10, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_5.begin(), return_oids_5.end()), + SetArrayArgument<6>(exp_create_status_1.begin(), exp_create_status_1.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_IN_USE, ProcessUpdateRequest(&wcmp_group)); + P4WcmpGroupEntry expected_wcmp_group = {.wcmp_group_id = kWcmpGroupId1, .wcmp_group_members = {}}; + expected_wcmp_group.wcmp_group_members.push_back(gm1); + expected_wcmp_group.wcmp_group_members.push_back(gm2); + expected_wcmp_group.wcmp_group_members.push_back(gm3); + // WCMP group remains as the old one + VerifyWcmpGroupEntry(expected_wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); + EXPECT_EQ(3, wcmp_group_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey3, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + + // Remove WCMP group member with nexthop_id=kNexthopId1 and + // nexthop_id=kNexthopId3(fail) - fail to clean up + exp_remove_status = {SAI_STATUS_OBJECT_IN_USE, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members( + Eq(2), ArrayEq(std::vector{kWcmpGroupMemberOid3, kWcmpGroupMemberOid5}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), + Return(SAI_STATUS_OBJECT_IN_USE))); + // Clean up - revert deletions -failure + std::vector return_oids{SAI_NULL_OBJECT_ID}; + std::vector exp_create_status{SAI_STATUS_TABLE_FULL}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 10, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_TABLE_FULL))); + // TODO: Expect critical state. + EXPECT_EQ("Failed to delete WCMP group member: 'ju1u32m3.atl11:qe-3/7'", + ProcessUpdateRequest(&wcmp_group).message()); + // WCMP group is as expected, but refcounts are not + VerifyWcmpGroupEntry(expected_wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); + EXPECT_EQ(2, wcmp_group_refcount); + // WCMP group is corrupt due to clean up failure + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &nexthop_refcount)); + EXPECT_EQ(0, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey3, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); } -TEST_F(WcmpManagerTest, - UpdateWcmpGroupFailsWhenCreateNewGroupMemberSaiCallFails) { - AddWcmpGroupEntry1(); - P4WcmpGroupEntry wcmp_group = {.wcmp_group_id = kWcmpGroupId1, - .wcmp_group_members = {}}; - - // Remove group member with nexthop_id=kNexthopId1 - wcmp_group.wcmp_group_members.clear(); - std::shared_ptr gm = - createWcmpGroupMemberEntry(kNexthopId2, 15); - wcmp_group.wcmp_group_members.push_back(gm); - std::vector exp_remove_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid2}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - std::vector return_oids_5{kWcmpGroupMemberOid5}; - std::vector exp_create_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 15, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_5.begin(), return_oids_5.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_TRUE(ProcessUpdateRequest(&wcmp_group).ok()); - VerifyWcmpGroupEntry(wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); - uint32_t wcmp_group_refcount = 0; - uint32_t nexthop_refcount = 0; - ASSERT_TRUE(p4_oid_mapper_->getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); - EXPECT_EQ(1, wcmp_group_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &nexthop_refcount)); - EXPECT_EQ(0, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey3, &nexthop_refcount)); - EXPECT_EQ(0, nexthop_refcount); - // Add WCMP group member with nexthop_id=kNexthopId1, weight=3 and - // nexthop_id=kNexthopId3, weight=30(fail), update nexthop_id=kNexthopId2 - // weight to 10. - P4WcmpGroupEntry updated_wcmp_group = {.wcmp_group_id = kWcmpGroupId1, - .wcmp_group_members = {}}; - std::shared_ptr updated_gm1 = - createWcmpGroupMemberEntry(kNexthopId1, 3); - std::shared_ptr updated_gm2 = - createWcmpGroupMemberEntry(kNexthopId2, 20); - std::shared_ptr updated_gm3 = - createWcmpGroupMemberEntry(kNexthopId3, 30); - updated_wcmp_group.wcmp_group_members.push_back(updated_gm1); - updated_wcmp_group.wcmp_group_members.push_back(updated_gm2); - updated_wcmp_group.wcmp_group_members.push_back(updated_gm3); - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid5}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - std::vector return_oids_1{kWcmpGroupMemberOid1}; - std::vector exp_create_status_fail{SAI_STATUS_SUCCESS, - SAI_STATUS_TABLE_FULL}; - std::vector return_oids_2_null{kWcmpGroupMemberOid2, - SAI_NULL_OBJECT_ID}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 3, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_1.begin(), return_oids_1.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 20, - kWcmpGroupOid1), - GetSaiNextHopGroupMemberAttribute(kNexthopOid3, 30, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce(DoAll(SetArrayArgument<5>(return_oids_2_null.begin(), - return_oids_2_null.end()), - SetArrayArgument<6>(exp_create_status_fail.begin(), - exp_create_status_fail.end()), - Return(SAI_STATUS_TABLE_FULL))); - // Clean up - success - std::vector exp_remove_status_2{SAI_STATUS_SUCCESS, - SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(2), - ArrayEq(std::vector{kWcmpGroupMemberOid2, - kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status_2.begin(), - exp_remove_status_2.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 15, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_5.begin(), return_oids_5.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_FALSE(ProcessUpdateRequest(&updated_wcmp_group).ok()); - P4WcmpGroupEntry expected_wcmp_group = {.wcmp_group_id = kWcmpGroupId1, - .wcmp_group_members = {}}; - std::shared_ptr expected_gm = - createWcmpGroupMemberEntry(kNexthopId2, 15); - expected_wcmp_group.wcmp_group_members.push_back(expected_gm); - VerifyWcmpGroupEntry(expected_wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); - ASSERT_TRUE(p4_oid_mapper_->getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); - EXPECT_EQ(1, wcmp_group_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &nexthop_refcount)); - EXPECT_EQ(0, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey3, &nexthop_refcount)); - EXPECT_EQ(0, nexthop_refcount); - - // Try again, but this time clean up failed to remove created group member - exp_remove_status = {SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid5}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 3, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_1.begin(), return_oids_1.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 20, - kWcmpGroupOid1), - GetSaiNextHopGroupMemberAttribute(kNexthopOid3, 30, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce(DoAll(SetArrayArgument<5>(return_oids_2_null.begin(), - return_oids_2_null.end()), - SetArrayArgument<6>(exp_create_status_fail.begin(), - exp_create_status_fail.end()), - Return(SAI_STATUS_TABLE_FULL))); - // Clean up - revert creation - failure - std::vector exp_remove_status_fail{SAI_STATUS_OBJECT_IN_USE, - SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(2), - ArrayEq(std::vector{kWcmpGroupMemberOid2, - kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status_fail.begin(), - exp_remove_status_fail.end()), - Return(SAI_STATUS_OBJECT_IN_USE))); - // TODO: Expect critical state. - EXPECT_EQ("Fail to create wcmp group member: 'ju1u32m3.atl11:qe-3/7'", - ProcessUpdateRequest(&updated_wcmp_group).message()); - // WCMP group is as expected, but refcounts are not - VerifyWcmpGroupEntry(expected_wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); - ASSERT_TRUE(p4_oid_mapper_->getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); - EXPECT_EQ(1, wcmp_group_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &nexthop_refcount)); - EXPECT_EQ(0, nexthop_refcount); // Corrupt status due to clean up failure - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey3, &nexthop_refcount)); - EXPECT_EQ(0, nexthop_refcount); +TEST_F(WcmpManagerTest, UpdateWcmpGroupFailsWhenCreateNewGroupMemberSaiCallFails) +{ + AddWcmpGroupEntry1(); + P4WcmpGroupEntry wcmp_group = {.wcmp_group_id = kWcmpGroupId1, .wcmp_group_members = {}}; + + // Remove group member with nexthop_id=kNexthopId1 + wcmp_group.wcmp_group_members.clear(); + std::shared_ptr gm = createWcmpGroupMemberEntry(kNexthopId2, 15); + wcmp_group.wcmp_group_members.push_back(gm); + std::vector exp_remove_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid2}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids_5{kWcmpGroupMemberOid5}; + std::vector exp_create_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 15, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_5.begin(), return_oids_5.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_TRUE(ProcessUpdateRequest(&wcmp_group).ok()); + VerifyWcmpGroupEntry(wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); + uint32_t wcmp_group_refcount = 0; + uint32_t nexthop_refcount = 0; + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); + EXPECT_EQ(1, wcmp_group_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &nexthop_refcount)); + EXPECT_EQ(0, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey3, &nexthop_refcount)); + EXPECT_EQ(0, nexthop_refcount); + // Add WCMP group member with nexthop_id=kNexthopId1, weight=3 and + // nexthop_id=kNexthopId3, weight=30(fail), update nexthop_id=kNexthopId2 + // weight to 10. + P4WcmpGroupEntry updated_wcmp_group = {.wcmp_group_id = kWcmpGroupId1, .wcmp_group_members = {}}; + std::shared_ptr updated_gm1 = createWcmpGroupMemberEntry(kNexthopId1, 3); + std::shared_ptr updated_gm2 = createWcmpGroupMemberEntry(kNexthopId2, 20); + std::shared_ptr updated_gm3 = createWcmpGroupMemberEntry(kNexthopId3, 30); + updated_wcmp_group.wcmp_group_members.push_back(updated_gm1); + updated_wcmp_group.wcmp_group_members.push_back(updated_gm2); + updated_wcmp_group.wcmp_group_members.push_back(updated_gm3); + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid5}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids_1{kWcmpGroupMemberOid1}; + std::vector exp_create_status_fail{SAI_STATUS_SUCCESS, SAI_STATUS_TABLE_FULL}; + std::vector return_oids_2_null{kWcmpGroupMemberOid2, SAI_NULL_OBJECT_ID}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 3, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_1.begin(), return_oids_1.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 20, kWcmpGroupOid1), + GetSaiNextHopGroupMemberAttribute(kNexthopOid3, 30, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_2_null.begin(), return_oids_2_null.end()), + SetArrayArgument<6>(exp_create_status_fail.begin(), exp_create_status_fail.end()), + Return(SAI_STATUS_TABLE_FULL))); + // Clean up - success + std::vector exp_remove_status_2{SAI_STATUS_SUCCESS, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members( + Eq(2), ArrayEq(std::vector{kWcmpGroupMemberOid2, kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status_2.begin(), exp_remove_status_2.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 15, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_5.begin(), return_oids_5.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_FALSE(ProcessUpdateRequest(&updated_wcmp_group).ok()); + P4WcmpGroupEntry expected_wcmp_group = {.wcmp_group_id = kWcmpGroupId1, .wcmp_group_members = {}}; + std::shared_ptr expected_gm = createWcmpGroupMemberEntry(kNexthopId2, 15); + expected_wcmp_group.wcmp_group_members.push_back(expected_gm); + VerifyWcmpGroupEntry(expected_wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); + EXPECT_EQ(1, wcmp_group_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &nexthop_refcount)); + EXPECT_EQ(0, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey3, &nexthop_refcount)); + EXPECT_EQ(0, nexthop_refcount); + + // Try again, but this time clean up failed to remove created group member + exp_remove_status = {SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid5}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 3, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_1.begin(), return_oids_1.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 20, kWcmpGroupOid1), + GetSaiNextHopGroupMemberAttribute(kNexthopOid3, 30, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_2_null.begin(), return_oids_2_null.end()), + SetArrayArgument<6>(exp_create_status_fail.begin(), exp_create_status_fail.end()), + Return(SAI_STATUS_TABLE_FULL))); + // Clean up - revert creation - failure + std::vector exp_remove_status_fail{SAI_STATUS_OBJECT_IN_USE, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members( + Eq(2), ArrayEq(std::vector{kWcmpGroupMemberOid2, kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status_fail.begin(), exp_remove_status_fail.end()), + Return(SAI_STATUS_OBJECT_IN_USE))); + // TODO: Expect critical state. + EXPECT_EQ("Fail to create wcmp group member: 'ju1u32m3.atl11:qe-3/7'", + ProcessUpdateRequest(&updated_wcmp_group).message()); + // WCMP group is as expected, but refcounts are not + VerifyWcmpGroupEntry(expected_wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); + EXPECT_EQ(1, wcmp_group_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &nexthop_refcount)); + EXPECT_EQ(0, nexthop_refcount); // Corrupt status due to clean up failure + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey3, &nexthop_refcount)); + EXPECT_EQ(0, nexthop_refcount); } -TEST_F(WcmpManagerTest, - UpdateWcmpGroupFailsWhenReduceGroupMemberWeightSaiCallFails) { - AddWcmpGroupEntry1(); - P4WcmpGroupEntry wcmp_group = {.wcmp_group_id = kWcmpGroupId1, - .wcmp_group_members = {}}; - // Update WCMP group member to nexthop_id=kNexthopId1, weight=1(reduce) and - // nexthop_id=kNexthopId2, weight=10(increase), update nexthop_id=kNexthopId1 - // weight=1(fail). - std::shared_ptr gm1 = - createWcmpGroupMemberEntry(kNexthopId1, 1); - std::shared_ptr gm2 = - createWcmpGroupMemberEntry(kNexthopId2, 10); - wcmp_group.wcmp_group_members.push_back(gm1); - wcmp_group.wcmp_group_members.push_back(gm2); - std::vector exp_remove_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - std::vector return_oids_1{kWcmpGroupMemberOid1}; - std::vector return_oids_null{SAI_NULL_OBJECT_ID}; - std::vector exp_create_status{SAI_STATUS_SUCCESS}; - std::vector exp_create_status_fail{SAI_STATUS_NOT_SUPPORTED}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce(DoAll( - SetArrayArgument<5>(return_oids_null.begin(), return_oids_null.end()), - SetArrayArgument<6>(exp_create_status_fail.begin(), - exp_create_status_fail.end()), - Return(SAI_STATUS_NOT_SUPPORTED))); - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_1.begin(), return_oids_1.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_NOT_SUPPORTED))); - EXPECT_FALSE(ProcessUpdateRequest(&wcmp_group).ok()); - P4WcmpGroupEntry expected_wcmp_group = {.wcmp_group_id = kWcmpGroupId1, - .wcmp_group_members = {}}; - std::shared_ptr expected_gm1 = - createWcmpGroupMemberEntry(kNexthopId1, 2); - std::shared_ptr expected_gm2 = - createWcmpGroupMemberEntry(kNexthopId2, 1); - expected_wcmp_group.wcmp_group_members.push_back(expected_gm1); - expected_wcmp_group.wcmp_group_members.push_back(expected_gm2); - VerifyWcmpGroupEntry(expected_wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); - uint32_t wcmp_group_refcount = 0; - uint32_t nexthop_refcount = 0; - ASSERT_TRUE(p4_oid_mapper_->getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); - EXPECT_EQ(2, wcmp_group_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); +TEST_F(WcmpManagerTest, UpdateWcmpGroupFailsWhenReduceGroupMemberWeightSaiCallFails) +{ + AddWcmpGroupEntry1(); + P4WcmpGroupEntry wcmp_group = {.wcmp_group_id = kWcmpGroupId1, .wcmp_group_members = {}}; + // Update WCMP group member to nexthop_id=kNexthopId1, weight=1(reduce) and + // nexthop_id=kNexthopId2, weight=10(increase), update nexthop_id=kNexthopId1 + // weight=1(fail). + std::shared_ptr gm1 = createWcmpGroupMemberEntry(kNexthopId1, 1); + std::shared_ptr gm2 = createWcmpGroupMemberEntry(kNexthopId2, 10); + wcmp_group.wcmp_group_members.push_back(gm1); + wcmp_group.wcmp_group_members.push_back(gm2); + std::vector exp_remove_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids_1{kWcmpGroupMemberOid1}; + std::vector return_oids_null{SAI_NULL_OBJECT_ID}; + std::vector exp_create_status{SAI_STATUS_SUCCESS}; + std::vector exp_create_status_fail{SAI_STATUS_NOT_SUPPORTED}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_null.begin(), return_oids_null.end()), + SetArrayArgument<6>(exp_create_status_fail.begin(), exp_create_status_fail.end()), + Return(SAI_STATUS_NOT_SUPPORTED))); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_1.begin(), return_oids_1.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_NOT_SUPPORTED))); + EXPECT_FALSE(ProcessUpdateRequest(&wcmp_group).ok()); + P4WcmpGroupEntry expected_wcmp_group = {.wcmp_group_id = kWcmpGroupId1, .wcmp_group_members = {}}; + std::shared_ptr expected_gm1 = createWcmpGroupMemberEntry(kNexthopId1, 2); + std::shared_ptr expected_gm2 = createWcmpGroupMemberEntry(kNexthopId2, 1); + expected_wcmp_group.wcmp_group_members.push_back(expected_gm1); + expected_wcmp_group.wcmp_group_members.push_back(expected_gm2); + VerifyWcmpGroupEntry(expected_wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); + uint32_t wcmp_group_refcount = 0; + uint32_t nexthop_refcount = 0; + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); + EXPECT_EQ(2, wcmp_group_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); } -TEST_F(WcmpManagerTest, - UpdateWcmpGroupFailsWhenIncreaseGroupMemberWeightSaiCallFails) { - AddWcmpGroupEntry1(); - P4WcmpGroupEntry wcmp_group = {.wcmp_group_id = kWcmpGroupId1, - .wcmp_group_members = {}}; - // Update WCMP group member to nexthop_id=kNexthopId1, weight=1(reduce) and - // nexthop_id=kNexthopId2, weight=10(increase), update nexthop_id=kNexthopId2 - // weight=10(fail). - std::shared_ptr gm1 = - createWcmpGroupMemberEntry(kNexthopId1, 1); - std::shared_ptr gm2 = - createWcmpGroupMemberEntry(kNexthopId2, 10); - wcmp_group.wcmp_group_members.push_back(gm1); - wcmp_group.wcmp_group_members.push_back(gm2); - std::vector exp_remove_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid2}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - std::vector return_oids_4{kWcmpGroupMemberOid4}; - std::vector return_oids_null{SAI_NULL_OBJECT_ID}; - std::vector exp_create_status{SAI_STATUS_SUCCESS}; - std::vector exp_create_status_fail{SAI_STATUS_NOT_SUPPORTED}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_4.begin(), return_oids_4.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 10, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce(DoAll( - SetArrayArgument<5>(return_oids_null.begin(), return_oids_null.end()), - SetArrayArgument<6>(exp_create_status_fail.begin(), - exp_create_status_fail.end()), - Return(SAI_STATUS_NOT_SUPPORTED))); - // Clean up modified members - success - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid4}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - std::vector return_oids_1_2{kWcmpGroupMemberOid1, - kWcmpGroupMemberOid2}; - std::vector exp_create_status_2{SAI_STATUS_SUCCESS, - SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, - kWcmpGroupOid1), - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce(DoAll( - SetArrayArgument<5>(return_oids_1_2.begin(), return_oids_1_2.end()), - SetArrayArgument<6>(exp_create_status_2.begin(), - exp_create_status_2.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_FALSE(ProcessUpdateRequest(&wcmp_group).ok()); - P4WcmpGroupEntry expected_wcmp_group = {.wcmp_group_id = kWcmpGroupId1, - .wcmp_group_members = {}}; - std::shared_ptr expected_gm1 = - createWcmpGroupMemberEntry(kNexthopId1, 2); - std::shared_ptr expected_gm2 = - createWcmpGroupMemberEntry(kNexthopId2, 1); - expected_wcmp_group.wcmp_group_members.push_back(expected_gm1); - expected_wcmp_group.wcmp_group_members.push_back(expected_gm2); - VerifyWcmpGroupEntry(expected_wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); - uint32_t wcmp_group_refcount = 0; - uint32_t nexthop_refcount = 0; - ASSERT_TRUE(p4_oid_mapper_->getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); - EXPECT_EQ(2, wcmp_group_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); - // Try again, the same error happens when update and new error during clean up - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid2}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_4.begin(), return_oids_4.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 10, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce(DoAll( - SetArrayArgument<5>(return_oids_null.begin(), return_oids_null.end()), - SetArrayArgument<6>(exp_create_status_fail.begin(), - exp_create_status_fail.end()), - Return(SAI_STATUS_NOT_SUPPORTED))); - // Clean up modified members - failure - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid4}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - std::vector return_oids_2_null{SAI_NULL_OBJECT_ID, - kWcmpGroupMemberOid2}; - std::vector exp_create_status_2_fail{SAI_STATUS_NOT_SUPPORTED, - SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, - kWcmpGroupOid1), - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce(DoAll(SetArrayArgument<5>(return_oids_2_null.begin(), - return_oids_2_null.end()), - SetArrayArgument<6>(exp_create_status_2_fail.begin(), - exp_create_status_2_fail.end()), - Return(SAI_STATUS_NOT_SUPPORTED))); - - // TODO: Expect critical state. - EXPECT_EQ("Fail to create wcmp group member: 'ju1u32m2.atl11:qe-3/7'", - ProcessUpdateRequest(&wcmp_group).message()); - // weight of wcmp_group_members[kNexthopId1] unable to revert - // SAI object in ASIC DB: missing group member with - // next_hop_id=kNexthopId1 - expected_gm1->weight = 2; - VerifyWcmpGroupEntry(expected_wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); - ASSERT_TRUE(p4_oid_mapper_->getRefCount( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); - EXPECT_EQ(1, wcmp_group_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &nexthop_refcount)); - EXPECT_EQ(0, nexthop_refcount); - ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &nexthop_refcount)); - EXPECT_EQ(1, nexthop_refcount); +TEST_F(WcmpManagerTest, UpdateWcmpGroupFailsWhenIncreaseGroupMemberWeightSaiCallFails) +{ + AddWcmpGroupEntry1(); + P4WcmpGroupEntry wcmp_group = {.wcmp_group_id = kWcmpGroupId1, .wcmp_group_members = {}}; + // Update WCMP group member to nexthop_id=kNexthopId1, weight=1(reduce) and + // nexthop_id=kNexthopId2, weight=10(increase), update nexthop_id=kNexthopId2 + // weight=10(fail). + std::shared_ptr gm1 = createWcmpGroupMemberEntry(kNexthopId1, 1); + std::shared_ptr gm2 = createWcmpGroupMemberEntry(kNexthopId2, 10); + wcmp_group.wcmp_group_members.push_back(gm1); + wcmp_group.wcmp_group_members.push_back(gm2); + std::vector exp_remove_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid2}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids_4{kWcmpGroupMemberOid4}; + std::vector return_oids_null{SAI_NULL_OBJECT_ID}; + std::vector exp_create_status{SAI_STATUS_SUCCESS}; + std::vector exp_create_status_fail{SAI_STATUS_NOT_SUPPORTED}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_4.begin(), return_oids_4.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 10, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_null.begin(), return_oids_null.end()), + SetArrayArgument<6>(exp_create_status_fail.begin(), exp_create_status_fail.end()), + Return(SAI_STATUS_NOT_SUPPORTED))); + // Clean up modified members - success + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid4}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids_1_2{kWcmpGroupMemberOid1, kWcmpGroupMemberOid2}; + std::vector exp_create_status_2{SAI_STATUS_SUCCESS, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, kWcmpGroupOid1), + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_1_2.begin(), return_oids_1_2.end()), + SetArrayArgument<6>(exp_create_status_2.begin(), exp_create_status_2.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_FALSE(ProcessUpdateRequest(&wcmp_group).ok()); + P4WcmpGroupEntry expected_wcmp_group = {.wcmp_group_id = kWcmpGroupId1, .wcmp_group_members = {}}; + std::shared_ptr expected_gm1 = createWcmpGroupMemberEntry(kNexthopId1, 2); + std::shared_ptr expected_gm2 = createWcmpGroupMemberEntry(kNexthopId2, 1); + expected_wcmp_group.wcmp_group_members.push_back(expected_gm1); + expected_wcmp_group.wcmp_group_members.push_back(expected_gm2); + VerifyWcmpGroupEntry(expected_wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); + uint32_t wcmp_group_refcount = 0; + uint32_t nexthop_refcount = 0; + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); + EXPECT_EQ(2, wcmp_group_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); + // Try again, the same error happens when update and new error during clean up + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid2}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_4.begin(), return_oids_4.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 10, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_null.begin(), return_oids_null.end()), + SetArrayArgument<6>(exp_create_status_fail.begin(), exp_create_status_fail.end()), + Return(SAI_STATUS_NOT_SUPPORTED))); + // Clean up modified members - failure + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid4}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids_2_null{SAI_NULL_OBJECT_ID, kWcmpGroupMemberOid2}; + std::vector exp_create_status_2_fail{SAI_STATUS_NOT_SUPPORTED, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, kWcmpGroupOid1), + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_2_null.begin(), return_oids_2_null.end()), + SetArrayArgument<6>(exp_create_status_2_fail.begin(), exp_create_status_2_fail.end()), + Return(SAI_STATUS_NOT_SUPPORTED))); + + // TODO: Expect critical state. + EXPECT_EQ("Fail to create wcmp group member: 'ju1u32m2.atl11:qe-3/7'", ProcessUpdateRequest(&wcmp_group).message()); + // weight of wcmp_group_members[kNexthopId1] unable to revert + // SAI object in ASIC DB: missing group member with + // next_hop_id=kNexthopId1 + expected_gm1->weight = 2; + VerifyWcmpGroupEntry(expected_wcmp_group, *GetWcmpGroupEntry(kWcmpGroupId1)); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, kWcmpGroupKey1, &wcmp_group_refcount)); + EXPECT_EQ(1, wcmp_group_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &nexthop_refcount)); + EXPECT_EQ(0, nexthop_refcount); + ASSERT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &nexthop_refcount)); + EXPECT_EQ(1, nexthop_refcount); } -TEST_F(WcmpManagerTest, ValidateWcmpGroupEntryFailsWhenNextHopDoesNotExist) { - const std::string kKeyPrefix = - std::string(APP_P4RT_WCMP_GROUP_TABLE_NAME) + kTableKeyDelimiter; - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); - nlohmann::json j; - j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; - std::vector attributes; - nlohmann::json actions; - nlohmann::json action; - action[p4orch::kAction] = p4orch::kSetNexthopId; - action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; - actions.push_back(action); - action[prependParamField(p4orch::kNexthopId)] = kNexthopId2; - actions.push_back(action); - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, - attributes)); - Drain(); - std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); - auto* wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); - EXPECT_EQ(nullptr, wcmp_group_entry_ptr); - EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(0, ref_cnt); +TEST_F(WcmpManagerTest, ValidateWcmpGroupEntryFailsWhenNextHopDoesNotExist) +{ + const std::string kKeyPrefix = std::string(APP_P4RT_WCMP_GROUP_TABLE_NAME) + kTableKeyDelimiter; + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); + nlohmann::json j; + j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; + std::vector attributes; + nlohmann::json actions; + nlohmann::json action; + action[p4orch::kAction] = p4orch::kSetNexthopId; + action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; + actions.push_back(action); + action[prependParamField(p4orch::kNexthopId)] = kNexthopId2; + actions.push_back(action); + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, attributes)); + Drain(); + std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); + auto *wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); + EXPECT_EQ(nullptr, wcmp_group_entry_ptr); + EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(0, ref_cnt); } -TEST_F(WcmpManagerTest, ValidateWcmpGroupEntryFailsWhenWeightLessThanOne) { - const std::string kKeyPrefix = - std::string(APP_P4RT_WCMP_GROUP_TABLE_NAME) + kTableKeyDelimiter; - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, kNexthopOid2); - nlohmann::json j; - j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; - std::vector attributes; - nlohmann::json actions; - nlohmann::json action; - action[p4orch::kAction] = p4orch::kSetNexthopId; - action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; - actions.push_back(action); - action[p4orch::kWeight] = -1; - action[prependParamField(p4orch::kNexthopId)] = kNexthopId2; - actions.push_back(action); - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, - attributes)); - Drain(); - std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); - auto* wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); - EXPECT_EQ(nullptr, wcmp_group_entry_ptr); - EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &ref_cnt)); - EXPECT_EQ(0, ref_cnt); +TEST_F(WcmpManagerTest, ValidateWcmpGroupEntryFailsWhenWeightLessThanOne) +{ + const std::string kKeyPrefix = std::string(APP_P4RT_WCMP_GROUP_TABLE_NAME) + kTableKeyDelimiter; + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, kNexthopOid2); + nlohmann::json j; + j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; + std::vector attributes; + nlohmann::json actions; + nlohmann::json action; + action[p4orch::kAction] = p4orch::kSetNexthopId; + action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; + actions.push_back(action); + action[p4orch::kWeight] = -1; + action[prependParamField(p4orch::kNexthopId)] = kNexthopId2; + actions.push_back(action); + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, attributes)); + Drain(); + std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); + auto *wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); + EXPECT_EQ(nullptr, wcmp_group_entry_ptr); + EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &ref_cnt)); + EXPECT_EQ(0, ref_cnt); } -TEST_F(WcmpManagerTest, WcmpGroupInvalidOperationInDrainFails) { - const std::string kKeyPrefix = - std::string(APP_P4RT_WCMP_GROUP_TABLE_NAME) + kTableKeyDelimiter; - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, kNexthopOid2); - nlohmann::json j; - j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; - std::vector attributes; - // If weight is omitted in the action, then it is set to 1 by default(ECMP) - nlohmann::json actions; - nlohmann::json action; - action[p4orch::kAction] = p4orch::kSetNexthopId; - action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; - actions.push_back(action); - action[prependParamField(p4orch::kNexthopId)] = kNexthopId2; - actions.push_back(action); - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - - // Invalid Operation string. Only SET and DEL are allowed - Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), "Update", - attributes)); - Drain(); - std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); - auto* wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); - EXPECT_EQ(nullptr, wcmp_group_entry_ptr); - EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &ref_cnt)); - EXPECT_EQ(0, ref_cnt); +TEST_F(WcmpManagerTest, WcmpGroupInvalidOperationInDrainFails) +{ + const std::string kKeyPrefix = std::string(APP_P4RT_WCMP_GROUP_TABLE_NAME) + kTableKeyDelimiter; + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, kNexthopOid2); + nlohmann::json j; + j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; + std::vector attributes; + // If weight is omitted in the action, then it is set to 1 by default(ECMP) + nlohmann::json actions; + nlohmann::json action; + action[p4orch::kAction] = p4orch::kSetNexthopId; + action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; + actions.push_back(action); + action[prependParamField(p4orch::kNexthopId)] = kNexthopId2; + actions.push_back(action); + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + + // Invalid Operation string. Only SET and DEL are allowed + Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), "Update", attributes)); + Drain(); + std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); + auto *wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); + EXPECT_EQ(nullptr, wcmp_group_entry_ptr); + EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &ref_cnt)); + EXPECT_EQ(0, ref_cnt); } -TEST_F(WcmpManagerTest, WcmpGroupUndefinedAttributesInDrainFails) { - const std::string kKeyPrefix = - std::string(APP_P4RT_WCMP_GROUP_TABLE_NAME) + kTableKeyDelimiter; - nlohmann::json j; - j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; - std::vector attributes; - attributes.push_back(swss::FieldValueTuple{"Undefined", "Invalid"}); - Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, - attributes)); - Drain(); - std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); - auto* wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); - EXPECT_EQ(nullptr, wcmp_group_entry_ptr); - EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); +TEST_F(WcmpManagerTest, WcmpGroupUndefinedAttributesInDrainFails) +{ + const std::string kKeyPrefix = std::string(APP_P4RT_WCMP_GROUP_TABLE_NAME) + kTableKeyDelimiter; + nlohmann::json j; + j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; + std::vector attributes; + attributes.push_back(swss::FieldValueTuple{"Undefined", "Invalid"}); + Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, attributes)); + Drain(); + std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); + auto *wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); + EXPECT_EQ(nullptr, wcmp_group_entry_ptr); + EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); } -TEST_F(WcmpManagerTest, WcmpGroupCreateAndDeleteInDrainSucceeds) { - const std::string kKeyPrefix = - std::string(APP_P4RT_WCMP_GROUP_TABLE_NAME) + kTableKeyDelimiter; - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, kNexthopOid2); - nlohmann::json j; - j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; - std::vector attributes; - // If weight is omitted in the action, then it is set to 1 by default(ECMP) - nlohmann::json actions; - nlohmann::json action; - action[p4orch::kAction] = p4orch::kSetNexthopId; - action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; - actions.push_back(action); - action[prependParamField(p4orch::kNexthopId)] = kNexthopId2; - actions.push_back(action); - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - - Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, - attributes)); - - EXPECT_CALL(mock_sai_next_hop_group_, create_next_hop_group(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kWcmpGroupOid1), Return(SAI_STATUS_SUCCESS))); - - std::vector return_oids{kWcmpGroupMemberOid1, - kWcmpGroupMemberOid2}; - std::vector exp_create_status{SAI_STATUS_SUCCESS, - SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, - kWcmpGroupOid1), - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - Drain(); - std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); - auto* wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); - EXPECT_NE(nullptr, wcmp_group_entry_ptr); - EXPECT_TRUE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - std::vector exp_remove_status{SAI_STATUS_SUCCESS, - SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(2), - ArrayEq(std::vector{kWcmpGroupMemberOid2, - kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group(Eq(kWcmpGroupOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - attributes.clear(); - Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), DEL_COMMAND, - attributes)); - Drain(); - wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); - EXPECT_EQ(nullptr, wcmp_group_entry_ptr); - EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &ref_cnt)); - EXPECT_EQ(0, ref_cnt); +TEST_F(WcmpManagerTest, WcmpGroupCreateAndDeleteInDrainSucceeds) +{ + const std::string kKeyPrefix = std::string(APP_P4RT_WCMP_GROUP_TABLE_NAME) + kTableKeyDelimiter; + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, kNexthopOid2); + nlohmann::json j; + j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; + std::vector attributes; + // If weight is omitted in the action, then it is set to 1 by default(ECMP) + nlohmann::json actions; + nlohmann::json action; + action[p4orch::kAction] = p4orch::kSetNexthopId; + action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; + actions.push_back(action); + action[prependParamField(p4orch::kNexthopId)] = kNexthopId2; + actions.push_back(action); + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + + Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, attributes)); + + EXPECT_CALL(mock_sai_next_hop_group_, create_next_hop_group(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupOid1), Return(SAI_STATUS_SUCCESS))); + + std::vector return_oids{kWcmpGroupMemberOid1, kWcmpGroupMemberOid2}; + std::vector exp_create_status{SAI_STATUS_SUCCESS, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, kWcmpGroupOid1), + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + Drain(); + std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); + auto *wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); + EXPECT_NE(nullptr, wcmp_group_entry_ptr); + EXPECT_TRUE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + std::vector exp_remove_status{SAI_STATUS_SUCCESS, SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members( + Eq(2), ArrayEq(std::vector{kWcmpGroupMemberOid2, kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group(Eq(kWcmpGroupOid1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + attributes.clear(); + Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), DEL_COMMAND, attributes)); + Drain(); + wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); + EXPECT_EQ(nullptr, wcmp_group_entry_ptr); + EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &ref_cnt)); + EXPECT_EQ(0, ref_cnt); } -TEST_F(WcmpManagerTest, WcmpGroupCreateAndUpdateInDrainSucceeds) { - const std::string kKeyPrefix = - std::string(APP_P4RT_WCMP_GROUP_TABLE_NAME) + kTableKeyDelimiter; - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, kNexthopOid2); - nlohmann::json j; - j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; - std::vector attributes; - nlohmann::json actions; - nlohmann::json action; - action[p4orch::kAction] = p4orch::kSetNexthopId; - action[p4orch::kWeight] = 1; - action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; - actions.push_back(action); - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - // Create WCMP group with member {next_hop_id=kNexthopId1, weight=1} - Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, - attributes)); - EXPECT_CALL(mock_sai_next_hop_group_, create_next_hop_group(_, _, _, _)) - .WillOnce( - DoAll(SetArgPointee<0>(kWcmpGroupOid1), Return(SAI_STATUS_SUCCESS))); - std::vector return_oids{kWcmpGroupMemberOid1}; - std::vector exp_create_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - Drain(); - std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); - auto* wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); - EXPECT_NE(nullptr, wcmp_group_entry_ptr); - EXPECT_EQ(1, wcmp_group_entry_ptr->wcmp_group_members.size()); - VerifyWcmpGroupMemberEntry(kNexthopId1, 1, - wcmp_group_entry_ptr->wcmp_group_members[0]); - EXPECT_EQ(kWcmpGroupMemberOid1, - wcmp_group_entry_ptr->wcmp_group_members[0]->member_oid); - EXPECT_TRUE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - // Update WCMP group with exact same members, the same entry will be removed - // and created again - Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, - attributes)); - return_oids = {kWcmpGroupMemberOid3}; - exp_create_status = {SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - std::vector exp_remove_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - Drain(); - wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); - EXPECT_NE(nullptr, wcmp_group_entry_ptr); - EXPECT_EQ(1, wcmp_group_entry_ptr->wcmp_group_members.size()); - VerifyWcmpGroupMemberEntry(kNexthopId1, 1, - wcmp_group_entry_ptr->wcmp_group_members[0]); - EXPECT_EQ(kWcmpGroupMemberOid3, - wcmp_group_entry_ptr->wcmp_group_members[0]->member_oid); - EXPECT_TRUE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - // Update WCMP group with member {next_hop_id=kNexthopId2, weight=1} - actions.clear(); - action[prependParamField(p4orch::kNexthopId)] = kNexthopId2; - actions.push_back(action); - attributes.clear(); - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, - attributes)); - return_oids = {kWcmpGroupMemberOid2}; - exp_create_status = {SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - exp_remove_status = {SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid3}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - Drain(); - wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); - EXPECT_NE(nullptr, wcmp_group_entry_ptr); - EXPECT_EQ(1, wcmp_group_entry_ptr->wcmp_group_members.size()); - VerifyWcmpGroupMemberEntry(kNexthopId2, 1, - wcmp_group_entry_ptr->wcmp_group_members[0]); - EXPECT_EQ(kWcmpGroupMemberOid2, - wcmp_group_entry_ptr->wcmp_group_members[0]->member_oid); - EXPECT_TRUE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(0, ref_cnt); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - // Update WCMP group with member {next_hop_id=kNexthopId2, weight=2} - actions.clear(); - action[p4orch::kWeight] = 2; - actions.push_back(action); - attributes.clear(); - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, - attributes)); - return_oids = {kWcmpGroupMemberOid4}; - exp_create_status = {SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 2, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - exp_remove_status = {SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid2}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - Drain(); - wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); - EXPECT_NE(nullptr, wcmp_group_entry_ptr); - EXPECT_EQ(1, wcmp_group_entry_ptr->wcmp_group_members.size()); - VerifyWcmpGroupMemberEntry(kNexthopId2, 2, - wcmp_group_entry_ptr->wcmp_group_members[0]); - EXPECT_EQ(kWcmpGroupMemberOid4, - wcmp_group_entry_ptr->wcmp_group_members[0]->member_oid); - EXPECT_TRUE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey2, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); +TEST_F(WcmpManagerTest, WcmpGroupCreateAndUpdateInDrainSucceeds) +{ + const std::string kKeyPrefix = std::string(APP_P4RT_WCMP_GROUP_TABLE_NAME) + kTableKeyDelimiter; + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, kNexthopOid2); + nlohmann::json j; + j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; + std::vector attributes; + nlohmann::json actions; + nlohmann::json action; + action[p4orch::kAction] = p4orch::kSetNexthopId; + action[p4orch::kWeight] = 1; + action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; + actions.push_back(action); + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + // Create WCMP group with member {next_hop_id=kNexthopId1, weight=1} + Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, attributes)); + EXPECT_CALL(mock_sai_next_hop_group_, create_next_hop_group(_, _, _, _)) + .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupOid1), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids{kWcmpGroupMemberOid1}; + std::vector exp_create_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + Drain(); + std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); + auto *wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); + EXPECT_NE(nullptr, wcmp_group_entry_ptr); + EXPECT_EQ(1, wcmp_group_entry_ptr->wcmp_group_members.size()); + VerifyWcmpGroupMemberEntry(kNexthopId1, 1, wcmp_group_entry_ptr->wcmp_group_members[0]); + EXPECT_EQ(kWcmpGroupMemberOid1, wcmp_group_entry_ptr->wcmp_group_members[0]->member_oid); + EXPECT_TRUE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + // Update WCMP group with exact same members, the same entry will be removed + // and created again + Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, attributes)); + return_oids = {kWcmpGroupMemberOid3}; + exp_create_status = {SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + std::vector exp_remove_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + Drain(); + wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); + EXPECT_NE(nullptr, wcmp_group_entry_ptr); + EXPECT_EQ(1, wcmp_group_entry_ptr->wcmp_group_members.size()); + VerifyWcmpGroupMemberEntry(kNexthopId1, 1, wcmp_group_entry_ptr->wcmp_group_members[0]); + EXPECT_EQ(kWcmpGroupMemberOid3, wcmp_group_entry_ptr->wcmp_group_members[0]->member_oid); + EXPECT_TRUE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + // Update WCMP group with member {next_hop_id=kNexthopId2, weight=1} + actions.clear(); + action[prependParamField(p4orch::kNexthopId)] = kNexthopId2; + actions.push_back(action); + attributes.clear(); + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, attributes)); + return_oids = {kWcmpGroupMemberOid2}; + exp_create_status = {SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + exp_remove_status = {SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid3}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + Drain(); + wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); + EXPECT_NE(nullptr, wcmp_group_entry_ptr); + EXPECT_EQ(1, wcmp_group_entry_ptr->wcmp_group_members.size()); + VerifyWcmpGroupMemberEntry(kNexthopId2, 1, wcmp_group_entry_ptr->wcmp_group_members[0]); + EXPECT_EQ(kWcmpGroupMemberOid2, wcmp_group_entry_ptr->wcmp_group_members[0]->member_oid); + EXPECT_TRUE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(0, ref_cnt); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + // Update WCMP group with member {next_hop_id=kNexthopId2, weight=2} + actions.clear(); + action[p4orch::kWeight] = 2; + actions.push_back(action); + attributes.clear(); + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, attributes)); + return_oids = {kWcmpGroupMemberOid4}; + exp_create_status = {SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 2, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + exp_remove_status = {SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid2}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + Drain(); + wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); + EXPECT_NE(nullptr, wcmp_group_entry_ptr); + EXPECT_EQ(1, wcmp_group_entry_ptr->wcmp_group_members.size()); + VerifyWcmpGroupMemberEntry(kNexthopId2, 2, wcmp_group_entry_ptr->wcmp_group_members[0]); + EXPECT_EQ(kWcmpGroupMemberOid4, wcmp_group_entry_ptr->wcmp_group_members[0]->member_oid); + EXPECT_TRUE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey2, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); } -TEST_F(WcmpManagerTest, DeserializeWcmpGroup) { - std::string key = R"({"match/wcmp_group_id":"group-a"})"; - std::vector attributes; - nlohmann::json actions; - nlohmann::json action; - action[p4orch::kAction] = p4orch::kSetNexthopId; - action[p4orch::kWeight] = 2; - action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; - actions.push_back(action); - action[p4orch::kWeight] = 1; - action[prependParamField(p4orch::kNexthopId)] = kNexthopId2; - actions.push_back(action); - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - auto wcmp_group_entry_or = DeserializeP4WcmpGroupAppDbEntry(key, attributes); - EXPECT_TRUE(wcmp_group_entry_or.ok()); - auto& wcmp_group_entry = *wcmp_group_entry_or; - P4WcmpGroupEntry expect_entry = {}; - expect_entry.wcmp_group_id = "group-a"; - std::shared_ptr gm_entry1 = - createWcmpGroupMemberEntry(kNexthopId1, 2); - expect_entry.wcmp_group_members.push_back(gm_entry1); - std::shared_ptr gm_entry2 = - createWcmpGroupMemberEntry(kNexthopId2, 1); - expect_entry.wcmp_group_members.push_back(gm_entry2); - VerifyWcmpGroupEntry(expect_entry, wcmp_group_entry); +TEST_F(WcmpManagerTest, DeserializeWcmpGroup) +{ + std::string key = R"({"match/wcmp_group_id":"group-a"})"; + std::vector attributes; + nlohmann::json actions; + nlohmann::json action; + action[p4orch::kAction] = p4orch::kSetNexthopId; + action[p4orch::kWeight] = 2; + action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; + actions.push_back(action); + action[p4orch::kWeight] = 1; + action[prependParamField(p4orch::kNexthopId)] = kNexthopId2; + actions.push_back(action); + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + auto wcmp_group_entry_or = DeserializeP4WcmpGroupAppDbEntry(key, attributes); + EXPECT_TRUE(wcmp_group_entry_or.ok()); + auto &wcmp_group_entry = *wcmp_group_entry_or; + P4WcmpGroupEntry expect_entry = {}; + expect_entry.wcmp_group_id = "group-a"; + std::shared_ptr gm_entry1 = createWcmpGroupMemberEntry(kNexthopId1, 2); + expect_entry.wcmp_group_members.push_back(gm_entry1); + std::shared_ptr gm_entry2 = createWcmpGroupMemberEntry(kNexthopId2, 1); + expect_entry.wcmp_group_members.push_back(gm_entry2); + VerifyWcmpGroupEntry(expect_entry, wcmp_group_entry); } -TEST_F(WcmpManagerTest, DeserializeWcmpGroupDuplicateGroupMembers) { - std::string key = R"({"match/wcmp_group_id":"group-a"})"; - std::vector attributes; - nlohmann::json actions; - nlohmann::json action; - action[p4orch::kAction] = p4orch::kSetNexthopId; - action[p4orch::kWeight] = 1; - action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; - actions.push_back(action); - action[prependParamField(p4orch::kNexthopId)] = kNexthopId2; - actions.push_back(action); - action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; - actions.push_back(action); - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - auto return_code_or = DeserializeP4WcmpGroupAppDbEntry(key, attributes); - EXPECT_TRUE(return_code_or.ok()); +TEST_F(WcmpManagerTest, DeserializeWcmpGroupDuplicateGroupMembers) +{ + std::string key = R"({"match/wcmp_group_id":"group-a"})"; + std::vector attributes; + nlohmann::json actions; + nlohmann::json action; + action[p4orch::kAction] = p4orch::kSetNexthopId; + action[p4orch::kWeight] = 1; + action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; + actions.push_back(action); + action[prependParamField(p4orch::kNexthopId)] = kNexthopId2; + actions.push_back(action); + action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; + actions.push_back(action); + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + auto return_code_or = DeserializeP4WcmpGroupAppDbEntry(key, attributes); + EXPECT_TRUE(return_code_or.ok()); } -TEST_F(WcmpManagerTest, DeserializeWcmpGroupFailsWhenGroupKeyIsInvalidJson) { - std::vector attributes; - nlohmann::json actions; - nlohmann::json action; - action[p4orch::kAction] = p4orch::kSetNexthopId; - action[p4orch::kWeight] = 1; - action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; - actions.push_back(action); - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - // Invalid JSON - std::string key = R"("match/wcmp_group_id":"group-a"})"; - EXPECT_FALSE(DeserializeP4WcmpGroupAppDbEntry(key, attributes).ok()); - // Is string not JSON - key = R"("group-a")"; - EXPECT_FALSE(DeserializeP4WcmpGroupAppDbEntry(key, attributes).ok()); +TEST_F(WcmpManagerTest, DeserializeWcmpGroupFailsWhenGroupKeyIsInvalidJson) +{ + std::vector attributes; + nlohmann::json actions; + nlohmann::json action; + action[p4orch::kAction] = p4orch::kSetNexthopId; + action[p4orch::kWeight] = 1; + action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; + actions.push_back(action); + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + // Invalid JSON + std::string key = R"("match/wcmp_group_id":"group-a"})"; + EXPECT_FALSE(DeserializeP4WcmpGroupAppDbEntry(key, attributes).ok()); + // Is string not JSON + key = R"("group-a")"; + EXPECT_FALSE(DeserializeP4WcmpGroupAppDbEntry(key, attributes).ok()); } -TEST_F(WcmpManagerTest, DeserializeWcmpGroupFailsWhenActionsStringIsInvalid) { - std::string key = R"({"match/wcmp_group_id":"group-a"})"; - std::vector attributes; - // Actions field is an invalid JSON - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, "Undefied"}); - EXPECT_FALSE(DeserializeP4WcmpGroupAppDbEntry(key, attributes).ok()); - - attributes.clear(); - nlohmann::json action; - action[p4orch::kAction] = kSetNexthopId; - action[p4orch::kWeight] = 1; - action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; - // Actions field is not an array - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, action.dump()}); - EXPECT_FALSE(DeserializeP4WcmpGroupAppDbEntry(key, attributes).ok()); - - attributes.clear(); - nlohmann::json actions; - action[p4orch::kAction] = "Undefined"; - actions.push_back(action); - // Actions field has undefiend action - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - EXPECT_FALSE(DeserializeP4WcmpGroupAppDbEntry(key, attributes).ok()); - - attributes.clear(); - actions.clear(); - action.clear(); - action[p4orch::kAction] = kSetNexthopId; - action[p4orch::kWeight] = 1; - actions.push_back(action); - // Actions field has the group member without next_hop_id field - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - EXPECT_FALSE(DeserializeP4WcmpGroupAppDbEntry(key, attributes).ok()); - attributes.clear(); - actions.clear(); - action[p4orch::kAction] = kSetNexthopId; - action[p4orch::kWeight] = 1; - action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; - actions.push_back(action); - actions.push_back(action); - // Actions field has multiple group members have the same next_hop_id - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - EXPECT_TRUE(DeserializeP4WcmpGroupAppDbEntry(key, attributes).ok()); +TEST_F(WcmpManagerTest, DeserializeWcmpGroupFailsWhenActionsStringIsInvalid) +{ + std::string key = R"({"match/wcmp_group_id":"group-a"})"; + std::vector attributes; + // Actions field is an invalid JSON + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, "Undefied"}); + EXPECT_FALSE(DeserializeP4WcmpGroupAppDbEntry(key, attributes).ok()); + + attributes.clear(); + nlohmann::json action; + action[p4orch::kAction] = kSetNexthopId; + action[p4orch::kWeight] = 1; + action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; + // Actions field is not an array + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, action.dump()}); + EXPECT_FALSE(DeserializeP4WcmpGroupAppDbEntry(key, attributes).ok()); + + attributes.clear(); + nlohmann::json actions; + action[p4orch::kAction] = "Undefined"; + actions.push_back(action); + // Actions field has undefiend action + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + EXPECT_FALSE(DeserializeP4WcmpGroupAppDbEntry(key, attributes).ok()); + + attributes.clear(); + actions.clear(); + action.clear(); + action[p4orch::kAction] = kSetNexthopId; + action[p4orch::kWeight] = 1; + actions.push_back(action); + // Actions field has the group member without next_hop_id field + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + EXPECT_FALSE(DeserializeP4WcmpGroupAppDbEntry(key, attributes).ok()); + attributes.clear(); + actions.clear(); + action[p4orch::kAction] = kSetNexthopId; + action[p4orch::kWeight] = 1; + action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; + actions.push_back(action); + actions.push_back(action); + // Actions field has multiple group members have the same next_hop_id + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + EXPECT_TRUE(DeserializeP4WcmpGroupAppDbEntry(key, attributes).ok()); } -TEST_F(WcmpManagerTest, DeserializeWcmpGroupFailsWithUndefinedAttributes) { - std::string key = R"({"match/wcmp_group_id":"group-a"})"; - std::vector attributes; - // Undefined field in attribute list - attributes.push_back(swss::FieldValueTuple{"Undefined", "Undefined"}); - EXPECT_FALSE(DeserializeP4WcmpGroupAppDbEntry(key, attributes).ok()); +TEST_F(WcmpManagerTest, DeserializeWcmpGroupFailsWithUndefinedAttributes) +{ + std::string key = R"({"match/wcmp_group_id":"group-a"})"; + std::vector attributes; + // Undefined field in attribute list + attributes.push_back(swss::FieldValueTuple{"Undefined", "Undefined"}); + EXPECT_FALSE(DeserializeP4WcmpGroupAppDbEntry(key, attributes).ok()); } -TEST_F(WcmpManagerTest, - ValidateWcmpGroupEntryWithInvalidWatchportAttributeFails) { - const std::string kKeyPrefix = - std::string(APP_P4RT_WCMP_GROUP_TABLE_NAME) + kTableKeyDelimiter; - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); - nlohmann::json j; - j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; - std::vector attributes; - nlohmann::json actions; - nlohmann::json action; - action[p4orch::kAction] = p4orch::kSetNexthopId; - action[p4orch::kWatchPort] = "EthernetXX"; - action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; - actions.push_back(action); - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, - attributes)); - Drain(); - std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); - auto* wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); - EXPECT_EQ(nullptr, wcmp_group_entry_ptr); - EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(0, ref_cnt); +TEST_F(WcmpManagerTest, ValidateWcmpGroupEntryWithInvalidWatchportAttributeFails) +{ + const std::string kKeyPrefix = std::string(APP_P4RT_WCMP_GROUP_TABLE_NAME) + kTableKeyDelimiter; + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, kNexthopOid1); + nlohmann::json j; + j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; + std::vector attributes; + nlohmann::json actions; + nlohmann::json action; + action[p4orch::kAction] = p4orch::kSetNexthopId; + action[p4orch::kWatchPort] = "EthernetXX"; + action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; + actions.push_back(action); + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + Enqueue(swss::KeyOpFieldsValuesTuple(kKeyPrefix + j.dump(), SET_COMMAND, attributes)); + Drain(); + std::string key = KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1); + auto *wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); + EXPECT_EQ(nullptr, wcmp_group_entry_ptr); + EXPECT_FALSE(p4_oid_mapper_->existsOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, key)); + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(0, ref_cnt); } -TEST_F(WcmpManagerTest, PruneNextHopSucceeds) { - // Add member with operationally up watch port - std::string port_name = "Ethernet6"; - P4WcmpGroupEntry app_db_entry = - AddWcmpGroupEntryWithWatchport(port_name, true); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group_member(Eq(kWcmpGroupMemberOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - // Prune next hops associated with port - PruneNextHops(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); +TEST_F(WcmpManagerTest, PruneNextHopSucceeds) +{ + // Add member with operationally up watch port + std::string port_name = "Ethernet6"; + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name, true); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group_member(Eq(kWcmpGroupMemberOid1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + // Prune next hops associated with port + PruneNextHops(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); } -TEST_F(WcmpManagerTest, PruneNextHopFailsWithNextHopRemovalFailure) { - // Add member with operationally up watch port - std::string port_name = "Ethernet6"; - P4WcmpGroupEntry app_db_entry = - AddWcmpGroupEntryWithWatchport(port_name, true); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group_member(Eq(kWcmpGroupMemberOid1))) - .WillOnce(Return(SAI_STATUS_FAILURE)); - // TODO: Expect critical state. - // Prune next hops associated with port (fails) - PruneNextHops(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); +TEST_F(WcmpManagerTest, PruneNextHopFailsWithNextHopRemovalFailure) +{ + // Add member with operationally up watch port + std::string port_name = "Ethernet6"; + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name, true); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group_member(Eq(kWcmpGroupMemberOid1))) + .WillOnce(Return(SAI_STATUS_FAILURE)); + // TODO: Expect critical state. + // Prune next hops associated with port (fails) + PruneNextHops(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); } -TEST_F(WcmpManagerTest, RestorePrunedNextHopSucceeds) { - // Add member with operationally down watch port. Since associated watchport - // is operationally down, member will not be created in SAI but will be - // directly added to the pruned set of WCMP group members. - std::string port_name = "Ethernet1"; - P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); - EXPECT_CALL( - mock_sai_next_hop_group_, - create_next_hop_group_member( - _, Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchSaiNextHopGroupMemberAttribute, kNexthopOid1, 2, - kWcmpGroupOid1, std::placeholders::_1)))) - .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupMemberOid1), - Return(SAI_STATUS_SUCCESS))); - - // Restore next hops associated with port - RestorePrunedNextHops(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); +TEST_F(WcmpManagerTest, RestorePrunedNextHopSucceeds) +{ + // Add member with operationally down watch port. Since associated watchport + // is operationally down, member will not be created in SAI but will be + // directly added to the pruned set of WCMP group members. + std::string port_name = "Ethernet1"; + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_member(_, Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchSaiNextHopGroupMemberAttribute, kNexthopOid1, 2, + kWcmpGroupOid1, std::placeholders::_1)))) + .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupMemberOid1), Return(SAI_STATUS_SUCCESS))); + + // Restore next hops associated with port + RestorePrunedNextHops(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); } -TEST_F(WcmpManagerTest, RestorePrunedNextHopFailsWithNoOidMappingForWcmpGroup) { - // Add member with operationally down watch port. Since associated watchport - // is operationally down, member will not be created in SAI but will be - // directly added to the pruned set of WCMP group members. - std::string port_name = "Ethernet1"; - P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); - p4_oid_mapper_->eraseOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1)); - // TODO: Expect critical state. - RestorePrunedNextHops(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); +TEST_F(WcmpManagerTest, RestorePrunedNextHopFailsWithNoOidMappingForWcmpGroup) +{ + // Add member with operationally down watch port. Since associated watchport + // is operationally down, member will not be created in SAI but will be + // directly added to the pruned set of WCMP group members. + std::string port_name = "Ethernet1"; + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); + p4_oid_mapper_->eraseOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, KeyGenerator::generateWcmpGroupKey(kWcmpGroupId1)); + // TODO: Expect critical state. + RestorePrunedNextHops(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); } -TEST_F(WcmpManagerTest, RestorePrunedNextHopFailsWithNextHopCreationFailure) { - // Add member with operationally down watch port. Since associated watchport - // is operationally down, member will not be created in SAI but will be - // directly added to the pruned set of WCMP group members. - std::string port_name = "Ethernet1"; - P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); - EXPECT_CALL( - mock_sai_next_hop_group_, - create_next_hop_group_member( - _, Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchSaiNextHopGroupMemberAttribute, kNexthopOid1, 2, - kWcmpGroupOid1, std::placeholders::_1)))) - .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupMemberOid1), - Return(SAI_STATUS_FAILURE))); - // TODO: Expect critical state. - RestorePrunedNextHops(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); +TEST_F(WcmpManagerTest, RestorePrunedNextHopFailsWithNextHopCreationFailure) +{ + // Add member with operationally down watch port. Since associated watchport + // is operationally down, member will not be created in SAI but will be + // directly added to the pruned set of WCMP group members. + std::string port_name = "Ethernet1"; + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_member(_, Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchSaiNextHopGroupMemberAttribute, kNexthopOid1, 2, + kWcmpGroupOid1, std::placeholders::_1)))) + .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupMemberOid1), Return(SAI_STATUS_FAILURE))); + // TODO: Expect critical state. + RestorePrunedNextHops(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); } -TEST_F(WcmpManagerTest, - CreateGroupWithWatchportFailsWithNextHopCreationFailure) { - // Add member with operationally up watch port - // Create WCMP group with members kNexthopId1 and kNexthopId2 (fails) - std::string port_name = "Ethernet6"; - P4WcmpGroupEntry app_db_entry = {.wcmp_group_id = kWcmpGroupId1, - .wcmp_group_members = {}}; - std::shared_ptr gm1 = - createWcmpGroupMemberEntryWithWatchport(kNexthopId1, 1, port_name, - kWcmpGroupId1, kNexthopOid1); - app_db_entry.wcmp_group_members.push_back(gm1); - std::shared_ptr gm2 = - createWcmpGroupMemberEntryWithWatchport(kNexthopId2, 1, port_name, - kWcmpGroupId1, kNexthopOid2); - app_db_entry.wcmp_group_members.push_back(gm2); - EXPECT_CALL( - mock_sai_next_hop_group_, - create_next_hop_group(_, Eq(gSwitchId), Eq(1), - Truly(std::bind(MatchSaiNextHopGroupAttribute, - std::placeholders::_1)))) - .WillOnce( - DoAll(SetArgPointee<0>(kWcmpGroupOid1), Return(SAI_STATUS_SUCCESS))); - std::vector return_oids{kWcmpGroupMemberOid1, - SAI_NULL_OBJECT_ID}; - std::vector exp_create_status{SAI_STATUS_SUCCESS, - SAI_STATUS_FAILURE}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, - kWcmpGroupOid1), - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_FAILURE))); - // Clean up created members - std::vector exp_remove_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group(Eq(kWcmpGroupOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddRequest(&app_db_entry)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(gm1, false, 0)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(gm2, false, 0)); - EXPECT_FALSE(gm1->pruned); - EXPECT_FALSE(gm2->pruned); +TEST_F(WcmpManagerTest, CreateGroupWithWatchportFailsWithNextHopCreationFailure) +{ + // Add member with operationally up watch port + // Create WCMP group with members kNexthopId1 and kNexthopId2 (fails) + std::string port_name = "Ethernet6"; + P4WcmpGroupEntry app_db_entry = {.wcmp_group_id = kWcmpGroupId1, .wcmp_group_members = {}}; + std::shared_ptr gm1 = + createWcmpGroupMemberEntryWithWatchport(kNexthopId1, 1, port_name, kWcmpGroupId1, kNexthopOid1); + app_db_entry.wcmp_group_members.push_back(gm1); + std::shared_ptr gm2 = + createWcmpGroupMemberEntryWithWatchport(kNexthopId2, 1, port_name, kWcmpGroupId1, kNexthopOid2); + app_db_entry.wcmp_group_members.push_back(gm2); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group(_, Eq(gSwitchId), Eq(1), + Truly(std::bind(MatchSaiNextHopGroupAttribute, std::placeholders::_1)))) + .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupOid1), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids{kWcmpGroupMemberOid1, SAI_NULL_OBJECT_ID}; + std::vector exp_create_status{SAI_STATUS_SUCCESS, SAI_STATUS_FAILURE}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(2), ArrayEq(std::vector{3, 3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, kWcmpGroupOid1), + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_FAILURE))); + // Clean up created members + std::vector exp_remove_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group(Eq(kWcmpGroupOid1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessAddRequest(&app_db_entry)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(gm1, false, 0)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(gm2, false, 0)); + EXPECT_FALSE(gm1->pruned); + EXPECT_FALSE(gm2->pruned); } -TEST_F(WcmpManagerTest, RemoveWcmpGroupAfterPruningSucceeds) { - // Add member with operationally up watch port - std::string port_name = "Ethernet6"; - P4WcmpGroupEntry app_db_entry = - AddWcmpGroupEntryWithWatchport(port_name, true); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group_member(Eq(kWcmpGroupMemberOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - PruneNextHops(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); - - // Remove Wcmp group. No SAI call for member removal is expected as it is - // already pruned. - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group(Eq(kWcmpGroupOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, RemoveWcmpGroup(kWcmpGroupId1)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - false, 0)); +TEST_F(WcmpManagerTest, RemoveWcmpGroupAfterPruningSucceeds) +{ + // Add member with operationally up watch port + std::string port_name = "Ethernet6"; + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name, true); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group_member(Eq(kWcmpGroupMemberOid1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + PruneNextHops(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); + + // Remove Wcmp group. No SAI call for member removal is expected as it is + // already pruned. + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group(Eq(kWcmpGroupOid1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, RemoveWcmpGroup(kWcmpGroupId1)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], false, 0)); } -TEST_F(WcmpManagerTest, RemoveWcmpGroupWithOperationallyDownWatchportSucceeds) { - // Add member with operationally down watch port. Since associated watchport - // is operationally down, member will not be created in SAI but will be - // directly added to the pruned set of WCMP group members. - P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport("Ethernet1"); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); - - // Remove Wcmp group. No SAI call for member removal is expected as it is - // already pruned. - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group(Eq(kWcmpGroupOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, RemoveWcmpGroup(kWcmpGroupId1)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - false, 0)); +TEST_F(WcmpManagerTest, RemoveWcmpGroupWithOperationallyDownWatchportSucceeds) +{ + // Add member with operationally down watch port. Since associated watchport + // is operationally down, member will not be created in SAI but will be + // directly added to the pruned set of WCMP group members. + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport("Ethernet1"); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); + + // Remove Wcmp group. No SAI call for member removal is expected as it is + // already pruned. + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group(Eq(kWcmpGroupOid1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, RemoveWcmpGroup(kWcmpGroupId1)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], false, 0)); } -TEST_F(WcmpManagerTest, RemoveNextHopWithPrunedMember) { - // Add member with operationally down watch port. Since associated watchport - // is operationally down, member will not be created in SAI but will be - // directly added to the pruned set of WCMP group members. - P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport("Ethernet1"); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); - - // Verify that next hop reference count is incremented due to the member. - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - // Remove Wcmp group. No SAI call for member removal is expected as it is - // already pruned. - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group(Eq(kWcmpGroupOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, RemoveWcmpGroup(kWcmpGroupId1)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - false, 0)); - - // Verify that the next hop reference count is now 0. - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(0, ref_cnt); +TEST_F(WcmpManagerTest, RemoveNextHopWithPrunedMember) +{ + // Add member with operationally down watch port. Since associated watchport + // is operationally down, member will not be created in SAI but will be + // directly added to the pruned set of WCMP group members. + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport("Ethernet1"); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); + + // Verify that next hop reference count is incremented due to the member. + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + // Remove Wcmp group. No SAI call for member removal is expected as it is + // already pruned. + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group(Eq(kWcmpGroupOid1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, RemoveWcmpGroup(kWcmpGroupId1)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], false, 0)); + + // Verify that the next hop reference count is now 0. + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(0, ref_cnt); } -TEST_F(WcmpManagerTest, RemoveNextHopWithRestoredPrunedMember) { - // Add member with operationally down watch port. Since associated watchport - // is operationally down, member will not be created in SAI but will be - // directly added to the pruned set of WCMP group members. - std::string port_name = "Ethernet1"; - P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); - - // Verify that next hop reference count is incremented due to the member. - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - // Restore member associated with port. - EXPECT_CALL( - mock_sai_next_hop_group_, - create_next_hop_group_member( - _, Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchSaiNextHopGroupMemberAttribute, kNexthopOid1, 2, - kWcmpGroupOid1, std::placeholders::_1)))) - .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupMemberOid1), - Return(SAI_STATUS_SUCCESS))); - RestorePrunedNextHops(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); - - // Verify that next hop reference count remains the same after restore. - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - // Remove Wcmp group. - std::vector exp_remove_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group(Eq(kWcmpGroupOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, RemoveWcmpGroup(kWcmpGroupId1)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - false, 0)); - - // Verify that the next hop reference count is now 0. - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(0, ref_cnt); +TEST_F(WcmpManagerTest, RemoveNextHopWithRestoredPrunedMember) +{ + // Add member with operationally down watch port. Since associated watchport + // is operationally down, member will not be created in SAI but will be + // directly added to the pruned set of WCMP group members. + std::string port_name = "Ethernet1"; + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); + + // Verify that next hop reference count is incremented due to the member. + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + // Restore member associated with port. + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_member(_, Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchSaiNextHopGroupMemberAttribute, kNexthopOid1, 2, + kWcmpGroupOid1, std::placeholders::_1)))) + .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupMemberOid1), Return(SAI_STATUS_SUCCESS))); + RestorePrunedNextHops(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); + + // Verify that next hop reference count remains the same after restore. + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + // Remove Wcmp group. + std::vector exp_remove_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group(Eq(kWcmpGroupOid1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, RemoveWcmpGroup(kWcmpGroupId1)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], false, 0)); + + // Verify that the next hop reference count is now 0. + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(0, ref_cnt); } -TEST_F(WcmpManagerTest, VerifyNextHopRefCountWhenMemberPruned) { - // Add member with operationally up watch port - std::string port_name = "Ethernet6"; - P4WcmpGroupEntry app_db_entry = - AddWcmpGroupEntryWithWatchport(port_name, true); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); - - // Verify that next hop reference count is incremented due to the member. - uint32_t ref_cnt; - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); - - // Prune member associated with port. - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group_member(Eq(kWcmpGroupMemberOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - PruneNextHops(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); - - // Verify that next hop reference count does not change on pruning. - EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, - kNexthopKey1, &ref_cnt)); - EXPECT_EQ(1, ref_cnt); +TEST_F(WcmpManagerTest, VerifyNextHopRefCountWhenMemberPruned) +{ + // Add member with operationally up watch port + std::string port_name = "Ethernet6"; + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name, true); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); + + // Verify that next hop reference count is incremented due to the member. + uint32_t ref_cnt; + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); + + // Prune member associated with port. + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group_member(Eq(kWcmpGroupMemberOid1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + PruneNextHops(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); + + // Verify that next hop reference count does not change on pruning. + EXPECT_TRUE(p4_oid_mapper_->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP, kNexthopKey1, &ref_cnt)); + EXPECT_EQ(1, ref_cnt); } -TEST_F(WcmpManagerTest, - UpdateWcmpGroupWithOperationallyUpWatchportMemberSucceeds) { - // Add member with operationally up watch port - std::string port_name = "Ethernet6"; - P4WcmpGroupEntry app_db_entry = - AddWcmpGroupEntryWithWatchport(port_name, true); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); - - // Update WCMP group to remove kNexthopId1 and add kNexthopId2 - P4WcmpGroupEntry updated_app_db_entry; - updated_app_db_entry.wcmp_group_id = kWcmpGroupId1; - std::shared_ptr updated_gm = - createWcmpGroupMemberEntryWithWatchport(kNexthopId2, 1, port_name, - kWcmpGroupId1, kNexthopOid2); - updated_app_db_entry.wcmp_group_members.push_back(updated_gm); - std::vector return_oids{kWcmpGroupMemberOid2}; - std::vector exp_create_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - std::vector exp_remove_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRequest(&updated_app_db_entry)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - false, 1)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(updated_gm, true, 1)); - EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); - EXPECT_FALSE(updated_gm->pruned); +TEST_F(WcmpManagerTest, UpdateWcmpGroupWithOperationallyUpWatchportMemberSucceeds) +{ + // Add member with operationally up watch port + std::string port_name = "Ethernet6"; + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name, true); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); + + // Update WCMP group to remove kNexthopId1 and add kNexthopId2 + P4WcmpGroupEntry updated_app_db_entry; + updated_app_db_entry.wcmp_group_id = kWcmpGroupId1; + std::shared_ptr updated_gm = + createWcmpGroupMemberEntryWithWatchport(kNexthopId2, 1, port_name, kWcmpGroupId1, kNexthopOid2); + updated_app_db_entry.wcmp_group_members.push_back(updated_gm); + std::vector return_oids{kWcmpGroupMemberOid2}; + std::vector exp_create_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + std::vector exp_remove_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRequest(&updated_app_db_entry)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], false, 1)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(updated_gm, true, 1)); + EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); + EXPECT_FALSE(updated_gm->pruned); } -TEST_F(WcmpManagerTest, - UpdateWcmpGroupWithOperationallyDownWatchportMemberSucceeds) { - // Add member with operationally down watch port. Since associated watchport - // is operationally down, member will not be created in SAI but will be - // directly added to the pruned set of WCMP group members. - std::string port_name = "Ethernet1"; - P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); - - // Update WCMP group to remove kNexthopId1 and add kNexthopId2. No SAI calls - // are expected as the associated watch port is operationally down. - P4WcmpGroupEntry updated_app_db_entry; - updated_app_db_entry.wcmp_group_id = kWcmpGroupId1; - std::shared_ptr updated_gm = - createWcmpGroupMemberEntryWithWatchport(kNexthopId2, 1, port_name, - kWcmpGroupId1, kNexthopOid2); - updated_app_db_entry.wcmp_group_members.push_back(updated_gm); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRequest(&updated_app_db_entry)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - false, 1)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(updated_gm, true, 1)); - EXPECT_TRUE(updated_gm->pruned); +TEST_F(WcmpManagerTest, UpdateWcmpGroupWithOperationallyDownWatchportMemberSucceeds) +{ + // Add member with operationally down watch port. Since associated watchport + // is operationally down, member will not be created in SAI but will be + // directly added to the pruned set of WCMP group members. + std::string port_name = "Ethernet1"; + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); + + // Update WCMP group to remove kNexthopId1 and add kNexthopId2. No SAI calls + // are expected as the associated watch port is operationally down. + P4WcmpGroupEntry updated_app_db_entry; + updated_app_db_entry.wcmp_group_id = kWcmpGroupId1; + std::shared_ptr updated_gm = + createWcmpGroupMemberEntryWithWatchport(kNexthopId2, 1, port_name, kWcmpGroupId1, kNexthopOid2); + updated_app_db_entry.wcmp_group_members.push_back(updated_gm); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRequest(&updated_app_db_entry)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], false, 1)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(updated_gm, true, 1)); + EXPECT_TRUE(updated_gm->pruned); } -TEST_F(WcmpManagerTest, PruneAfterWcmpGroupUpdateSucceeds) { - // Add member with operationally up watch port - std::string port_name = "Ethernet6"; - P4WcmpGroupEntry app_db_entry = - AddWcmpGroupEntryWithWatchport(port_name, true); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); - - // Update WCMP group to modify weight of kNexthopId1. - P4WcmpGroupEntry updated_app_db_entry; - updated_app_db_entry.wcmp_group_id = kWcmpGroupId1; - std::shared_ptr updated_gm = - createWcmpGroupMemberEntryWithWatchport(kNexthopId1, 10, port_name, - kWcmpGroupId1, kNexthopOid1); - updated_app_db_entry.wcmp_group_members.push_back(updated_gm); - std::vector exp_remove_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - std::vector return_oids{kWcmpGroupMemberOid1}; - std::vector exp_create_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 10, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRequest(&updated_app_db_entry)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - false, 1)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap( - updated_app_db_entry.wcmp_group_members[0], true, 1)); - EXPECT_FALSE(updated_app_db_entry.wcmp_group_members[0]->pruned); - - // Prune members associated with port. - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group_member(Eq(kWcmpGroupMemberOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - PruneNextHops(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap( - updated_app_db_entry.wcmp_group_members[0], true, 1)); - EXPECT_TRUE(updated_app_db_entry.wcmp_group_members[0]->pruned); - - // Remove Wcmp group. No SAI call for member removal is expected as it is - // already pruned. - // RemoveWcmpGroupWithOperationallyDownWatchportSucceeds verfies that SAI call - // for pruned member is not made on group removal. Hence, the member must be - // removed from SAI during prune. - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group(Eq(kWcmpGroupOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, RemoveWcmpGroup(kWcmpGroupId1)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap( - updated_app_db_entry.wcmp_group_members[0], false, 0)); +TEST_F(WcmpManagerTest, PruneAfterWcmpGroupUpdateSucceeds) +{ + // Add member with operationally up watch port + std::string port_name = "Ethernet6"; + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name, true); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); + + // Update WCMP group to modify weight of kNexthopId1. + P4WcmpGroupEntry updated_app_db_entry; + updated_app_db_entry.wcmp_group_id = kWcmpGroupId1; + std::shared_ptr updated_gm = + createWcmpGroupMemberEntryWithWatchport(kNexthopId1, 10, port_name, kWcmpGroupId1, kNexthopOid1); + updated_app_db_entry.wcmp_group_members.push_back(updated_gm); + std::vector exp_remove_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids{kWcmpGroupMemberOid1}; + std::vector exp_create_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 10, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids.begin(), return_oids.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRequest(&updated_app_db_entry)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], false, 1)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(updated_app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_FALSE(updated_app_db_entry.wcmp_group_members[0]->pruned); + + // Prune members associated with port. + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group_member(Eq(kWcmpGroupMemberOid1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + PruneNextHops(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(updated_app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(updated_app_db_entry.wcmp_group_members[0]->pruned); + + // Remove Wcmp group. No SAI call for member removal is expected as it is + // already pruned. + // RemoveWcmpGroupWithOperationallyDownWatchportSucceeds verfies that SAI call + // for pruned member is not made on group removal. Hence, the member must be + // removed from SAI during prune. + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group(Eq(kWcmpGroupOid1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, RemoveWcmpGroup(kWcmpGroupId1)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(updated_app_db_entry.wcmp_group_members[0], false, 0)); } -TEST_F(WcmpManagerTest, PrunedMemberUpdateOnRestoreSucceeds) { - // Add member with operationally down watch port. Since associated watchport - // is operationally down, member will not be created in SAI but will be - // directly added to the pruned set of WCMP group members. - std::string port_name = "Ethernet1"; - P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); - - // Update WCMP group to modify weight of kNexthopId1. - P4WcmpGroupEntry updated_app_db_entry; - updated_app_db_entry.wcmp_group_id = kWcmpGroupId1; - std::shared_ptr updated_gm = - createWcmpGroupMemberEntryWithWatchport(kNexthopId1, 10, port_name, - kWcmpGroupId1, kNexthopOid1); - updated_app_db_entry.wcmp_group_members.push_back(updated_gm); - EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, - ProcessUpdateRequest(&updated_app_db_entry)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - false, 1)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap( - updated_app_db_entry.wcmp_group_members[0], true, 1)); - EXPECT_TRUE(updated_app_db_entry.wcmp_group_members[0]->pruned); - - // Restore members associated with port. - // Verify that the weight of the restored member is updated. - EXPECT_CALL( - mock_sai_next_hop_group_, - create_next_hop_group_member( - _, Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchSaiNextHopGroupMemberAttribute, kNexthopOid1, 10, - kWcmpGroupOid1, std::placeholders::_1)))) - .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupMemberOid1), - Return(SAI_STATUS_SUCCESS))); - RestorePrunedNextHops(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap( - updated_app_db_entry.wcmp_group_members[0], true, 1)); - EXPECT_FALSE(updated_app_db_entry.wcmp_group_members[0]->pruned); +TEST_F(WcmpManagerTest, PrunedMemberUpdateOnRestoreSucceeds) +{ + // Add member with operationally down watch port. Since associated watchport + // is operationally down, member will not be created in SAI but will be + // directly added to the pruned set of WCMP group members. + std::string port_name = "Ethernet1"; + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); + + // Update WCMP group to modify weight of kNexthopId1. + P4WcmpGroupEntry updated_app_db_entry; + updated_app_db_entry.wcmp_group_id = kWcmpGroupId1; + std::shared_ptr updated_gm = + createWcmpGroupMemberEntryWithWatchport(kNexthopId1, 10, port_name, kWcmpGroupId1, kNexthopOid1); + updated_app_db_entry.wcmp_group_members.push_back(updated_gm); + EXPECT_EQ(StatusCode::SWSS_RC_SUCCESS, ProcessUpdateRequest(&updated_app_db_entry)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], false, 1)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(updated_app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(updated_app_db_entry.wcmp_group_members[0]->pruned); + + // Restore members associated with port. + // Verify that the weight of the restored member is updated. + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_member(_, Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchSaiNextHopGroupMemberAttribute, kNexthopOid1, 10, + kWcmpGroupOid1, std::placeholders::_1)))) + .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupMemberOid1), Return(SAI_STATUS_SUCCESS))); + RestorePrunedNextHops(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(updated_app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_FALSE(updated_app_db_entry.wcmp_group_members[0]->pruned); } -TEST_F( - WcmpManagerTest, - UpdateWcmpGroupWithOperationallyUpWatchportMemberFailsWithMemberRemovalFailure) { - // Add member with operationally up watch port - std::string port_name = "Ethernet6"; - P4WcmpGroupEntry app_db_entry = - AddWcmpGroupEntryWithWatchport(port_name, true); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); - - // Update WCMP group to remove kNexthopId1(fails) and add kNexthopId2 - P4WcmpGroupEntry updated_app_db_entry; - updated_app_db_entry.wcmp_group_id = kWcmpGroupId1; - std::shared_ptr updated_gm2 = - createWcmpGroupMemberEntryWithWatchport(kNexthopId2, 10, port_name, - kWcmpGroupId1, kNexthopOid2); - std::shared_ptr updated_gm1 = - createWcmpGroupMemberEntryWithWatchport(kNexthopId1, 1, port_name, - kWcmpGroupId1, kNexthopOid1); - updated_app_db_entry.wcmp_group_members.push_back(updated_gm1); - updated_app_db_entry.wcmp_group_members.push_back(updated_gm2); - std::vector exp_remove_status{SAI_STATUS_SUCCESS}; - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - std::vector return_oids_4{kWcmpGroupMemberOid4}; - std::vector return_oids_null{SAI_NULL_OBJECT_ID}; - std::vector exp_create_status{SAI_STATUS_SUCCESS}; - std::vector exp_create_status_fail{ - SAI_STATUS_INSUFFICIENT_RESOURCES}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_4.begin(), return_oids_4.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 10, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce(DoAll( - SetArrayArgument<5>(return_oids_null.begin(), return_oids_null.end()), - SetArrayArgument<6>(exp_create_status_fail.begin(), - exp_create_status_fail.end()), - Return(SAI_STATUS_INSUFFICIENT_RESOURCES))); - // Clean up created member-succeeds - std::vector return_oids_1{kWcmpGroupMemberOid1}; - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_1.begin(), return_oids_1.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid4}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, - ProcessUpdateRequest(&updated_app_db_entry)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(updated_gm2, false, 1)); - EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); - EXPECT_FALSE(updated_gm2->pruned); - - // Update again, this time clean up fails - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce( - DoAll(SetArrayArgument<5>(return_oids_4.begin(), return_oids_4.end()), - SetArrayArgument<6>(exp_create_status.begin(), - exp_create_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 10, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce(DoAll( - SetArrayArgument<5>(return_oids_null.begin(), return_oids_null.end()), - SetArrayArgument<6>(exp_create_status_fail.begin(), - exp_create_status_fail.end()), - Return(SAI_STATUS_INSUFFICIENT_RESOURCES))); - // Clean up created member(fails) - EXPECT_CALL( - mock_sai_next_hop_group_, - remove_next_hop_group_members( - Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid4}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) - .WillOnce(DoAll(SetArrayArgument<3>(exp_remove_status.begin(), - exp_remove_status.end()), - Return(SAI_STATUS_SUCCESS))); - EXPECT_CALL(mock_sai_next_hop_group_, - create_next_hop_group_members( - Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), - AttrArrayArrayEq(std::vector>{ - GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, - kWcmpGroupOid1)}), - Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) - .WillOnce(DoAll( - SetArrayArgument<5>(return_oids_null.begin(), return_oids_null.end()), - SetArrayArgument<6>(exp_create_status_fail.begin(), - exp_create_status_fail.end()), - Return(SAI_STATUS_INSUFFICIENT_RESOURCES))); - // TODO: Expect critical state. - EXPECT_EQ("Fail to create wcmp group member: 'ju1u32m2.atl11:qe-3/7'", - ProcessUpdateRequest(&updated_app_db_entry).message()); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - false, 0)); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(updated_gm2, false, 0)); - EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); - EXPECT_FALSE(updated_gm2->pruned); +TEST_F(WcmpManagerTest, UpdateWcmpGroupWithOperationallyUpWatchportMemberFailsWithMemberRemovalFailure) +{ + // Add member with operationally up watch port + std::string port_name = "Ethernet6"; + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name, true); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); + + // Update WCMP group to remove kNexthopId1(fails) and add kNexthopId2 + P4WcmpGroupEntry updated_app_db_entry; + updated_app_db_entry.wcmp_group_id = kWcmpGroupId1; + std::shared_ptr updated_gm2 = + createWcmpGroupMemberEntryWithWatchport(kNexthopId2, 10, port_name, kWcmpGroupId1, kNexthopOid2); + std::shared_ptr updated_gm1 = + createWcmpGroupMemberEntryWithWatchport(kNexthopId1, 1, port_name, kWcmpGroupId1, kNexthopOid1); + updated_app_db_entry.wcmp_group_members.push_back(updated_gm1); + updated_app_db_entry.wcmp_group_members.push_back(updated_gm2); + std::vector exp_remove_status{SAI_STATUS_SUCCESS}; + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + std::vector return_oids_4{kWcmpGroupMemberOid4}; + std::vector return_oids_null{SAI_NULL_OBJECT_ID}; + std::vector exp_create_status{SAI_STATUS_SUCCESS}; + std::vector exp_create_status_fail{SAI_STATUS_INSUFFICIENT_RESOURCES}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_4.begin(), return_oids_4.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 10, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_null.begin(), return_oids_null.end()), + SetArrayArgument<6>(exp_create_status_fail.begin(), exp_create_status_fail.end()), + Return(SAI_STATUS_INSUFFICIENT_RESOURCES))); + // Clean up created member-succeeds + std::vector return_oids_1{kWcmpGroupMemberOid1}; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_1.begin(), return_oids_1.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid4}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_EQ(StatusCode::SWSS_RC_UNKNOWN, ProcessUpdateRequest(&updated_app_db_entry)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(updated_gm2, false, 1)); + EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); + EXPECT_FALSE(updated_gm2->pruned); + + // Update again, this time clean up fails + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid1}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 1, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_4.begin(), return_oids_4.end()), + SetArrayArgument<6>(exp_create_status.begin(), exp_create_status.end()), + Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid2, 10, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_null.begin(), return_oids_null.end()), + SetArrayArgument<6>(exp_create_status_fail.begin(), exp_create_status_fail.end()), + Return(SAI_STATUS_INSUFFICIENT_RESOURCES))); + // Clean up created member(fails) + EXPECT_CALL(mock_sai_next_hop_group_, + remove_next_hop_group_members(Eq(1), ArrayEq(std::vector{kWcmpGroupMemberOid4}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _)) + .WillOnce( + DoAll(SetArrayArgument<3>(exp_remove_status.begin(), exp_remove_status.end()), Return(SAI_STATUS_SUCCESS))); + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_members(Eq(gSwitchId), Eq(1), ArrayEq(std::vector{3}), + AttrArrayArrayEq(std::vector>{ + GetSaiNextHopGroupMemberAttribute(kNexthopOid1, 2, kWcmpGroupOid1)}), + Eq(SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR), _, _)) + .WillOnce(DoAll(SetArrayArgument<5>(return_oids_null.begin(), return_oids_null.end()), + SetArrayArgument<6>(exp_create_status_fail.begin(), exp_create_status_fail.end()), + Return(SAI_STATUS_INSUFFICIENT_RESOURCES))); + // TODO: Expect critical state. + EXPECT_EQ("Fail to create wcmp group member: 'ju1u32m2.atl11:qe-3/7'", + ProcessUpdateRequest(&updated_app_db_entry).message()); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], false, 0)); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(updated_gm2, false, 0)); + EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); + EXPECT_FALSE(updated_gm2->pruned); } -TEST_F(WcmpManagerTest, WatchportStateChangetoOperDownSucceeds) { - // Add member with operationally up watch port - std::string port_name = "Ethernet6"; - P4WcmpGroupEntry app_db_entry = - AddWcmpGroupEntryWithWatchport(port_name, true); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); - - // Send port down signal - // Verify that the next hop member associated with the port is pruned. - std::string op = "port_state_change"; - std::string data = - "[{\"port_id\":\"oid:0x56789abcdff\",\"port_state\":\"SAI_PORT_OPER_" - "STATUS_DOWN\"}]"; - EXPECT_CALL(mock_sai_next_hop_group_, - remove_next_hop_group_member(Eq(kWcmpGroupMemberOid1))) - .WillOnce(Return(SAI_STATUS_SUCCESS)); - HandlePortStatusChangeNotification(op, data); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); +TEST_F(WcmpManagerTest, WatchportStateChangetoOperDownSucceeds) +{ + // Add member with operationally up watch port + std::string port_name = "Ethernet6"; + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name, true); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); + + // Send port down signal + // Verify that the next hop member associated with the port is pruned. + std::string op = "port_state_change"; + std::string data = "[{\"port_id\":\"oid:0x56789abcdff\",\"port_state\":\"SAI_PORT_OPER_" + "STATUS_DOWN\"}]"; + EXPECT_CALL(mock_sai_next_hop_group_, remove_next_hop_group_member(Eq(kWcmpGroupMemberOid1))) + .WillOnce(Return(SAI_STATUS_SUCCESS)); + HandlePortStatusChangeNotification(op, data); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); } -TEST_F(WcmpManagerTest, WatchportStateChangeToOperUpSucceeds) { - // Add member with operationally down watch port. Since associated watchport - // is operationally down, member will not be created in SAI but will be - // directly added to the pruned set of WCMP group members. - std::string port_name = "Ethernet1"; - P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); - - // Send port up signal. - // Verify that the pruned next hop member associated with the port is - // restored. - std::string op = "port_state_change"; - std::string data = - "[{\"port_id\":\"oid:0x112233\",\"port_state\":\"SAI_PORT_OPER_" - "STATUS_UP\"}]"; - EXPECT_CALL( - mock_sai_next_hop_group_, - create_next_hop_group_member( - _, Eq(gSwitchId), Eq(3), - Truly(std::bind(MatchSaiNextHopGroupMemberAttribute, kNexthopOid1, 2, - kWcmpGroupOid1, std::placeholders::_1)))) - .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupMemberOid1), - Return(SAI_STATUS_SUCCESS))); - HandlePortStatusChangeNotification(op, data); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); +TEST_F(WcmpManagerTest, WatchportStateChangeToOperUpSucceeds) +{ + // Add member with operationally down watch port. Since associated watchport + // is operationally down, member will not be created in SAI but will be + // directly added to the pruned set of WCMP group members. + std::string port_name = "Ethernet1"; + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); + + // Send port up signal. + // Verify that the pruned next hop member associated with the port is + // restored. + std::string op = "port_state_change"; + std::string data = "[{\"port_id\":\"oid:0x112233\",\"port_state\":\"SAI_PORT_OPER_" + "STATUS_UP\"}]"; + EXPECT_CALL(mock_sai_next_hop_group_, + create_next_hop_group_member(_, Eq(gSwitchId), Eq(3), + Truly(std::bind(MatchSaiNextHopGroupMemberAttribute, kNexthopOid1, 2, + kWcmpGroupOid1, std::placeholders::_1)))) + .WillOnce(DoAll(SetArgPointee<0>(kWcmpGroupMemberOid1), Return(SAI_STATUS_SUCCESS))); + HandlePortStatusChangeNotification(op, data); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_FALSE(app_db_entry.wcmp_group_members[0]->pruned); } -TEST_F(WcmpManagerTest, - WatchportStateChangeFromOperUnknownToDownPrunesMemberOnlyOnceSuceeds) { - // Add member with operationally unknown watch port. Since associated - // watchport is not operationally up, member will not be created in SAI but - // will be directly added to the pruned set of WCMP group members. - std::string port_name = "Ethernet1"; - P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); - - // Send port down signal. - // Verify that the pruned next hop member is not pruned again. - std::string op = "port_state_change"; - std::string data = - "[{\"port_id\":\"oid:0x56789abcfff\",\"port_state\":\"SAI_PORT_OPER_" - "STATUS_DOWN\"}]"; - HandlePortStatusChangeNotification(op, data); - EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], - true, 1)); - EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); +TEST_F(WcmpManagerTest, WatchportStateChangeFromOperUnknownToDownPrunesMemberOnlyOnceSuceeds) +{ + // Add member with operationally unknown watch port. Since associated + // watchport is not operationally up, member will not be created in SAI but + // will be directly added to the pruned set of WCMP group members. + std::string port_name = "Ethernet1"; + P4WcmpGroupEntry app_db_entry = AddWcmpGroupEntryWithWatchport(port_name); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); + + // Send port down signal. + // Verify that the pruned next hop member is not pruned again. + std::string op = "port_state_change"; + std::string data = "[{\"port_id\":\"oid:0x56789abcfff\",\"port_state\":\"SAI_PORT_OPER_" + "STATUS_DOWN\"}]"; + HandlePortStatusChangeNotification(op, data); + EXPECT_TRUE(VerifyWcmpGroupMemberInPortMap(app_db_entry.wcmp_group_members[0], true, 1)); + EXPECT_TRUE(app_db_entry.wcmp_group_members[0]->pruned); } -TEST_F(WcmpManagerTest, VerifyStateTest) { - AddWcmpGroupEntryWithWatchport("Ethernet6", true); - nlohmann::json j; - j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; - const std::string db_key = - std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + - APP_P4RT_WCMP_GROUP_TABLE_NAME + kTableKeyDelimiter + j.dump(); - std::vector attributes; - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set("SAI_OBJECT_TYPE_NEXT_HOP_GROUP:oid:0xa", - std::vector{swss::FieldValueTuple{ - "SAI_NEXT_HOP_GROUP_ATTR_TYPE", - "SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP"}}); - table.set( - "SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER:oid:0xb", - std::vector{ - swss::FieldValueTuple{ - "SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID", "oid:0xa"}, - swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID", - "oid:0x1"}, - swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT", "2"}}); - - // Verification should succeed with vaild key and value. - nlohmann::json actions; - nlohmann::json action; - action[p4orch::kAction] = p4orch::kSetNexthopId; - action[p4orch::kWeight] = 2; - action[p4orch::kWatchPort] = "Ethernet6"; - action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; - actions.push_back(action); - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - EXPECT_EQ(VerifyState(db_key, attributes), ""); - - // Invalid key should fail verification. - EXPECT_FALSE(VerifyState("invalid", attributes).empty()); - EXPECT_FALSE(VerifyState("invalid:invalid", attributes).empty()); - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes) - .empty()); - EXPECT_FALSE( - VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", - attributes) - .empty()); - EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + - ":FIXED_WCMP_GROUP_TABLE:invalid", - attributes) - .empty()); - - // Non-existing entry should fail verification. - j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId2; - EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + - kTableKeyDelimiter + - APP_P4RT_WCMP_GROUP_TABLE_NAME + - kTableKeyDelimiter + j.dump(), - attributes) - .empty()); - - // Non-existing nexthop should fail verification. - actions.clear(); - attributes.clear(); - action[prependParamField(p4orch::kNexthopId)] = "invalid"; - actions.push_back(action); - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - actions.clear(); - attributes.clear(); - action[p4orch::kAction] = p4orch::kSetNexthopId; - action[p4orch::kWeight] = 2; - action[p4orch::kWatchPort] = "Ethernet6"; - action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; - actions.push_back(action); - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - - auto* wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); - EXPECT_NE(nullptr, wcmp_group_entry_ptr); - - // Verification should fail if WCMP group ID mismatches. - auto saved_wcmp_group_id = wcmp_group_entry_ptr->wcmp_group_id; - wcmp_group_entry_ptr->wcmp_group_id = kWcmpGroupId2; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - wcmp_group_entry_ptr->wcmp_group_id = saved_wcmp_group_id; - - // Verification should fail if WCMP group ID mismatches. - auto saved_wcmp_group_oid = wcmp_group_entry_ptr->wcmp_group_oid; - wcmp_group_entry_ptr->wcmp_group_oid = 1111; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - wcmp_group_entry_ptr->wcmp_group_oid = saved_wcmp_group_oid; - - // Verification should fail if group size mismatches. - wcmp_group_entry_ptr->wcmp_group_members.push_back( - std::make_shared()); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - wcmp_group_entry_ptr->wcmp_group_members.pop_back(); - - // Verification should fail if member nexthop ID mismatches. - auto saved_next_hop_id = - wcmp_group_entry_ptr->wcmp_group_members[0]->next_hop_id; - wcmp_group_entry_ptr->wcmp_group_members[0]->next_hop_id = kNexthopId3; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - wcmp_group_entry_ptr->wcmp_group_members[0]->next_hop_id = saved_next_hop_id; - - // Verification should fail if member weight mismatches. - auto saved_weight = wcmp_group_entry_ptr->wcmp_group_members[0]->weight; - wcmp_group_entry_ptr->wcmp_group_members[0]->weight = 3; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - wcmp_group_entry_ptr->wcmp_group_members[0]->weight = saved_weight; - - // Verification should fail if member watch port mismatches. - auto saved_watch_port = - wcmp_group_entry_ptr->wcmp_group_members[0]->watch_port; - wcmp_group_entry_ptr->wcmp_group_members[0]->watch_port = "invalid"; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - wcmp_group_entry_ptr->wcmp_group_members[0]->watch_port = saved_watch_port; - - // Verification should fail if member WCMP group ID mismatches. - auto saved_member_wcmp_group_id = - wcmp_group_entry_ptr->wcmp_group_members[0]->wcmp_group_id; - wcmp_group_entry_ptr->wcmp_group_members[0]->wcmp_group_id = kWcmpGroupId2; - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - wcmp_group_entry_ptr->wcmp_group_members[0]->wcmp_group_id = - saved_member_wcmp_group_id; - - // Verification should fail if member OID mapper mismatches. - p4_oid_mapper_->eraseOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, - kWcmpGroupKey1 + kTableKeyDelimiter + - sai_serialize_object_id(kWcmpGroupMemberOid1)); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, - kWcmpGroupKey1 + kTableKeyDelimiter + - sai_serialize_object_id(kWcmpGroupMemberOid1), - kWcmpGroupMemberOid1); +TEST_F(WcmpManagerTest, VerifyStateTest) +{ + AddWcmpGroupEntryWithWatchport("Ethernet6", true); + nlohmann::json j; + j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_WCMP_GROUP_TABLE_NAME + + kTableKeyDelimiter + j.dump(); + std::vector attributes; + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set("SAI_OBJECT_TYPE_NEXT_HOP_GROUP:oid:0xa", + std::vector{swss::FieldValueTuple{ + "SAI_NEXT_HOP_GROUP_ATTR_TYPE", "SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP"}}); + table.set("SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER:oid:0xb", + std::vector{ + swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID", "oid:0xa"}, + swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID", "oid:0x1"}, + swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT", "2"}}); + + // Verification should succeed with vaild key and value. + nlohmann::json actions; + nlohmann::json action; + action[p4orch::kAction] = p4orch::kSetNexthopId; + action[p4orch::kWeight] = 2; + action[p4orch::kWatchPort] = "Ethernet6"; + action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; + actions.push_back(action); + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + EXPECT_EQ(VerifyState(db_key, attributes), ""); + + // Invalid key should fail verification. + EXPECT_FALSE(VerifyState("invalid", attributes).empty()); + EXPECT_FALSE(VerifyState("invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":invalid:invalid", attributes).empty()); + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + ":FIXED_WCMP_GROUP_TABLE:invalid", attributes).empty()); + + // Non-existing entry should fail verification. + j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId2; + EXPECT_FALSE(VerifyState(std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_WCMP_GROUP_TABLE_NAME + + kTableKeyDelimiter + j.dump(), + attributes) + .empty()); + + // Non-existing nexthop should fail verification. + actions.clear(); + attributes.clear(); + action[prependParamField(p4orch::kNexthopId)] = "invalid"; + actions.push_back(action); + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + actions.clear(); + attributes.clear(); + action[p4orch::kAction] = p4orch::kSetNexthopId; + action[p4orch::kWeight] = 2; + action[p4orch::kWatchPort] = "Ethernet6"; + action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; + actions.push_back(action); + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + + auto *wcmp_group_entry_ptr = GetWcmpGroupEntry(kWcmpGroupId1); + EXPECT_NE(nullptr, wcmp_group_entry_ptr); + + // Verification should fail if WCMP group ID mismatches. + auto saved_wcmp_group_id = wcmp_group_entry_ptr->wcmp_group_id; + wcmp_group_entry_ptr->wcmp_group_id = kWcmpGroupId2; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + wcmp_group_entry_ptr->wcmp_group_id = saved_wcmp_group_id; + + // Verification should fail if WCMP group ID mismatches. + auto saved_wcmp_group_oid = wcmp_group_entry_ptr->wcmp_group_oid; + wcmp_group_entry_ptr->wcmp_group_oid = 1111; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + wcmp_group_entry_ptr->wcmp_group_oid = saved_wcmp_group_oid; + + // Verification should fail if group size mismatches. + wcmp_group_entry_ptr->wcmp_group_members.push_back(std::make_shared()); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + wcmp_group_entry_ptr->wcmp_group_members.pop_back(); + + // Verification should fail if member nexthop ID mismatches. + auto saved_next_hop_id = wcmp_group_entry_ptr->wcmp_group_members[0]->next_hop_id; + wcmp_group_entry_ptr->wcmp_group_members[0]->next_hop_id = kNexthopId3; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + wcmp_group_entry_ptr->wcmp_group_members[0]->next_hop_id = saved_next_hop_id; + + // Verification should fail if member weight mismatches. + auto saved_weight = wcmp_group_entry_ptr->wcmp_group_members[0]->weight; + wcmp_group_entry_ptr->wcmp_group_members[0]->weight = 3; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + wcmp_group_entry_ptr->wcmp_group_members[0]->weight = saved_weight; + + // Verification should fail if member watch port mismatches. + auto saved_watch_port = wcmp_group_entry_ptr->wcmp_group_members[0]->watch_port; + wcmp_group_entry_ptr->wcmp_group_members[0]->watch_port = "invalid"; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + wcmp_group_entry_ptr->wcmp_group_members[0]->watch_port = saved_watch_port; + + // Verification should fail if member WCMP group ID mismatches. + auto saved_member_wcmp_group_id = wcmp_group_entry_ptr->wcmp_group_members[0]->wcmp_group_id; + wcmp_group_entry_ptr->wcmp_group_members[0]->wcmp_group_id = kWcmpGroupId2; + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + wcmp_group_entry_ptr->wcmp_group_members[0]->wcmp_group_id = saved_member_wcmp_group_id; + + // Verification should fail if member OID mapper mismatches. + p4_oid_mapper_->eraseOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, + kWcmpGroupKey1 + kTableKeyDelimiter + sai_serialize_object_id(kWcmpGroupMemberOid1)); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + p4_oid_mapper_->setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, + kWcmpGroupKey1 + kTableKeyDelimiter + sai_serialize_object_id(kWcmpGroupMemberOid1), + kWcmpGroupMemberOid1); } -TEST_F(WcmpManagerTest, VerifyStateAsicDbTest) { - AddWcmpGroupEntryWithWatchport("Ethernet6", true); - nlohmann::json j; - j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; - const std::string db_key = - std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + - APP_P4RT_WCMP_GROUP_TABLE_NAME + kTableKeyDelimiter + j.dump(); - std::vector attributes; - nlohmann::json actions; - nlohmann::json action; - action[p4orch::kAction] = p4orch::kSetNexthopId; - action[p4orch::kWeight] = 2; - action[p4orch::kWatchPort] = "Ethernet6"; - action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; - actions.push_back(action); - attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); - - // Setup ASIC DB. - swss::Table table(nullptr, "ASIC_STATE"); - table.set("SAI_OBJECT_TYPE_NEXT_HOP_GROUP:oid:0xa", - std::vector{swss::FieldValueTuple{ - "SAI_NEXT_HOP_GROUP_ATTR_TYPE", - "SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP"}}); - table.set( - "SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER:oid:0xb", - std::vector{ - swss::FieldValueTuple{ - "SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID", "oid:0xa"}, - swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID", - "oid:0x1"}, - swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT", "2"}}); - - // Verification should succeed with correct ASIC DB values. - EXPECT_EQ(VerifyState(db_key, attributes), ""); - - // Verification should fail if group values mismatch. - table.set("SAI_OBJECT_TYPE_NEXT_HOP_GROUP:oid:0xa", - std::vector{swss::FieldValueTuple{ - "SAI_NEXT_HOP_GROUP_ATTR_TYPE", "invalid"}}); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - - // Verification should fail if group table is missing. - table.del("SAI_OBJECT_TYPE_NEXT_HOP_GROUP:oid:0xa"); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - table.set("SAI_OBJECT_TYPE_NEXT_HOP_GROUP:oid:0xa", - std::vector{swss::FieldValueTuple{ - "SAI_NEXT_HOP_GROUP_ATTR_TYPE", - "SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP"}}); - - // Verification should fail if member values mismatch. - table.set("SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER:oid:0xb", - std::vector{swss::FieldValueTuple{ - "SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT", "1"}}); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - - // Verification should fail if member table is missing. - table.del("SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER:oid:0xb"); - EXPECT_FALSE(VerifyState(db_key, attributes).empty()); - table.set( - "SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER:oid:0xb", - std::vector{ - swss::FieldValueTuple{ - "SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID", "oid:0xa"}, - swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID", - "oid:0x1"}, - swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT", "2"}}); +TEST_F(WcmpManagerTest, VerifyStateAsicDbTest) +{ + AddWcmpGroupEntryWithWatchport("Ethernet6", true); + nlohmann::json j; + j[prependMatchField(p4orch::kWcmpGroupId)] = kWcmpGroupId1; + const std::string db_key = std::string(APP_P4RT_TABLE_NAME) + kTableKeyDelimiter + APP_P4RT_WCMP_GROUP_TABLE_NAME + + kTableKeyDelimiter + j.dump(); + std::vector attributes; + nlohmann::json actions; + nlohmann::json action; + action[p4orch::kAction] = p4orch::kSetNexthopId; + action[p4orch::kWeight] = 2; + action[p4orch::kWatchPort] = "Ethernet6"; + action[prependParamField(p4orch::kNexthopId)] = kNexthopId1; + actions.push_back(action); + attributes.push_back(swss::FieldValueTuple{p4orch::kActions, actions.dump()}); + + // Setup ASIC DB. + swss::Table table(nullptr, "ASIC_STATE"); + table.set("SAI_OBJECT_TYPE_NEXT_HOP_GROUP:oid:0xa", + std::vector{swss::FieldValueTuple{ + "SAI_NEXT_HOP_GROUP_ATTR_TYPE", "SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP"}}); + table.set("SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER:oid:0xb", + std::vector{ + swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID", "oid:0xa"}, + swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID", "oid:0x1"}, + swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT", "2"}}); + + // Verification should succeed with correct ASIC DB values. + EXPECT_EQ(VerifyState(db_key, attributes), ""); + + // Verification should fail if group values mismatch. + table.set("SAI_OBJECT_TYPE_NEXT_HOP_GROUP:oid:0xa", + std::vector{swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_ATTR_TYPE", "invalid"}}); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + + // Verification should fail if group table is missing. + table.del("SAI_OBJECT_TYPE_NEXT_HOP_GROUP:oid:0xa"); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + table.set("SAI_OBJECT_TYPE_NEXT_HOP_GROUP:oid:0xa", + std::vector{swss::FieldValueTuple{ + "SAI_NEXT_HOP_GROUP_ATTR_TYPE", "SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_UNORDERED_ECMP"}}); + + // Verification should fail if member values mismatch. + table.set("SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER:oid:0xb", + std::vector{swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT", "1"}}); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + + // Verification should fail if member table is missing. + table.del("SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER:oid:0xb"); + EXPECT_FALSE(VerifyState(db_key, attributes).empty()); + table.set("SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER:oid:0xb", + std::vector{ + swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID", "oid:0xa"}, + swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID", "oid:0x1"}, + swss::FieldValueTuple{"SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT", "2"}}); } -} // namespace test -} // namespace p4orch +} // namespace test +} // namespace p4orch diff --git a/orchagent/p4orch/wcmp_manager.cpp b/orchagent/p4orch/wcmp_manager.cpp index d50f8d3b036..81c373b16fd 100644 --- a/orchagent/p4orch/wcmp_manager.cpp +++ b/orchagent/p4orch/wcmp_manager.cpp @@ -13,1018 +13,1020 @@ #include "portsorch.h" #include "sai_serialize.h" #include "table.h" -extern "C" { +extern "C" +{ #include "sai.h" } using ::p4orch::kTableKeyDelimiter; extern sai_object_id_t gSwitchId; -extern sai_next_hop_group_api_t* sai_next_hop_group_api; -extern CrmOrch* gCrmOrch; -extern PortsOrch* gPortsOrch; +extern sai_next_hop_group_api_t *sai_next_hop_group_api; +extern CrmOrch *gCrmOrch; +extern PortsOrch *gPortsOrch; extern size_t gMaxBulkSize; -namespace p4orch { +namespace p4orch +{ -namespace { +namespace +{ -std::string getWcmpGroupMemberKey(const std::string& wcmp_group_key, - const sai_object_id_t wcmp_member_oid) { - return wcmp_group_key + kTableKeyDelimiter + - sai_serialize_object_id(wcmp_member_oid); +std::string getWcmpGroupMemberKey(const std::string &wcmp_group_key, const sai_object_id_t wcmp_member_oid) +{ + return wcmp_group_key + kTableKeyDelimiter + sai_serialize_object_id(wcmp_member_oid); } -std::vector getSaiGroupAttrs( - const P4WcmpGroupEntry& wcmp_group_entry) { - std::vector attrs; - sai_attribute_t attr; +std::vector getSaiGroupAttrs(const P4WcmpGroupEntry &wcmp_group_entry) +{ + std::vector attrs; + sai_attribute_t attr; - // TODO: Update type to WCMP when SAI supports it. - attr.id = SAI_NEXT_HOP_GROUP_ATTR_TYPE; - attr.value.s32 = SAI_NEXT_HOP_GROUP_TYPE_ECMP; - attrs.push_back(attr); + // TODO: Update type to WCMP when SAI supports it. + attr.id = SAI_NEXT_HOP_GROUP_ATTR_TYPE; + attr.value.s32 = SAI_NEXT_HOP_GROUP_TYPE_ECMP; + attrs.push_back(attr); - return attrs; + return attrs; } -} // namespace +} // namespace -WcmpManager::WcmpManager(P4OidMapper* p4oidMapper, - ResponsePublisherInterface* publisher) - : gNextHopGroupMemberBulker(sai_next_hop_group_api, gSwitchId, - gMaxBulkSize) { - SWSS_LOG_ENTER(); +WcmpManager::WcmpManager(P4OidMapper *p4oidMapper, ResponsePublisherInterface *publisher) + : gNextHopGroupMemberBulker(sai_next_hop_group_api, gSwitchId, gMaxBulkSize) +{ + SWSS_LOG_ENTER(); - assert(p4oidMapper != nullptr); - m_p4OidMapper = p4oidMapper; - assert(publisher != nullptr); - m_publisher = publisher; + assert(p4oidMapper != nullptr); + m_p4OidMapper = p4oidMapper; + assert(publisher != nullptr); + m_publisher = publisher; } -std::vector WcmpManager::getSaiMemberAttrs( - const P4WcmpGroupMemberEntry& wcmp_member_entry, - const sai_object_id_t group_oid) { - std::vector attrs; - sai_attribute_t attr; - sai_object_id_t next_hop_oid = SAI_NULL_OBJECT_ID; - m_p4OidMapper->getOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(wcmp_member_entry.next_hop_id), - &next_hop_oid); - - attr.id = SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID; - attr.value.oid = group_oid; - attrs.push_back(attr); - - attr.id = SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID; - attr.value.oid = next_hop_oid; - attrs.push_back(attr); - - attr.id = SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT; - attr.value.u32 = (uint32_t)wcmp_member_entry.weight; - attrs.push_back(attr); - - return attrs; +std::vector WcmpManager::getSaiMemberAttrs(const P4WcmpGroupMemberEntry &wcmp_member_entry, + const sai_object_id_t group_oid) +{ + std::vector attrs; + sai_attribute_t attr; + sai_object_id_t next_hop_oid = SAI_NULL_OBJECT_ID; + m_p4OidMapper->getOID(SAI_OBJECT_TYPE_NEXT_HOP, KeyGenerator::generateNextHopKey(wcmp_member_entry.next_hop_id), + &next_hop_oid); + + attr.id = SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID; + attr.value.oid = group_oid; + attrs.push_back(attr); + + attr.id = SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID; + attr.value.oid = next_hop_oid; + attrs.push_back(attr); + + attr.id = SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT; + attr.value.u32 = (uint32_t)wcmp_member_entry.weight; + attrs.push_back(attr); + + return attrs; } -ReturnCode WcmpManager::validateWcmpGroupEntry( - const P4WcmpGroupEntry& app_db_entry) { - for (auto& wcmp_group_member : app_db_entry.wcmp_group_members) { - if (wcmp_group_member->weight <= 0) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid WCMP group member weight " << wcmp_group_member->weight - << ": should be greater than 0."; - } - sai_object_id_t nexthop_oid = SAI_NULL_OBJECT_ID; - if (!m_p4OidMapper->getOID( - SAI_OBJECT_TYPE_NEXT_HOP, - KeyGenerator::generateNextHopKey(wcmp_group_member->next_hop_id), - &nexthop_oid)) { - return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "Nexthop id " << QuotedVar(wcmp_group_member->next_hop_id) - << " does not exist for WCMP group " - << QuotedVar(app_db_entry.wcmp_group_id); - } - if (!wcmp_group_member->watch_port.empty()) { - Port port; - if (!gPortsOrch->getPort(wcmp_group_member->watch_port, port)) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid watch_port field " << wcmp_group_member->watch_port - << ": should be a valid port name."; - } +ReturnCode WcmpManager::validateWcmpGroupEntry(const P4WcmpGroupEntry &app_db_entry) +{ + for (auto &wcmp_group_member : app_db_entry.wcmp_group_members) + { + if (wcmp_group_member->weight <= 0) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid WCMP group member weight " << wcmp_group_member->weight << ": should be greater than 0."; + } + sai_object_id_t nexthop_oid = SAI_NULL_OBJECT_ID; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_NEXT_HOP, + KeyGenerator::generateNextHopKey(wcmp_group_member->next_hop_id), &nexthop_oid)) + { + return ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "Nexthop id " << QuotedVar(wcmp_group_member->next_hop_id) << " does not exist for WCMP group " + << QuotedVar(app_db_entry.wcmp_group_id); + } + if (!wcmp_group_member->watch_port.empty()) + { + Port port; + if (!gPortsOrch->getPort(wcmp_group_member->watch_port, port)) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid watch_port field " << wcmp_group_member->watch_port + << ": should be a valid port name."; + } + } } - } - return ReturnCode(); + return ReturnCode(); } ReturnCodeOr WcmpManager::deserializeP4WcmpGroupAppDbEntry( - const std::string& key, - const std::vector& attributes) { - P4WcmpGroupEntry app_db_entry = {}; - try { - nlohmann::json j = nlohmann::json::parse(key); - if (!j.is_object()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid WCMP group key: should be a JSON object."; + const std::string &key, const std::vector &attributes) +{ + P4WcmpGroupEntry app_db_entry = {}; + try + { + nlohmann::json j = nlohmann::json::parse(key); + if (!j.is_object()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Invalid WCMP group key: should be a JSON object."; + } + app_db_entry.wcmp_group_id = j[prependMatchField(kWcmpGroupId)]; + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) << "Failed to deserialize WCMP group key"; } - app_db_entry.wcmp_group_id = j[prependMatchField(kWcmpGroupId)]; - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to deserialize WCMP group key"; - } - - for (const auto& it : attributes) { - const auto& field = fvField(it); - const auto& value = fvValue(it); - if (field == kActions) { - try { - nlohmann::json j = nlohmann::json::parse(value); - if (!j.is_array()) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Invalid WCMP group actions " << QuotedVar(value) - << ", expecting an array."; + + for (const auto &it : attributes) + { + const auto &field = fvField(it); + const auto &value = fvValue(it); + if (field == kActions) + { + try + { + nlohmann::json j = nlohmann::json::parse(value); + if (!j.is_array()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Invalid WCMP group actions " << QuotedVar(value) << ", expecting an array."; + } + for (auto &action_item : j) + { + std::shared_ptr wcmp_group_member = + std::make_shared(); + std::string action = action_item[kAction]; + if (action != kSetNexthopId) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unexpected action " << QuotedVar(action) << " in WCMP group entry"; + } + if (action_item[prependParamField(kNexthopId)].empty()) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Next hop id was not found in entry member for WCMP " + "group " + << QuotedVar(app_db_entry.wcmp_group_id); + } + wcmp_group_member->next_hop_id = action_item[prependParamField(kNexthopId)]; + if (!action_item[kWeight].empty()) + { + wcmp_group_member->weight = action_item[kWeight]; + } + if (!action_item[kWatchPort].empty()) + { + wcmp_group_member->watch_port = action_item[kWatchPort]; + } + wcmp_group_member->wcmp_group_id = app_db_entry.wcmp_group_id; + wcmp_group_member->pruned = false; + app_db_entry.wcmp_group_members.push_back(wcmp_group_member); + } + } + catch (std::exception &ex) + { + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Failed to deserialize WCMP group actions fields: " << QuotedVar(value); + } } - for (auto& action_item : j) { - std::shared_ptr wcmp_group_member = - std::make_shared(); - std::string action = action_item[kAction]; - if (action != kSetNexthopId) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unexpected action " << QuotedVar(action) - << " in WCMP group entry"; - } - if (action_item[prependParamField(kNexthopId)].empty()) { + else if (field != kControllerMetadata) + { return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Next hop id was not found in entry member for WCMP " - "group " - << QuotedVar(app_db_entry.wcmp_group_id); - } - wcmp_group_member->next_hop_id = - action_item[prependParamField(kNexthopId)]; - if (!action_item[kWeight].empty()) { - wcmp_group_member->weight = action_item[kWeight]; - } - if (!action_item[kWatchPort].empty()) { - wcmp_group_member->watch_port = action_item[kWatchPort]; - } - wcmp_group_member->wcmp_group_id = app_db_entry.wcmp_group_id; - wcmp_group_member->pruned = false; - app_db_entry.wcmp_group_members.push_back(wcmp_group_member); + << "Unexpected field " << QuotedVar(field) << " in table entry"; } - } catch (std::exception& ex) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Failed to deserialize WCMP group actions fields: " - << QuotedVar(value); - } - } else if (field != kControllerMetadata) { - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unexpected field " << QuotedVar(field) << " in table entry"; } - } - return app_db_entry; + return app_db_entry; } -P4WcmpGroupEntry* WcmpManager::getWcmpGroupEntry( - const std::string& wcmp_group_id) { - SWSS_LOG_ENTER(); - const auto& wcmp_group_it = m_wcmpGroupTable.find(wcmp_group_id); - if (wcmp_group_it == m_wcmpGroupTable.end()) return nullptr; - return &wcmp_group_it->second; +P4WcmpGroupEntry *WcmpManager::getWcmpGroupEntry(const std::string &wcmp_group_id) +{ + SWSS_LOG_ENTER(); + const auto &wcmp_group_it = m_wcmpGroupTable.find(wcmp_group_id); + if (wcmp_group_it == m_wcmpGroupTable.end()) + return nullptr; + return &wcmp_group_it->second; } -ReturnCode WcmpManager::processAddRequest(P4WcmpGroupEntry* app_db_entry) { - SWSS_LOG_ENTER(); - auto status = createWcmpGroup(app_db_entry); - if (!status.ok()) { - SWSS_LOG_ERROR("Failed to create WCMP group with id %s: %s", - QuotedVar(app_db_entry->wcmp_group_id).c_str(), - status.message().c_str()); - } - return status; +ReturnCode WcmpManager::processAddRequest(P4WcmpGroupEntry *app_db_entry) +{ + SWSS_LOG_ENTER(); + auto status = createWcmpGroup(app_db_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Failed to create WCMP group with id %s: %s", QuotedVar(app_db_entry->wcmp_group_id).c_str(), + status.message().c_str()); + } + return status; } -ReturnCode WcmpManager::createWcmpGroupMember( - std::shared_ptr wcmp_group_member, - const sai_object_id_t group_oid, const std::string& wcmp_group_key) { - auto attrs = getSaiMemberAttrs(*wcmp_group_member, group_oid); - - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_next_hop_group_api->create_next_hop_group_member( - &wcmp_group_member->member_oid, gSwitchId, (uint32_t)attrs.size(), - attrs.data()), - "Failed to create next hop group member " - << QuotedVar(wcmp_group_member->next_hop_id)); - - // Update reference count - m_p4OidMapper->setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, - getWcmpGroupMemberKey(wcmp_group_key, wcmp_group_member->member_oid), - wcmp_group_member->member_oid); - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - wcmp_group_key); - return ReturnCode(); +ReturnCode WcmpManager::createWcmpGroupMember(std::shared_ptr wcmp_group_member, + const sai_object_id_t group_oid, const std::string &wcmp_group_key) +{ + auto attrs = getSaiMemberAttrs(*wcmp_group_member, group_oid); + + CHECK_ERROR_AND_LOG_AND_RETURN( + sai_next_hop_group_api->create_next_hop_group_member(&wcmp_group_member->member_oid, gSwitchId, + (uint32_t)attrs.size(), attrs.data()), + "Failed to create next hop group member " << QuotedVar(wcmp_group_member->next_hop_id)); + + // Update reference count + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, + getWcmpGroupMemberKey(wcmp_group_key, wcmp_group_member->member_oid), + wcmp_group_member->member_oid); + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key); + return ReturnCode(); } -void WcmpManager::insertMemberInPortNameToWcmpGroupMemberMap( - std::shared_ptr member) { - port_name_to_wcmp_group_member_map[member->watch_port].insert(member); +void WcmpManager::insertMemberInPortNameToWcmpGroupMemberMap(std::shared_ptr member) +{ + port_name_to_wcmp_group_member_map[member->watch_port].insert(member); } -void WcmpManager::removeMemberFromPortNameToWcmpGroupMemberMap( - std::shared_ptr member) { - if (port_name_to_wcmp_group_member_map.find(member->watch_port) != - port_name_to_wcmp_group_member_map.end()) { - auto& s = port_name_to_wcmp_group_member_map[member->watch_port]; - auto it = s.find(member); - if (it != s.end()) { - s.erase(it); +void WcmpManager::removeMemberFromPortNameToWcmpGroupMemberMap(std::shared_ptr member) +{ + if (port_name_to_wcmp_group_member_map.find(member->watch_port) != port_name_to_wcmp_group_member_map.end()) + { + auto &s = port_name_to_wcmp_group_member_map[member->watch_port]; + auto it = s.find(member); + if (it != s.end()) + { + s.erase(it); + } } - } } -ReturnCode WcmpManager::fetchPortOperStatus( - const std::string& port_name, sai_port_oper_status_t* oper_status) { - if (!getPortOperStatusFromMap(port_name, oper_status)) { - // Get port object for associated watch port - Port port; - if (!gPortsOrch->getPort(port_name, port)) { - SWSS_LOG_ERROR("Failed to get port object for port %s", - port_name.c_str()); - return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM); - } - // Get the oper-status of the port from hardware. In case of warm reboot, - // this ensures that actual state of the port oper-status is used to - // determine whether member associated with watch_port is to be created in - // SAI. - if (!gPortsOrch->getPortOperStatus(port, *oper_status)) { - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL( - "Failed to get port oper-status for port " << port.m_alias); +ReturnCode WcmpManager::fetchPortOperStatus(const std::string &port_name, sai_port_oper_status_t *oper_status) +{ + if (!getPortOperStatusFromMap(port_name, oper_status)) + { + // Get port object for associated watch port + Port port; + if (!gPortsOrch->getPort(port_name, port)) + { + SWSS_LOG_ERROR("Failed to get port object for port %s", port_name.c_str()); + return ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM); + } + // Get the oper-status of the port from hardware. In case of warm reboot, + // this ensures that actual state of the port oper-status is used to + // determine whether member associated with watch_port is to be created in + // SAI. + if (!gPortsOrch->getPortOperStatus(port, *oper_status)) + { + RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL("Failed to get port oper-status for port " << port.m_alias); + } + // Update port oper-status in local map + updatePortOperStatusMap(port.m_alias, *oper_status); } - // Update port oper-status in local map - updatePortOperStatusMap(port.m_alias, *oper_status); - } - return ReturnCode(); + return ReturnCode(); } ReturnCode WcmpManager::processWcmpGroupMembersAddition( - const std::vector>& members, - const std::string& wcmp_group_key, sai_object_id_t wcmp_group_oid, - std::vector>& - created_wcmp_group_members) { - SWSS_LOG_ENTER(); - ReturnCode status; - vector nhgm_ids(members.size(), SAI_NULL_OBJECT_ID); - for (size_t i = 0; i < members.size(); ++i) { - bool insert_member = true; - auto& member = members[i]; - if (!member->watch_port.empty()) { - // Create member in SAI only for operationally up ports - sai_port_oper_status_t oper_status = SAI_PORT_OPER_STATUS_DOWN; - status = fetchPortOperStatus(member->watch_port, &oper_status); - if (!status.ok()) { - break; - } - - if (oper_status != SAI_PORT_OPER_STATUS_UP) { - insert_member = false; - member->pruned = true; - SWSS_LOG_NOTICE( - "Member %s in group %s not created in asic as the associated " - "watchport " - "(%s) is not operationally up", - member->next_hop_id.c_str(), member->wcmp_group_id.c_str(), - member->watch_port.c_str()); - } - } - if (insert_member) { - auto attrs = getSaiMemberAttrs(*(member.get()), wcmp_group_oid); - gNextHopGroupMemberBulker.create_entry( - &nhgm_ids[i], (uint32_t)attrs.size(), attrs.data()); + const std::vector> &members, const std::string &wcmp_group_key, + sai_object_id_t wcmp_group_oid, std::vector> &created_wcmp_group_members) +{ + SWSS_LOG_ENTER(); + ReturnCode status; + vector nhgm_ids(members.size(), SAI_NULL_OBJECT_ID); + for (size_t i = 0; i < members.size(); ++i) + { + bool insert_member = true; + auto &member = members[i]; + if (!member->watch_port.empty()) + { + // Create member in SAI only for operationally up ports + sai_port_oper_status_t oper_status = SAI_PORT_OPER_STATUS_DOWN; + status = fetchPortOperStatus(member->watch_port, &oper_status); + if (!status.ok()) + { + break; + } + + if (oper_status != SAI_PORT_OPER_STATUS_UP) + { + insert_member = false; + member->pruned = true; + SWSS_LOG_NOTICE("Member %s in group %s not created in asic as the associated " + "watchport " + "(%s) is not operationally up", + member->next_hop_id.c_str(), member->wcmp_group_id.c_str(), member->watch_port.c_str()); + } + } + if (insert_member) + { + auto attrs = getSaiMemberAttrs(*(member.get()), wcmp_group_oid); + gNextHopGroupMemberBulker.create_entry(&nhgm_ids[i], (uint32_t)attrs.size(), attrs.data()); + } } - } - if (status.ok()) { - gNextHopGroupMemberBulker.flush(); - for (size_t i = 0; i < members.size(); ++i) { - auto& member = members[i]; - if (!member->pruned) { - if (nhgm_ids[i] == SAI_NULL_OBJECT_ID) { - if (status.ok()) { - status = ReturnCode(StatusCode::SWSS_RC_UNKNOWN) - << "Fail to create wcmp group member: " - << QuotedVar(member->next_hop_id); - } else { - status << "; Fail to create wcmp group member: " - << QuotedVar(member->next_hop_id); - } - continue; + if (status.ok()) + { + gNextHopGroupMemberBulker.flush(); + for (size_t i = 0; i < members.size(); ++i) + { + auto &member = members[i]; + if (!member->pruned) + { + if (nhgm_ids[i] == SAI_NULL_OBJECT_ID) + { + if (status.ok()) + { + status = ReturnCode(StatusCode::SWSS_RC_UNKNOWN) + << "Fail to create wcmp group member: " << QuotedVar(member->next_hop_id); + } + else + { + status << "; Fail to create wcmp group member: " << QuotedVar(member->next_hop_id); + } + continue; + } + member->member_oid = nhgm_ids[i]; + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, + getWcmpGroupMemberKey(wcmp_group_key, member->member_oid), member->member_oid); + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key); + } + if (!member->watch_port.empty()) + { + // Add member to port_name_to_wcmp_group_member_map + insertMemberInPortNameToWcmpGroupMemberMap(member); + } + const std::string &next_hop_key = KeyGenerator::generateNextHopKey(member->next_hop_id); + gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_NEXTHOP_GROUP_MEMBER); + m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key); + created_wcmp_group_members.push_back(member); } - member->member_oid = nhgm_ids[i]; - m_p4OidMapper->setOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, - getWcmpGroupMemberKey(wcmp_group_key, member->member_oid), - member->member_oid); - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - wcmp_group_key); - } - if (!member->watch_port.empty()) { - // Add member to port_name_to_wcmp_group_member_map - insertMemberInPortNameToWcmpGroupMemberMap(member); - } - const std::string& next_hop_key = - KeyGenerator::generateNextHopKey(member->next_hop_id); - gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_NEXTHOP_GROUP_MEMBER); - m_p4OidMapper->increaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key); - created_wcmp_group_members.push_back(member); } - } - return status; + return status; } -ReturnCode WcmpManager::createWcmpGroup(P4WcmpGroupEntry* wcmp_group) { - SWSS_LOG_ENTER(); - - auto attrs = getSaiGroupAttrs(*wcmp_group); - CHECK_ERROR_AND_LOG_AND_RETURN(sai_next_hop_group_api->create_next_hop_group( - &wcmp_group->wcmp_group_oid, gSwitchId, - (uint32_t)attrs.size(), attrs.data()), - "Failed to create next hop group " - << QuotedVar(wcmp_group->wcmp_group_id)); - // Update reference count - const auto& wcmp_group_key = - KeyGenerator::generateWcmpGroupKey(wcmp_group->wcmp_group_id); - gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_NEXTHOP_GROUP); - m_p4OidMapper->setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key, - wcmp_group->wcmp_group_oid); - - // Create next hop group members - std::vector> - created_wcmp_group_members; - ReturnCode status = processWcmpGroupMembersAddition( - wcmp_group->wcmp_group_members, wcmp_group_key, - wcmp_group->wcmp_group_oid, created_wcmp_group_members); - if (!status.ok()) { - // Clean up created group members and the group - recoverGroupMembers(wcmp_group, wcmp_group_key, created_wcmp_group_members, - {}); - auto sai_status = sai_next_hop_group_api->remove_next_hop_group( - wcmp_group->wcmp_group_oid); - if (sai_status != SAI_STATUS_SUCCESS) { - std::stringstream ss; - ss << "Failed to delete WCMP group with id " - << QuotedVar(wcmp_group->wcmp_group_id); - SWSS_LOG_ERROR("%s SAI_STATUS: %s", ss.str().c_str(), - sai_serialize_status(sai_status).c_str()); - SWSS_RAISE_CRITICAL_STATE(ss.str()); +ReturnCode WcmpManager::createWcmpGroup(P4WcmpGroupEntry *wcmp_group) +{ + SWSS_LOG_ENTER(); + + auto attrs = getSaiGroupAttrs(*wcmp_group); + CHECK_ERROR_AND_LOG_AND_RETURN(sai_next_hop_group_api->create_next_hop_group(&wcmp_group->wcmp_group_oid, gSwitchId, + (uint32_t)attrs.size(), attrs.data()), + "Failed to create next hop group " << QuotedVar(wcmp_group->wcmp_group_id)); + // Update reference count + const auto &wcmp_group_key = KeyGenerator::generateWcmpGroupKey(wcmp_group->wcmp_group_id); + gCrmOrch->incCrmResUsedCounter(CrmResourceType::CRM_NEXTHOP_GROUP); + m_p4OidMapper->setOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key, wcmp_group->wcmp_group_oid); + + // Create next hop group members + std::vector> created_wcmp_group_members; + ReturnCode status = processWcmpGroupMembersAddition(wcmp_group->wcmp_group_members, wcmp_group_key, + wcmp_group->wcmp_group_oid, created_wcmp_group_members); + if (!status.ok()) + { + // Clean up created group members and the group + recoverGroupMembers(wcmp_group, wcmp_group_key, created_wcmp_group_members, {}); + auto sai_status = sai_next_hop_group_api->remove_next_hop_group(wcmp_group->wcmp_group_oid); + if (sai_status != SAI_STATUS_SUCCESS) + { + std::stringstream ss; + ss << "Failed to delete WCMP group with id " << QuotedVar(wcmp_group->wcmp_group_id); + SWSS_LOG_ERROR("%s SAI_STATUS: %s", ss.str().c_str(), sai_serialize_status(sai_status).c_str()); + SWSS_RAISE_CRITICAL_STATE(ss.str()); + } + gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_NEXTHOP_GROUP); + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key); + return status; } - gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_NEXTHOP_GROUP); - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key); - return status; - } - m_wcmpGroupTable[wcmp_group->wcmp_group_id] = *wcmp_group; - return ReturnCode(); + m_wcmpGroupTable[wcmp_group->wcmp_group_id] = *wcmp_group; + return ReturnCode(); } void WcmpManager::recoverGroupMembers( - p4orch::P4WcmpGroupEntry* wcmp_group_entry, - const std::string& wcmp_group_key, - const std::vector>& - created_wcmp_group_members, - const std::vector>& - removed_wcmp_group_members) { - SWSS_LOG_ENTER(); - std::vector> members; - ReturnCode recovery_status; - // Clean up created group members - remove created new members - if (created_wcmp_group_members.size() != 0) { - recovery_status = processWcmpGroupMembersRemoval(created_wcmp_group_members, - wcmp_group_key, members) - .prepend("Error during recovery: "); - } - - // Clean up removed group members - create removed old members - if (recovery_status.ok() && removed_wcmp_group_members.size() != 0) { - recovery_status = processWcmpGroupMembersAddition( - removed_wcmp_group_members, wcmp_group_key, - wcmp_group_entry->wcmp_group_oid, members) - .prepend("Error during recovery: "); - } - - if (!recovery_status.ok()) { - SWSS_RAISE_CRITICAL_STATE(recovery_status.message()); - } -} + p4orch::P4WcmpGroupEntry *wcmp_group_entry, const std::string &wcmp_group_key, + const std::vector> &created_wcmp_group_members, + const std::vector> &removed_wcmp_group_members) +{ + SWSS_LOG_ENTER(); + std::vector> members; + ReturnCode recovery_status; + // Clean up created group members - remove created new members + if (created_wcmp_group_members.size() != 0) + { + recovery_status = processWcmpGroupMembersRemoval(created_wcmp_group_members, wcmp_group_key, members) + .prepend("Error during recovery: "); + } -ReturnCode WcmpManager::processUpdateRequest( - P4WcmpGroupEntry* wcmp_group_entry) { - SWSS_LOG_ENTER(); - auto* old_wcmp = getWcmpGroupEntry(wcmp_group_entry->wcmp_group_id); - wcmp_group_entry->wcmp_group_oid = old_wcmp->wcmp_group_oid; - const auto& wcmp_group_key = - KeyGenerator::generateWcmpGroupKey(wcmp_group_entry->wcmp_group_id); - // Keep record of created next hop group members - std::vector> - created_wcmp_group_members; - // Keep record of removed next hop group members - std::vector> - removed_wcmp_group_members; - - // Update group members steps: - // 1. Find the old member in the list with the smallest weight - // 2. Find the new member in the list with the smallest weight - // 3. Make SAI calls to remove old members except the reserved member with the - // smallest weight - // 4. Make SAI call to create the new member with the smallest weight - // 5. Make SAI call to remove the reserved old member - // 6. Make SAI calls to create remaining new members - ReturnCode update_request_status; - auto find_smallest_index = - [&](p4orch::P4WcmpGroupEntry* wcmp, - std::vector>& other_members) - -> int { - other_members.clear(); - if (wcmp->wcmp_group_members.empty()) { - return -1; + // Clean up removed group members - create removed old members + if (recovery_status.ok() && removed_wcmp_group_members.size() != 0) + { + recovery_status = processWcmpGroupMembersAddition(removed_wcmp_group_members, wcmp_group_key, + wcmp_group_entry->wcmp_group_oid, members) + .prepend("Error during recovery: "); } - int reserved_idx = 0; - for (int i = 1; i < (int)wcmp->wcmp_group_members.size(); i++) { - if (wcmp->wcmp_group_members[i]->weight < - wcmp->wcmp_group_members[reserved_idx]->weight) { - other_members.push_back(wcmp->wcmp_group_members[reserved_idx]); - reserved_idx = i; - } else { - other_members.push_back(wcmp->wcmp_group_members[i]); - } + + if (!recovery_status.ok()) + { + SWSS_RAISE_CRITICAL_STATE(recovery_status.message()); } - return reserved_idx; - }; - // Find the old member who has the smallest weight, -1 if the member list is - // empty - std::vector> other_old_members; - int reserved_old_member_index = - find_smallest_index(old_wcmp, other_old_members); - // Find the new member who has the smallest weight, -1 if the member list is - // empty - std::vector> other_new_members; - int reserved_new_member_index = - find_smallest_index(wcmp_group_entry, other_new_members); - - // Remove stale group members except the member with the smallest weight - if (other_old_members.size() != 0) { - update_request_status = processWcmpGroupMembersRemoval( - other_old_members, wcmp_group_key, removed_wcmp_group_members); - if (!update_request_status.ok()) { - recoverGroupMembers(wcmp_group_entry, wcmp_group_key, - created_wcmp_group_members, - removed_wcmp_group_members); - return update_request_status; +} + +ReturnCode WcmpManager::processUpdateRequest(P4WcmpGroupEntry *wcmp_group_entry) +{ + SWSS_LOG_ENTER(); + auto *old_wcmp = getWcmpGroupEntry(wcmp_group_entry->wcmp_group_id); + wcmp_group_entry->wcmp_group_oid = old_wcmp->wcmp_group_oid; + const auto &wcmp_group_key = KeyGenerator::generateWcmpGroupKey(wcmp_group_entry->wcmp_group_id); + // Keep record of created next hop group members + std::vector> created_wcmp_group_members; + // Keep record of removed next hop group members + std::vector> removed_wcmp_group_members; + + // Update group members steps: + // 1. Find the old member in the list with the smallest weight + // 2. Find the new member in the list with the smallest weight + // 3. Make SAI calls to remove old members except the reserved member with the + // smallest weight + // 4. Make SAI call to create the new member with the smallest weight + // 5. Make SAI call to remove the reserved old member + // 6. Make SAI calls to create remaining new members + ReturnCode update_request_status; + auto find_smallest_index = [&](p4orch::P4WcmpGroupEntry *wcmp, + std::vector> &other_members) -> int { + other_members.clear(); + if (wcmp->wcmp_group_members.empty()) + { + return -1; + } + int reserved_idx = 0; + for (int i = 1; i < (int)wcmp->wcmp_group_members.size(); i++) + { + if (wcmp->wcmp_group_members[i]->weight < wcmp->wcmp_group_members[reserved_idx]->weight) + { + other_members.push_back(wcmp->wcmp_group_members[reserved_idx]); + reserved_idx = i; + } + else + { + other_members.push_back(wcmp->wcmp_group_members[i]); + } + } + return reserved_idx; + }; + // Find the old member who has the smallest weight, -1 if the member list is + // empty + std::vector> other_old_members; + int reserved_old_member_index = find_smallest_index(old_wcmp, other_old_members); + // Find the new member who has the smallest weight, -1 if the member list is + // empty + std::vector> other_new_members; + int reserved_new_member_index = find_smallest_index(wcmp_group_entry, other_new_members); + + // Remove stale group members except the member with the smallest weight + if (other_old_members.size() != 0) + { + update_request_status = + processWcmpGroupMembersRemoval(other_old_members, wcmp_group_key, removed_wcmp_group_members); + if (!update_request_status.ok()) + { + recoverGroupMembers(wcmp_group_entry, wcmp_group_key, created_wcmp_group_members, + removed_wcmp_group_members); + return update_request_status; + } } - } - - // Create the new member with the smallest weight if member list is nonempty - if (reserved_new_member_index != -1) { - update_request_status = processWcmpGroupMembersAddition( - {wcmp_group_entry->wcmp_group_members[reserved_new_member_index]}, - wcmp_group_key, wcmp_group_entry->wcmp_group_oid, - created_wcmp_group_members); - if (!update_request_status.ok()) { - recoverGroupMembers(wcmp_group_entry, wcmp_group_key, - created_wcmp_group_members, - removed_wcmp_group_members); - return update_request_status; + + // Create the new member with the smallest weight if member list is nonempty + if (reserved_new_member_index != -1) + { + update_request_status = processWcmpGroupMembersAddition( + {wcmp_group_entry->wcmp_group_members[reserved_new_member_index]}, wcmp_group_key, + wcmp_group_entry->wcmp_group_oid, created_wcmp_group_members); + if (!update_request_status.ok()) + { + recoverGroupMembers(wcmp_group_entry, wcmp_group_key, created_wcmp_group_members, + removed_wcmp_group_members); + return update_request_status; + } } - } - - // Remove the old member with the smallest weight if member list is nonempty - if (reserved_old_member_index != -1) { - update_request_status = processWcmpGroupMembersRemoval( - {old_wcmp->wcmp_group_members[reserved_old_member_index]}, - wcmp_group_key, removed_wcmp_group_members); - if (!update_request_status.ok()) { - recoverGroupMembers(wcmp_group_entry, wcmp_group_key, - created_wcmp_group_members, - removed_wcmp_group_members); - return update_request_status; + + // Remove the old member with the smallest weight if member list is nonempty + if (reserved_old_member_index != -1) + { + update_request_status = processWcmpGroupMembersRemoval( + {old_wcmp->wcmp_group_members[reserved_old_member_index]}, wcmp_group_key, removed_wcmp_group_members); + if (!update_request_status.ok()) + { + recoverGroupMembers(wcmp_group_entry, wcmp_group_key, created_wcmp_group_members, + removed_wcmp_group_members); + return update_request_status; + } } - } - - // Create new group members - if (other_new_members.size() != 0) { - update_request_status = processWcmpGroupMembersAddition( - other_new_members, wcmp_group_key, wcmp_group_entry->wcmp_group_oid, - created_wcmp_group_members); - if (!update_request_status.ok()) { - recoverGroupMembers(wcmp_group_entry, wcmp_group_key, - created_wcmp_group_members, - removed_wcmp_group_members); - return update_request_status; + + // Create new group members + if (other_new_members.size() != 0) + { + update_request_status = processWcmpGroupMembersAddition( + other_new_members, wcmp_group_key, wcmp_group_entry->wcmp_group_oid, created_wcmp_group_members); + if (!update_request_status.ok()) + { + recoverGroupMembers(wcmp_group_entry, wcmp_group_key, created_wcmp_group_members, + removed_wcmp_group_members); + return update_request_status; + } } - } - m_wcmpGroupTable[wcmp_group_entry->wcmp_group_id] = *wcmp_group_entry; - return update_request_status; + m_wcmpGroupTable[wcmp_group_entry->wcmp_group_id] = *wcmp_group_entry; + return update_request_status; } -ReturnCode WcmpManager::removeWcmpGroupMember( - const std::shared_ptr wcmp_group_member, - const std::string& wcmp_group_key) { - SWSS_LOG_ENTER(); - - CHECK_ERROR_AND_LOG_AND_RETURN( - sai_next_hop_group_api->remove_next_hop_group_member( - wcmp_group_member->member_oid), - "Failed to remove WCMP group member with nexthop id " - << QuotedVar(wcmp_group_member->next_hop_id)); - m_p4OidMapper->eraseOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, - getWcmpGroupMemberKey(wcmp_group_key, wcmp_group_member->member_oid)); - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - wcmp_group_key); - return ReturnCode(); +ReturnCode WcmpManager::removeWcmpGroupMember(const std::shared_ptr wcmp_group_member, + const std::string &wcmp_group_key) +{ + SWSS_LOG_ENTER(); + + CHECK_ERROR_AND_LOG_AND_RETURN(sai_next_hop_group_api->remove_next_hop_group_member(wcmp_group_member->member_oid), + "Failed to remove WCMP group member with nexthop id " + << QuotedVar(wcmp_group_member->next_hop_id)); + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, + getWcmpGroupMemberKey(wcmp_group_key, wcmp_group_member->member_oid)); + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key); + return ReturnCode(); } ReturnCode WcmpManager::processWcmpGroupMembersRemoval( - const std::vector>& members, - const std::string& wcmp_group_key, - std::vector>& - removed_wcmp_group_members) { - SWSS_LOG_ENTER(); - ReturnCode status; - std::vector statuses(members.size(), SAI_STATUS_FAILURE); - for (size_t i = 0; i < members.size(); ++i) { - auto& member = members[i]; - if (!member->pruned) { - gNextHopGroupMemberBulker.remove_entry(&statuses[i], member->member_oid); + const std::vector> &members, const std::string &wcmp_group_key, + std::vector> &removed_wcmp_group_members) +{ + SWSS_LOG_ENTER(); + ReturnCode status; + std::vector statuses(members.size(), SAI_STATUS_FAILURE); + for (size_t i = 0; i < members.size(); ++i) + { + auto &member = members[i]; + if (!member->pruned) + { + gNextHopGroupMemberBulker.remove_entry(&statuses[i], member->member_oid); + } } - } - gNextHopGroupMemberBulker.flush(); - for (size_t i = 0; i < members.size(); ++i) { - auto& member = members[i]; - if (member->pruned) { - SWSS_LOG_NOTICE("Removed pruned member %s from group %s", - member->next_hop_id.c_str(), - member->wcmp_group_id.c_str()); - member->pruned = false; - } else { - if (statuses[i] != SAI_STATUS_SUCCESS) { - if (status.ok()) { - status = ReturnCode(statuses[i]) - << "Failed to delete WCMP group member: " - << QuotedVar(member->next_hop_id); - } else { - status << "; Failed to delete WCMP group member: " - << QuotedVar(member->next_hop_id); + gNextHopGroupMemberBulker.flush(); + for (size_t i = 0; i < members.size(); ++i) + { + auto &member = members[i]; + if (member->pruned) + { + SWSS_LOG_NOTICE("Removed pruned member %s from group %s", member->next_hop_id.c_str(), + member->wcmp_group_id.c_str()); + member->pruned = false; } - continue; - } else { - m_p4OidMapper->eraseOID( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, - getWcmpGroupMemberKey(wcmp_group_key, member->member_oid)); - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - wcmp_group_key); - } + else + { + if (statuses[i] != SAI_STATUS_SUCCESS) + { + if (status.ok()) + { + status = ReturnCode(statuses[i]) + << "Failed to delete WCMP group member: " << QuotedVar(member->next_hop_id); + } + else + { + status << "; Failed to delete WCMP group member: " << QuotedVar(member->next_hop_id); + } + continue; + } + else + { + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, + getWcmpGroupMemberKey(wcmp_group_key, member->member_oid)); + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key); + } + } + const std::string &next_hop_key = KeyGenerator::generateNextHopKey(member->next_hop_id); + gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_NEXTHOP_GROUP_MEMBER); + m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key); + removeMemberFromPortNameToWcmpGroupMemberMap(member); + removed_wcmp_group_members.push_back(member); } - const std::string& next_hop_key = - KeyGenerator::generateNextHopKey(member->next_hop_id); - gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_NEXTHOP_GROUP_MEMBER); - m_p4OidMapper->decreaseRefCount(SAI_OBJECT_TYPE_NEXT_HOP, next_hop_key); - removeMemberFromPortNameToWcmpGroupMemberMap(member); - removed_wcmp_group_members.push_back(member); - } - return status; + return status; } -ReturnCode WcmpManager::removeWcmpGroup(const std::string& wcmp_group_id) { - SWSS_LOG_ENTER(); - auto* wcmp_group = getWcmpGroupEntry(wcmp_group_id); - if (wcmp_group == nullptr) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) - << "WCMP group with id " << QuotedVar(wcmp_group_id) - << " was not found."); - } - // Check refcount before deleting group members - uint32_t expected_refcount = (uint32_t)wcmp_group->wcmp_group_members.size(); - uint32_t wcmp_group_refcount = 0; - const auto& wcmp_group_key = - KeyGenerator::generateWcmpGroupKey(wcmp_group_id); - m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key, - &wcmp_group_refcount); - if (wcmp_group_refcount > expected_refcount) { - LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_IN_USE) - << "Failed to remove WCMP group with id " - << QuotedVar(wcmp_group_id) << ", as it has " - << wcmp_group_refcount - expected_refcount - << " more objects than its group members (size=" - << expected_refcount << ") referencing it."); - } - - // Delete group members - std::vector> - removed_wcmp_group_members; - ReturnCode status = processWcmpGroupMembersRemoval( - wcmp_group->wcmp_group_members, wcmp_group_key, - removed_wcmp_group_members); - - // Delete group - if (status.ok()) { - auto sai_status = sai_next_hop_group_api->remove_next_hop_group( - wcmp_group->wcmp_group_oid); - if (sai_status == SAI_STATUS_SUCCESS) { - m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key); - gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_NEXTHOP_GROUP); - m_wcmpGroupTable.erase(wcmp_group->wcmp_group_id); - return ReturnCode(); +ReturnCode WcmpManager::removeWcmpGroup(const std::string &wcmp_group_id) +{ + SWSS_LOG_ENTER(); + auto *wcmp_group = getWcmpGroupEntry(wcmp_group_id); + if (wcmp_group == nullptr) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_NOT_FOUND) + << "WCMP group with id " << QuotedVar(wcmp_group_id) << " was not found."); + } + // Check refcount before deleting group members + uint32_t expected_refcount = (uint32_t)wcmp_group->wcmp_group_members.size(); + uint32_t wcmp_group_refcount = 0; + const auto &wcmp_group_key = KeyGenerator::generateWcmpGroupKey(wcmp_group_id); + m_p4OidMapper->getRefCount(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key, &wcmp_group_refcount); + if (wcmp_group_refcount > expected_refcount) + { + LOG_ERROR_AND_RETURN(ReturnCode(StatusCode::SWSS_RC_IN_USE) + << "Failed to remove WCMP group with id " << QuotedVar(wcmp_group_id) << ", as it has " + << wcmp_group_refcount - expected_refcount << " more objects than its group members (size=" + << expected_refcount << ") referencing it."); } - status = ReturnCode(sai_status) << "Failed to delete WCMP group with id " - << QuotedVar(wcmp_group->wcmp_group_id); - SWSS_LOG_ERROR("%s SAI_STATUS: %s", status.message().c_str(), - sai_serialize_status(sai_status).c_str()); - } - // Recover group members. - recoverGroupMembers(wcmp_group, wcmp_group_key, {}, - removed_wcmp_group_members); - return status; -} -void WcmpManager::pruneNextHops(const std::string& port) { - SWSS_LOG_ENTER(); - - // Get list of WCMP group members associated with the watch_port - if (port_name_to_wcmp_group_member_map.find(port) != - port_name_to_wcmp_group_member_map.end()) { - for (const auto& member : port_name_to_wcmp_group_member_map[port]) { - // Prune a member if it is not already pruned. - if (!member->pruned) { - const auto& wcmp_group_key = - KeyGenerator::generateWcmpGroupKey(member->wcmp_group_id); - auto status = removeWcmpGroupMember(member, wcmp_group_key); - if (!status.ok()) { - std::stringstream msg; - msg << "Failed to prune member " << member->next_hop_id - << " from group " << member->wcmp_group_id << ": " - << status.message(); - SWSS_RAISE_CRITICAL_STATE(msg.str()); - return; + // Delete group members + std::vector> removed_wcmp_group_members; + ReturnCode status = + processWcmpGroupMembersRemoval(wcmp_group->wcmp_group_members, wcmp_group_key, removed_wcmp_group_members); + + // Delete group + if (status.ok()) + { + auto sai_status = sai_next_hop_group_api->remove_next_hop_group(wcmp_group->wcmp_group_oid); + if (sai_status == SAI_STATUS_SUCCESS) + { + m_p4OidMapper->eraseOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key); + gCrmOrch->decCrmResUsedCounter(CrmResourceType::CRM_NEXTHOP_GROUP); + m_wcmpGroupTable.erase(wcmp_group->wcmp_group_id); + return ReturnCode(); } - member->pruned = true; - SWSS_LOG_NOTICE("Pruned member %s from group %s", - member->next_hop_id.c_str(), - member->wcmp_group_id.c_str()); - } + status = ReturnCode(sai_status) << "Failed to delete WCMP group with id " + << QuotedVar(wcmp_group->wcmp_group_id); + SWSS_LOG_ERROR("%s SAI_STATUS: %s", status.message().c_str(), sai_serialize_status(sai_status).c_str()); } - } + // Recover group members. + recoverGroupMembers(wcmp_group, wcmp_group_key, {}, removed_wcmp_group_members); + return status; } -void WcmpManager::restorePrunedNextHops(const std::string& port) { - SWSS_LOG_ENTER(); - - // Get list of WCMP group members associated with the watch_port that were - // pruned - if (port_name_to_wcmp_group_member_map.find(port) != - port_name_to_wcmp_group_member_map.end()) { - ReturnCode status; - for (auto member : port_name_to_wcmp_group_member_map[port]) { - if (member->pruned) { - const auto& wcmp_group_key = - KeyGenerator::generateWcmpGroupKey(member->wcmp_group_id); - sai_object_id_t wcmp_group_oid = SAI_NULL_OBJECT_ID; - if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, - wcmp_group_key, &wcmp_group_oid)) { - status = ReturnCode(StatusCode::SWSS_RC_INTERNAL) - << "Error during restoring pruned next hop: Failed to get " - "WCMP group OID for group " - << member->wcmp_group_id; - SWSS_LOG_ERROR("%s", status.message().c_str()); - SWSS_RAISE_CRITICAL_STATE(status.message()); - return; +void WcmpManager::pruneNextHops(const std::string &port) +{ + SWSS_LOG_ENTER(); + + // Get list of WCMP group members associated with the watch_port + if (port_name_to_wcmp_group_member_map.find(port) != port_name_to_wcmp_group_member_map.end()) + { + for (const auto &member : port_name_to_wcmp_group_member_map[port]) + { + // Prune a member if it is not already pruned. + if (!member->pruned) + { + const auto &wcmp_group_key = KeyGenerator::generateWcmpGroupKey(member->wcmp_group_id); + auto status = removeWcmpGroupMember(member, wcmp_group_key); + if (!status.ok()) + { + std::stringstream msg; + msg << "Failed to prune member " << member->next_hop_id << " from group " << member->wcmp_group_id + << ": " << status.message(); + SWSS_RAISE_CRITICAL_STATE(msg.str()); + return; + } + member->pruned = true; + SWSS_LOG_NOTICE("Pruned member %s from group %s", member->next_hop_id.c_str(), + member->wcmp_group_id.c_str()); + } } - status = createWcmpGroupMember(member, wcmp_group_oid, wcmp_group_key); - if (!status.ok()) { - status.prepend("Error during restoring pruned next hop: "); - SWSS_LOG_ERROR("%s", status.message().c_str()); - SWSS_RAISE_CRITICAL_STATE(status.message()); - return; + } +} + +void WcmpManager::restorePrunedNextHops(const std::string &port) +{ + SWSS_LOG_ENTER(); + + // Get list of WCMP group members associated with the watch_port that were + // pruned + if (port_name_to_wcmp_group_member_map.find(port) != port_name_to_wcmp_group_member_map.end()) + { + ReturnCode status; + for (auto member : port_name_to_wcmp_group_member_map[port]) + { + if (member->pruned) + { + const auto &wcmp_group_key = KeyGenerator::generateWcmpGroupKey(member->wcmp_group_id); + sai_object_id_t wcmp_group_oid = SAI_NULL_OBJECT_ID; + if (!m_p4OidMapper->getOID(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key, &wcmp_group_oid)) + { + status = ReturnCode(StatusCode::SWSS_RC_INTERNAL) + << "Error during restoring pruned next hop: Failed to get " + "WCMP group OID for group " + << member->wcmp_group_id; + SWSS_LOG_ERROR("%s", status.message().c_str()); + SWSS_RAISE_CRITICAL_STATE(status.message()); + return; + } + status = createWcmpGroupMember(member, wcmp_group_oid, wcmp_group_key); + if (!status.ok()) + { + status.prepend("Error during restoring pruned next hop: "); + SWSS_LOG_ERROR("%s", status.message().c_str()); + SWSS_RAISE_CRITICAL_STATE(status.message()); + return; + } + member->pruned = false; + SWSS_LOG_NOTICE("Restored pruned member %s in group %s", member->next_hop_id.c_str(), + member->wcmp_group_id.c_str()); + } } - member->pruned = false; - SWSS_LOG_NOTICE("Restored pruned member %s in group %s", - member->next_hop_id.c_str(), - member->wcmp_group_id.c_str()); - } } - } } -bool WcmpManager::getPortOperStatusFromMap( - const std::string& port, sai_port_oper_status_t* oper_status) { - if (port_oper_status_map.find(port) != port_oper_status_map.end()) { - *oper_status = port_oper_status_map[port]; - return true; - } - return false; +bool WcmpManager::getPortOperStatusFromMap(const std::string &port, sai_port_oper_status_t *oper_status) +{ + if (port_oper_status_map.find(port) != port_oper_status_map.end()) + { + *oper_status = port_oper_status_map[port]; + return true; + } + return false; } -void WcmpManager::updatePortOperStatusMap( - const std::string& port, const sai_port_oper_status_t& status) { - port_oper_status_map[port] = status; +void WcmpManager::updatePortOperStatusMap(const std::string &port, const sai_port_oper_status_t &status) +{ + port_oper_status_map[port] = status; } -ReturnCode WcmpManager::getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) { - std::string value; - - try { - nlohmann::json j = nlohmann::json::parse(json_key); - if (j.find(prependMatchField(p4orch::kWcmpGroupId)) != j.end()) { - value = j.at(prependMatchField(p4orch::kWcmpGroupId)).get(); - object_key = KeyGenerator::generateWcmpGroupKey(value); - object_type = SAI_OBJECT_TYPE_NEXT_HOP_GROUP; - return ReturnCode(); - } else { - SWSS_LOG_ERROR( - "%s match parameter absent: required for dependent object query", - p4orch::kWcmpGroupId); +ReturnCode WcmpManager::getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) +{ + std::string value; + + try + { + nlohmann::json j = nlohmann::json::parse(json_key); + if (j.find(prependMatchField(p4orch::kWcmpGroupId)) != j.end()) + { + value = j.at(prependMatchField(p4orch::kWcmpGroupId)).get(); + object_key = KeyGenerator::generateWcmpGroupKey(value); + object_type = SAI_OBJECT_TYPE_NEXT_HOP_GROUP; + return ReturnCode(); + } + else + { + SWSS_LOG_ERROR("%s match parameter absent: required for dependent object query", p4orch::kWcmpGroupId); + } + } + catch (std::exception &ex) + { + SWSS_LOG_ERROR("json_key parse error"); } - } catch (std::exception& ex) { - SWSS_LOG_ERROR("json_key parse error"); - } - return StatusCode::SWSS_RC_INVALID_PARAM; + return StatusCode::SWSS_RC_INVALID_PARAM; } -void WcmpManager::enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) { - m_entries.push_back(entry); +void WcmpManager::enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) +{ + m_entries.push_back(entry); } -void WcmpManager::drain() { - SWSS_LOG_ENTER(); +void WcmpManager::drain() +{ + SWSS_LOG_ENTER(); + + for (const auto &key_op_fvs_tuple : m_entries) + { + std::string table_name; + std::string db_key; + parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &db_key); + const std::vector &attributes = kfvFieldsValues(key_op_fvs_tuple); + + ReturnCode status; + auto app_db_entry_or = deserializeP4WcmpGroupAppDbEntry(db_key, attributes); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + SWSS_LOG_ERROR("Unable to deserialize APP DB WCMP group entry with key %s: %s", + QuotedVar(table_name + ":" + db_key).c_str(), status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + auto &app_db_entry = *app_db_entry_or; + + const std::string &operation = kfvOp(key_op_fvs_tuple); + if (operation == SET_COMMAND) + { + status = validateWcmpGroupEntry(app_db_entry); + if (!status.ok()) + { + SWSS_LOG_ERROR("Invalid WCMP group with id %s: %s", QuotedVar(app_db_entry.wcmp_group_id).c_str(), + status.message().c_str()); + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), + status, + /*replace=*/true); + continue; + } + auto *wcmp_group_entry = getWcmpGroupEntry(app_db_entry.wcmp_group_id); + if (wcmp_group_entry == nullptr) + { + // Create WCMP group + status = processAddRequest(&app_db_entry); + } + else + { + // Modify existing WCMP group + status = processUpdateRequest(&app_db_entry); + } + } + else if (operation == DEL_COMMAND) + { + // Delete WCMP group + status = removeWcmpGroup(app_db_entry.wcmp_group_id); + } + else + { + status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) + << "Unknown operation type: " << QuotedVar(operation) << " for WCMP group entry with key " + << QuotedVar(table_name) << ":" << QuotedVar(db_key) + << "; only SET and DEL operations are allowed."; + SWSS_LOG_ERROR("Unknown operation type %s\n", QuotedVar(operation).c_str()); + } + m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), kfvFieldsValues(key_op_fvs_tuple), status, + /*replace=*/true); + } + m_entries.clear(); +} - for (const auto& key_op_fvs_tuple : m_entries) { +std::string WcmpManager::verifyState(const std::string &key, const std::vector &tuple) +{ + SWSS_LOG_ENTER(); + + auto pos = key.find_first_of(kTableKeyDelimiter); + if (pos == std::string::npos) + { + return std::string("Invalid key: ") + key; + } + std::string p4rt_table = key.substr(0, pos); + std::string p4rt_key = key.substr(pos + 1); + if (p4rt_table != APP_P4RT_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } std::string table_name; - std::string db_key; - parseP4RTKey(kfvKey(key_op_fvs_tuple), &table_name, &db_key); - const std::vector& attributes = - kfvFieldsValues(key_op_fvs_tuple); + std::string key_content; + parseP4RTKey(p4rt_key, &table_name, &key_content); + if (table_name != APP_P4RT_WCMP_GROUP_TABLE_NAME) + { + return std::string("Invalid key: ") + key; + } ReturnCode status; - auto app_db_entry_or = deserializeP4WcmpGroupAppDbEntry(db_key, attributes); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - SWSS_LOG_ERROR( - "Unable to deserialize APP DB WCMP group entry with key %s: %s", - QuotedVar(table_name + ":" + db_key).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; + auto app_db_entry_or = deserializeP4WcmpGroupAppDbEntry(key_content, tuple); + if (!app_db_entry_or.ok()) + { + status = app_db_entry_or.status(); + std::stringstream msg; + msg << "Unable to deserialize key " << QuotedVar(key) << ": " << status.message(); + return msg.str(); } - auto& app_db_entry = *app_db_entry_or; - - const std::string& operation = kfvOp(key_op_fvs_tuple); - if (operation == SET_COMMAND) { - status = validateWcmpGroupEntry(app_db_entry); - if (!status.ok()) { - SWSS_LOG_ERROR("Invalid WCMP group with id %s: %s", - QuotedVar(app_db_entry.wcmp_group_id).c_str(), - status.message().c_str()); - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - continue; - } - auto* wcmp_group_entry = getWcmpGroupEntry(app_db_entry.wcmp_group_id); - if (wcmp_group_entry == nullptr) { - // Create WCMP group - status = processAddRequest(&app_db_entry); - } else { - // Modify existing WCMP group - status = processUpdateRequest(&app_db_entry); - } - } else if (operation == DEL_COMMAND) { - // Delete WCMP group - status = removeWcmpGroup(app_db_entry.wcmp_group_id); - } else { - status = ReturnCode(StatusCode::SWSS_RC_INVALID_PARAM) - << "Unknown operation type: " << QuotedVar(operation) - << " for WCMP group entry with key " << QuotedVar(table_name) - << ":" << QuotedVar(db_key) - << "; only SET and DEL operations are allowed."; - SWSS_LOG_ERROR("Unknown operation type %s\n", - QuotedVar(operation).c_str()); + auto &app_db_entry = *app_db_entry_or; + + auto *wcmp_group_entry = getWcmpGroupEntry(app_db_entry.wcmp_group_id); + if (wcmp_group_entry == nullptr) + { + std::stringstream msg; + msg << "No entry found with key " << QuotedVar(key); + return msg.str(); } - m_publisher->publish(APP_P4RT_TABLE_NAME, kfvKey(key_op_fvs_tuple), - kfvFieldsValues(key_op_fvs_tuple), status, - /*replace=*/true); - } - m_entries.clear(); -} -std::string WcmpManager::verifyState( - const std::string& key, const std::vector& tuple) { - SWSS_LOG_ENTER(); - - auto pos = key.find_first_of(kTableKeyDelimiter); - if (pos == std::string::npos) { - return std::string("Invalid key: ") + key; - } - std::string p4rt_table = key.substr(0, pos); - std::string p4rt_key = key.substr(pos + 1); - if (p4rt_table != APP_P4RT_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - std::string table_name; - std::string key_content; - parseP4RTKey(p4rt_key, &table_name, &key_content); - if (table_name != APP_P4RT_WCMP_GROUP_TABLE_NAME) { - return std::string("Invalid key: ") + key; - } - - ReturnCode status; - auto app_db_entry_or = deserializeP4WcmpGroupAppDbEntry(key_content, tuple); - if (!app_db_entry_or.ok()) { - status = app_db_entry_or.status(); - std::stringstream msg; - msg << "Unable to deserialize key " << QuotedVar(key) << ": " - << status.message(); - return msg.str(); - } - auto& app_db_entry = *app_db_entry_or; - - auto* wcmp_group_entry = getWcmpGroupEntry(app_db_entry.wcmp_group_id); - if (wcmp_group_entry == nullptr) { - std::stringstream msg; - msg << "No entry found with key " << QuotedVar(key); - return msg.str(); - } - - std::string cache_result = verifyStateCache(app_db_entry, wcmp_group_entry); - std::string asic_db_result = verifyStateAsicDb(wcmp_group_entry); - if (cache_result.empty()) { - return asic_db_result; - } - if (asic_db_result.empty()) { - return cache_result; - } - return cache_result + "; " + asic_db_result; + std::string cache_result = verifyStateCache(app_db_entry, wcmp_group_entry); + std::string asic_db_result = verifyStateAsicDb(wcmp_group_entry); + if (cache_result.empty()) + { + return asic_db_result; + } + if (asic_db_result.empty()) + { + return cache_result; + } + return cache_result + "; " + asic_db_result; } -std::string WcmpManager::verifyStateCache( - const P4WcmpGroupEntry& app_db_entry, - const P4WcmpGroupEntry* wcmp_group_entry) { - const std::string& wcmp_group_key = - KeyGenerator::generateWcmpGroupKey(app_db_entry.wcmp_group_id); - ReturnCode status = validateWcmpGroupEntry(app_db_entry); - if (!status.ok()) { - std::stringstream msg; - msg << "Validation failed for WCMP group DB entry with key " - << QuotedVar(wcmp_group_key) << ": " << status.message(); - return msg.str(); - } - - if (wcmp_group_entry->wcmp_group_id != app_db_entry.wcmp_group_id) { - std::stringstream msg; - msg << "WCMP group ID " << QuotedVar(app_db_entry.wcmp_group_id) - << " does not match internal cache " - << QuotedVar(wcmp_group_entry->wcmp_group_id) << " in wcmp manager."; - return msg.str(); - } - - std::string err_msg = m_p4OidMapper->verifyOIDMapping( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key, - wcmp_group_entry->wcmp_group_oid); - if (!err_msg.empty()) { - return err_msg; - } - - if (wcmp_group_entry->wcmp_group_members.size() != - app_db_entry.wcmp_group_members.size()) { - std::stringstream msg; - msg << "WCMP group with ID " << QuotedVar(app_db_entry.wcmp_group_id) - << " has member size " << app_db_entry.wcmp_group_members.size() - << " non-matching internal cache " - << wcmp_group_entry->wcmp_group_members.size(); - return msg.str(); - } - - for (size_t i = 0; i < wcmp_group_entry->wcmp_group_members.size(); ++i) { - if (wcmp_group_entry->wcmp_group_members[i]->next_hop_id != - app_db_entry.wcmp_group_members[i]->next_hop_id) { - std::stringstream msg; - msg << "WCMP group member " - << QuotedVar(app_db_entry.wcmp_group_members[i]->next_hop_id) - << " does not match internal cache " - << QuotedVar(wcmp_group_entry->wcmp_group_members[i]->next_hop_id) - << " in wcmp manager."; - return msg.str(); - } - if (wcmp_group_entry->wcmp_group_members[i]->weight != - app_db_entry.wcmp_group_members[i]->weight) { - std::stringstream msg; - msg << "WCMP group member " - << QuotedVar(app_db_entry.wcmp_group_members[i]->next_hop_id) - << " weight " << app_db_entry.wcmp_group_members[i]->weight - << " does not match internal cache " - << wcmp_group_entry->wcmp_group_members[i]->weight - << " in wcmp manager."; - return msg.str(); +std::string WcmpManager::verifyStateCache(const P4WcmpGroupEntry &app_db_entry, + const P4WcmpGroupEntry *wcmp_group_entry) +{ + const std::string &wcmp_group_key = KeyGenerator::generateWcmpGroupKey(app_db_entry.wcmp_group_id); + ReturnCode status = validateWcmpGroupEntry(app_db_entry); + if (!status.ok()) + { + std::stringstream msg; + msg << "Validation failed for WCMP group DB entry with key " << QuotedVar(wcmp_group_key) << ": " + << status.message(); + return msg.str(); } - if (wcmp_group_entry->wcmp_group_members[i]->watch_port != - app_db_entry.wcmp_group_members[i]->watch_port) { - std::stringstream msg; - msg << "WCMP group member " - << QuotedVar(app_db_entry.wcmp_group_members[i]->next_hop_id) - << " watch port " - << QuotedVar(app_db_entry.wcmp_group_members[i]->watch_port) - << " does not match internal cache " - << QuotedVar(wcmp_group_entry->wcmp_group_members[i]->watch_port) - << " in wcmp manager."; - return msg.str(); + + if (wcmp_group_entry->wcmp_group_id != app_db_entry.wcmp_group_id) + { + std::stringstream msg; + msg << "WCMP group ID " << QuotedVar(app_db_entry.wcmp_group_id) << " does not match internal cache " + << QuotedVar(wcmp_group_entry->wcmp_group_id) << " in wcmp manager."; + return msg.str(); } - if (wcmp_group_entry->wcmp_group_members[i]->wcmp_group_id != - app_db_entry.wcmp_group_members[i]->wcmp_group_id) { - std::stringstream msg; - msg << "WCMP group member " - << QuotedVar(app_db_entry.wcmp_group_members[i]->next_hop_id) - << " group ID " - << QuotedVar(app_db_entry.wcmp_group_members[i]->wcmp_group_id) - << " does not match internal cache " - << QuotedVar(wcmp_group_entry->wcmp_group_members[i]->wcmp_group_id) - << " in wcmp manager."; - return msg.str(); + + std::string err_msg = m_p4OidMapper->verifyOIDMapping(SAI_OBJECT_TYPE_NEXT_HOP_GROUP, wcmp_group_key, + wcmp_group_entry->wcmp_group_oid); + if (!err_msg.empty()) + { + return err_msg; } - if (!app_db_entry.wcmp_group_members[i]->watch_port.empty() && - wcmp_group_entry->wcmp_group_members[i]->pruned) { - continue; + + if (wcmp_group_entry->wcmp_group_members.size() != app_db_entry.wcmp_group_members.size()) + { + std::stringstream msg; + msg << "WCMP group with ID " << QuotedVar(app_db_entry.wcmp_group_id) << " has member size " + << app_db_entry.wcmp_group_members.size() << " non-matching internal cache " + << wcmp_group_entry->wcmp_group_members.size(); + return msg.str(); } - err_msg = m_p4OidMapper->verifyOIDMapping( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, - getWcmpGroupMemberKey( - wcmp_group_key, - wcmp_group_entry->wcmp_group_members[i]->member_oid), - wcmp_group_entry->wcmp_group_members[i]->member_oid); - if (!err_msg.empty()) { - return err_msg; + + for (size_t i = 0; i < wcmp_group_entry->wcmp_group_members.size(); ++i) + { + if (wcmp_group_entry->wcmp_group_members[i]->next_hop_id != app_db_entry.wcmp_group_members[i]->next_hop_id) + { + std::stringstream msg; + msg << "WCMP group member " << QuotedVar(app_db_entry.wcmp_group_members[i]->next_hop_id) + << " does not match internal cache " << QuotedVar(wcmp_group_entry->wcmp_group_members[i]->next_hop_id) + << " in wcmp manager."; + return msg.str(); + } + if (wcmp_group_entry->wcmp_group_members[i]->weight != app_db_entry.wcmp_group_members[i]->weight) + { + std::stringstream msg; + msg << "WCMP group member " << QuotedVar(app_db_entry.wcmp_group_members[i]->next_hop_id) << " weight " + << app_db_entry.wcmp_group_members[i]->weight << " does not match internal cache " + << wcmp_group_entry->wcmp_group_members[i]->weight << " in wcmp manager."; + return msg.str(); + } + if (wcmp_group_entry->wcmp_group_members[i]->watch_port != app_db_entry.wcmp_group_members[i]->watch_port) + { + std::stringstream msg; + msg << "WCMP group member " << QuotedVar(app_db_entry.wcmp_group_members[i]->next_hop_id) << " watch port " + << QuotedVar(app_db_entry.wcmp_group_members[i]->watch_port) << " does not match internal cache " + << QuotedVar(wcmp_group_entry->wcmp_group_members[i]->watch_port) << " in wcmp manager."; + return msg.str(); + } + if (wcmp_group_entry->wcmp_group_members[i]->wcmp_group_id != app_db_entry.wcmp_group_members[i]->wcmp_group_id) + { + std::stringstream msg; + msg << "WCMP group member " << QuotedVar(app_db_entry.wcmp_group_members[i]->next_hop_id) << " group ID " + << QuotedVar(app_db_entry.wcmp_group_members[i]->wcmp_group_id) << " does not match internal cache " + << QuotedVar(wcmp_group_entry->wcmp_group_members[i]->wcmp_group_id) << " in wcmp manager."; + return msg.str(); + } + if (!app_db_entry.wcmp_group_members[i]->watch_port.empty() && wcmp_group_entry->wcmp_group_members[i]->pruned) + { + continue; + } + err_msg = m_p4OidMapper->verifyOIDMapping( + SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, + getWcmpGroupMemberKey(wcmp_group_key, wcmp_group_entry->wcmp_group_members[i]->member_oid), + wcmp_group_entry->wcmp_group_members[i]->member_oid); + if (!err_msg.empty()) + { + return err_msg; + } } - } - return ""; + return ""; } -std::string WcmpManager::verifyStateAsicDb( - const P4WcmpGroupEntry* wcmp_group_entry) { - swss::DBConnector db("ASIC_DB", 0); - swss::Table table(&db, "ASIC_STATE"); - - auto group_attrs = getSaiGroupAttrs(*wcmp_group_entry); - std::vector exp = - saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP, (uint32_t)group_attrs.size(), - group_attrs.data(), /*countOnly=*/false); - std::string key = sai_serialize_object_type(SAI_OBJECT_TYPE_NEXT_HOP_GROUP) + - ":" + - sai_serialize_object_id(wcmp_group_entry->wcmp_group_oid); - std::vector values; - if (!table.get(key, values)) { - return std::string("ASIC DB key not found ") + key; - } - auto group_result = - verifyAttrs(values, exp, std::vector{}, - /*allow_unknown=*/false); - if (!group_result.empty()) { - return group_result; - } - - for (const auto& member : wcmp_group_entry->wcmp_group_members) { - if (!member->watch_port.empty() && member->pruned) { - continue; - } - auto member_attrs = - getSaiMemberAttrs(*member, wcmp_group_entry->wcmp_group_oid); - std::vector exp = - saimeta::SaiAttributeList::serialize_attr_list( - SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, - (uint32_t)member_attrs.size(), member_attrs.data(), - /*countOnly=*/false); - std::string key = - sai_serialize_object_type(SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER) + ":" + - sai_serialize_object_id(member->member_oid); +std::string WcmpManager::verifyStateAsicDb(const P4WcmpGroupEntry *wcmp_group_entry) +{ + swss::DBConnector db("ASIC_DB", 0); + swss::Table table(&db, "ASIC_STATE"); + + auto group_attrs = getSaiGroupAttrs(*wcmp_group_entry); + std::vector exp = saimeta::SaiAttributeList::serialize_attr_list( + SAI_OBJECT_TYPE_NEXT_HOP_GROUP, (uint32_t)group_attrs.size(), group_attrs.data(), /*countOnly=*/false); + std::string key = sai_serialize_object_type(SAI_OBJECT_TYPE_NEXT_HOP_GROUP) + ":" + + sai_serialize_object_id(wcmp_group_entry->wcmp_group_oid); std::vector values; - if (!table.get(key, values)) { - return std::string("ASIC DB key not found ") + key; + if (!table.get(key, values)) + { + return std::string("ASIC DB key not found ") + key; } - auto member_result = - verifyAttrs(values, exp, std::vector{}, - /*allow_unknown=*/false); - if (!member_result.empty()) { - return member_result; + auto group_result = verifyAttrs(values, exp, std::vector{}, + /*allow_unknown=*/false); + if (!group_result.empty()) + { + return group_result; + } + + for (const auto &member : wcmp_group_entry->wcmp_group_members) + { + if (!member->watch_port.empty() && member->pruned) + { + continue; + } + auto member_attrs = getSaiMemberAttrs(*member, wcmp_group_entry->wcmp_group_oid); + std::vector exp = saimeta::SaiAttributeList::serialize_attr_list( + SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER, (uint32_t)member_attrs.size(), member_attrs.data(), + /*countOnly=*/false); + std::string key = sai_serialize_object_type(SAI_OBJECT_TYPE_NEXT_HOP_GROUP_MEMBER) + ":" + + sai_serialize_object_id(member->member_oid); + std::vector values; + if (!table.get(key, values)) + { + return std::string("ASIC DB key not found ") + key; + } + auto member_result = verifyAttrs(values, exp, std::vector{}, + /*allow_unknown=*/false); + if (!member_result.empty()) + { + return member_result; + } } - } - return ""; + return ""; } -} // namespace p4orch +} // namespace p4orch diff --git a/orchagent/p4orch/wcmp_manager.h b/orchagent/p4orch/wcmp_manager.h index f18db8729c4..7d533bf28fd 100644 --- a/orchagent/p4orch/wcmp_manager.h +++ b/orchagent/p4orch/wcmp_manager.h @@ -11,30 +11,35 @@ #include "p4orch/p4oidmapper.h" #include "response_publisher_interface.h" #include "return_code.h" -extern "C" { +extern "C" +{ #include "sai.h" } -namespace p4orch { -namespace test { +namespace p4orch +{ +namespace test +{ class WcmpManagerTest; -} // namespace test - -struct P4WcmpGroupMemberEntry { - std::string next_hop_id; - // Default ECMP(weight=1) - int weight = 1; - std::string watch_port; - bool pruned; - sai_object_id_t member_oid = SAI_NULL_OBJECT_ID; - std::string wcmp_group_id; +} // namespace test + +struct P4WcmpGroupMemberEntry +{ + std::string next_hop_id; + // Default ECMP(weight=1) + int weight = 1; + std::string watch_port; + bool pruned; + sai_object_id_t member_oid = SAI_NULL_OBJECT_ID; + std::string wcmp_group_id; }; -struct P4WcmpGroupEntry { - std::string wcmp_group_id; - // next_hop_id: P4WcmpGroupMemberEntry - std::vector> wcmp_group_members; - sai_object_id_t wcmp_group_oid = SAI_NULL_OBJECT_ID; +struct P4WcmpGroupEntry +{ + std::string wcmp_group_id; + // next_hop_id: P4WcmpGroupMemberEntry + std::vector> wcmp_group_members; + sai_object_id_t wcmp_group_oid = SAI_NULL_OBJECT_ID; }; // WcmpManager listens to changes in table APP_P4RT_WCMP_GROUP_TABLE_NAME and @@ -57,139 +62,120 @@ struct P4WcmpGroupEntry { // }, // ] // "controller_metadata" = "..." -class WcmpManager : public ObjectManagerInterface { - public: - WcmpManager(P4OidMapper* p4oidMapper, ResponsePublisherInterface* publisher); - - virtual ~WcmpManager() = default; - - void enqueue(const std::string& table_name, - const swss::KeyOpFieldsValuesTuple& entry) override; - void drain() override; - std::string verifyState( - const std::string& key, - const std::vector& tuple) override; - ReturnCode getSaiObject(const std::string& json_key, - sai_object_type_t& object_type, - std::string& object_key) override; - - // Prunes next hop members egressing through the given port. - void pruneNextHops(const std::string& port); - - // Restores pruned next hop members on link up. Returns an SWSS status code. - void restorePrunedNextHops(const std::string& port); - - // Inserts into/updates port_oper_status_map - void updatePortOperStatusMap(const std::string& port, - const sai_port_oper_status_t& status); - - private: - // Gets the internal cached WCMP group entry by its key. - // Return nullptr if corresponding WCMP group entry is not cached. - P4WcmpGroupEntry* getWcmpGroupEntry(const std::string& wcmp_group_id); - - // Deserializes an entry from table APP_P4RT_WCMP_GROUP_TABLE_NAME. - ReturnCodeOr deserializeP4WcmpGroupAppDbEntry( - const std::string& key, - const std::vector& attributes); - - // Perform validation on WCMP group entry. Return a SWSS status code - ReturnCode validateWcmpGroupEntry(const P4WcmpGroupEntry& app_db_entry); - - // Processes add operation for an entry. - ReturnCode processAddRequest(P4WcmpGroupEntry* app_db_entry); - - // Creates an WCMP group in the WCMP group table. - // validateWcmpGroupEntry() is required in caller function before - // createWcmpGroup() is called - ReturnCode createWcmpGroup(P4WcmpGroupEntry* wcmp_group_entry); - - // Creates WCMP group member in the WCMP group. - ReturnCode createWcmpGroupMember( - std::shared_ptr wcmp_group_member, - const sai_object_id_t group_oid, const std::string& wcmp_group_key); - - // Performs watchport related addition operations and creates WCMP group - // members. - ReturnCode processWcmpGroupMembersAddition( - const std::vector>& members, - const std::string& wcmp_group_key, sai_object_id_t wcmp_group_oid, - std::vector>& - created_wcmp_group_members); - - // Performs watchport related removal operations and removes WCMP group - // members. - ReturnCode processWcmpGroupMembersRemoval( - const std::vector>& members, - const std::string& wcmp_group_key, - std::vector>& - removed_wcmp_group_members); - - // Processes update operation for a WCMP group entry. - ReturnCode processUpdateRequest(P4WcmpGroupEntry* wcmp_group_entry); - - // Clean up group members when request fails - void recoverGroupMembers( - p4orch::P4WcmpGroupEntry* wcmp_group, const std::string& wcmp_group_key, - const std::vector>& - created_wcmp_group_members, - const std::vector>& - removed_wcmp_group_members); - - // Deletes a WCMP group in the WCMP group table. - ReturnCode removeWcmpGroup(const std::string& wcmp_group_id); - - // Deletes a WCMP group member in the WCMP group table. - ReturnCode removeWcmpGroupMember( - const std::shared_ptr wcmp_group_member, - const std::string& wcmp_group_id); - - // Fetches oper-status of port using port_oper_status_map or SAI. - ReturnCode fetchPortOperStatus(const std::string& port, - sai_port_oper_status_t* oper_status); - - // Inserts a next hop member in port_name_to_wcmp_group_member_map - void insertMemberInPortNameToWcmpGroupMemberMap( - std::shared_ptr member); - - // Removes a next hop member from port_name_to_wcmp_group_member_map - void removeMemberFromPortNameToWcmpGroupMemberMap( - std::shared_ptr member); - - // Gets port oper-status from port_oper_status_map if present - bool getPortOperStatusFromMap(const std::string& port, - sai_port_oper_status_t* status); - - // Verifies the internal cache for an entry. - std::string verifyStateCache(const P4WcmpGroupEntry& app_db_entry, - const P4WcmpGroupEntry* wcmp_group_entry); - - // Verifies the ASIC DB for an entry. - std::string verifyStateAsicDb(const P4WcmpGroupEntry* wcmp_group_entry); - - // Returns the SAI attributes for a group member. - std::vector getSaiMemberAttrs( - const P4WcmpGroupMemberEntry& wcmp_member_entry, - const sai_object_id_t group_oid); - - // Maps wcmp_group_id to P4WcmpGroupEntry - std::unordered_map m_wcmpGroupTable; - - // Maps port name to P4WcmpGroupMemberEntry - std::unordered_map< - std::string, std::unordered_set>> - port_name_to_wcmp_group_member_map; - - // Maps port name to oper-status - std::unordered_map port_oper_status_map; - - // Owners of pointers below must outlive this class's instance. - P4OidMapper* m_p4OidMapper; - std::deque m_entries; - ResponsePublisherInterface* m_publisher; - ObjectBulker gNextHopGroupMemberBulker; - - friend class p4orch::test::WcmpManagerTest; +class WcmpManager : public ObjectManagerInterface +{ + public: + WcmpManager(P4OidMapper *p4oidMapper, ResponsePublisherInterface *publisher); + + virtual ~WcmpManager() = default; + + void enqueue(const std::string &table_name, const swss::KeyOpFieldsValuesTuple &entry) override; + void drain() override; + std::string verifyState(const std::string &key, const std::vector &tuple) override; + ReturnCode getSaiObject(const std::string &json_key, sai_object_type_t &object_type, + std::string &object_key) override; + + // Prunes next hop members egressing through the given port. + void pruneNextHops(const std::string &port); + + // Restores pruned next hop members on link up. Returns an SWSS status code. + void restorePrunedNextHops(const std::string &port); + + // Inserts into/updates port_oper_status_map + void updatePortOperStatusMap(const std::string &port, const sai_port_oper_status_t &status); + + private: + // Gets the internal cached WCMP group entry by its key. + // Return nullptr if corresponding WCMP group entry is not cached. + P4WcmpGroupEntry *getWcmpGroupEntry(const std::string &wcmp_group_id); + + // Deserializes an entry from table APP_P4RT_WCMP_GROUP_TABLE_NAME. + ReturnCodeOr deserializeP4WcmpGroupAppDbEntry( + const std::string &key, const std::vector &attributes); + + // Perform validation on WCMP group entry. Return a SWSS status code + ReturnCode validateWcmpGroupEntry(const P4WcmpGroupEntry &app_db_entry); + + // Processes add operation for an entry. + ReturnCode processAddRequest(P4WcmpGroupEntry *app_db_entry); + + // Creates an WCMP group in the WCMP group table. + // validateWcmpGroupEntry() is required in caller function before + // createWcmpGroup() is called + ReturnCode createWcmpGroup(P4WcmpGroupEntry *wcmp_group_entry); + + // Creates WCMP group member in the WCMP group. + ReturnCode createWcmpGroupMember(std::shared_ptr wcmp_group_member, + const sai_object_id_t group_oid, const std::string &wcmp_group_key); + + // Performs watchport related addition operations and creates WCMP group + // members. + ReturnCode processWcmpGroupMembersAddition( + const std::vector> &members, const std::string &wcmp_group_key, + sai_object_id_t wcmp_group_oid, + std::vector> &created_wcmp_group_members); + + // Performs watchport related removal operations and removes WCMP group + // members. + ReturnCode processWcmpGroupMembersRemoval( + const std::vector> &members, const std::string &wcmp_group_key, + std::vector> &removed_wcmp_group_members); + + // Processes update operation for a WCMP group entry. + ReturnCode processUpdateRequest(P4WcmpGroupEntry *wcmp_group_entry); + + // Clean up group members when request fails + void recoverGroupMembers( + p4orch::P4WcmpGroupEntry *wcmp_group, const std::string &wcmp_group_key, + const std::vector> &created_wcmp_group_members, + const std::vector> &removed_wcmp_group_members); + + // Deletes a WCMP group in the WCMP group table. + ReturnCode removeWcmpGroup(const std::string &wcmp_group_id); + + // Deletes a WCMP group member in the WCMP group table. + ReturnCode removeWcmpGroupMember(const std::shared_ptr wcmp_group_member, + const std::string &wcmp_group_id); + + // Fetches oper-status of port using port_oper_status_map or SAI. + ReturnCode fetchPortOperStatus(const std::string &port, sai_port_oper_status_t *oper_status); + + // Inserts a next hop member in port_name_to_wcmp_group_member_map + void insertMemberInPortNameToWcmpGroupMemberMap(std::shared_ptr member); + + // Removes a next hop member from port_name_to_wcmp_group_member_map + void removeMemberFromPortNameToWcmpGroupMemberMap(std::shared_ptr member); + + // Gets port oper-status from port_oper_status_map if present + bool getPortOperStatusFromMap(const std::string &port, sai_port_oper_status_t *status); + + // Verifies the internal cache for an entry. + std::string verifyStateCache(const P4WcmpGroupEntry &app_db_entry, const P4WcmpGroupEntry *wcmp_group_entry); + + // Verifies the ASIC DB for an entry. + std::string verifyStateAsicDb(const P4WcmpGroupEntry *wcmp_group_entry); + + // Returns the SAI attributes for a group member. + std::vector getSaiMemberAttrs(const P4WcmpGroupMemberEntry &wcmp_member_entry, + const sai_object_id_t group_oid); + + // Maps wcmp_group_id to P4WcmpGroupEntry + std::unordered_map m_wcmpGroupTable; + + // Maps port name to P4WcmpGroupMemberEntry + std::unordered_map>> + port_name_to_wcmp_group_member_map; + + // Maps port name to oper-status + std::unordered_map port_oper_status_map; + + // Owners of pointers below must outlive this class's instance. + P4OidMapper *m_p4OidMapper; + std::deque m_entries; + ResponsePublisherInterface *m_publisher; + ObjectBulker gNextHopGroupMemberBulker; + + friend class p4orch::test::WcmpManagerTest; }; -} // namespace p4orch +} // namespace p4orch diff --git a/orchagent/response_publisher.cpp b/orchagent/response_publisher.cpp index ab0b187829f..5adc500fe80 100644 --- a/orchagent/response_publisher.cpp +++ b/orchagent/response_publisher.cpp @@ -5,239 +5,275 @@ #include #include -namespace { +namespace +{ // Returns the component string that we need to prepend for sending the error // message. // Returns an empty string if the status is OK. // Returns "[SAI] " if the ReturnCode is generated from a SAI status code. // Else, returns "[OrchAgent] ". -std::string PrependedComponent(const ReturnCode& status) { - constexpr char* kOrchagentComponent = "[OrchAgent] "; - constexpr char* kSaiComponent = "[SAI] "; - if (status.ok()) { - return ""; - } - if (status.isSai()) { - return kSaiComponent; - } - return kOrchagentComponent; +std::string PrependedComponent(const ReturnCode &status) +{ + constexpr char *kOrchagentComponent = "[OrchAgent] "; + constexpr char *kSaiComponent = "[SAI] "; + if (status.ok()) + { + return ""; + } + if (status.isSai()) + { + return kSaiComponent; + } + return kOrchagentComponent; } -void RecordDBWrite(const std::string& table, const std::string& key, - const std::vector& attrs, - const std::string& op) { - if (!swss::Recorder::Instance().respub.isRecord()) { - return; - } +void RecordDBWrite(const std::string &table, const std::string &key, const std::vector &attrs, + const std::string &op) +{ + if (!swss::Recorder::Instance().respub.isRecord()) + { + return; + } - std::string s = table + ":" + key + "|" + op; - for (const auto& attr : attrs) { - s += "|" + fvField(attr) + ":" + fvValue(attr); - } + std::string s = table + ":" + key + "|" + op; + for (const auto &attr : attrs) + { + s += "|" + fvField(attr) + ":" + fvValue(attr); + } - swss::Recorder::Instance().respub.record(s); + swss::Recorder::Instance().respub.record(s); } -void RecordResponse(const std::string& response_channel, const std::string& key, - const std::vector& attrs, - const std::string& status) { - if (!swss::Recorder::Instance().respub.isRecord()) { - return; - } +void RecordResponse(const std::string &response_channel, const std::string &key, + const std::vector &attrs, const std::string &status) +{ + if (!swss::Recorder::Instance().respub.isRecord()) + { + return; + } - std::string s = response_channel + ":" + key + "|" + status; - for (const auto& attr : attrs) { - s += "|" + fvField(attr) + ":" + fvValue(attr); - } + std::string s = response_channel + ":" + key + "|" + status; + for (const auto &attr : attrs) + { + s += "|" + fvField(attr) + ":" + fvValue(attr); + } - swss::Recorder::Instance().respub.record(s); + swss::Recorder::Instance().respub.record(s); } -} // namespace - -ResponsePublisher::ResponsePublisher(const std::string& dbName, bool buffered, - bool db_write_thread) - : m_db(std::make_unique(dbName, 0)), - m_buffered(buffered) { - if (m_buffered) { - m_ntf_pipe = std::make_unique(m_db.get()); - m_pipe = std::make_unique(m_db.get()); - } else { - m_ntf_pipe = std::make_unique(m_db.get(), 1); - m_pipe = std::make_unique(m_db.get(), 1); - } - if (db_write_thread) { - m_update_thread = std::unique_ptr( - new std::thread(&ResponsePublisher::dbUpdateThread, this)); - } -} +} // namespace -ResponsePublisher::~ResponsePublisher() { - if (m_update_thread != nullptr) { - { - std::lock_guard lock(m_lock); - m_queue.push(entry{ - .table = "", - .key = "", - .values = std::vector{}, - .op = "", - .replace = false, - .flush = false, - .shutdown = true, - }); - } - m_signal.notify_one(); - m_update_thread->join(); - } +ResponsePublisher::ResponsePublisher(const std::string &dbName, bool buffered, bool db_write_thread) + : m_db(std::make_unique(dbName, 0)), m_buffered(buffered) +{ + if (m_buffered) + { + m_ntf_pipe = std::make_unique(m_db.get()); + m_pipe = std::make_unique(m_db.get()); + } + else + { + m_ntf_pipe = std::make_unique(m_db.get(), 1); + m_pipe = std::make_unique(m_db.get(), 1); + } + if (db_write_thread) + { + m_update_thread = std::unique_ptr(new std::thread(&ResponsePublisher::dbUpdateThread, this)); + } } -void ResponsePublisher::publish( - const std::string& table, const std::string& key, - const std::vector& intent_attrs, - const ReturnCode& status, - const std::vector& state_attrs, bool replace) { - std::string response_channel = "APPL_DB_" + table + "_RESPONSE_CHANNEL"; - swss::NotificationProducer notificationProducer{m_ntf_pipe.get(), - response_channel, m_buffered}; - - auto intent_attrs_copy = intent_attrs; - // Add error message as the first field-value-pair. - swss::FieldValueTuple err_str("err_str", - PrependedComponent(status) + status.message()); - intent_attrs_copy.insert(intent_attrs_copy.begin(), err_str); - // Sends the response to the notification channel. - notificationProducer.send(status.codeStr(), key, intent_attrs_copy); - RecordResponse(response_channel, key, intent_attrs_copy, status.codeStr()); - - // Write to the DB only if: - // 1) A write operation is being performed and state attributes are specified. - // 2) A successful delete operation. - if ((intent_attrs.size() && state_attrs.size()) || - (status.ok() && !intent_attrs.size())) { - writeToDB(table, key, state_attrs, - intent_attrs.size() ? SET_COMMAND : DEL_COMMAND, replace); - } +ResponsePublisher::~ResponsePublisher() +{ + if (m_update_thread != nullptr) + { + { + std::lock_guard lock(m_lock); + m_queue.push(entry{ + .table = "", + .key = "", + .values = std::vector{}, + .op = "", + .replace = false, + .flush = false, + .shutdown = true, + }); + } + m_signal.notify_one(); + m_update_thread->join(); + } } -void ResponsePublisher::publish( - const std::string& table, const std::string& key, - const std::vector& intent_attrs, - const ReturnCode& status, bool replace) { - // If status is OK then intent attributes need to be written in - // APPL_STATE_DB. In this case, pass the intent attributes as state - // attributes. In case of a failure status, nothing needs to be written in - // APPL_STATE_DB. - std::vector state_attrs; - if (status.ok()) { - state_attrs = intent_attrs; - } - publish(table, key, intent_attrs, status, state_attrs, replace); -} +void ResponsePublisher::publish(const std::string &table, const std::string &key, + const std::vector &intent_attrs, const ReturnCode &status, + const std::vector &state_attrs, bool replace) +{ + std::string response_channel = "APPL_DB_" + table + "_RESPONSE_CHANNEL"; + swss::NotificationProducer notificationProducer{m_ntf_pipe.get(), response_channel, m_buffered}; -void ResponsePublisher::writeToDB( - const std::string& table, const std::string& key, - const std::vector& values, const std::string& op, - bool replace) { - if (m_update_thread != nullptr) { - { - std::lock_guard lock(m_lock); - m_queue.push(entry{ - .table = table, - .key = key, - .values = values, - .op = op, - .replace = replace, - .flush = false, - .shutdown = false, - }); - } - m_signal.notify_one(); - } else { - writeToDBInternal(table, key, values, op, replace); - } - RecordDBWrite(table, key, values, op); + auto intent_attrs_copy = intent_attrs; + // Add error message as the first field-value-pair. + swss::FieldValueTuple err_str("err_str", PrependedComponent(status) + status.message()); + intent_attrs_copy.insert(intent_attrs_copy.begin(), err_str); + // Sends the response to the notification channel. + notificationProducer.send(status.codeStr(), key, intent_attrs_copy); + RecordResponse(response_channel, key, intent_attrs_copy, status.codeStr()); + + // Write to the DB only if: + // 1) A write operation is being performed and state attributes are specified. + // 2) A successful delete operation. + if ((intent_attrs.size() && state_attrs.size()) || (status.ok() && !intent_attrs.size())) + { + writeToDB(table, key, state_attrs, intent_attrs.size() ? SET_COMMAND : DEL_COMMAND, replace); + } } -void ResponsePublisher::writeToDBInternal( - const std::string& table, const std::string& key, - const std::vector& values, const std::string& op, - bool replace) { - swss::Table applStateTable{m_pipe.get(), table, m_buffered}; - - auto attrs = values; - if (op == SET_COMMAND) { - if (replace) { - applStateTable.del(key); - } - if (!values.size()) { - attrs.push_back(swss::FieldValueTuple("NULL", "NULL")); - } - - // Write to DB only if the key does not exist or non-NULL attributes are - // being written to the entry. - std::vector fv; - if (!applStateTable.get(key, fv)) { - applStateTable.set(key, attrs); - return; - } - for (auto it = attrs.cbegin(); it != attrs.cend();) { - if (it->first == "NULL") { - it = attrs.erase(it); - } else { - it++; - } - } - if (attrs.size()) { - applStateTable.set(key, attrs); - } - } else if (op == DEL_COMMAND) { - applStateTable.del(key); - } +void ResponsePublisher::publish(const std::string &table, const std::string &key, + const std::vector &intent_attrs, const ReturnCode &status, + bool replace) +{ + // If status is OK then intent attributes need to be written in + // APPL_STATE_DB. In this case, pass the intent attributes as state + // attributes. In case of a failure status, nothing needs to be written in + // APPL_STATE_DB. + std::vector state_attrs; + if (status.ok()) + { + state_attrs = intent_attrs; + } + publish(table, key, intent_attrs, status, state_attrs, replace); } -void ResponsePublisher::flush() { - m_ntf_pipe->flush(); - if (m_update_thread != nullptr) { - { - std::lock_guard lock(m_lock); - m_queue.push(entry{ - .table = "", - .key = "", - .values = std::vector{}, - .op = "", - .replace = false, - .flush = true, - .shutdown = false, - }); - } - m_signal.notify_one(); - } else { - m_pipe->flush(); - } +void ResponsePublisher::writeToDB(const std::string &table, const std::string &key, + const std::vector &values, const std::string &op, bool replace) +{ + if (m_update_thread != nullptr) + { + { + std::lock_guard lock(m_lock); + m_queue.push(entry{ + .table = table, + .key = key, + .values = values, + .op = op, + .replace = replace, + .flush = false, + .shutdown = false, + }); + } + m_signal.notify_one(); + } + else + { + writeToDBInternal(table, key, values, op, replace); + } + RecordDBWrite(table, key, values, op); } -void ResponsePublisher::setBuffered(bool buffered) { m_buffered = buffered; } +void ResponsePublisher::writeToDBInternal(const std::string &table, const std::string &key, + const std::vector &values, const std::string &op, + bool replace) +{ + swss::Table applStateTable{m_pipe.get(), table, m_buffered}; + + auto attrs = values; + if (op == SET_COMMAND) + { + if (replace) + { + applStateTable.del(key); + } + if (!values.size()) + { + attrs.push_back(swss::FieldValueTuple("NULL", "NULL")); + } -void ResponsePublisher::dbUpdateThread() { - while (true) { - entry e; + // Write to DB only if the key does not exist or non-NULL attributes are + // being written to the entry. + std::vector fv; + if (!applStateTable.get(key, fv)) + { + applStateTable.set(key, attrs); + return; + } + for (auto it = attrs.cbegin(); it != attrs.cend();) + { + if (it->first == "NULL") + { + it = attrs.erase(it); + } + else + { + it++; + } + } + if (attrs.size()) + { + applStateTable.set(key, attrs); + } + } + else if (op == DEL_COMMAND) { - std::unique_lock lock(m_lock); - while (m_queue.empty()) { - m_signal.wait(lock); - } + applStateTable.del(key); + } +} - e = m_queue.front(); - m_queue.pop(); +void ResponsePublisher::flush() +{ + m_ntf_pipe->flush(); + if (m_update_thread != nullptr) + { + { + std::lock_guard lock(m_lock); + m_queue.push(entry{ + .table = "", + .key = "", + .values = std::vector{}, + .op = "", + .replace = false, + .flush = true, + .shutdown = false, + }); + } + m_signal.notify_one(); } - if (e.shutdown) { - break; + else + { + m_pipe->flush(); } - if (e.flush) { - m_pipe->flush(); - } else { - writeToDBInternal(e.table, e.key, e.values, e.op, e.replace); +} + +void ResponsePublisher::setBuffered(bool buffered) +{ + m_buffered = buffered; +} + +void ResponsePublisher::dbUpdateThread() +{ + while (true) + { + entry e; + { + std::unique_lock lock(m_lock); + while (m_queue.empty()) + { + m_signal.wait(lock); + } + + e = m_queue.front(); + m_queue.pop(); + } + if (e.shutdown) + { + break; + } + if (e.flush) + { + m_pipe->flush(); + } + else + { + writeToDBInternal(e.table, e.key, e.values, e.op, e.replace); + } } - } } diff --git a/orchagent/response_publisher.h b/orchagent/response_publisher.h index 593a6594678..d583fa60495 100644 --- a/orchagent/response_publisher.h +++ b/orchagent/response_publisher.h @@ -18,75 +18,72 @@ // This class performs two tasks when publish is called: // 1. Sends a notification into the redis channel. // 2. Writes the operation into the DB. -class ResponsePublisher : public ResponsePublisherInterface { - public: - explicit ResponsePublisher(const std::string& dbName, bool buffered = false, - bool db_write_thread = false); +class ResponsePublisher : public ResponsePublisherInterface +{ + public: + explicit ResponsePublisher(const std::string &dbName, bool buffered = false, bool db_write_thread = false); - virtual ~ResponsePublisher(); + virtual ~ResponsePublisher(); - // Intent attributes are the attributes sent in the notification into the - // redis channel. - // State attributes are the list of attributes that need to be written in - // the DB namespace. These might be different from intent attributes. For - // example: - // 1) If only a subset of the intent attributes were successfully applied, the - // state attributes shall be different from intent attributes. - // 2) If additional state changes occur due to the intent attributes, more - // attributes need to be added in the state DB namespace. - // 3) Invalid attributes are excluded from the state attributes. - // State attributes will be written into the DB even if the status code - // consists of an error. - void publish(const std::string& table, const std::string& key, - const std::vector& intent_attrs, - const ReturnCode& status, - const std::vector& state_attrs, - bool replace = false) override; + // Intent attributes are the attributes sent in the notification into the + // redis channel. + // State attributes are the list of attributes that need to be written in + // the DB namespace. These might be different from intent attributes. For + // example: + // 1) If only a subset of the intent attributes were successfully applied, the + // state attributes shall be different from intent attributes. + // 2) If additional state changes occur due to the intent attributes, more + // attributes need to be added in the state DB namespace. + // 3) Invalid attributes are excluded from the state attributes. + // State attributes will be written into the DB even if the status code + // consists of an error. + void publish(const std::string &table, const std::string &key, + const std::vector &intent_attrs, const ReturnCode &status, + const std::vector &state_attrs, bool replace = false) override; - void publish(const std::string& table, const std::string& key, - const std::vector& intent_attrs, - const ReturnCode& status, bool replace = false) override; + void publish(const std::string &table, const std::string &key, + const std::vector &intent_attrs, const ReturnCode &status, + bool replace = false) override; - void writeToDB(const std::string& table, const std::string& key, - const std::vector& values, - const std::string& op, bool replace = false) override; + void writeToDB(const std::string &table, const std::string &key, const std::vector &values, + const std::string &op, bool replace = false) override; - /** - * @brief Flush pending responses - */ - void flush(); + /** + * @brief Flush pending responses + */ + void flush(); - /** - * @brief Set buffering mode - * - * @param buffered Flag whether responses are buffered - */ - void setBuffered(bool buffered); + /** + * @brief Set buffering mode + * + * @param buffered Flag whether responses are buffered + */ + void setBuffered(bool buffered); - private: - struct entry { - std::string table; - std::string key; - std::vector values; - std::string op; - bool replace; - bool flush; - bool shutdown; - }; + private: + struct entry + { + std::string table; + std::string key; + std::vector values; + std::string op; + bool replace; + bool flush; + bool shutdown; + }; - void dbUpdateThread(); - void writeToDBInternal(const std::string& table, const std::string& key, - const std::vector& values, - const std::string& op, bool replace); + void dbUpdateThread(); + void writeToDBInternal(const std::string &table, const std::string &key, + const std::vector &values, const std::string &op, bool replace); - std::unique_ptr m_db; - std::unique_ptr m_ntf_pipe; - std::unique_ptr m_pipe; + std::unique_ptr m_db; + std::unique_ptr m_ntf_pipe; + std::unique_ptr m_pipe; - bool m_buffered{false}; - // Thread to write to DB. - std::unique_ptr m_update_thread; - std::queue m_queue; - mutable std::mutex m_lock; - std::condition_variable m_signal; + bool m_buffered{false}; + // Thread to write to DB. + std::unique_ptr m_update_thread; + std::queue m_queue; + mutable std::mutex m_lock; + std::condition_variable m_signal; }; diff --git a/orchagent/response_publisher_interface.h b/orchagent/response_publisher_interface.h index 92d364a500f..094238b8260 100644 --- a/orchagent/response_publisher_interface.h +++ b/orchagent/response_publisher_interface.h @@ -5,32 +5,31 @@ #include "return_code.h" #include "table.h" -class ResponsePublisherInterface { - public: - virtual ~ResponsePublisherInterface() = default; +class ResponsePublisherInterface +{ + public: + virtual ~ResponsePublisherInterface() = default; - // Publishes the response status. - // If intent attributes are empty, it is a delete operation. - // What "publish" needs to do is completely up to implementation. - // This API does not include redis DB namespace. So if implementation chooses - // to write to a redis DB, it will need to use a fixed namespace. - // The replace flag indicates the state attributes will replace the old ones. - virtual void publish(const std::string& table, const std::string& key, - const std::vector& intent_attrs, - const ReturnCode& status, - const std::vector& state_attrs, - bool replace = false) = 0; + // Publishes the response status. + // If intent attributes are empty, it is a delete operation. + // What "publish" needs to do is completely up to implementation. + // This API does not include redis DB namespace. So if implementation chooses + // to write to a redis DB, it will need to use a fixed namespace. + // The replace flag indicates the state attributes will replace the old ones. + virtual void publish(const std::string &table, const std::string &key, + const std::vector &intent_attrs, const ReturnCode &status, + const std::vector &state_attrs, bool replace = false) = 0; - // Publishes response status. If response status is OK then also writes the - // intent attributes into the DB. - // The replace flag indicates a replace operation. - virtual void publish(const std::string& table, const std::string& key, - const std::vector& intent_attrs, - const ReturnCode& status, bool replace = false) = 0; + // Publishes response status. If response status is OK then also writes the + // intent attributes into the DB. + // The replace flag indicates a replace operation. + virtual void publish(const std::string &table, const std::string &key, + const std::vector &intent_attrs, const ReturnCode &status, + bool replace = false) = 0; - // Write to DB only. This API does not send notification. - // The replace flag indicates the new attributes will replace the old ones. - virtual void writeToDB(const std::string& table, const std::string& key, - const std::vector& values, - const std::string& op, bool replace = false) = 0; + // Write to DB only. This API does not send notification. + // The replace flag indicates the new attributes will replace the old ones. + virtual void writeToDB(const std::string &table, const std::string &key, + const std::vector &values, const std::string &op, + bool replace = false) = 0; }; diff --git a/orchagent/return_code.h b/orchagent/return_code.h index 592ad091470..c9b404f5d7f 100644 --- a/orchagent/return_code.h +++ b/orchagent/return_code.h @@ -10,7 +10,8 @@ #include "sai_serialize.h" #include "status_code_util.h" -extern "C" { +extern "C" +{ #include "sai.h" } @@ -25,37 +26,41 @@ using swss::StatusCode; // RETURN_IF_ERROR(Foo()); // return ReturnCode(); // } -#define RETURN_IF_ERROR(expr) \ - do { \ - ReturnCode RETURN_IF_ERROR_RC_ = expr; \ - if (!RETURN_IF_ERROR_RC_.ok()) return RETURN_IF_ERROR_RC_; \ - } while (0) +#define RETURN_IF_ERROR(expr) \ + do \ + { \ + ReturnCode RETURN_IF_ERROR_RC_ = expr; \ + if (!RETURN_IF_ERROR_RC_.ok()) \ + return RETURN_IF_ERROR_RC_; \ + } while (0) // LOG_ERROR_AND_RETURN evaluates an expression that should returns an error // ReturnCode. Logs the error message in the ReturnCode by calling // SWSS_LOG_ERROR and returns. -#define LOG_ERROR_AND_RETURN(expr) \ - do { \ - ReturnCode LOG_ERROR_AND_RETURN_RC_ = expr; \ - SWSS_LOG_ERROR("%s", LOG_ERROR_AND_RETURN_RC_.message().c_str()); \ - return LOG_ERROR_AND_RETURN_RC_; \ - } while (0) +#define LOG_ERROR_AND_RETURN(expr) \ + do \ + { \ + ReturnCode LOG_ERROR_AND_RETURN_RC_ = expr; \ + SWSS_LOG_ERROR("%s", LOG_ERROR_AND_RETURN_RC_.message().c_str()); \ + return LOG_ERROR_AND_RETURN_RC_; \ + } while (0) // Same as RETURN_IF_ERROR, plus a call of SWSS_LOG_ERROR for the return code // error message. -#define LOG_AND_RETURN_IF_ERROR(expr) \ - do { \ - ReturnCode LOG_AND_RETURN_IF_ERROR_RC_ = expr; \ - if (!LOG_AND_RETURN_IF_ERROR_RC_.ok()) { \ - SWSS_LOG_ERROR("%s", LOG_AND_RETURN_IF_ERROR_RC_.message().c_str()); \ - return LOG_AND_RETURN_IF_ERROR_RC_; \ - } \ - } while (0) +#define LOG_AND_RETURN_IF_ERROR(expr) \ + do \ + { \ + ReturnCode LOG_AND_RETURN_IF_ERROR_RC_ = expr; \ + if (!LOG_AND_RETURN_IF_ERROR_RC_.ok()) \ + { \ + SWSS_LOG_ERROR("%s", LOG_AND_RETURN_IF_ERROR_RC_.message().c_str()); \ + return LOG_AND_RETURN_IF_ERROR_RC_; \ + } \ + } while (0) #define RETURNCODE_MACROS_IMPL_CONCAT_INNER_(x, y) x##y -#define RETURNCODE_MACROS_IMPL_CONCAT_(x, y) \ - RETURNCODE_MACROS_IMPL_CONCAT_INNER_(x, y) +#define RETURNCODE_MACROS_IMPL_CONCAT_(x, y) RETURNCODE_MACROS_IMPL_CONCAT_INNER_(x, y) // ASSIGN_OR_RETURN evaluates an expression that returns a ReturnCodeOr. If the // result is ok, the value is saved to dest. Otherwise, the ReturnCode is @@ -68,17 +73,13 @@ using swss::StatusCode; // std::cout << "value: " << value; // return ReturnCode(); // } -#define ASSIGN_OR_RETURN(dest, expr) \ - auto RETURNCODE_MACROS_IMPL_CONCAT_(ASSIGN_OR_RETURN_RESULT_, __LINE__) = \ - expr; \ - if (!RETURNCODE_MACROS_IMPL_CONCAT_(ASSIGN_OR_RETURN_RESULT_, __LINE__) \ - .ok()) { \ - return RETURNCODE_MACROS_IMPL_CONCAT_(ASSIGN_OR_RETURN_RESULT_, __LINE__) \ - .status(); \ - } \ - dest = std::move( \ - RETURNCODE_MACROS_IMPL_CONCAT_(ASSIGN_OR_RETURN_RESULT_, __LINE__) \ - .value()) +#define ASSIGN_OR_RETURN(dest, expr) \ + auto RETURNCODE_MACROS_IMPL_CONCAT_(ASSIGN_OR_RETURN_RESULT_, __LINE__) = expr; \ + if (!RETURNCODE_MACROS_IMPL_CONCAT_(ASSIGN_OR_RETURN_RESULT_, __LINE__).ok()) \ + { \ + return RETURNCODE_MACROS_IMPL_CONCAT_(ASSIGN_OR_RETURN_RESULT_, __LINE__).status(); \ + } \ + dest = std::move(RETURNCODE_MACROS_IMPL_CONCAT_(ASSIGN_OR_RETURN_RESULT_, __LINE__).value()) // CHECK_ERROR_AND_LOG evaluates an expression that returns a sai_status_t. If // the result is not SAI_STATUS_SUCCESS, it will log an error message. @@ -87,17 +88,18 @@ using swss::StatusCode; // CHECK_ERROR_AND_LOG( // sai_router_intfs_api->set_router_interface_attribute(...), // "error message" << " stream"); -#define CHECK_ERROR_AND_LOG(expr, msg_stream) \ - do { \ - sai_status_t CHECK_ERROR_AND_LOG_SAI_ = expr; \ - if (CHECK_ERROR_AND_LOG_SAI_ != SAI_STATUS_SUCCESS) { \ - std::stringstream CHECK_ERROR_AND_LOG_SS_; \ - CHECK_ERROR_AND_LOG_SS_ << msg_stream; \ - SWSS_LOG_ERROR("%s SAI_STATUS: %s", \ - CHECK_ERROR_AND_LOG_SS_.str().c_str(), \ - sai_serialize_status(CHECK_ERROR_AND_LOG_SAI_).c_str()); \ - } \ - } while (0) +#define CHECK_ERROR_AND_LOG(expr, msg_stream) \ + do \ + { \ + sai_status_t CHECK_ERROR_AND_LOG_SAI_ = expr; \ + if (CHECK_ERROR_AND_LOG_SAI_ != SAI_STATUS_SUCCESS) \ + { \ + std::stringstream CHECK_ERROR_AND_LOG_SS_; \ + CHECK_ERROR_AND_LOG_SS_ << msg_stream; \ + SWSS_LOG_ERROR("%s SAI_STATUS: %s", CHECK_ERROR_AND_LOG_SS_.str().c_str(), \ + sai_serialize_status(CHECK_ERROR_AND_LOG_SAI_).c_str()); \ + } \ + } while (0) // CHECK_ERROR_AND_LOG_AND_RETURN evaluates an expression that returns a // sai_status_t. If the result is not SAI_STATUS_SUCCESS, it will log an error @@ -107,83 +109,78 @@ using swss::StatusCode; // CHECK_ERROR_AND_LOG_AND_RETURN( // sai_router_intfs_api->set_router_interface_attribute(...), // "error message" << " stream"); -#define CHECK_ERROR_AND_LOG_AND_RETURN(expr, msg_stream) \ - do { \ - sai_status_t CHECK_ERROR_AND_LOG_AND_RETURN_SAI_ = expr; \ - if (CHECK_ERROR_AND_LOG_AND_RETURN_SAI_ != SAI_STATUS_SUCCESS) { \ - ReturnCode CHECK_ERROR_AND_LOG_AND_RETURN_RC_ = \ - ReturnCode(CHECK_ERROR_AND_LOG_AND_RETURN_SAI_) << msg_stream; \ - SWSS_LOG_ERROR( \ - "%s SAI_STATUS: %s", \ - CHECK_ERROR_AND_LOG_AND_RETURN_RC_.message().c_str(), \ - sai_serialize_status(CHECK_ERROR_AND_LOG_AND_RETURN_SAI_).c_str()); \ - return CHECK_ERROR_AND_LOG_AND_RETURN_RC_; \ - } \ - } while (0) +#define CHECK_ERROR_AND_LOG_AND_RETURN(expr, msg_stream) \ + do \ + { \ + sai_status_t CHECK_ERROR_AND_LOG_AND_RETURN_SAI_ = expr; \ + if (CHECK_ERROR_AND_LOG_AND_RETURN_SAI_ != SAI_STATUS_SUCCESS) \ + { \ + ReturnCode CHECK_ERROR_AND_LOG_AND_RETURN_RC_ = ReturnCode(CHECK_ERROR_AND_LOG_AND_RETURN_SAI_) \ + << msg_stream; \ + SWSS_LOG_ERROR("%s SAI_STATUS: %s", CHECK_ERROR_AND_LOG_AND_RETURN_RC_.message().c_str(), \ + sai_serialize_status(CHECK_ERROR_AND_LOG_AND_RETURN_SAI_).c_str()); \ + return CHECK_ERROR_AND_LOG_AND_RETURN_RC_; \ + } \ + } while (0) // This macro raises critical state to indicate that something is seriously // wrong in the system. Currently, this macro just logs an error message. // TODO: Implement this macro. -#define SWSS_RAISE_CRITICAL_STATE(err_str) \ - do { \ - std::string err_msge = err_str; \ - SWSS_LOG_ERROR("Orchagent is in critical state: %s", err_msge.c_str()); \ - } while (0) +#define SWSS_RAISE_CRITICAL_STATE(err_str) \ + do \ + { \ + std::string err_msge = err_str; \ + SWSS_LOG_ERROR("Orchagent is in critical state: %s", err_msge.c_str()); \ + } while (0) // RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL returns an error status of // SWSS_RC_INTERNAL. It also logs the error message and reports critical state. -#define RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL(msg_stream) \ - do { \ - ReturnCode RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL_RC_ = \ - ReturnCode(StatusCode::SWSS_RC_INTERNAL) << msg_stream; \ - SWSS_LOG_ERROR( \ - "%s", RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL_RC_.message().c_str()); \ - SWSS_RAISE_CRITICAL_STATE( \ - RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL_RC_.message()); \ - return RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL_RC_; \ - } while (0) - -#define SAI_RANGED_STATUS_IS_INVALID_ATTRIBUTE(x) \ - ((SAI_STATUS_CODE(x) & ~(0xFFFFL)) == \ - SAI_STATUS_CODE(SAI_STATUS_INVALID_ATTRIBUTE_0)) - -#define SAI_RANGED_STATUS_IS_INVALID_ATTR_VALUE(x) \ - ((SAI_STATUS_CODE(x) & ~(0xFFFFL)) == \ - SAI_STATUS_CODE(SAI_STATUS_INVALID_ATTR_VALUE_0)) - -#define SAI_RANGED_STATUS_IS_ATTR_NOT_IMPLEMENTED(x) \ - ((SAI_STATUS_CODE(x) & ~(0xFFFFL)) == \ - SAI_STATUS_CODE(SAI_STATUS_ATTR_NOT_IMPLEMENTED_0)) - -#define SAI_RANGED_STATUS_IS_UNKNOWN_ATTRIBUTE(x) \ - ((SAI_STATUS_CODE(x) & ~(0xFFFFL)) == \ - SAI_STATUS_CODE(SAI_STATUS_UNKNOWN_ATTRIBUTE_0)) - -#define SAI_RANGED_STATUS_IS_ATTR_NOT_SUPPORTED(x) \ - ((SAI_STATUS_CODE(x) & ~(0xFFFFL)) == \ - SAI_STATUS_CODE(SAI_STATUS_ATTR_NOT_SUPPORTED_0)) - -class ReturnCode { - public: - ReturnCode() - : status_(StatusCode::SWSS_RC_SUCCESS), - stream_(std::ios_base::out | std::ios_base::ate), - is_sai_(false) {} - - ReturnCode(const StatusCode& status, const std::string& message = "") - : status_(status), - stream_(std::ios_base::out | std::ios_base::ate), - is_sai_(false) { - stream_ << message; - } - - ReturnCode(const sai_status_t& status, const std::string& message = "") - : stream_(std::ios_base::out | std::ios_base::ate), is_sai_(true) { - // Non-ranged SAI codes that are not included in this lookup map will map to - // SWSS_RC_UNKNOWN. This includes the general SAI failure: - // SAI_STATUS_FAILURE. - static const auto* const saiStatusCodeLookup = - new std::unordered_map({ +#define RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL(msg_stream) \ + do \ + { \ + ReturnCode RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL_RC_ = ReturnCode(StatusCode::SWSS_RC_INTERNAL) \ + << msg_stream; \ + SWSS_LOG_ERROR("%s", RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL_RC_.message().c_str()); \ + SWSS_RAISE_CRITICAL_STATE(RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL_RC_.message()); \ + return RETURN_INTERNAL_ERROR_AND_RAISE_CRITICAL_RC_; \ + } while (0) + +#define SAI_RANGED_STATUS_IS_INVALID_ATTRIBUTE(x) \ + ((SAI_STATUS_CODE(x) & ~(0xFFFFL)) == SAI_STATUS_CODE(SAI_STATUS_INVALID_ATTRIBUTE_0)) + +#define SAI_RANGED_STATUS_IS_INVALID_ATTR_VALUE(x) \ + ((SAI_STATUS_CODE(x) & ~(0xFFFFL)) == SAI_STATUS_CODE(SAI_STATUS_INVALID_ATTR_VALUE_0)) + +#define SAI_RANGED_STATUS_IS_ATTR_NOT_IMPLEMENTED(x) \ + ((SAI_STATUS_CODE(x) & ~(0xFFFFL)) == SAI_STATUS_CODE(SAI_STATUS_ATTR_NOT_IMPLEMENTED_0)) + +#define SAI_RANGED_STATUS_IS_UNKNOWN_ATTRIBUTE(x) \ + ((SAI_STATUS_CODE(x) & ~(0xFFFFL)) == SAI_STATUS_CODE(SAI_STATUS_UNKNOWN_ATTRIBUTE_0)) + +#define SAI_RANGED_STATUS_IS_ATTR_NOT_SUPPORTED(x) \ + ((SAI_STATUS_CODE(x) & ~(0xFFFFL)) == SAI_STATUS_CODE(SAI_STATUS_ATTR_NOT_SUPPORTED_0)) + +class ReturnCode +{ + public: + ReturnCode() + : status_(StatusCode::SWSS_RC_SUCCESS), stream_(std::ios_base::out | std::ios_base::ate), is_sai_(false) + { + } + + ReturnCode(const StatusCode &status, const std::string &message = "") + : status_(status), stream_(std::ios_base::out | std::ios_base::ate), is_sai_(false) + { + stream_ << message; + } + + ReturnCode(const sai_status_t &status, const std::string &message = "") + : stream_(std::ios_base::out | std::ios_base::ate), is_sai_(true) + { + // Non-ranged SAI codes that are not included in this lookup map will map to + // SWSS_RC_UNKNOWN. This includes the general SAI failure: + // SAI_STATUS_FAILURE. + static const auto *const saiStatusCodeLookup = new std::unordered_map({ {SAI_STATUS_SUCCESS, StatusCode::SWSS_RC_SUCCESS}, {SAI_STATUS_NOT_SUPPORTED, StatusCode::SWSS_RC_UNIMPLEMENTED}, {SAI_STATUS_NO_MEMORY, StatusCode::SWSS_RC_NO_MEMORY}, @@ -197,148 +194,221 @@ class ReturnCode { {SAI_STATUS_NOT_EXECUTED, StatusCode::SWSS_RC_NOT_EXECUTED}, }); - if (saiStatusCodeLookup->find(status) == saiStatusCodeLookup->end()) { - // Check for ranged SAI codes. - if (SAI_RANGED_STATUS_IS_INVALID_ATTRIBUTE(status)) { - status_ = StatusCode::SWSS_RC_INVALID_PARAM; - } else if (SAI_RANGED_STATUS_IS_INVALID_ATTR_VALUE(status)) { - status_ = StatusCode::SWSS_RC_INVALID_PARAM; - } else if (SAI_RANGED_STATUS_IS_ATTR_NOT_IMPLEMENTED(status)) { - status_ = StatusCode::SWSS_RC_UNIMPLEMENTED; - } else if (SAI_RANGED_STATUS_IS_UNKNOWN_ATTRIBUTE(status)) { - status_ = StatusCode::SWSS_RC_INVALID_PARAM; - } else if (SAI_RANGED_STATUS_IS_ATTR_NOT_SUPPORTED(status)) { - status_ = StatusCode::SWSS_RC_UNIMPLEMENTED; - } else { - status_ = StatusCode::SWSS_RC_UNKNOWN; - } - } else { - status_ = saiStatusCodeLookup->at(status); - } - stream_ << message; - } - - ReturnCode(const ReturnCode& return_code) - : stream_(std::ios_base::out | std::ios_base::ate) { - status_ = return_code.status_; - stream_ << return_code.stream_.str(); - is_sai_ = return_code.is_sai_; - } - - ReturnCode& operator=(const ReturnCode& return_code) { - status_ = return_code.status_; - stream_.str(return_code.stream_.str()); - is_sai_ = return_code.is_sai_; - return *this; - } - - ~ReturnCode() = default; - - bool ok() const { return status_ == StatusCode::SWSS_RC_SUCCESS; } - - StatusCode code() const { return status_; } - - std::string codeStr() const { return swss::statusCodeToStr(status_); } - - std::string message() const { - if (stream_.str().empty()) { - return codeStr(); - } - return stream_.str(); - } - - ReturnCode& prepend(const std::string& msg) { - const std::string& tmp = stream_.str(); - stream_.str(msg + tmp); - return *this; - } - - std::string toString() const { return codeStr() + ":" + message(); } - - // Whether the ReturnCode is generated from a SAI status code or not. - bool isSai() const { return is_sai_; } - - template - ReturnCode& operator<<(T val) { - stream_ << val; - return *this; - } - - bool operator==(const ReturnCode& x) const { - return status_ == x.status_ && message() == x.message(); - } - - bool operator!=(const ReturnCode& x) const { - return status_ != x.status_ || message() != x.message(); - } - - bool operator==(const StatusCode& x) const { return status_ == x; } - - bool operator!=(const StatusCode& x) const { return status_ != x; } - - private: - StatusCode status_; - std::stringstream stream_; - // Whether the ReturnCode is generated from a SAI status code or not. - bool is_sai_; + if (saiStatusCodeLookup->find(status) == saiStatusCodeLookup->end()) + { + // Check for ranged SAI codes. + if (SAI_RANGED_STATUS_IS_INVALID_ATTRIBUTE(status)) + { + status_ = StatusCode::SWSS_RC_INVALID_PARAM; + } + else if (SAI_RANGED_STATUS_IS_INVALID_ATTR_VALUE(status)) + { + status_ = StatusCode::SWSS_RC_INVALID_PARAM; + } + else if (SAI_RANGED_STATUS_IS_ATTR_NOT_IMPLEMENTED(status)) + { + status_ = StatusCode::SWSS_RC_UNIMPLEMENTED; + } + else if (SAI_RANGED_STATUS_IS_UNKNOWN_ATTRIBUTE(status)) + { + status_ = StatusCode::SWSS_RC_INVALID_PARAM; + } + else if (SAI_RANGED_STATUS_IS_ATTR_NOT_SUPPORTED(status)) + { + status_ = StatusCode::SWSS_RC_UNIMPLEMENTED; + } + else + { + status_ = StatusCode::SWSS_RC_UNKNOWN; + } + } + else + { + status_ = saiStatusCodeLookup->at(status); + } + stream_ << message; + } + + ReturnCode(const ReturnCode &return_code) : stream_(std::ios_base::out | std::ios_base::ate) + { + status_ = return_code.status_; + stream_ << return_code.stream_.str(); + is_sai_ = return_code.is_sai_; + } + + ReturnCode &operator=(const ReturnCode &return_code) + { + status_ = return_code.status_; + stream_.str(return_code.stream_.str()); + is_sai_ = return_code.is_sai_; + return *this; + } + + ~ReturnCode() = default; + + bool ok() const + { + return status_ == StatusCode::SWSS_RC_SUCCESS; + } + + StatusCode code() const + { + return status_; + } + + std::string codeStr() const + { + return swss::statusCodeToStr(status_); + } + + std::string message() const + { + if (stream_.str().empty()) + { + return codeStr(); + } + return stream_.str(); + } + + ReturnCode &prepend(const std::string &msg) + { + const std::string &tmp = stream_.str(); + stream_.str(msg + tmp); + return *this; + } + + std::string toString() const + { + return codeStr() + ":" + message(); + } + + // Whether the ReturnCode is generated from a SAI status code or not. + bool isSai() const + { + return is_sai_; + } + + template ReturnCode &operator<<(T val) + { + stream_ << val; + return *this; + } + + bool operator==(const ReturnCode &x) const + { + return status_ == x.status_ && message() == x.message(); + } + + bool operator!=(const ReturnCode &x) const + { + return status_ != x.status_ || message() != x.message(); + } + + bool operator==(const StatusCode &x) const + { + return status_ == x; + } + + bool operator!=(const StatusCode &x) const + { + return status_ != x; + } + + private: + StatusCode status_; + std::stringstream stream_; + // Whether the ReturnCode is generated from a SAI status code or not. + bool is_sai_; }; -inline bool operator==(const StatusCode& lhs, const ReturnCode& rhs) { - return lhs == rhs.code(); +inline bool operator==(const StatusCode &lhs, const ReturnCode &rhs) +{ + return lhs == rhs.code(); } -inline bool operator!=(const StatusCode& lhs, const ReturnCode& rhs) { - return lhs != rhs.code(); +inline bool operator!=(const StatusCode &lhs, const ReturnCode &rhs) +{ + return lhs != rhs.code(); } -template -class ReturnCodeOr { - public: - using value_type = T; - - // Value Constructors. - ReturnCodeOr(const T& value) - : return_code_(ReturnCode()), value_(std::unique_ptr(new T(value))) {} - ReturnCodeOr(T&& value) - : return_code_(ReturnCode()), - value_(std::unique_ptr(new T(std::move(value)))) {} - - // ReturnCode constructors. - ReturnCodeOr(const ReturnCode& return_code) : return_code_(return_code) { - assert(!return_code.ok()); - } - - // ReturnCode accessors. - bool ok() const { return return_code_.ok(); } - const ReturnCode& status() const { return return_code_; } - - // Value accessors. - const T& value() const& { - assert(return_code_.ok()); - return *value_; - } - T& value() & { - assert(return_code_.ok()); - return *value_; - } - const T&& value() const&& { - assert(return_code_.ok()); - return std::move(*value_); - } - T&& value() && { - assert(return_code_.ok()); - return std::move(*value_); - } - - const T& operator*() const& { return value(); } - T& operator*() & { return value(); } - const T&& operator*() const&& { return value(); } - T&& operator*() && { return value(); } - - const T* operator->() const { return value_.get(); } - T* operator->() { return value_.get(); } - - private: - ReturnCode return_code_; - std::unique_ptr value_; +template class ReturnCodeOr +{ + public: + using value_type = T; + + // Value Constructors. + ReturnCodeOr(const T &value) : return_code_(ReturnCode()), value_(std::unique_ptr(new T(value))) + { + } + ReturnCodeOr(T &&value) : return_code_(ReturnCode()), value_(std::unique_ptr(new T(std::move(value)))) + { + } + + // ReturnCode constructors. + ReturnCodeOr(const ReturnCode &return_code) : return_code_(return_code) + { + assert(!return_code.ok()); + } + + // ReturnCode accessors. + bool ok() const + { + return return_code_.ok(); + } + const ReturnCode &status() const + { + return return_code_; + } + + // Value accessors. + const T &value() const & + { + assert(return_code_.ok()); + return *value_; + } + T &value() & + { + assert(return_code_.ok()); + return *value_; + } + const T &&value() const && + { + assert(return_code_.ok()); + return std::move(*value_); + } + T &&value() && + { + assert(return_code_.ok()); + return std::move(*value_); + } + + const T &operator*() const & + { + return value(); + } + T &operator*() & + { + return value(); + } + const T &&operator*() const && + { + return value(); + } + T &&operator*() && + { + return value(); + } + + const T *operator->() const + { + return value_.get(); + } + T *operator->() + { + return value_.get(); + } + + private: + ReturnCode return_code_; + std::unique_ptr value_; };