From bfd37e3e108e4af6c7a3ec7dafad14829e948732 Mon Sep 17 00:00:00 2001 From: Junchao-Mellanox <57339448+Junchao-Mellanox@users.noreply.github.com> Date: Tue, 9 Aug 2022 00:55:39 +0800 Subject: [PATCH] [sonic-sairedis] Support bulk counter (#1094) Note: the build may fail due to SAI header dependency. Vendor SAI implementation shall include this PR: https://github.com/opencomputeproject/SAI/pull/1352 HLD: https://github.com/sonic-net/SONiC/blob/master/doc/bulk_counter/bulk_counter.md **Why I did this?** PR https://github.com/opencomputeproject/SAI/pull/1352/files introduced new SAI APIs that supports bulk stats: sai_bulk_object_get_stats sai_bulk_object_clear_stats SONiC flex counter infrastructure shall utilize bulk stats API to gain better performance. This document discusses how to integrate these two new APIs to SONiC. **What I did?** 1. Support using bulk stats APIs based on object type. E.g. for a counter group that queries queue and pg stats, queue stats support bulk while pg stats does not, in that case queue stats shall use bulk API, pg stats shall use non bulk API 2. Automatically fall back to old way if bulk stats APIs are not supported **How I test this** Almost full unit test coverage Manual test --- lib/ClientSai.cpp | 39 ++ lib/ClientSai.h | 21 + lib/ClientServerSai.cpp | 50 ++ lib/ClientServerSai.h | 21 + lib/RedisRemoteSaiInterface.cpp | 35 ++ lib/RedisRemoteSaiInterface.h | 21 + lib/Sai.cpp | 31 ++ lib/Sai.h | 21 + lib/ServerSai.cpp | 50 ++ lib/ServerSai.h | 21 + lib/sai_redis_interfacequery.cpp | 31 ++ meta/DummySaiInterface.cpp | 31 ++ meta/DummySaiInterface.h | 21 + meta/Meta.cpp | 31 ++ meta/Meta.h | 21 + meta/SaiInterface.h | 21 + syncd/FlexCounter.cpp | 222 +++++++- syncd/VendorSai.cpp | 52 ++ syncd/VendorSai.h | 21 + unittest/lib/Makefile.am | 2 +- unittest/lib/TestClientServerSai.cpp | 88 ++++ unittest/lib/TestContext.cpp | 27 + .../lib/test_sai_redis_interfacequery.cpp | 25 + unittest/meta/TestMeta.cpp | 22 + unittest/syncd/MockableSaiInterface.cpp | 39 ++ unittest/syncd/MockableSaiInterface.h | 24 + unittest/syncd/TestFlexCounter.cpp | 485 ++++++++++++++++-- unittest/vslib/TestSaiUnittests.cpp | 25 + unittest/vslib/test_sai_vs_interfacequery.cpp | 25 + vslib/Sai.cpp | 35 ++ vslib/Sai.h | 21 + vslib/VirtualSwitchSaiInterface.cpp | 31 ++ vslib/VirtualSwitchSaiInterface.h | 21 + vslib/sai_vs_interfacequery.cpp | 31 ++ 34 files changed, 1610 insertions(+), 52 deletions(-) diff --git a/lib/ClientSai.cpp b/lib/ClientSai.cpp index f83d733db..f51af7f8a 100644 --- a/lib/ClientSai.cpp +++ b/lib/ClientSai.cpp @@ -983,6 +983,45 @@ sai_status_t ClientSai::waitForClearStatsResponse() return status; } +sai_status_t ClientSai::bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) +{ + MUTEX(); + SWSS_LOG_ENTER(); + REDIS_CHECK_API_INITIALIZED(); + + SWSS_LOG_ERROR("not implemented"); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + +sai_status_t ClientSai::bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) +{ + MUTEX(); + SWSS_LOG_ENTER(); + REDIS_CHECK_API_INITIALIZED(); + + SWSS_LOG_ERROR("not implemented"); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + // BULK CREATE sai_status_t ClientSai::bulkCreate( diff --git a/lib/ClientSai.h b/lib/ClientSai.h index f051a51d5..05d0f5888 100644 --- a/lib/ClientSai.h +++ b/lib/ClientSai.h @@ -116,6 +116,27 @@ namespace sairedis _In_ uint32_t number_of_counters, _In_ const sai_stat_id_t *counter_ids) override; + virtual sai_status_t bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) override; + + virtual sai_status_t bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) override; + public: // non QUAD API virtual sai_status_t flushFdbEntries( diff --git a/lib/ClientServerSai.cpp b/lib/ClientServerSai.cpp index 71598a24e..60366aaef 100644 --- a/lib/ClientServerSai.cpp +++ b/lib/ClientServerSai.cpp @@ -297,6 +297,56 @@ sai_status_t ClientServerSai::clearStats( counter_ids); } +sai_status_t ClientServerSai::bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) +{ + MUTEX(); + SWSS_LOG_ENTER(); + REDIS_CHECK_API_INITIALIZED(); + + return m_sai->bulkGetStats(switchId, + object_type, + object_count, + object_key, + number_of_counters, + counter_ids, + mode, + object_statuses, + counters); +} + +sai_status_t ClientServerSai::bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) +{ + MUTEX(); + SWSS_LOG_ENTER(); + REDIS_CHECK_API_INITIALIZED(); + + return m_sai->bulkClearStats(switchId, + object_type, + object_count, + object_key, + number_of_counters, + counter_ids, + mode, + object_statuses); +} + // BULK QUAD OID sai_status_t ClientServerSai::bulkCreate( diff --git a/lib/ClientServerSai.h b/lib/ClientServerSai.h index e8fb16583..db6c2460c 100644 --- a/lib/ClientServerSai.h +++ b/lib/ClientServerSai.h @@ -108,6 +108,27 @@ namespace sairedis _In_ uint32_t number_of_counters, _In_ const sai_stat_id_t *counter_ids) override; + virtual sai_status_t bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) override; + + virtual sai_status_t bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) override; + public: // non QUAD API virtual sai_status_t flushFdbEntries( diff --git a/lib/RedisRemoteSaiInterface.cpp b/lib/RedisRemoteSaiInterface.cpp index 5e44c36d5..47e4630f8 100644 --- a/lib/RedisRemoteSaiInterface.cpp +++ b/lib/RedisRemoteSaiInterface.cpp @@ -1211,6 +1211,41 @@ sai_status_t RedisRemoteSaiInterface::clearStats( return status; } +sai_status_t RedisRemoteSaiInterface::bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) +{ + SWSS_LOG_ENTER(); + + SWSS_LOG_ERROR("not implemented"); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + +sai_status_t RedisRemoteSaiInterface::bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) +{ + SWSS_LOG_ENTER(); + + SWSS_LOG_ERROR("not implemented"); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + sai_status_t RedisRemoteSaiInterface::waitForClearStatsResponse() { SWSS_LOG_ENTER(); diff --git a/lib/RedisRemoteSaiInterface.h b/lib/RedisRemoteSaiInterface.h index eb3014f25..8d5b01c1f 100644 --- a/lib/RedisRemoteSaiInterface.h +++ b/lib/RedisRemoteSaiInterface.h @@ -127,6 +127,27 @@ namespace sairedis _In_ uint32_t number_of_counters, _In_ const sai_stat_id_t *counter_ids) override; + virtual sai_status_t bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) override; + + virtual sai_status_t bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) override; + public: // non QUAD API virtual sai_status_t flushFdbEntries( diff --git a/lib/Sai.cpp b/lib/Sai.cpp index ecbaed77f..15725dc24 100644 --- a/lib/Sai.cpp +++ b/lib/Sai.cpp @@ -401,6 +401,37 @@ sai_status_t Sai::clearStats( counter_ids); } +sai_status_t Sai::bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) +{ + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + +sai_status_t Sai::bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) +{ + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + // BULK QUAD OID sai_status_t Sai::bulkCreate( diff --git a/lib/Sai.h b/lib/Sai.h index 3162ab30d..d92c43919 100644 --- a/lib/Sai.h +++ b/lib/Sai.h @@ -117,6 +117,27 @@ namespace sairedis _In_ uint32_t number_of_counters, _In_ const sai_stat_id_t *counter_ids) override; + virtual sai_status_t bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) override; + + virtual sai_status_t bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) override; + public: // non QUAD API virtual sai_status_t flushFdbEntries( diff --git a/lib/ServerSai.cpp b/lib/ServerSai.cpp index 0e17ef0bd..fc434c138 100644 --- a/lib/ServerSai.cpp +++ b/lib/ServerSai.cpp @@ -317,6 +317,56 @@ sai_status_t ServerSai::clearStats( counter_ids); } +sai_status_t ServerSai::bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) +{ + MUTEX(); + SWSS_LOG_ENTER(); + REDIS_CHECK_API_INITIALIZED(); + + return m_sai->bulkGetStats(switchId, + object_type, + object_count, + object_key, + number_of_counters, + counter_ids, + mode, + object_statuses, + counters); +} + +sai_status_t ServerSai::bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) +{ + MUTEX(); + SWSS_LOG_ENTER(); + REDIS_CHECK_API_INITIALIZED(); + + return m_sai->bulkClearStats(switchId, + object_type, + object_count, + object_key, + number_of_counters, + counter_ids, + mode, + object_statuses); +} + // BULK QUAD OID sai_status_t ServerSai::bulkCreate( diff --git a/lib/ServerSai.h b/lib/ServerSai.h index d9f27b4f8..b67c4ed1c 100644 --- a/lib/ServerSai.h +++ b/lib/ServerSai.h @@ -113,6 +113,27 @@ namespace sairedis _In_ uint32_t number_of_counters, _In_ const sai_stat_id_t *counter_ids) override; + virtual sai_status_t bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) override; + + virtual sai_status_t bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) override; + public: // non QUAD API virtual sai_status_t flushFdbEntries( diff --git a/lib/sai_redis_interfacequery.cpp b/lib/sai_redis_interfacequery.cpp index bac354020..d65c0a2c2 100644 --- a/lib/sai_redis_interfacequery.cpp +++ b/lib/sai_redis_interfacequery.cpp @@ -248,3 +248,34 @@ sai_status_t sai_query_api_version( return SAI_STATUS_NOT_IMPLEMENTED; } + +sai_status_t sai_bulk_object_get_stats( + _In_ sai_object_id_t switch_id, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) +{ + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + +sai_status_t sai_bulk_object_clear_stats( + _In_ sai_object_id_t switch_id, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) +{ + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; +} diff --git a/meta/DummySaiInterface.cpp b/meta/DummySaiInterface.cpp index 481488547..7098e1c94 100644 --- a/meta/DummySaiInterface.cpp +++ b/meta/DummySaiInterface.cpp @@ -213,6 +213,37 @@ sai_status_t DummySaiInterface::clearStats( return m_status; } +sai_status_t DummySaiInterface::bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) +{ + SWSS_LOG_ENTER(); + + return m_status; +} + +sai_status_t DummySaiInterface::bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) +{ + SWSS_LOG_ENTER(); + + return m_status; +} + // bulk QUAD sai_status_t DummySaiInterface::bulkRemove( diff --git a/meta/DummySaiInterface.h b/meta/DummySaiInterface.h index d40db5347..2cb9db43e 100644 --- a/meta/DummySaiInterface.h +++ b/meta/DummySaiInterface.h @@ -117,6 +117,27 @@ namespace saimeta _In_ uint32_t number_of_counters, _In_ const sai_stat_id_t *counter_ids) override; + virtual sai_status_t bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) override; + + virtual sai_status_t bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) override; + public: // non QUAD API virtual sai_status_t flushFdbEntries( diff --git a/meta/Meta.cpp b/meta/Meta.cpp index 346d7201d..2db3fc09e 100644 --- a/meta/Meta.cpp +++ b/meta/Meta.cpp @@ -1850,6 +1850,37 @@ sai_status_t Meta::clearStats( return status; } +sai_status_t Meta::bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) +{ + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + +sai_status_t Meta::bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) +{ + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + // for bulk operations actually we could make copy of current db and actually // execute to see if all will succeed diff --git a/meta/Meta.h b/meta/Meta.h index 2c928e8a6..82418a91d 100644 --- a/meta/Meta.h +++ b/meta/Meta.h @@ -124,6 +124,27 @@ namespace saimeta _In_ uint32_t number_of_counters, _In_ const sai_stat_id_t *counter_ids) override; + virtual sai_status_t bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) override; + + virtual sai_status_t bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) override; + public: // non QUAD API virtual sai_status_t flushFdbEntries( diff --git a/meta/SaiInterface.h b/meta/SaiInterface.h index 8acf4983c..d5b7a77d4 100644 --- a/meta/SaiInterface.h +++ b/meta/SaiInterface.h @@ -215,6 +215,27 @@ namespace sairedis _In_ uint32_t number_of_counters, _In_ const sai_stat_id_t *counter_ids) = 0; + virtual sai_status_t bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) = 0; + + virtual sai_status_t bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) = 0; + public: // non QUAD API virtual sai_status_t flushFdbEntries( diff --git a/syncd/FlexCounter.cpp b/syncd/FlexCounter.cpp index 23655433e..49d9c4d63 100644 --- a/syncd/FlexCounter.cpp +++ b/syncd/FlexCounter.cpp @@ -116,6 +116,18 @@ struct HasStatsMode enum { value = std::is_void(0))>::value }; }; +// BulkStatsContext is used to store bulk counter related +// data and avoid construct them each time calling SAI bulk API +template +struct BulkStatsContext +{ + std::vector object_vids; + std::vector object_keys; + std::vector counter_ids; + std::vector object_statuses; + std::vector counters; +}; + // TODO: use if const expression when cpp17 is supported template std::string serializeStat( @@ -356,6 +368,7 @@ class CounterContext : public BaseCounterContext { public: typedef CounterIds CounterIdsType; + typedef BulkStatsContext BulkContextType; CounterContext( _In_ const std::string &name, @@ -436,20 +449,36 @@ class CounterContext : public BaseCounterContext } } - auto it = m_objectIdsMap.find(vid); - if (it != m_objectIdsMap.end()) - { - it->second->counter_ids = supportedIds; - return; - } + // Perform a remove and re-add to simplify the logic here + removeObject(vid, false); - auto counter_data = std::make_shared>(rid, supportedIds); + bool supportBulk; // TODO: use if const expression when cpp17 is supported if (HasStatsMode::value) { - counter_data->setStatsMode(instance_stats_mode); + supportBulk = false; + } + else + { + supportBulk = checkBulkCapability(vid, rid, supportedIds); + } + + if (!supportBulk) + { + auto counter_data = std::make_shared>(rid, supportedIds); + // TODO: use if const expression when cpp17 is supported + if (HasStatsMode::value) + { + counter_data->setStatsMode(instance_stats_mode); + } + m_objectIdsMap.emplace(vid, counter_data); + } + else + { + std::sort(supportedIds.begin(), supportedIds.end()); + auto bulkContext = getBulkStatsContext(supportedIds); + addBulkStatsContext(vid, rid, supportedIds, *bulkContext.get()); } - m_objectIdsMap.emplace(vid, counter_data); } void removeObject( @@ -457,6 +486,15 @@ class CounterContext : public BaseCounterContext { SWSS_LOG_ENTER(); + removeObject(vid, true); + } + + void removeObject( + _In_ sai_object_id_t vid, + _In_ bool log) + { + SWSS_LOG_ENTER(); + auto iter = m_objectIdsMap.find(vid); if (iter != m_objectIdsMap.end()) { @@ -464,9 +502,12 @@ class CounterContext : public BaseCounterContext } else { - SWSS_LOG_NOTICE("Trying to remove nonexisting %s %s", - sai_serialize_object_type(m_objectType).c_str(), - sai_serialize_object_id(vid).c_str()); + if (!removeBulkStatsContext(vid) && log) + { + SWSS_LOG_NOTICE("Trying to remove nonexisting %s %s", + sai_serialize_object_type(m_objectType).c_str(), + sai_serialize_object_id(vid).c_str()); + } } } @@ -501,6 +542,11 @@ class CounterContext : public BaseCounterContext } countersTable.set(sai_serialize_object_id(vid), values, ""); } + + for (const auto &kv : m_bulkContexts) + { + bulkCollectData(countersTable, *kv.second.get()); + } } void runPlugin( @@ -509,16 +555,25 @@ class CounterContext : public BaseCounterContext { SWSS_LOG_ENTER(); - if (m_objectIdsMap.empty()) + if (!hasObject()) { return; } std::vector idStrings; idStrings.reserve(m_objectIdsMap.size()); std::transform(m_objectIdsMap.begin(), - m_objectIdsMap.end(), - std::back_inserter(idStrings), - [] (auto &kv) { return sai_serialize_object_id(kv.first); }); + m_objectIdsMap.end(), + std::back_inserter(idStrings), + [] (auto &kv) { return sai_serialize_object_id(kv.first); }); + + for (auto &kv : m_bulkContexts) + { + std::transform(kv.second->object_vids.begin(), + kv.second->object_vids.end(), + std::back_inserter(idStrings), + [] (auto &vid) { return sai_serialize_object_id(vid); }); + } + std::for_each(m_plugins.begin(), m_plugins.end(), [&] (auto &sha) { runRedisScript(counters_db, sha, idStrings, argv); }); @@ -527,11 +582,12 @@ class CounterContext : public BaseCounterContext bool hasObject() const override { SWSS_LOG_ENTER(); - return !m_objectIdsMap.empty(); + return !m_objectIdsMap.empty() || !m_bulkContexts.empty(); } private: - bool isCounterSupported(_In_ StatType counter) const + bool isCounterSupported( + _In_ StatType counter) const { SWSS_LOG_ENTER(); return m_supportedCounters.count(counter) != 0; @@ -617,6 +673,135 @@ class CounterContext : public BaseCounterContext return true; } + void bulkCollectData( + _In_ swss::Table &countersTable, + _Inout_ BulkContextType &ctx) + { + SWSS_LOG_ENTER(); + auto statsMode = m_groupStatsMode == SAI_STATS_MODE_READ ? SAI_STATS_MODE_BULK_READ : SAI_STATS_MODE_BULK_READ_AND_CLEAR; + sai_status_t status = m_vendorSai->bulkGetStats( + SAI_NULL_OBJECT_ID, + m_objectType, + static_cast(ctx.object_keys.size()), + ctx.object_keys.data(), + static_cast(ctx.counter_ids.size()), + reinterpret_cast(ctx.counter_ids.data()), + statsMode, + ctx.object_statuses.data(), + ctx.counters.data()); + if (SAI_STATUS_SUCCESS != status) + { + SWSS_LOG_WARN("Failed to bulk get stats for %s: %u", m_name.c_str(), status); + } + + std::vector values; + for (size_t i = 0; i < ctx.object_keys.size(); i++) + { + if (SAI_STATUS_SUCCESS != ctx.object_statuses[i]) + { + SWSS_LOG_ERROR("Failed to get stats of %s 0x%" PRIx64 ": %d", m_name.c_str(), ctx.object_keys[i].key.object_id, ctx.object_statuses[i]); + continue; + } + const auto &vid = ctx.object_vids[i]; + + for (size_t j = 0; j < ctx.counter_ids.size(); j++) + { + values.emplace_back(serializeStat(ctx.counter_ids[j]), std::to_string(ctx.counters[i * ctx.counter_ids.size() + j])); + } + countersTable.set(sai_serialize_object_id(vid), values, ""); + values.clear(); + } + } + + auto getBulkStatsContext( + _In_ const std::vector& counterIds) + { + SWSS_LOG_ENTER(); + auto iter = m_bulkContexts.find(counterIds); + if (iter != m_bulkContexts.end()) + { + return iter->second; + } + + auto ret = m_bulkContexts.emplace(counterIds, std::make_shared()); + return ret.first->second; + } + + void addBulkStatsContext( + _In_ sai_object_id_t vid, + _In_ sai_object_id_t rid, + _In_ const std::vector& counterIds, + _Inout_ BulkContextType &ctx) + { + SWSS_LOG_ENTER(); + ctx.object_vids.push_back(vid); + sai_object_key_t object_key; + object_key.key.object_id = rid; + ctx.object_keys.push_back(object_key); + if (ctx.counter_ids.empty()) + { + ctx.counter_ids = counterIds; + } + ctx.object_statuses.push_back(SAI_STATUS_SUCCESS); + ctx.counters.resize(counterIds.size() * ctx.object_keys.size()); + } + + bool removeBulkStatsContext( + _In_ sai_object_id_t vid) + { + SWSS_LOG_ENTER(); + bool found = false; + for (auto iter = m_bulkContexts.begin(); iter != m_bulkContexts.end(); iter++) + { + auto &ctx = *iter->second.get(); + auto vid_iter = std::find(ctx.object_vids.begin(), ctx.object_vids.end(), vid); + if (vid_iter == ctx.object_vids.end()) + { + continue; + } + found = true; + auto index = std::distance(ctx.object_vids.begin(), vid_iter); + ctx.object_vids.erase(vid_iter); + if (ctx.object_vids.empty()) + { + m_bulkContexts.erase(iter); + } + else + { + auto key_iter = ctx.object_keys.begin(); + std::advance(key_iter, index); + ctx.object_keys.erase(key_iter); + ctx.counters.resize(ctx.counter_ids.size() * ctx.object_keys.size()); + ctx.object_statuses.pop_back(); + } + break; + } + + return found; + } + + bool checkBulkCapability( + _In_ sai_object_id_t vid, + _In_ sai_object_id_t rid, + _In_ const std::vector& counter_ids) + { + SWSS_LOG_ENTER(); + BulkContextType ctx; + addBulkStatsContext(vid, rid, counter_ids, ctx); + auto statsMode = m_groupStatsMode == SAI_STATS_MODE_READ ? SAI_STATS_MODE_BULK_READ : SAI_STATS_MODE_BULK_READ_AND_CLEAR; + sai_status_t status = m_vendorSai->bulkGetStats( + SAI_NULL_OBJECT_ID, + m_objectType, + static_cast(ctx.object_keys.size()), + ctx.object_keys.data(), + static_cast(ctx.counter_ids.size()), + reinterpret_cast(ctx.counter_ids.data()), + statsMode, + ctx.object_statuses.data(), + ctx.counters.data()); + return status == SAI_STATUS_SUCCESS; + } + void updateSupportedCounters( _In_ sai_object_id_t rid, _In_ const std::vector& counter_ids, @@ -721,6 +906,7 @@ class CounterContext : public BaseCounterContext sai_stats_mode_t& m_groupStatsMode; std::set m_supportedCounters; std::map> m_objectIdsMap; + std::map, std::shared_ptr> m_bulkContexts; }; template diff --git a/syncd/VendorSai.cpp b/syncd/VendorSai.cpp index 303cfde66..c7ce4eec9 100644 --- a/syncd/VendorSai.cpp +++ b/syncd/VendorSai.cpp @@ -646,6 +646,58 @@ sai_status_t VendorSai::clearStats( return ptr(object_id, number_of_counters, counter_ids); } +sai_status_t VendorSai::bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) +{ + MUTEX(); + SWSS_LOG_ENTER(); + VENDOR_CHECK_API_INITIALIZED(); + + return sai_bulk_object_get_stats( + switchId, + object_type, + object_count, + object_key, + number_of_counters, + counter_ids, + mode, + object_statuses, + counters); +} + +sai_status_t VendorSai::bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) +{ + MUTEX(); + SWSS_LOG_ENTER(); + VENDOR_CHECK_API_INITIALIZED(); + + return sai_bulk_object_clear_stats( + switchId, + object_type, + object_count, + object_key, + number_of_counters, + counter_ids, + mode, + object_statuses); +} + // BULK QUAD OID sai_status_t VendorSai::bulkCreate( diff --git a/syncd/VendorSai.h b/syncd/VendorSai.h index 3ef2f7694..cf3562e2f 100644 --- a/syncd/VendorSai.h +++ b/syncd/VendorSai.h @@ -114,6 +114,27 @@ namespace syncd _In_ uint32_t number_of_counters, _In_ const sai_stat_id_t *counter_ids) override; + virtual sai_status_t bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) override; + + virtual sai_status_t bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) override; + public: // non QUAD API virtual sai_status_t flushFdbEntries( diff --git a/unittest/lib/Makefile.am b/unittest/lib/Makefile.am index c5e7b3b20..5ed79f199 100644 --- a/unittest/lib/Makefile.am +++ b/unittest/lib/Makefile.am @@ -9,7 +9,7 @@ tests_SOURCES = \ ../../meta/NumberOidIndexGenerator.cpp \ TestSwitch.cpp \ TestClientConfig.cpp \ - TestClientServerSai.cppa \ + TestClientServerSai.cpp \ TestContext.cpp \ TestContextConfig.cpp \ TestContextConfigContainer.cpp \ diff --git a/unittest/lib/TestClientServerSai.cpp b/unittest/lib/TestClientServerSai.cpp index ea77661bf..d88d5cd44 100644 --- a/unittest/lib/TestClientServerSai.cpp +++ b/unittest/lib/TestClientServerSai.cpp @@ -1,5 +1,7 @@ #include "ClientServerSai.h" +#include "sairedis.h" + #include "swss/logger.h" #include @@ -33,6 +35,25 @@ static sai_service_method_table_t test_services = { profile_get_next_value }; +static const char* client_profile_get_value( + _In_ sai_switch_profile_id_t profile_id, + _In_ const char* variable) +{ + SWSS_LOG_ENTER(); + + if (variable != NULL && strcmp(variable, SAI_REDIS_KEY_ENABLE_CLIENT) == 0 ) + return "true"; + else + return NULL; + + return nullptr; +} + +static sai_service_method_table_t test_client_services = { + client_profile_get_value, + profile_get_next_value +}; + TEST(ClientServerSai, ctr) { auto css = std::make_shared(); @@ -81,3 +102,70 @@ TEST(ClientServerSai, logSet) EXPECT_EQ(SAI_STATUS_SUCCESS, css->logSet(SAI_API_PORT, SAI_LOG_LEVEL_NOTICE)); } + +TEST(ClientServerSai, bulkGetClearStats) +{ + auto css = std::make_shared(); + + EXPECT_EQ(SAI_STATUS_FAILURE, css->bulkGetStats(SAI_NULL_OBJECT_ID, + SAI_OBJECT_TYPE_PORT, + 0, + nullptr, + 0, + nullptr, + SAI_STATS_MODE_BULK_READ, + nullptr, + nullptr)); + + EXPECT_EQ(SAI_STATUS_FAILURE, css->bulkClearStats(SAI_NULL_OBJECT_ID, + SAI_OBJECT_TYPE_PORT, + 0, + nullptr, + 0, + nullptr, + SAI_STATS_MODE_BULK_CLEAR, + nullptr)); + + EXPECT_EQ(SAI_STATUS_SUCCESS, css->initialize(0, &test_services)); + + EXPECT_EQ(SAI_STATUS_NOT_IMPLEMENTED, css->bulkGetStats(SAI_NULL_OBJECT_ID, + SAI_OBJECT_TYPE_PORT, + 0, + nullptr, + 0, + nullptr, + SAI_STATS_MODE_BULK_READ, + nullptr, + nullptr)); + + EXPECT_EQ(SAI_STATUS_NOT_IMPLEMENTED, css->bulkClearStats(SAI_NULL_OBJECT_ID, + SAI_OBJECT_TYPE_PORT, + 0, + nullptr, + 0, + nullptr, + SAI_STATS_MODE_BULK_CLEAR, + nullptr)); + + css = std::make_shared(); + EXPECT_EQ(SAI_STATUS_SUCCESS, css->initialize(0, &test_client_services)); + + EXPECT_EQ(SAI_STATUS_NOT_IMPLEMENTED, css->bulkGetStats(SAI_NULL_OBJECT_ID, + SAI_OBJECT_TYPE_PORT, + 0, + nullptr, + 0, + nullptr, + SAI_STATS_MODE_BULK_READ, + nullptr, + nullptr)); + + EXPECT_EQ(SAI_STATUS_NOT_IMPLEMENTED, css->bulkClearStats(SAI_NULL_OBJECT_ID, + SAI_OBJECT_TYPE_PORT, + 0, + nullptr, + 0, + nullptr, + SAI_STATS_MODE_BULK_CLEAR, + nullptr)); +} diff --git a/unittest/lib/TestContext.cpp b/unittest/lib/TestContext.cpp index 45e9ba446..e39fc7854 100644 --- a/unittest/lib/TestContext.cpp +++ b/unittest/lib/TestContext.cpp @@ -29,3 +29,30 @@ TEST(Context, populateMetadata) ctx->populateMetadata(0x212121212212121L); } + +TEST(Context, bulkGetClearStats) +{ + auto recorder = std::make_shared(); + + auto cc = std::make_shared(0, "syncd", "ASIC_DB", "COUNTERS_DB","FLEX_DB", "STATE_DB"); + + auto ctx = std::make_shared(cc, recorder,handle_notification); + + EXPECT_EQ(SAI_STATUS_NOT_IMPLEMENTED, ctx->m_redisSai->bulkGetStats(SAI_NULL_OBJECT_ID, + SAI_OBJECT_TYPE_PORT, + 0, + nullptr, + 0, + nullptr, + SAI_STATS_MODE_BULK_READ, + nullptr, + nullptr)); + EXPECT_EQ(SAI_STATUS_NOT_IMPLEMENTED, ctx->m_redisSai->bulkClearStats(SAI_NULL_OBJECT_ID, + SAI_OBJECT_TYPE_PORT, + 0, + nullptr, + 0, + nullptr, + SAI_STATS_MODE_BULK_CLEAR, + nullptr)); +} diff --git a/unittest/lib/test_sai_redis_interfacequery.cpp b/unittest/lib/test_sai_redis_interfacequery.cpp index 2031d92f4..0fbf297e6 100644 --- a/unittest/lib/test_sai_redis_interfacequery.cpp +++ b/unittest/lib/test_sai_redis_interfacequery.cpp @@ -80,3 +80,28 @@ TEST(libsairedis, sai_query_stats_capability) { EXPECT_EQ(SAI_STATUS_NOT_IMPLEMENTED, sai_query_stats_capability(0,SAI_OBJECT_TYPE_NULL,0)); } + +TEST(libsairedis, sai_bulk_object_get_stats) +{ + EXPECT_EQ(SAI_STATUS_NOT_IMPLEMENTED, sai_bulk_object_get_stats(SAI_NULL_OBJECT_ID, + SAI_OBJECT_TYPE_PORT, + 0, + nullptr, + 0, + nullptr, + SAI_STATS_MODE_BULK_READ, + nullptr, + nullptr)); +} + +TEST(libsairedis, sai_bulk_object_clear_stats) +{ + EXPECT_EQ(SAI_STATUS_NOT_IMPLEMENTED, sai_bulk_object_clear_stats(SAI_NULL_OBJECT_ID, + SAI_OBJECT_TYPE_PORT, + 0, + nullptr, + 0, + nullptr, + SAI_STATS_MODE_BULK_CLEAR, + nullptr)); +} diff --git a/unittest/meta/TestMeta.cpp b/unittest/meta/TestMeta.cpp index 89cd60f2a..17311c783 100644 --- a/unittest/meta/TestMeta.cpp +++ b/unittest/meta/TestMeta.cpp @@ -1056,3 +1056,25 @@ TEST(Meta, populate) m.populate(dump); } + +TEST(Meta, bulkGetClearStats) +{ + Meta m(std::make_shared()); + EXPECT_EQ(SAI_STATUS_NOT_IMPLEMENTED, m.bulkGetStats(SAI_NULL_OBJECT_ID, + SAI_OBJECT_TYPE_PORT, + 0, + nullptr, + 0, + nullptr, + SAI_STATS_MODE_BULK_READ, + nullptr, + nullptr)); + EXPECT_EQ(SAI_STATUS_NOT_IMPLEMENTED, m.bulkClearStats(SAI_NULL_OBJECT_ID, + SAI_OBJECT_TYPE_PORT, + 0, + nullptr, + 0, + nullptr, + SAI_STATS_MODE_BULK_CLEAR, + nullptr)); +} diff --git a/unittest/syncd/MockableSaiInterface.cpp b/unittest/syncd/MockableSaiInterface.cpp index c96764e3a..e52b1dc58 100644 --- a/unittest/syncd/MockableSaiInterface.cpp +++ b/unittest/syncd/MockableSaiInterface.cpp @@ -200,6 +200,45 @@ sai_status_t MockableSaiInterface::clearStats( return SAI_STATUS_SUCCESS; } +sai_status_t MockableSaiInterface::bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) +{ + SWSS_LOG_ENTER(); + if (mock_bulkGetStats) + { + return mock_bulkGetStats(switchId, object_type, object_count, object_key, number_of_counters, counter_ids, mode, object_statuses, counters); + } + + return SAI_STATUS_SUCCESS; +} + +sai_status_t MockableSaiInterface::bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) +{ + SWSS_LOG_ENTER(); + if (mock_bulkClearStats) + { + return mock_bulkClearStats(switchId, object_type, object_count, object_key, number_of_counters, counter_ids, mode, object_statuses); + } + + return SAI_STATUS_SUCCESS; +} + sai_status_t MockableSaiInterface::flushFdbEntries( _In_ sai_object_id_t switchId, _In_ uint32_t attrCount, diff --git a/unittest/syncd/MockableSaiInterface.h b/unittest/syncd/MockableSaiInterface.h index 536c45830..0a17e4b22 100644 --- a/unittest/syncd/MockableSaiInterface.h +++ b/unittest/syncd/MockableSaiInterface.h @@ -120,6 +120,30 @@ class MockableSaiInterface: public saimeta::DummySaiInterface std::function mock_clearStats; + virtual sai_status_t bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) override; + + std::function mock_bulkGetStats; + + virtual sai_status_t bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) override; + + std::function mock_bulkClearStats; public: // non QUAD API diff --git a/unittest/syncd/TestFlexCounter.cpp b/unittest/syncd/TestFlexCounter.cpp index c770e9be8..482fc6c1c 100644 --- a/unittest/syncd/TestFlexCounter.cpp +++ b/unittest/syncd/TestFlexCounter.cpp @@ -40,7 +40,7 @@ std::shared_ptr sai(new MockableSaiInterface()); typedef std::function& counterIdNames, const std::vector& expectedValues)> VerifyStatsFunc; void testAddRemoveCounter( - sai_object_id_t object_id, + const std::vector& object_ids, sai_object_type_t object_type, const std::string& counterIdFieldName, const std::vector& counterIdNames, @@ -57,19 +57,17 @@ void testAddRemoveCounter( std::vector values; values.emplace_back(POLL_INTERVAL_FIELD, "1000"); - fc.addCounterPlugin(values); - - values.clear(); values.emplace_back(FLEX_COUNTER_STATUS_FIELD, "enable"); - fc.addCounterPlugin(values); - - values.clear(); values.emplace_back(STATS_MODE_FIELD, statsMode); fc.addCounterPlugin(values); values.clear(); values.emplace_back(counterIdFieldName, join(counterIdNames)); - fc.addCounter(object_id, object_id, values); + for (auto object_id : object_ids) + { + fc.addCounter(object_id, object_id, values); + } + EXPECT_EQ(fc.isEmpty(), false); usleep(1000*1050); @@ -77,21 +75,25 @@ void testAddRemoveCounter( swss::RedisPipeline pipeline(&db); swss::Table countersTable(&pipeline, COUNTERS_TABLE, false); - std::string expectedKey = toOid(object_id); std::vector keys; countersTable.getKeys(keys); - EXPECT_EQ(keys.size(), size_t(1)); - EXPECT_EQ(keys[0], expectedKey); - - verifyFunc(countersTable, expectedKey, counterIdNames, expectedValues); + EXPECT_EQ(keys.size(), object_ids.size()); - fc.removeCounter(object_id); - EXPECT_EQ(fc.isEmpty(), true); + for (size_t i = 0; i < object_ids.size(); i++) + { + std::string expectedKey = toOid(object_ids[i]); + verifyFunc(countersTable, expectedKey, counterIdNames, expectedValues); + } - if (!autoRemoveDbEntry) + for (auto object_id : object_ids) { - countersTable.del(expectedKey); + fc.removeCounter(object_id); + if (!autoRemoveDbEntry) + { + countersTable.del(toOid(object_id)); + } } + EXPECT_EQ(fc.isEmpty(), true); countersTable.getKeys(keys); ASSERT_TRUE(keys.empty()); @@ -118,6 +120,11 @@ TEST(FlexCounter, addRemoveCounter) return SAI_STATUS_FAILURE; }; + sai->mock_bulkGetStats = [](sai_object_id_t, sai_object_type_t, uint32_t, const sai_object_key_t *, uint32_t, const sai_stat_id_t *, sai_stats_mode_t, sai_status_t *, uint64_t *) + { + return SAI_STATUS_FAILURE; + }; + auto counterVerifyFunc = [] (swss::Table &countersTable, const std::string& key, const std::vector& counterIdNames, const std::vector& expectedValues) { std::string value; @@ -129,7 +136,7 @@ TEST(FlexCounter, addRemoveCounter) }; testAddRemoveCounter( - sai_object_id_t(0x54000000000000), + {sai_object_id_t(0x54000000000000)}, SAI_OBJECT_TYPE_COUNTER, FLOW_COUNTER_ID_LIST, {"SAI_COUNTER_STAT_PACKETS", "SAI_COUNTER_STAT_BYTES"}, @@ -138,7 +145,7 @@ TEST(FlexCounter, addRemoveCounter) true); testAddRemoveCounter( - sai_object_id_t(0x5a000000000000), + {sai_object_id_t(0x5a000000000000)}, SAI_OBJECT_TYPE_MACSEC_FLOW, MACSEC_FLOW_COUNTER_ID_LIST, {"SAI_MACSEC_FLOW_STAT_CONTROL_PKTS", "SAI_MACSEC_FLOW_STAT_PKTS_UNTAGGED"}, @@ -147,7 +154,7 @@ TEST(FlexCounter, addRemoveCounter) false); testAddRemoveCounter( - sai_object_id_t(0x5c000000000000), + {sai_object_id_t(0x5c000000000000)}, SAI_OBJECT_TYPE_MACSEC_SA, MACSEC_SA_COUNTER_ID_LIST, {"SAI_MACSEC_SA_STAT_OCTETS_ENCRYPTED", "SAI_MACSEC_SA_STAT_OCTETS_PROTECTED"}, @@ -156,7 +163,7 @@ TEST(FlexCounter, addRemoveCounter) false); testAddRemoveCounter( - sai_object_id_t(0x1000000000000), + {sai_object_id_t(0x1000000000000)}, SAI_OBJECT_TYPE_PORT, PORT_COUNTER_ID_LIST, {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS"}, @@ -165,7 +172,7 @@ TEST(FlexCounter, addRemoveCounter) false); testAddRemoveCounter( - sai_object_id_t(0x1000000000000), + {sai_object_id_t(0x1000000000000)}, SAI_OBJECT_TYPE_PORT, PORT_DEBUG_COUNTER_ID_LIST, {"SAI_PORT_STAT_IN_CONFIGURED_DROP_REASONS_0_DROPPED_PKTS", "SAI_PORT_STAT_IN_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS"}, @@ -180,7 +187,7 @@ TEST(FlexCounter, addRemoveCounter) }; testAddRemoveCounter( - sai_object_id_t(0x15000000000000), + {sai_object_id_t(0x15000000000000)}, SAI_OBJECT_TYPE_QUEUE, QUEUE_COUNTER_ID_LIST, {"SAI_QUEUE_STAT_PACKETS", "SAI_QUEUE_STAT_BYTES"}, @@ -191,7 +198,7 @@ TEST(FlexCounter, addRemoveCounter) EXPECT_EQ(true, clearCalled); testAddRemoveCounter( - sai_object_id_t(0x1a000000000000), + {sai_object_id_t(0x1a000000000000)}, SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, PG_COUNTER_ID_LIST, {"SAI_INGRESS_PRIORITY_GROUP_STAT_PACKETS", "SAI_INGRESS_PRIORITY_GROUP_STAT_BYTES"}, @@ -200,7 +207,7 @@ TEST(FlexCounter, addRemoveCounter) false); testAddRemoveCounter( - sai_object_id_t(0x6000000000000), + {sai_object_id_t(0x6000000000000)}, SAI_OBJECT_TYPE_ROUTER_INTERFACE, RIF_COUNTER_ID_LIST, {"SAI_ROUTER_INTERFACE_STAT_IN_OCTETS", "SAI_ROUTER_INTERFACE_STAT_IN_PACKETS"}, @@ -209,7 +216,7 @@ TEST(FlexCounter, addRemoveCounter) false); testAddRemoveCounter( - sai_object_id_t(0x21000000000000), + {sai_object_id_t(0x21000000000000)}, SAI_OBJECT_TYPE_SWITCH, SWITCH_DEBUG_COUNTER_ID_LIST, {"SAI_SWITCH_STAT_IN_CONFIGURED_DROP_REASONS_0_DROPPED_PKTS", "SAI_SWITCH_STAT_IN_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS"}, @@ -218,7 +225,7 @@ TEST(FlexCounter, addRemoveCounter) false); testAddRemoveCounter( - sai_object_id_t(0x2a000000000000), + {sai_object_id_t(0x2a000000000000)}, SAI_OBJECT_TYPE_TUNNEL, TUNNEL_COUNTER_ID_LIST, {"SAI_TUNNEL_STAT_IN_OCTETS", "SAI_TUNNEL_STAT_IN_PACKETS"}, @@ -228,7 +235,7 @@ TEST(FlexCounter, addRemoveCounter) clearCalled = false; testAddRemoveCounter( - sai_object_id_t(0x18000000000000), + {sai_object_id_t(0x18000000000000)}, SAI_OBJECT_TYPE_BUFFER_POOL, BUFFER_POOL_COUNTER_ID_LIST, {"SAI_BUFFER_POOL_STAT_CURR_OCCUPANCY_BYTES", "SAI_BUFFER_POOL_STAT_WATERMARK_BYTES"}, @@ -249,7 +256,7 @@ TEST(FlexCounter, addRemoveCounter) }; testAddRemoveCounter( - sai_object_id_t(0x15000000000000), + {sai_object_id_t(0x15000000000000)}, SAI_OBJECT_TYPE_QUEUE, QUEUE_ATTR_ID_LIST, {"SAI_QUEUE_ATTR_PAUSE_STATUS"}, @@ -269,7 +276,7 @@ TEST(FlexCounter, addRemoveCounter) }; testAddRemoveCounter( - sai_object_id_t(0x1a000000000000), + {sai_object_id_t(0x1a000000000000)}, SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, PG_ATTR_ID_LIST, {"SAI_INGRESS_PRIORITY_GROUP_ATTR_PORT"}, @@ -293,7 +300,7 @@ TEST(FlexCounter, addRemoveCounter) }; testAddRemoveCounter( - sai_object_id_t(0x5c000000000000), + {sai_object_id_t(0x5c000000000000)}, SAI_OBJECT_TYPE_MACSEC_SA, MACSEC_SA_ATTR_ID_LIST, {"SAI_MACSEC_SA_ATTR_CONFIGURED_EGRESS_XPN", "SAI_MACSEC_SA_ATTR_AN"}, @@ -313,7 +320,7 @@ TEST(FlexCounter, addRemoveCounter) }; testAddRemoveCounter( - sai_object_id_t(0x9000000000000), + {sai_object_id_t(0x9000000000000)}, SAI_OBJECT_TYPE_ACL_COUNTER, ACL_COUNTER_ATTR_ID_LIST, {"SAI_ACL_COUNTER_ATTR_PACKETS"}, @@ -346,6 +353,15 @@ TEST(FlexCounter, queryCounterCapability) return SAI_STATUS_SUCCESS; }; + sai->mock_clearStats = [&] (sai_object_type_t object_type, sai_object_id_t object_id, uint32_t number_of_counters, const sai_stat_id_t *counter_ids) { + return SAI_STATUS_SUCCESS; + }; + + sai->mock_bulkGetStats = [](sai_object_id_t, sai_object_type_t, uint32_t, const sai_object_key_t *, uint32_t, const sai_stat_id_t *, sai_stats_mode_t, sai_status_t *, uint64_t *) + { + return SAI_STATUS_FAILURE; + }; + auto counterVerifyFunc = [] (swss::Table &countersTable, const std::string& key, const std::vector& counterIdNames, const std::vector& expectedValues) { std::string value; @@ -357,7 +373,7 @@ TEST(FlexCounter, queryCounterCapability) }; testAddRemoveCounter( - sai_object_id_t(0x1000000000000), + {sai_object_id_t(0x1000000000000)}, SAI_OBJECT_TYPE_PORT, PORT_COUNTER_ID_LIST, {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS"}, @@ -417,3 +433,406 @@ TEST(FlexCounter, addRemoveCounterPlugin) } } +TEST(FlexCounter, addRemoveCounterForPort) +{ + FlexCounter fc("test", sai, "COUNTERS_DB"); + + sai_object_id_t counterVid{0x1000000000000}; + sai_object_id_t counterRid{0x1000000000000}; + std::vector values; + values.emplace_back(PORT_COUNTER_ID_LIST, "SAI_PORT_STAT_IF_IN_OCTETS,SAI_PORT_STAT_IF_IN_ERRORS"); + + test_syncd::mockVidManagerObjectTypeQuery(SAI_OBJECT_TYPE_PORT); + sai->mock_getStats = [](sai_object_type_t, sai_object_id_t, uint32_t number_of_counters, const sai_stat_id_t *ids, uint64_t *counters) { + for (uint32_t i = 0; i < number_of_counters; i++) + { + if (ids[i] == SAI_PORT_STAT_IF_IN_OCTETS) + { + counters[i] = 100; + } + else if (ids[i] == SAI_PORT_STAT_IF_IN_ERRORS) + { + counters[i] = 200; + } + else + { + return SAI_STATUS_FAILURE; + } + } + return SAI_STATUS_SUCCESS; + }; + + fc.addCounter(counterVid, counterRid, values); + EXPECT_EQ(fc.isEmpty(), false); + + values.clear(); + values.emplace_back(POLL_INTERVAL_FIELD, "1000"); + values.emplace_back(FLEX_COUNTER_STATUS_FIELD, "enable"); + values.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ); + fc.addCounterPlugin(values); + + usleep(1000*1000); + swss::DBConnector db("COUNTERS_DB", 0); + swss::RedisPipeline pipeline(&db); + swss::Table countersTable(&pipeline, COUNTERS_TABLE, false); + + std::vector keys; + countersTable.getKeys(keys); + EXPECT_EQ(keys.size(), size_t(1)); + std::string expectedKey = toOid(counterVid); + EXPECT_EQ(keys[0], expectedKey); + + std::string value; + countersTable.hget(expectedKey, "SAI_PORT_STAT_IF_IN_OCTETS", value); + EXPECT_EQ(value, "100"); + countersTable.hget(expectedKey, "SAI_PORT_STAT_IF_IN_ERRORS", value); + EXPECT_EQ(value, "200"); + + fc.removeCounter(counterVid); + EXPECT_EQ(fc.isEmpty(), true); + countersTable.del(expectedKey); + countersTable.getKeys(keys); + ASSERT_TRUE(keys.empty()); + + // Test again with queryStatsCapability support + sai->mock_queryStatsCapability = [](sai_object_id_t, sai_object_type_t, sai_stat_capability_list_t *capability) { + if (capability->count < 2) + { + capability->count = 2; + return SAI_STATUS_BUFFER_OVERFLOW; + } + + capability->list[0].stat_enum = SAI_PORT_STAT_IF_IN_OCTETS; + capability->list[0].stat_modes = SAI_STATS_MODE_READ | SAI_STATS_MODE_READ_AND_CLEAR; + capability->list[1].stat_enum = SAI_PORT_STAT_IF_IN_ERRORS; + capability->list[1].stat_modes = SAI_STATS_MODE_READ | SAI_STATS_MODE_READ_AND_CLEAR; + return SAI_STATUS_SUCCESS; + }; + + values.clear(); + values.emplace_back(PORT_COUNTER_ID_LIST, "SAI_PORT_STAT_IF_IN_OCTETS,SAI_PORT_STAT_IF_IN_ERRORS"); + fc.addCounter(counterVid, counterRid, values); + EXPECT_EQ(fc.isEmpty(), false); + + usleep(1000*1000); + countersTable.hget(expectedKey, "SAI_PORT_STAT_IF_IN_OCTETS", value); + EXPECT_EQ(value, "100"); + countersTable.hget(expectedKey, "SAI_PORT_STAT_IF_IN_ERRORS", value); + EXPECT_EQ(value, "200"); + + fc.removeCounter(counterVid); + EXPECT_EQ(fc.isEmpty(), true); + countersTable.del(expectedKey); + countersTable.getKeys(keys); + ASSERT_TRUE(keys.empty()); +} + +TEST(FlexCounter, bulkCounter) +{ + sai->mock_getStatsExt = [&](sai_object_type_t, sai_object_id_t, uint32_t number_of_counters, const sai_stat_id_t *, sai_stats_mode_t, uint64_t *counters) { + for (uint32_t i = 0; i < number_of_counters; i++) + { + counters[i] = (i + 1) * 10; + } + return SAI_STATUS_SUCCESS; + }; + sai->mock_getStats = [&](sai_object_type_t, sai_object_id_t, uint32_t number_of_counters, const sai_stat_id_t *, uint64_t *counters) { + for (uint32_t i = 0; i < number_of_counters; i++) + { + counters[i] = (i + 1) * 10; + } + return SAI_STATUS_SUCCESS; + }; + sai->mock_queryStatsCapability = [&](sai_object_id_t switch_id, sai_object_type_t object_type, sai_stat_capability_list_t *stats_capability) { + // For now, just return failure to make test simple, will write a singe test to cover querySupportedCounters + return SAI_STATUS_FAILURE; + }; + + bool clearCalled = false; + sai->mock_bulkGetStats = [&](sai_object_id_t, + sai_object_type_t, + uint32_t object_count, + const sai_object_key_t *object_keys, + uint32_t number_of_counters, + const sai_stat_id_t *counter_ids, + sai_stats_mode_t mode, + sai_status_t *object_status, + uint64_t *counters) + { + EXPECT_TRUE(mode == SAI_STATS_MODE_BULK_READ_AND_CLEAR || mode == SAI_STATS_MODE_BULK_READ); + if (mode == SAI_STATS_MODE_BULK_READ_AND_CLEAR) + { + clearCalled = true; + } + for (uint32_t i = 0; i < object_count; i++) + { + object_status[i] = SAI_STATUS_SUCCESS; + for (uint32_t j = 0; j < number_of_counters; j++) + { + counters[i * number_of_counters + j] = (j + 1) * 100; + } + } + return SAI_STATUS_SUCCESS; + }; + + auto counterVerifyFunc = [] (swss::Table &countersTable, const std::string& key, const std::vector& counterIdNames, const std::vector& expectedValues) + { + std::string value; + for (size_t i = 0; i < counterIdNames.size(); i++) + { + countersTable.hget(key, counterIdNames[i], value); + ASSERT_EQ(value, expectedValues[i]); + } + }; + + testAddRemoveCounter( + {sai_object_id_t(0x54000000000000), sai_object_id_t(0x54000000000001)}, + SAI_OBJECT_TYPE_COUNTER, + FLOW_COUNTER_ID_LIST, + {"SAI_COUNTER_STAT_PACKETS", "SAI_COUNTER_STAT_BYTES"}, + {"100", "200"}, + counterVerifyFunc, + true); + + testAddRemoveCounter( + {sai_object_id_t(0x5a000000000000), sai_object_id_t(0x5a000000000001)}, + SAI_OBJECT_TYPE_MACSEC_FLOW, + MACSEC_FLOW_COUNTER_ID_LIST, + {"SAI_MACSEC_FLOW_STAT_CONTROL_PKTS", "SAI_MACSEC_FLOW_STAT_PKTS_UNTAGGED"}, + {"100", "200"}, + counterVerifyFunc, + false); + + testAddRemoveCounter( + {sai_object_id_t(0x5c000000000000), sai_object_id_t(0x5c000000000001)}, + SAI_OBJECT_TYPE_MACSEC_SA, + MACSEC_SA_COUNTER_ID_LIST, + {"SAI_MACSEC_SA_STAT_OCTETS_ENCRYPTED", "SAI_MACSEC_SA_STAT_OCTETS_PROTECTED"}, + {"100", "200"}, + counterVerifyFunc, + false); + + testAddRemoveCounter( + {sai_object_id_t(0x1000000000000), sai_object_id_t(0x1000000000001)}, + SAI_OBJECT_TYPE_PORT, + PORT_COUNTER_ID_LIST, + {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS"}, + {"100", "200"}, + counterVerifyFunc, + false); + + testAddRemoveCounter( + {sai_object_id_t(0x1000000000000), sai_object_id_t(0x1000000000001)}, + SAI_OBJECT_TYPE_PORT, + PORT_DEBUG_COUNTER_ID_LIST, + {"SAI_PORT_STAT_IN_CONFIGURED_DROP_REASONS_0_DROPPED_PKTS", "SAI_PORT_STAT_IN_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS"}, + {"100", "200"}, + counterVerifyFunc, + false); + + testAddRemoveCounter( + {sai_object_id_t(0x15000000000000), sai_object_id_t(0x15000000000001)}, + SAI_OBJECT_TYPE_QUEUE, + QUEUE_COUNTER_ID_LIST, + {"SAI_QUEUE_STAT_PACKETS", "SAI_QUEUE_STAT_BYTES"}, + {"100", "200"}, + counterVerifyFunc, + false, + STATS_MODE_READ_AND_CLEAR); + EXPECT_EQ(true, clearCalled); + + testAddRemoveCounter( + {sai_object_id_t(0x1a000000000000), sai_object_id_t(0x1a000000000001)}, + SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, + PG_COUNTER_ID_LIST, + {"SAI_INGRESS_PRIORITY_GROUP_STAT_PACKETS", "SAI_INGRESS_PRIORITY_GROUP_STAT_BYTES"}, + {"100", "200"}, + counterVerifyFunc, + false); + + testAddRemoveCounter( + {sai_object_id_t(0x6000000000000), sai_object_id_t(0x6000000000001)}, + SAI_OBJECT_TYPE_ROUTER_INTERFACE, + RIF_COUNTER_ID_LIST, + {"SAI_ROUTER_INTERFACE_STAT_IN_OCTETS", "SAI_ROUTER_INTERFACE_STAT_IN_PACKETS"}, + {"100", "200"}, + counterVerifyFunc, + false); + + testAddRemoveCounter( + {sai_object_id_t(0x21000000000000), sai_object_id_t(0x21000000000001)}, + SAI_OBJECT_TYPE_SWITCH, + SWITCH_DEBUG_COUNTER_ID_LIST, + {"SAI_SWITCH_STAT_IN_CONFIGURED_DROP_REASONS_0_DROPPED_PKTS", "SAI_SWITCH_STAT_IN_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS"}, + {"100", "200"}, + counterVerifyFunc, + false); + + testAddRemoveCounter( + {sai_object_id_t(0x2a000000000000), sai_object_id_t(0x2a000000000001)}, + SAI_OBJECT_TYPE_TUNNEL, + TUNNEL_COUNTER_ID_LIST, + {"SAI_TUNNEL_STAT_IN_OCTETS", "SAI_TUNNEL_STAT_IN_PACKETS"}, + {"100", "200"}, + counterVerifyFunc, + false); + + clearCalled = false; + testAddRemoveCounter( + {sai_object_id_t(0x18000000000000), sai_object_id_t(0x18000000000001)}, + SAI_OBJECT_TYPE_BUFFER_POOL, + BUFFER_POOL_COUNTER_ID_LIST, + {"SAI_BUFFER_POOL_STAT_CURR_OCCUPANCY_BYTES", "SAI_BUFFER_POOL_STAT_WATERMARK_BYTES"}, + {"10", "20"}, + counterVerifyFunc, + false); + // buffer pool stats does not support bulk + EXPECT_EQ(false, clearCalled); +} + +TEST(FlexCounter, counterIdChange) +{ + sai->mock_getStats = [&](sai_object_type_t, sai_object_id_t, uint32_t number_of_counters, const sai_stat_id_t *, uint64_t *counters) { + for (uint32_t i = 0; i < number_of_counters; i++) + { + counters[i] = (i + 1) * 10; + } + return SAI_STATUS_SUCCESS; + }; + sai->mock_bulkGetStats = [&](sai_object_id_t, + sai_object_type_t, + uint32_t object_count, + const sai_object_key_t *object_keys, + uint32_t number_of_counters, + const sai_stat_id_t *counter_ids, + sai_stats_mode_t mode, + sai_status_t *object_status, + uint64_t *counters) + { + for (uint32_t i = 0; i < number_of_counters; i++) + { + switch(counter_ids[i]) + { + case SAI_PORT_STAT_IF_IN_OCTETS: + case SAI_PORT_STAT_IF_IN_UCAST_PKTS: + break; + default: + return SAI_STATUS_NOT_SUPPORTED; + } + } + + for (uint32_t i = 0; i < object_count; i++) + { + object_status[i] = SAI_STATUS_SUCCESS; + for (uint32_t j = 0; j < number_of_counters; j++) + { + counters[i * number_of_counters + j] = (j + 1) * 100; + } + } + return SAI_STATUS_SUCCESS; + }; + auto counterVerifyFunc = [] (swss::Table &countersTable, const std::string& key, const std::vector& counterIdNames, const std::vector& expectedValues) + { + std::string value; + for (size_t i = 0; i < counterIdNames.size(); i++) + { + countersTable.hget(key, counterIdNames[i], value); + ASSERT_EQ(value, expectedValues[i]); + } + }; + + FlexCounter fc("test", sai, "COUNTERS_DB"); + + test_syncd::mockVidManagerObjectTypeQuery(SAI_OBJECT_TYPE_PORT); + + std::vector values; + values.emplace_back(POLL_INTERVAL_FIELD, "1000"); + values.emplace_back(FLEX_COUNTER_STATUS_FIELD, "enable"); + values.emplace_back(STATS_MODE_FIELD, STATS_MODE_READ); + fc.addCounterPlugin(values); + + values.clear(); + values.emplace_back(PORT_COUNTER_ID_LIST, "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS,SAI_PORT_STAT_IF_IN_DISCARDS"); + sai_object_id_t oid{0x1000000000000}; + fc.addCounter(oid, oid, values); + + usleep(1000*1050); + swss::DBConnector db("COUNTERS_DB", 0); + swss::RedisPipeline pipeline(&db); + swss::Table countersTable(&pipeline, COUNTERS_TABLE, false); + + std::vector keys; + countersTable.getKeys(keys); + EXPECT_EQ(keys.size(),1); + std::string expectedKey = toOid(oid); + counterVerifyFunc(countersTable, + expectedKey, + {"SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS", "SAI_PORT_STAT_IF_IN_DISCARDS"}, + {"10", "20"}); + + // not support bulk to support bulk + values.clear(); + values.emplace_back(PORT_COUNTER_ID_LIST, "SAI_PORT_STAT_IF_IN_OCTETS,SAI_PORT_STAT_IF_IN_UCAST_PKTS"); + fc.addCounter(oid, oid, values); + + usleep(1000*1050); + counterVerifyFunc(countersTable, + expectedKey, + {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS"}, + {"100", "200"}); + + // support bulk but counter id changes + values.clear(); + values.emplace_back(PORT_COUNTER_ID_LIST, "SAI_PORT_STAT_IF_IN_OCTETS"); + fc.addCounter(oid, oid, values); + + usleep(1000*1050); + counterVerifyFunc(countersTable, + expectedKey, + {"SAI_PORT_STAT_IF_IN_OCTETS"}, + {"100"}); + + // support bulk with different counter id + sai_object_id_t oid1{0x1000000000001}; + values.clear(); + values.emplace_back(PORT_COUNTER_ID_LIST, "SAI_PORT_STAT_IF_IN_OCTETS,SAI_PORT_STAT_IF_IN_UCAST_PKTS"); + fc.addCounter(oid1, oid1, values); + + usleep(1000*1050); + counterVerifyFunc(countersTable, + toOid(oid1), + {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS"}, + {"100", "200"}); + + // support bulk to not support bulk + values.clear(); + values.emplace_back(PORT_COUNTER_ID_LIST, "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS,SAI_PORT_STAT_IF_IN_UCAST_PKTS"); + fc.addCounter(oid, oid, values); + + usleep(1000*1050); + counterVerifyFunc(countersTable, + expectedKey, + {"SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS"}, + {"10", "20"}); + + // not support bulk but counter id changes + values.clear(); + values.emplace_back(PORT_COUNTER_ID_LIST, "SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS,SAI_PORT_STAT_IF_IN_DISCARDS"); + fc.addCounter(oid, oid, values); + usleep(1000*1050); + counterVerifyFunc(countersTable, + expectedKey, + {"SAI_PORT_STAT_IF_IN_NON_UCAST_PKTS", "SAI_PORT_STAT_IF_IN_DISCARDS"}, + {"10", "20"}); + + // verify oid1 is still using bulk + counterVerifyFunc(countersTable, + toOid(oid1), + {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS"}, + {"100", "200"}); + + fc.removeCounter(oid); + countersTable.del(expectedKey); + fc.removeCounter(oid1); + countersTable.del(toOid(oid1)); +} diff --git a/unittest/vslib/TestSaiUnittests.cpp b/unittest/vslib/TestSaiUnittests.cpp index 9f8653967..e59a1dac5 100644 --- a/unittest/vslib/TestSaiUnittests.cpp +++ b/unittest/vslib/TestSaiUnittests.cpp @@ -183,3 +183,28 @@ TEST(SaiUnittests, channelOpSetStats) usleep(100*1000); } +TEST(SaiUnittests, bulkGetClearStats) +{ + Sai sai; + + sai.initialize(0, &test_services); + + EXPECT_EQ(SAI_STATUS_NOT_IMPLEMENTED, sai.bulkGetStats(SAI_NULL_OBJECT_ID, + SAI_OBJECT_TYPE_PORT, + 0, + nullptr, + 0, + nullptr, + SAI_STATS_MODE_BULK_READ, + nullptr, + nullptr)); + EXPECT_EQ(SAI_STATUS_NOT_IMPLEMENTED, sai.bulkClearStats(SAI_NULL_OBJECT_ID, + SAI_OBJECT_TYPE_PORT, + 0, + nullptr, + 0, + nullptr, + SAI_STATS_MODE_BULK_READ, + nullptr)); +} + diff --git a/unittest/vslib/test_sai_vs_interfacequery.cpp b/unittest/vslib/test_sai_vs_interfacequery.cpp index 0db425ab4..f10592aa9 100644 --- a/unittest/vslib/test_sai_vs_interfacequery.cpp +++ b/unittest/vslib/test_sai_vs_interfacequery.cpp @@ -55,3 +55,28 @@ TEST(libsaivs, sai_switch_id_query) { EXPECT_EQ(SAI_NULL_OBJECT_ID, sai_switch_id_query(SAI_NULL_OBJECT_ID)); } + +TEST(libsaivs, sai_bulk_object_get_stats) +{ + EXPECT_EQ(SAI_STATUS_NOT_IMPLEMENTED, sai_bulk_object_get_stats(SAI_NULL_OBJECT_ID, + SAI_OBJECT_TYPE_PORT, + 0, + nullptr, + 0, + nullptr, + SAI_STATS_MODE_BULK_READ, + nullptr, + nullptr)); +} + +TEST(libsaivs, sai_bulk_object_clear_stats) +{ + EXPECT_EQ(SAI_STATUS_NOT_IMPLEMENTED, sai_bulk_object_clear_stats(SAI_NULL_OBJECT_ID, + SAI_OBJECT_TYPE_PORT, + 0, + nullptr, + 0, + nullptr, + SAI_STATS_MODE_BULK_CLEAR, + nullptr)); +} diff --git a/vslib/Sai.cpp b/vslib/Sai.cpp index 79262ef8f..98d0ed476 100644 --- a/vslib/Sai.cpp +++ b/vslib/Sai.cpp @@ -519,6 +519,41 @@ sai_status_t Sai::clearStats( counter_ids); } +sai_status_t Sai::bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) +{ + MUTEX(); + SWSS_LOG_ENTER(); + VS_CHECK_API_INITIALIZED(); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + +sai_status_t Sai::bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) +{ + MUTEX(); + SWSS_LOG_ENTER(); + VS_CHECK_API_INITIALIZED(); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + // BULK QUAD OID sai_status_t Sai::bulkCreate( diff --git a/vslib/Sai.h b/vslib/Sai.h index 7af8e39c1..11075b6ae 100644 --- a/vslib/Sai.h +++ b/vslib/Sai.h @@ -122,6 +122,27 @@ namespace saivs _In_ uint32_t number_of_counters, _In_ const sai_stat_id_t *counter_ids) override; + virtual sai_status_t bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) override; + + virtual sai_status_t bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) override; + public: // non QUAD API virtual sai_status_t flushFdbEntries( diff --git a/vslib/VirtualSwitchSaiInterface.cpp b/vslib/VirtualSwitchSaiInterface.cpp index 013e2ae06..4e28991bc 100644 --- a/vslib/VirtualSwitchSaiInterface.cpp +++ b/vslib/VirtualSwitchSaiInterface.cpp @@ -961,6 +961,37 @@ sai_status_t VirtualSwitchSaiInterface::clearStats( counters); } +sai_status_t VirtualSwitchSaiInterface::bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) +{ + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + +sai_status_t VirtualSwitchSaiInterface::bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) +{ + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + sai_status_t VirtualSwitchSaiInterface::bulkRemove( _In_ sai_object_id_t switchId, _In_ sai_object_type_t object_type, diff --git a/vslib/VirtualSwitchSaiInterface.h b/vslib/VirtualSwitchSaiInterface.h index dc5d32c27..d868ee59d 100644 --- a/vslib/VirtualSwitchSaiInterface.h +++ b/vslib/VirtualSwitchSaiInterface.h @@ -121,6 +121,27 @@ namespace saivs _In_ uint32_t number_of_counters, _In_ const sai_stat_id_t *counter_ids) override; + virtual sai_status_t bulkGetStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) override; + + virtual sai_status_t bulkClearStats( + _In_ sai_object_id_t switchId, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) override; + public: // non QUAD API virtual sai_status_t flushFdbEntries( diff --git a/vslib/sai_vs_interfacequery.cpp b/vslib/sai_vs_interfacequery.cpp index 8dac01d43..5a0a9ae03 100644 --- a/vslib/sai_vs_interfacequery.cpp +++ b/vslib/sai_vs_interfacequery.cpp @@ -201,3 +201,34 @@ sai_status_t sai_query_api_version( *version = SAI_API_VERSION; return SAI_STATUS_SUCCESS; } + +sai_status_t sai_bulk_object_get_stats( + _In_ sai_object_id_t switch_id, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses, + _Out_ uint64_t *counters) +{ + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; +} + +sai_status_t sai_bulk_object_clear_stats( + _In_ sai_object_id_t switch_id, + _In_ sai_object_type_t object_type, + _In_ uint32_t object_count, + _In_ const sai_object_key_t *object_key, + _In_ uint32_t number_of_counters, + _In_ const sai_stat_id_t *counter_ids, + _In_ sai_stats_mode_t mode, + _Inout_ sai_status_t *object_statuses) +{ + SWSS_LOG_ENTER(); + + return SAI_STATUS_NOT_IMPLEMENTED; +}