diff --git a/syncd/FlexCounter.cpp b/syncd/FlexCounter.cpp index 356668ab0..23655433e 100644 --- a/syncd/FlexCounter.cpp +++ b/syncd/FlexCounter.cpp @@ -15,3098 +15,1278 @@ using namespace std; #define MUTEX std::unique_lock _lock(m_mtx); #define MUTEX_UNLOCK _lock.unlock(); -FlexCounter::FlexCounter( - _In_ const std::string& instanceId, - _In_ std::shared_ptr vendorSai, - _In_ const std::string& dbCounters): - m_readyToPoll(false), - m_pollInterval(0), - m_instanceId(instanceId), - m_vendorSai(vendorSai), - m_dbCounters(dbCounters) +static const std::string COUNTER_TYPE_PORT = "Port Counter"; +static const std::string COUNTER_TYPE_PORT_DEBUG = "Port Debug Counter"; +static const std::string COUNTER_TYPE_QUEUE = "Queue Counter"; +static const std::string COUNTER_TYPE_PG = "Priority Group Counter"; +static const std::string COUNTER_TYPE_RIF = "Rif Counter"; +static const std::string COUNTER_TYPE_SWITCH_DEBUG = "Switch Debug Counter"; +static const std::string COUNTER_TYPE_MACSEC_FLOW = "MACSEC Flow Counter"; +static const std::string COUNTER_TYPE_MACSEC_SA = "MACSEC SA Counter"; +static const std::string COUNTER_TYPE_FLOW = "Flow Counter"; +static const std::string COUNTER_TYPE_TUNNEL = "Tunnel Counter"; +static const std::string COUNTER_TYPE_BUFFER_POOL = "Buffer Pool Counter"; +static const std::string ATTR_TYPE_QUEUE = "Queue Attribute"; +static const std::string ATTR_TYPE_PG = "Priority Group Attribute"; +static const std::string ATTR_TYPE_MACSEC_SA = "MACSEC SA Attribute"; +static const std::string ATTR_TYPE_ACL_COUNTER = "ACL Counter Attribute"; + +BaseCounterContext::BaseCounterContext(const std::string &name): +m_name(name) { SWSS_LOG_ENTER(); - - m_enable = false; - m_isDiscarded = false; - - startFlexCounterThread(); } -FlexCounter::~FlexCounter(void) +void BaseCounterContext::addPlugins( + _In_ const std::vector& shaStrings) { SWSS_LOG_ENTER(); - endFlexCounterThread(); + for (const auto &sha : shaStrings) + { + auto ret = m_plugins.insert(sha); + if (ret.second) + { + SWSS_LOG_NOTICE("%s counters plugin %s registered", m_name.c_str(), sha.c_str()); + } + else + { + SWSS_LOG_ERROR("Plugin %s already registered", sha.c_str()); + } + } } -FlexCounter::PortCounterIds::PortCounterIds( - _In_ sai_object_id_t port, - _In_ const std::vector &portIds): - portId(port), portCounterIds(portIds) +template +struct CounterIds +{ + CounterIds( + _In_ sai_object_id_t id, + _In_ const std::vector &ids + ): rid(id), counter_ids(ids) {} + void setStatsMode(sai_stats_mode_t statsMode) {} + sai_stats_mode_t getStatsMode() const + { + SWSS_LOG_ENTER(); + SWSS_LOG_THROW("This counter type has no stats mode field"); + // GCC 8.3 requires a return value here + return SAI_STATS_MODE_READ_AND_CLEAR; + } + sai_object_id_t rid; + std::vector counter_ids; +}; + +// CounterIds structure contains stats mode, now buffer pool is the only one +// has member stats_mode. +template +struct CounterIds::value> > +{ + CounterIds( + _In_ sai_object_id_t id, + _In_ const std::vector &ids + ): rid(id), counter_ids(ids) + { + SWSS_LOG_ENTER(); + } + + void setStatsMode(sai_stats_mode_t statsMode) + { + SWSS_LOG_ENTER(); + stats_mode = statsMode; + } + + sai_stats_mode_t getStatsMode() const + { + SWSS_LOG_ENTER(); + return stats_mode; + } + sai_object_id_t rid; + std::vector counter_ids; + sai_stats_mode_t stats_mode; +}; + +template +struct HasStatsMode +{ + template + static void check(decltype(&U::stats_mode)); + template + static int check(...); + + enum { value = std::is_void(0))>::value }; +}; + +// TODO: use if const expression when cpp17 is supported +template +std::string serializeStat( + _In_ const StatType stat) { SWSS_LOG_ENTER(); + SWSS_LOG_THROW("serializeStat for default type parameter is not implemented"); + // GCC 8.3 requires a return value here + return ""; } -FlexCounter::SwitchCounterIds::SwitchCounterIds( - _In_ sai_object_id_t oid, - _In_ const std::vector &counterIds) - : switchId(oid), - switchCounterIds(counterIds) +template <> +std::string serializeStat( + _In_ const sai_port_stat_t stat) { SWSS_LOG_ENTER(); + return sai_serialize_port_stat(stat); } -FlexCounter::QueueCounterIds::QueueCounterIds( - _In_ sai_object_id_t queue, - _In_ const std::vector &queueIds): - queueId(queue), queueCounterIds(queueIds) +template <> +std::string serializeStat( + _In_ const sai_queue_stat_t stat) { SWSS_LOG_ENTER(); + return sai_serialize_queue_stat(stat); } -FlexCounter::QueueAttrIds::QueueAttrIds( - _In_ sai_object_id_t queue, - _In_ const std::vector &queueIds): - queueId(queue), queueAttrIds(queueIds) +template <> +std::string serializeStat( + _In_ const sai_ingress_priority_group_stat_t stat) { SWSS_LOG_ENTER(); + return sai_serialize_ingress_priority_group_stat(stat); } -FlexCounter::IngressPriorityGroupAttrIds::IngressPriorityGroupAttrIds( - _In_ sai_object_id_t priorityGroup, - _In_ const std::vector &priorityGroupIds): - priorityGroupId(priorityGroup), priorityGroupAttrIds(priorityGroupIds) +template <> +std::string serializeStat( + _In_ const sai_router_interface_stat_t stat) { SWSS_LOG_ENTER(); + return sai_serialize_router_interface_stat(stat); } -FlexCounter::IngressPriorityGroupCounterIds::IngressPriorityGroupCounterIds( - _In_ sai_object_id_t priorityGroup, - _In_ const std::vector &priorityGroupIds): - priorityGroupId(priorityGroup), priorityGroupCounterIds(priorityGroupIds) +template <> +std::string serializeStat( + _In_ const sai_switch_stat_t stat) { SWSS_LOG_ENTER(); + return sai_serialize_switch_stat(stat); } -FlexCounter::RifCounterIds::RifCounterIds( - _In_ sai_object_id_t rif, - _In_ const std::vector &rifIds): - rifId(rif), rifCounterIds(rifIds) +template <> +std::string serializeStat( + _In_ const sai_macsec_flow_stat_t stat) { SWSS_LOG_ENTER(); + return sai_serialize_macsec_flow_stat(stat); } -FlexCounter::BufferPoolCounterIds::BufferPoolCounterIds( - _In_ sai_object_id_t bufferPool, - _In_ const std::vector &bufferPoolIds, - _In_ sai_stats_mode_t statsMode): - bufferPoolId(bufferPool), bufferPoolStatsMode(statsMode), bufferPoolCounterIds(bufferPoolIds) +template <> +std::string serializeStat( + _In_ const sai_macsec_sa_stat_t stat) { SWSS_LOG_ENTER(); + return sai_serialize_macsec_sa_stat(stat); } -FlexCounter::MACsecFlowCounterIds::MACsecFlowCounterIds( - _In_ sai_object_id_t macsecFlow, - _In_ const std::vector &macsecFlowIds): - m_macsecFlowId(macsecFlow), - m_macsecFlowCounterIds(macsecFlowIds) +template <> +std::string serializeStat( + _In_ const sai_counter_stat_t stat) { SWSS_LOG_ENTER(); + return sai_serialize_counter_stat(stat); } -FlexCounter::MACsecSACounterIds::MACsecSACounterIds( - _In_ sai_object_id_t macsecSA, - _In_ const std::vector &macsecSAIds): - m_macsecSAId(macsecSA), - m_macsecSACounterIds(macsecSAIds) +template <> +std::string serializeStat( + _In_ const sai_tunnel_stat_t stat) { SWSS_LOG_ENTER(); + return sai_serialize_tunnel_stat(stat); } -FlexCounter::MACsecSAAttrIds::MACsecSAAttrIds( - _In_ sai_object_id_t macsecSA, - _In_ const std::vector &macsecSAIds): - m_macsecSAId(macsecSA), - m_macsecSAAttrIds(macsecSAIds) +template <> +std::string serializeStat( + _In_ const sai_buffer_pool_stat_t stat) { SWSS_LOG_ENTER(); - // empty intentionally + return sai_serialize_buffer_pool_stat(stat); } -FlexCounter::AclCounterAttrIds::AclCounterAttrIds( - _In_ sai_object_id_t aclCounter, - _In_ const std::vector &aclCounterIds): - m_aclCounterId(aclCounter), - m_aclCounterAttrIds(aclCounterIds) +template +void deserializeStat( + _In_ const char* name, + _Out_ StatType *stat) { SWSS_LOG_ENTER(); + SWSS_LOG_THROW("deserializeStat for default type parameter is not implemented"); } -FlexCounter::TunnelCounterIds::TunnelCounterIds( - _In_ sai_object_id_t tunnelRid, - _In_ const std::vector &tunnelIds): - m_tunnelId(tunnelRid), - m_tunnelCounterIds(tunnelIds) +template <> +void deserializeStat( + _In_ const char* name, + _Out_ sai_port_stat_t *stat) { SWSS_LOG_ENTER(); - // empty intentionally + sai_deserialize_port_stat(name, stat); } -FlexCounter::FlowCounterIds::FlowCounterIds( - _In_ sai_object_id_t counter, - _In_ const std::vector &flowCounters): - counterId(counter), - flowCounterIds(flowCounters) +template <> +void deserializeStat( + _In_ const char* name, + _Out_ sai_queue_stat_t *stat) { SWSS_LOG_ENTER(); - // empty intentionally + sai_deserialize_queue_stat(name, stat); } -void FlexCounter::setPollInterval( - _In_ uint32_t pollInterval) +template <> +void deserializeStat( + _In_ const char* name, + _Out_ sai_ingress_priority_group_stat_t *stat) { SWSS_LOG_ENTER(); - - m_pollInterval = pollInterval; + sai_deserialize_ingress_priority_group_stat(name, stat); } -void FlexCounter::setStatus( - _In_ const std::string& status) +template <> +void deserializeStat( + _In_ const char* name, + _Out_ sai_router_interface_stat_t *stat) { SWSS_LOG_ENTER(); + sai_deserialize_router_interface_stat(name, stat); +} - if (status == "enable") - { - m_enable = true; - } - else if (status == "disable") - { - m_enable = false; - } - else - { - SWSS_LOG_WARN("Input value %s is not supported for Flex counter status, enter enable or disable", status.c_str()); - } +template <> +void deserializeStat( + _In_ const char* name, + _Out_ sai_switch_stat_t *stat) +{ + SWSS_LOG_ENTER(); + sai_deserialize_switch_stat(name, stat); } -void FlexCounter::setStatsMode( - _In_ const std::string& mode) +template <> +void deserializeStat( + _In_ const char* name, + _Out_ sai_macsec_flow_stat_t *stat) { SWSS_LOG_ENTER(); + sai_deserialize_macsec_flow_stat(name, stat); +} - if (mode == STATS_MODE_READ) - { - m_statsMode = SAI_STATS_MODE_READ; +template <> +void deserializeStat( + _In_ const char* name, + _Out_ sai_macsec_sa_stat_t *stat) +{ + SWSS_LOG_ENTER(); + sai_deserialize_macsec_sa_stat(name, stat); +} - SWSS_LOG_DEBUG("Set STATS MODE %s for FC %s", mode.c_str(), m_instanceId.c_str()); - } - else if (mode == STATS_MODE_READ_AND_CLEAR) - { - m_statsMode = SAI_STATS_MODE_READ_AND_CLEAR; +template <> +void deserializeStat( + _In_ const char* name, + _Out_ sai_counter_stat_t *stat) +{ + SWSS_LOG_ENTER(); + sai_deserialize_counter_stat(name, stat); +} - SWSS_LOG_DEBUG("Set STATS MODE %s for FC %s", mode.c_str(), m_instanceId.c_str()); - } - else - { - SWSS_LOG_WARN("Input value %s is not supported for Flex counter stats mode, enter STATS_MODE_READ or STATS_MODE_READ_AND_CLEAR", mode.c_str()); - } +template <> +void deserializeStat( + _In_ const char* name, + _Out_ sai_tunnel_stat_t *stat) +{ + SWSS_LOG_ENTER(); + sai_deserialize_tunnel_stat(name, stat); } -void FlexCounter::addCollectCountersHandler(const std::string &key, const collect_counters_handler_t &handler) +template <> +void deserializeStat( + _In_ const char* name, + _Out_ sai_buffer_pool_stat_t *stat) { SWSS_LOG_ENTER(); + sai_deserialize_buffer_pool_stat(name, stat); +} - m_collectCountersHandlers.emplace(key, handler); +template +void deserializeAttr( + _In_ const std::string& name, + _Out_ AttrType &attr) +{ + SWSS_LOG_ENTER(); + SWSS_LOG_THROW("deserializeAttr for default type parameter is not implemented"); } -void FlexCounter::removeCollectCountersHandler(const std::string &key) +template <> +void deserializeAttr( + _In_ const std::string& name, + _Out_ sai_queue_attr_t &attr) { SWSS_LOG_ENTER(); + sai_deserialize_queue_attr(name, attr); +} - m_collectCountersHandlers.erase(key); +template <> +void deserializeAttr( + _In_ const std::string& name, + _Out_ sai_ingress_priority_group_attr_t &attr) +{ + SWSS_LOG_ENTER(); + sai_deserialize_ingress_priority_group_attr(name, attr); } -/* The current implementation of 'setPortCounterList' and 'setQueueCounterList' are - * not the same. Need to refactor these two functions to have the similar logic. - * Either the full SAI attributes are queried once, or each of the needed counters - * will be queried when they are set. - */ -void FlexCounter::setPortCounterList( - _In_ sai_object_id_t portVid, - _In_ sai_object_id_t portId, - _In_ const std::vector &counterIds) +template <> +void deserializeAttr( + _In_ const std::string& name, + _Out_ sai_macsec_sa_attr_t &attr) { SWSS_LOG_ENTER(); + sai_deserialize_macsec_sa_attr(name, attr); +} - PortCountersSet supportedPortCounters; - updateSupportedPortCounters(portId, supportedPortCounters); +template <> +void deserializeAttr( + _In_ const std::string& name, + _Out_ sai_acl_counter_attr_t &attr) +{ + SWSS_LOG_ENTER(); + sai_deserialize_acl_counter_attr(name, attr); +} - // Remove unsupported counters - std::vector supportedIds; +template +class CounterContext : public BaseCounterContext +{ +public: + typedef CounterIds CounterIdsType; - for (auto &counter : counterIds) + CounterContext( + _In_ const std::string &name, + _In_ sai_object_type_t object_type, + _In_ sairedis::SaiInterface *vendor_sai, + _In_ sai_stats_mode_t &stats_mode): + BaseCounterContext(name), m_objectType(object_type), m_vendorSai(vendor_sai), m_groupStatsMode(stats_mode) { - if (supportedPortCounters.count(counter) != 0) - { - supportedIds.push_back(counter); - } + SWSS_LOG_ENTER(); } - if (supportedIds.size() == 0) + // For those object type who support per object stats mode, e.g. buffer pool. + virtual void addObject( + _In_ sai_object_id_t vid, + _In_ sai_object_id_t rid, + _In_ const std::vector &idStrings, + _In_ const std::string &per_object_stats_mode) override { - SWSS_LOG_NOTICE("Port %s does not has supported counters", sai_serialize_object_id(portId).c_str()); - return; - } + 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()); + } - auto it = m_portCounterIdsMap.find(portVid); + 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 (it != m_portCounterIdsMap.end()) - { - it->second->portCounterIds = supportedIds; - return; - } + std::vector counter_ids; + for (const auto &str : idStrings) + { + StatType stat; + deserializeStat(str.c_str(), &stat); + counter_ids.push_back(stat); + } - auto portCounterIds = std::make_shared(portId, supportedIds); + updateSupportedCounters(rid, counter_ids, effective_stats_mode); - m_portCounterIdsMap.emplace(portVid, portCounterIds); + std::vector supportedIds; + for (auto &counter : counter_ids) + { + if (isCounterSupported(counter)) + { + supportedIds.push_back(counter); + } + } - addCollectCountersHandler(PORT_COUNTER_ID_LIST, &FlexCounter::collectPortCounters); -} + if (supportedIds.empty()) + { + SWSS_LOG_NOTICE("%s %s does not has supported counters", m_name.c_str(), sai_serialize_object_id(rid).c_str()); + return; + } -void FlexCounter::setPortDebugCounterList( - _In_ sai_object_id_t portVid, - _In_ sai_object_id_t portId, - _In_ const std::vector &counterIds) -{ - SWSS_LOG_ENTER(); + if (double_confirm_supported_counters) + { + std::vector stats(supportedIds.size()); + if (!collectData(rid, supportedIds, effective_stats_mode, false, stats)) + { + SWSS_LOG_ERROR("%s RID %s can't provide the statistic", m_name.c_str(), sai_serialize_object_id(rid).c_str()); + return; + } + } - // Because debug counters can be added and removed over time, we currently - // check that the provided list of counters is valid every time. - auto supportedIds = saiCheckSupportedPortDebugCounters(portId, counterIds); + auto it = m_objectIdsMap.find(vid); + if (it != m_objectIdsMap.end()) + { + it->second->counter_ids = supportedIds; + return; + } - if (supportedIds.size() == 0) - { - SWSS_LOG_NOTICE("Port %s does not have supported debug counters", sai_serialize_object_id(portId).c_str()); - return; + 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); } - auto it = m_portDebugCounterIdsMap.find(portVid); - - if (it != m_portDebugCounterIdsMap.end()) + void removeObject( + _In_ sai_object_id_t vid) override { - it->second->portCounterIds = supportedIds; - return; - } + SWSS_LOG_ENTER(); - auto portDebugCounterIds = std::make_shared(portId, supportedIds); + auto iter = m_objectIdsMap.find(vid); + if (iter != m_objectIdsMap.end()) + { + m_objectIdsMap.erase(iter); + } + 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()); + } + } - m_portDebugCounterIdsMap.emplace(portVid, portDebugCounterIds); + virtual void collectData( + _In_ swss::Table &countersTable) override + { + SWSS_LOG_ENTER(); + sai_stats_mode_t effective_stats_mode = m_groupStatsMode; + for (const auto &kv : m_objectIdsMap) + { + const auto &vid = kv.first; + const auto &rid = kv.second->rid; + const auto &statIds = kv.second->counter_ids; - addCollectCountersHandler(PORT_DEBUG_COUNTER_ID_LIST, &FlexCounter::collectPortDebugCounters); -} + // TODO: use if const expression when cpp17 is supported + if (HasStatsMode::value) + { + effective_stats_mode = (m_groupStatsMode == SAI_STATS_MODE_READ_AND_CLEAR || + kv.second->getStatsMode() == SAI_STATS_MODE_READ_AND_CLEAR) ? SAI_STATS_MODE_READ_AND_CLEAR : SAI_STATS_MODE_READ; + } -void FlexCounter::setQueueCounterList( - _In_ sai_object_id_t queueVid, - _In_ sai_object_id_t queueRid, - _In_ const std::vector &counterIds) -{ - SWSS_LOG_ENTER(); + std::vector stats(statIds.size()); + if (!collectData(rid, statIds, effective_stats_mode, true, stats)) + { + continue; + } - updateSupportedQueueCounters(queueRid, counterIds); + std::vector values; + for (size_t i = 0; i != statIds.size(); i++) + { + values.emplace_back(serializeStat(statIds[i]), std::to_string(stats[i])); + } + countersTable.set(sai_serialize_object_id(vid), values, ""); + } + } - // Remove unsupported counters - std::vector supportedIds; - for (auto &counter : counterIds) + void runPlugin( + _In_ swss::DBConnector& counters_db, + _In_ const std::vector& argv) override { - if (isQueueCounterSupported(counter)) + SWSS_LOG_ENTER(); + + if (m_objectIdsMap.empty()) { - supportedIds.push_back(counter); + 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); }); + std::for_each(m_plugins.begin(), + m_plugins.end(), + [&] (auto &sha) { runRedisScript(counters_db, sha, idStrings, argv); }); } - if (supportedIds.size() == 0) + bool hasObject() const override { - SWSS_LOG_NOTICE("%s: queue %s does not has supported counters", m_instanceId.c_str(), sai_serialize_object_id(queueRid).c_str()); - return; + SWSS_LOG_ENTER(); + return !m_objectIdsMap.empty(); } - // Check if queue is able to provide the statistic - std::vector queueStats(supportedIds.size()); - - sai_status_t status = m_vendorSai->getStats( - SAI_OBJECT_TYPE_QUEUE, - queueRid, - static_cast(supportedIds.size()), - (const sai_stat_id_t *)supportedIds.data(), - queueStats.data()); - - if (status != SAI_STATUS_SUCCESS) +private: + bool isCounterSupported(_In_ StatType counter) const { - SWSS_LOG_ERROR("Queue RID %s can't provide the statistic", sai_serialize_object_id(queueRid).c_str()); - return; + SWSS_LOG_ENTER(); + return m_supportedCounters.count(counter) != 0; } - auto it = m_queueCounterIdsMap.find(queueVid); - - if (it != m_queueCounterIdsMap.end()) + bool collectData( + _In_ sai_object_id_t rid, + _In_ const std::vector &counter_ids, + _In_ sai_stats_mode_t stats_mode, + _In_ bool log_err, + _Out_ std::vector &stats) { - it->second->queueCounterIds = supportedIds; - return; - } - - auto queueCounterIds = std::make_shared(queueRid, supportedIds); - - m_queueCounterIdsMap.emplace(queueVid, queueCounterIds); - - addCollectCountersHandler(QUEUE_COUNTER_ID_LIST, &FlexCounter::collectQueueCounters); -} + SWSS_LOG_ENTER(); + sai_status_t status; + if (!use_sai_stats_ext) + { + status = m_vendorSai->getStats( + m_objectType, + rid, + static_cast(counter_ids.size()), + (const sai_stat_id_t *)counter_ids.data(), + stats.data()); -void FlexCounter::setQueueAttrList( - _In_ sai_object_id_t queueVid, - _In_ sai_object_id_t queueRid, - _In_ const std::vector &attrIds) -{ - SWSS_LOG_ENTER(); + if (status != SAI_STATUS_SUCCESS) + { + if (log_err) + SWSS_LOG_ERROR("Failed to get stats of %s 0x%" PRIx64 ": %d", m_name.c_str(), rid, status); + else + SWSS_LOG_INFO("Failed to get stats of %s 0x%" PRIx64 ": %d", m_name.c_str(), rid, status); + return false; + } - auto it = m_queueAttrIdsMap.find(queueVid); + if (stats_mode == SAI_STATS_MODE_READ_AND_CLEAR) + { + status = m_vendorSai->clearStats( + m_objectType, + rid, + static_cast(counter_ids.size()), + reinterpret_cast(counter_ids.data())); + if (status != SAI_STATUS_SUCCESS) + { + if (log_err) + { + SWSS_LOG_ERROR("%s: failed to clear stats %s, rv: %s", + m_name.c_str(), + sai_serialize_object_id(rid).c_str(), + sai_serialize_status(status).c_str()); + } + else + { + SWSS_LOG_INFO("%s: failed to clear stats %s, rv: %s", + m_name.c_str(), + sai_serialize_object_id(rid).c_str(), + sai_serialize_status(status).c_str()); + } + return false; + } + } + } + else + { + status = m_vendorSai->getStatsExt( + m_objectType, + rid, + static_cast(counter_ids.size()), + reinterpret_cast(counter_ids.data()), + stats_mode, + stats.data()); + if (status != SAI_STATUS_SUCCESS) + { + if (log_err) + { + SWSS_LOG_ERROR("Failed to get stats of %s 0x%" PRIx64 ": %d", m_name.c_str(), rid, status); + } + else + { + SWSS_LOG_INFO("Failed to get stats of %s 0x%" PRIx64 ": %d", m_name.c_str(), rid, status); + } + return false; + } + } - if (it != m_queueAttrIdsMap.end()) - { - it->second->queueAttrIds = attrIds; - return; + return true; } - auto queueAttrIds = std::make_shared(queueRid, attrIds); - - m_queueAttrIdsMap.emplace(queueVid, queueAttrIds); + void updateSupportedCounters( + _In_ sai_object_id_t rid, + _In_ const std::vector& counter_ids, + _In_ sai_stats_mode_t stats_mode) + { + SWSS_LOG_ENTER(); + if (!m_supportedCounters.empty() && !always_check_supported_counters) + { + SWSS_LOG_NOTICE("Ignore checking of supported counters"); + return; + } - addCollectCountersHandler(QUEUE_ATTR_ID_LIST, &FlexCounter::collectQueueAttrs); -} + if (always_check_supported_counters) + { + m_supportedCounters.clear(); + } -void FlexCounter::setPriorityGroupCounterList( - _In_ sai_object_id_t priorityGroupVid, - _In_ sai_object_id_t priorityGroupRid, - _In_ const std::vector &counterIds) -{ - SWSS_LOG_ENTER(); + if (!use_sai_stats_capa_query || querySupportedCounters(rid, stats_mode) != SAI_STATUS_SUCCESS) + { + /* Fallback to legacy approach */ + getSupportedCounters(rid, counter_ids, stats_mode); + } + } - updateSupportedPriorityGroupCounters(priorityGroupRid, counterIds); + sai_status_t querySupportedCounters( + _In_ sai_object_id_t rid, + _In_ sai_stats_mode_t stats_mode) + { + SWSS_LOG_ENTER(); + sai_stat_capability_list_t stats_capability; + stats_capability.count = 0; + stats_capability.list = nullptr; - // Remove unsupported counters - std::vector supportedIds; + /* First call is to check the size needed to allocate */ + sai_status_t status = m_vendorSai->queryStatsCapability( + rid, + m_objectType, + &stats_capability); - for (auto &counter : counterIds) - { - if (isPriorityGroupCounterSupported(counter)) + /* Second call is for query statistics capability */ + if (status == SAI_STATUS_BUFFER_OVERFLOW) { - supportedIds.push_back(counter); + std::vector statCapabilityList(stats_capability.count); + stats_capability.list = statCapabilityList.data(); + status = m_vendorSai->queryStatsCapability( + rid, + m_objectType, + &stats_capability); + + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_INFO("Unable to get %s supported counters for %s", + m_name.c_str(), + sai_serialize_object_id(rid).c_str()); + } + else + { + for (auto statCapability: statCapabilityList) + { + auto currentStatModes = statCapability.stat_modes; + if (!(currentStatModes & stats_mode)) + { + continue; + } + + StatType counter = static_cast(statCapability.stat_enum); + m_supportedCounters.insert(counter); + } + } } + return status; } - if (supportedIds.size() == 0) + void getSupportedCounters( + _In_ sai_object_id_t rid, + _In_ const std::vector& counter_ids, + _In_ sai_stats_mode_t stats_mode) { - SWSS_LOG_NOTICE("%s: priority group %s does not have supported counters", - m_instanceId.c_str(), - sai_serialize_object_id(priorityGroupRid).c_str()); - return; - } + SWSS_LOG_ENTER(); + std::vector values(1); - // Check if PG is able to provide the statistic - std::vector priorityGroupStats(supportedIds.size()); + for (const auto &counter : counter_ids) + { + if (isCounterSupported(counter)) + { + continue; + } - sai_status_t status = m_vendorSai->getStats( - SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, - priorityGroupRid, - static_cast(supportedIds.size()), - (const sai_stat_id_t *)supportedIds.data(), - priorityGroupStats.data()); + std::vector tmp_counter_ids {counter}; + if (!collectData(rid, tmp_counter_ids, stats_mode, false, values)) + { + continue; + } - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Priority group %s can't provide the statistic", sai_serialize_object_id(priorityGroupRid).c_str()); - return; + m_supportedCounters.insert(counter); + } } - auto it = m_priorityGroupCounterIdsMap.find(priorityGroupVid); +protected: + sai_object_type_t m_objectType; + sairedis::SaiInterface *m_vendorSai; + sai_stats_mode_t& m_groupStatsMode; + std::set m_supportedCounters; + std::map> m_objectIdsMap; +}; - if (it != m_priorityGroupCounterIdsMap.end()) +template +class AttrContext : public CounterContext +{ +public: + typedef CounterIds AttrIdsType; + typedef CounterContext Base; + AttrContext( + _In_ const std::string &name, + _In_ sai_object_type_t object_type, + _In_ sairedis::SaiInterface *vendor_sai, + _In_ sai_stats_mode_t &stats_mode): + CounterContext(name, object_type, vendor_sai, stats_mode) { - it->second->priorityGroupCounterIds = supportedIds; - return; + SWSS_LOG_ENTER(); } - auto priorityGroupCounterIds = std::make_shared(priorityGroupRid, supportedIds); - - m_priorityGroupCounterIdsMap.emplace(priorityGroupVid, priorityGroupCounterIds); + void addObject( + _In_ sai_object_id_t vid, + _In_ sai_object_id_t rid, + _In_ const std::vector &idStrings, + _In_ const std::string &per_object_stats_mode) override + { + SWSS_LOG_ENTER(); - addCollectCountersHandler(PG_COUNTER_ID_LIST, &FlexCounter::collectPriorityGroupCounters); -} + std::vector attrIds; -void FlexCounter::setSwitchDebugCounterList( - _In_ sai_object_id_t switchVid, - _In_ sai_object_id_t switchRid, - _In_ const std::vector &counterIds) -{ - SWSS_LOG_ENTER(); + for (const auto &str : idStrings) + { + AttrType attr; + deserializeAttr(str, attr); + attrIds.push_back(attr); + } - // Because debug counters can be added and removed over time, we currently - // check that the provided list of counters is valid every time. - std::vector supportedIds = saiCheckSupportedSwitchDebugCounters(switchRid, counterIds); + auto it = Base::m_objectIdsMap.find(vid); + if (it != Base::m_objectIdsMap.end()) + { + it->second->counter_ids = attrIds; + return; + } - if (supportedIds.size() == 0) - { - SWSS_LOG_NOTICE("Switch %s does not have supported debug counters", sai_serialize_object_id(switchRid).c_str()); - return; + auto attr_ids = std::make_shared(rid, attrIds); + Base::m_objectIdsMap.emplace(vid, attr_ids); } - auto it = m_switchDebugCounterIdsMap.find(switchVid); - - if (it != m_switchDebugCounterIdsMap.end()) + void collectData( + _In_ swss::Table &countersTable) override { - it->second->switchCounterIds = supportedIds; - return; - } + SWSS_LOG_ENTER(); - auto switchDebugCounterIds = std::make_shared(switchRid, supportedIds); + for (const auto &kv : Base::m_objectIdsMap) + { + const auto &vid = kv.first; + const auto &rid = kv.second->rid; + const auto &attrIds = kv.second->counter_ids; - m_switchDebugCounterIdsMap.emplace(switchVid, switchDebugCounterIds); + std::vector attrs(attrIds.size()); + for (size_t i = 0; i < attrIds.size(); i++) + { + attrs[i].id = attrIds[i]; + } - addCollectCountersHandler(SWITCH_DEBUG_COUNTER_ID_LIST, &FlexCounter::collectSwitchDebugCounters); -} + // Get attr + sai_status_t status = Base::m_vendorSai->get( + Base::m_objectType, + rid, + static_cast(attrIds.size()), + attrs.data()); -void FlexCounter::setMACsecFlowCounterList( - _In_ sai_object_id_t macsecFlowVid, - _In_ sai_object_id_t macsecFlowRid, - _In_ const std::vector &counterIds) -{ - SWSS_LOG_ENTER(); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to get attr of %s 0x%" PRIx64 ": %d", + sai_serialize_object_type(Base::m_objectType).c_str(), vid, status); + continue; + } - auto it = m_macsecFlowCounterIdsMap.find(macsecFlowVid); - - if (it != m_macsecFlowCounterIdsMap.end()) - { - it->second->m_macsecFlowCounterIds = counterIds; - return; - } - - auto macsecFlowCounterIds = std::make_shared(macsecFlowRid, counterIds); - - m_macsecFlowCounterIdsMap.emplace(macsecFlowVid, macsecFlowCounterIds); - - addCollectCountersHandler(MACSEC_FLOW_COUNTER_ID_LIST, &FlexCounter::collectMACsecFlowCounters); -} - -void FlexCounter::setMACsecSACounterList( - _In_ sai_object_id_t macsecSAVid, - _In_ sai_object_id_t macsecSARid, - _In_ const std::vector &counterIds) -{ - SWSS_LOG_ENTER(); - - auto it = m_macsecSACounterIdsMap.find(macsecSAVid); - - if (it != m_macsecSACounterIdsMap.end()) - { - it->second->m_macsecSACounterIds = counterIds; - return; - } - - auto macsecSACounterIds = std::make_shared(macsecSARid, counterIds); - - m_macsecSACounterIdsMap.emplace(macsecSAVid, macsecSACounterIds); - - addCollectCountersHandler(MACSEC_SA_COUNTER_ID_LIST, &FlexCounter::collectMACsecSACounters); -} - -void FlexCounter::setPriorityGroupAttrList( - _In_ sai_object_id_t priorityGroupVid, - _In_ sai_object_id_t priorityGroupRid, - _In_ const std::vector &attrIds) -{ - SWSS_LOG_ENTER(); - - auto it = m_priorityGroupAttrIdsMap.find(priorityGroupVid); - - if (it != m_priorityGroupAttrIdsMap.end()) - { - it->second->priorityGroupAttrIds = attrIds; - return; + std::vector values; + for (size_t i = 0; i != attrIds.size(); i++) + { + auto meta = sai_metadata_get_attr_metadata(Base::m_objectType, attrs[i].id); + if (!meta) + { + SWSS_LOG_THROW("Failed to get metadata for %s", sai_serialize_object_type(Base::m_objectType).c_str()); + } + values.emplace_back(meta->attridname, sai_serialize_attr_value(*meta, attrs[i])); + } + countersTable.set(sai_serialize_object_id(vid), values, ""); + } } +}; - auto priorityGroupAttrIds = std::make_shared(priorityGroupRid, attrIds); - - m_priorityGroupAttrIdsMap.emplace(priorityGroupVid, priorityGroupAttrIds); - - addCollectCountersHandler(PG_ATTR_ID_LIST, &FlexCounter::collectPriorityGroupAttrs); -} - -void FlexCounter::setMACsecSAAttrList( - _In_ sai_object_id_t macsecSAVid, - _In_ sai_object_id_t macsecSARid, - _In_ const std::vector &attrIds) +FlexCounter::FlexCounter( + _In_ const std::string& instanceId, + _In_ std::shared_ptr vendorSai, + _In_ const std::string& dbCounters): + m_readyToPoll(false), + m_pollInterval(0), + m_instanceId(instanceId), + m_vendorSai(vendorSai), + m_dbCounters(dbCounters) { SWSS_LOG_ENTER(); - auto it = m_macsecSAAttrIdsMap.find(macsecSAVid); - - if (it != m_macsecSAAttrIdsMap.end()) - { - it->second->m_macsecSAAttrIds = attrIds; - return; - } - - auto macsecSAAttrIds = std::make_shared(macsecSARid, attrIds); - - m_macsecSAAttrIdsMap.emplace(macsecSAVid, macsecSAAttrIds); + m_enable = false; + m_isDiscarded = false; - addCollectCountersHandler(MACSEC_SA_ATTR_ID_LIST, &FlexCounter::collectMACsecSAAttrs); + startFlexCounterThread(); } -void FlexCounter::setAclCounterAttrList( - _In_ sai_object_id_t aclCounterVid, - _In_ sai_object_id_t aclCounterRid, - _In_ const std::vector &attrIds) +FlexCounter::~FlexCounter(void) { SWSS_LOG_ENTER(); - auto it = m_aclCounterAttrIdsMap.find(aclCounterVid); - - if (it != m_aclCounterAttrIdsMap.end()) - { - it->second->m_aclCounterAttrIds = attrIds; - return; - } - - auto aclCounterAttrIds = std::make_shared(aclCounterRid, attrIds); - - m_aclCounterAttrIdsMap.emplace(aclCounterVid, aclCounterAttrIds); - - addCollectCountersHandler(ACL_COUNTER_ATTR_ID_LIST, &FlexCounter::collectAclCounterAttrs); + endFlexCounterThread(); } -void FlexCounter::setRifCounterList( - _In_ sai_object_id_t rifVid, - _In_ sai_object_id_t rifRid, - _In_ const std::vector &counterIds) +void FlexCounter::setPollInterval( + _In_ uint32_t pollInterval) { SWSS_LOG_ENTER(); - updateSupportedRifCounters(rifRid); - - // Remove unsupported counters - std::vector supportedIds; - - for (auto &counter : counterIds) - { - if (isRifCounterSupported(counter)) - { - supportedIds.push_back(counter); - } - } - - if (supportedIds.empty()) - { - SWSS_LOG_NOTICE("Router interface %s does not have supported counters", sai_serialize_object_id(rifRid).c_str()); - return; - } - - auto it = m_rifCounterIdsMap.find(rifVid); - - if (it != m_rifCounterIdsMap.end()) - { - it->second->rifCounterIds = supportedIds; - return; - } - - auto rifCounterIds = std::make_shared(rifRid, supportedIds); - - m_rifCounterIdsMap.emplace(rifVid, rifCounterIds); - - addCollectCountersHandler(RIF_COUNTER_ID_LIST, &FlexCounter::collectRifCounters); + m_pollInterval = pollInterval; } -void FlexCounter::setBufferPoolCounterList( - _In_ sai_object_id_t bufferPoolVid, - _In_ sai_object_id_t bufferPoolId, - _In_ const std::vector &counterIds, - _In_ const std::string &statsMode) +void FlexCounter::setStatus( + _In_ const std::string& status) { SWSS_LOG_ENTER(); - sai_stats_mode_t bufferPoolStatsMode = SAI_STATS_MODE_READ_AND_CLEAR; - - if (statsMode == STATS_MODE_READ_AND_CLEAR) + if (status == "enable") { - bufferPoolStatsMode = SAI_STATS_MODE_READ_AND_CLEAR; + m_enable = true; } - else if (statsMode == STATS_MODE_READ) + else if (status == "disable") { - bufferPoolStatsMode = SAI_STATS_MODE_READ; + m_enable = false; } else { - SWSS_LOG_WARN("Stats mode %s not supported for flex counter. Using STATS_MODE_READ_AND_CLEAR", statsMode.c_str()); - } - - updateSupportedBufferPoolCounters(bufferPoolId, counterIds, bufferPoolStatsMode); - - // Filter unsupported counters - std::vector supportedIds; - - for (auto counterId : counterIds) - { - if (isBufferPoolCounterSupported(counterId)) - { - supportedIds.push_back(counterId); - } - } - - if (supportedIds.size() == 0) - { - SWSS_LOG_NOTICE("Buffer pool %s does not has supported counters", sai_serialize_object_id(bufferPoolId).c_str()); - return; - } - - auto it = m_bufferPoolCounterIdsMap.find(bufferPoolVid); - - if (it != m_bufferPoolCounterIdsMap.end()) - { - it->second->bufferPoolCounterIds = supportedIds; - return; + SWSS_LOG_WARN("Input value %s is not supported for Flex counter status, enter enable or disable", status.c_str()); } - - auto bufferPoolCounterIds = std::make_shared(bufferPoolId, supportedIds, bufferPoolStatsMode); - - m_bufferPoolCounterIdsMap.emplace(bufferPoolVid, bufferPoolCounterIds); - - addCollectCountersHandler(BUFFER_POOL_COUNTER_ID_LIST, &FlexCounter::collectBufferPoolCounters); } -void FlexCounter::setTunnelCounterList( - _In_ sai_object_id_t tunnelVid, - _In_ sai_object_id_t tunnelRid, - _In_ const std::vector &counterIds) +void FlexCounter::setStatsMode( + _In_ const std::string& mode) { SWSS_LOG_ENTER(); - updateSupportedTunnelCounters(tunnelRid, counterIds); - - // Remove unsupported counters - std::vector supportedIds; - - for (auto &counter : counterIds) - { - if (isTunnelCounterSupported(counter)) - { - supportedIds.push_back(counter); - } - } - - if (supportedIds.empty()) + if (mode == STATS_MODE_READ) { - SWSS_LOG_NOTICE("Tunnel %s does not have supported counters", sai_serialize_object_id(tunnelRid).c_str()); - return; - } - - auto it = m_tunnelCounterIdsMap.find(tunnelVid); + m_statsMode = SAI_STATS_MODE_READ; - if (it != m_tunnelCounterIdsMap.end()) - { - it->second->m_tunnelCounterIds = supportedIds; - return; + SWSS_LOG_DEBUG("Set STATS MODE %s for FC %s", mode.c_str(), m_instanceId.c_str()); } - - auto tunnelCounterIds = std::make_shared(tunnelRid, supportedIds); - - m_tunnelCounterIdsMap.emplace(tunnelVid, tunnelCounterIds); - - addCollectCountersHandler(TUNNEL_COUNTER_ID_LIST, &FlexCounter::collectTunnelCounters); -} - -void FlexCounter::setFlowCounterList( - _In_ sai_object_id_t counterVid, - _In_ sai_object_id_t counterRid, - _In_ const std::vector& counterIds) -{ - SWSS_LOG_ENTER(); - - updateSupportedFlowCounters(counterRid, counterIds); - - std::vector supportedIds; - for (auto &counter : counterIds) + else if (mode == STATS_MODE_READ_AND_CLEAR) { - if (m_supportedFlowCounters.count(counter) != 0) - { - supportedIds.push_back(counter); - } - } + m_statsMode = SAI_STATS_MODE_READ_AND_CLEAR; - if (supportedIds.empty()) - { - SWSS_LOG_NOTICE("Flow counter %s does not have supported counters", sai_serialize_object_id(counterRid).c_str()); - return; + SWSS_LOG_DEBUG("Set STATS MODE %s for FC %s", mode.c_str(), m_instanceId.c_str()); } - - auto it = m_flowCounterIdsMap.find(counterVid); - if (it != m_flowCounterIdsMap.end()) + else { - it->second->flowCounterIds = supportedIds; - return; + SWSS_LOG_WARN("Input value %s is not supported for Flex counter stats mode, enter STATS_MODE_READ or STATS_MODE_READ_AND_CLEAR", mode.c_str()); } - - auto flowCounterIds = std::make_shared(counterRid, supportedIds); - - m_flowCounterIdsMap.emplace(counterVid, flowCounterIds); - - addCollectCountersHandler(FLOW_COUNTER_ID_LIST, &FlexCounter::collectFlowCounters); } -void FlexCounter::removePort( - _In_ sai_object_id_t portVid) +void FlexCounter::removeDataFromCountersDB( + _In_ sai_object_id_t vid, + _In_ const std::string &ratePrefix) { SWSS_LOG_ENTER(); + swss::DBConnector db(m_dbCounters, 0); + swss::RedisPipeline pipeline(&db); + swss::Table countersTable(&pipeline, COUNTERS_TABLE, false); - auto it = m_portCounterIdsMap.find(portVid); - - if (it == m_portCounterIdsMap.end()) - { - SWSS_LOG_NOTICE("Trying to remove nonexisting port %s", - sai_serialize_object_id(portVid).c_str()); - return; - } - - m_portCounterIdsMap.erase(it); - - if (m_portCounterIdsMap.empty()) + std::string vidStr = sai_serialize_object_id(vid); + countersTable.del(vidStr); + if (!ratePrefix.empty()) { - removeCollectCountersHandler(PORT_COUNTER_ID_LIST); + swss::Table ratesTable(&pipeline, RATES_TABLE, false); + ratesTable.del(vidStr); + ratesTable.del(vidStr + ratePrefix); } } -void FlexCounter::removePortDebugCounters( - _In_ sai_object_id_t portVid) +void FlexCounter::removeCounterPlugins() { - SWSS_LOG_ENTER(); + MUTEX; - auto it = m_portDebugCounterIdsMap.find(portVid); + SWSS_LOG_ENTER(); - if (it == m_portDebugCounterIdsMap.end()) + for (const auto &kv : m_counterContext) { - SWSS_LOG_NOTICE("Trying to remove nonexisting port debug counter %s", - sai_serialize_object_id(portVid).c_str()); - return; + kv.second->removePlugins(); } - m_portDebugCounterIdsMap.erase(it); - - if (m_portDebugCounterIdsMap.empty()) - { - removeCollectCountersHandler(PORT_DEBUG_COUNTER_ID_LIST); - } + m_isDiscarded = true; } -void FlexCounter::removeQueue( - _In_ sai_object_id_t queueVid) +void FlexCounter::addCounterPlugin( + _In_ const std::vector& values) { - SWSS_LOG_ENTER(); + MUTEX; - bool found = false; + SWSS_LOG_ENTER(); - auto counterIter = m_queueCounterIdsMap.find(queueVid); + m_isDiscarded = false; - if (counterIter != m_queueCounterIdsMap.end()) + for (auto& fvt: values) { - m_queueCounterIdsMap.erase(counterIter); + auto& field = fvField(fvt); + auto& value = fvValue(fvt); - if (m_queueCounterIdsMap.empty()) + auto shaStrings = swss::tokenize(value, ','); + + if (field == POLL_INTERVAL_FIELD) { - removeCollectCountersHandler(QUEUE_COUNTER_ID_LIST); + setPollInterval(stoi(value)); } - - found = true; - } - - auto attrIter = m_queueAttrIdsMap.find(queueVid); - - if (attrIter != m_queueAttrIdsMap.end()) - { - m_queueAttrIdsMap.erase(attrIter); - - if (m_queueAttrIdsMap.empty()) + else if (field == FLEX_COUNTER_STATUS_FIELD) + { + setStatus(value); + } + else if (field == STATS_MODE_FIELD) { - removeCollectCountersHandler(QUEUE_ATTR_ID_LIST); + setStatsMode(value); } - - found = true; - } - - if (!found) - { - SWSS_LOG_NOTICE("Trying to remove nonexisting queue %s", - sai_serialize_object_id(queueVid).c_str()); - } -} - -void FlexCounter::removePriorityGroup( - _In_ sai_object_id_t priorityGroupVid) -{ - SWSS_LOG_ENTER(); - - bool found = false; - - auto counterIter = m_priorityGroupCounterIdsMap.find(priorityGroupVid); - - if (counterIter != m_priorityGroupCounterIdsMap.end()) - { - m_priorityGroupCounterIdsMap.erase(counterIter); - - if (m_priorityGroupCounterIdsMap.empty()) + else if (field == QUEUE_PLUGIN_FIELD) { - removeCollectCountersHandler(PG_COUNTER_ID_LIST); + getCounterContext(COUNTER_TYPE_QUEUE)->addPlugins(shaStrings); } - - found = true; - } - - auto attrIter = m_priorityGroupAttrIdsMap.find(priorityGroupVid); - - if (attrIter != m_priorityGroupAttrIdsMap.end()) - { - m_priorityGroupAttrIdsMap.erase(attrIter); - - if (m_priorityGroupAttrIdsMap.empty()) + else if (field == PG_PLUGIN_FIELD) { - removeCollectCountersHandler(PG_ATTR_ID_LIST); + getCounterContext(COUNTER_TYPE_PG)->addPlugins(shaStrings); + } + else if (field == PORT_PLUGIN_FIELD) + { + getCounterContext(COUNTER_TYPE_PORT)->addPlugins(shaStrings); + } + else if (field == RIF_PLUGIN_FIELD) + { + getCounterContext(COUNTER_TYPE_RIF)->addPlugins(shaStrings); + } + else if (field == BUFFER_POOL_PLUGIN_FIELD) + { + getCounterContext(COUNTER_TYPE_BUFFER_POOL)->addPlugins(shaStrings); + } + else if (field == TUNNEL_PLUGIN_FIELD) + { + getCounterContext(COUNTER_TYPE_TUNNEL)->addPlugins(shaStrings); + } + else if (field == FLOW_COUNTER_PLUGIN_FIELD) + { + getCounterContext(COUNTER_TYPE_FLOW)->addPlugins(shaStrings); + } + else + { + SWSS_LOG_ERROR("Field is not supported %s", field.c_str()); } - - found = true; } - if (!found) - { - SWSS_LOG_NOTICE("Trying to remove nonexisting PG %s", - sai_serialize_object_id(priorityGroupVid).c_str()); - return; - } + // notify thread to start polling + notifyPoll(); } -void FlexCounter::removeMACsecFlow( - _In_ sai_object_id_t macsecFlowVid) +bool FlexCounter::isEmpty() { - SWSS_LOG_ENTER(); - - bool found = false; + MUTEX; - auto counterIter = m_macsecFlowCounterIdsMap.find(macsecFlowVid); + SWSS_LOG_ENTER(); - if (counterIter != m_macsecFlowCounterIdsMap.end()) - { - m_macsecFlowCounterIdsMap.erase(counterIter); + return allIdsEmpty() && allPluginsEmpty(); +} - if (m_macsecFlowCounterIdsMap.empty()) - { - removeCollectCountersHandler(MACSEC_FLOW_COUNTER_ID_LIST); - } +bool FlexCounter::isDiscarded() +{ + SWSS_LOG_ENTER(); - found = true; - } - - if (!found) - { - SWSS_LOG_WARN("Trying to remove nonexisting MACsec Flow %s", - sai_serialize_object_id(macsecFlowVid).c_str()); - } -} - -void FlexCounter::removeMACsecSA( - _In_ sai_object_id_t macsecSAVid) -{ - SWSS_LOG_ENTER(); - - bool found = false; - - auto counterIter = m_macsecSACounterIdsMap.find(macsecSAVid); - - if (counterIter != m_macsecSACounterIdsMap.end()) - { - m_macsecSACounterIdsMap.erase(counterIter); - - if (m_macsecSACounterIdsMap.empty()) - { - removeCollectCountersHandler(MACSEC_SA_COUNTER_ID_LIST); - } - - found = true; - } - - auto attrIter = m_macsecSAAttrIdsMap.find(macsecSAVid); - - if (attrIter != m_macsecSAAttrIdsMap.end()) - { - m_macsecSAAttrIdsMap.erase(attrIter); - - if (m_macsecSAAttrIdsMap.empty()) - { - removeCollectCountersHandler(MACSEC_SA_ATTR_ID_LIST); - } - - found = true; - } - - if (!found) - { - SWSS_LOG_WARN("Trying to remove nonexisting MACsec SA %s", - sai_serialize_object_id(macsecSAVid).c_str()); - } -} - -void FlexCounter::removeAclCounter( - _In_ sai_object_id_t aclCounterVid) -{ - SWSS_LOG_ENTER(); - - auto itr = m_aclCounterAttrIdsMap.find(aclCounterVid); - - if (itr != m_aclCounterAttrIdsMap.end()) - { - m_aclCounterAttrIdsMap.erase(itr); - - if (m_aclCounterAttrIdsMap.empty()) - { - removeCollectCountersHandler(ACL_COUNTER_ATTR_ID_LIST); - } - } - else - { - SWSS_LOG_WARN("Trying to remove nonexisting ACL counter %s", - sai_serialize_object_id(aclCounterVid).c_str()); - } -} - -void FlexCounter::removeFlowCounter( - _In_ sai_object_id_t counterVid) -{ - SWSS_LOG_ENTER(); - - auto it = m_flowCounterIdsMap.find(counterVid); - - if (it == m_flowCounterIdsMap.end()) - { - SWSS_LOG_NOTICE("Trying to remove nonexisting flow counter from Id 0x%" PRIx64, counterVid); - return; - } - - swss::DBConnector db(m_dbCounters, 0); - swss::RedisPipeline pipeline(&db); - swss::Table countersTable(&pipeline, COUNTERS_TABLE, false); - swss::Table ratesTable(&pipeline, RATES_TABLE, false); - - // Remove counter and rate entries from COUNTER DB to avoid resource leak - std::string counterVidStr = sai_serialize_object_id(counterVid); - countersTable.del(counterVidStr); - ratesTable.del(counterVidStr); - ratesTable.del(counterVidStr + ":TRAP"); - - m_flowCounterIdsMap.erase(it); - - if (m_flowCounterIdsMap.empty()) - { - removeCollectCountersHandler(FLOW_COUNTER_ID_LIST); - } -} - -void FlexCounter::removeRif( - _In_ sai_object_id_t rifVid) -{ - SWSS_LOG_ENTER(); - - auto it = m_rifCounterIdsMap.find(rifVid); - - if (it == m_rifCounterIdsMap.end()) - { - SWSS_LOG_NOTICE("Trying to remove nonexisting router interface counter from Id 0x%" PRIx64, rifVid); - return; - } - - m_rifCounterIdsMap.erase(it); - - if (m_rifCounterIdsMap.empty()) - { - removeCollectCountersHandler(RIF_COUNTER_ID_LIST); - } -} - -void FlexCounter::removeBufferPool( - _In_ sai_object_id_t bufferPoolVid) -{ - SWSS_LOG_ENTER(); - - bool found = false; - - auto it = m_bufferPoolCounterIdsMap.find(bufferPoolVid); - - if (it != m_bufferPoolCounterIdsMap.end()) - { - m_bufferPoolCounterIdsMap.erase(it); - - if (m_bufferPoolCounterIdsMap.empty()) - { - removeCollectCountersHandler(BUFFER_POOL_COUNTER_ID_LIST); - } - found = true; - } - - if (!found) - { - SWSS_LOG_NOTICE("Trying to remove nonexisting buffer pool 0x%" PRIx64 " from flex counter %s", bufferPoolVid, m_instanceId.c_str()); - } -} - -void FlexCounter::removeSwitchDebugCounters( - _In_ sai_object_id_t switchVid) -{ - SWSS_LOG_ENTER(); - - auto it = m_switchDebugCounterIdsMap.find(switchVid); - - if (it == m_switchDebugCounterIdsMap.end()) - { - SWSS_LOG_NOTICE("Trying to remove nonexisting switch debug counter Ids 0x%" PRIx64, switchVid); - return; - } - - m_switchDebugCounterIdsMap.erase(it); - - if (m_switchDebugCounterIdsMap.empty()) - { - removeCollectCountersHandler(SWITCH_DEBUG_COUNTER_ID_LIST); - } -} - -void FlexCounter::removeTunnel( - _In_ sai_object_id_t tunnelVid) -{ - SWSS_LOG_ENTER(); - - auto it = m_tunnelCounterIdsMap.find(tunnelVid); - - if (it == m_tunnelCounterIdsMap.end()) - { - SWSS_LOG_NOTICE("Trying to remove nonexisting tunnel counter from Id 0x%" PRIx64, tunnelVid); - return; - } - - m_tunnelCounterIdsMap.erase(it); - - if (m_tunnelCounterIdsMap.empty()) - { - removeCollectCountersHandler(TUNNEL_COUNTER_ID_LIST); - } -} - -void FlexCounter::checkPluginRegistered( - _In_ const std::string& sha) const -{ - SWSS_LOG_ENTER(); - - if ( - m_portPlugins.find(sha) != m_portPlugins.end() || - m_rifPlugins.find(sha) != m_rifPlugins.end() || - m_queuePlugins.find(sha) != m_queuePlugins.end() || - m_priorityGroupPlugins.find(sha) != m_priorityGroupPlugins.end() || - m_bufferPoolPlugins.find(sha) != m_bufferPoolPlugins.end() || - m_tunnelPlugins.find(sha) != m_tunnelPlugins.end() || - m_flowCounterPlugins.find(sha) != m_flowCounterPlugins.end() - ) - { - SWSS_LOG_ERROR("Plugin %s already registered", sha.c_str()); - } -} - -void FlexCounter::addPortCounterPlugin( - _In_ const std::string& sha) -{ - SWSS_LOG_ENTER(); - - checkPluginRegistered(sha); - - m_portPlugins.insert(sha); - - SWSS_LOG_NOTICE("Port counters plugin %s registered", sha.c_str()); -} - -void FlexCounter::addRifCounterPlugin( - _In_ const std::string& sha) -{ - SWSS_LOG_ENTER(); - - checkPluginRegistered(sha); - - m_rifPlugins.insert(sha); - - SWSS_LOG_NOTICE("Rif counters plugin %s registered", sha.c_str()); -} - -void FlexCounter::addQueueCounterPlugin( - _In_ const std::string& sha) -{ - SWSS_LOG_ENTER(); - - checkPluginRegistered(sha); - - m_queuePlugins.insert(sha); - - SWSS_LOG_NOTICE("Queue counters plugin %s registered", sha.c_str()); -} - -void FlexCounter::addFlowCounterPlugin( - _In_ const std::string& sha) -{ - SWSS_LOG_ENTER(); - - checkPluginRegistered(sha); - - m_flowCounterPlugins.insert(sha); - - SWSS_LOG_NOTICE("Flow counters plugin %s registered", sha.c_str()); -} - -void FlexCounter::addPriorityGroupCounterPlugin( - _In_ const std::string& sha) -{ - SWSS_LOG_ENTER(); - - checkPluginRegistered(sha); - - m_priorityGroupPlugins.insert(sha); - - SWSS_LOG_NOTICE("Priority group counters plugin %s registered", sha.c_str()); -} - -void FlexCounter::addBufferPoolCounterPlugin( - _In_ const std::string& sha) -{ - SWSS_LOG_ENTER(); - - checkPluginRegistered(sha); - - m_bufferPoolPlugins.insert(sha); - - SWSS_LOG_NOTICE("Buffer pool counters plugin %s registered", sha.c_str()); -} - -void FlexCounter::addTunnelCounterPlugin( - _In_ const std::string& sha) -{ - SWSS_LOG_ENTER(); - - checkPluginRegistered(sha); - - m_tunnelPlugins.insert(sha); - - SWSS_LOG_NOTICE("Tunnel counters plugin %s registered", sha.c_str()); -} - -void FlexCounter::removeCounterPlugins() -{ - MUTEX; - - SWSS_LOG_ENTER(); - - m_queuePlugins.clear(); - m_portPlugins.clear(); - m_rifPlugins.clear(); - m_priorityGroupPlugins.clear(); - m_bufferPoolPlugins.clear(); - m_tunnelPlugins.clear(); - m_flowCounterPlugins.clear(); - - m_isDiscarded = true; -} - -void FlexCounter::addCounterPlugin( - _In_ const std::vector& values) -{ - MUTEX; - - SWSS_LOG_ENTER(); - - m_isDiscarded = false; - - for (auto& fvt: values) - { - auto& field = fvField(fvt); - auto& value = fvValue(fvt); - - auto shaStrings = swss::tokenize(value, ','); - - if (field == POLL_INTERVAL_FIELD) - { - setPollInterval(stoi(value)); - } - else if (field == FLEX_COUNTER_STATUS_FIELD) - { - setStatus(value); - } - else if (field == STATS_MODE_FIELD) - { - setStatsMode(value); - } - else if (field == QUEUE_PLUGIN_FIELD) - { - for (auto& sha: shaStrings) - { - addQueueCounterPlugin(sha); - } - } - else if (field == PG_PLUGIN_FIELD) - { - for (auto& sha: shaStrings) - { - addPriorityGroupCounterPlugin(sha); - } - } - else if (field == PORT_PLUGIN_FIELD) - { - for (auto& sha: shaStrings) - { - addPortCounterPlugin(sha); - } - } - else if (field == RIF_PLUGIN_FIELD) - { - for (auto& sha: shaStrings) - { - addRifCounterPlugin(sha); - } - } - else if (field == BUFFER_POOL_PLUGIN_FIELD) - { - for (auto& sha: shaStrings) - { - addBufferPoolCounterPlugin(sha); - } - } - else if (field == TUNNEL_PLUGIN_FIELD) - { - for (auto& sha: shaStrings) - { - addTunnelCounterPlugin(sha); - } - } - else if (field == FLOW_COUNTER_PLUGIN_FIELD) - { - for (auto& sha: shaStrings) - { - addFlowCounterPlugin(sha); - } - } - else - { - SWSS_LOG_ERROR("Field is not supported %s", field.c_str()); - } - } - - // notify thread to start polling - notifyPoll(); -} - -bool FlexCounter::isEmpty() -{ - MUTEX; - - SWSS_LOG_ENTER(); - - return allIdsEmpty() && allPluginsEmpty(); -} - -bool FlexCounter::isDiscarded() -{ - SWSS_LOG_ENTER(); - - return isEmpty() && m_isDiscarded; -} - -bool FlexCounter::allIdsEmpty() const -{ - SWSS_LOG_ENTER(); - - return m_priorityGroupCounterIdsMap.empty() && - m_priorityGroupAttrIdsMap.empty() && - m_queueCounterIdsMap.empty() && - m_queueAttrIdsMap.empty() && - m_portCounterIdsMap.empty() && - m_portDebugCounterIdsMap.empty() && - m_rifCounterIdsMap.empty() && - m_bufferPoolCounterIdsMap.empty() && - m_switchDebugCounterIdsMap.empty() && - m_aclCounterAttrIdsMap.empty() && - m_tunnelCounterIdsMap.empty() && - m_flowCounterIdsMap.empty() && - m_macsecFlowCounterIdsMap.empty() && - m_macsecSACounterIdsMap.empty() && - m_macsecSAAttrIdsMap.empty(); -} - -bool FlexCounter::allPluginsEmpty() const -{ - SWSS_LOG_ENTER(); - - return m_priorityGroupPlugins.empty() && - m_queuePlugins.empty() && - m_portPlugins.empty() && - m_rifPlugins.empty() && - m_bufferPoolPlugins.empty() && - m_tunnelPlugins.empty() && - m_flowCounterPlugins.empty(); -} - -bool FlexCounter::isQueueCounterSupported( - _In_ sai_queue_stat_t counter) const -{ - SWSS_LOG_ENTER(); - - return m_supportedQueueCounters.count(counter) != 0; -} - -bool FlexCounter::isPriorityGroupCounterSupported( - _In_ sai_ingress_priority_group_stat_t counter) const -{ - SWSS_LOG_ENTER(); - - return m_supportedPriorityGroupCounters.count(counter) != 0; -} - -bool FlexCounter::isRifCounterSupported( - _In_ sai_router_interface_stat_t counter) const -{ - SWSS_LOG_ENTER(); - - return m_supportedRifCounters.count(counter) != 0; -} - -bool FlexCounter::isBufferPoolCounterSupported( - _In_ sai_buffer_pool_stat_t counter) const -{ - SWSS_LOG_ENTER(); - - return m_supportedBufferPoolCounters.count(counter) != 0; -} - -bool FlexCounter::isTunnelCounterSupported( - _In_ sai_tunnel_stat_t counter) const -{ - SWSS_LOG_ENTER(); - - return m_supportedTunnelCounters.count(counter) != 0; -} - -bool FlexCounter::isStatsModeSupported( - _In_ uint32_t statsMode, - _In_ sai_stats_mode_t statCapability) -{ - SWSS_LOG_ENTER(); - - return statsMode & statCapability; -} - -void FlexCounter::collectCounters( - _In_ swss::Table &countersTable) -{ - SWSS_LOG_ENTER(); - - for (const auto &it : m_collectCountersHandlers) - { - (this->*(it.second))(countersTable); - } - - countersTable.flush(); -} - -void FlexCounter::collectPortCounters( - _In_ swss::Table &countersTable) -{ - SWSS_LOG_ENTER(); - - // Collect stats for every registered port - for (const auto &kv: m_portCounterIdsMap) - { - const auto &portVid = kv.first; - const auto &portId = kv.second->portId; - const auto &portCounterIds = kv.second->portCounterIds; - - std::vector portStats(portCounterIds.size()); - - // Get port stats - sai_status_t status = m_vendorSai->getStats( - SAI_OBJECT_TYPE_PORT, - portId, - static_cast(portCounterIds.size()), - (const sai_stat_id_t *)portCounterIds.data(), - portStats.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to get stats of port 0x%" PRIx64 ": %d", portId, status); - continue; - } - - // Push all counter values to a single vector - std::vector values; - - for (size_t i = 0; i != portCounterIds.size(); i++) - { - const std::string &counterName = sai_serialize_port_stat(portCounterIds[i]); - - values.emplace_back(counterName, std::to_string(portStats[i])); - } - - // Write counters to DB - std::string portVidStr = sai_serialize_object_id(portVid); - - countersTable.set(portVidStr, values, ""); - } -} - -void FlexCounter::collectPortDebugCounters( - _In_ swss::Table &countersTable) -{ - SWSS_LOG_ENTER(); - - // Collect stats for every registered port - for (const auto &kv: m_portDebugCounterIdsMap) - { - const auto &portVid = kv.first; - const auto &portId = kv.second->portId; - const auto &portCounterIds = kv.second->portCounterIds; - - std::vector portStats(portCounterIds.size()); - - // Get port stats - sai_status_t status = m_vendorSai->getStatsExt( - SAI_OBJECT_TYPE_PORT, - portId, - static_cast(portCounterIds.size()), - (const sai_stat_id_t *)portCounterIds.data(), - SAI_STATS_MODE_READ, - portStats.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to get stats of port 0x%" PRIx64 ": %d", portId, status); - continue; - } - - // Push all counter values to a single vector - std::vector values; - - for (size_t i = 0; i != portCounterIds.size(); i++) - { - const std::string &counterName = sai_serialize_port_stat(portCounterIds[i]); - - values.emplace_back(counterName, std::to_string(portStats[i])); - } - - // Write counters to DB - std::string portVidStr = sai_serialize_object_id(portVid); - - countersTable.set(portVidStr, values, ""); - } -} - -void FlexCounter::collectQueueCounters( - _In_ swss::Table &countersTable) -{ - SWSS_LOG_ENTER(); - - // Collect stats for every registered queue - for (const auto &kv: m_queueCounterIdsMap) - { - const auto &queueVid = kv.first; - const auto &queueId = kv.second->queueId; - const auto &queueCounterIds = kv.second->queueCounterIds; - - std::vector queueStats(queueCounterIds.size()); - - // Get queue stats - sai_status_t status = -1; - // TODO: replace if with get_queue_stats_ext() call when it is fully supported - // Example: - // sai_status_t status = m_vendorSai->getStatsExt( - // queueId, - // static_cast(queueCounterIds.size()), - // queueCounterIds.data(), - // m_statsMode, - // queueStats.data()); - status = m_vendorSai->getStats( - SAI_OBJECT_TYPE_QUEUE, - queueId, - static_cast(queueCounterIds.size()), - (const sai_stat_id_t *)queueCounterIds.data(), - queueStats.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("%s: failed to get stats of queue 0x%" PRIx64 ": %d", m_instanceId.c_str(), queueVid, status); - continue; - } - - if (m_statsMode == SAI_STATS_MODE_READ_AND_CLEAR) - { - status = m_vendorSai->clearStats( - SAI_OBJECT_TYPE_QUEUE, - queueId, - static_cast(queueCounterIds.size()), - (const sai_stat_id_t *)queueCounterIds.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("%s: failed to clear stats of queue 0x%" PRIx64 ": %d", m_instanceId.c_str(), queueVid, status); - continue; - } - } - - // Push all counter values to a single vector - std::vector values; - - for (size_t i = 0; i != queueCounterIds.size(); i++) - { - const std::string &counterName = sai_serialize_queue_stat(queueCounterIds[i]); - - values.emplace_back(counterName, std::to_string(queueStats[i])); - } - - // Write counters to DB - std::string queueVidStr = sai_serialize_object_id(queueVid); - - countersTable.set(queueVidStr, values, ""); - } -} - -void FlexCounter::collectQueueAttrs( - _In_ swss::Table &countersTable) -{ - SWSS_LOG_ENTER(); - - // Collect attrs for every registered queue - for (const auto &kv: m_queueAttrIdsMap) - { - const auto &queueVid = kv.first; - const auto &queueId = kv.second->queueId; - const auto &queueAttrIds = kv.second->queueAttrIds; - - std::vector queueAttr(queueAttrIds.size()); - - for (size_t i = 0; i < queueAttrIds.size(); i++) - { - queueAttr[i].id = queueAttrIds[i]; - } - - // Get queue attr - sai_status_t status = m_vendorSai->get( - SAI_OBJECT_TYPE_QUEUE, - queueId, - static_cast(queueAttrIds.size()), - queueAttr.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to get attr of queue 0x%" PRIx64 ": %d", queueVid, status); - continue; - } - - // Push all counter values to a single vector - std::vector values; - - for (size_t i = 0; i != queueAttrIds.size(); i++) - { - const std::string &counterName = sai_serialize_queue_attr(queueAttrIds[i]); - - auto meta = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_QUEUE, queueAttr[i].id); - - values.emplace_back(counterName, sai_serialize_attr_value(*meta, queueAttr[i])); - } - // Write counters to DB - std::string queueVidStr = sai_serialize_object_id(queueVid); - - countersTable.set(queueVidStr, values, ""); - } -} - -void FlexCounter::collectPriorityGroupCounters( - _In_ swss::Table &countersTable) -{ - SWSS_LOG_ENTER(); - - // Collect stats for every registered ingress priority group - for (const auto &kv: m_priorityGroupCounterIdsMap) - { - const auto &priorityGroupVid = kv.first; - const auto &priorityGroupId = kv.second->priorityGroupId; - const auto &priorityGroupCounterIds = kv.second->priorityGroupCounterIds; - - std::vector priorityGroupStats(priorityGroupCounterIds.size()); - - // Get PG stats - sai_status_t status = -1; - // TODO: replace if with get_ingress_priority_group_stats_ext() call when it is fully supported - status = m_vendorSai->getStats( - SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, - priorityGroupId, - static_cast(priorityGroupCounterIds.size()), - (const sai_stat_id_t *)priorityGroupCounterIds.data(), - priorityGroupStats.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("%s: failed to get %ld/%ld stats of PG 0x%" PRIx64 ": %d", - m_instanceId.c_str(), - priorityGroupCounterIds.size(), - priorityGroupStats.size(), - priorityGroupVid, - status); - continue; - } - - if (m_statsMode == SAI_STATS_MODE_READ_AND_CLEAR) - { - status = m_vendorSai->clearStats( - SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, - priorityGroupId, - static_cast(priorityGroupCounterIds.size()), - (const sai_stat_id_t *)priorityGroupCounterIds.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("%s: failed to clear %ld/%ld stats of PG 0x%" PRIx64 ": %d", - m_instanceId.c_str(), - priorityGroupCounterIds.size(), - priorityGroupStats.size(), - priorityGroupVid, - status); - continue; - } - } - - // Push all counter values to a single vector - std::vector values; - - for (size_t i = 0; i != priorityGroupCounterIds.size(); i++) - { - const std::string &counterName = sai_serialize_ingress_priority_group_stat(priorityGroupCounterIds[i]); - - values.emplace_back(counterName, std::to_string(priorityGroupStats[i])); - } - - // Write counters to DB - std::string priorityGroupVidStr = sai_serialize_object_id(priorityGroupVid); - - countersTable.set(priorityGroupVidStr, values, ""); - } -} - -void FlexCounter::collectSwitchDebugCounters( - _In_ swss::Table &countersTable) -{ - SWSS_LOG_ENTER(); - - // Collect stats for every registered port - for (const auto &kv: m_switchDebugCounterIdsMap) - { - const auto &switchVid = kv.first; - const auto &switchId = kv.second->switchId; - const auto &switchCounterIds = kv.second->switchCounterIds; - - std::vector switchStats(switchCounterIds.size()); - - // Get port stats - sai_status_t status = m_vendorSai->getStatsExt( - SAI_OBJECT_TYPE_SWITCH, - switchId, - static_cast(switchCounterIds.size()), - (const sai_stat_id_t *)switchCounterIds.data(), - SAI_STATS_MODE_READ, - switchStats.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to get stats of port 0x%" PRIx64 ": %d", switchId, status); - continue; - } - - // Push all counter values to a single vector - std::vector values; - - for (size_t i = 0; i != switchCounterIds.size(); i++) - { - const std::string &counterName = sai_serialize_switch_stat(switchCounterIds[i]); - - values.emplace_back(counterName, std::to_string(switchStats[i])); - } - - // Write counters to DB - std::string switchVidStr = sai_serialize_object_id(switchVid); - - countersTable.set(switchVidStr, values, ""); - } -} - -void FlexCounter::collectFlowCounters( - _In_ swss::Table &countersTable) -{ - SWSS_LOG_ENTER(); - - // Collect stats for every registered flow counter - for (const auto &kv: m_flowCounterIdsMap) - { - const auto &counterVid = kv.first; - const auto &counterRId = kv.second->counterId; - const auto &counterIds = kv.second->flowCounterIds; - - std::vector stats(counterIds.size()); - - // Get flow counter stats - sai_status_t status = m_vendorSai->getStatsExt( - SAI_OBJECT_TYPE_COUNTER, - counterRId, - static_cast(counterIds.size()), - (const sai_stat_id_t *)counterIds.data(), - SAI_STATS_MODE_READ, - stats.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to get stats of flow counter 0x%" PRIx64 ": %d", counterRId, status); - continue; - } - - // Push all counter values to a single vector - std::vector values; - - for (size_t i = 0; i != counterIds.size(); i++) - { - values.emplace_back(sai_serialize_counter_stat(counterIds[i]), std::to_string(stats[i])); - } - - // Write counters to DB - std::string counterVidStr = sai_serialize_object_id(counterVid); - - countersTable.set(counterVidStr, values, ""); - } -} - -void FlexCounter::collectPriorityGroupAttrs( - _In_ swss::Table &countersTable) -{ - SWSS_LOG_ENTER(); - - // Collect attrs for every registered priority group - for (const auto &kv: m_priorityGroupAttrIdsMap) - { - const auto &priorityGroupVid = kv.first; - const auto &priorityGroupId = kv.second->priorityGroupId; - const auto &priorityGroupAttrIds = kv.second->priorityGroupAttrIds; - - std::vector priorityGroupAttr(priorityGroupAttrIds.size()); - - for (size_t i = 0; i < priorityGroupAttrIds.size(); i++) - { - priorityGroupAttr[i].id = priorityGroupAttrIds[i]; - } - - // Get PG attr - sai_status_t status = m_vendorSai->get( - SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, - priorityGroupId, - static_cast(priorityGroupAttrIds.size()), - priorityGroupAttr.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to get attr of PG 0x%" PRIx64 ": %d", priorityGroupVid, status); - continue; - } - - // Push all counter values to a single vector - std::vector values; - - for (size_t i = 0; i != priorityGroupAttrIds.size(); i++) - { - const std::string &counterName = sai_serialize_ingress_priority_group_attr(priorityGroupAttrIds[i]); - - auto meta = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, priorityGroupAttr[i].id); - - values.emplace_back(counterName, sai_serialize_attr_value(*meta, priorityGroupAttr[i])); - } - // Write counters to DB - std::string priorityGroupVidStr = sai_serialize_object_id(priorityGroupVid); - - countersTable.set(priorityGroupVidStr, values, ""); - } -} - -void FlexCounter::collectMACsecFlowCounters( - _In_ swss::Table &countersTable) -{ - SWSS_LOG_ENTER(); - - // Collect stats for every registered MACsec Flow - for (const auto &kv: m_macsecFlowCounterIdsMap) - { - const auto &macsecFlowVid = kv.first; - const auto &macsecFlowRid = kv.second->m_macsecFlowId; - const auto &macsecFlowCounterIds = kv.second->m_macsecFlowCounterIds; - - std::vector macsecFlowStats(macsecFlowCounterIds.size()); - - // Get MACsec Flow stats - sai_status_t status = m_vendorSai->getStats( - SAI_OBJECT_TYPE_MACSEC_FLOW, - macsecFlowRid, - static_cast(macsecFlowCounterIds.size()), - (const sai_stat_id_t *)macsecFlowCounterIds.data(), - macsecFlowStats.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR( - "Failed to get stats of MACsec Flow %s: %s", - sai_serialize_object_id(macsecFlowVid).c_str(), - sai_serialize_status(status).c_str()); - continue; - } - - if (m_statsMode == SAI_STATS_MODE_READ_AND_CLEAR) - { - status = m_vendorSai->clearStats( - SAI_OBJECT_TYPE_MACSEC_FLOW, - macsecFlowRid, - static_cast(macsecFlowCounterIds.size()), - (const sai_stat_id_t *)macsecFlowCounterIds.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR( - "Failed to clear stats of MACsec Flow %s: %s", - sai_serialize_object_id(macsecFlowVid).c_str(), - sai_serialize_status(status).c_str()); - continue; - } - } - - // Push all counter values to a single vector - std::vector values; - - for (size_t i = 0; i != macsecFlowCounterIds.size(); i++) - { - const std::string &counterName = sai_serialize_macsec_flow_stat(macsecFlowCounterIds[i]); - - values.emplace_back(counterName, std::to_string(macsecFlowStats[i])); - } - - // Write counters to DB - std::string macsecFlowVidStr = sai_serialize_object_id(macsecFlowVid); - - countersTable.set(macsecFlowVidStr, values, ""); - } -} - -void FlexCounter::collectMACsecSACounters( - _In_ swss::Table &countersTable) -{ - SWSS_LOG_ENTER(); - - // Collect stats for every registered MACsec SA - for (const auto &kv: m_macsecSACounterIdsMap) - { - const auto &macsecSAVid = kv.first; - const auto &macsecSARid = kv.second->m_macsecSAId; - const auto &macsecSACounterIds = kv.second->m_macsecSACounterIds; - - std::vector macsecSAStats(macsecSACounterIds.size()); - - // Get MACsec SA stats - sai_status_t status = m_vendorSai->getStats( - SAI_OBJECT_TYPE_MACSEC_SA, - macsecSARid, - static_cast(macsecSACounterIds.size()), - (const sai_stat_id_t *)macsecSACounterIds.data(), - macsecSAStats.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR( - "Failed to get stats of MACsec SA %s: %s", - sai_serialize_object_id(macsecSAVid).c_str(), - sai_serialize_status(status).c_str()); - continue; - } - - if (m_statsMode == SAI_STATS_MODE_READ_AND_CLEAR) - { - status = m_vendorSai->clearStats( - SAI_OBJECT_TYPE_MACSEC_SA, - macsecSARid, - static_cast(macsecSACounterIds.size()), - (const sai_stat_id_t *)macsecSACounterIds.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR( - "Failed to clear stats of MACsec SA %s: %s", - sai_serialize_object_id(macsecSAVid).c_str(), - sai_serialize_status(status).c_str()); - continue; - } - } - - // Push all counter values to a single vector - std::vector values; - - for (size_t i = 0; i != macsecSACounterIds.size(); i++) - { - const std::string &counterName = sai_serialize_macsec_sa_stat(macsecSACounterIds[i]); - - values.emplace_back(counterName, std::to_string(macsecSAStats[i])); - } - - // Write counters to DB - std::string macsecSAVidStr = sai_serialize_object_id(macsecSAVid); - - countersTable.set(macsecSAVidStr, values, ""); - } -} - -void FlexCounter::collectMACsecSAAttrs( - _In_ swss::Table &countersTable) -{ - SWSS_LOG_ENTER(); - - // Collect attrs for every registered MACsec SA - for (const auto &kv: m_macsecSAAttrIdsMap) - { - const auto &macsecSAVid = kv.first; - const auto &macsecSARid = kv.second->m_macsecSAId; - const auto &macsecSAAttrIds = kv.second->m_macsecSAAttrIds; - - std::vector macsecSAAttrs(macsecSAAttrIds.size()); - - for (size_t i = 0; i < macsecSAAttrIds.size(); i++) - { - macsecSAAttrs[i].id = macsecSAAttrIds[i]; - } - - // Get MACsec SA attr - sai_status_t status = m_vendorSai->get( - SAI_OBJECT_TYPE_MACSEC_SA, - macsecSARid, - static_cast(macsecSAAttrs.size()), - macsecSAAttrs.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_WARN( - "Failed to get attr of MACsec SA %s: %s", - sai_serialize_object_id(macsecSAVid).c_str(), - sai_serialize_status(status).c_str()); - continue; - } - - // Push all counter values to a single vector - std::vector values; - - for (const auto& macsecSAAttr : macsecSAAttrs) - { - auto meta = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_MACSEC_SA, macsecSAAttr.id); - values.emplace_back(meta->attridname, sai_serialize_attr_value(*meta, macsecSAAttr)); - } - - // Write counters to DB - std::string macsecSAVidStr = sai_serialize_object_id(macsecSAVid); - - countersTable.set(macsecSAVidStr, values, ""); - } -} - -void FlexCounter::collectAclCounterAttrs( - _In_ swss::Table &countersTable) -{ - SWSS_LOG_ENTER(); - - for (const auto &kv: m_aclCounterAttrIdsMap) - { - const auto &aclCounterVid = kv.first; - const auto &aclCounterRid = kv.second->m_aclCounterId; - const auto &aclCounterAttrIds = kv.second->m_aclCounterAttrIds; - - std::vector aclCounterAttrs(aclCounterAttrIds.size()); - - for (size_t i = 0; i < aclCounterAttrIds.size(); i++) - { - aclCounterAttrs[i].id = aclCounterAttrIds[i]; - } - - sai_status_t status = m_vendorSai->get( - SAI_OBJECT_TYPE_ACL_COUNTER, - aclCounterRid, - static_cast(aclCounterAttrs.size()), - aclCounterAttrs.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_WARN( - "Failed to get attr of ACL counter %s: %s", - sai_serialize_object_id(aclCounterVid).c_str(), - sai_serialize_status(status).c_str()); - continue; - } - - std::vector values; - - for (const auto& aclCounterAttr : aclCounterAttrs) - { - auto meta = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_ACL_COUNTER, aclCounterAttr.id); - if (!meta) - { - SWSS_LOG_THROW("Failed to get metadata for SAI_OBJECT_TYPE_ACL_COUNTER"); - } - values.emplace_back(meta->attridname, sai_serialize_attr_value(*meta, aclCounterAttr)); - } - - // Write counters to DB - auto aclCounterVidStr = sai_serialize_object_id(aclCounterVid); - - countersTable.set(aclCounterVidStr, values); - } -} - -void FlexCounter::collectRifCounters( - _In_ swss::Table &countersTable) -{ - SWSS_LOG_ENTER(); - - // Collect stats for every registered router interface - for (const auto &kv: m_rifCounterIdsMap) - { - const auto &rifVid = kv.first; - const auto &rifId = kv.second->rifId; - const auto &rifCounterIds = kv.second->rifCounterIds; - - std::vector rifStats(rifCounterIds.size()); - - // Get rif stats - sai_status_t status = m_vendorSai->getStats( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - rifId, - static_cast(rifCounterIds.size()), - (const sai_stat_id_t *)rifCounterIds.data(), - rifStats.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to get stats of router interface 0x%" PRIx64 ": %d", rifId, status); - continue; - } - - // Push all counter values to a single vector - std::vector values; - - for (size_t i = 0; i != rifCounterIds.size(); i++) - { - const std::string &counterName = sai_serialize_router_interface_stat(rifCounterIds[i]); - - values.emplace_back(counterName, std::to_string(rifStats[i])); - } - - // Write counters to DB - std::string rifVidStr = sai_serialize_object_id(rifVid); - - countersTable.set(rifVidStr, values, ""); - } -} - -void FlexCounter::collectBufferPoolCounters( - _In_ swss::Table &countersTable) -{ - SWSS_LOG_ENTER(); - - // Collect stats for every registered buffer pool - for (const auto &it : m_bufferPoolCounterIdsMap) - { - const auto &bufferPoolVid = it.first; - const auto &bufferPoolId = it.second->bufferPoolId; - const auto &bufferPoolCounterIds = it.second->bufferPoolCounterIds; - const auto &bufferPoolStatsMode = it.second->bufferPoolStatsMode; - - std::vector bufferPoolStats(bufferPoolCounterIds.size()); - - // Get buffer pool stats - sai_status_t status = -1; - - status = m_vendorSai->getStats( - SAI_OBJECT_TYPE_BUFFER_POOL, - bufferPoolId, - static_cast(bufferPoolCounterIds.size()), - reinterpret_cast(bufferPoolCounterIds.data()), - bufferPoolStats.data()); - - if (status != SAI_STATUS_SUCCESS) - { - // Because of stat pre-qualification in setting the buffer pool counter list, - // it is less likely that we will get a failure return here in polling the stats - SWSS_LOG_ERROR("%s: failed to get stats of buffer pool %s, rv: %s", - m_instanceId.c_str(), - sai_serialize_object_id(bufferPoolId).c_str(), - sai_serialize_status(status).c_str()); - continue; - } - if (m_statsMode == SAI_STATS_MODE_READ_AND_CLEAR || bufferPoolStatsMode == SAI_STATS_MODE_READ_AND_CLEAR) - { - status = m_vendorSai->clearStats( - SAI_OBJECT_TYPE_BUFFER_POOL, - bufferPoolId, - static_cast(bufferPoolCounterIds.size()), - reinterpret_cast(bufferPoolCounterIds.data())); - - if (status != SAI_STATUS_SUCCESS) - { - // Because of stat pre-qualification in setting the buffer pool counter list, - // it is less likely that we will get a failure return here in clearing the stats - SWSS_LOG_ERROR("%s: failed to clear stats of buffer pool %s, rv: %s", - m_instanceId.c_str(), - sai_serialize_object_id(bufferPoolId).c_str(), - sai_serialize_status(status).c_str()); - continue; - } - } - - // Write counter values to DB table - std::vector fvTuples; - - for (size_t i = 0; i < bufferPoolCounterIds.size(); ++i) - { - fvTuples.emplace_back(sai_serialize_buffer_pool_stat(bufferPoolCounterIds[i]), std::to_string(bufferPoolStats[i])); - } - - countersTable.set(sai_serialize_object_id(bufferPoolVid), fvTuples); - } -} - -void FlexCounter::collectTunnelCounters( - _In_ swss::Table &countersTable) -{ - SWSS_LOG_ENTER(); - - // Collect stats for every registered tunnel - for (const auto &kv: m_tunnelCounterIdsMap) - { - const auto &tunnelVid = kv.first; - const auto &tunnelId = kv.second->m_tunnelId; - const auto &tunnelCounterIds = kv.second->m_tunnelCounterIds; - - std::vector tunnelStats(tunnelCounterIds.size()); - - // Get tunnel stats - sai_status_t status = m_vendorSai->getStats( - SAI_OBJECT_TYPE_TUNNEL, - tunnelId, - static_cast(tunnelCounterIds.size()), - (const sai_stat_id_t *)tunnelCounterIds.data(), - tunnelStats.data()); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to get stats of tunnel 0x%" PRIx64 ": %d", tunnelId, status); - continue; - } - - // Push all counter values to a single vector - std::vector values; - - for (size_t i = 0; i != tunnelCounterIds.size(); i++) - { - const std::string &counterName = sai_serialize_tunnel_stat(tunnelCounterIds[i]); - - values.emplace_back(counterName, std::to_string(tunnelStats[i])); - } - - // Write counters to DB - std::string tunnelVidStr = sai_serialize_object_id(tunnelVid); - - countersTable.set(tunnelVidStr, values, ""); - } -} - -void FlexCounter::runPlugins( - _In_ swss::DBConnector& counters_db) -{ - SWSS_LOG_ENTER(); - - const std::vector argv = - { - std::to_string(counters_db.getDbId()), - COUNTERS_TABLE, - std::to_string(m_pollInterval) - }; - - std::vector portList; - - portList.reserve(m_portCounterIdsMap.size()); - - for (const auto& kv : m_portCounterIdsMap) - { - portList.push_back(sai_serialize_object_id(kv.first)); - } - - for (const auto& sha : m_portPlugins) - { - runRedisScript(counters_db, sha, portList, argv); - } - - std::vector rifList; - rifList.reserve(m_rifCounterIdsMap.size()); - for (const auto& kv : m_rifCounterIdsMap) - { - rifList.push_back(sai_serialize_object_id(kv.first)); - } - for (const auto& sha : m_rifPlugins) - { - runRedisScript(counters_db, sha, rifList, argv); - } - - std::vector queueList; - - queueList.reserve(m_queueCounterIdsMap.size()); - - for (const auto& kv : m_queueCounterIdsMap) - { - queueList.push_back(sai_serialize_object_id(kv.first)); - } - - for (const auto& sha : m_queuePlugins) - { - runRedisScript(counters_db, sha, queueList, argv); - } - - std::vector flowCounterList; - - flowCounterList.reserve(m_flowCounterIdsMap.size()); - - for (const auto& kv : m_flowCounterIdsMap) - { - flowCounterList.push_back(sai_serialize_object_id(kv.first)); - } - - for (const auto& sha : m_flowCounterPlugins) - { - runRedisScript(counters_db, sha, flowCounterList, argv); - } - - std::vector priorityGroupList; - - priorityGroupList.reserve(m_priorityGroupCounterIdsMap.size()); - - for (const auto& kv : m_priorityGroupCounterIdsMap) - { - priorityGroupList.push_back(sai_serialize_object_id(kv.first)); - } - - for (const auto& sha : m_priorityGroupPlugins) - { - runRedisScript(counters_db, sha, priorityGroupList, argv); - } - - std::vector bufferPoolVids; - - bufferPoolVids.reserve(m_bufferPoolCounterIdsMap.size()); - - for (const auto& it : m_bufferPoolCounterIdsMap) - { - bufferPoolVids.push_back(sai_serialize_object_id(it.first)); - } - - for (const auto& sha : m_bufferPoolPlugins) - { - runRedisScript(counters_db, sha, bufferPoolVids, argv); - } - - std::vector tunnelList; - tunnelList.reserve(m_tunnelCounterIdsMap.size()); - for (const auto& kv : m_tunnelCounterIdsMap) - { - tunnelList.push_back(sai_serialize_object_id(kv.first)); - } - for (const auto& sha : m_tunnelPlugins) - { - runRedisScript(counters_db, sha, tunnelList, argv); - } -} - -void FlexCounter::flexCounterThreadRunFunction() -{ - SWSS_LOG_ENTER(); - - swss::DBConnector db(m_dbCounters, 0); - swss::RedisPipeline pipeline(&db); - swss::Table countersTable(&pipeline, COUNTERS_TABLE, true); - - while (m_runFlexCounterThread) - { - MUTEX; - - if (m_enable && !allIdsEmpty() && (m_pollInterval > 0)) - { - auto start = std::chrono::steady_clock::now(); - - collectCounters(countersTable); - - runPlugins(db); - - auto finish = std::chrono::steady_clock::now(); - - uint32_t delay = static_cast( - std::chrono::duration_cast(finish - start).count()); - - uint32_t correction = delay % m_pollInterval; - correction = m_pollInterval - correction; - MUTEX_UNLOCK; // explicit unlock - - SWSS_LOG_DEBUG("End of flex counter thread FC %s, took %d ms", m_instanceId.c_str(), delay); - - std::unique_lock lk(m_mtxSleep); - - m_cvSleep.wait_for(lk, std::chrono::milliseconds(correction)); - - continue; - } - - MUTEX_UNLOCK; // explicit unlock - - // nothing to collect, wait until notified - waitPoll(); - } -} - -void FlexCounter::startFlexCounterThread() -{ - SWSS_LOG_ENTER(); - - m_runFlexCounterThread = true; - - m_flexCounterThread = std::make_shared(&FlexCounter::flexCounterThreadRunFunction, this); - - SWSS_LOG_INFO("Flex Counter thread started"); -} - -void FlexCounter::endFlexCounterThread(void) -{ - SWSS_LOG_ENTER(); - - MUTEX; - - if (!m_runFlexCounterThread) - { - return; - } - - m_runFlexCounterThread = false; - - notifyPoll(); - - m_cvSleep.notify_all(); - - if (m_flexCounterThread != nullptr) - { - auto fcThread = std::move(m_flexCounterThread); - - MUTEX_UNLOCK; // NOTE: explicit unlock before join to not cause deadlock - - SWSS_LOG_INFO("Wait for Flex Counter thread to end"); - - fcThread->join(); - } - - SWSS_LOG_INFO("Flex Counter thread ended"); -} - -sai_status_t FlexCounter::querySupportedPortCounters( - _In_ sai_object_id_t portRid, - _Out_ PortCountersSet &supportedPortCounters) -{ - SWSS_LOG_ENTER(); - - sai_stat_capability_list_t stats_capability; - stats_capability.count = 0; - stats_capability.list = nullptr; - - /* First call is to check the size needed to allocate */ - sai_status_t status = m_vendorSai->queryStatsCapability( - portRid, - SAI_OBJECT_TYPE_PORT, - &stats_capability); - - /* Second call is for query statistics capability */ - if (status == SAI_STATUS_BUFFER_OVERFLOW) - { - std::vector statCapabilityList(stats_capability.count); - stats_capability.list = statCapabilityList.data(); - status = m_vendorSai->queryStatsCapability( - portRid, - SAI_OBJECT_TYPE_PORT, - &stats_capability); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_NOTICE("Unable to query port supported counters for %s: %s", - sai_serialize_object_id(portRid).c_str(), - sai_serialize_status(status).c_str()); - } - else - { - for (auto statCapability: statCapabilityList) - { - sai_port_stat_t counter = static_cast(statCapability.stat_enum); - supportedPortCounters.insert(counter); - } - } - } - return status; -} - -void FlexCounter::getSupportedPortCounters( - _In_ sai_object_id_t portRid, - _Out_ PortCountersSet &supportedPortCounters) -{ - SWSS_LOG_ENTER(); - - uint64_t value; - - for (int id = SAI_PORT_STAT_IF_IN_OCTETS; id <= SAI_PORT_STAT_IF_OUT_FABRIC_DATA_UNITS; ++id) - { - sai_port_stat_t counter = static_cast(id); - - sai_status_t status = m_vendorSai->getStats(SAI_OBJECT_TYPE_PORT, portRid, 1, (sai_stat_id_t *)&counter, &value); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_NOTICE("Counter %s is not supported on port RID %s: %s", - sai_serialize_port_stat(counter).c_str(), - sai_serialize_object_id(portRid).c_str(), - sai_serialize_status(status).c_str()); - - continue; - } - - supportedPortCounters.insert(counter); - } -} - -void FlexCounter::updateSupportedPortCounters( - _In_ sai_object_id_t portRid, - _Out_ PortCountersSet &supportedPortCounters) -{ - SWSS_LOG_ENTER(); - - /* Query SAI supported port counters */ - sai_status_t status = querySupportedPortCounters(portRid, supportedPortCounters); - if (status != SAI_STATUS_SUCCESS) - { - /* Fallback to legacy approach */ - getSupportedPortCounters(portRid, supportedPortCounters); - } -} - -std::vector FlexCounter::saiCheckSupportedPortDebugCounters( - _In_ sai_object_id_t portId, - _In_ const std::vector &counterIds) -{ - SWSS_LOG_ENTER(); - - std::vector supportedPortDebugCounters; - - uint64_t value; - - for (auto counter: counterIds) - { - if (counter < SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE || counter >= SAI_PORT_STAT_OUT_DROP_REASON_RANGE_END) - { - SWSS_LOG_NOTICE("Debug counter %s out of bounds", sai_serialize_port_stat(counter).c_str()); - continue; - } - - sai_status_t status = m_vendorSai->getStatsExt( - SAI_OBJECT_TYPE_PORT, - portId, - 1, - (const sai_stat_id_t *)&counter, - SAI_STATS_MODE_READ, - &value); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_NOTICE("Debug counter %s is not supported on port RID %s: %s", - sai_serialize_port_stat(counter).c_str(), - sai_serialize_object_id(portId).c_str(), - sai_serialize_status(status).c_str()); - - continue; - } - - supportedPortDebugCounters.push_back(counter); - } - - return supportedPortDebugCounters; -} - -sai_status_t FlexCounter::querySupportedQueueCounters( - _In_ sai_object_id_t queueId) -{ - SWSS_LOG_ENTER(); - - sai_stat_capability_list_t stats_capability; - stats_capability.count = 0; - stats_capability.list = nullptr; - - /* First call is to check the size needed to allocate */ - sai_status_t status = m_vendorSai->queryStatsCapability( - queueId, - SAI_OBJECT_TYPE_QUEUE, - &stats_capability); - - /* Second call is for query statistics capability */ - if (status == SAI_STATUS_BUFFER_OVERFLOW) - { - std::vector statCapabilityList(stats_capability.count); - stats_capability.list = statCapabilityList.data(); - status = m_vendorSai->queryStatsCapability( - queueId, - SAI_OBJECT_TYPE_QUEUE, - &stats_capability); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_INFO("Unable to get queue supported counters for %s", - sai_serialize_object_id(queueId).c_str()); - } - else - { - for (auto statCapability: statCapabilityList) - { - auto currentStatModes = statCapability.stat_modes; - if (m_statsMode == SAI_STATS_MODE_READ_AND_CLEAR && !isStatsModeSupported(currentStatModes, SAI_STATS_MODE_READ_AND_CLEAR)) - { - continue; - } - sai_queue_stat_t counter = static_cast(statCapability.stat_enum); - m_supportedQueueCounters.insert(counter); - } - } - } - return status; -} - -void FlexCounter::getSupportedQueueCounters( - _In_ sai_object_id_t queueId, - _In_ const std::vector &counterIds) -{ - SWSS_LOG_ENTER(); - - uint64_t value; - - for (auto &counter : counterIds) - { - sai_status_t status = m_vendorSai->getStats( - SAI_OBJECT_TYPE_QUEUE, - queueId, - 1, (const sai_stat_id_t *)&counter, - &value); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_NOTICE("%s: counter %s is not supported on queue %s, rv: %s", - m_instanceId.c_str(), - sai_serialize_queue_stat(counter).c_str(), - sai_serialize_object_id(queueId).c_str(), - sai_serialize_status(status).c_str()); - - continue; - } - - if (m_statsMode == SAI_STATS_MODE_READ_AND_CLEAR) - { - status = m_vendorSai->clearStats(SAI_OBJECT_TYPE_QUEUE, queueId, 1, (const sai_stat_id_t *)&counter); - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_NOTICE("%s: clear counter %s is not supported on queue %s, rv: %s", - m_instanceId.c_str(), - sai_serialize_queue_stat(counter).c_str(), - sai_serialize_object_id(queueId).c_str(), - sai_serialize_status(status).c_str()); - - continue; - } - } - - m_supportedQueueCounters.insert(counter); - } -} - -void FlexCounter::updateSupportedQueueCounters( - _In_ sai_object_id_t queueId, - _In_ const std::vector &counterIds) -{ - SWSS_LOG_ENTER(); - - m_supportedQueueCounters.clear(); - - /* Query SAI supported queue counters */ - sai_status_t status = querySupportedQueueCounters(queueId); - if (status != SAI_STATUS_SUCCESS) - { - /* Fallback to legacy approach */ - getSupportedQueueCounters(queueId, counterIds); - } -} - -sai_status_t FlexCounter::querySupportedPriorityGroupCounters( - _In_ sai_object_id_t priorityGroupRid) -{ - SWSS_LOG_ENTER(); - - sai_stat_capability_list_t stats_capability; - stats_capability.count = 0; - stats_capability.list = nullptr; - - /* First call is to check the size needed to allocate */ - sai_status_t status = m_vendorSai->queryStatsCapability( - priorityGroupRid, - SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, - &stats_capability); - - /* Second call is for query statistics capability */ - if (status == SAI_STATUS_BUFFER_OVERFLOW) - { - std::vector statCapabilityList(stats_capability.count); - stats_capability.list = statCapabilityList.data(); - status = m_vendorSai->queryStatsCapability(priorityGroupRid, - SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, - &stats_capability); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_INFO("Unable to get priority group supported counters for %s", - sai_serialize_object_id(priorityGroupRid).c_str()); - } - else - { - - for (auto statCapability: statCapabilityList) - { - auto currentStatModes = statCapability.stat_modes; - if (m_statsMode == SAI_STATS_MODE_READ_AND_CLEAR && !isStatsModeSupported(currentStatModes, SAI_STATS_MODE_READ_AND_CLEAR)) - { - continue; - } - sai_ingress_priority_group_stat_t counter = static_cast(statCapability.stat_enum); - m_supportedPriorityGroupCounters.insert(counter); - } - } - } - return status; -} - -void FlexCounter::getSupportedPriorityGroupCounters( - _In_ sai_object_id_t priorityGroupRid, - _In_ const std::vector &counterIds) -{ - SWSS_LOG_ENTER(); - - uint64_t value; - - for (auto &counter : counterIds) - { - sai_status_t status = m_vendorSai->getStats( - SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, - priorityGroupRid, - 1, - (const sai_stat_id_t *)&counter, - &value); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_NOTICE("%s: counter %s is not supported on PG %s, rv: %s", - m_instanceId.c_str(), - sai_serialize_ingress_priority_group_stat(counter).c_str(), - sai_serialize_object_id(priorityGroupRid).c_str(), - sai_serialize_status(status).c_str()); - - continue; - } - - if (m_statsMode == SAI_STATS_MODE_READ_AND_CLEAR) - { - status = m_vendorSai->clearStats( - SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, - priorityGroupRid, - 1, - (const sai_stat_id_t *)&counter); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_NOTICE("%s: clear counter %s is not supported on PG %s, rv: %s", - m_instanceId.c_str(), - sai_serialize_ingress_priority_group_stat(counter).c_str(), - sai_serialize_object_id(priorityGroupRid).c_str(), - sai_serialize_status(status).c_str()); - - continue; - } - } - - m_supportedPriorityGroupCounters.insert(counter); - } + return isEmpty() && m_isDiscarded; } -void FlexCounter::updateSupportedPriorityGroupCounters( - _In_ sai_object_id_t priorityGroupRid, - _In_ const std::vector &counterIds) +bool FlexCounter::allIdsEmpty() const { SWSS_LOG_ENTER(); - m_supportedPriorityGroupCounters.clear(); - - /* Query SAI supported priority group counters */ - sai_status_t status = querySupportedPriorityGroupCounters(priorityGroupRid); - if (status != SAI_STATUS_SUCCESS) + for (auto &kv : m_counterContext) { - /* Fallback to legacy approach */ - getSupportedPriorityGroupCounters(priorityGroupRid, counterIds); + if (kv.second->hasObject()) + { + return false; + } } + + return true; } -sai_status_t FlexCounter::querySupportedRifCounters( - _In_ sai_object_id_t rifRid) +bool FlexCounter::allPluginsEmpty() const { SWSS_LOG_ENTER(); - sai_stat_capability_list_t stats_capability; - stats_capability.count = 0; - stats_capability.list = nullptr; - - /* First call is to check the size needed to allocate */ - sai_status_t status = m_vendorSai->queryStatsCapability( - rifRid, - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - &stats_capability); - - /* Second call is for query statistics capability */ - if (status == SAI_STATUS_BUFFER_OVERFLOW) + for (auto &kv : m_counterContext) { - std::vector statCapabilityList(stats_capability.count); - stats_capability.list = statCapabilityList.data(); - status = m_vendorSai->queryStatsCapability( - rifRid, - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - &stats_capability); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_INFO("Unable to get routed port supported counters for %s", - sai_serialize_object_id(rifRid).c_str()); - } - else + if (kv.second->hasPlugin()) { - for (auto statCapability: statCapabilityList) - { - sai_router_interface_stat_t counter = static_cast(statCapability.stat_enum); - m_supportedRifCounters.insert(counter); - } + return false; } } - return status; + + return true; } -void FlexCounter::getSupportedRifCounters( - _In_ sai_object_id_t rifRid) +std::shared_ptr FlexCounter::createCounterContext( + _In_ const std::string& context_name) { SWSS_LOG_ENTER(); + if (context_name == COUNTER_TYPE_PORT) + { + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_PORT, m_vendorSai.get(), m_statsMode); + context->always_check_supported_counters = true; + return context; + } + else if (context_name == COUNTER_TYPE_PORT_DEBUG) + { + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_PORT, m_vendorSai.get(), m_statsMode); + context->always_check_supported_counters = true; + context->use_sai_stats_capa_query = false; + context->use_sai_stats_ext = true; - uint64_t value; + return context; + } + else if (context_name == COUNTER_TYPE_QUEUE) + { + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_QUEUE, m_vendorSai.get(), m_statsMode); + context->always_check_supported_counters = true; + context->double_confirm_supported_counters = true; + return context; + } + else if (context_name == COUNTER_TYPE_PG) + { + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, m_vendorSai.get(), m_statsMode); + context->always_check_supported_counters = true; + context->double_confirm_supported_counters = true; + return context; + } + else if (context_name == COUNTER_TYPE_RIF) + { + return std::make_shared>(context_name, SAI_OBJECT_TYPE_ROUTER_INTERFACE, m_vendorSai.get(), m_statsMode); + } + else if (context_name == COUNTER_TYPE_SWITCH_DEBUG) + { + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_SWITCH, m_vendorSai.get(), m_statsMode); + context->always_check_supported_counters = true; + context->use_sai_stats_capa_query = false; + context->use_sai_stats_ext = true; - for (int cntr_id = SAI_ROUTER_INTERFACE_STAT_IN_OCTETS; cntr_id <= SAI_ROUTER_INTERFACE_STAT_OUT_ERROR_PACKETS; ++cntr_id) + return context; + } + else if (context_name == COUNTER_TYPE_MACSEC_FLOW) + { + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_MACSEC_FLOW, m_vendorSai.get(), m_statsMode); + context->use_sai_stats_capa_query = false; + return context; + } + else if (context_name == COUNTER_TYPE_MACSEC_SA) + { + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_MACSEC_SA, m_vendorSai.get(), m_statsMode); + context->use_sai_stats_capa_query = false; + return context; + } + else if (context_name == COUNTER_TYPE_FLOW) { - sai_router_interface_stat_t counter = static_cast(cntr_id); + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_COUNTER, m_vendorSai.get(), m_statsMode); + context->use_sai_stats_capa_query = false; + context->use_sai_stats_ext = true; - sai_status_t status = m_vendorSai->getStats( - SAI_OBJECT_TYPE_ROUTER_INTERFACE, - rifRid, - 1, - (const sai_stat_id_t *)&counter, - &value); + return context; + } + else if (context_name == COUNTER_TYPE_TUNNEL) + { + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_TUNNEL, m_vendorSai.get(), m_statsMode); + context->use_sai_stats_capa_query = false; + return context; + } + else if (context_name == COUNTER_TYPE_BUFFER_POOL) + { + auto context = std::make_shared>(context_name, SAI_OBJECT_TYPE_BUFFER_POOL, m_vendorSai.get(), m_statsMode); + context->always_check_supported_counters = true; + return context; + } + else if (context_name == ATTR_TYPE_QUEUE) + { + return std::make_shared>(context_name, SAI_OBJECT_TYPE_QUEUE, m_vendorSai.get(), m_statsMode); + } + else if (context_name == ATTR_TYPE_PG) + { + return std::make_shared>(context_name, SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, m_vendorSai.get(), m_statsMode); + } + else if (context_name == ATTR_TYPE_MACSEC_SA) + { + return std::make_shared>(context_name, SAI_OBJECT_TYPE_MACSEC_SA, m_vendorSai.get(), m_statsMode); + } + else if (context_name == ATTR_TYPE_ACL_COUNTER) + { + return std::make_shared>(context_name, SAI_OBJECT_TYPE_ACL_COUNTER, m_vendorSai.get(), m_statsMode); + } - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_INFO("Counter %s is not supported on router interface RID %s: %s", - sai_serialize_router_interface_stat(counter).c_str(), - sai_serialize_object_id(rifRid).c_str(), - sai_serialize_status(status).c_str()); + SWSS_LOG_THROW("Invalid counter type %s", context_name.c_str()); + // GCC 8.3 requires a return value here + return nullptr; +} - continue; - } +std::shared_ptr FlexCounter::getCounterContext( + _In_ const std::string &name) +{ + SWSS_LOG_ENTER(); - m_supportedRifCounters.insert(counter); + auto iter = m_counterContext.find(name); + if (iter != m_counterContext.end()) + { + return iter->second; } + + auto ret = m_counterContext.emplace(name, createCounterContext(name)); + return ret.first->second; } -void FlexCounter::updateSupportedFlowCounters( - _In_ sai_object_id_t counterRid, - _In_ const std::vector &counterIds) +void FlexCounter::removeCounterContext( + _In_ const std::string &name) { SWSS_LOG_ENTER(); - if (!m_supportedFlowCounters.empty()) + auto iter = m_counterContext.find(name); + if (iter != m_counterContext.end()) { - return; + m_counterContext.erase(iter); } - - uint64_t value; - for (auto &counter : counterIds) + else { - sai_status_t status = m_vendorSai->getStatsExt( - SAI_OBJECT_TYPE_COUNTER, - counterRid, - 1, - (const sai_stat_id_t *)&counter, - SAI_STATS_MODE_READ, - &value); - - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_NOTICE("%s: counter %s is not supported on flow counter %s, rv: %s", - m_instanceId.c_str(), - sai_serialize_counter_stat(counter).c_str(), - sai_serialize_object_id(counterRid).c_str(), - sai_serialize_status(status).c_str()); - - continue; - } - - m_supportedFlowCounters.insert(counter); + SWSS_LOG_ERROR("Try to remove non-exist counter context %s", name.c_str()); } } -void FlexCounter::updateSupportedRifCounters( - _In_ sai_object_id_t rifRid) +bool FlexCounter::hasCounterContext( + _In_ const std::string &name) const { SWSS_LOG_ENTER(); + return m_counterContext.find(name) != m_counterContext.end(); +} - if (m_supportedRifCounters.size()) - { - return; - } +void FlexCounter::collectCounters( + _In_ swss::Table &countersTable) +{ + SWSS_LOG_ENTER(); - /* Query SAI supported rif counters */ - sai_status_t status = querySupportedRifCounters(rifRid); - if (status != SAI_STATUS_SUCCESS) + for (const auto &it : m_counterContext) { - /* Fallback to legacy approach */ - getSupportedRifCounters(rifRid); + it.second->collectData(countersTable); } + + countersTable.flush(); } -sai_status_t FlexCounter::querySupportedBufferPoolCounters( - _In_ sai_object_id_t bufferPoolId, - _In_ sai_stats_mode_t statsMode) +void FlexCounter::runPlugins( + _In_ swss::DBConnector& counters_db) { SWSS_LOG_ENTER(); - sai_stat_capability_list_t stats_capability; - stats_capability.count = 0; - stats_capability.list = nullptr; - - /* First call is to check the size needed to allocate */ - sai_status_t status = m_vendorSai->queryStatsCapability( - bufferPoolId, - SAI_OBJECT_TYPE_BUFFER_POOL, - &stats_capability); - - /* Second call is for query statistics capability */ - if (status == SAI_STATUS_BUFFER_OVERFLOW) + const std::vector argv = { - std::vector statCapabilityList(stats_capability.count); - stats_capability.list = statCapabilityList.data(); - status = m_vendorSai->queryStatsCapability( - bufferPoolId, - SAI_OBJECT_TYPE_BUFFER_POOL, - &stats_capability); + std::to_string(counters_db.getDbId()), + COUNTERS_TABLE, + std::to_string(m_pollInterval) + }; - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_INFO("Unable to get buffer pool supported counters for %s", - sai_serialize_object_id(bufferPoolId).c_str()); - } - else - { - for (auto statCapability: statCapabilityList) - { - auto currentStatModes = statCapability.stat_modes; - if ((m_statsMode == SAI_STATS_MODE_READ_AND_CLEAR || statsMode == SAI_STATS_MODE_READ_AND_CLEAR) && - !isStatsModeSupported(currentStatModes, SAI_STATS_MODE_READ_AND_CLEAR)) - { - continue; - } - sai_buffer_pool_stat_t counter = static_cast(statCapability.stat_enum); - m_supportedBufferPoolCounters.insert(counter); - } - } + for (const auto &it : m_counterContext) + { + it.second->runPlugin(counters_db, argv); } - return status; } -void FlexCounter::getSupportedBufferPoolCounters( - _In_ sai_object_id_t bufferPoolId, - _In_ const std::vector &counterIds, - _In_ sai_stats_mode_t statsMode) +void FlexCounter::flexCounterThreadRunFunction() { SWSS_LOG_ENTER(); - uint64_t value; + swss::DBConnector db(m_dbCounters, 0); + swss::RedisPipeline pipeline(&db); + swss::Table countersTable(&pipeline, COUNTERS_TABLE, true); - for (const auto &counterId : counterIds) + while (m_runFlexCounterThread) { - sai_status_t status = m_vendorSai->getStats( - SAI_OBJECT_TYPE_BUFFER_POOL, - bufferPoolId, - 1, - (const sai_stat_id_t *)&counterId, - &value); + MUTEX; - if (status != SAI_STATUS_SUCCESS) + if (m_enable && !allIdsEmpty() && (m_pollInterval > 0)) { - SWSS_LOG_ERROR("%s: counter %s is not supported on buffer pool %s, rv: %s", - m_instanceId.c_str(), - sai_serialize_buffer_pool_stat(counterId).c_str(), - sai_serialize_object_id(bufferPoolId).c_str(), - sai_serialize_status(status).c_str()); - - continue; - } + auto start = std::chrono::steady_clock::now(); - if (m_statsMode == SAI_STATS_MODE_READ_AND_CLEAR || statsMode == SAI_STATS_MODE_READ_AND_CLEAR) - { - status = m_vendorSai->clearStats( - SAI_OBJECT_TYPE_BUFFER_POOL, - bufferPoolId, - 1, - (const sai_stat_id_t *)&counterId); + collectCounters(countersTable); - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("%s: clear counter %s is not supported on buffer pool %s, rv: %s", - m_instanceId.c_str(), - sai_serialize_buffer_pool_stat(counterId).c_str(), - sai_serialize_object_id(bufferPoolId).c_str(), - sai_serialize_status(status).c_str()); + runPlugins(db); - continue; - } - } + auto finish = std::chrono::steady_clock::now(); - m_supportedBufferPoolCounters.insert(counterId); - } -} + uint32_t delay = static_cast( + std::chrono::duration_cast(finish - start).count()); -void FlexCounter::updateSupportedTunnelCounters( - _In_ sai_object_id_t tunnelRid, - _In_ const std::vector &counterIds) -{ - SWSS_LOG_ENTER(); + uint32_t correction = delay % m_pollInterval; + correction = m_pollInterval - correction; + MUTEX_UNLOCK; // explicit unlock - if (m_supportedTunnelCounters.size()) - { - return; - } + SWSS_LOG_DEBUG("End of flex counter thread FC %s, took %d ms", m_instanceId.c_str(), delay); - uint64_t value; - for (auto &counter: counterIds) - { - sai_status_t status = m_vendorSai->getStats( - SAI_OBJECT_TYPE_TUNNEL, - tunnelRid, - 1, - (const sai_stat_id_t *)&counter, - &value); + std::unique_lock lk(m_mtxSleep); - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_INFO("Counter %s is not supported on tunnel RID %s: %s", - sai_serialize_tunnel_stat(counter).c_str(), - sai_serialize_object_id(tunnelRid).c_str(), - sai_serialize_status(status).c_str()); + m_cvSleep.wait_for(lk, std::chrono::milliseconds(correction)); continue; } - m_supportedTunnelCounters.insert(counter); + MUTEX_UNLOCK; // explicit unlock + + // nothing to collect, wait until notified + waitPoll(); } } -void FlexCounter::updateSupportedBufferPoolCounters( - _In_ sai_object_id_t bufferPoolId, - _In_ const std::vector &counterIds, - _In_ sai_stats_mode_t statsMode) +void FlexCounter::startFlexCounterThread() { SWSS_LOG_ENTER(); - m_supportedBufferPoolCounters.clear(); + m_runFlexCounterThread = true; - /* Query SAI supported buffer pool counters */ - sai_status_t status = querySupportedBufferPoolCounters(bufferPoolId, statsMode); - if (status != SAI_STATUS_SUCCESS) - { - /* Fallback to legacy approach */ - getSupportedBufferPoolCounters(bufferPoolId, counterIds, statsMode); - } + m_flexCounterThread = std::make_shared(&FlexCounter::flexCounterThreadRunFunction, this); + + SWSS_LOG_INFO("Flex Counter thread started"); } -std::vector FlexCounter::saiCheckSupportedSwitchDebugCounters( - _In_ sai_object_id_t switchId, - _In_ const std::vector &counterIds) +void FlexCounter::endFlexCounterThread(void) { SWSS_LOG_ENTER(); - std::vector supportedSwitchDebugCounters; - uint64_t value; - for (auto counter: counterIds) + MUTEX; + + if (!m_runFlexCounterThread) { - if (counter < SAI_SWITCH_STAT_IN_DROP_REASON_RANGE_BASE || counter >= SAI_SWITCH_STAT_OUT_DROP_REASON_RANGE_END) - { - SWSS_LOG_NOTICE("Debug counter %s out of bounds", sai_serialize_switch_stat(counter).c_str()); - continue; - } + return; + } - sai_status_t status = m_vendorSai->getStatsExt( - SAI_OBJECT_TYPE_SWITCH, - switchId, - 1, (const sai_stat_id_t *)&counter, - SAI_STATS_MODE_READ, - &value); + m_runFlexCounterThread = false; - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_NOTICE("Debug counter %s is not supported on switch RID %s: %s", - sai_serialize_switch_stat(counter).c_str(), - sai_serialize_object_id(switchId).c_str(), - sai_serialize_status(status).c_str()); + notifyPoll(); - continue; - } + m_cvSleep.notify_all(); + + if (m_flexCounterThread != nullptr) + { + auto fcThread = std::move(m_flexCounterThread); + + MUTEX_UNLOCK; // NOTE: explicit unlock before join to not cause deadlock + + SWSS_LOG_INFO("Wait for Flex Counter thread to end"); - supportedSwitchDebugCounters.push_back(counter); + fcThread->join(); } - return supportedSwitchDebugCounters; + SWSS_LOG_INFO("Flex Counter thread ended"); } void FlexCounter::removeCounter( @@ -3120,48 +1300,98 @@ void FlexCounter::removeCounter( if (objectType == SAI_OBJECT_TYPE_PORT) { - removePort(vid); - removePortDebugCounters(vid); + if (hasCounterContext(COUNTER_TYPE_PORT)) + { + getCounterContext(COUNTER_TYPE_PORT)->removeObject(vid); + } + if (hasCounterContext(COUNTER_TYPE_PORT_DEBUG)) + { + getCounterContext(COUNTER_TYPE_PORT_DEBUG)->removeObject(vid); + } } else if (objectType == SAI_OBJECT_TYPE_QUEUE) { - removeQueue(vid); + if (hasCounterContext(COUNTER_TYPE_QUEUE)) + { + getCounterContext(COUNTER_TYPE_QUEUE)->removeObject(vid); + } + if (hasCounterContext(ATTR_TYPE_QUEUE)) + { + getCounterContext(ATTR_TYPE_QUEUE)->removeObject(vid); + } } else if (objectType == SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP) { - removePriorityGroup(vid); + if (hasCounterContext(COUNTER_TYPE_PG)) + { + getCounterContext(COUNTER_TYPE_PG)->removeObject(vid); + } + if (hasCounterContext(ATTR_TYPE_PG)) + { + getCounterContext(ATTR_TYPE_PG)->removeObject(vid); + } } else if (objectType == SAI_OBJECT_TYPE_ROUTER_INTERFACE) { - removeRif(vid); + if (hasCounterContext(COUNTER_TYPE_RIF)) + { + getCounterContext(COUNTER_TYPE_RIF)->removeObject(vid); + } } else if (objectType == SAI_OBJECT_TYPE_BUFFER_POOL) { - removeBufferPool(vid); + if (hasCounterContext(COUNTER_TYPE_BUFFER_POOL)) + { + getCounterContext(COUNTER_TYPE_BUFFER_POOL)->removeObject(vid); + } } else if (objectType == SAI_OBJECT_TYPE_SWITCH) { - removeSwitchDebugCounters(vid); + if (hasCounterContext(COUNTER_TYPE_SWITCH_DEBUG)) + { + getCounterContext(COUNTER_TYPE_SWITCH_DEBUG)->removeObject(vid); + } } else if (objectType == SAI_OBJECT_TYPE_MACSEC_FLOW) { - removeMACsecFlow(vid); + if (hasCounterContext(COUNTER_TYPE_MACSEC_FLOW)) + { + getCounterContext(COUNTER_TYPE_MACSEC_FLOW)->removeObject(vid); + } } else if (objectType == SAI_OBJECT_TYPE_MACSEC_SA) { - removeMACsecSA(vid); + if (hasCounterContext(COUNTER_TYPE_MACSEC_SA)) + { + getCounterContext(COUNTER_TYPE_MACSEC_SA)->removeObject(vid); + } + + if (hasCounterContext(ATTR_TYPE_MACSEC_SA)) + { + getCounterContext(ATTR_TYPE_MACSEC_SA)->removeObject(vid); + } } else if (objectType == SAI_OBJECT_TYPE_ACL_COUNTER) { - removeAclCounter(vid); + if (hasCounterContext(ATTR_TYPE_ACL_COUNTER)) + { + getCounterContext(ATTR_TYPE_ACL_COUNTER)->removeObject(vid); + } } else if (objectType == SAI_OBJECT_TYPE_TUNNEL) { - removeTunnel(vid); + if (hasCounterContext(COUNTER_TYPE_TUNNEL)) + { + getCounterContext(COUNTER_TYPE_TUNNEL)->removeObject(vid); + } } else if (objectType == SAI_OBJECT_TYPE_COUNTER) { - removeFlowCounter(vid); + if (hasCounterContext(COUNTER_TYPE_FLOW)) + { + getCounterContext(COUNTER_TYPE_FLOW)->removeObject(vid); + removeDataFromCountersDB(vid, ":TRAP"); + } } else { @@ -3194,173 +1424,108 @@ void FlexCounter::addCounter( if (objectType == SAI_OBJECT_TYPE_PORT && field == PORT_COUNTER_ID_LIST) { - std::vector portCounterIds; - - for (const auto &str : idStrings) - { - sai_port_stat_t stat; - sai_deserialize_port_stat(str.c_str(), &stat); - portCounterIds.push_back(stat); - } - - setPortCounterList(vid, rid, portCounterIds); - + getCounterContext(COUNTER_TYPE_PORT)->addObject( + vid, + rid, + idStrings, + ""); } else if (objectType == SAI_OBJECT_TYPE_PORT && field == PORT_DEBUG_COUNTER_ID_LIST) { - std::vector portDebugCounterIds; - - for (const auto &str : idStrings) - { - sai_port_stat_t stat; - sai_deserialize_port_stat(str.c_str(), &stat); - portDebugCounterIds.push_back(stat); - } - - setPortDebugCounterList(vid, rid, portDebugCounterIds); + getCounterContext(COUNTER_TYPE_PORT_DEBUG)->addObject( + vid, + rid, + idStrings, + ""); } else if (objectType == SAI_OBJECT_TYPE_QUEUE && field == QUEUE_COUNTER_ID_LIST) { - std::vector queueCounterIds; - - for (const auto &str : idStrings) - { - sai_queue_stat_t stat; - sai_deserialize_queue_stat(str.c_str(), &stat); - queueCounterIds.push_back(stat); - } + getCounterContext(COUNTER_TYPE_QUEUE)->addObject( + vid, + rid, + idStrings, + ""); - setQueueCounterList(vid, rid, queueCounterIds); } else if (objectType == SAI_OBJECT_TYPE_QUEUE && field == QUEUE_ATTR_ID_LIST) { - std::vector queueAttrIds; - - for (const auto &str : idStrings) - { - sai_queue_attr_t attr; - sai_deserialize_queue_attr(str, attr); - queueAttrIds.push_back(attr); - } - - setQueueAttrList(vid, rid, queueAttrIds); + getCounterContext(ATTR_TYPE_QUEUE)->addObject( + vid, + rid, + idStrings, + ""); } else if (objectType == SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP && field == PG_COUNTER_ID_LIST) { - std::vector pgCounterIds; - - for (const auto &str : idStrings) - { - sai_ingress_priority_group_stat_t stat; - sai_deserialize_ingress_priority_group_stat(str.c_str(), &stat); - pgCounterIds.push_back(stat); - } - - setPriorityGroupCounterList(vid, rid, pgCounterIds); + getCounterContext(COUNTER_TYPE_PG)->addObject( + vid, + rid, + idStrings, + ""); } else if (objectType == SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP && field == PG_ATTR_ID_LIST) { - std::vector pgAttrIds; - - for (const auto &str : idStrings) - { - sai_ingress_priority_group_attr_t attr; - sai_deserialize_ingress_priority_group_attr(str, attr); - pgAttrIds.push_back(attr); - } - - setPriorityGroupAttrList(vid, rid, pgAttrIds); + getCounterContext(ATTR_TYPE_PG)->addObject( + vid, + rid, + idStrings, + ""); } else if (objectType == SAI_OBJECT_TYPE_ROUTER_INTERFACE && field == RIF_COUNTER_ID_LIST) { - std::vector rifCounterIds; - - for (const auto &str : idStrings) - { - sai_router_interface_stat_t stat; - sai_deserialize_router_interface_stat(str.c_str(), &stat); - rifCounterIds.push_back(stat); - } - - setRifCounterList(vid, rid, rifCounterIds); + getCounterContext(COUNTER_TYPE_RIF)->addObject( + vid, + rid, + idStrings, + ""); } else if (objectType == SAI_OBJECT_TYPE_SWITCH && field == SWITCH_DEBUG_COUNTER_ID_LIST) { - std::vector switchCounterIds; - - for (const auto &str : idStrings) - { - sai_switch_stat_t stat; - sai_deserialize_switch_stat(str.c_str(), &stat); - switchCounterIds.push_back(stat); - } - - setSwitchDebugCounterList(vid, rid, switchCounterIds); + getCounterContext(COUNTER_TYPE_SWITCH_DEBUG)->addObject( + vid, + rid, + idStrings, + ""); } else if (objectType == SAI_OBJECT_TYPE_MACSEC_FLOW && field == MACSEC_FLOW_COUNTER_ID_LIST) { - std::vector macsecFlowCounterIds; - - for (const auto &str : idStrings) - { - sai_macsec_flow_stat_t stat; - sai_deserialize_macsec_flow_stat(str.c_str(), &stat); - macsecFlowCounterIds.push_back(stat); - } - - setMACsecFlowCounterList(vid, rid, macsecFlowCounterIds); + getCounterContext(COUNTER_TYPE_MACSEC_FLOW)->addObject( + vid, + rid, + idStrings, + ""); } else if (objectType == SAI_OBJECT_TYPE_MACSEC_SA && field == MACSEC_SA_COUNTER_ID_LIST) { - std::vector macsecSACounterIds; - - for (const auto &str : idStrings) - { - sai_macsec_sa_stat_t stat; - sai_deserialize_macsec_sa_stat(str.c_str(), &stat); - macsecSACounterIds.push_back(stat); - } - - setMACsecSACounterList(vid, rid, macsecSACounterIds); + getCounterContext(COUNTER_TYPE_MACSEC_SA)->addObject( + vid, + rid, + idStrings, + ""); } else if (objectType == SAI_OBJECT_TYPE_MACSEC_SA && field == MACSEC_SA_ATTR_ID_LIST) { - std::vector macsecSAAttrIds; - - for (const auto &str : idStrings) - { - sai_macsec_sa_attr_t attr; - sai_deserialize_macsec_sa_attr(str, attr); - macsecSAAttrIds.push_back(attr); - } - - setMACsecSAAttrList(vid, rid, macsecSAAttrIds); + getCounterContext(ATTR_TYPE_MACSEC_SA)->addObject( + vid, + rid, + idStrings, + ""); } else if (objectType == SAI_OBJECT_TYPE_ACL_COUNTER && field == ACL_COUNTER_ATTR_ID_LIST) { - std::vector aclCounterIds; - - for (const auto &str : idStrings) - { - sai_acl_counter_attr_t attr{}; - sai_deserialize_acl_counter_attr(str, attr); - aclCounterIds.push_back(attr); - } - - setAclCounterAttrList(vid, rid, aclCounterIds); + getCounterContext(ATTR_TYPE_ACL_COUNTER)->addObject( + vid, + rid, + idStrings, + ""); } else if (objectType == SAI_OBJECT_TYPE_COUNTER && field == FLOW_COUNTER_ID_LIST) { - std::vector counterStatIds; - - for (const auto &str : idStrings) - { - sai_counter_stat_t stat; - sai_deserialize_counter_stat(str.c_str(), &stat); - counterStatIds.push_back(stat); - } - - setFlowCounterList(vid, rid, counterStatIds); + getCounterContext(COUNTER_TYPE_FLOW)->addObject( + vid, + rid, + idStrings, + ""); } else if (objectType == SAI_OBJECT_TYPE_BUFFER_POOL && field == BUFFER_POOL_COUNTER_ID_LIST) { @@ -3372,16 +1537,11 @@ void FlexCounter::addCounter( } else if (objectType == SAI_OBJECT_TYPE_TUNNEL && field == TUNNEL_COUNTER_ID_LIST) { - std::vector tunnelCounterIds; - - for (const auto &str : idStrings) - { - sai_tunnel_stat_t stat; - sai_deserialize_tunnel_stat(str.c_str(), &stat); - tunnelCounterIds.push_back(stat); - } - - setTunnelCounterList(vid, rid, tunnelCounterIds); + getCounterContext(COUNTER_TYPE_TUNNEL)->addObject( + vid, + rid, + idStrings, + ""); } else { @@ -3395,16 +1555,11 @@ void FlexCounter::addCounter( if (objectType == SAI_OBJECT_TYPE_BUFFER_POOL && counterIds.size()) { - std::vector bufferPoolCounterIds; - - for (const auto &str : counterIds) - { - sai_buffer_pool_stat_t stat; - sai_deserialize_buffer_pool_stat(str.c_str(), &stat); - bufferPoolCounterIds.push_back(stat); - } - - setBufferPoolCounterList(vid, rid, bufferPoolCounterIds, statsMode); + getCounterContext(COUNTER_TYPE_BUFFER_POOL)->addObject( + vid, + rid, + counterIds, + statsMode); } // notify thread to start polling diff --git a/syncd/FlexCounter.h b/syncd/FlexCounter.h index cfc79b660..0ed9c8be3 100644 --- a/syncd/FlexCounter.h +++ b/syncd/FlexCounter.h @@ -13,17 +13,55 @@ extern "C" { #include #include #include +#include namespace syncd { + class BaseCounterContext + { + public: + BaseCounterContext(const std::string &name); + void addPlugins( + _In_ const std::vector& shaStrings); + + bool hasPlugin() const {return !m_plugins.empty();} + + void removePlugins() {m_plugins.clear();} + + virtual void addObject( + _In_ sai_object_id_t vid, + _In_ sai_object_id_t rid, + _In_ const std::vector &idStrings, + _In_ const std::string &per_object_stats_mode) = 0; + + virtual void removeObject( + _In_ sai_object_id_t vid) = 0; + + virtual void collectData( + _In_ swss::Table &countersTable) = 0; + + virtual void runPlugin( + _In_ swss::DBConnector& counters_db, + _In_ const std::vector& argv) = 0; + + virtual bool hasObject() const = 0; + + protected: + std::string m_name; + std::set m_plugins; + + public: + bool always_check_supported_counters = false; + bool use_sai_stats_capa_query = true; + bool use_sai_stats_ext = false; + bool double_confirm_supported_counters = false; + }; class FlexCounter { private: - FlexCounter(const FlexCounter&) = delete; public: - FlexCounter( _In_ const std::string& instanceId, _In_ std::shared_ptr vendorSai, @@ -32,7 +70,6 @@ namespace syncd virtual ~FlexCounter(); public: - void addCounterPlugin( _In_ const std::vector& values); @@ -61,396 +98,28 @@ namespace syncd void setStatsMode( _In_ const std::string& mode); - private: // plugins - - void addPortCounterPlugin( - _In_ const std::string& sha); - - void addRifCounterPlugin( - _In_ const std::string& sha); - - void addBufferPoolCounterPlugin( - _In_ const std::string& sha); - - void addPriorityGroupCounterPlugin( - _In_ const std::string& sha); - - void addQueueCounterPlugin( - _In_ const std::string& sha); - - void addTunnelCounterPlugin( - _In_ const std::string& sha); - - void addFlowCounterPlugin( - _In_ const std::string& sha); - private: - - void checkPluginRegistered( - _In_ const std::string& sha) const; - bool allIdsEmpty() const; bool allPluginsEmpty() const; private: // remove counter + void removeDataFromCountersDB( + _In_ sai_object_id_t vid, + _In_ const std::string &ratePrefix); - void removePort( - _In_ sai_object_id_t portVid); - - void removePortDebugCounters( - _In_ sai_object_id_t portVid); - - void removeQueue( - _In_ sai_object_id_t queueVid); - - void removePriorityGroup( - _In_ sai_object_id_t priorityGroupVid); - - void removeRif( - _In_ sai_object_id_t rifVid); - - void removeBufferPool( - _In_ sai_object_id_t bufferPoolVid); - - void removeSwitchDebugCounters( - _In_ sai_object_id_t switchVid); - - void removeMACsecFlow( - _In_ sai_object_id_t macsecFlowVid); - - void removeMACsecSA( - _In_ sai_object_id_t macsecSAVid); - - void removeAclCounter( - _In_ sai_object_id_t aclCounterVid); - - void removeTunnel( - _In_ sai_object_id_t tunnelVid); - - void removeFlowCounter( - _In_ sai_object_id_t counterVid); - - private: // set counter list - - void setPortCounterList( - _In_ sai_object_id_t portVid, - _In_ sai_object_id_t portRid, - _In_ const std::vector &counterIds); - - void setPortDebugCounterList( - _In_ sai_object_id_t portVid, - _In_ sai_object_id_t portRid, - _In_ const std::vector &counterIds); - - void setQueueCounterList( - _In_ sai_object_id_t queueVid, - _In_ sai_object_id_t queueRid, - _In_ const std::vector &counterIds); - - void setPriorityGroupCounterList( - _In_ sai_object_id_t priorityGroupVid, - _In_ sai_object_id_t priorityGroupRid, - _In_ const std::vector &counterIds); - - void setRifCounterList( - _In_ sai_object_id_t rifVid, - _In_ sai_object_id_t rifRid, - _In_ const std::vector &counterIds); - - void setSwitchDebugCounterList( - _In_ sai_object_id_t switchVid, - _In_ sai_object_id_t switchRid, - _In_ const std::vector &counterIds); - - void setBufferPoolCounterList( - _In_ sai_object_id_t bufferPoolVid, - _In_ sai_object_id_t bufferPoolRid, - _In_ const std::vector& counterIds, - _In_ const std::string& statsMode); - - void setTunnelCounterList( - _In_ sai_object_id_t tunnelVid, - _In_ sai_object_id_t tunnelRid, - _In_ const std::vector &counterIds); - - void setFlowCounterList( - _In_ sai_object_id_t counterVid, - _In_ sai_object_id_t counterRid, - _In_ const std::vector& counterIds); - - void setMACsecFlowCounterList( - _In_ sai_object_id_t macsecFlowVid, - _In_ sai_object_id_t macsecFlowRid, - _In_ const std::vector &counterIds); - - void setMACsecSACounterList( - _In_ sai_object_id_t macsecSAVid, - _In_ sai_object_id_t macsecSARid, - _In_ const std::vector &counterIds); - - private: // set attr list - - void setQueueAttrList( - _In_ sai_object_id_t queueVid, - _In_ sai_object_id_t queueRid, - _In_ const std::vector &attrIds); - - void setPriorityGroupAttrList( - _In_ sai_object_id_t priorityGroupVid, - _In_ sai_object_id_t priorityGroupRid, - _In_ const std::vector &attrIds); - - void setMACsecSAAttrList( - _In_ sai_object_id_t macsecSAVid, - _In_ sai_object_id_t macsecSARid, - _In_ const std::vector &attrIds); - - void setAclCounterAttrList( - _In_ sai_object_id_t aclCounterVid, - _In_ sai_object_id_t aclCounterRid, - _In_ const std::vector &attrIds); - - private: // is counter supported - - bool isPriorityGroupCounterSupported( - _In_ sai_ingress_priority_group_stat_t counter) const; - - bool isQueueCounterSupported( - _In_ sai_queue_stat_t counter) const; - - bool isRifCounterSupported( - _In_ sai_router_interface_stat_t counter) const; - - bool isBufferPoolCounterSupported( - _In_ sai_buffer_pool_stat_t counter) const; - - bool isTunnelCounterSupported( - _In_ sai_tunnel_stat_t counter) const; - - bool isStatsModeSupported( - _In_ uint32_t statsMode, - _In_ sai_stats_mode_t statCapability); - - private: // update supported counters - - typedef std::set PortCountersSet; - sai_status_t querySupportedPortCounters( - _In_ sai_object_id_t portRid, - _Out_ PortCountersSet &supportedPortCounters); - - void getSupportedPortCounters( - _In_ sai_object_id_t portRid, - _Out_ PortCountersSet &supportedPortCounters); - - void updateSupportedPortCounters( - _In_ sai_object_id_t portRid, - _Out_ PortCountersSet &supportedPortCounters); - - std::vector saiCheckSupportedPortDebugCounters( - _In_ sai_object_id_t portRid, - _In_ const std::vector &counterIds); - - sai_status_t querySupportedQueueCounters( - _In_ sai_object_id_t queueId); - - void getSupportedQueueCounters( - _In_ sai_object_id_t queueId, const std::vector &counterIds); - - void updateSupportedQueueCounters( - _In_ sai_object_id_t queueRid, - _In_ const std::vector &counterIds); - - sai_status_t querySupportedRifCounters( - _In_ sai_object_id_t rifRid); - - void getSupportedRifCounters( - _In_ sai_object_id_t rifRid); - - void updateSupportedRifCounters( - _In_ sai_object_id_t rifRid); - - sai_status_t querySupportedBufferPoolCounters( - _In_ sai_object_id_t bufferPoolId, - _In_ sai_stats_mode_t statsMode); - - void getSupportedBufferPoolCounters( - _In_ sai_object_id_t bufferPoolId, - _In_ const std::vector &counterIds, - _In_ sai_stats_mode_t statsMode); - - void updateSupportedBufferPoolCounters( - _In_ sai_object_id_t bufferPoolRid, - _In_ const std::vector &counterIds, - _In_ sai_stats_mode_t statsMode); - - sai_status_t querySupportedPriorityGroupCounters( - _In_ sai_object_id_t priorityGroupRid); - - void getSupportedPriorityGroupCounters( - _In_ sai_object_id_t priorityGroupRid, - _In_ const std::vector &counterIds); - - void updateSupportedPriorityGroupCounters( - _In_ sai_object_id_t priorityGroupRid, - _In_ const std::vector &counterIds); - - void updateSupportedFlowCounters( - _In_ sai_object_id_t counterRid, - _In_ const std::vector &counterIds); - - std::vector saiCheckSupportedSwitchDebugCounters( - _In_ sai_object_id_t switchRid, - _In_ const std::vector &counterIds); - - void updateSupportedTunnelCounters( - _In_ sai_object_id_t tunnelRid, - _In_ const std::vector &counterIds); private: + std::shared_ptr getCounterContext( + _In_ const std::string &name); - struct QueueCounterIds - { - QueueCounterIds( - _In_ sai_object_id_t queue, - _In_ const std::vector &queueIds); - - sai_object_id_t queueId; - std::vector queueCounterIds; - }; - - struct QueueAttrIds - { - QueueAttrIds( - _In_ sai_object_id_t queue, - _In_ const std::vector &queueIds); - - sai_object_id_t queueId; - std::vector queueAttrIds; - }; - - struct IngressPriorityGroupCounterIds - { - IngressPriorityGroupCounterIds( - _In_ sai_object_id_t priorityGroup, - _In_ const std::vector &priorityGroupIds); - - sai_object_id_t priorityGroupId; - std::vector priorityGroupCounterIds; - }; - - struct IngressPriorityGroupAttrIds - { - IngressPriorityGroupAttrIds( - _In_ sai_object_id_t priorityGroup, - _In_ const std::vector &priorityGroupIds); - - sai_object_id_t priorityGroupId; - std::vector priorityGroupAttrIds; - }; - - struct BufferPoolCounterIds - { - BufferPoolCounterIds( - _In_ sai_object_id_t bufferPool, - _In_ const std::vector &bufferPoolIds, - _In_ sai_stats_mode_t statsMode); - - sai_object_id_t bufferPoolId; - sai_stats_mode_t bufferPoolStatsMode; - std::vector bufferPoolCounterIds; - }; - - struct PortCounterIds - { - PortCounterIds( - _In_ sai_object_id_t port, - _In_ const std::vector &portIds); - - sai_object_id_t portId; - std::vector portCounterIds; - }; - - struct SwitchCounterIds - { - SwitchCounterIds( - _In_ sai_object_id_t oid, - _In_ const std::vector &counterIds); - - sai_object_id_t switchId; - std::vector switchCounterIds; - }; - - struct RifCounterIds - { - RifCounterIds( - _In_ sai_object_id_t rif, - _In_ const std::vector &rifIds); - - sai_object_id_t rifId; - std::vector rifCounterIds; - }; - - struct MACsecFlowCounterIds - { - MACsecFlowCounterIds( - _In_ sai_object_id_t macsecFlow, - _In_ const std::vector &macsecFlowIds); - - sai_object_id_t m_macsecFlowId; - std::vector m_macsecFlowCounterIds; - }; - - struct MACsecSACounterIds - { - MACsecSACounterIds( - _In_ sai_object_id_t macsecSA, - _In_ const std::vector &macsecSAIds); - - sai_object_id_t m_macsecSAId; - std::vector m_macsecSACounterIds; - }; - - struct MACsecSAAttrIds - { - MACsecSAAttrIds( - _In_ sai_object_id_t macsecSA, - _In_ const std::vector &macsecSAIds); - - sai_object_id_t m_macsecSAId; - std::vector m_macsecSAAttrIds; - }; - - struct AclCounterAttrIds - { - AclCounterAttrIds( - _In_ sai_object_id_t aclCounter, - _In_ const std::vector &aclCounterIds); - - sai_object_id_t m_aclCounterId; - std::vector m_aclCounterAttrIds; - }; - - struct TunnelCounterIds - { - TunnelCounterIds( - _In_ sai_object_id_t tunnel, - _In_ const std::vector &tunnelIds); - - sai_object_id_t m_tunnelId; - std::vector m_tunnelCounterIds; - }; - - struct FlowCounterIds - { - FlowCounterIds( - _In_ sai_object_id_t counterId, - _In_ const std::vector &flowCounterIds); - - sai_object_id_t counterId; - std::vector flowCounterIds; - }; + std::shared_ptr createCounterContext( + _In_ const std::string &name); - private: + void removeCounterContext( + _In_ const std::string &name); + + bool hasCounterContext( + _In_ const std::string &name) const; void collectCounters( _In_ swss::Table &countersTable); @@ -464,116 +133,12 @@ namespace syncd void flexCounterThreadRunFunction(); - private: - - typedef void (FlexCounter::*collect_counters_handler_t)( - _In_ swss::Table &countersTable); - - typedef std::unordered_map collect_counters_handler_unordered_map_t; - - private: // collect counters: - - void collectPortCounters( - _In_ swss::Table &countersTable); - - void collectPortDebugCounters( - _In_ swss::Table &countersTable); - - void collectQueueCounters( - _In_ swss::Table &countersTable); - - void collectPriorityGroupCounters( - _In_ swss::Table &countersTable); - - void collectRifCounters( - _In_ swss::Table &countersTable); - - void collectBufferPoolCounters( - _In_ swss::Table &countersTable); - - void collectSwitchDebugCounters( - _In_ swss::Table &countersTable); - - void collectTunnelCounters( - _In_ swss::Table &countersTable); - - void collectFlowCounters( - _In_ swss::Table &countersTable); - - void collectMACsecFlowCounters( - _In_ swss::Table &countersTable); - - void collectMACsecSACounters( - _In_ swss::Table &countersTable); - - private: // collect attributes - - void collectQueueAttrs( - _In_ swss::Table &countersTable); - - void collectPriorityGroupAttrs( - _In_ swss::Table &countersTable); - - void collectMACsecSAAttrs( - _In_ swss::Table &countersTable); - - void collectAclCounterAttrs( - _In_ swss::Table &countersTable); - - private: - - void addCollectCountersHandler( - _In_ const std::string& key, - _In_ const collect_counters_handler_t &handler); - - void removeCollectCountersHandler( - _In_ const std::string& key); - private: void waitPoll(); void notifyPoll(); - private: // plugins - - std::set m_queuePlugins; - std::set m_portPlugins; - std::set m_rifPlugins; - std::set m_priorityGroupPlugins; - std::set m_bufferPoolPlugins; - std::set m_tunnelPlugins; - std::set m_flowCounterPlugins; - - private: // supported counters - - std::set m_supportedPriorityGroupCounters; - std::set m_supportedQueueCounters; - std::set m_supportedRifCounters; - std::set m_supportedBufferPoolCounters; - std::set m_supportedTunnelCounters; - std::set m_supportedFlowCounters; - - private: // registered VID maps - - std::map> m_portCounterIdsMap; - std::map> m_portDebugCounterIdsMap; - std::map> m_queueCounterIdsMap; - std::map> m_priorityGroupCounterIdsMap; - std::map> m_rifCounterIdsMap; - std::map> m_bufferPoolCounterIdsMap; - std::map> m_switchDebugCounterIdsMap; - std::map> m_tunnelCounterIdsMap; - std::map> m_flowCounterIdsMap; - std::map> m_macsecFlowCounterIdsMap; - std::map> m_macsecSACounterIdsMap; - - std::map> m_queueAttrIdsMap; - std::map> m_priorityGroupAttrIdsMap; - std::map> m_macsecSAAttrIdsMap; - std::map> m_aclCounterAttrIdsMap; - private: - bool m_runFlexCounterThread; std::shared_ptr m_flexCounterThread; @@ -596,12 +161,12 @@ namespace syncd bool m_enable; - collect_counters_handler_unordered_map_t m_collectCountersHandlers; - std::shared_ptr m_vendorSai; std::string m_dbCounters; bool m_isDiscarded; + + std::map> m_counterContext; }; } diff --git a/unittest/syncd/TestFlexCounter.cpp b/unittest/syncd/TestFlexCounter.cpp index ea2aaf560..c770e9be8 100644 --- a/unittest/syncd/TestFlexCounter.cpp +++ b/unittest/syncd/TestFlexCounter.cpp @@ -8,97 +8,54 @@ using namespace syncd; using namespace std; -TEST(FlexCounter, addRemoveCounterForFlowCounter) +std::string join(const std::vector& input) { - std::shared_ptr sai(new MockableSaiInterface()); - FlexCounter fc("test", sai, "COUNTERS_DB"); - - sai_object_id_t counterVid{0x54000000000000}; - sai_object_id_t counterRid{0x54000000000000}; - std::vector values; - values.emplace_back(FLOW_COUNTER_ID_LIST, "SAI_COUNTER_STAT_PACKETS,SAI_COUNTER_STAT_BYTES"); - - test_syncd::mockVidManagerObjectTypeQuery(SAI_OBJECT_TYPE_COUNTER); - 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) * 100; - } - return SAI_STATUS_SUCCESS; - }; - - fc.addCounter(counterVid, counterRid, values); - EXPECT_EQ(fc.isEmpty(), false); - - values.clear(); - values.emplace_back(POLL_INTERVAL_FIELD, "1000"); - fc.addCounterPlugin(values); - - values.clear(); - values.emplace_back(FLEX_COUNTER_STATUS_FIELD, "enable"); - 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)); - EXPECT_EQ(keys[0], "oid:0x54000000000000"); - - std::string value; - countersTable.hget("oid:0x54000000000000", "SAI_COUNTER_STAT_PACKETS", value); - EXPECT_EQ(value, "100"); - countersTable.hget("oid:0x54000000000000", "SAI_COUNTER_STAT_BYTES", value); - EXPECT_EQ(value, "200"); - - fc.removeCounter(counterVid); - EXPECT_EQ(fc.isEmpty(), true); - countersTable.getKeys(keys); - - ASSERT_TRUE(keys.empty()); - + SWSS_LOG_ENTER(); + + if (input.empty()) + { + return ""; + } + std::ostringstream ostream; + auto iter = input.begin(); + ostream << *iter; + while (++iter != input.end()) + { + ostream << "," << *iter; + } + return ostream.str(); } -TEST(FlexCounter, addRemoveCounterPluginForFlowCounter) +template +std::string toOid(T value) { - std::shared_ptr sai(new MockableSaiInterface()); - FlexCounter fc("test", sai, "COUNTERS_DB"); - - std::vector values; - values.emplace_back(FLOW_COUNTER_PLUGIN_FIELD, "dummy_sha_strings"); - fc.addCounterPlugin(values); - EXPECT_EQ(fc.isEmpty(), false); + SWSS_LOG_ENTER(); - fc.removeCounterPlugins(); - EXPECT_EQ(fc.isEmpty(), true); + std::ostringstream ostream; + ostream << "oid:0x" << std::hex << value; + return ostream.str(); } -TEST(FlexCounter, addRemoveCounterForMACsecFlow) +std::shared_ptr sai(new MockableSaiInterface()); +typedef std::function& counterIdNames, const std::vector& expectedValues)> VerifyStatsFunc; + +void testAddRemoveCounter( + sai_object_id_t object_id, + sai_object_type_t object_type, + const std::string& counterIdFieldName, + const std::vector& counterIdNames, + const std::vector& expectedValues, + VerifyStatsFunc verifyFunc, + bool autoRemoveDbEntry, + const std::string statsMode = STATS_MODE_READ) { - std::shared_ptr sai(new MockableSaiInterface()); - FlexCounter fc("test", sai, "COUNTERS_DB"); - - sai_object_id_t macsecFlowVid{0x5a000000000000}; - sai_object_id_t macsecFlowRid{0x5a000000000000}; - std::vector values; - values.emplace_back(MACSEC_FLOW_COUNTER_ID_LIST, "SAI_MACSEC_FLOW_STAT_CONTROL_PKTS,SAI_MACSEC_FLOW_STAT_PKTS_UNTAGGED"); + SWSS_LOG_ENTER(); - test_syncd::mockVidManagerObjectTypeQuery(SAI_OBJECT_TYPE_MACSEC_FLOW); - 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) * 100; - } - return SAI_STATUS_SUCCESS; - }; + FlexCounter fc("test", sai, "COUNTERS_DB"); - fc.addCounter(macsecFlowVid, macsecFlowRid, values); - EXPECT_EQ(fc.isEmpty(), false); + test_syncd::mockVidManagerObjectTypeQuery(object_type); - values.clear(); + std::vector values; values.emplace_back(POLL_INTERVAL_FIELD, "1000"); fc.addCounterPlugin(values); @@ -106,42 +63,42 @@ TEST(FlexCounter, addRemoveCounterForMACsecFlow) values.emplace_back(FLEX_COUNTER_STATUS_FIELD, "enable"); fc.addCounterPlugin(values); - usleep(1000*1000); + 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); + EXPECT_EQ(fc.isEmpty(), false); + + usleep(1000*1050); swss::DBConnector db("COUNTERS_DB", 0); 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], "oid:0x5a000000000000"); + EXPECT_EQ(keys[0], expectedKey); - std::string value; - countersTable.hget("oid:0x5a000000000000", "SAI_MACSEC_FLOW_STAT_CONTROL_PKTS", value); - //EXPECT_EQ(value, "100"); - countersTable.hget("oid:0x5a000000000000", "SAI_MACSEC_FLOW_STAT_PKTS_UNTAGGED", value); - //EXPECT_EQ(value, "200"); + verifyFunc(countersTable, expectedKey, counterIdNames, expectedValues); - fc.removeCounter(macsecFlowVid); + fc.removeCounter(object_id); EXPECT_EQ(fc.isEmpty(), true); - countersTable.del("oid:0x5a000000000000"); - countersTable.getKeys(keys); - ASSERT_TRUE(keys.empty()); + if (!autoRemoveDbEntry) + { + countersTable.del(expectedKey); + } + countersTable.getKeys(keys); + ASSERT_TRUE(keys.empty()); } -TEST(FlexCounter, addRemoveCounterForMACsecSA) +TEST(FlexCounter, addRemoveCounter) { - std::shared_ptr sai(new MockableSaiInterface()); - FlexCounter fc("test", sai, "COUNTERS_DB"); - - sai_object_id_t macsecSAVid{0x5c000000000000}; - sai_object_id_t macsecSARid{0x5c000000000000}; - std::vector values; - values.emplace_back(MACSEC_SA_COUNTER_ID_LIST, "SAI_MACSEC_SA_STAT_OCTETS_ENCRYPTED,SAI_MACSEC_SA_STAT_OCTETS_PROTECTED"); - - test_syncd::mockVidManagerObjectTypeQuery(SAI_OBJECT_TYPE_MACSEC_SA); 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++) { @@ -149,130 +106,314 @@ TEST(FlexCounter, addRemoveCounterForMACsecSA) } 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) * 100; + } + 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; + }; - fc.addCounter(macsecSAVid, macsecSARid, values); - EXPECT_EQ(fc.isEmpty(), false); - - values.clear(); - values.emplace_back(POLL_INTERVAL_FIELD, "1000"); - fc.addCounterPlugin(values); - - values.clear(); - values.emplace_back(FLEX_COUNTER_STATUS_FIELD, "enable"); - fc.addCounterPlugin(values); + 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); + EXPECT_EQ(value, expectedValues[i]); + } + }; - usleep(1000*1000); - swss::DBConnector db("COUNTERS_DB", 0); - swss::RedisPipeline pipeline(&db); - swss::Table countersTable(&pipeline, COUNTERS_TABLE, false); + testAddRemoveCounter( + sai_object_id_t(0x54000000000000), + 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_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_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_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_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); + + 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; + return SAI_STATUS_SUCCESS; + }; - std::vector keys; - countersTable.getKeys(keys); - EXPECT_EQ(keys.size(), size_t(1)); - EXPECT_EQ(keys[0], "oid:0x5c000000000000"); + testAddRemoveCounter( + sai_object_id_t(0x15000000000000), + 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_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_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_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_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_TYPE_BUFFER_POOL, + BUFFER_POOL_COUNTER_ID_LIST, + {"SAI_BUFFER_POOL_STAT_CURR_OCCUPANCY_BYTES", "SAI_BUFFER_POOL_STAT_WATERMARK_BYTES"}, + {"100", "200"}, + counterVerifyFunc, + false); + EXPECT_EQ(true, clearCalled); + + 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++) + { + if (attr_list[i].id == SAI_QUEUE_ATTR_PAUSE_STATUS) + { + attr_list[i].value.booldata = false; + } + } + return SAI_STATUS_SUCCESS; + }; - std::string value; - countersTable.hget("oid:0x5c000000000000", "SAI_MACSEC_SA_STAT_OCTETS_ENCRYPTED", value); - //EXPECT_EQ(value, "100"); - countersTable.hget("oid:0x5c000000000000", "SAI_MACSEC_SA_STAT_OCTETS_PROTECTED", value); - //EXPECT_EQ(value, "200"); + testAddRemoveCounter( + sai_object_id_t(0x15000000000000), + SAI_OBJECT_TYPE_QUEUE, + QUEUE_ATTR_ID_LIST, + {"SAI_QUEUE_ATTR_PAUSE_STATUS"}, + {"false"}, + counterVerifyFunc, + false); + + 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++) + { + if (attr_list[i].id == SAI_INGRESS_PRIORITY_GROUP_ATTR_PORT) + { + attr_list[i].value.oid = 1; + } + } + return SAI_STATUS_SUCCESS; + }; - fc.removeCounter(macsecSAVid); - EXPECT_EQ(fc.isEmpty(), true); - countersTable.del("oid:0x5c000000000000"); - countersTable.getKeys(keys); + testAddRemoveCounter( + sai_object_id_t(0x1a000000000000), + SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP, + PG_ATTR_ID_LIST, + {"SAI_INGRESS_PRIORITY_GROUP_ATTR_PORT"}, + {"oid:0x1"}, + counterVerifyFunc, + false); + + 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++) + { + if (attr_list[i].id == SAI_MACSEC_SA_ATTR_CONFIGURED_EGRESS_XPN) + { + attr_list[i].value.u64 = 0; + } + else if (attr_list[i].id == SAI_MACSEC_SA_ATTR_AN) + { + attr_list[i].value.u8 = 1; + } + } + return SAI_STATUS_SUCCESS; + }; - ASSERT_TRUE(keys.empty()); + testAddRemoveCounter( + 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"}, + {"0", "1"}, + counterVerifyFunc, + false); + + 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++) + { + if (attr_list[i].id == SAI_ACL_COUNTER_ATTR_PACKETS) + { + attr_list[i].value.u64 = 1000; + } + } + return SAI_STATUS_SUCCESS; + }; + testAddRemoveCounter( + sai_object_id_t(0x9000000000000), + SAI_OBJECT_TYPE_ACL_COUNTER, + ACL_COUNTER_ATTR_ID_LIST, + {"SAI_ACL_COUNTER_ATTR_PACKETS"}, + {"1000"}, + counterVerifyFunc, + false); } -TEST(FlexCounter, addRemoveCounterForPort) +TEST(FlexCounter, queryCounterCapability) { - std::shared_ptr sai(new MockableSaiInterface()); - 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"); + sai->mock_queryStatsCapability = [](sai_object_id_t switch_id, sai_object_type_t object_type, sai_stat_capability_list_t *stats_capability) { + if (stats_capability->count == 0) + { + stats_capability->count = 1; + return SAI_STATUS_BUFFER_OVERFLOW; + } + else + { + stats_capability->list[0].stat_enum = SAI_PORT_STAT_IF_IN_OCTETS; + stats_capability->list[0].stat_modes = SAI_STATS_MODE_READ | SAI_STATS_MODE_READ_AND_CLEAR; + return SAI_STATUS_SUCCESS; + } + }; - 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) { + 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++) { - 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; - } + counters[i] = 1000; } return SAI_STATUS_SUCCESS; }; - fc.addCounter(counterVid, counterRid, values); - EXPECT_EQ(fc.isEmpty(), false); + auto counterVerifyFunc = [] (swss::Table &countersTable, const std::string& key, const std::vector& counterIdNames, const std::vector& expectedValues) + { + std::string value; + countersTable.hget(key, "SAI_PORT_STAT_IF_IN_OCTETS", value); + EXPECT_EQ(value, "1000"); + // SAI_PORT_STAT_IF_IN_UCAST_PKTS is not supported, shall not in countersTable + bool ret = countersTable.hget(key, "SAI_PORT_STAT_IF_IN_UCAST_PKTS", value); + EXPECT_EQ(false, ret); + }; - values.clear(); - values.emplace_back(POLL_INTERVAL_FIELD, "1000"); - values.emplace_back(FLEX_COUNTER_STATUS_FIELD, "enable"); - fc.addCounterPlugin(values); + testAddRemoveCounter( + 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"}, + {}, + counterVerifyFunc, + false); +} - usleep(1000*1000); - swss::DBConnector db("COUNTERS_DB", 0); - swss::RedisPipeline pipeline(&db); - swss::Table countersTable(&pipeline, COUNTERS_TABLE, false); +TEST(FlexCounter, noSupportedCounters) +{ + sai->mock_queryStatsCapability = [](sai_object_id_t switch_id, sai_object_type_t object_type, sai_stat_capability_list_t *stats_capability) { + return SAI_STATUS_FAILURE; + }; - std::vector keys; - countersTable.getKeys(keys); - EXPECT_EQ(keys.size(), size_t(1)); - EXPECT_EQ(keys[0], "oid:0x1000000000000"); + 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_FAILURE; + }; + + FlexCounter fc("test", sai, "COUNTERS_DB"); + std::vector values; + values.emplace_back(PORT_COUNTER_ID_LIST, "SAI_PORT_STAT_IF_IN_OCTETS,SAI_PORT_STAT_IF_IN_UCAST_PKTS"); - std::string value; - countersTable.hget("oid:0x1000000000000", "SAI_PORT_STAT_IF_IN_OCTETS", value); - EXPECT_EQ(value, "100"); - countersTable.hget("oid:0x1000000000000", "SAI_PORT_STAT_IF_IN_ERRORS", value); - EXPECT_EQ(value, "200"); + test_syncd::mockVidManagerObjectTypeQuery(SAI_OBJECT_TYPE_PORT); - fc.removeCounter(counterVid); + fc.addCounter(sai_object_id_t(0x1000000000000), sai_object_id_t(0x1000000000000), values); + // No supported counter, this object shall not be queried EXPECT_EQ(fc.isEmpty(), true); - countersTable.del("oid:0x1000000000000"); - 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; - } +void testAddRemovePlugin(const std::string& pluginFieldName) +{ + SWSS_LOG_ENTER(); - capability->list[0].stat_enum = SAI_PORT_STAT_IF_IN_OCTETS; - capability->list[1].stat_enum = SAI_PORT_STAT_IF_IN_ERRORS; - return SAI_STATUS_SUCCESS; - }; + FlexCounter fc("test", sai, "COUNTERS_DB"); - 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); + std::vector values; + values.emplace_back(pluginFieldName, "dummy_sha_strings"); + fc.addCounterPlugin(values); EXPECT_EQ(fc.isEmpty(), false); - usleep(1000*1000); - countersTable.hget("oid:0x1000000000000", "SAI_PORT_STAT_IF_IN_OCTETS", value); - EXPECT_EQ(value, "100"); - countersTable.hget("oid:0x1000000000000", "SAI_PORT_STAT_IF_IN_ERRORS", value); - EXPECT_EQ(value, "200"); - - fc.removeCounter(counterVid); + fc.removeCounterPlugins(); EXPECT_EQ(fc.isEmpty(), true); - countersTable.del("oid:0x1000000000000"); - countersTable.getKeys(keys); - ASSERT_TRUE(keys.empty()); } + +TEST(FlexCounter, addRemoveCounterPlugin) +{ + std::string fields[] = {QUEUE_PLUGIN_FIELD, + PG_PLUGIN_FIELD, + PORT_PLUGIN_FIELD, + RIF_PLUGIN_FIELD, + BUFFER_POOL_PLUGIN_FIELD, + TUNNEL_PLUGIN_FIELD, + FLOW_COUNTER_PLUGIN_FIELD}; + for (auto &field : fields) + { + testAddRemovePlugin(field); + } +} +