diff --git a/orchagent/Makefile.am b/orchagent/Makefile.am index 2a211f4ce5..f6f11e49c2 100644 --- a/orchagent/Makefile.am +++ b/orchagent/Makefile.am @@ -19,7 +19,8 @@ dist_swss_DATA = \ port_rates.lua \ watermark_queue.lua \ watermark_pg.lua \ - watermark_bufferpool.lua + watermark_bufferpool.lua \ + tunnel_rates.lua bin_PROGRAMS = orchagent routeresync orchagent_restart_check diff --git a/orchagent/flex_counter/flex_counter_manager.cpp b/orchagent/flex_counter/flex_counter_manager.cpp index 000ead1882..66501e3dd0 100644 --- a/orchagent/flex_counter/flex_counter_manager.cpp +++ b/orchagent/flex_counter/flex_counter_manager.cpp @@ -32,21 +32,60 @@ const unordered_map FlexCounterManager::status_lookup = const unordered_map FlexCounterManager::counter_id_field_lookup = { - { CounterType::PORT_DEBUG, PORT_DEBUG_COUNTER_ID_LIST }, - { CounterType::SWITCH_DEBUG, SWITCH_DEBUG_COUNTER_ID_LIST }, - { CounterType::PORT, PORT_COUNTER_ID_LIST }, - { CounterType::QUEUE, QUEUE_COUNTER_ID_LIST } + { CounterType::PORT_DEBUG, PORT_DEBUG_COUNTER_ID_LIST }, + { CounterType::SWITCH_DEBUG, SWITCH_DEBUG_COUNTER_ID_LIST }, + { CounterType::PORT, PORT_COUNTER_ID_LIST }, + { CounterType::QUEUE, QUEUE_COUNTER_ID_LIST }, + { CounterType::TUNNEL, TUNNEL_COUNTER_ID_LIST }, }; +FlexManagerDirectory g_FlexManagerDirectory; + +FlexCounterManager *FlexManagerDirectory::createFlexCounterManager(const string& group_name, + const StatsMode stats_mode, + const uint polling_interval, + const bool enabled, + FieldValueTuple fv_plugin) +{ + if (m_managers.find(group_name) != m_managers.end()) + { + if (stats_mode != m_managers[group_name]->getStatsMode()) + { + SWSS_LOG_ERROR("Stats mode mismatch with already created flex counter manager %s", + group_name.c_str()); + return NULL; + } + if (polling_interval != m_managers[group_name]->getPollingInterval()) + { + SWSS_LOG_ERROR("Polling interval mismatch with already created flex counter manager %s", + group_name.c_str()); + return NULL; + } + if (enabled != m_managers[group_name]->getEnabled()) + { + SWSS_LOG_ERROR("Enabled field mismatch with already created flex counter manager %s", + group_name.c_str()); + return NULL; + } + return m_managers[group_name]; + } + FlexCounterManager *fc_manager = new FlexCounterManager(group_name, stats_mode, polling_interval, + enabled, fv_plugin); + m_managers[group_name] = fc_manager; + return fc_manager; +} + FlexCounterManager::FlexCounterManager( const string& group_name, const StatsMode stats_mode, const uint polling_interval, - const bool enabled) : + const bool enabled, + FieldValueTuple fv_plugin) : group_name(group_name), stats_mode(stats_mode), polling_interval(polling_interval), enabled(enabled), + fv_plugin(fv_plugin), flex_counter_db(new DBConnector("FLEX_COUNTER_DB", 0)), flex_counter_group_table(new ProducerTable(flex_counter_db.get(), FLEX_COUNTER_GROUP_TABLE)), flex_counter_table(new ProducerTable(flex_counter_db.get(), FLEX_COUNTER_TABLE)) @@ -83,6 +122,11 @@ void FlexCounterManager::applyGroupConfiguration() FieldValueTuple(FLEX_COUNTER_STATUS_FIELD, status_lookup.at(enabled)) }; + if (!fvField(fv_plugin).empty()) + { + field_values.emplace_back(fv_plugin); + } + flex_counter_group_table->set(group_name, field_values); } diff --git a/orchagent/flex_counter/flex_counter_manager.h b/orchagent/flex_counter/flex_counter_manager.h index 1561236019..98c15593bf 100644 --- a/orchagent/flex_counter/flex_counter_manager.h +++ b/orchagent/flex_counter/flex_counter_manager.h @@ -4,8 +4,10 @@ #include #include #include +#include #include "dbconnector.h" #include "producertable.h" +#include "table.h" #include extern "C" { @@ -22,7 +24,8 @@ enum class CounterType PORT, QUEUE, PORT_DEBUG, - SWITCH_DEBUG + SWITCH_DEBUG, + TUNNEL, }; // FlexCounterManager allows users to manage a group of flex counters. @@ -37,7 +40,11 @@ class FlexCounterManager const std::string& group_name, const StatsMode stats_mode, const uint polling_interval, - const bool enabled); + const bool enabled, + swss::FieldValueTuple fv_plugin = std::make_pair("","")); + + FlexCounterManager() + {} FlexCounterManager(const FlexCounterManager&) = delete; FlexCounterManager& operator=(const FlexCounterManager&) = delete; @@ -53,6 +60,26 @@ class FlexCounterManager const std::unordered_set& counter_stats); void clearCounterIdList(const sai_object_id_t object_id); + const std::string& getGroupName() const + { + return group_name; + } + + const StatsMode& getStatsMode() const + { + return stats_mode; + } + + const uint& getPollingInterval() const + { + return polling_interval; + } + + const bool& getEnabled() const + { + return enabled; + } + protected: void applyGroupConfiguration(); @@ -67,6 +94,7 @@ class FlexCounterManager StatsMode stats_mode; uint polling_interval; bool enabled; + swss::FieldValueTuple fv_plugin; std::unordered_set installed_counters; std::shared_ptr flex_counter_db = nullptr; @@ -78,4 +106,14 @@ class FlexCounterManager static const std::unordered_map counter_id_field_lookup; }; +class FlexManagerDirectory +{ + public: + FlexCounterManager* createFlexCounterManager(const std::string& group_name, const StatsMode stats_mode, + const uint polling_interval, const bool enabled, + swss::FieldValueTuple fv_plugin = std::make_pair("","")); + private: + std::unordered_map m_managers; +}; + #endif // ORCHAGENT_FLEX_COUNTER_MANAGER_H diff --git a/orchagent/flexcounterorch.cpp b/orchagent/flexcounterorch.cpp index d8b6cdd2dd..3b6d2f3cd4 100644 --- a/orchagent/flexcounterorch.cpp +++ b/orchagent/flexcounterorch.cpp @@ -7,12 +7,14 @@ #include "bufferorch.h" #include "flexcounterorch.h" #include "debugcounterorch.h" +#include "directory.h" extern sai_port_api_t *sai_port_api; extern PortsOrch *gPortsOrch; extern IntfsOrch *gIntfsOrch; extern BufferOrch *gBufferOrch; +extern Directory gDirectory; #define BUFFER_POOL_WATERMARK_KEY "BUFFER_POOL_WATERMARK" #define PORT_KEY "PORT" @@ -20,6 +22,7 @@ extern BufferOrch *gBufferOrch; #define QUEUE_KEY "QUEUE" #define PG_WATERMARK_KEY "PG_WATERMARK" #define RIF_KEY "RIF" +#define TUNNEL_KEY "TUNNEL" unordered_map flexCounterGroupMap = { @@ -35,6 +38,7 @@ unordered_map flexCounterGroupMap = {"RIF", RIF_STAT_COUNTER_FLEX_COUNTER_GROUP}, {"RIF_RATES", RIF_RATE_COUNTER_FLEX_COUNTER_GROUP}, {"DEBUG_COUNTER", DEBUG_COUNTER_FLEX_COUNTER_GROUP}, + {"TUNNEL", TUNNEL_STAT_COUNTER_FLEX_COUNTER_GROUP}, }; @@ -56,6 +60,8 @@ void FlexCounterOrch::doTask(Consumer &consumer) { SWSS_LOG_ENTER(); + VxlanTunnelOrch* vxlan_tunnel_orch = gDirectory.get(); + if (!gPortsOrch->allPortsReady()) { return; @@ -129,7 +135,10 @@ void FlexCounterOrch::doTask(Consumer &consumer) { gBufferOrch->generateBufferPoolWatermarkCounterIdList(); } - + if (vxlan_tunnel_orch && (key== TUNNEL_KEY) && (value == "enable")) + { + vxlan_tunnel_orch->generateTunnelCounterMap(); + } vector fieldValues; fieldValues.emplace_back(FLEX_COUNTER_STATUS_FIELD, value); m_flexCounterGroupTable->set(flexCounterGroupMap[key], fieldValues); diff --git a/orchagent/tunnel_rates.lua b/orchagent/tunnel_rates.lua new file mode 100644 index 0000000000..3b536c29ac --- /dev/null +++ b/orchagent/tunnel_rates.lua @@ -0,0 +1,98 @@ +-- KEYS - rif IDs +-- ARGV[1] - counters db index +-- ARGV[2] - counters table name +-- ARGV[3] - poll time interval +-- return log + +local logtable = {} + +local function logit(msg) + logtable[#logtable+1] = tostring(msg) +end + +local counters_db = ARGV[1] +local counters_table_name = ARGV[2] +local rates_table_name = "RATES" +local sec_to_ms = 1000 + +-- Get configuration +redis.call('SELECT', counters_db) +local smooth_interval = redis.call('HGET', rates_table_name .. ':' .. 'TUNNEL', 'TUNNEL_SMOOTH_INTERVAL') +local alpha = redis.call('HGET', rates_table_name .. ':' .. 'TUNNEL', 'TUNNEL_ALPHA') +if not alpha then + logit("Alpha is not defined") + return logtable +end +local one_minus_alpha = 1.0 - alpha +local delta = tonumber(ARGV[3]) + +local n = table.getn(KEYS) +for i = 1, n do + local state_table = rates_table_name .. ':' .. KEYS[i] .. ':' .. 'TUNNEL' + local initialized = redis.call('HGET', state_table, 'INIT_DONE') + logit(initialized) + + -- Get new COUNTERS values + local in_octets = 0 + local in_packets = 0 + local out_octets = 0 + local out_packets = 0 + + if redis.call('HEXISTS', counters_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_IN_OCTETS') == 1 then + in_octets = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_IN_OCTETS') + end + if redis.call('HEXISTS', counters_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_IN_PACKETS') == 1 then + in_packets = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_IN_PACKETS') + end + if redis.call('HEXISTS', counters_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_OUT_OCTETS') == 1 then + out_octets = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_OUT_OCTETS') + end + if redis.call('HEXISTS', counters_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_OUT_PACKETS') == 1 then + out_packets = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_OUT_PACKETS') + end + + if initialized == "DONE" or initialized == "COUNTERS_LAST" then + -- Get old COUNTERS values + local in_octets_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_IN_OCTETS_last') + local in_packets_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_IN_PACKETS_last') + local out_octets_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_OUT_OCTETS_last') + local out_packets_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_OUT_PACKETS_last') + + -- Calculate new rates values + local rx_bps_new = (in_octets - in_octets_last)*sec_to_ms/delta + local tx_bps_new = (out_octets - out_octets_last)*sec_to_ms/delta + local rx_pps_new = (in_packets - in_packets_last)*sec_to_ms/delta + local tx_pps_new = (out_packets - out_packets_last)*sec_to_ms/delta + + if initialized == "DONE" then + -- Get old rates values + local rx_bps_old = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'RX_BPS') + local rx_pps_old = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'RX_PPS') + local tx_bps_old = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'TX_BPS') + local tx_pps_old = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'TX_PPS') + + -- Smooth the rates values and store them in DB + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'RX_BPS', alpha*rx_bps_new + one_minus_alpha*rx_bps_old) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'RX_PPS', alpha*rx_pps_new + one_minus_alpha*rx_pps_old) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'TX_BPS', alpha*tx_bps_new + one_minus_alpha*tx_bps_old) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'TX_PPS', alpha*tx_pps_new + one_minus_alpha*tx_pps_old) + else + -- Store unsmoothed initial rates values in DB + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'RX_BPS', rx_bps_new) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'RX_PPS', rx_pps_new) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'TX_BPS', tx_bps_new) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'TX_PPS', tx_pps_new) + redis.call('HSET', state_table, 'INIT_DONE', 'DONE') + end + else + redis.call('HSET', state_table, 'INIT_DONE', 'COUNTERS_LAST') + end + + -- Set old COUNTERS values + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_IN_OCTETS_last', in_octets) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_IN_PACKETS_last', in_packets) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_OUT_OCTETS_last', out_octets) + redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_OUT_PACKETS_last', out_packets) +end + +return logtable diff --git a/orchagent/vxlanorch.cpp b/orchagent/vxlanorch.cpp index 86d4a772dc..a34ada6715 100644 --- a/orchagent/vxlanorch.cpp +++ b/orchagent/vxlanorch.cpp @@ -15,6 +15,9 @@ #include "swssnet.h" #include "warm_restart.h" #include "tokenize.h" +#include "sai_serialize.h" +#include "flex_counter_manager.h" +#include "redisapi.h" /* Global variables */ extern sai_object_id_t gSwitchId; @@ -24,6 +27,9 @@ extern sai_next_hop_api_t *sai_next_hop_api; extern Directory gDirectory; extern PortsOrch* gPortsOrch; extern sai_object_id_t gUnderlayIfId; +extern FlexManagerDirectory g_FlexManagerDirectory; + +#define FLEX_COUNTER_UPD_INTERVAL 1 const map vxlanTunnelMap = { @@ -57,6 +63,14 @@ const map> vxlanTunnelMapKeyVal = }, }; +const vector tunnel_stat_ids = +{ + SAI_TUNNEL_STAT_IN_OCTETS, + SAI_TUNNEL_STAT_IN_PACKETS, + SAI_TUNNEL_STAT_OUT_OCTETS, + SAI_TUNNEL_STAT_OUT_PACKETS +}; + /* * Manipulators for the above Map */ @@ -482,6 +496,7 @@ bool VxlanTunnel::createTunnel(MAP_T encap, MAP_T decap, uint8_t encap_ttl) { try { + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); sai_ip_address_t ips, ipd, *ip=nullptr; uint8_t mapper_list = 0; swss::copy(ips, src_ip_); @@ -511,6 +526,11 @@ bool VxlanTunnel::createTunnel(MAP_T encap, MAP_T decap, uint8_t encap_ttl) ids_.tunnel_id = create_tunnel(&ids_, ip, NULL, gUnderlayIfId, false, encap_ttl); + if (ids_.tunnel_id != SAI_NULL_OBJECT_ID) + { + tunnel_orch->addTunnelToFlexCounter(ids_.tunnel_id, tunnel_name_); + } + ip = nullptr; if (!dst_ip_.isZero()) { @@ -840,11 +860,14 @@ bool VxlanTunnel::deleteTunnelHw(uint8_t mapper_list, tunnel_map_use_t map_src, { try { + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); + if (with_term) { remove_tunnel_termination(ids_.tunnel_term_id); } + tunnel_orch->removeTunnelFromFlexCounter(ids_.tunnel_id, tunnel_name_); remove_tunnel(ids_.tunnel_id); deleteMapperHw(mapper_list, map_src); } @@ -869,6 +892,7 @@ bool VxlanTunnel::createTunnelHw(uint8_t mapper_list, tunnel_map_use_t map_src, try { + VxlanTunnelOrch* tunnel_orch = gDirectory.get(); sai_ip_address_t ips, ipd, *ip=nullptr; swss::copy(ips, src_ip_); @@ -885,6 +909,11 @@ bool VxlanTunnel::createTunnelHw(uint8_t mapper_list, tunnel_map_use_t map_src, ids_.tunnel_id = create_tunnel(&ids_, &ips, ip, gUnderlayIfId, p2p, encap_ttl); + if (ids_.tunnel_id != SAI_NULL_OBJECT_ID) + { + tunnel_orch->addTunnelToFlexCounter(ids_.tunnel_id, tunnel_name_); + } + if (with_term) { ids_.tunnel_term_id = create_tunnel_termination(ids_.tunnel_id, ips, @@ -1156,6 +1185,125 @@ bool VxlanTunnel::deleteDynamicDIPTunnel(const std::string dip, tunnel_user_t us //------------------- VxlanTunnelOrch Implementation --------------------------// +VxlanTunnelOrch::VxlanTunnelOrch(DBConnector *statedb, DBConnector *db, const std::string& tableName) : + Orch2(db, tableName, request_), + m_stateVxlanTable(statedb, STATE_VXLAN_TUNNEL_TABLE_NAME) +{ + FieldValueTuple fv; + string tunnel_rate_plugin = "tunnel_rates.lua"; + m_counter_db = shared_ptr(new DBConnector("COUNTERS_DB", 0)); + m_asic_db = shared_ptr(new DBConnector("ASIC_DB", 0)); + try + { + string tunnel_rate_script = swss::loadLuaScript(tunnel_rate_plugin); + string tunnel_rate_sha = swss::loadRedisScript(m_counter_db.get(), tunnel_rate_script); + fv = FieldValueTuple(TUNNEL_PLUGIN_FIELD, tunnel_rate_sha); + } + catch (const runtime_error &e) + { + SWSS_LOG_WARN("Tunnel flex counter group plugins was not set successfully: %s", e.what()); + } + + tunnel_stat_manager = g_FlexManagerDirectory.createFlexCounterManager(TUNNEL_STAT_COUNTER_FLEX_COUNTER_GROUP, + StatsMode::READ, TUNNEL_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, false, fv); + + m_tunnelNameTable = unique_ptr(new Table(m_counter_db.get(), COUNTERS_TUNNEL_NAME_MAP)); + m_tunnelTypeTable = unique_ptr
(new Table(m_counter_db.get(), COUNTERS_TUNNEL_TYPE_MAP)); + + m_vidToRidTable = unique_ptr
(new Table(m_asic_db.get(), "VIDTORID")); + + auto intervT = timespec { .tv_sec = FLEX_COUNTER_UPD_INTERVAL , .tv_nsec = 0 }; + m_FlexCounterUpdTimer = new SelectableTimer(intervT); + auto executorT = new ExecutableTimer(m_FlexCounterUpdTimer, this, "FLEX_COUNTER_UPD_TIMER"); + Orch::addExecutor(executorT); + +} + +void VxlanTunnelOrch::doTask(SelectableTimer &timer) +{ + SWSS_LOG_ENTER(); + + for (auto it = m_pendingAddToFlexCntr.begin(); it != m_pendingAddToFlexCntr.end(); ) + { + string value; + const auto id = sai_serialize_object_id(it->first); + + if (m_vidToRidTable->hget("", id, value)) + { + SWSS_LOG_INFO("Registering %s, id %s", it->second.c_str(), id.c_str()); + vector tunnelNameFvs; + vector tunnelTypeFvs; + string type = "SAI_TUNNEL_TYPE_VXLAN"; + + tunnelNameFvs.emplace_back(it->second, id); + tunnelTypeFvs.emplace_back(id, type); + + m_tunnelNameTable->set("", tunnelNameFvs); + m_tunnelTypeTable->set("", tunnelTypeFvs); + auto tunnel_stats = generateTunnelCounterStats(); + + tunnel_stat_manager->setCounterIdList(it->first, CounterType::TUNNEL, + tunnel_stats); + it = m_pendingAddToFlexCntr.erase(it); + } + else + { + ++it; + } + } +} +void VxlanTunnelOrch::addTunnelToFlexCounter(sai_object_id_t oid, const string &name) +{ + m_pendingAddToFlexCntr[oid] = name; +} + +void VxlanTunnelOrch::removeTunnelFromFlexCounter(sai_object_id_t oid, const string &name) +{ + SWSS_LOG_ENTER(); + + if (oid == SAI_NULL_OBJECT_ID) + { + SWSS_LOG_WARN("Not removing NULL OID to flex for tunnel %s", name.c_str()); + return; + } + + if (m_pendingAddToFlexCntr.find(oid) != m_pendingAddToFlexCntr.end()) + { + m_pendingAddToFlexCntr.erase(oid); + return; + } + + string sai_oid = sai_serialize_object_id(oid); + + m_tunnelNameTable->hdel("", name); + m_tunnelTypeTable->hdel("", sai_oid); + tunnel_stat_manager->clearCounterIdList(oid); + SWSS_LOG_DEBUG("Unregistered tunnel %s to Flex counter", name.c_str()); +} + +std::unordered_set VxlanTunnelOrch::generateTunnelCounterStats() +{ + std::unordered_set counter_stats; + + for (const auto& it: tunnel_stat_ids) + { + counter_stats.emplace(sai_serialize_tunnel_stat(it)); + } + return counter_stats; +} + +void VxlanTunnelOrch::generateTunnelCounterMap() +{ + if (m_isTunnelCounterMapGenerated) + { + return; + } + + m_FlexCounterUpdTimer->start(); + + m_isTunnelCounterMapGenerated = true; +} + sai_object_id_t VxlanTunnelOrch::createNextHopTunnel(string tunnelName, IpAddress& ipAddr, MacAddress macAddress, uint32_t vni) diff --git a/orchagent/vxlanorch.h b/orchagent/vxlanorch.h index ad000ec8db..d28a9740de 100644 --- a/orchagent/vxlanorch.h +++ b/orchagent/vxlanorch.h @@ -7,6 +7,7 @@ #include "request_parser.h" #include "portsorch.h" #include "vrforch.h" +#include "timer.h" enum class MAP_T { @@ -35,6 +36,9 @@ typedef enum #define IS_TUNNELMAP_SET_VRF(x) ((x)& (1< VTEPTable; class VxlanTunnelOrch : public Orch2 { public: - VxlanTunnelOrch(DBConnector *statedb, DBConnector *db, const std::string& tableName) : - Orch2(db, tableName, request_), - m_stateVxlanTable(statedb, STATE_VXLAN_TUNNEL_TABLE_NAME) - {} - + VxlanTunnelOrch(DBConnector *statedb, DBConnector *db, const std::string& tableName); bool isTunnelExists(const std::string& tunnelName) const { @@ -342,17 +342,32 @@ class VxlanTunnelOrch : public Orch2 vxlan_vni_vlan_map_table_.erase(vni); } + unordered_set generateTunnelCounterStats(); + void generateTunnelCounterMap(); + void addTunnelToFlexCounter(sai_object_id_t oid, const std::string &name); + void removeTunnelFromFlexCounter(sai_object_id_t oid, const std::string &name); private: virtual bool addOperation(const Request& request); virtual bool delOperation(const Request& request); + void doTask(swss::SelectableTimer&); VxlanTunnelTable vxlan_tunnel_table_; VxlanTunnelRequest request_; VxlanVniVlanMapTable vxlan_vni_vlan_map_table_; VTEPTable vtep_table_; Table m_stateVxlanTable; + std::map m_pendingAddToFlexCntr; + FlexCounterManager vxlan_tunnel_stat_manager; + bool m_isTunnelCounterMapGenerated = false; + FlexCounterManager *tunnel_stat_manager; + unique_ptr
m_tunnelNameTable; + unique_ptr
m_tunnelTypeTable; + unique_ptr
m_vidToRidTable; + shared_ptr m_counter_db; + shared_ptr m_asic_db; + SelectableTimer* m_FlexCounterUpdTimer = nullptr; }; const request_description_t vxlan_tunnel_map_request_description = { diff --git a/tests/test_flex_counters.py b/tests/test_flex_counters.py index ecdc844572..6fe3e67500 100644 --- a/tests/test_flex_counters.py +++ b/tests/test_flex_counters.py @@ -8,6 +8,7 @@ BUFFER_POOL_WATERMARK_KEY = "BUFFER_POOL_WATERMARK" PORT_BUFFER_DROP_KEY = "PORT_BUFFER_DROP" PG_WATERMARK_KEY = "PG_WATERMARK" +TUNNEL_KEY = "TUNNEL" # Counter stats on FlexCountersDB PORT_STAT = "PORT_STAT_COUNTER" @@ -16,6 +17,7 @@ BUFFER_POOL_WATERMARK_STAT = "BUFFER_POOL_WATERMARK_STAT_COUNTER" PORT_BUFFER_DROP_STAT = "PORT_BUFFER_DROP_STAT" PG_WATERMARK_STAT = "PG_WATERMARK_STAT_COUNTER" +TUNNEL_STAT = "TUNNEL_STAT_COUNTER" # Counter maps on CountersDB PORT_MAP = "COUNTERS_PORT_NAME_MAP" @@ -24,7 +26,9 @@ BUFFER_POOL_WATERMARK_MAP = "COUNTERS_BUFFER_POOL_NAME_MAP" PORT_BUFFER_DROP_MAP = "COUNTERS_PORT_NAME_MAP" PG_WATERMARK_MAP = "COUNTERS_PG_NAME_MAP" +TUNNEL_MAP = "COUNTERS_TUNNEL_NAME_MAP" +TUNNEL_TYPE_MAP = "COUNTERS_TUNNEL_TYPE_MAP" NUMBER_OF_RETRIES = 10 CPU_PORT_OID = "0x0" @@ -33,7 +37,9 @@ "rif_counter":[RIF_KEY, RIF_STAT, RIF_MAP], "buffer_pool_watermark_counter":[BUFFER_POOL_WATERMARK_KEY, BUFFER_POOL_WATERMARK_STAT, BUFFER_POOL_WATERMARK_MAP], "port_buffer_drop_counter":[PORT_BUFFER_DROP_KEY, PORT_BUFFER_DROP_STAT, PORT_BUFFER_DROP_MAP], - "pg_watermark_counter":[PG_WATERMARK_KEY, PG_WATERMARK_STAT, PG_WATERMARK_MAP]} + "pg_watermark_counter":[PG_WATERMARK_KEY, PG_WATERMARK_STAT, PG_WATERMARK_MAP], + "vxlan_tunnel_counter":[TUNNEL_KEY, TUNNEL_STAT, TUNNEL_MAP]} + class TestFlexCounters(object): @@ -66,6 +72,15 @@ def verify_no_flex_counters_tables(self, counter_stat): counters_stat_keys = self.flex_db.get_keys("FLEX_COUNTER_TABLE:" + counter_stat) assert len(counters_stat_keys) == 0, "FLEX_COUNTER_TABLE:" + str(counter_stat) + " tables exist before enabling the flex counter group" + def verify_no_flex_counters_tables_after_delete(self, counter_stat): + for retry in range(NUMBER_OF_RETRIES): + counters_stat_keys = self.flex_db.get_keys("FLEX_COUNTER_TABLE:" + counter_stat + ":") + if len(counters_stat_keys) == 0: + return + else: + time.sleep(1) + assert False, "FLEX_COUNTER_TABLE:" + str(counter_stat) + " tables exist after removing the entries" + def verify_flex_counters_populated(self, map, stat): counters_keys = self.counters_db.db_connection.hgetall(map) for counter_entry in counters_keys.items(): @@ -73,6 +88,14 @@ def verify_flex_counters_populated(self, map, stat): oid = counter_entry[1] self.wait_for_id_list(stat, name, oid) + def verify_tunnel_type_vxlan(self, name_map, type_map): + counters_keys = self.counters_db.db_connection.hgetall(name_map) + for counter_entry in counters_keys.items(): + oid = counter_entry[1] + fvs = self.counters_db.get_entry(type_map, "") + assert fvs != {} + assert fvs.get(oid) == "SAI_TUNNEL_TYPE_VXLAN" + def verify_only_phy_ports_created(self): port_counters_keys = self.counters_db.db_connection.hgetall(PORT_MAP) port_counters_stat_keys = self.flex_db.get_keys("FLEX_COUNTER_TABLE:" + PORT_STAT) @@ -102,6 +125,12 @@ def test_flex_counters(self, dvs, counter_type): self.config_db.db_connection.hset('INTERFACE|Ethernet0', "NULL", "NULL") self.config_db.db_connection.hset('INTERFACE|Ethernet0|192.168.0.1/24', "NULL", "NULL") + if counter_type == "vxlan_tunnel_counter": + self.config_db.db_connection.hset("VLAN|Vlan10", "vlanid", "10") + self.config_db.db_connection.hset("VXLAN_TUNNEL|vtep1", "src_ip", "1.1.1.1") + self.config_db.db_connection.hset("VXLAN_TUNNEL_MAP|vtep1|map_100_Vlan10", "vlan", "Vlan10") + self.config_db.db_connection.hset("VXLAN_TUNNEL_MAP|vtep1|map_100_Vlan10", "vni", "100") + self.enable_flex_counter_group(counter_key, counter_map) self.verify_flex_counters_populated(counter_map, counter_stat) @@ -110,3 +139,10 @@ def test_flex_counters(self, dvs, counter_type): if counter_type == "rif_counter": self.config_db.db_connection.hdel('INTERFACE|Ethernet0|192.168.0.1/24', "NULL") + + if counter_type == "vxlan_tunnel_counter": + self.verify_tunnel_type_vxlan(counter_map, TUNNEL_TYPE_MAP) + self.config_db.delete_entry("VLAN","Vlan10") + self.config_db.delete_entry("VLAN_TUNNEL","vtep1") + self.config_db.delete_entry("VLAN_TUNNEL_MAP","vtep1|map_100_Vlan10") + self.verify_no_flex_counters_tables_after_delete(counter_stat)