Skip to content

Commit 40316f7

Browse files
Broadcast Unknown-multicast and Unknown-unicast Storm-control (#1306)
* Handle BUM Storm-control CONFIG_DB update. * Segregate POLICER table and PORT_STORM_CONTROL table handling * Broadcast, Unknown-multicast and Unknown-unicast storm-control on Ethernet interfaces.
1 parent f5c5cc5 commit 40316f7

File tree

6 files changed

+621
-8
lines changed

6 files changed

+621
-8
lines changed

orchagent/orchdaemon.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ QosOrch *gQosOrch;
4545
SwitchOrch *gSwitchOrch;
4646
Directory<Orch*> gDirectory;
4747
NatOrch *gNatOrch;
48+
PolicerOrch *gPolicerOrch;
4849
MlagOrch *gMlagOrch;
4950
IsoGrpOrch *gIsoGrpOrch;
5051
MACsecOrch *gMacsecOrch;
@@ -242,11 +243,17 @@ bool OrchDaemon::init()
242243
};
243244
gBufferOrch = new BufferOrch(m_applDb, m_configDb, m_stateDb, buffer_tables);
244245

245-
PolicerOrch *policer_orch = new PolicerOrch(m_configDb, "POLICER");
246+
vector<TableConnector> policer_tables = {
247+
TableConnector(m_configDb, CFG_POLICER_TABLE_NAME),
248+
TableConnector(m_configDb, CFG_PORT_STORM_CONTROL_TABLE_NAME)
249+
};
250+
251+
TableConnector stateDbStorm(m_stateDb, "BUM_STORM_CAPABILITY");
252+
gPolicerOrch = new PolicerOrch(policer_tables, gPortsOrch);
246253

247254
TableConnector stateDbMirrorSession(m_stateDb, STATE_MIRROR_SESSION_TABLE_NAME);
248255
TableConnector confDbMirrorSession(m_configDb, CFG_MIRROR_SESSION_TABLE_NAME);
249-
gMirrorOrch = new MirrorOrch(stateDbMirrorSession, confDbMirrorSession, gPortsOrch, gRouteOrch, gNeighOrch, gFdbOrch, policer_orch);
256+
gMirrorOrch = new MirrorOrch(stateDbMirrorSession, confDbMirrorSession, gPortsOrch, gRouteOrch, gNeighOrch, gFdbOrch, gPolicerOrch);
250257

251258
TableConnector confDbAclTable(m_configDb, CFG_ACL_TABLE_TABLE_NAME);
252259
TableConnector confDbAclTableType(m_configDb, CFG_ACL_TABLE_TYPE_TABLE_NAME);
@@ -339,7 +346,7 @@ bool OrchDaemon::init()
339346
* when iterating ConsumerMap. This is ensured implicitly by the order of keys in ordered map.
340347
* For cases when Orch has to process tables in specific order, like PortsOrch during warm start, it has to override Orch::doTask()
341348
*/
342-
m_orchList = { gSwitchOrch, gCrmOrch, gPortsOrch, gBufferOrch, gFlowCounterRouteOrch, mux_orch, mux_cb_orch, gIntfsOrch, gNeighOrch, gNhgMapOrch, gNhgOrch, gCbfNhgOrch, gRouteOrch, gCoppOrch, gQosOrch, wm_orch, policer_orch, tunnel_decap_orch, sflow_orch, gDebugCounterOrch, gMacsecOrch, gBfdOrch, gSrv6Orch};
349+
m_orchList = { gSwitchOrch, gCrmOrch, gPortsOrch, gBufferOrch, gFlowCounterRouteOrch, mux_orch, mux_cb_orch, gIntfsOrch, gNeighOrch, gNhgMapOrch, gNhgOrch, gCbfNhgOrch, gRouteOrch, gCoppOrch, gQosOrch, wm_orch, gPolicerOrch, tunnel_decap_orch, sflow_orch, gDebugCounterOrch, gMacsecOrch, gBfdOrch, gSrv6Orch};
343350

344351
bool initialize_dtel = false;
345352
if (platform == BFN_PLATFORM_SUBSTRING || platform == VS_PLATFORM_SUBSTRING)

orchagent/policerorch.cpp

Lines changed: 279 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ using namespace std;
88
using namespace swss;
99

1010
extern sai_policer_api_t* sai_policer_api;
11+
extern sai_port_api_t *sai_port_api;
1112

1213
extern sai_object_id_t gSwitchId;
1314
extern PortsOrch* gPortsOrch;
1415

16+
#define ETHERNET_PREFIX "Ethernet"
17+
1518
static const string meter_type_field = "METER_TYPE";
1619
static const string mode_field = "MODE";
1720
static const string color_source_field = "COLOR_SOURCE";
@@ -23,6 +26,11 @@ static const string green_packet_action_field = "GREEN_PACKET_ACTION";
2326
static const string red_packet_action_field = "RED_PACKET_ACTION";
2427
static const string yellow_packet_action_field = "YELLOW_PACKET_ACTION";
2528

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+
2634
static const map<string, sai_meter_type_t> meter_type_map = {
2735
{"PACKETS", SAI_METER_TYPE_PACKETS},
2836
{"BYTES", SAI_METER_TYPE_BYTES}
@@ -105,15 +113,268 @@ bool PolicerOrch::decreaseRefCount(const string &name)
105113
return true;
106114
}
107115

108-
PolicerOrch::PolicerOrch(DBConnector* db, string tableName) :
109-
Orch(db, tableName)
116+
PolicerOrch::PolicerOrch(vector<TableConnector> &tableNames, PortsOrch *portOrch) : Orch(tableNames), m_portsOrch(portOrch)
110117
{
111118
SWSS_LOG_ENTER();
112119
}
113120

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+
114374
void PolicerOrch::doTask(Consumer &consumer)
115375
{
116376
SWSS_LOG_ENTER();
377+
task_process_status storm_status = task_success;
117378

118379
if (!gPortsOrch->allPortsReady())
119380
{
@@ -127,7 +388,23 @@ void PolicerOrch::doTask(Consumer &consumer)
127388

128389
auto key = kfvKey(tuple);
129390
auto op = kfvOp(tuple);
391+
auto table_name = consumer.getTableName();
130392

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+
}
131408
if (op == SET_COMMAND)
132409
{
133410
// Mark the operation as an 'update', if the policer exists.

orchagent/policerorch.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,20 @@ typedef map<string, int> PolicerRefCountTable;
1414
class PolicerOrch : public Orch
1515
{
1616
public:
17-
PolicerOrch(DBConnector* db, string tableName);
17+
PolicerOrch(vector<TableConnector> &tableNames, PortsOrch *portOrch);
1818

1919
bool policerExists(const string &name);
2020
bool getPolicerOid(const string &name, sai_object_id_t &oid);
2121

2222
bool increaseRefCount(const string &name);
2323
bool decreaseRefCount(const string &name);
24+
task_process_status handlePortStormControlTable(swss::KeyOpFieldsValuesTuple tuple);
2425
private:
26+
PortsOrch *m_portsOrch;
2527
virtual void doTask(Consumer& consumer);
2628

2729
PolicerTable m_syncdPolicers;
2830
PolicerRefCountTable m_policerRefCounts;
2931
};
32+
33+

tests/mock_tests/aclorch_ut.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,12 @@ namespace aclorch_test
426426
};
427427
gRouteOrch = new RouteOrch(m_app_db.get(), route_tables, gSwitchOrch, gNeighOrch, gIntfsOrch, gVrfOrch, gFgNhgOrch, gSrv6Orch);
428428

429-
PolicerOrch *policer_orch = new PolicerOrch(m_config_db.get(), "POLICER");
429+
vector<TableConnector> policer_tables = {
430+
TableConnector(m_config_db.get(), CFG_POLICER_TABLE_NAME),
431+
TableConnector(m_config_db.get(), CFG_PORT_STORM_CONTROL_TABLE_NAME)
432+
};
433+
TableConnector stateDbStorm(m_state_db.get(), "BUM_STORM_CAPABILITY");
434+
PolicerOrch *policer_orch = new PolicerOrch(policer_tables, gPortsOrch);
430435

431436
TableConnector stateDbMirrorSession(m_state_db.get(), STATE_MIRROR_SESSION_TABLE_NAME);
432437
TableConnector confDbMirrorSession(m_config_db.get(), CFG_MIRROR_SESSION_TABLE_NAME);

0 commit comments

Comments
 (0)