Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VxLAN Tunnel Counters and Rates implementation #1859

Merged
merged 19 commits into from
Nov 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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