Skip to content

Commit 9f30ca1

Browse files
authored
VxLAN Tunnel Counters and Rates implementation (#1859)
* Tunnel stats support
1 parent ac3103a commit 9f30ca1

8 files changed

+391
-4
lines changed

orchagent/Makefile.am

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ dist_swss_DATA = \
2323
watermark_queue.lua \
2424
watermark_pg.lua \
2525
watermark_bufferpool.lua \
26-
lagids.lua
26+
lagids.lua \
27+
tunnel_rates.lua
2728

2829
bin_PROGRAMS = orchagent routeresync orchagent_restart_check
2930

orchagent/flex_counter/flex_counter_manager.cpp

+45-1
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,56 @@ const unordered_map<CounterType, string> FlexCounterManager::counter_id_field_lo
3939
{ CounterType::PORT, PORT_COUNTER_ID_LIST },
4040
{ CounterType::QUEUE, QUEUE_COUNTER_ID_LIST },
4141
{ CounterType::MACSEC_SA_ATTR, MACSEC_SA_ATTR_ID_LIST },
42+
{ CounterType::TUNNEL, TUNNEL_COUNTER_ID_LIST },
4243
};
4344

45+
FlexManagerDirectory g_FlexManagerDirectory;
46+
47+
FlexCounterManager *FlexManagerDirectory::createFlexCounterManager(const string& group_name,
48+
const StatsMode stats_mode,
49+
const uint polling_interval,
50+
const bool enabled,
51+
FieldValueTuple fv_plugin)
52+
{
53+
if (m_managers.find(group_name) != m_managers.end())
54+
{
55+
if (stats_mode != m_managers[group_name]->getStatsMode())
56+
{
57+
SWSS_LOG_ERROR("Stats mode mismatch with already created flex counter manager %s",
58+
group_name.c_str());
59+
return NULL;
60+
}
61+
if (polling_interval != m_managers[group_name]->getPollingInterval())
62+
{
63+
SWSS_LOG_ERROR("Polling interval mismatch with already created flex counter manager %s",
64+
group_name.c_str());
65+
return NULL;
66+
}
67+
if (enabled != m_managers[group_name]->getEnabled())
68+
{
69+
SWSS_LOG_ERROR("Enabled field mismatch with already created flex counter manager %s",
70+
group_name.c_str());
71+
return NULL;
72+
}
73+
return m_managers[group_name];
74+
}
75+
FlexCounterManager *fc_manager = new FlexCounterManager(group_name, stats_mode, polling_interval,
76+
enabled, fv_plugin);
77+
m_managers[group_name] = fc_manager;
78+
return fc_manager;
79+
}
80+
4481
FlexCounterManager::FlexCounterManager(
4582
const string& group_name,
4683
const StatsMode stats_mode,
4784
const uint polling_interval,
48-
const bool enabled) :
85+
const bool enabled,
86+
FieldValueTuple fv_plugin) :
4987
group_name(group_name),
5088
stats_mode(stats_mode),
5189
polling_interval(polling_interval),
5290
enabled(enabled),
91+
fv_plugin(fv_plugin),
5392
flex_counter_db(new DBConnector("FLEX_COUNTER_DB", 0)),
5493
flex_counter_group_table(new ProducerTable(flex_counter_db.get(), FLEX_COUNTER_GROUP_TABLE)),
5594
flex_counter_table(new ProducerTable(flex_counter_db.get(), FLEX_COUNTER_TABLE))
@@ -86,6 +125,11 @@ void FlexCounterManager::applyGroupConfiguration()
86125
FieldValueTuple(FLEX_COUNTER_STATUS_FIELD, status_lookup.at(enabled))
87126
};
88127

128+
if (!fvField(fv_plugin).empty())
129+
{
130+
field_values.emplace_back(fv_plugin);
131+
}
132+
89133
flex_counter_group_table->set(group_name, field_values);
90134
}
91135

orchagent/flex_counter/flex_counter_manager.h

+39-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
#include <string>
55
#include <unordered_set>
66
#include <unordered_map>
7+
#include <utility>
78
#include "dbconnector.h"
89
#include "producertable.h"
10+
#include "table.h"
911
#include <inttypes.h>
1012

1113
extern "C" {
@@ -24,6 +26,7 @@ enum class CounterType
2426
PORT_DEBUG,
2527
SWITCH_DEBUG,
2628
MACSEC_SA_ATTR,
29+
TUNNEL,
2730
};
2831

2932
// FlexCounterManager allows users to manage a group of flex counters.
@@ -38,7 +41,11 @@ class FlexCounterManager
3841
const std::string& group_name,
3942
const StatsMode stats_mode,
4043
const uint polling_interval,
41-
const bool enabled);
44+
const bool enabled,
45+
swss::FieldValueTuple fv_plugin = std::make_pair("",""));
46+
47+
FlexCounterManager()
48+
{}
4249

4350
FlexCounterManager(const FlexCounterManager&) = delete;
4451
FlexCounterManager& operator=(const FlexCounterManager&) = delete;
@@ -54,6 +61,26 @@ class FlexCounterManager
5461
const std::unordered_set<std::string>& counter_stats);
5562
void clearCounterIdList(const sai_object_id_t object_id);
5663

64+
const std::string& getGroupName() const
65+
{
66+
return group_name;
67+
}
68+
69+
const StatsMode& getStatsMode() const
70+
{
71+
return stats_mode;
72+
}
73+
74+
const uint& getPollingInterval() const
75+
{
76+
return polling_interval;
77+
}
78+
79+
const bool& getEnabled() const
80+
{
81+
return enabled;
82+
}
83+
5784
protected:
5885
void applyGroupConfiguration();
5986

@@ -68,6 +95,7 @@ class FlexCounterManager
6895
StatsMode stats_mode;
6996
uint polling_interval;
7097
bool enabled;
98+
swss::FieldValueTuple fv_plugin;
7199
std::unordered_set<sai_object_id_t> installed_counters;
72100

73101
std::shared_ptr<swss::DBConnector> flex_counter_db = nullptr;
@@ -79,4 +107,14 @@ class FlexCounterManager
79107
static const std::unordered_map<CounterType, std::string> counter_id_field_lookup;
80108
};
81109

110+
class FlexManagerDirectory
111+
{
112+
public:
113+
FlexCounterManager* createFlexCounterManager(const std::string& group_name, const StatsMode stats_mode,
114+
const uint polling_interval, const bool enabled,
115+
swss::FieldValueTuple fv_plugin = std::make_pair("",""));
116+
private:
117+
std::unordered_map<std::string, FlexCounterManager*> m_managers;
118+
};
119+
82120
#endif // ORCHAGENT_FLEX_COUNTER_MANAGER_H

orchagent/flexcounterorch.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,23 @@
99
#include "bufferorch.h"
1010
#include "flexcounterorch.h"
1111
#include "debugcounterorch.h"
12+
#include "directory.h"
1213

1314
extern sai_port_api_t *sai_port_api;
1415

1516
extern PortsOrch *gPortsOrch;
1617
extern FabricPortsOrch *gFabricPortsOrch;
1718
extern IntfsOrch *gIntfsOrch;
1819
extern BufferOrch *gBufferOrch;
20+
extern Directory<Orch*> gDirectory;
1921

2022
#define BUFFER_POOL_WATERMARK_KEY "BUFFER_POOL_WATERMARK"
2123
#define PORT_KEY "PORT"
2224
#define PORT_BUFFER_DROP_KEY "PORT_BUFFER_DROP"
2325
#define QUEUE_KEY "QUEUE"
2426
#define PG_WATERMARK_KEY "PG_WATERMARK"
2527
#define RIF_KEY "RIF"
28+
#define TUNNEL_KEY "TUNNEL"
2629

2730
unordered_map<string, string> flexCounterGroupMap =
2831
{
@@ -38,6 +41,7 @@ unordered_map<string, string> flexCounterGroupMap =
3841
{"RIF", RIF_STAT_COUNTER_FLEX_COUNTER_GROUP},
3942
{"RIF_RATES", RIF_RATE_COUNTER_FLEX_COUNTER_GROUP},
4043
{"DEBUG_COUNTER", DEBUG_COUNTER_FLEX_COUNTER_GROUP},
44+
{"TUNNEL", TUNNEL_STAT_COUNTER_FLEX_COUNTER_GROUP},
4145
};
4246

4347

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

65+
VxlanTunnelOrch* vxlan_tunnel_orch = gDirectory.get<VxlanTunnelOrch*>();
6166
if (gPortsOrch && !gPortsOrch->allPortsReady())
6267
{
6368
return;
@@ -147,6 +152,10 @@ void FlexCounterOrch::doTask(Consumer &consumer)
147152
{
148153
gFabricPortsOrch->generateQueueStats();
149154
}
155+
if (vxlan_tunnel_orch && (key== TUNNEL_KEY) && (value == "enable"))
156+
{
157+
vxlan_tunnel_orch->generateTunnelCounterMap();
158+
}
150159
vector<FieldValueTuple> fieldValues;
151160
fieldValues.emplace_back(FLEX_COUNTER_STATUS_FIELD, value);
152161
m_flexCounterGroupTable->set(flexCounterGroupMap[key], fieldValues);

orchagent/tunnel_rates.lua

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
-- KEYS - rif IDs
2+
-- ARGV[1] - counters db index
3+
-- ARGV[2] - counters table name
4+
-- ARGV[3] - poll time interval
5+
-- return log
6+
7+
local logtable = {}
8+
9+
local function logit(msg)
10+
logtable[#logtable+1] = tostring(msg)
11+
end
12+
13+
local counters_db = ARGV[1]
14+
local counters_table_name = ARGV[2]
15+
local rates_table_name = "RATES"
16+
local sec_to_ms = 1000
17+
18+
-- Get configuration
19+
redis.call('SELECT', counters_db)
20+
local smooth_interval = redis.call('HGET', rates_table_name .. ':' .. 'TUNNEL', 'TUNNEL_SMOOTH_INTERVAL')
21+
local alpha = redis.call('HGET', rates_table_name .. ':' .. 'TUNNEL', 'TUNNEL_ALPHA')
22+
if not alpha then
23+
logit("Alpha is not defined")
24+
return logtable
25+
end
26+
local one_minus_alpha = 1.0 - alpha
27+
local delta = tonumber(ARGV[3])
28+
29+
local n = table.getn(KEYS)
30+
for i = 1, n do
31+
local state_table = rates_table_name .. ':' .. KEYS[i] .. ':' .. 'TUNNEL'
32+
local initialized = redis.call('HGET', state_table, 'INIT_DONE')
33+
logit(initialized)
34+
35+
-- Get new COUNTERS values
36+
local in_octets = 0
37+
local in_packets = 0
38+
local out_octets = 0
39+
local out_packets = 0
40+
41+
if redis.call('HEXISTS', counters_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_IN_OCTETS') == 1 then
42+
in_octets = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_IN_OCTETS')
43+
end
44+
if redis.call('HEXISTS', counters_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_IN_PACKETS') == 1 then
45+
in_packets = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_IN_PACKETS')
46+
end
47+
if redis.call('HEXISTS', counters_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_OUT_OCTETS') == 1 then
48+
out_octets = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_OUT_OCTETS')
49+
end
50+
if redis.call('HEXISTS', counters_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_OUT_PACKETS') == 1 then
51+
out_packets = redis.call('HGET', counters_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_OUT_PACKETS')
52+
end
53+
54+
if initialized == "DONE" or initialized == "COUNTERS_LAST" then
55+
-- Get old COUNTERS values
56+
local in_octets_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_IN_OCTETS_last')
57+
local in_packets_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_IN_PACKETS_last')
58+
local out_octets_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_OUT_OCTETS_last')
59+
local out_packets_last = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_OUT_PACKETS_last')
60+
61+
-- Calculate new rates values
62+
local rx_bps_new = (in_octets - in_octets_last)*sec_to_ms/delta
63+
local tx_bps_new = (out_octets - out_octets_last)*sec_to_ms/delta
64+
local rx_pps_new = (in_packets - in_packets_last)*sec_to_ms/delta
65+
local tx_pps_new = (out_packets - out_packets_last)*sec_to_ms/delta
66+
67+
if initialized == "DONE" then
68+
-- Get old rates values
69+
local rx_bps_old = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'RX_BPS')
70+
local rx_pps_old = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'RX_PPS')
71+
local tx_bps_old = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'TX_BPS')
72+
local tx_pps_old = redis.call('HGET', rates_table_name .. ':' .. KEYS[i], 'TX_PPS')
73+
74+
-- Smooth the rates values and store them in DB
75+
redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'RX_BPS', alpha*rx_bps_new + one_minus_alpha*rx_bps_old)
76+
redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'RX_PPS', alpha*rx_pps_new + one_minus_alpha*rx_pps_old)
77+
redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'TX_BPS', alpha*tx_bps_new + one_minus_alpha*tx_bps_old)
78+
redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'TX_PPS', alpha*tx_pps_new + one_minus_alpha*tx_pps_old)
79+
else
80+
-- Store unsmoothed initial rates values in DB
81+
redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'RX_BPS', rx_bps_new)
82+
redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'RX_PPS', rx_pps_new)
83+
redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'TX_BPS', tx_bps_new)
84+
redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'TX_PPS', tx_pps_new)
85+
redis.call('HSET', state_table, 'INIT_DONE', 'DONE')
86+
end
87+
else
88+
redis.call('HSET', state_table, 'INIT_DONE', 'COUNTERS_LAST')
89+
end
90+
91+
-- Set old COUNTERS values
92+
redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_IN_OCTETS_last', in_octets)
93+
redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_IN_PACKETS_last', in_packets)
94+
redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_OUT_OCTETS_last', out_octets)
95+
redis.call('HSET', rates_table_name .. ':' .. KEYS[i], 'SAI_TUNNEL_STAT_OUT_PACKETS_last', out_packets)
96+
end
97+
98+
return logtable

0 commit comments

Comments
 (0)