Skip to content

Commit 1ddec53

Browse files
Added new "PFC History Orch"
PfcHistoryOrch is used to configure the flex counters for the PFC historical statistics feature. This change includes the lua script plugin that will be run.
1 parent 3a80d64 commit 1ddec53

File tree

7 files changed

+306
-0
lines changed

7 files changed

+306
-0
lines changed

orchagent/flexcounterorch.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "notifier.h"
66
#include "sai_serialize.h"
77
#include "pfcwdorch.h"
8+
#include "pfchistoryorch.h"
89
#include "bufferorch.h"
910
#include "flexcounterorch.h"
1011
#include "debugcounterorch.h"
@@ -46,6 +47,7 @@ extern sai_object_id_t gSwitchId;
4647
#define ENI_KEY "ENI"
4748
#define WRED_QUEUE_KEY "WRED_ECN_QUEUE"
4849
#define WRED_PORT_KEY "WRED_ECN_PORT"
50+
#define PFC_STAT_HISTORY_KEY "PFC_STAT_HISTORY"
4951

5052
unordered_map<string, string> flexCounterGroupMap =
5153
{
@@ -54,6 +56,7 @@ unordered_map<string, string> flexCounterGroupMap =
5456
{"PORT_BUFFER_DROP", PORT_BUFFER_DROP_STAT_FLEX_COUNTER_GROUP},
5557
{"QUEUE", QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP},
5658
{"PFCWD", PFC_WD_FLEX_COUNTER_GROUP},
59+
{PFC_STAT_HISTORY_KEY, PFC_STAT_HISTORY_FLEX_COUNTER_GROUP},
5760
{"QUEUE_WATERMARK", QUEUE_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP},
5861
{"PG_WATERMARK", PG_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP},
5962
{"PG_DROP", PG_DROP_STAT_COUNTER_FLEX_COUNTER_GROUP},

orchagent/orchdaemon.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,7 @@ bool OrchDaemon::init()
828828
}
829829

830830
m_orchList.push_back(&CounterCheckOrch::getInstance(m_configDb));
831+
m_orchList.push_back(&PfcHistoryOrch::getInstance(m_configDb));
831832

832833
vector<string> p4rt_tables = {APP_P4RT_TABLE_NAME};
833834
gP4Orch = new P4Orch(m_applDb, p4rt_tables, vrf_orch, gCoppOrch);

orchagent/orchdaemon.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "vxlanorch.h"
3232
#include "vnetorch.h"
3333
#include "countercheckorch.h"
34+
#include "pfchistoryorch.h"
3435
#include "flexcounterorch.h"
3536
#include "watermarkorch.h"
3637
#include "policerorch.h"

orchagent/pfc_stat_history.lua

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
-- KEYS - port IDs
2+
-- ARGV[1] - counters db index
3+
-- ARGV[2] - counters table name
4+
-- ARGV[3] - poll time interval (milliseconds)
5+
local counters_db = ARGV[1]
6+
local counters_table_name = ARGV[2]
7+
local poll_time = tonumber(ARGV[3]) * 1000
8+
9+
10+
local pfc_hist_table_name = "PFC_STAT_HISTORY"
11+
local rets = {}
12+
13+
local function parse_boolean(str) return str == "true" end
14+
local function parse_number(str) return tonumber(str) or 0 end
15+
16+
redis.call('SELECT', counters_db)
17+
18+
19+
local n = table.getn(KEYS)
20+
21+
for i = n, 1, -1 do
22+
-- port oid
23+
local port = KEYS[i]
24+
local port_key = pfc_hist_table_name .. ':' .. port
25+
26+
for prio = 0, 7 do
27+
local total_pause_time_field = 'TOTAL_PAUSE_TIME_MS_' .. prio
28+
local total_pause_transitions_field = 'TOTAL_PAUSE_TRANSITIONS_' .. prio
29+
local recent_pause_timestamp_field = 'RECENT_PAUSE_TIMESTAMP_' .. prio
30+
local recent_pause_time_field = 'RECENT_PAUSE_TIME_MS_' .. prio
31+
local prev_num_frames_field = 'PREV_RX_PKTS_' .. prio
32+
local pause_field = 'PAUSE_' .. prio
33+
34+
-- 1) get the updated pfc frame count
35+
local num_frames_new = parse_number(
36+
redis.call('HGET', counters_table_name .. ':' .. port, 'SAI_PORT_STAT_PFC_' .. prio .. '_RX_PKTS')
37+
)
38+
-- skip this port if no data
39+
if num_frames_new == false then break end
40+
41+
-- 2) get the info stored at last poll
42+
local total_pause_time_ms = parse_number(
43+
redis.call('HGET', port_key, total_pause_time_field)
44+
)
45+
local total_pause_transitions = parse_number(
46+
redis.call('HGET', port_key, total_pause_transitions_field)
47+
)
48+
local recent_pause_timestamp = parse_number(
49+
redis.call('HGET', port_key, recent_pause_timestamp_field)
50+
)
51+
local recent_pause_time_ms = parse_number(
52+
redis.call('HGET', port_key, recent_pause_time_field)
53+
)
54+
local num_frames_old = parse_number(
55+
redis.call('HGET', port_key, prev_num_frames_field)
56+
)
57+
local was_paused = parse_boolean(
58+
redis.call('HGET', port_key, pause_field)
59+
)
60+
61+
-- if the framecount increased then pause activity occured
62+
local now_paused = num_frames_new > num_frames_old
63+
-- Fetch current time from Redis, microsecond precision
64+
local time = redis.call('TIME')
65+
local seconds = tonumber(time[1])
66+
local microseconds = tonumber(time[2])
67+
local now_ms = (seconds * 1000) + math.floor(microseconds / 1000)
68+
69+
-- transitioned unpaused to paused, assume pause starts this moment, update db to reflect that
70+
if not was_paused and now_paused then
71+
local total_pause_transitions_new = total_pause_transitions + 1;
72+
redis.call('HSET', port_key, total_pause_transitions_field, total_pause_transitions_new)
73+
redis.call('HSET', port_key, recent_pause_timestamp_field, now_ms)
74+
redis.call('HSET', port_key, recent_pause_time_field, 0)
75+
76+
-- paused to paused OR paused to unpaused, assume paused since last check
77+
elseif was_paused then
78+
-- recent time is diff between now and when pause started
79+
local recent_pause_time_ms_new = now_ms - recent_pause_timestamp
80+
-- total time is current total time adds new recentpause
81+
local total_pause_time_ms_new = total_pause_time_ms
82+
- recent_pause_time_ms
83+
+ recent_pause_time_ms_new;
84+
85+
redis.call('HSET', port_key, total_pause_time_field, total_pause_time_ms_new)
86+
redis.call('HSET', port_key, recent_pause_time_field, recent_pause_time_ms_new)
87+
end
88+
89+
redis.call('HSET', port_key, prev_num_frames_field, num_frames_new)
90+
redis.call('HSET', port_key, pause_field, tostring(now_paused))
91+
end
92+
end
93+
94+
return rets

orchagent/pfchistoryorch.cpp

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#include "pfchistoryorch.h"
2+
#include "portsorch.h"
3+
4+
#define DEFAULT_POLL_INTERVAL "1000"
5+
6+
extern sai_object_id_t gSwitchId;
7+
extern sai_port_api_t *sai_port_api;
8+
extern PortsOrch *gPortsOrch;
9+
10+
PfcHistoryOrch& PfcHistoryOrch::getInstance(DBConnector *db)
11+
{
12+
SWSS_LOG_ENTER();
13+
static std::vector<string> tableNames = {
14+
CFG_PFC_STAT_HISTORY_TABLE_NAME
15+
};
16+
static const std::vector<sai_port_stat_t> portStatIds =
17+
{
18+
SAI_PORT_STAT_PFC_0_RX_PKTS,
19+
SAI_PORT_STAT_PFC_1_RX_PKTS,
20+
SAI_PORT_STAT_PFC_2_RX_PKTS,
21+
SAI_PORT_STAT_PFC_3_RX_PKTS,
22+
SAI_PORT_STAT_PFC_4_RX_PKTS,
23+
SAI_PORT_STAT_PFC_5_RX_PKTS,
24+
SAI_PORT_STAT_PFC_6_RX_PKTS,
25+
SAI_PORT_STAT_PFC_7_RX_PKTS,
26+
};
27+
static PfcHistoryOrch *historyOrch = new PfcHistoryOrch(db, tableNames, portStatIds);
28+
29+
return *historyOrch;
30+
}
31+
32+
PfcHistoryOrch::PfcHistoryOrch(
33+
DBConnector *db,
34+
std::vector<string> &tableNames,
35+
const vector<sai_port_stat_t> &portStatIds
36+
):
37+
Orch(db, tableNames),
38+
c_portStatIds(portStatIds),
39+
m_countersDb(new DBConnector("COUNTERS_DB", 0))
40+
{
41+
SWSS_LOG_ENTER();
42+
43+
// clear history stats for safe restart
44+
removeAllPfcStatHistoryCounters();
45+
46+
// if config_db has not yet been populated, provide the defaults so it is consistent with flex_counter_db
47+
swss::Table flexCounterTable(db, CFG_FLEX_COUNTER_TABLE_NAME);
48+
std::string poll_interval;
49+
if(!flexCounterTable.hget(PFC_STAT_HISTORY_FLEX_COUNTER_GROUP, POLL_INTERVAL_FIELD, poll_interval)){
50+
flexCounterTable.hset(PFC_STAT_HISTORY_FLEX_COUNTER_GROUP, POLL_INTERVAL_FIELD, DEFAULT_POLL_INTERVAL);
51+
}
52+
std::string status;
53+
if(!flexCounterTable.hget(PFC_STAT_HISTORY_FLEX_COUNTER_GROUP, FLEX_COUNTER_STATUS_FIELD, status)){
54+
flexCounterTable.hset(PFC_STAT_HISTORY_FLEX_COUNTER_GROUP, FLEX_COUNTER_STATUS_FIELD, "disable");
55+
}
56+
57+
string pluginName = "pfc_stat_history.lua";
58+
string sha;
59+
try
60+
{
61+
string script = swss::loadLuaScript(pluginName);
62+
sha = swss::loadRedisScript(m_countersDb.get(), script);
63+
}
64+
catch (const runtime_error &e)
65+
{
66+
SWSS_LOG_ERROR("PFC STAT HISTORY flex counter group not set successfully: %s", e.what());
67+
}
68+
69+
setFlexCounterGroupParameter(PFC_STAT_HISTORY_FLEX_COUNTER_GROUP,
70+
DEFAULT_POLL_INTERVAL, // this will be overwritten by the config_db entry regardless
71+
STATS_MODE_READ, // don't clear counters on read
72+
PORT_PLUGIN_FIELD, // "context name" in syncd, "plugin name" here
73+
sha);
74+
}
75+
76+
PfcHistoryOrch::~PfcHistoryOrch(void)
77+
{
78+
SWSS_LOG_ENTER();
79+
}
80+
81+
// Remove all PFC Historical Stats from COUNTERS_DB
82+
void PfcHistoryOrch::removeAllPfcStatHistoryCounters()
83+
{
84+
SWSS_LOG_ENTER();
85+
86+
vector<string> keys;
87+
const auto pfcHistTable = std::make_unique<Table>(m_countersDb.get(), COUNTERS_PFC_STAT_HISTORY_TABLE);
88+
pfcHistTable->getKeys(keys);
89+
for (auto key : keys)
90+
{
91+
pfcHistTable->del(key);
92+
}
93+
}
94+
95+
void PfcHistoryOrch::doTask(Consumer& consumer){
96+
SWSS_LOG_ENTER();
97+
98+
if (!gPortsOrch->allPortsReady())
99+
{
100+
return;
101+
}
102+
103+
if ((consumer.getDbName() == "CONFIG_DB")
104+
&& consumer.getTableName() == CFG_PFC_STAT_HISTORY_TABLE_NAME
105+
)
106+
{
107+
auto it = consumer.m_toSync.begin();
108+
while (it != consumer.m_toSync.end())
109+
{
110+
KeyOpFieldsValuesTuple t = it->second;
111+
string key = kfvKey(t);
112+
string op = kfvOp(t);
113+
std::vector<FieldValueTuple> fvt = kfvFieldsValues(t);
114+
115+
Port port;
116+
if (!gPortsOrch->getPort(key, port))
117+
{
118+
return;
119+
}
120+
121+
if (op == SET_COMMAND)
122+
{
123+
if (port.m_type != Port::PHY)
124+
{
125+
SWSS_LOG_ERROR("%s not a physical port!", sai_serialize_object_id(port.m_port_id).c_str());
126+
continue;
127+
}
128+
129+
if (!c_portStatIds.empty())
130+
{
131+
string key = string(PFC_STAT_HISTORY_FLEX_COUNTER_GROUP) + ":" + sai_serialize_object_id(port.m_port_id);
132+
string str = counterIdsToStr(c_portStatIds);
133+
134+
// FLEX_COUNTER_TABLE:PFC_STAT_HISTORY:oid:<port> : {PORT_COUNTER_ID_LIST: SAI_PORT_PFC_X_RX_PKTS}
135+
startFlexCounterPolling(gSwitchId, key, str, PORT_COUNTER_ID_LIST);
136+
}
137+
else{
138+
SWSS_LOG_ERROR("No port stat ids provided, polling on %s not started", sai_serialize_object_id(port.m_port_id).c_str());
139+
}
140+
}
141+
else if (op == DEL_COMMAND)
142+
{
143+
string key = string(PFC_STAT_HISTORY_FLEX_COUNTER_GROUP) + ":" + sai_serialize_object_id(port.m_port_id);
144+
// Unregister in syncd
145+
stopFlexCounterPolling(gSwitchId, key);
146+
}
147+
else
148+
{
149+
SWSS_LOG_ERROR("Unknown operation type %s", op.c_str());
150+
}
151+
consumer.m_toSync.erase(it++);
152+
}
153+
}
154+
}
155+
156+
string PfcHistoryOrch::counterIdsToStr(const vector<sai_port_stat_t> ids)
157+
{
158+
SWSS_LOG_ENTER();
159+
160+
string str;
161+
162+
for (const auto& i: ids)
163+
{
164+
str += sai_serialize_port_stat(i) + ",";
165+
}
166+
167+
// Remove trailing ','
168+
if (!str.empty())
169+
{
170+
str.pop_back();
171+
}
172+
173+
return str;
174+
}

orchagent/pfchistoryorch.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#ifndef PFCHISTORY_ORCH_H
2+
#define PFCHISTORY_ORCH_H
3+
4+
#include "orch.h"
5+
6+
#define PFC_STAT_HISTORY_FLEX_COUNTER_GROUP "PFC_STAT_HISTORY"
7+
8+
extern "C" {
9+
#include "sai.h"
10+
}
11+
12+
class PfcHistoryOrch: public Orch
13+
{
14+
public:
15+
static PfcHistoryOrch& getInstance(swss::DBConnector *db = nullptr);
16+
virtual void doTask(Consumer& consumer);
17+
18+
private:
19+
PfcHistoryOrch(
20+
swss::DBConnector *db,
21+
std::vector<std::string> &tableNames,
22+
const std::vector<sai_port_stat_t> &portStatIds
23+
);
24+
virtual ~PfcHistoryOrch(void);
25+
static std::string counterIdsToStr(const std::vector<sai_port_stat_t> ids);
26+
void removeAllPfcStatHistoryCounters();
27+
28+
const std::vector<sai_port_stat_t> c_portStatIds;
29+
std::shared_ptr<swss::DBConnector> m_countersDb = nullptr;
30+
};
31+
32+
#endif

tests/mock_tests/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ tests_SOURCES = aclorch_ut.cpp \
111111
$(top_srcdir)/orchagent/request_parser.cpp \
112112
$(top_srcdir)/orchagent/vrforch.cpp \
113113
$(top_srcdir)/orchagent/countercheckorch.cpp \
114+
$(top_srcdir)/orchagent/pfchistoryorch.cpp \
114115
$(top_srcdir)/orchagent/vxlanorch.cpp \
115116
$(top_srcdir)/orchagent/vnetorch.cpp \
116117
$(top_srcdir)/orchagent/dtelorch.cpp \

0 commit comments

Comments
 (0)