Skip to content

Commit 9f6efa0

Browse files
stepanblyschakliat-grozovik
authored andcommitted
[port/buffer] introduce a sync mechanism to protect port PG/queue from changes under PFC storm (#1143)
* [port/buffer] introduce a sync mechanism to protect port PG/queue from changes under PFC storm Signed-off-by: Stepan Blyschak <[email protected]> * [pfcactionhandler] fix pg lock bit is not set Signed-off-by: Stepan Blyschak <[email protected]> * [portsorch_ut] add PfcZeroBufferHandlerLocksPortPgAndQueue unit test Signed-off-by: Stepan Blyschak <[email protected]> * [pfcactionhandler] add method header Signed-off-by: Stepan Blyschak <[email protected]> * [port.h] fix typos Signed-off-by: Stepan Blyschak <[email protected]> * [pfcactionhandler] fix method name that set lock bits Signed-off-by: Stepan Blyschak <[email protected]>
1 parent 823e426 commit 9f6efa0

File tree

8 files changed

+181
-10
lines changed

8 files changed

+181
-10
lines changed

orchagent/bufferorch.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,11 @@ task_process_status BufferOrch::processQueue(Consumer &consumer)
562562
SWSS_LOG_ERROR("Invalid queue index specified:%zd", ind);
563563
return task_process_status::task_invalid_entry;
564564
}
565+
if (port.m_queue_lock[ind])
566+
{
567+
SWSS_LOG_WARN("Queue %zd on port %s is locked, will retry", ind, port_name.c_str());
568+
return task_process_status::task_need_retry;
569+
}
565570
queue_id = port.m_queue_ids[ind];
566571
SWSS_LOG_DEBUG("Applying buffer profile:0x%" PRIx64 " to queue index:%zd, queue sai_id:0x%" PRIx64, sai_buffer_profile, ind, queue_id);
567572
sai_status_t sai_status = sai_queue_api->set_queue_attribute(queue_id, &attr);
@@ -661,6 +666,11 @@ task_process_status BufferOrch::processPriorityGroup(Consumer &consumer)
661666
SWSS_LOG_ERROR("Invalid pg index specified:%zd", ind);
662667
return task_process_status::task_invalid_entry;
663668
}
669+
if (port.m_priority_group_lock[ind])
670+
{
671+
SWSS_LOG_WARN("Priority group %zd on port %s is locked, will retry", ind, port_name.c_str());
672+
return task_process_status::task_need_retry;
673+
}
664674
pg_id = port.m_priority_group_ids[ind];
665675
SWSS_LOG_DEBUG("Applying buffer profile:0x%" PRIx64 " to port:%s pg index:%zd, pg sai_id:0x%" PRIx64, sai_buffer_profile, port_name.c_str(), ind, pg_id);
666676
sai_status_t sai_status = sai_buffer_api->set_ingress_priority_group_attribute(pg_id, &attr);

orchagent/pfcactionhandler.cpp

+25-7
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,15 @@ PfcWdZeroBufferHandler::PfcWdZeroBufferHandler(sai_object_id_t port,
434434
{
435435
SWSS_LOG_ENTER();
436436

437+
Port portInstance;
438+
if (!gPortsOrch->getPort(port, portInstance))
439+
{
440+
SWSS_LOG_ERROR("Cannot get port by ID 0x%" PRIx64, port);
441+
return;
442+
}
443+
444+
setPriorityGroupAndQueueLockFlag(portInstance, true);
445+
437446
sai_attribute_t attr;
438447
attr.id = SAI_QUEUE_ATTR_BUFFER_PROFILE_ID;
439448

@@ -462,13 +471,6 @@ PfcWdZeroBufferHandler::PfcWdZeroBufferHandler(sai_object_id_t port,
462471
m_originalQueueBufferProfile = oldQueueProfileId;
463472

464473
// Get PG
465-
Port portInstance;
466-
if (!gPortsOrch->getPort(port, portInstance))
467-
{
468-
SWSS_LOG_ERROR("Cannot get port by ID 0x%" PRIx64, port);
469-
return;
470-
}
471-
472474
sai_object_id_t pg = portInstance.m_priority_group_ids[static_cast <size_t> (queueId)];
473475

474476
attr.id = SAI_INGRESS_PRIORITY_GROUP_ATTR_BUFFER_PROFILE;
@@ -533,6 +535,22 @@ PfcWdZeroBufferHandler::~PfcWdZeroBufferHandler(void)
533535
SWSS_LOG_ERROR("Failed to set buffer profile ID on queue 0x%" PRIx64 ": %d", getQueue(), status);
534536
return;
535537
}
538+
539+
setPriorityGroupAndQueueLockFlag(portInstance, false);
540+
}
541+
542+
void PfcWdZeroBufferHandler::setPriorityGroupAndQueueLockFlag(Port& port, bool isLocked) const
543+
{
544+
// set lock bits on PG and queue
545+
port.m_priority_group_lock[static_cast<size_t>(getQueueId())] = isLocked;
546+
for (size_t i = 0; i < port.m_queue_ids.size(); ++i)
547+
{
548+
if (port.m_queue_ids[i] == getQueue())
549+
{
550+
port.m_queue_lock[i] = isLocked;
551+
}
552+
}
553+
gPortsOrch->setPort(port.m_alias, port);
536554
}
537555

538556
PfcWdZeroBufferHandler::ZeroBufferProfile::ZeroBufferProfile(void)

orchagent/pfcactionhandler.h

+9-3
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,17 @@ class PfcWdActionHandler
3131
uint8_t queueId, shared_ptr<Table> countersTable);
3232
virtual ~PfcWdActionHandler(void);
3333

34-
inline sai_object_id_t getPort(void)
34+
inline sai_object_id_t getPort(void) const
3535
{
3636
return m_port;
3737
}
3838

39-
inline sai_object_id_t getQueue(void)
39+
inline sai_object_id_t getQueue(void) const
4040
{
4141
return m_queue;
4242
}
4343

44-
inline sai_object_id_t getQueueId(void)
44+
inline uint8_t getQueueId(void) const
4545
{
4646
return m_queueId;
4747
}
@@ -123,6 +123,12 @@ class PfcWdZeroBufferHandler: public PfcWdLossyHandler
123123
virtual ~PfcWdZeroBufferHandler(void);
124124

125125
private:
126+
/*
127+
* Sets lock bits on port's priority group and queue
128+
* to protect them from beeing changed by other Orch's
129+
*/
130+
void setPriorityGroupAndQueueLockFlag(Port& port, bool isLocked) const;
131+
126132
// Singletone class for keeping shared data - zero buffer profiles
127133
class ZeroBufferProfile
128134
{

orchagent/port.h

+10
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,16 @@ class Port
9696
std::vector<sai_object_id_t> m_priority_group_ids;
9797
sai_port_priority_flow_control_mode_t m_pfc_asym = SAI_PORT_PRIORITY_FLOW_CONTROL_MODE_COMBINED;
9898
uint8_t m_pfc_bitmask = 0;
99+
/*
100+
* Following two bit vectors are used to lock
101+
* the PG/queue from being changed in BufferOrch.
102+
* The use case scenario is when PfcWdZeroBufferHandler
103+
* sets zero buffer profile it should protect PG/queue
104+
* from being overwritten in BufferOrch.
105+
*/
106+
std::vector<bool> m_queue_lock;
107+
std::vector<bool> m_priority_group_lock;
108+
99109
};
100110

101111
}

orchagent/portsorch.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -2608,6 +2608,7 @@ void PortsOrch::initializeQueues(Port &port)
26082608
SWSS_LOG_INFO("Get %d queues for port %s", attr.value.u32, port.m_alias.c_str());
26092609

26102610
port.m_queue_ids.resize(attr.value.u32);
2611+
port.m_queue_lock.resize(attr.value.u32);
26112612

26122613
if (attr.value.u32 == 0)
26132614
{
@@ -2643,6 +2644,7 @@ void PortsOrch::initializePriorityGroups(Port &port)
26432644
SWSS_LOG_INFO("Get %d priority groups for port %s", attr.value.u32, port.m_alias.c_str());
26442645

26452646
port.m_priority_group_ids.resize(attr.value.u32);
2647+
port.m_priority_group_lock.resize(attr.value.u32);
26462648

26472649
if (attr.value.u32 == 0)
26482650
{

tests/mock_tests/mock_orchagent_main.h

+1
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,4 @@ extern sai_tunnel_api_t *sai_tunnel_api;
5454
extern sai_next_hop_api_t *sai_next_hop_api;
5555
extern sai_hostif_api_t *sai_hostif_api;
5656
extern sai_buffer_api_t *sai_buffer_api;
57+
extern sai_queue_api_t *sai_queue_api;

tests/mock_tests/portsorch_ut.cpp

+122
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "ut_helper.h"
22
#include "mock_orchagent_main.h"
33
#include "mock_table.h"
4+
#include "pfcactionhandler.h"
45

56
#include <sstream>
67

@@ -14,12 +15,15 @@ namespace portsorch_test
1415
shared_ptr<swss::DBConnector> m_app_db;
1516
shared_ptr<swss::DBConnector> m_config_db;
1617
shared_ptr<swss::DBConnector> m_state_db;
18+
shared_ptr<swss::DBConnector> m_counters_db;
1719

1820
PortsOrchTest()
1921
{
2022
// FIXME: move out from constructor
2123
m_app_db = make_shared<swss::DBConnector>(
2224
"APPL_DB", 0);
25+
m_counters_db = make_shared<swss::DBConnector>(
26+
"COUNTERS_DB", 0);
2327
m_config_db = make_shared<swss::DBConnector>(
2428
"CONFIG_DB", 0);
2529
m_state_db = make_shared<swss::DBConnector>(
@@ -310,4 +314,122 @@ namespace portsorch_test
310314
gBufferOrch->dumpPendingTasks(ts);
311315
ASSERT_TRUE(ts.empty());
312316
}
317+
318+
TEST_F(PortsOrchTest, PfcZeroBufferHandlerLocksPortPgAndQueue)
319+
{
320+
Table portTable = Table(m_app_db.get(), APP_PORT_TABLE_NAME);
321+
Table pgTable = Table(m_config_db.get(), CFG_BUFFER_PG_TABLE_NAME);
322+
Table profileTable = Table(m_config_db.get(), CFG_BUFFER_PROFILE_TABLE_NAME);
323+
Table poolTable = Table(m_config_db.get(), CFG_BUFFER_POOL_TABLE_NAME);
324+
325+
// Get SAI default ports to populate DB
326+
auto ports = ut_helper::getInitialSaiPorts();
327+
328+
// Create dependencies ...
329+
330+
const int portsorch_base_pri = 40;
331+
332+
vector<table_name_with_pri_t> ports_tables = {
333+
{ APP_PORT_TABLE_NAME, portsorch_base_pri + 5 },
334+
{ APP_VLAN_TABLE_NAME, portsorch_base_pri + 2 },
335+
{ APP_VLAN_MEMBER_TABLE_NAME, portsorch_base_pri },
336+
{ APP_LAG_TABLE_NAME, portsorch_base_pri + 4 },
337+
{ APP_LAG_MEMBER_TABLE_NAME, portsorch_base_pri }
338+
};
339+
340+
ASSERT_EQ(gPortsOrch, nullptr);
341+
gPortsOrch = new PortsOrch(m_app_db.get(), ports_tables);
342+
vector<string> buffer_tables = { CFG_BUFFER_POOL_TABLE_NAME,
343+
CFG_BUFFER_PROFILE_TABLE_NAME,
344+
CFG_BUFFER_QUEUE_TABLE_NAME,
345+
CFG_BUFFER_PG_TABLE_NAME,
346+
CFG_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME,
347+
CFG_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME };
348+
349+
ASSERT_EQ(gBufferOrch, nullptr);
350+
gBufferOrch = new BufferOrch(m_config_db.get(), buffer_tables);
351+
352+
// Populate port table with SAI ports
353+
for (const auto &it : ports)
354+
{
355+
portTable.set(it.first, it.second);
356+
}
357+
358+
// Set PortConfigDone, PortInitDone
359+
portTable.set("PortConfigDone", { { "count", to_string(ports.size()) } });
360+
portTable.set("PortInitDone", { { "lanes", "0" } });
361+
362+
// refill consumer
363+
gPortsOrch->addExistingData(&portTable);
364+
365+
// Apply configuration :
366+
// create ports
367+
368+
static_cast<Orch *>(gPortsOrch)->doTask();
369+
370+
// Apply configuration
371+
// ports
372+
static_cast<Orch *>(gPortsOrch)->doTask();
373+
374+
ASSERT_TRUE(gPortsOrch->allPortsReady());
375+
376+
// No more tasks
377+
vector<string> ts;
378+
gPortsOrch->dumpPendingTasks(ts);
379+
ASSERT_TRUE(ts.empty());
380+
ts.clear();
381+
382+
// Simulate storm drop handler started on Ethernet0 TC 3
383+
Port port;
384+
gPortsOrch->getPort("Ethernet0", port);
385+
386+
auto countersTable = make_shared<Table>(m_counters_db.get(), COUNTERS_TABLE);
387+
auto dropHandler = make_unique<PfcWdZeroBufferHandler>(port.m_port_id, port.m_queue_ids[3], 3, countersTable);
388+
389+
// Create test buffer pool
390+
poolTable.set(
391+
"test_pool",
392+
{
393+
{ "type", "ingress" },
394+
{ "mode", "dynamic" },
395+
{ "size", "4200000" },
396+
});
397+
398+
// Create test buffer profile
399+
profileTable.set("test_profile", { { "pool", "[BUFFER_POOL|test_pool]" },
400+
{ "xon", "14832" },
401+
{ "xoff", "14832" },
402+
{ "size", "35000" },
403+
{ "dynamic_th", "0" } });
404+
405+
// Apply profile on PGs 3-4 all ports
406+
for (const auto &it : ports)
407+
{
408+
std::ostringstream oss;
409+
oss << it.first << "|3-4";
410+
pgTable.set(oss.str(), { { "profile", "[BUFFER_PROFILE|test_profile]" } });
411+
}
412+
gBufferOrch->addExistingData(&pgTable);
413+
gBufferOrch->addExistingData(&poolTable);
414+
gBufferOrch->addExistingData(&profileTable);
415+
416+
// process pool, profile and PGs
417+
static_cast<Orch *>(gBufferOrch)->doTask();
418+
419+
auto pgConsumer = static_cast<Consumer*>(gBufferOrch->getExecutor(CFG_BUFFER_PG_TABLE_NAME));
420+
pgConsumer->dumpPendingTasks(ts);
421+
ASSERT_FALSE(ts.empty()); // PG is skipped
422+
ts.clear();
423+
424+
// release zero buffer drop handler
425+
dropHandler.reset();
426+
427+
// process PGs
428+
static_cast<Orch *>(gBufferOrch)->doTask();
429+
430+
pgConsumer = static_cast<Consumer*>(gBufferOrch->getExecutor(CFG_BUFFER_PG_TABLE_NAME));
431+
pgConsumer->dumpPendingTasks(ts);
432+
ASSERT_TRUE(ts.empty()); // PG should be proceesed now
433+
ts.clear();
434+
}
313435
}

tests/mock_tests/ut_saihelper.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ namespace ut_helper
7777
sai_api_query(SAI_API_ACL, (void **)&sai_acl_api);
7878
sai_api_query(SAI_API_HOSTIF, (void **)&sai_hostif_api);
7979
sai_api_query(SAI_API_BUFFER, (void **)&sai_buffer_api);
80+
sai_api_query(SAI_API_QUEUE, (void **)&sai_queue_api);
8081

8182
return SAI_STATUS_SUCCESS;
8283
}
@@ -99,6 +100,7 @@ namespace ut_helper
99100
sai_acl_api = nullptr;
100101
sai_hostif_api = nullptr;
101102
sai_buffer_api = nullptr;
103+
sai_queue_api = nullptr;
102104
}
103105

104106
map<string, vector<FieldValueTuple>> getInitialSaiPorts()

0 commit comments

Comments
 (0)