From d8bbe321816afbf13f5bb3a291a552ff322b0c12 Mon Sep 17 00:00:00 2001 From: rpmarvell Date: Thu, 20 Apr 2023 01:33:52 -0700 Subject: [PATCH] sonic-sairedis : Wred stats feature changes on Sai-redis and Syncd * Stats capability query API support is added Signed-off-by: rpmarvell --- lib/ClientSai.cpp | 154 ++++++++++++++++++++++++++++-- lib/ClientSai.h | 3 + lib/ClientServerSai.cpp | 5 +- lib/Recorder.cpp | 84 +++++++++++++++++ lib/Recorder.h | 18 ++++ lib/RedisRemoteSaiInterface.cpp | 156 +++++++++++++++++++++++++++++-- lib/RedisRemoteSaiInterface.h | 3 + lib/Sai.cpp | 8 +- lib/ServerSai.cpp | 93 +++++++++++++++++- lib/ServerSai.h | 3 + lib/sai_redis_interfacequery.cpp | 5 +- lib/sairediscommon.h | 3 + meta/DummySaiInterface.cpp | 2 +- meta/Meta.cpp | 69 +++++++------- meta/Meta.h | 4 - syncd/FlexCounter.cpp | 48 ++++++++++ syncd/Syncd.cpp | 88 +++++++++++++++++ syncd/Syncd.h | 3 + 18 files changed, 685 insertions(+), 64 deletions(-) diff --git a/lib/ClientSai.cpp b/lib/ClientSai.cpp index c4b9397cd..bd46c9c8b 100644 --- a/lib/ClientSai.cpp +++ b/lib/ClientSai.cpp @@ -886,16 +886,6 @@ sai_status_t ClientSai::getStats( return waitForGetStatsResponse(number_of_counters, counters); } -sai_status_t ClientSai::queryStatsCapability( - _In_ sai_object_id_t switchId, - _In_ sai_object_type_t objectType, - _Inout_ sai_stat_capability_list_t *stats_capability) -{ - SWSS_LOG_ENTER(); - - return SAI_STATUS_NOT_IMPLEMENTED; -} - sai_status_t ClientSai::waitForGetStatsResponse( _In_ uint32_t number_of_counters, _Out_ uint64_t *counters) @@ -924,6 +914,150 @@ sai_status_t ClientSai::waitForGetStatsResponse( return status; } +sai_status_t ClientSai::queryStatsCapability( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t objectType, + _Inout_ sai_stat_capability_list_t *stats_capability) +{ + MUTEX(); + SWSS_LOG_ENTER(); + REDIS_CHECK_API_INITIALIZED(); + + if (stats_capability && stats_capability->list) + { + // clear input list, since we use serialize to transfer values + for (uint32_t idx = 0; idx < stats_capability->count; idx++) + { + stats_capability->list[idx].stat_enum = 0; + stats_capability->list[idx].stat_modes = 0; + } + } + + auto switchIdStr = sai_serialize_object_id(switchId); + auto objectTypeStr = sai_serialize_object_type(objectType); + const std::string list_size = std::to_string(stats_capability->count); + + const std::vector entry = + { + swss::FieldValueTuple("OBJECT_TYPE", objectTypeStr), + swss::FieldValueTuple("LIST_SIZE", list_size) + }; + + SWSS_LOG_NOTICE( /* DEBUG */ + "Query arguments: switch %s, object type: %s, count: %s", + switchIdStr.c_str(), + objectTypeStr.c_str(), + list_size.c_str() + ); + + // This query will not put any data into the ASIC view, just into the + // message queue + + m_communicationChannel->set(switchIdStr, entry, REDIS_ASIC_STATE_COMMAND_STATS_CAPABILITY_QUERY); + + auto status = waitForQueryStatsCapabilityResponse(stats_capability); + + return status; +} + +sai_status_t ClientSai::waitForQueryStatsCapabilityResponse( + _Inout_ sai_stat_capability_list_t* stats_capability) +{ + SWSS_LOG_ENTER(); + + swss::KeyOpFieldsValuesTuple kco; + + auto status = m_communicationChannel->wait(REDIS_ASIC_STATE_COMMAND_STATS_CAPABILITY_RESPONSE, kco); + + if (status == SAI_STATUS_SUCCESS) + { + const std::vector &values = kfvFieldsValues(kco); + + if (values.size() != 3) + { + SWSS_LOG_ERROR("Invalid response from syncd: expected 3 value, received %zu", values.size()); + + return SAI_STATUS_FAILURE; + } + + const std::string &stat_enum_str = fvValue(values[0]); + const std::string &stat_modes_str = fvValue(values[1]); + const uint32_t num_capabilities = std::stoi(fvValue(values[2])); + + /*DEBUG*/ + SWSS_LOG_NOTICE("Received payload: stat_enums = '%s', stat_modes = '%s', count = %d", + stat_enum_str.c_str(), stat_modes_str.c_str(), num_capabilities); + + stats_capability->count = num_capabilities; + + size_t stat_enum_position = 0; + size_t stat_modes_position = 0; + for (uint32_t i = 0; i < num_capabilities; i++) + { + /* Populate stat_enum */ + size_t old_stat_enum_position = stat_enum_position; + stat_enum_position = stat_enum_str.find(",", old_stat_enum_position); + std::string stat_enum = stat_enum_str.substr(old_stat_enum_position, + stat_enum_position - old_stat_enum_position); + stats_capability->list[i].stat_enum = std::stoi(stat_enum); + + // We have run out of values to add to our list + if (stat_enum_position == std::string::npos) + { + if (num_capabilities != i + 1) + { + SWSS_LOG_WARN("Query returned less stat_enums than expected: expected %d, received %d", + num_capabilities, i+1); + } + + break; + } + + /* Populate stat_modes */ + size_t old_stat_modes_position = stat_modes_position; + stat_modes_position = stat_modes_str.find(",", old_stat_modes_position); + std::string stat_modes = stat_modes_str.substr(old_stat_modes_position, + stat_modes_position - old_stat_modes_position); + stats_capability->list[i].stat_modes = std::stoi(stat_modes); + + // We have run out of values to add to our list + if (stat_modes_position == std::string::npos) + { + if (num_capabilities != i + 1) + { + SWSS_LOG_WARN("Query returned less stat_modes than expected: expected %d, received %d", + num_capabilities, i+1); + } + + break; + } + + // Skip the commas + stat_enum_position++; + stat_modes_position++; + } + } + else if (status == SAI_STATUS_BUFFER_OVERFLOW) + { + const std::vector &values = kfvFieldsValues(kco); + + if (values.size() != 1) + { + SWSS_LOG_ERROR("Invalid response from syncd: expected 1 value, received %zu", values.size()); + + return SAI_STATUS_FAILURE; + } + + const uint32_t num_capabilities = std::stoi(fvValue(values[0])); + + SWSS_LOG_DEBUG("Received payload: count = %u", num_capabilities); + + stats_capability->count = num_capabilities; + } + + return status; +} + sai_status_t ClientSai::getStatsExt( _In_ sai_object_type_t object_type, _In_ sai_object_id_t object_id, diff --git a/lib/ClientSai.h b/lib/ClientSai.h index 05d0f5888..4eeccd099 100644 --- a/lib/ClientSai.h +++ b/lib/ClientSai.h @@ -285,6 +285,9 @@ namespace sairedis sai_status_t waitForObjectTypeGetAvailabilityResponse( _In_ uint64_t *count); + sai_status_t waitForQueryStatsCapabilityResponse( + _Inout_ sai_stat_capability_list_t* stats_capability); + private: void handleNotification( diff --git a/lib/ClientServerSai.cpp b/lib/ClientServerSai.cpp index 60366aaef..b98299ce1 100644 --- a/lib/ClientServerSai.cpp +++ b/lib/ClientServerSai.cpp @@ -256,7 +256,10 @@ sai_status_t ClientServerSai::queryStatsCapability( SWSS_LOG_ENTER(); REDIS_CHECK_API_INITIALIZED(); - return SAI_STATUS_NOT_IMPLEMENTED; + return m_sai->queryStatsCapability( + switchId, + objectType, + stats_capability); } sai_status_t ClientServerSai::getStatsExt( diff --git a/lib/Recorder.cpp b/lib/Recorder.cpp index 6f7162343..7ff8a710c 100644 --- a/lib/Recorder.cpp +++ b/lib/Recorder.cpp @@ -370,6 +370,24 @@ void Recorder::recordObjectTypeGetAvailabilityResponse( recordLine("Q|object_type_get_availability|" + sai_serialize_status(status) + "|" + Globals::joinFieldValues(arguments)); } +void Recorder::recordQueryStatsCapability( + _In_ const std::string& key, + _In_ const std::vector& arguments) +{ + SWSS_LOG_ENTER(); + + recordLine("q|stats_capability|" + key + "|" + Globals::joinFieldValues(arguments)); +} + +void Recorder::recordQueryStatsCapabilityResponse( + _In_ sai_status_t status, + _In_ const std::vector& arguments) +{ + SWSS_LOG_ENTER(); + + recordLine("Q|stats_capability|" + sai_serialize_status(status) + "|" + Globals::joinFieldValues(arguments)); +} + void Recorder::recordNotifySyncd( _In_ const std::string& key) { @@ -1089,6 +1107,72 @@ void Recorder::recordQueryAattributeEnumValuesCapabilityResponse( recordQueryAttributeEnumValuesCapabilityResponse(status, values); } +void Recorder::recordQueryStatsCapability( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _Inout_ sai_stat_capability_list_t* stats_capability) +{ + SWSS_LOG_ENTER(); + + auto key = sai_serialize_object_type(SAI_OBJECT_TYPE_SWITCH) + ":" + sai_serialize_object_id(switchId); + + auto object_type_str = sai_serialize_object_type(object_type); + const std::string list_size = std::to_string(stats_capability->count); + const std::vector values = + { + swss::FieldValueTuple("OBJECT_TYPE", object_type_str), + swss::FieldValueTuple("LIST_SIZE", list_size) + }; + + /*DEBUG*/ + SWSS_LOG_NOTICE("Query arguments: switch %s, object_type: %s, count: %s", + key.c_str(), + object_type_str.c_str(), + list_size.c_str()); + + recordQueryStatsCapability (key, values); +} + +void Recorder::recordQueryStatsCapabilityResponse( + _In_ sai_status_t status, + _In_ sai_object_type_t objectType, + _In_ const sai_stat_capability_list_t *stats_capability) +{ + SWSS_LOG_ENTER(); +#if 0 + std::vector values; + + auto meta = sai_metadata_get_attr_metadata(objectType, attrId); + + if (meta == NULL) + { + SWSS_LOG_ERROR("Failed to find attribute metadata: object type %s, attr id %d", + sai_serialize_object_type(objectType).c_str(), + attrId); + + return; + } + + if (!meta->enummetadata) + { + SWSS_LOG_ERROR("Attribute %s is not enum/enumlist!", meta->attridname); + return; + } + + bool countOnly = (status == SAI_STATUS_BUFFER_OVERFLOW); + + if (status == SAI_STATUS_SUCCESS || status == SAI_STATUS_BUFFER_OVERFLOW) + { + auto str_attr_id = sai_serialize_attr_id(*meta); + auto str_enum_list = sai_serialize_enum_list(*enumValuesCapability, meta->enummetadata, countOnly); + + values.emplace_back(str_attr_id, str_enum_list); + } + + recordQueryAttributeEnumValuesCapabilityResponse(status, values); +#endif +} + void Recorder::recordNotifySyncd( _In_ sai_object_id_t switchId, _In_ sai_redis_notify_syncd_t redisNotifySyncd) diff --git a/lib/Recorder.h b/lib/Recorder.h index 3d55dbf12..4e5008299 100644 --- a/lib/Recorder.h +++ b/lib/Recorder.h @@ -325,6 +325,16 @@ namespace sairedis _In_ sai_attr_id_t attrId, _In_ const sai_s32_list_t* enumValuesCapability); + void recordQueryStatsCapability( + _In_ sai_object_id_t switch_id, + _In_ sai_object_type_t object_type, + _Inout_ sai_stat_capability_list_t* stats_capability); + + void recordQueryStatsCapabilityResponse( + _In_ sai_status_t status, + _In_ sai_object_type_t objectType, + _In_ const sai_stat_capability_list_t *stats_capability); + // TODO move to private void recordQueryAttributeCapability( _In_ const std::string& key, @@ -350,6 +360,14 @@ namespace sairedis _In_ sai_status_t status, _In_ const std::vector& arguments); + void recordQueryStatsCapability( + _In_ const std::string& key, + _In_ const std::vector& arguments); + + void recordQueryStatsCapabilityResponse( + _In_ sai_status_t status, + _In_ const std::vector& arguments); + public: // SAI notifications void recordNotification( diff --git a/lib/RedisRemoteSaiInterface.cpp b/lib/RedisRemoteSaiInterface.cpp index ec69c4d4f..4e46ec9c4 100644 --- a/lib/RedisRemoteSaiInterface.cpp +++ b/lib/RedisRemoteSaiInterface.cpp @@ -1136,16 +1136,6 @@ sai_status_t RedisRemoteSaiInterface::getStats( return waitForGetStatsResponse(number_of_counters, counters); } -sai_status_t RedisRemoteSaiInterface::queryStatsCapability( - _In_ sai_object_id_t switchId, - _In_ sai_object_type_t objectType, - _Inout_ sai_stat_capability_list_t *stats_capability) -{ - SWSS_LOG_ENTER(); - - return SAI_STATUS_NOT_IMPLEMENTED; -} - sai_status_t RedisRemoteSaiInterface::waitForGetStatsResponse( _In_ uint32_t number_of_counters, _Out_ uint64_t *counters) @@ -1174,6 +1164,152 @@ sai_status_t RedisRemoteSaiInterface::waitForGetStatsResponse( return status; } +sai_status_t RedisRemoteSaiInterface::queryStatsCapability( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t objectType, + _Inout_ sai_stat_capability_list_t *stats_capability) +{ + SWSS_LOG_ENTER(); + + if (stats_capability && stats_capability->list) + { + // clear input list, since we use serialize to transfer values + for (uint32_t idx = 0; idx < stats_capability->count; idx++) + { + stats_capability->list[idx].stat_enum = 0; + stats_capability->list[idx].stat_modes = 0; + } + } + + auto switchIdStr = sai_serialize_object_id(switchId); + auto objectTypeStr = sai_serialize_object_type(objectType); + const std::string list_size = std::to_string(stats_capability->count); + + const std::vector entry = + { + swss::FieldValueTuple("OBJECT_TYPE", objectTypeStr), + swss::FieldValueTuple("LIST_SIZE", list_size) + }; + + SWSS_LOG_NOTICE( /* DEBUG */ + "Query arguments: switch %s, object type: %s, count: %s", + switchIdStr.c_str(), + objectTypeStr.c_str(), + list_size.c_str() + ); + + // This query will not put any data into the ASIC view, just into the + // message queue + + m_recorder->recordQueryStatsCapability(switchId, objectType, stats_capability); + + m_communicationChannel->set(switchIdStr, entry, REDIS_ASIC_STATE_COMMAND_STATS_CAPABILITY_QUERY); + + auto status = waitForQueryStatsCapabilityResponse(stats_capability); + + m_recorder->recordQueryStatsCapabilityResponse(status, objectType, stats_capability); + + return status; +} + +sai_status_t RedisRemoteSaiInterface::waitForQueryStatsCapabilityResponse( + _Inout_ sai_stat_capability_list_t* stats_capability) +{ + SWSS_LOG_ENTER(); + + swss::KeyOpFieldsValuesTuple kco; + + auto status = m_communicationChannel->wait(REDIS_ASIC_STATE_COMMAND_STATS_CAPABILITY_RESPONSE, kco); + + if (status == SAI_STATUS_SUCCESS) + { + const std::vector &values = kfvFieldsValues(kco); + + if (values.size() != 3) + { + SWSS_LOG_ERROR("Invalid response from syncd: expected 3 value, received %zu", values.size()); + + return SAI_STATUS_FAILURE; + } + + const std::string &stat_enum_str = fvValue(values[0]); + const std::string &stat_modes_str = fvValue(values[1]); + const uint32_t num_capabilities = std::stoi(fvValue(values[2])); + + /*DEBUG*/ + SWSS_LOG_NOTICE("Received payload: stat_enums = '%s', stat_modes = '%s', count = %d", + stat_enum_str.c_str(), stat_modes_str.c_str(), num_capabilities); + + stats_capability->count = num_capabilities; + + size_t stat_enum_position = 0; + size_t stat_modes_position = 0; + for (uint32_t i = 0; i < num_capabilities; i++) + { + /* Populate stat_enum */ + size_t old_stat_enum_position = stat_enum_position; + stat_enum_position = stat_enum_str.find(",", old_stat_enum_position); + std::string stat_enum = stat_enum_str.substr(old_stat_enum_position, + stat_enum_position - old_stat_enum_position); + stats_capability->list[i].stat_enum = std::stoi(stat_enum); + + // We have run out of values to add to our list + if (stat_enum_position == std::string::npos) + { + if (num_capabilities != i + 1) + { + SWSS_LOG_WARN("Query returned less stat_enums than expected: expected %d, received %d", + num_capabilities, i+1); + } + + break; + } + + /* Populate stat_modes */ + size_t old_stat_modes_position = stat_modes_position; + stat_modes_position = stat_modes_str.find(",", old_stat_modes_position); + std::string stat_modes = stat_modes_str.substr(old_stat_modes_position, + stat_modes_position - old_stat_modes_position); + stats_capability->list[i].stat_modes = std::stoi(stat_modes); + + // We have run out of values to add to our list + if (stat_modes_position == std::string::npos) + { + if (num_capabilities != i + 1) + { + SWSS_LOG_WARN("Query returned less stat_modes than expected: expected %d, received %d", + num_capabilities, i+1); + } + + break; + } + + // Skip the commas + stat_enum_position++; + stat_modes_position++; + } + } + else if (status == SAI_STATUS_BUFFER_OVERFLOW) + { + const std::vector &values = kfvFieldsValues(kco); + + if (values.size() != 1) + { + SWSS_LOG_ERROR("Invalid response from syncd: expected 1 value, received %zu", values.size()); + + return SAI_STATUS_FAILURE; + } + + const uint32_t num_capabilities = std::stoi(fvValue(values[0])); + + SWSS_LOG_DEBUG("Received payload: count = %u", num_capabilities); + + stats_capability->count = num_capabilities; + } + + return status; +} + sai_status_t RedisRemoteSaiInterface::getStatsExt( _In_ sai_object_type_t object_type, _In_ sai_object_id_t object_id, diff --git a/lib/RedisRemoteSaiInterface.h b/lib/RedisRemoteSaiInterface.h index 8d5b01c1f..54ed30333 100644 --- a/lib/RedisRemoteSaiInterface.h +++ b/lib/RedisRemoteSaiInterface.h @@ -325,6 +325,9 @@ namespace sairedis sai_status_t waitForObjectTypeGetAvailabilityResponse( _In_ uint64_t *count); + sai_status_t waitForQueryStatsCapabilityResponse( + _Inout_ sai_stat_capability_list_t* stats_capability); + private: // notify syncd response sai_status_t waitForNotifySyncdResponse(); diff --git a/lib/Sai.cpp b/lib/Sai.cpp index 15725dc24..4110dd3b5 100644 --- a/lib/Sai.cpp +++ b/lib/Sai.cpp @@ -356,9 +356,15 @@ sai_status_t Sai::queryStatsCapability( _In_ sai_object_type_t objectType, _Inout_ sai_stat_capability_list_t *stats_capability) { + MUTEX(); SWSS_LOG_ENTER(); + REDIS_CHECK_API_INITIALIZED(); + REDIS_CHECK_CONTEXT(switchId); - return SAI_STATUS_NOT_IMPLEMENTED; + return context->m_meta->queryStatsCapability( + switchId, + objectType, + stats_capability); } sai_status_t Sai::getStatsExt( diff --git a/lib/ServerSai.cpp b/lib/ServerSai.cpp index fc434c138..dd20964ac 100644 --- a/lib/ServerSai.cpp +++ b/lib/ServerSai.cpp @@ -274,9 +274,14 @@ sai_status_t ServerSai::queryStatsCapability( _In_ sai_object_type_t objectType, _Inout_ sai_stat_capability_list_t *stats_capability) { + MUTEX(); SWSS_LOG_ENTER(); + REDIS_CHECK_API_INITIALIZED(); - return SAI_STATUS_NOT_IMPLEMENTED; + return m_sai->queryStatsCapability( + switchId, + objectType, + stats_capability); } sai_status_t ServerSai::getStatsExt( @@ -729,6 +734,9 @@ sai_status_t ServerSai::processSingleEvent( if (op == REDIS_ASIC_STATE_COMMAND_OBJECT_TYPE_GET_AVAILABILITY_QUERY) return processObjectTypeGetAvailabilityQuery(kco); + if (op == REDIS_ASIC_STATE_COMMAND_STATS_CAPABILITY_QUERY) + return processStatsCapabilityQuery(kco); + SWSS_LOG_THROW("event op '%s' is not implemented, FIXME", op.c_str()); } @@ -1781,6 +1789,89 @@ sai_status_t ServerSai::processObjectTypeGetAvailabilityQuery( return status; } +sai_status_t ServerSai::processStatsCapabilityQuery( + _In_ const swss::KeyOpFieldsValuesTuple &kco) +{ + SWSS_LOG_ENTER(); + + auto& strSwitchOid = kfvKey(kco); + + sai_object_id_t switchOid; + sai_deserialize_object_id(strSwitchOid, switchOid); + + auto& values = kfvFieldsValues(kco); + + if (values.size() != 2) + { + SWSS_LOG_ERROR("Invalid input: expected 2 arguments, received %zu", values.size()); + + m_selectableChannel->set(sai_serialize_status(SAI_STATUS_INVALID_PARAMETER), {}, REDIS_ASIC_STATE_COMMAND_STATS_CAPABILITY_RESPONSE); + + return SAI_STATUS_INVALID_PARAMETER; + } + + sai_object_type_t objectType; + sai_deserialize_object_type(fvValue(values[0]), objectType); + + uint32_t list_size = std::stoi(fvValue(values[1])); + + std::vector stat_capability_list(list_size); + + sai_stat_capability_list_t statCapList; + + statCapList.count = list_size; + statCapList.list = stat_capability_list.data(); + + sai_status_t status = m_sai->queryStatsCapability(switchOid, objectType, &statCapList); + + std::vector entry; + + if (status == SAI_STATUS_SUCCESS) + { + std::vector vec_stat_enum; + std::vector vec_stat_modes; + + for (uint32_t it = 0; it < statCapList.count; it++) + { + vec_stat_enum.push_back(std::to_string(statCapList.list[it].stat_enum)); + vec_stat_modes.push_back(std::to_string(statCapList.list[it].stat_modes)); + } + + std::ostringstream join_stat_enum; + std::copy(vec_stat_enum.begin(), vec_stat_enum.end(), std::ostream_iterator(join_stat_enum, ",")); + auto strCapEnum = join_stat_enum.str(); + + std::ostringstream join_stat_modes; + std::copy(vec_stat_modes.begin(), vec_stat_modes.end(), std::ostream_iterator(join_stat_modes, ",")); + auto strCapModes = join_stat_modes.str(); + + entry = + { + swss::FieldValueTuple("STAT_ENUM", strCapEnum), + swss::FieldValueTuple("STAT_MODES", strCapModes), + swss::FieldValueTuple("STAT_COUNT", std::to_string(statCapList.count)) + }; + + /*DEBUG*/ + SWSS_LOG_NOTICE("Sending response: stat_enums = '%s', stat_modes = '%s', count = %d", + strCapEnum.c_str(), strCapModes.c_str(), statCapList.count); + } + else if (status == SAI_STATUS_BUFFER_OVERFLOW) + { + entry = + { + swss::FieldValueTuple("STAT_COUNT", std::to_string(statCapList.count)) + }; + + /*DEBUG*/ + SWSS_LOG_NOTICE("Sending response: count = %u", statCapList.count); + } + + m_selectableChannel->set(sai_serialize_status(status), entry, REDIS_ASIC_STATE_COMMAND_STATS_CAPABILITY_RESPONSE); + + return status; +} + sai_status_t ServerSai::processFdbFlush( _In_ const swss::KeyOpFieldsValuesTuple &kco) { diff --git a/lib/ServerSai.h b/lib/ServerSai.h index b67c4ed1c..a0193a890 100644 --- a/lib/ServerSai.h +++ b/lib/ServerSai.h @@ -282,6 +282,9 @@ namespace sairedis sai_status_t processObjectTypeGetAvailabilityQuery( _In_ const swss::KeyOpFieldsValuesTuple &kco); + sai_status_t processStatsCapabilityQuery( + _In_ const swss::KeyOpFieldsValuesTuple &kco); + private: bool m_apiInitialized; diff --git a/lib/sai_redis_interfacequery.cpp b/lib/sai_redis_interfacequery.cpp index 46890ae74..7548067b3 100644 --- a/lib/sai_redis_interfacequery.cpp +++ b/lib/sai_redis_interfacequery.cpp @@ -239,7 +239,10 @@ sai_status_t sai_query_stats_capability( { SWSS_LOG_ENTER(); - return SAI_STATUS_NOT_IMPLEMENTED; + return redis_sai->queryStatsCapability( + switch_id, + object_type, + stats_capability); } sai_status_t sai_query_api_version( diff --git a/lib/sairediscommon.h b/lib/sairediscommon.h index 7a6a997d9..e712737a9 100644 --- a/lib/sairediscommon.h +++ b/lib/sairediscommon.h @@ -52,6 +52,9 @@ #define REDIS_ASIC_STATE_COMMAND_OBJECT_TYPE_GET_AVAILABILITY_QUERY "object_type_get_availability_query" #define REDIS_ASIC_STATE_COMMAND_OBJECT_TYPE_GET_AVAILABILITY_RESPONSE "object_type_get_availability_response" +#define REDIS_ASIC_STATE_COMMAND_STATS_CAPABILITY_QUERY "stats_capability_query" +#define REDIS_ASIC_STATE_COMMAND_STATS_CAPABILITY_RESPONSE "stats_capability_response" + /** * @brief Redis virtual object id counter key name. * diff --git a/meta/DummySaiInterface.cpp b/meta/DummySaiInterface.cpp index d09d8d233..de2260f96 100644 --- a/meta/DummySaiInterface.cpp +++ b/meta/DummySaiInterface.cpp @@ -186,7 +186,7 @@ sai_status_t DummySaiInterface::queryStatsCapability( { SWSS_LOG_ENTER(); - return SAI_STATUS_NOT_IMPLEMENTED; + return m_status; } sai_status_t DummySaiInterface::getStatsExt( diff --git a/meta/Meta.cpp b/meta/Meta.cpp index 78330cc9a..04a3b4fc3 100644 --- a/meta/Meta.cpp +++ b/meta/Meta.cpp @@ -1740,37 +1740,6 @@ sai_status_t Meta::meta_validate_stats( return SAI_STATUS_SUCCESS; } -sai_status_t Meta::meta_validate_query_stats_capability( - _In_ sai_object_type_t object_type, - _In_ sai_object_id_t object_id) -{ - SWSS_LOG_ENTER(); - - PARAMETER_CHECK_OBJECT_TYPE_VALID(object_type); - PARAMETER_CHECK_OID_OBJECT_TYPE(object_id, object_type); - PARAMETER_CHECK_OID_EXISTS(object_id, object_type); - - sai_object_id_t switch_id = switchIdQuery(object_id); - - // checks also if object type is OID - sai_status_t status = meta_sai_validate_oid(object_type, &object_id, switch_id, false); - - CHECK_STATUS_SUCCESS(status); - - auto info = sai_metadata_get_object_type_info(object_type); - - PARAMETER_CHECK_IF_NOT_NULL(info); - - if (info->statenum == nullptr) - { - SWSS_LOG_ERROR("%s does not support stats", info->objecttypename); - - return SAI_STATUS_INVALID_PARAMETER; - } - - return SAI_STATUS_SUCCESS; -} - sai_status_t Meta::getStats( _In_ sai_object_type_t object_type, _In_ sai_object_id_t object_id, @@ -1798,13 +1767,43 @@ sai_status_t Meta::queryStatsCapability( { SWSS_LOG_ENTER(); - auto status = meta_validate_query_stats_capability(objectType, switchId); + PARAMETER_CHECK_OID_OBJECT_TYPE(switchId, SAI_OBJECT_TYPE_SWITCH); + PARAMETER_CHECK_OID_EXISTS(switchId, SAI_OBJECT_TYPE_SWITCH); + PARAMETER_CHECK_OBJECT_TYPE_VALID(objectType); + PARAMETER_CHECK_IF_NOT_NULL(stats_capability); - CHECK_STATUS_SUCCESS(status); + auto info = sai_metadata_get_object_type_info(objectType); - status = m_implementation->queryStatsCapability(switchId, objectType, stats_capability); + PARAMETER_CHECK_IF_NOT_NULL(info); - // no post validation required + if (info->statenum == nullptr) + { + SWSS_LOG_ERROR("%s does not support stats", info->objecttypename); + + return SAI_STATUS_INVALID_PARAMETER; + } + + auto status = m_implementation->queryStatsCapability(switchId, objectType, stats_capability); + + if (status == SAI_STATUS_SUCCESS) + { + if (stats_capability->list) + { + // check if all returned values are members of defined enum + + for (uint32_t idx = 0; idx < stats_capability->count; idx++) + { + if (sai_metadata_get_enum_value_name(info->statenum, + stats_capability->list[idx].stat_enum) == nullptr) + { + SWSS_LOG_ERROR("value %d is not in range on %s", + stats_capability->list[idx].stat_enum, info->statenum->name); + + return SAI_STATUS_INVALID_PARAMETER; + } + } + } + } return status; } diff --git a/meta/Meta.h b/meta/Meta.h index dc66946f8..e50e76cb2 100644 --- a/meta/Meta.h +++ b/meta/Meta.h @@ -427,10 +427,6 @@ namespace saimeta _Out_ uint64_t *counters, _In_ sai_stats_mode_t mode); - sai_status_t meta_validate_query_stats_capability( - _In_ sai_object_type_t object_type, - _In_ sai_object_id_t object_id); - private: // validate OID sai_status_t meta_sai_validate_oid( diff --git a/syncd/FlexCounter.cpp b/syncd/FlexCounter.cpp index 4352efded..20cff13be 100644 --- a/syncd/FlexCounter.cpp +++ b/syncd/FlexCounter.cpp @@ -30,6 +30,8 @@ static const std::string ATTR_TYPE_QUEUE = "Queue Attribute"; static const std::string ATTR_TYPE_PG = "Priority Group Attribute"; static const std::string ATTR_TYPE_MACSEC_SA = "MACSEC SA Attribute"; static const std::string ATTR_TYPE_ACL_COUNTER = "ACL Counter Attribute"; +static const std::string COUNTER_TYPE_WRED_ECN_QUEUE = "WRED Queue Counter"; +static const std::string COUNTER_TYPE_WRED_ECN_PORT = "WRED Port Counter"; BaseCounterContext::BaseCounterContext(const std::string &name): m_name(name) @@ -1139,6 +1141,10 @@ void FlexCounter::addCounterPlugin( { getCounterContext(COUNTER_TYPE_QUEUE)->addPlugins(shaStrings); } + else if (field == WRED_QUEUE_PLUGIN_FIELD) + { + getCounterContext(COUNTER_TYPE_WRED_ECN_QUEUE)->addPlugins(shaStrings); + } else if (field == PG_PLUGIN_FIELD) { getCounterContext(COUNTER_TYPE_PG)->addPlugins(shaStrings); @@ -1147,6 +1153,10 @@ void FlexCounter::addCounterPlugin( { getCounterContext(COUNTER_TYPE_PORT)->addPlugins(shaStrings); } + else if (field == WRED_PORT_PLUGIN_FIELD) + { + getCounterContext(COUNTER_TYPE_WRED_ECN_PORT)->addPlugins(shaStrings); + } else if (field == RIF_PLUGIN_FIELD) { getCounterContext(COUNTER_TYPE_RIF)->addPlugins(shaStrings); @@ -1229,6 +1239,12 @@ std::shared_ptr FlexCounter::createCounterContext( context->always_check_supported_counters = true; return context; } + else if (context_name == COUNTER_TYPE_WRED_ECN_PORT) + { + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_PORT, m_vendorSai.get(), m_statsMode); + context->always_check_supported_counters = true; + return context; + } else if (context_name == COUNTER_TYPE_PORT_DEBUG) { auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_PORT, m_vendorSai.get(), m_statsMode); @@ -1245,6 +1261,13 @@ std::shared_ptr FlexCounter::createCounterContext( context->double_confirm_supported_counters = true; return context; } + else if (context_name == COUNTER_TYPE_WRED_ECN_QUEUE) + { + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_QUEUE, m_vendorSai.get(), m_statsMode); + context->always_check_supported_counters = true; + context->double_confirm_supported_counters = true; + return context; + } else if (context_name == COUNTER_TYPE_PG) { auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, m_vendorSai.get(), m_statsMode); @@ -1494,6 +1517,10 @@ void FlexCounter::removeCounter( { getCounterContext(COUNTER_TYPE_PORT_DEBUG)->removeObject(vid); } + if (hasCounterContext(COUNTER_TYPE_WRED_ECN_PORT)) + { + getCounterContext(COUNTER_TYPE_WRED_ECN_PORT)->removeObject(vid); + } } else if (objectType == SAI_OBJECT_TYPE_QUEUE) { @@ -1501,6 +1528,10 @@ void FlexCounter::removeCounter( { getCounterContext(COUNTER_TYPE_QUEUE)->removeObject(vid); } + if (hasCounterContext(COUNTER_TYPE_WRED_ECN_QUEUE)) + { + getCounterContext(COUNTER_TYPE_WRED_ECN_QUEUE)->removeObject(vid); + } if (hasCounterContext(ATTR_TYPE_QUEUE)) { getCounterContext(ATTR_TYPE_QUEUE)->removeObject(vid); @@ -1617,6 +1648,14 @@ void FlexCounter::addCounter( idStrings, ""); } + else if (objectType == SAI_OBJECT_TYPE_PORT && field == WRED_PORT_COUNTER_ID_LIST) + { + getCounterContext(COUNTER_TYPE_PORT)->addObject( + vid, + rid, + idStrings, + ""); + } else if (objectType == SAI_OBJECT_TYPE_PORT && field == PORT_DEBUG_COUNTER_ID_LIST) { getCounterContext(COUNTER_TYPE_PORT_DEBUG)->addObject( @@ -1642,6 +1681,15 @@ void FlexCounter::addCounter( idStrings, ""); } + else if (objectType == SAI_OBJECT_TYPE_QUEUE && field == WRED_QUEUE_COUNTER_ID_LIST) + { + getCounterContext(COUNTER_TYPE_QUEUE)->addObject( + vid, + rid, + idStrings, + ""); + + } else if (objectType == SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP && field == PG_COUNTER_ID_LIST) { getCounterContext(COUNTER_TYPE_PG)->addObject( diff --git a/syncd/Syncd.cpp b/syncd/Syncd.cpp index f6ebd904f..e33bd1175 100644 --- a/syncd/Syncd.cpp +++ b/syncd/Syncd.cpp @@ -368,6 +368,9 @@ sai_status_t Syncd::processSingleEvent( if (op == REDIS_ASIC_STATE_COMMAND_OBJECT_TYPE_GET_AVAILABILITY_QUERY) return processObjectTypeGetAvailabilityQuery(kco); + if (op == REDIS_ASIC_STATE_COMMAND_STATS_CAPABILITY_QUERY) + return processStatsCapabilityQuery(kco); + SWSS_LOG_THROW("event op '%s' is not implemented, FIXME", op.c_str()); } @@ -553,6 +556,91 @@ sai_status_t Syncd::processObjectTypeGetAvailabilityQuery( return status; } +sai_status_t Syncd::processStatsCapabilityQuery( + _In_ const swss::KeyOpFieldsValuesTuple &kco) +{ + SWSS_LOG_ENTER(); + + auto& strSwitchVid = kfvKey(kco); + + sai_object_id_t switchVid; + sai_deserialize_object_id(strSwitchVid, switchVid); + + sai_object_id_t switchRid = m_translator->translateVidToRid(switchVid); + + auto& values = kfvFieldsValues(kco); + + if (values.size() != 2) + { + SWSS_LOG_ERROR("Invalid input: expected 2 arguments, received %zu", values.size()); + + m_selectableChannel->set(sai_serialize_status(SAI_STATUS_INVALID_PARAMETER), {}, REDIS_ASIC_STATE_COMMAND_STATS_CAPABILITY_RESPONSE); + + return SAI_STATUS_INVALID_PARAMETER; + } + + sai_object_type_t objectType; + sai_deserialize_object_type(fvValue(values[0]), objectType); + + uint32_t list_size = std::stoi(fvValue(values[1])); + + std::vector stat_capability_list(list_size); + + sai_stat_capability_list_t statCapList; + + statCapList.count = list_size; + statCapList.list = stat_capability_list.data(); + + sai_status_t status = m_vendorSai->queryStatsCapability(switchRid, objectType, &statCapList); + + std::vector entry; + + if (status == SAI_STATUS_SUCCESS) + { + std::vector vec_stat_enum; + std::vector vec_stat_modes; + + for (uint32_t it = 0; it < statCapList.count; it++) + { + vec_stat_enum.push_back(std::to_string(statCapList.list[it].stat_enum)); + vec_stat_modes.push_back(std::to_string(statCapList.list[it].stat_modes)); + } + + std::ostringstream join_stat_enum; + std::copy(vec_stat_enum.begin(), vec_stat_enum.end(), std::ostream_iterator(join_stat_enum, ",")); + auto strCapEnum = join_stat_enum.str(); + + std::ostringstream join_stat_modes; + std::copy(vec_stat_modes.begin(), vec_stat_modes.end(), std::ostream_iterator(join_stat_modes, ",")); + auto strCapModes = join_stat_modes.str(); + + entry = + { + swss::FieldValueTuple("STAT_ENUM", strCapEnum), + swss::FieldValueTuple("STAT_MODES", strCapModes), + swss::FieldValueTuple("STAT_COUNT", std::to_string(statCapList.count)) + }; + + /*DEBUG*/ + SWSS_LOG_NOTICE("Sending response: stat_enums = '%s', stat_modes = '%s', count = %d", + strCapEnum.c_str(), strCapModes.c_str(), statCapList.count); + } + else if (status == SAI_STATUS_BUFFER_OVERFLOW) + { + entry = + { + swss::FieldValueTuple("STAT_COUNT", std::to_string(statCapList.count)) + }; + + /*DEBUG*/ + SWSS_LOG_NOTICE("Sending response: count = %u", statCapList.count); + } + + m_selectableChannel->set(sai_serialize_status(status), entry, REDIS_ASIC_STATE_COMMAND_STATS_CAPABILITY_RESPONSE); + + return status; +} + sai_status_t Syncd::processFdbFlush( _In_ const swss::KeyOpFieldsValuesTuple &kco) { diff --git a/syncd/Syncd.h b/syncd/Syncd.h index b7622bf01..cab8476f0 100644 --- a/syncd/Syncd.h +++ b/syncd/Syncd.h @@ -134,6 +134,9 @@ namespace syncd sai_status_t processObjectTypeGetAvailabilityQuery( _In_ const swss::KeyOpFieldsValuesTuple &kco); + sai_status_t processStatsCapabilityQuery( + _In_ const swss::KeyOpFieldsValuesTuple &kco); + sai_status_t processFdbFlush( _In_ const swss::KeyOpFieldsValuesTuple &kco);