@@ -8,10 +8,13 @@ using namespace std;
8
8
using namespace swss ;
9
9
10
10
extern sai_policer_api_t * sai_policer_api;
11
+ extern sai_port_api_t *sai_port_api;
11
12
12
13
extern sai_object_id_t gSwitchId ;
13
14
extern PortsOrch* gPortsOrch ;
14
15
16
+ #define ETHERNET_PREFIX " Ethernet"
17
+
15
18
static const string meter_type_field = " METER_TYPE" ;
16
19
static const string mode_field = " MODE" ;
17
20
static const string color_source_field = " COLOR_SOURCE" ;
@@ -23,6 +26,11 @@ static const string green_packet_action_field = "GREEN_PACKET_ACTION";
23
26
static const string red_packet_action_field = " RED_PACKET_ACTION" ;
24
27
static const string yellow_packet_action_field = " YELLOW_PACKET_ACTION" ;
25
28
29
+ static const string storm_control_kbps = " KBPS" ;
30
+ static const string storm_broadcast = " broadcast" ;
31
+ static const string storm_unknown_unicast = " unknown-unicast" ;
32
+ static const string storm_unknown_mcast = " unknown-multicast" ;
33
+
26
34
static const map<string, sai_meter_type_t > meter_type_map = {
27
35
{" PACKETS" , SAI_METER_TYPE_PACKETS},
28
36
{" BYTES" , SAI_METER_TYPE_BYTES}
@@ -105,15 +113,268 @@ bool PolicerOrch::decreaseRefCount(const string &name)
105
113
return true ;
106
114
}
107
115
108
- PolicerOrch::PolicerOrch (DBConnector* db, string tableName) :
109
- Orch(db, tableName)
116
+ PolicerOrch::PolicerOrch (vector<TableConnector> &tableNames, PortsOrch *portOrch) : Orch(tableNames), m_portsOrch(portOrch)
110
117
{
111
118
SWSS_LOG_ENTER ();
112
119
}
113
120
121
+ task_process_status PolicerOrch::handlePortStormControlTable (swss::KeyOpFieldsValuesTuple tuple)
122
+ {
123
+ auto key = kfvKey (tuple);
124
+ auto op = kfvOp (tuple);
125
+ string storm_key = key;
126
+ auto tokens = tokenize (storm_key, config_db_key_delimiter);
127
+ auto interface_name = tokens[0 ];
128
+ auto storm_type = tokens[1 ];
129
+ Port port;
130
+
131
+ /* Only proceed for Ethernet interfaces*/
132
+ if (strncmp (interface_name.c_str (), ETHERNET_PREFIX, strlen (ETHERNET_PREFIX)))
133
+ {
134
+ SWSS_LOG_ERROR (" %s: Unsupported / Invalid interface %s" ,
135
+ storm_type.c_str (), interface_name.c_str ());
136
+ return task_process_status::task_success;
137
+ }
138
+ if (!gPortsOrch ->getPort (interface_name, port))
139
+ {
140
+ SWSS_LOG_ERROR (" Failed to apply storm-control %s to port %s. Port not found" ,
141
+ storm_type.c_str (), interface_name.c_str ());
142
+ /* continue here as there can be more interfaces*/
143
+ return task_process_status::task_success;
144
+ }
145
+ /* Policer Name: _<interface_name>_<storm_type>*/
146
+ const auto storm_policer_name = " _" +interface_name+" _" +storm_type;
147
+
148
+ if (op == SET_COMMAND)
149
+ {
150
+ // Mark the operation as an 'update', if the policer exists.
151
+ bool update = m_syncdPolicers.find (storm_policer_name) != m_syncdPolicers.end ();
152
+ vector <sai_attribute_t > attrs;
153
+ bool cir = false ;
154
+ sai_attribute_t attr;
155
+
156
+ /* Meter type hardcoded to BYTES*/
157
+ attr.id = SAI_POLICER_ATTR_METER_TYPE;
158
+ attr.value .s32 = (sai_meter_type_t ) meter_type_map.at (" BYTES" );
159
+ attrs.push_back (attr);
160
+
161
+ /* Policer mode hardcoded to STORM_CONTROL*/
162
+ attr.id = SAI_POLICER_ATTR_MODE;
163
+ attr.value .s32 = (sai_policer_mode_t ) policer_mode_map.at (" STORM_CONTROL" );
164
+ attrs.push_back (attr);
165
+
166
+ /* Red Packet Action hardcoded to DROP*/
167
+ attr.id = SAI_POLICER_ATTR_RED_PACKET_ACTION;
168
+ attr.value .s32 = packet_action_map.at (" DROP" );
169
+ attrs.push_back (attr);
170
+
171
+ for (auto i = kfvFieldsValues (tuple).begin ();
172
+ i != kfvFieldsValues (tuple).end (); ++i)
173
+ {
174
+ auto field = to_upper (fvField (*i));
175
+ auto value = to_upper (fvValue (*i));
176
+
177
+ /* BPS value is used as CIR*/
178
+ if (field == storm_control_kbps)
179
+ {
180
+ attr.id = SAI_POLICER_ATTR_CIR;
181
+ /* convert kbps to bps*/
182
+ attr.value .u64 = (stoul (value)*1000 /8 );
183
+ cir = true ;
184
+ attrs.push_back (attr);
185
+ SWSS_LOG_DEBUG (" CIR %s" ,value.c_str ());
186
+ }
187
+ else
188
+ {
189
+ SWSS_LOG_ERROR (" Unknown storm control attribute %s specified" ,
190
+ field.c_str ());
191
+ continue ;
192
+ }
193
+ }
194
+ /* CIR is mandatory parameter*/
195
+ if (!cir)
196
+ {
197
+ SWSS_LOG_ERROR (" Failed to create storm control policer %s,\
198
+ missing mandatory fields" , storm_policer_name.c_str ());
199
+ return task_process_status::task_failed;
200
+ }
201
+
202
+ /* Enabling storm-control on port*/
203
+ sai_attribute_t port_attr;
204
+ if (storm_type == storm_broadcast)
205
+ {
206
+ port_attr.id = SAI_PORT_ATTR_BROADCAST_STORM_CONTROL_POLICER_ID;
207
+ }
208
+ else if (storm_type == storm_unknown_unicast)
209
+ {
210
+ port_attr.id = SAI_PORT_ATTR_FLOOD_STORM_CONTROL_POLICER_ID;
211
+ }
212
+ else if (storm_type == storm_unknown_mcast)
213
+ {
214
+ port_attr.id = SAI_PORT_ATTR_MULTICAST_STORM_CONTROL_POLICER_ID;
215
+ }
216
+ else
217
+ {
218
+ SWSS_LOG_ERROR (" Unknown storm_type %s" , storm_type.c_str ());
219
+ return task_process_status::task_failed;
220
+ }
221
+
222
+ sai_object_id_t policer_id;
223
+ // Create a new policer
224
+ if (!update)
225
+ {
226
+ sai_status_t status = sai_policer_api->create_policer (
227
+ &policer_id, gSwitchId , (uint32_t )attrs.size (), attrs.data ());
228
+ if (status != SAI_STATUS_SUCCESS)
229
+ {
230
+ SWSS_LOG_ERROR (" Failed to create policer %s, rv:%d" ,
231
+ storm_policer_name.c_str (), status);
232
+ if (handleSaiCreateStatus (SAI_API_POLICER, status) == task_need_retry)
233
+ {
234
+ return task_process_status::task_need_retry;
235
+ }
236
+ }
237
+
238
+ SWSS_LOG_DEBUG (" Created storm-control policer %s" , storm_policer_name.c_str ());
239
+ m_syncdPolicers[storm_policer_name] = policer_id;
240
+ m_policerRefCounts[storm_policer_name] = 0 ;
241
+ }
242
+ // Update an existing policer
243
+ else
244
+ {
245
+ policer_id = m_syncdPolicers[storm_policer_name];
246
+
247
+ // The update operation has limitations that it could only update
248
+ // the rate and the size accordingly.
249
+ // STORM_CONTROL: CIR, CBS
250
+ for (auto & attr: attrs)
251
+ {
252
+ if (attr.id != SAI_POLICER_ATTR_CIR)
253
+ {
254
+ continue ;
255
+ }
256
+
257
+ sai_status_t status = sai_policer_api->set_policer_attribute (
258
+ policer_id, &attr);
259
+ if (status != SAI_STATUS_SUCCESS)
260
+ {
261
+ SWSS_LOG_ERROR (" Failed to update policer %s attribute, rv:%d" ,
262
+ storm_policer_name.c_str (), status);
263
+ if (handleSaiSetStatus (SAI_API_POLICER, status) == task_need_retry)
264
+ {
265
+ return task_process_status::task_need_retry;
266
+ }
267
+
268
+ }
269
+ }
270
+ }
271
+ policer_id = m_syncdPolicers[storm_policer_name];
272
+
273
+ if (update)
274
+ {
275
+ SWSS_LOG_NOTICE (" update storm-control policer %s" , storm_policer_name.c_str ());
276
+ port_attr.value .oid = SAI_NULL_OBJECT_ID;
277
+ /* Remove and re-apply policer*/
278
+ sai_status_t status = sai_port_api->set_port_attribute (port.m_port_id , &port_attr);
279
+ if (status != SAI_STATUS_SUCCESS)
280
+ {
281
+ SWSS_LOG_ERROR (" Failed to remove storm-control %s from port %s, rv:%d" ,
282
+ storm_type.c_str (), interface_name.c_str (), status);
283
+ if (handleSaiSetStatus (SAI_API_POLICER, status) == task_need_retry)
284
+ {
285
+ return task_process_status::task_need_retry;
286
+ }
287
+ }
288
+ }
289
+ port_attr.value .oid = policer_id;
290
+
291
+ sai_status_t status = sai_port_api->set_port_attribute (port.m_port_id , &port_attr);
292
+ if (status != SAI_STATUS_SUCCESS)
293
+ {
294
+ SWSS_LOG_ERROR (" Failed to apply storm-control %s to port %s, rv:%d" ,
295
+ storm_type.c_str (), interface_name.c_str (),status);
296
+
297
+ /* TODO: Do the below policer cleanup in an API*/
298
+ /* Remove the already created policer*/
299
+ if (SAI_STATUS_SUCCESS != sai_policer_api->remove_policer (
300
+ m_syncdPolicers[storm_policer_name]))
301
+ {
302
+ SWSS_LOG_ERROR (" Failed to remove policer %s, rv:%d" ,
303
+ storm_policer_name.c_str (), status);
304
+ /* TODO: Just doing a syslog. */
305
+ }
306
+
307
+ SWSS_LOG_NOTICE (" Removed policer %s as set_port_attribute for %s failed" ,
308
+ storm_policer_name.c_str (),interface_name.c_str ());
309
+ m_syncdPolicers.erase (storm_policer_name);
310
+ m_policerRefCounts.erase (storm_policer_name);
311
+
312
+ return task_process_status::task_need_retry;
313
+ }
314
+ }
315
+ else if (op == DEL_COMMAND)
316
+ {
317
+ if (m_syncdPolicers.find (storm_policer_name) == m_syncdPolicers.end ())
318
+ {
319
+ SWSS_LOG_ERROR (" Policer %s not configured" , storm_policer_name.c_str ());
320
+ return task_process_status::task_success;
321
+ }
322
+
323
+ sai_attribute_t port_attr;
324
+ if (storm_type == storm_broadcast)
325
+ {
326
+ port_attr.id = SAI_PORT_ATTR_BROADCAST_STORM_CONTROL_POLICER_ID;
327
+ }
328
+ else if (storm_type == storm_unknown_unicast)
329
+ {
330
+ port_attr.id = SAI_PORT_ATTR_FLOOD_STORM_CONTROL_POLICER_ID;
331
+ }
332
+ else if (storm_type == storm_unknown_mcast)
333
+ {
334
+ port_attr.id = SAI_PORT_ATTR_MULTICAST_STORM_CONTROL_POLICER_ID;
335
+ }
336
+ else
337
+ {
338
+ SWSS_LOG_ERROR (" Unknown storm_type %s" , storm_type.c_str ());
339
+ return task_process_status::task_failed;
340
+ }
341
+
342
+ port_attr.value .oid = SAI_NULL_OBJECT_ID;
343
+
344
+ sai_status_t status = sai_port_api->set_port_attribute (port.m_port_id , &port_attr);
345
+ if (status != SAI_STATUS_SUCCESS)
346
+ {
347
+ SWSS_LOG_ERROR (" Failed to remove storm-control %s from port %s, rv:%d" ,
348
+ storm_type.c_str (), interface_name.c_str (), status);
349
+ if (handleSaiRemoveStatus (SAI_API_POLICER, status) == task_need_retry)
350
+ {
351
+ return task_process_status::task_need_retry;
352
+ }
353
+ }
354
+
355
+ status = sai_policer_api->remove_policer (
356
+ m_syncdPolicers[storm_policer_name]);
357
+ if (status != SAI_STATUS_SUCCESS)
358
+ {
359
+ SWSS_LOG_ERROR (" Failed to remove policer %s, rv:%d" ,
360
+ storm_policer_name.c_str (), status);
361
+ if (handleSaiRemoveStatus (SAI_API_POLICER, status) == task_need_retry)
362
+ {
363
+ return task_process_status::task_need_retry;
364
+ }
365
+ }
366
+
367
+ SWSS_LOG_NOTICE (" Removed policer %s" , storm_policer_name.c_str ());
368
+ m_syncdPolicers.erase (storm_policer_name);
369
+ m_policerRefCounts.erase (storm_policer_name);
370
+ }
371
+ return task_process_status::task_success;
372
+ }
373
+
114
374
void PolicerOrch::doTask (Consumer &consumer)
115
375
{
116
376
SWSS_LOG_ENTER ();
377
+ task_process_status storm_status = task_success;
117
378
118
379
if (!gPortsOrch ->allPortsReady ())
119
380
{
@@ -127,7 +388,23 @@ void PolicerOrch::doTask(Consumer &consumer)
127
388
128
389
auto key = kfvKey (tuple);
129
390
auto op = kfvOp (tuple);
391
+ auto table_name = consumer.getTableName ();
130
392
393
+ // Special handling for storm-control configuration.
394
+ if (table_name == CFG_PORT_STORM_CONTROL_TABLE_NAME)
395
+ {
396
+ storm_status = handlePortStormControlTable (tuple);
397
+ if ((storm_status == task_process_status::task_success) ||
398
+ (storm_status == task_process_status::task_failed))
399
+ {
400
+ it = consumer.m_toSync .erase (it);
401
+ }
402
+ else
403
+ {
404
+ it++;
405
+ }
406
+ continue ;
407
+ }
131
408
if (op == SET_COMMAND)
132
409
{
133
410
// Mark the operation as an 'update', if the policer exists.
0 commit comments