diff --git a/lib/inc/ServerSai.h b/lib/inc/ServerSai.h index 37a4550767e9..f9bd96648739 100644 --- a/lib/inc/ServerSai.h +++ b/lib/inc/ServerSai.h @@ -337,6 +337,14 @@ namespace sairedis _In_ const sai_object_id_t* object_ids, _In_ const sai_status_t* statuses); + // STATS API + + sai_status_t processGetStatsEvent( + _In_ const swss::KeyOpFieldsValuesTuple &kco); + + sai_status_t processClearStatsEvent( + _In_ const swss::KeyOpFieldsValuesTuple &kco); + // NON QUAD API sai_status_t processFdbFlush( diff --git a/lib/src/ServerSai.cpp b/lib/src/ServerSai.cpp index 5feec62eb910..ca28b275be5e 100644 --- a/lib/src/ServerSai.cpp +++ b/lib/src/ServerSai.cpp @@ -691,12 +691,11 @@ sai_status_t ServerSai::processSingleEvent( if (op == REDIS_ASIC_STATE_COMMAND_BULK_SET) return processBulkQuadEvent(SAI_COMMON_API_BULK_SET, kco); -// TODO implement -// if (op == REDIS_ASIC_STATE_COMMAND_GET_STATS) -// return processGetStatsEvent(kco); -// -// if (op == REDIS_ASIC_STATE_COMMAND_CLEAR_STATS) -// return processClearStatsEvent(kco); + if (op == REDIS_ASIC_STATE_COMMAND_GET_STATS) + return processGetStatsEvent(kco); + + if (op == REDIS_ASIC_STATE_COMMAND_CLEAR_STATS) + return processClearStatsEvent(kco); if (op == REDIS_ASIC_STATE_COMMAND_FLUSH) return processFdbFlush(kco); @@ -1737,3 +1736,100 @@ sai_status_t ServerSai::processFdbFlush( return status; } + +sai_status_t ServerSai::processClearStatsEvent( + _In_ const swss::KeyOpFieldsValuesTuple &kco) +{ + SWSS_LOG_ENTER(); + + const std::string &key = kfvKey(kco); + + sai_object_meta_key_t metaKey; + sai_deserialize_object_meta_key(key, metaKey); + + auto info = sai_metadata_get_object_type_info(metaKey.objecttype); + + if (info->isnonobjectid) + { + SWSS_LOG_THROW("non object id not supported on clear stats: %s, FIXME", key.c_str()); + } + + std::vector counter_ids; + + for (auto&v: kfvFieldsValues(kco)) + { + int32_t val; + sai_deserialize_enum(fvField(v), info->statenum, val); + + counter_ids.push_back(val); + } + + auto status = m_sai->clearStats( + metaKey.objecttype, + metaKey.objectkey.key.object_id, + (uint32_t)counter_ids.size(), + counter_ids.data()); + + m_selectableChannel->set(sai_serialize_status(status), {}, REDIS_ASIC_STATE_COMMAND_GETRESPONSE); + + return status; +} + +sai_status_t ServerSai::processGetStatsEvent( + _In_ const swss::KeyOpFieldsValuesTuple &kco) +{ + SWSS_LOG_ENTER(); + + const std::string &key = kfvKey(kco); + + sai_object_meta_key_t metaKey; + sai_deserialize_object_meta_key(key, metaKey); + + // TODO get stats on created object in init view mode could fail + + auto info = sai_metadata_get_object_type_info(metaKey.objecttype); + + if (info->isnonobjectid) + { + SWSS_LOG_THROW("non object id not supported on clear stats: %s, FIXME", key.c_str()); + } + + std::vector counter_ids; + + for (auto&v: kfvFieldsValues(kco)) + { + int32_t val; + sai_deserialize_enum(fvField(v), info->statenum, val); + + counter_ids.push_back(val); + } + + std::vector result(counter_ids.size()); + + auto status = m_sai->getStats( + metaKey.objecttype, + metaKey.objectkey.key.object_id, + (uint32_t)counter_ids.size(), + counter_ids.data(), + result.data()); + + std::vector entry; + + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to get stats"); + } + else + { + const auto& values = kfvFieldsValues(kco); + + for (size_t i = 0; i < values.size(); i++) + { + entry.emplace_back(fvField(values[i]), std::to_string(result[i])); + } + } + + m_selectableChannel->set(sai_serialize_status(status), entry, REDIS_ASIC_STATE_COMMAND_GETRESPONSE); + + return status; +} diff --git a/tests/testclient.cpp b/tests/testclient.cpp index 0ded4f57d357..960daf19f008 100644 --- a/tests/testclient.cpp +++ b/tests/testclient.cpp @@ -27,6 +27,8 @@ class TestClient void test_fdb_flush(); + void test_stats(); + private: int profileGetNextValue( @@ -457,6 +459,55 @@ void TestClient::test_fdb_flush() ASSERT_SUCCESS(sai_api_uninitialize()); } +void TestClient::test_stats() +{ + SWSS_LOG_ENTER(); + + m_profileMap.clear(); + + m_profileMap[SAI_REDIS_KEY_ENABLE_CLIENT] = "true"; // act as a client + + m_profileIter = m_profileMap.begin(); + + m_smt.profileGetValue = std::bind(&TestClient::profileGetValue, this, _1, _2); + m_smt.profileGetNextValue = std::bind(&TestClient::profileGetNextValue, this, _1, _2, _3); + + m_test_services = m_smt.getServiceMethodTable(); + + ASSERT_SUCCESS(sai_api_initialize(0, &m_test_services)); + + sai_switch_api_t* switch_api; + + ASSERT_SUCCESS(sai_api_query(SAI_API_SWITCH, (void**)&switch_api)); + + sai_attribute_t attr; + + // connect to existing switch + attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; + attr.value.booldata = false; + + sai_object_id_t switch_id = SAI_NULL_OBJECT_ID; + + ASSERT_SUCCESS(switch_api->create_switch(&switch_id, 1, &attr)); + + ASSERT_TRUE(switch_id != SAI_NULL_OBJECT_ID); + + SWSS_LOG_NOTICE("switchId: %s", sai_serialize_object_id(switch_id).c_str()); + + uint64_t counters[1]; + sai_stat_id_t counter_ids[1] = { SAI_SWITCH_STAT_ECC_DROP }; + + SWSS_LOG_NOTICE(" * get_switch_stats"); + + ASSERT_SUCCESS(switch_api->get_switch_stats(switch_id, 1, counter_ids, counters)); + + SWSS_LOG_NOTICE(" * clear_switch_stats"); + + ASSERT_SUCCESS(switch_api->clear_switch_stats(switch_id, 1, counter_ids)); + + ASSERT_SUCCESS(sai_api_uninitialize()); +} + int main() { swss::Logger::getInstance().setMinPrio(swss::Logger::SWSS_DEBUG); @@ -475,5 +526,7 @@ int main() tc.test_fdb_flush(); + tc.test_stats(); + return EXIT_SUCCESS; }