diff --git a/syncd/FlexCounter.cpp b/syncd/FlexCounter.cpp index c742c1688..3a37334f0 100644 --- a/syncd/FlexCounter.cpp +++ b/syncd/FlexCounter.cpp @@ -47,6 +47,26 @@ const std::map FlexCounter::m_plugIn2CounterType = { {WRED_QUEUE_PLUGIN_FIELD, COUNTER_TYPE_WRED_ECN_QUEUE}, {WRED_PORT_PLUGIN_FIELD, COUNTER_TYPE_WRED_ECN_PORT}}; +const std::map, std::string> FlexCounter::m_objectTypeField2CounterType = { + {{SAI_OBJECT_TYPE_PORT, PORT_COUNTER_ID_LIST}, COUNTER_TYPE_PORT}, + {{SAI_OBJECT_TYPE_PORT, PORT_DEBUG_COUNTER_ID_LIST}, COUNTER_TYPE_PORT_DEBUG}, + {{SAI_OBJECT_TYPE_QUEUE, QUEUE_COUNTER_ID_LIST}, COUNTER_TYPE_QUEUE}, + {{SAI_OBJECT_TYPE_QUEUE, QUEUE_ATTR_ID_LIST}, ATTR_TYPE_QUEUE}, + {{SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, PG_COUNTER_ID_LIST}, COUNTER_TYPE_PG}, + {{SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, PG_ATTR_ID_LIST}, ATTR_TYPE_PG}, + {{SAI_OBJECT_TYPE_ROUTER_INTERFACE, RIF_COUNTER_ID_LIST}, COUNTER_TYPE_RIF}, + {{SAI_OBJECT_TYPE_SWITCH, SWITCH_DEBUG_COUNTER_ID_LIST}, COUNTER_TYPE_SWITCH_DEBUG}, + {{SAI_OBJECT_TYPE_MACSEC_FLOW, MACSEC_FLOW_COUNTER_ID_LIST}, COUNTER_TYPE_MACSEC_FLOW}, + {{SAI_OBJECT_TYPE_MACSEC_SA, MACSEC_SA_COUNTER_ID_LIST}, COUNTER_TYPE_MACSEC_SA}, + {{SAI_OBJECT_TYPE_MACSEC_SA, MACSEC_SA_ATTR_ID_LIST}, ATTR_TYPE_MACSEC_SA}, + {{SAI_OBJECT_TYPE_ACL_COUNTER, ACL_COUNTER_ATTR_ID_LIST}, ATTR_TYPE_ACL_COUNTER}, + {{SAI_OBJECT_TYPE_COUNTER, FLOW_COUNTER_ID_LIST}, COUNTER_TYPE_FLOW}, + {{SAI_OBJECT_TYPE_POLICER, POLICER_COUNTER_ID_LIST}, COUNTER_TYPE_POLICER}, + {{SAI_OBJECT_TYPE_TUNNEL, TUNNEL_COUNTER_ID_LIST}, COUNTER_TYPE_TUNNEL}, + {{(sai_object_type_t)SAI_OBJECT_TYPE_ENI, ENI_COUNTER_ID_LIST}, COUNTER_TYPE_ENI}, + {{(sai_object_type_t)SAI_OBJECT_TYPE_ENI, DASH_METER_COUNTER_ID_LIST}, COUNTER_TYPE_METER_BUCKET} +}; + BaseCounterContext::BaseCounterContext(const std::string &name, const std::string &instance): m_name(name), m_instanceId(instance) @@ -823,6 +843,172 @@ class CounterContext : public BaseCounterContext } } + virtual void bulkAddObject( + _In_ const std::vector& vids, + _In_ const std::vector& rids, + _In_ const std::vector& idStrings, + _In_ const std::string &per_object_stats_mode) + { + SWSS_LOG_ENTER(); + sai_stats_mode_t instance_stats_mode = SAI_STATS_MODE_READ_AND_CLEAR; + sai_stats_mode_t effective_stats_mode; + // TODO: use if const expression when c++17 is supported + if (HasStatsMode::value) + { + if (per_object_stats_mode == STATS_MODE_READ_AND_CLEAR) + { + instance_stats_mode = SAI_STATS_MODE_READ_AND_CLEAR; + } + else if (per_object_stats_mode == STATS_MODE_READ) + { + instance_stats_mode = SAI_STATS_MODE_READ; + } + else + { + SWSS_LOG_WARN("Stats mode %s not supported for flex counter. Using STATS_MODE_READ_AND_CLEAR", per_object_stats_mode.c_str()); + } + + effective_stats_mode = (m_groupStatsMode == SAI_STATS_MODE_READ_AND_CLEAR || + instance_stats_mode == SAI_STATS_MODE_READ_AND_CLEAR) ? SAI_STATS_MODE_READ_AND_CLEAR : SAI_STATS_MODE_READ; + } + else + { + effective_stats_mode = m_groupStatsMode; + } + + if (HasStatsMode::value) + { + // Bulk operation is not supported by the counter group. + SWSS_LOG_NOTICE("Counter group %s does not support bulk. Fallback to single call", m_name.c_str()); + + // Fall back to old way + for (size_t i = 0; i < vids.size(); i++) + { + auto rid = rids[i]; + auto vid = vids[i]; + addObject(vid, rid, idStrings, per_object_stats_mode); + } + + return; + } + + std::vector allCounterIds, supportedIds; + for (const auto &str : idStrings) + { + StatType stat; + deserializeStat(str.c_str(), &stat); + { + allCounterIds.push_back(stat); + } + } + + updateSupportedCounters(rids[0]/*it is not really used*/, allCounterIds, effective_stats_mode); + for (auto stat : allCounterIds) + { + if (isCounterSupported(stat)) + { + supportedIds.push_back(stat); + } + } + + std::map, std::tuple> bulkUnsupportedCounters; + auto statsMode = m_groupStatsMode == SAI_STATS_MODE_READ ? SAI_STATS_MODE_BULK_READ : SAI_STATS_MODE_BULK_READ_AND_CLEAR; + auto checkAndUpdateBulkCapability = [&](const std::vector &counter_ids, const std::string &prefix, uint32_t bulk_chunk_size) + { + BulkContextType ctx; + ctx.counter_ids = counter_ids; + addBulkStatsContext(vids, rids, counter_ids, ctx); + auto 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 (status == SAI_STATUS_SUCCESS) + { + auto bulkContext = getBulkStatsContext(counter_ids, prefix, bulk_chunk_size); + addBulkStatsContext(vids, rids, counter_ids, *bulkContext.get()); + } + else + { + // Bulk is not supported for this counter prefix + // Append it to bulkUnsupportedCounters + std::tuple value(prefix, bulk_chunk_size); + bulkUnsupportedCounters.emplace(counter_ids, value); + SWSS_LOG_NOTICE("Counters starting with %s do not support bulk. Fallback to single call for these counters", prefix.c_str()); + } + }; + + if (m_counterChunkSizeMapFromPrefix.empty()) + { + std::sort(supportedIds.begin(), supportedIds.end()); + checkAndUpdateBulkCapability(supportedIds, "default", default_bulk_chunk_size); + } + else + { + std::map> counter_prefix_map; + std::vector default_partition; + createCounterBulkChunkSizePerPrefixPartition(supportedIds, counter_prefix_map, default_partition); + + for (auto &counterPrefix : counter_prefix_map) + { + std::sort(counterPrefix.second.begin(), counterPrefix.second.end()); + } + + std::sort(default_partition.begin(), default_partition.end()); + + for (auto &counterPrefix : counter_prefix_map) + { + checkAndUpdateBulkCapability(counterPrefix.second, counterPrefix.first, m_counterChunkSizeMapFromPrefix[counterPrefix.first]); + } + + checkAndUpdateBulkCapability(default_partition, "default", default_bulk_chunk_size); + } + + if (!bulkUnsupportedCounters.empty()) + { + SWSS_LOG_NOTICE("Partial counters do not support bulk. Re-check bulk capability for each object"); + + for (auto &it : bulkUnsupportedCounters) + { + std::vector bulkSupportedRIDs; + std::vector bulkSupportedVIDs; + for (size_t i = 0; i < vids.size(); i++) + { + auto rid = rids[i]; + auto vid = vids[i]; + + if (checkBulkCapability(vid, rid, it.first)) + { + bulkSupportedVIDs.push_back(vid); + bulkSupportedRIDs.push_back(rid); + } + else + { + SWSS_LOG_INFO("Fallback to single call for object 0x%" PRIx64, vid); + 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); + } + } + + if (!bulkSupportedVIDs.empty() && !bulkSupportedRIDs.empty()) + { + auto bulkContext = getBulkStatsContext(it.first, get<0>(it.second), get<1>(it.second)); + addBulkStatsContext(bulkSupportedVIDs, bulkSupportedRIDs, it.first, *bulkContext.get()); + } + } + } + } + void removeObject( _In_ sai_object_id_t vid) override { @@ -842,14 +1028,14 @@ class CounterContext : public BaseCounterContext { m_objectIdsMap.erase(iter); } - else + + // An object can be in both m_objectIdsMap and the bulk context + // when bulk polling is supported by some counter prefixes but unsupported by some others + if (!removeBulkStatsContext(vid) && log) { - 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()); - } + SWSS_LOG_NOTICE("Trying to remove nonexisting %s %s", + sai_serialize_object_type(m_objectType).c_str(), + sai_serialize_object_id(vid).c_str()); } } @@ -1050,7 +1236,8 @@ class CounterContext : public BaseCounterContext ctx.counters.data() + current * ctx.counter_ids.size()); if (SAI_STATUS_SUCCESS != status) { - SWSS_LOG_WARN("Failed to bulk get stats for %s: %u", m_name.c_str(), status); + SWSS_LOG_WARN("Failed to bulk get stats for %s %s %s %s starting object %u bulk chunk size %u: %d", + m_instanceId.c_str(), m_name.c_str(), ctx.name.c_str(), sai_serialize_object_type(m_objectType).c_str(), current, bulk_chunk_size, status); } current += bulk_chunk_size; @@ -1071,7 +1258,7 @@ class CounterContext : public BaseCounterContext { 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]); + SWSS_LOG_ERROR("Failed to get stats of %s 0x%" PRIx64 " 0x%" PRIx64 ": %d", m_name.c_str(), ctx.object_vids[i], ctx.object_keys[i].key.object_id, ctx.object_statuses[i]); continue; } const auto &vid = ctx.object_vids[i]; @@ -1132,6 +1319,23 @@ class CounterContext : public BaseCounterContext ctx.counters.resize(counterIds.size() * ctx.object_keys.size()); } + void addBulkStatsContext( + _In_ const std::vector &vids, + _In_ const std::vector &rids, + _In_ const std::vector& counterIds, + _Inout_ BulkContextType &ctx) + { + SWSS_LOG_ENTER(); + ctx.object_vids.insert(ctx.object_vids.end(), vids.begin(), vids.end()); + transform(rids.begin(), rids.end(), back_inserter(ctx.object_keys), [](sai_object_id_t rid) { + sai_object_key_t key; + key.key.object_id = rid; + return key; + }); + ctx.object_statuses.insert(ctx.object_statuses.end(), vids.size(), SAI_STATUS_SUCCESS); + ctx.counters.resize(counterIds.size() * ctx.object_keys.size()); + } + bool removeBulkStatsContext( _In_ sai_object_id_t vid) { @@ -1357,6 +1561,20 @@ class AttrContext : public CounterContext Base::m_objectIdsMap.emplace(vid, attr_ids); } + void bulkAddObject( + _In_ const std::vector& vids, + _In_ const std::vector& rids, + _In_ const std::vector& idStrings, + _In_ const std::string &per_object_stats_mode) override + { + SWSS_LOG_ENTER(); + + for (auto i = 0uL; i < vids.size(); i++) + { + addObject(vids[i], rids[i], idStrings, per_object_stats_mode); + } + } + void collectData( _In_ swss::Table &countersTable) override { @@ -1529,6 +1747,20 @@ class DashMeterCounterContext : public BaseCounterContext } } + void bulkAddObject( + _In_ const std::vector& vids, + _In_ const std::vector& rids, + _In_ const std::vector& idStrings, + _In_ const std::string &per_object_stats_mode) override + { + SWSS_LOG_ENTER(); + + for (auto i = 0uL; i < vids.size(); i++) + { + addObject(vids[i], rids[i], idStrings, per_object_stats_mode); + } + } + bool hasObject() const override { SWSS_LOG_ENTER(); @@ -2145,7 +2377,15 @@ std::shared_ptr FlexCounter::getCounterContext( return iter->second; } - auto ret = m_counterContext.emplace(name, createCounterContext(name, m_instanceId)); + auto counterContext = createCounterContext(name, m_instanceId); + + if (m_noDoubleCheckBulkCapability) + { + counterContext->setNoDoubleCheckBulkCapability(true); + SWSS_LOG_NOTICE("Do not double check bulk capability counter context %s %s", m_instanceId.c_str(), name.c_str()); + } + + auto ret = m_counterContext.emplace(name, counterContext); return ret.first->second; } @@ -2450,116 +2690,73 @@ void FlexCounter::addCounter( auto idStrings = swss::tokenize(value, ','); - if (objectType == SAI_OBJECT_TYPE_PORT && field == 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( - vid, - rid, - idStrings, - ""); - } - else if (objectType == SAI_OBJECT_TYPE_QUEUE && field == QUEUE_COUNTER_ID_LIST) - { - getCounterContext(COUNTER_TYPE_QUEUE)->addObject( - vid, - rid, - idStrings, - ""); - - } - else if (objectType == SAI_OBJECT_TYPE_QUEUE && field == QUEUE_ATTR_ID_LIST) - { - getCounterContext(ATTR_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( - vid, - rid, - idStrings, - ""); - } - else if (objectType == SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP && field == PG_ATTR_ID_LIST) + const auto &counterGroupRef = m_objectTypeField2CounterType.find({objectType, field}); + if (counterGroupRef != m_objectTypeField2CounterType.end()) { - getCounterContext(ATTR_TYPE_PG)->addObject( + getCounterContext(counterGroupRef->second)->addObject( vid, rid, idStrings, ""); } - else if (objectType == SAI_OBJECT_TYPE_ROUTER_INTERFACE && field == RIF_COUNTER_ID_LIST) - { - getCounterContext(COUNTER_TYPE_RIF)->addObject( - vid, - rid, - idStrings, - ""); - } - else if (objectType == SAI_OBJECT_TYPE_SWITCH && field == SWITCH_DEBUG_COUNTER_ID_LIST) - { - getCounterContext(COUNTER_TYPE_SWITCH_DEBUG)->addObject( - vid, - rid, - idStrings, - ""); - } - else if (objectType == SAI_OBJECT_TYPE_MACSEC_FLOW && field == MACSEC_FLOW_COUNTER_ID_LIST) - { - getCounterContext(COUNTER_TYPE_MACSEC_FLOW)->addObject( - vid, - rid, - idStrings, - ""); - } - else if (objectType == SAI_OBJECT_TYPE_MACSEC_SA && field == MACSEC_SA_COUNTER_ID_LIST) - { - getCounterContext(COUNTER_TYPE_MACSEC_SA)->addObject( - vid, - rid, - idStrings, - ""); - } - else if (objectType == SAI_OBJECT_TYPE_MACSEC_SA && field == MACSEC_SA_ATTR_ID_LIST) + else if (objectType == SAI_OBJECT_TYPE_BUFFER_POOL && field == BUFFER_POOL_COUNTER_ID_LIST) { - getCounterContext(ATTR_TYPE_MACSEC_SA)->addObject( - vid, - rid, - idStrings, - ""); + counterIds = idStrings; } - else if (objectType == SAI_OBJECT_TYPE_ACL_COUNTER && field == ACL_COUNTER_ATTR_ID_LIST) + else if (objectType == SAI_OBJECT_TYPE_BUFFER_POOL && field == STATS_MODE_FIELD) { - getCounterContext(ATTR_TYPE_ACL_COUNTER)->addObject( - vid, - rid, - idStrings, - ""); + statsMode = value; } - else if (objectType == SAI_OBJECT_TYPE_COUNTER && field == FLOW_COUNTER_ID_LIST) + else { - getCounterContext(COUNTER_TYPE_FLOW)->addObject( - vid, - rid, - idStrings, - ""); + SWSS_LOG_ERROR("Object type and field combination is not supported, object type %s, field %s", + sai_serialize_object_type(objectType).c_str(), + field.c_str()); } - else if (objectType == SAI_OBJECT_TYPE_POLICER && field == POLICER_COUNTER_ID_LIST) + } + + // outside loop since required 2 fields BUFFER_POOL_COUNTER_ID_LIST and STATS_MODE_FIELD + + if (objectType == SAI_OBJECT_TYPE_BUFFER_POOL && counterIds.size()) + { + getCounterContext(COUNTER_TYPE_BUFFER_POOL)->addObject( + vid, + rid, + counterIds, + statsMode); + } + + // notify thread to start polling + notifyPoll(); +} + +void FlexCounter::bulkAddCounter( + _In_ sai_object_type_t objectType, + _In_ const std::vector& vids, + _In_ const std::vector& rids, + _In_ const std::vector& values) +{ + MUTEX; + + SWSS_LOG_ENTER(); + + std::vector counterIds; + + std::string statsMode; + + for (const auto& valuePair: values) + { + const auto field = fvField(valuePair); + const auto value = fvValue(valuePair); + + auto idStrings = swss::tokenize(value, ','); + + const auto &counterGroupRef = m_objectTypeField2CounterType.find({objectType, field}); + if (counterGroupRef != m_objectTypeField2CounterType.end()) { - getCounterContext(COUNTER_TYPE_POLICER)->addObject( - vid, - rid, + getCounterContext(counterGroupRef->second)->bulkAddObject( + vids, + rids, idStrings, ""); } @@ -2571,30 +2768,6 @@ void FlexCounter::addCounter( { statsMode = value; } - else if (objectType == SAI_OBJECT_TYPE_TUNNEL && field == TUNNEL_COUNTER_ID_LIST) - { - getCounterContext(COUNTER_TYPE_TUNNEL)->addObject( - vid, - rid, - idStrings, - ""); - } - else if (objectType == (sai_object_type_t)SAI_OBJECT_TYPE_ENI && field == ENI_COUNTER_ID_LIST) - { - getCounterContext(COUNTER_TYPE_ENI)->addObject( - vid, - rid, - idStrings, - ""); - } - else if (objectType == (sai_object_type_t)SAI_OBJECT_TYPE_ENI && field == DASH_METER_COUNTER_ID_LIST) - { - getCounterContext(COUNTER_TYPE_METER_BUCKET)->addObject( - vid, - rid, - idStrings, - ""); - } else { SWSS_LOG_ERROR("Object type and field combination is not supported, object type %s, field %s", @@ -2607,9 +2780,9 @@ void FlexCounter::addCounter( if (objectType == SAI_OBJECT_TYPE_BUFFER_POOL && counterIds.size()) { - getCounterContext(COUNTER_TYPE_BUFFER_POOL)->addObject( - vid, - rid, + getCounterContext(COUNTER_TYPE_BUFFER_POOL)->bulkAddObject( + vids, + rids, counterIds, statsMode); } diff --git a/syncd/FlexCounter.h b/syncd/FlexCounter.h index 9053046bf..5a2191c0b 100644 --- a/syncd/FlexCounter.h +++ b/syncd/FlexCounter.h @@ -43,6 +43,12 @@ namespace syncd _In_ const std::vector &idStrings, _In_ const std::string &per_object_stats_mode) = 0; + virtual void bulkAddObject( + _In_ const std::vector& vids, + _In_ const std::vector& rids, + _In_ const std::vector& idStrings, + _In_ const std::string &per_object_stats_mode) = 0; + virtual void removeObject( _In_ sai_object_id_t vid) = 0; @@ -95,6 +101,12 @@ namespace syncd _In_ sai_object_id_t rid, _In_ const std::vector& values); + void bulkAddCounter( + _In_ sai_object_type_t objectType, + _In_ const std::vector& vids, + _In_ const std::vector& rids, + _In_ const std::vector& values); + void removeCounter( _In_ sai_object_id_t vid); @@ -188,5 +200,7 @@ namespace syncd bool m_noDoubleCheckBulkCapability; static const std::map m_plugIn2CounterType; + + static const std::map, std::string> m_objectTypeField2CounterType; }; } diff --git a/syncd/FlexCounterManager.cpp b/syncd/FlexCounterManager.cpp index 5088a19c5..312d9286f 100644 --- a/syncd/FlexCounterManager.cpp +++ b/syncd/FlexCounterManager.cpp @@ -1,4 +1,5 @@ #include "FlexCounterManager.h" +#include "VidManager.h" #include "swss/logger.h" @@ -100,6 +101,26 @@ void FlexCounterManager::addCounter( } } +void FlexCounterManager::bulkAddCounter( + _In_ const std::vector &vids, + _In_ const std::vector &rids, + _In_ const std::string& instanceId, + _In_ const std::vector& values) +{ + SWSS_LOG_ENTER(); + + auto fc = getInstance(instanceId); + + sai_object_type_t objectType = VidManager::objectTypeQuery(vids.at(0)); // VID and RID will have the same object type + + fc->bulkAddCounter(objectType, vids, rids, values); + + if (fc->isDiscarded()) + { + removeInstance(instanceId); + } +} + void FlexCounterManager::removeCounter( _In_ sai_object_id_t vid, _In_ const std::string& instanceId) diff --git a/syncd/FlexCounterManager.h b/syncd/FlexCounterManager.h index 5ba2f9992..4b50a6ccd 100644 --- a/syncd/FlexCounterManager.h +++ b/syncd/FlexCounterManager.h @@ -38,6 +38,12 @@ namespace syncd _In_ const std::string& instanceId, _In_ const std::vector& values); + void bulkAddCounter( + _In_ const std::vector &vids, + _In_ const std::vector &rids, + _In_ const std::string& instanceId, + _In_ const std::vector& values); + void removeCounter( _In_ sai_object_id_t vid, _In_ const std::string& instanceId); diff --git a/syncd/Syncd.cpp b/syncd/Syncd.cpp index fb82d9878..deeaa7043 100644 --- a/syncd/Syncd.cpp +++ b/syncd/Syncd.cpp @@ -2791,49 +2791,95 @@ sai_status_t Syncd::processFlexCounterEvent( } auto groupName = key.substr(0, delimiter); - auto strVid = key.substr(delimiter + 1); + auto strVids = key.substr(delimiter + 1); + auto vidStringVector = swss::tokenize(strVids, ','); - auto effective_op = op; - - sai_object_id_t vid; - sai_deserialize_object_id(strVid, vid); + if (fromAsicChannel && op == SET_COMMAND && (!vidStringVector.empty())) + { + std::vector vids; + std::vector rids; + std::vector keys; - sai_object_id_t rid; + vids.reserve(vidStringVector.size()); + rids.reserve(vidStringVector.size()); + keys.reserve(vidStringVector.size()); - if (!m_translator->tryTranslateVidToRid(vid, rid)) - { - if (fromAsicChannel) + for (auto &strVid: vidStringVector) { - SWSS_LOG_ERROR("port VID %s, was not found (probably port was removed/splitted) and will remove from counters now", - sai_serialize_object_id(vid).c_str()); + sai_object_id_t vid, rid; + sai_deserialize_object_id(strVid, vid); + vids.emplace_back(vid); + + if (!m_translator->tryTranslateVidToRid(vid, rid)) + { + SWSS_LOG_ERROR("port VID %s, was not found (probably port was removed/splitted) and will remove from counters now", + sai_serialize_object_id(vid).c_str()); + } + + rids.emplace_back(rid); + keys.emplace_back(groupName + ":" + strVid); } - else + + m_manager->bulkAddCounter(vids, rids, groupName, values); + + for (auto &singleKey: keys) { - SWSS_LOG_WARN("port VID %s, was not found (probably port was removed/splitted) and will remove from counters now", - sai_serialize_object_id(vid).c_str()); + m_flexCounterTable->set(singleKey, values); } - effective_op = DEL_COMMAND; - } - if (effective_op == SET_COMMAND) - { - m_manager->addCounter(vid, rid, groupName, values); if (fromAsicChannel) { - m_flexCounterTable->set(key, values); + sendApiResponse(SAI_COMMON_API_SET, SAI_STATUS_SUCCESS); } + + return SAI_STATUS_SUCCESS; } - else if (effective_op == DEL_COMMAND) + + for(auto &strVid : vidStringVector) { - if (fromAsicChannel) + auto effective_op = op; + auto singleKey = groupName + ":" + strVid; + + sai_object_id_t vid; + sai_deserialize_object_id(strVid, vid); + + sai_object_id_t rid; + + if (!m_translator->tryTranslateVidToRid(vid, rid)) { - m_flexCounterTable->del(key); + if (fromAsicChannel) + { + SWSS_LOG_ERROR("port VID %s, was not found (probably port was removed/splitted) and will remove from counters now", + sai_serialize_object_id(vid).c_str()); + } + else + { + SWSS_LOG_WARN("port VID %s, was not found (probably port was removed/splitted) and will remove from counters now", + sai_serialize_object_id(vid).c_str()); + } + effective_op = DEL_COMMAND; + } + + if (effective_op == SET_COMMAND) + { + m_manager->addCounter(vid, rid, groupName, values); + if (fromAsicChannel) + { + m_flexCounterTable->set(singleKey, values); + } + } + else if (effective_op == DEL_COMMAND) + { + if (fromAsicChannel) + { + m_flexCounterTable->del(singleKey); + } + m_manager->removeCounter(vid, groupName); + } + else + { + SWSS_LOG_ERROR("unknown command: %s", op.c_str()); } - m_manager->removeCounter(vid, groupName); - } - else - { - SWSS_LOG_ERROR("unknown command: %s", op.c_str()); } if (fromAsicChannel) diff --git a/syncd/tests/TestSyncdMlnx.cpp b/syncd/tests/TestSyncdMlnx.cpp index 3c0c852c6..ed94b33be 100644 --- a/syncd/tests/TestSyncdMlnx.cpp +++ b/syncd/tests/TestSyncdMlnx.cpp @@ -222,29 +222,40 @@ TEST_F(SyncdMlnxTest, queryAttrEnumValuesCapability) TEST_F(SyncdMlnxTest, portBulkAddRemove) { - const std::uint32_t portCount = 1; + const std::uint32_t portCount = 4; const std::uint32_t laneCount = 4; // Generate port config - std::array laneList = { 1000, 1001, 1002, 1003 }; - sai_attribute_t attr; - std::vector attrList; - - attr.id = SAI_PORT_ATTR_HW_LANE_LIST; - attr.value.u32list.count = static_cast(laneList.size()); - attr.value.u32list.list = laneList.data(); - attrList.push_back(attr); - - attr.id = SAI_PORT_ATTR_SPEED; - attr.value.u32 = 1000; - attrList.push_back(attr); + std::array, portCount> laneLists; + std::array, portCount> attrLists; + std::array attrCountList; + std::array attrPtrList; - std::array attrCountList = { static_cast(attrList.size()) }; - std::array attrPtrList = { attrList.data() }; + uint32_t lane = 1000; + for (auto i = 0u; i < portCount; i++) + { + auto &laneList = laneLists[i]; + auto &attrList = attrLists[i]; + for (auto j = 0u; j < laneCount; j++) + { + laneList.push_back(lane++); + } + attr.id = SAI_PORT_ATTR_HW_LANE_LIST; + attr.value.u32list.count = static_cast(laneList.size()); + attr.value.u32list.list = laneList.data(); + attrList.push_back(attr); + + attr.id = SAI_PORT_ATTR_SPEED; + attr.value.u32 = 1000; + attrList.push_back(attr); + + attrPtrList[i] = attrList.data(); + attrCountList[i] = static_cast(attrList.size()); + } - std::array oidList = { SAI_NULL_OBJECT_ID }; - std::array statusList = { SAI_STATUS_SUCCESS }; + std::vector oidList(portCount, SAI_NULL_OBJECT_ID); + std::vector statusList(portCount, SAI_STATUS_SUCCESS); // Validate port bulk add auto status = m_sairedis->bulkCreate( @@ -334,15 +345,41 @@ TEST_F(SyncdMlnxTest, portBulkAddRemove) fvVectorExpected.emplace_back(counter_field_name, counters); ASSERT_EQ(fvVectorExpected, fvVector); + // Try with bulk initialization + key = "PORT_STAT_COUNTER:"; + for (auto i = 1u; i < portCount; i++) + { + key += sai_serialize_object_id(oidList[i]) + ","; + } + key.pop_back(); + + flexCounterParam.counter_key.list = (int8_t*)const_cast(key.c_str()); + flexCounterParam.counter_key.count = (uint32_t)key.length(); + status = m_sairedis->set(SAI_OBJECT_TYPE_SWITCH, m_switchId, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + + for (auto i = 1u; i < portCount; i++) + { + key = "PORT_STAT_COUNTER:" + sai_serialize_object_id(oidList[i]); + ASSERT_TRUE(m_flexCounterTable->get(key, fvVector)); + ASSERT_EQ(fvVectorExpected, fvVector); + } + flexCounterParam.counter_ids.list = nullptr; flexCounterParam.counter_ids.count = 0; flexCounterParam.counter_field_name.list = nullptr; flexCounterParam.counter_field_name.count = 0; // 3. Stop counter polling for the port - status = m_sairedis->set(SAI_OBJECT_TYPE_SWITCH, m_switchId, &attr); - ASSERT_EQ(status, SAI_STATUS_SUCCESS); - ASSERT_FALSE(m_flexCounterTable->get(key, fvVector)); + for (auto i = 0u; i < portCount; i++) + { + key = "PORT_STAT_COUNTER:" + sai_serialize_object_id(oidList[i]); + flexCounterParam.counter_key.list = (int8_t*)const_cast(key.c_str()); + flexCounterParam.counter_key.count = (uint32_t)key.length(); + status = m_sairedis->set(SAI_OBJECT_TYPE_SWITCH, m_switchId, &attr); + ASSERT_EQ(status, SAI_STATUS_SUCCESS); + ASSERT_FALSE(m_flexCounterTable->get(key, fvVector)); + } // 4. Disable counter polling for the group flexCounterGroupParam.poll_interval.list = nullptr; diff --git a/unittest/syncd/TestFlexCounter.cpp b/unittest/syncd/TestFlexCounter.cpp index 9b70e314b..8ef4119ec 100644 --- a/unittest/syncd/TestFlexCounter.cpp +++ b/unittest/syncd/TestFlexCounter.cpp @@ -86,11 +86,13 @@ void testAddRemoveCounter( VerifyStatsFunc verifyFunc, bool autoRemoveDbEntry, const std::string statsMode = STATS_MODE_READ, + bool bulkAdd = false, const std::string bulkChunkSize = "", const std::string bulkChunkSizePerCounter = "", bool bulkChunkSizeAfterPort = true, const std::string pluginName = "", - bool immediatelyRemoveBulkChunkSizePerCounter = false) + bool immediatelyRemoveBulkChunkSizePerCounter = false, + bool forceSingleCreate = false) { SWSS_LOG_ENTER(); @@ -123,9 +125,25 @@ void testAddRemoveCounter( values.clear(); values.emplace_back(counterIdFieldName, join(counterIdNames)); - for (auto object_id : object_ids) + + if (bulkAdd) { - fc.addCounter(object_id, object_id, values); + fc.bulkAddCounter(object_type, object_ids, object_ids, values); + } + else if (forceSingleCreate) + { + for (auto object_id : object_ids) + { + fc.addCounter(object_id, object_id, values); + } + } + else + { + for (auto object_id : object_ids) + { + std::vector tmp_object_ids = {object_id}; + fc.bulkAddCounter(object_type, tmp_object_ids, tmp_object_ids, values); + } } if (bulkChunkSizeAfterPort) @@ -215,6 +233,18 @@ TEST(FlexCounter, addRemoveCounter) counterVerifyFunc, true); + // Bulk create mode to satisfy the coverage requirement + testAddRemoveCounter( + 1, + SAI_OBJECT_TYPE_COUNTER, + FLOW_COUNTER_ID_LIST, + {"SAI_COUNTER_STAT_PACKETS", "SAI_COUNTER_STAT_BYTES"}, + {"100", "200"}, + counterVerifyFunc, + true, + STATS_MODE_READ, + true); + testAddRemoveCounter( 1, SAI_OBJECT_TYPE_MACSEC_FLOW, @@ -224,6 +254,18 @@ TEST(FlexCounter, addRemoveCounter) counterVerifyFunc, false); + // Bulk create mode to satisfy the coverage requirement + testAddRemoveCounter( + 1, + 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, + STATS_MODE_READ, + true); + testAddRemoveCounter( 1, SAI_OBJECT_TYPE_MACSEC_SA, @@ -233,6 +275,18 @@ TEST(FlexCounter, addRemoveCounter) counterVerifyFunc, false); + // Bulk create mode to satisfy the coverage requirement + testAddRemoveCounter( + 1, + 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, + STATS_MODE_READ, + true); + testAddRemoveCounter( 1, SAI_OBJECT_TYPE_PORT, @@ -251,6 +305,18 @@ TEST(FlexCounter, addRemoveCounter) counterVerifyFunc, false); + // Bulk create mode to satisfy the coverage requirement + testAddRemoveCounter( + 1, + 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, + STATS_MODE_READ, + true); + bool clearCalled = false; 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) { clearCalled = true; @@ -268,6 +334,19 @@ TEST(FlexCounter, addRemoveCounter) STATS_MODE_READ_AND_CLEAR); EXPECT_EQ(true, clearCalled); + // Bulk create mode to satisfy the coverage requirement + testAddRemoveCounter( + 1, + 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, + true); + EXPECT_EQ(true, clearCalled); + testAddRemoveCounter( 1, SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, @@ -277,6 +356,18 @@ TEST(FlexCounter, addRemoveCounter) counterVerifyFunc, false); + // Bulk create mode to satisfy the coverage requirement + testAddRemoveCounter( + 1, + 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, + STATS_MODE_READ, + true); + testAddRemoveCounter( 1, SAI_OBJECT_TYPE_ROUTER_INTERFACE, @@ -286,6 +377,18 @@ TEST(FlexCounter, addRemoveCounter) counterVerifyFunc, false); + // Bulk create mode to satisfy the coverage requirement + testAddRemoveCounter( + 1, + 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, + STATS_MODE_READ, + true); + testAddRemoveCounter( 1, SAI_OBJECT_TYPE_SWITCH, @@ -295,6 +398,18 @@ TEST(FlexCounter, addRemoveCounter) counterVerifyFunc, false); + // Bulk create mode to satisfy the coverage requirement + testAddRemoveCounter( + 1, + 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, + STATS_MODE_READ, + true); + testAddRemoveCounter( 1, SAI_OBJECT_TYPE_TUNNEL, @@ -304,6 +419,18 @@ TEST(FlexCounter, addRemoveCounter) counterVerifyFunc, false); + // Bulk create mode to satisfy the coverage requirement + testAddRemoveCounter( + 1, + SAI_OBJECT_TYPE_TUNNEL, + TUNNEL_COUNTER_ID_LIST, + {"SAI_TUNNEL_STAT_IN_OCTETS", "SAI_TUNNEL_STAT_IN_PACKETS"}, + {"100", "200"}, + counterVerifyFunc, + false, + STATS_MODE_READ, + true); + testAddRemoveCounter( 1, (sai_object_type_t)SAI_OBJECT_TYPE_ENI, @@ -344,6 +471,18 @@ TEST(FlexCounter, addRemoveCounter) counterVerifyFunc, false); + // Bulk create mode to satisfy the coverage requirement + testAddRemoveCounter( + 1, + SAI_OBJECT_TYPE_QUEUE, + QUEUE_ATTR_ID_LIST, + {"SAI_QUEUE_ATTR_PAUSE_STATUS"}, + {"false"}, + counterVerifyFunc, + false, + STATS_MODE_READ, + true); + sai->mock_get = [] (sai_object_type_t objectType, sai_object_id_t objectId, uint32_t attr_count, sai_attribute_t *attr_list) { for (uint32_t i = 0; i < attr_count; i++) { @@ -364,6 +503,18 @@ TEST(FlexCounter, addRemoveCounter) counterVerifyFunc, false); + // Bulk create mode to satisfy the coverage requirement + testAddRemoveCounter( + 1, + SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, + PG_ATTR_ID_LIST, + {"SAI_INGRESS_PRIORITY_GROUP_ATTR_PORT"}, + {"oid:0x1"}, + counterVerifyFunc, + false, + STATS_MODE_READ, + true); + sai->mock_get = [] (sai_object_type_t objectType, sai_object_id_t objectId, uint32_t attr_count, sai_attribute_t *attr_list) { for (uint32_t i = 0; i < attr_count; i++) { @@ -388,6 +539,18 @@ TEST(FlexCounter, addRemoveCounter) counterVerifyFunc, false); + // Bulk create mode to satisfy the coverage requirement + testAddRemoveCounter( + 1, + SAI_OBJECT_TYPE_MACSEC_SA, + MACSEC_SA_ATTR_ID_LIST, + {"SAI_MACSEC_SA_ATTR_CONFIGURED_EGRESS_XPN", "SAI_MACSEC_SA_ATTR_AN"}, + {"0", "1"}, + counterVerifyFunc, + false, + STATS_MODE_READ, + true); + sai->mock_get = [] (sai_object_type_t objectType, sai_object_id_t objectId, uint32_t attr_count, sai_attribute_t *attr_list) { for (uint32_t i = 0; i < attr_count; i++) { @@ -407,6 +570,18 @@ TEST(FlexCounter, addRemoveCounter) {"1000"}, counterVerifyFunc, false); + + // Bulk create mode to satisfy the coverage requirement + testAddRemoveCounter( + 1, + SAI_OBJECT_TYPE_ACL_COUNTER, + ACL_COUNTER_ATTR_ID_LIST, + {"SAI_ACL_COUNTER_ATTR_PACKETS"}, + {"1000"}, + counterVerifyFunc, + false, + STATS_MODE_READ, + true); } TEST(FlexCounter, queryCounterCapability) @@ -802,13 +977,28 @@ TEST(FlexCounter, bulkChunksize) * and verify whether the database content aligns with the stored values * 3. Verify whether values of all counter IDs of all objects have been generated * 4. Verify whether the bulk chunk size is correct + * 5. Simulate bulk-unsupported counter IDs which should be fetched by single call + * with both per counter bulk size supported or not + * + * A counter can be polled in initialization phase and runtime + * For each test, it is expected to call bulk for "initialCheckCount" times during initialization. + * In this stage, the mock function just return succeed for failure to indicate whether bulk poll is supported + * but it does not provide a counter value for further check + * + * The calls to bulk starting from "initialCheckCount+1" are treated as runtime calls. + * The counter values objects are generated as following: + * - a counterSeed maintains the current counter value to return + * - If the counterValuesMap[object_id][counter_id] exists, returns it as the counter's value + * - Otherwise, it's the first time the (object, counter ID) is polled + * - return the current value of counterSeed as the counter's value + * - store the counter's value into counterValuesMap + * - increase the counterSeed + * When the test finishes, the counterSeed should equal (number_of_objects * number_of_bulk_supported_counters) + * And all integer < counterSeed should be returned to one and only one (object, counter ID) tuple, + * which can be verified by the verify function. + * + * For the bulk-unsupported counters, getStatExt will be called to poll counters, and return counter_id * OID as the counter's value */ - 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) { - 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) { - 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; @@ -853,10 +1043,45 @@ TEST(FlexCounter, bulkChunksize) } }; + // Bulk-unsupported counter IDs should be polled using single call (getStatExt) + std::set bulkUnsupportedCounters; + std::set bulkUnsupportedObjectIds; + bool forceSingleCall = false; + // > + auto _getStatsExt = [&](sai_object_type_t, sai_object_id_t oid, uint32_t number_of_counters, const sai_stat_id_t *counter_ids, sai_stats_mode_t, uint64_t *counters) { + for (auto i = 0u; i < number_of_counters; i++) + { + if (forceSingleCall + || (bulkUnsupportedCounters.find(counter_ids[i]) != bulkUnsupportedCounters.end() + && (bulkUnsupportedObjectIds.empty() || bulkUnsupportedObjectIds.find(oid) != bulkUnsupportedObjectIds.end()))) + { + // avoid counter_id == 0 which causes the same counter value (0) for all objects + counters[i] = (1 + counter_ids[i]) * (uint64_t)oid; + if (counterValuesMap.find(oid) == counterValuesMap.end()) + { + counterValuesMap[oid] = {}; + } + counterValuesMap[oid][counter_ids[i]] = counters[i]; + } + } + return SAI_STATUS_SUCCESS; + }; + + sai->mock_getStats = [&](sai_object_type_t type, sai_object_id_t oid, uint32_t number_of_counters, const sai_stat_id_t *counter_ids, uint64_t *counters) { + return _getStatsExt(type, oid, number_of_counters, counter_ids, SAI_STATS_MODE_READ, counters); + }; + + sai->mock_getStatsExt = [&](sai_object_type_t type, sai_object_id_t oid, uint32_t number_of_counters, const sai_stat_id_t *counter_ids, sai_stats_mode_t mode, uint64_t *counters) { + return _getStatsExt(type, oid, number_of_counters, counter_ids, mode, counters); + }; + std::vector> counterRecord; std::vector> valueRecord; sai_uint64_t counterSeed = 0; + // non zero unifiedBulkChunkSize indicates all counter IDs share the same bulk chunk size uint32_t unifiedBulkChunkSize = 0; + int32_t initialCheckCount; + int32_t partialSupportingBulkObjectFactor; sai->mock_bulkGetStats = [&](sai_object_id_t, sai_object_type_t, uint32_t object_count, @@ -870,12 +1095,36 @@ TEST(FlexCounter, bulkChunksize) EXPECT_TRUE(mode == SAI_STATS_MODE_BULK_READ); std::vector record; std::vector value; - if (number_of_counters >= 5 && object_count == 1) + if (initialCheckCount-- > 0) { allObjectIds.insert(toOid(object_keys[0].key.object_id)); // This call is to check whether bulk counter polling is supported during initialization + if (!bulkUnsupportedCounters.empty()) + { + // Simulate counters that are not supported being polled in bulk mode + for (auto i = 0u; i < number_of_counters; i++) + { + if (bulkUnsupportedCounters.find(counter_ids[i]) != bulkUnsupportedCounters.end()) + { + if (partialSupportingBulkObjectFactor != 0) + { + for(auto j = 0u; j < object_count; j++) + { + if (j % partialSupportingBulkObjectFactor == 0) + { + bulkUnsupportedObjectIds.insert(object_keys[j].key.object_id); + } + } + } + return SAI_STATUS_FAILURE; + } + } + } return SAI_STATUS_SUCCESS; } + + EXPECT_TRUE(!forceSingleCall); + for (uint32_t i = 0; i < object_count; i++) { object_status[i] = SAI_STATUS_SUCCESS; @@ -894,7 +1143,7 @@ TEST(FlexCounter, bulkChunksize) { if (object_count != unifiedBulkChunkSize) { - EXPECT_EQ(object_count, unifiedBulkChunkSize); + EXPECT_EQ(object_count, unifiedBulkChunkSize); } continue; } @@ -945,6 +1194,8 @@ TEST(FlexCounter, bulkChunksize) allObjectIds.erase(key); }; + // create ports first and then set bulk chunk size + per counter bulk chunk size + initialCheckCount = 6; testAddRemoveCounter( 6, SAI_OBJECT_TYPE_PORT, @@ -954,10 +1205,13 @@ TEST(FlexCounter, bulkChunksize) counterVerifyFunc, false, STATS_MODE_READ, + false, "3", "SAI_PORT_STAT_IF_OUT_QLEN:0;SAI_PORT_STAT_IF_IN_FEC:2"); EXPECT_TRUE(allObjectIds.empty()); + // set bulk chunk size + per counter bulk chunk size first and then create ports + initialCheckCount = 6; testAddRemoveCounter( 6, SAI_OBJECT_TYPE_PORT, @@ -967,13 +1221,20 @@ TEST(FlexCounter, bulkChunksize) counterVerifyFunc, false, STATS_MODE_READ, + false, "3", "SAI_PORT_STAT_IF_OUT_QLEN:0;SAI_PORT_STAT_IF_IN_FEC:2", false, - PORT_PLUGIN_FIELD); + PORT_PLUGIN_FIELD, + false, + true); EXPECT_TRUE(allObjectIds.empty()); + // Remove per counter bulk chunk size after initializing it + // This is to cover the scenario of removing per counter bulk chunk size filed + // All counters share a unified bulk chunk size unifiedBulkChunkSize = 3; + initialCheckCount = 6; testAddRemoveCounter( 6, SAI_OBJECT_TYPE_PORT, @@ -983,12 +1244,115 @@ TEST(FlexCounter, bulkChunksize) counterVerifyFunc, false, STATS_MODE_READ, + false, "3", "SAI_PORT_STAT_IF_OUT_QLEN:0;SAI_PORT_STAT_IF_IN_FEC:2", true, "", true); EXPECT_TRUE(allObjectIds.empty()); + unifiedBulkChunkSize = 0; + + // add ports counters in bulk mode first and then set bulk chunk size + per counter bulk chunk size + initialCheckCount = 3; + testAddRemoveCounter( + 6, + SAI_OBJECT_TYPE_PORT, + PORT_COUNTER_ID_LIST, + {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS", "SAI_PORT_STAT_IF_OUT_QLEN", "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES", "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES"}, + {}, + counterVerifyFunc, + false, + STATS_MODE_READ, + true, + "3", + "SAI_PORT_STAT_IF_OUT_QLEN:0;SAI_PORT_STAT_IF_IN_FEC:2"); + EXPECT_TRUE(allObjectIds.empty()); + + // set bulk chunk size + per counter bulk chunk size first and then add ports counters in bulk mode + initialCheckCount = 3; + testAddRemoveCounter( + 6, + SAI_OBJECT_TYPE_PORT, + PORT_COUNTER_ID_LIST, + {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS", "SAI_PORT_STAT_IF_OUT_QLEN", "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES", "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES"}, + {}, + counterVerifyFunc, + false, + STATS_MODE_READ, + true, + "3", + "SAI_PORT_STAT_IF_OUT_QLEN:0;SAI_PORT_STAT_IF_IN_FEC:2", + false, + PORT_PLUGIN_FIELD); + EXPECT_TRUE(allObjectIds.empty()); + + // add ports counters in bulk mode with some bulk-unsupported counters first and then set bulk chunk size + per counter bulk chunk size + // all counters will be polled using single call in runtime + forceSingleCall = true; + initialCheckCount = 1; // check bulk for all counter IDs altogether + initialCheckCount += 6; // for bulk unsupported counter prefix, check bulk again for each objects + bulkUnsupportedCounters = { + SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES, + SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES + }; + testAddRemoveCounter( + 6, + SAI_OBJECT_TYPE_PORT, + PORT_COUNTER_ID_LIST, + {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS", "SAI_PORT_STAT_IF_OUT_QLEN", "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES", "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES"}, + {}, + counterVerifyFunc, + false, + STATS_MODE_READ, + true, + "3", + "SAI_PORT_STAT_IF_OUT_QLEN:0;SAI_PORT_STAT_IF_IN_FEC:2"); + EXPECT_TRUE(allObjectIds.empty()); + forceSingleCall = false; + + // set bulk chunk size + per counter bulk chunk size first and then add ports counters in bulk mode with some bulk-unsupported counters + // All bulk-unsupported counters are polled using single call and all the rest counters are polled using bulk call + // For each OID, it will be in both m_bulkContexts and m_objectIdsMap + initialCheckCount = 3; // check bulk for 3 prefixes + initialCheckCount += 6; // for bulk unsupported counter prefix, check bulk again for each objects + testAddRemoveCounter( + 6, + SAI_OBJECT_TYPE_PORT, + PORT_COUNTER_ID_LIST, + {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS", "SAI_PORT_STAT_IF_OUT_QLEN", "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES", "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES"}, + {}, + counterVerifyFunc, + false, + STATS_MODE_READ, + true, + "3", + "SAI_PORT_STAT_IF_OUT_QLEN:0;SAI_PORT_STAT_IF_IN_FEC:2", + false, + PORT_PLUGIN_FIELD); + EXPECT_TRUE(allObjectIds.empty()); + + // set bulk chunk size + per counter bulk chunk size first and then add ports counters in bulk mode with some bulk-unsupported counters + // All bulk-unsupported counters are polled using single call and all the rest counters are polled using bulk call + // For each OID, it will be in both m_bulkContexts and m_objectIdsMap + initialCheckCount = 3; // check bulk for 3 prefixes + initialCheckCount += 6; // for bulk unsupported counter prefix, check bulk again for each objects + partialSupportingBulkObjectFactor = 2; + testAddRemoveCounter( + 6, + SAI_OBJECT_TYPE_PORT, + PORT_COUNTER_ID_LIST, + {"SAI_PORT_STAT_IF_IN_OCTETS", "SAI_PORT_STAT_IF_IN_UCAST_PKTS", "SAI_PORT_STAT_IF_OUT_QLEN", "SAI_PORT_STAT_IF_IN_FEC_CORRECTABLE_FRAMES", "SAI_PORT_STAT_IF_IN_FEC_NOT_CORRECTABLE_FRAMES"}, + {}, + counterVerifyFunc, + false, + STATS_MODE_READ, + true, + "3", + "SAI_PORT_STAT_IF_OUT_QLEN:0;SAI_PORT_STAT_IF_IN_FEC:2", + false, + PORT_PLUGIN_FIELD); + EXPECT_TRUE(allObjectIds.empty()); } TEST(FlexCounter, counterIdChange)