1
1
#include " tokenize.h"
2
-
3
2
#include " bufferorch.h"
4
3
#include " logger.h"
4
+ #include " sai_serialize.h"
5
5
6
6
#include < sstream>
7
7
#include < iostream>
8
8
9
+ using namespace std ;
10
+
9
11
extern sai_port_api_t *sai_port_api;
10
12
extern sai_queue_api_t *sai_queue_api;
11
13
extern sai_switch_api_t *sai_switch_api;
@@ -14,7 +16,13 @@ extern sai_buffer_api_t *sai_buffer_api;
14
16
extern PortsOrch *gPortsOrch ;
15
17
extern sai_object_id_t gSwitchId ;
16
18
17
- using namespace std ;
19
+ #define BUFFER_POOL_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS " 10000"
20
+
21
+
22
+ static const vector<sai_buffer_pool_stat_t > bufferPoolWatermarkStatIds =
23
+ {
24
+ SAI_BUFFER_POOL_STAT_WATERMARK_BYTES,
25
+ };
18
26
19
27
type_map BufferOrch::m_buffer_type_maps = {
20
28
{CFG_BUFFER_POOL_TABLE_NAME, new object_map ()},
@@ -25,11 +33,18 @@ type_map BufferOrch::m_buffer_type_maps = {
25
33
{CFG_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME, new object_map ()}
26
34
};
27
35
28
- BufferOrch::BufferOrch (DBConnector *db, vector<string> &tableNames) : Orch(db, tableNames)
36
+ BufferOrch::BufferOrch (DBConnector *db, vector<string> &tableNames) :
37
+ Orch(db, tableNames),
38
+ m_flexCounterDb(new DBConnector(FLEX_COUNTER_DB, DBConnector::DEFAULT_UNIXSOCKET, 0 )),
39
+ m_flexCounterTable(new ProducerTable(m_flexCounterDb.get(), FLEX_COUNTER_TABLE)),
40
+ m_flexCounterGroupTable(new ProducerTable(m_flexCounterDb.get(), FLEX_COUNTER_GROUP_TABLE)),
41
+ m_countersDb(new DBConnector(COUNTERS_DB, DBConnector::DEFAULT_UNIXSOCKET, 0 )),
42
+ m_countersDbRedisClient(m_countersDb.get())
29
43
{
30
44
SWSS_LOG_ENTER ();
31
45
initTableHandlers ();
32
46
initBufferReadyLists (db);
47
+ initFlexCounterGroupTable ();
33
48
};
34
49
35
50
void BufferOrch::initTableHandlers ()
@@ -82,6 +97,32 @@ void BufferOrch::initBufferReadyList(Table& table)
82
97
}
83
98
}
84
99
100
+ void BufferOrch::initFlexCounterGroupTable (void )
101
+ {
102
+ string bufferPoolWmPluginName = " watermark_bufferpool.lua" ;
103
+
104
+ try
105
+ {
106
+ string bufferPoolLuaScript = swss::loadLuaScript (bufferPoolWmPluginName);
107
+ string bufferPoolWmSha = swss::loadRedisScript (m_countersDb.get (), bufferPoolLuaScript);
108
+
109
+ vector<FieldValueTuple> fvTuples;
110
+ fvTuples.emplace_back (BUFFER_POOL_PLUGIN_FIELD, bufferPoolWmSha);
111
+ fvTuples.emplace_back (POLL_INTERVAL_FIELD, BUFFER_POOL_WATERMARK_FLEX_STAT_COUNTER_POLL_MSECS);
112
+
113
+ // TODO (work in progress):
114
+ // Some platforms do not support buffer pool watermark clear operation on a particular pool
115
+ // Invoke the SAI clear_stats API per pool to query the capability from the API call return status
116
+ fvTuples.emplace_back (STATS_MODE_FIELD, STATS_MODE_READ_AND_CLEAR);
117
+
118
+ m_flexCounterGroupTable->set (BUFFER_POOL_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP, fvTuples);
119
+ }
120
+ catch (const runtime_error &e)
121
+ {
122
+ SWSS_LOG_ERROR (" Buffer pool watermark lua script and/or flex counter group not set successfully. Runtime error: %s" , e.what ());
123
+ }
124
+ }
125
+
85
126
bool BufferOrch::isPortReady (const std::string& port_name) const
86
127
{
87
128
SWSS_LOG_ENTER ();
@@ -105,6 +146,51 @@ bool BufferOrch::isPortReady(const std::string& port_name) const
105
146
return result;
106
147
}
107
148
149
+ void BufferOrch::generateBufferPoolWatermarkCounterIdList (void )
150
+ {
151
+ // This function will be called in FlexCounterOrch when field:value tuple "FLEX_COUNTER_STATUS":"enable"
152
+ // is received on buffer pool watermark key under table "FLEX_COUNTER_GROUP_TABLE"
153
+ // Because the SubscriberStateTable listens to the entire keyspace of "BUFFER_POOL_WATERMARK", any update
154
+ // to field value tuples under key "BUFFER_POOL_WATERMARK" will cause this tuple to be heard again
155
+ // To avoid resync the coutner ID list a second time, we introduce a data member variable to mark whether
156
+ // this operation has already been done or not yet
157
+ if (m_isBufferPoolWatermarkCounterIdListGenerated)
158
+ {
159
+ return ;
160
+ }
161
+
162
+ // Detokenize the SAI watermark stats to a string, separated by comma
163
+ string statList;
164
+ for (const auto &it : bufferPoolWatermarkStatIds)
165
+ {
166
+ statList += (sai_serialize_buffer_pool_stat (it) + list_item_delimiter);
167
+ }
168
+ if (!statList.empty ())
169
+ {
170
+ statList.pop_back ();
171
+ }
172
+
173
+ vector<FieldValueTuple> fvTuples;
174
+ fvTuples.emplace_back (BUFFER_POOL_COUNTER_ID_LIST, statList);
175
+
176
+ // Push buffer pool watermark COUNTER_ID_LIST to FLEX_COUNTER_TABLE on a per buffer pool basis
177
+ for (const auto &it : *(m_buffer_type_maps[CFG_BUFFER_POOL_TABLE_NAME]))
178
+ {
179
+ string key = BUFFER_POOL_WATERMARK_STAT_COUNTER_FLEX_COUNTER_GROUP " :" + sai_serialize_object_id (it.second );
180
+ m_flexCounterTable->set (key, fvTuples);
181
+ }
182
+
183
+ m_isBufferPoolWatermarkCounterIdListGenerated = true ;
184
+ }
185
+
186
+ const object_map &BufferOrch::getBufferPoolNameOidMap (void )
187
+ {
188
+ // In the case different Orches are running in
189
+ // different threads, caller may need to grab a read lock
190
+ // before calling this function
191
+ return *m_buffer_type_maps[CFG_BUFFER_POOL_TABLE_NAME];
192
+ }
193
+
108
194
task_process_status BufferOrch::processBufferPool (Consumer &consumer)
109
195
{
110
196
SWSS_LOG_ENTER ();
@@ -209,6 +295,12 @@ task_process_status BufferOrch::processBufferPool(Consumer &consumer)
209
295
}
210
296
(*(m_buffer_type_maps[map_type_name]))[object_name] = sai_object;
211
297
SWSS_LOG_NOTICE (" Created buffer pool %s with type %s" , object_name.c_str (), map_type_name.c_str ());
298
+ // Here we take the PFC watchdog approach to update the COUNTERS_DB metadata (e.g., PFC_WD_DETECTION_TIME per queue)
299
+ // at initialization (creation and registration phase)
300
+ // Specifically, we push the buffer pool name to oid mapping upon the creation of the oid
301
+ // In pg and queue case, this mapping installment is deferred to FlexCounterOrch at a reception of field
302
+ // "FLEX_COUNTER_STATUS"
303
+ m_countersDbRedisClient.hset (COUNTERS_BUFFER_POOL_NAME_MAP, object_name, sai_serialize_object_id (sai_object));
212
304
}
213
305
}
214
306
else if (op == DEL_COMMAND)
@@ -222,6 +314,7 @@ task_process_status BufferOrch::processBufferPool(Consumer &consumer)
222
314
SWSS_LOG_NOTICE (" Removed buffer pool %s with type %s" , object_name.c_str (), map_type_name.c_str ());
223
315
auto it_to_delete = (m_buffer_type_maps[map_type_name])->find (object_name);
224
316
(m_buffer_type_maps[map_type_name])->erase (it_to_delete);
317
+ m_countersDbRedisClient.hdel (COUNTERS_BUFFER_POOL_NAME_MAP, object_name);
225
318
}
226
319
else
227
320
{
@@ -370,7 +463,7 @@ task_process_status BufferOrch::processBufferProfile(Consumer &consumer)
370
463
}
371
464
372
465
/*
373
- Input sample "BUFFER_QUEUE_TABLE: Ethernet4,Ethernet45: 10-15"
466
+ Input sample "BUFFER_QUEUE| Ethernet4,Ethernet45| 10-15"
374
467
*/
375
468
task_process_status BufferOrch::processQueue (Consumer &consumer)
376
469
{
0 commit comments