Skip to content

Commit

Permalink
VxLAN Tunnel Counters and Rates implementation (#1859)
Browse files Browse the repository at this point in the history
* Tunnel stats support
  • Loading branch information
dgsudharsan authored Nov 1, 2021
1 parent ac3103a commit 9f30ca1
Show file tree
Hide file tree
Showing 8 changed files with 391 additions and 4 deletions.
3 changes: 2 additions & 1 deletion orchagent/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ dist_swss_DATA = \
watermark_queue.lua \
watermark_pg.lua \
watermark_bufferpool.lua \
lagids.lua
lagids.lua \
tunnel_rates.lua

bin_PROGRAMS = orchagent routeresync orchagent_restart_check

Expand Down
46 changes: 45 additions & 1 deletion orchagent/flex_counter/flex_counter_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,56 @@ const unordered_map<CounterType, string> FlexCounterManager::counter_id_field_lo
{ CounterType::PORT, PORT_COUNTER_ID_LIST },
{ CounterType::QUEUE, QUEUE_COUNTER_ID_LIST },
{ CounterType::MACSEC_SA_ATTR, MACSEC_SA_ATTR_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))
Expand Down Expand Up @@ -86,6 +125,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);
}

Expand Down
40 changes: 39 additions & 1 deletion orchagent/flex_counter/flex_counter_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
#include <string>
#include <unordered_set>
#include <unordered_map>
#include <utility>
#include "dbconnector.h"
#include "producertable.h"
#include "table.h"
#include <inttypes.h>

extern "C" {
Expand All @@ -24,6 +26,7 @@ enum class CounterType
PORT_DEBUG,
SWITCH_DEBUG,
MACSEC_SA_ATTR,
TUNNEL,
};

// FlexCounterManager allows users to manage a group of flex counters.
Expand All @@ -38,7 +41,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;
Expand All @@ -54,6 +61,26 @@ class FlexCounterManager
const std::unordered_set<std::string>& 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();

Expand All @@ -68,6 +95,7 @@ class FlexCounterManager
StatsMode stats_mode;
uint polling_interval;
bool enabled;
swss::FieldValueTuple fv_plugin;
std::unordered_set<sai_object_id_t> installed_counters;

std::shared_ptr<swss::DBConnector> flex_counter_db = nullptr;
Expand All @@ -79,4 +107,14 @@ class FlexCounterManager
static const std::unordered_map<CounterType, std::string> 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<std::string, FlexCounterManager*> m_managers;
};

#endif // ORCHAGENT_FLEX_COUNTER_MANAGER_H
9 changes: 9 additions & 0 deletions orchagent/flexcounterorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,23 @@
#include "bufferorch.h"
#include "flexcounterorch.h"
#include "debugcounterorch.h"
#include "directory.h"

extern sai_port_api_t *sai_port_api;

extern PortsOrch *gPortsOrch;
extern FabricPortsOrch *gFabricPortsOrch;
extern IntfsOrch *gIntfsOrch;
extern BufferOrch *gBufferOrch;
extern Directory<Orch*> gDirectory;

#define BUFFER_POOL_WATERMARK_KEY "BUFFER_POOL_WATERMARK"
#define PORT_KEY "PORT"
#define PORT_BUFFER_DROP_KEY "PORT_BUFFER_DROP"
#define QUEUE_KEY "QUEUE"
#define PG_WATERMARK_KEY "PG_WATERMARK"
#define RIF_KEY "RIF"
#define TUNNEL_KEY "TUNNEL"

unordered_map<string, string> flexCounterGroupMap =
{
Expand All @@ -38,6 +41,7 @@ unordered_map<string, string> 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},
};


Expand All @@ -58,6 +62,7 @@ void FlexCounterOrch::doTask(Consumer &consumer)
{
SWSS_LOG_ENTER();

VxlanTunnelOrch* vxlan_tunnel_orch = gDirectory.get<VxlanTunnelOrch*>();
if (gPortsOrch && !gPortsOrch->allPortsReady())
{
return;
Expand Down Expand Up @@ -147,6 +152,10 @@ void FlexCounterOrch::doTask(Consumer &consumer)
{
gFabricPortsOrch->generateQueueStats();
}
if (vxlan_tunnel_orch && (key== TUNNEL_KEY) && (value == "enable"))
{
vxlan_tunnel_orch->generateTunnelCounterMap();
}
vector<FieldValueTuple> fieldValues;
fieldValues.emplace_back(FLEX_COUNTER_STATUS_FIELD, value);
m_flexCounterGroupTable->set(flexCounterGroupMap[key], fieldValues);
Expand Down
98 changes: 98 additions & 0 deletions orchagent/tunnel_rates.lua
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 9f30ca1

Please sign in to comment.