Skip to content

Commit 5329c39

Browse files
authored
Update orchagent to support new field pfcwd_sw_enable (sonic-net#2171)
Signed-off-by: bingwang bingwang@microsoft.com What I did Currently, the entry pfc_enable in table PORT_QOS_MAP is used to specify pfc and pfc_watchdog are enabled on which queues. To avoid PFC deadlock in Dual-ToR scrnario, we are going to introduce two extra lossless queues to carry bounced back traffic.HLD. The extra lossless queues require another two pfc_watchdogs, and the new watchdogs will be implemented by hardware due to limited resources. The hardware pfc watchdog is not covered in this PR. To specify on which queue to enable pfc watchdog, we need to define new table pfcwd_sw_enable. Table Description pfc_enable Specify on which queues to enable PFC pfcwd_sw_enable Specify on which queues to enable software PFC watchdog This PR is to update orchagent to support new field pfcwd_sw_enable . As two extra lossless PGs (2 and 6) are to be added, buffermgrd is also updated in this PR to generate lossless profile for the new PGs. Why I did it Update orchagent to support new field pfcwd_sw_enable . How I verified it Verified by UT. sudo pytest3 --dvsname=vs tests/test_pfcwd.py::TestPfcwdFunc -v --pdb ========================================================================================= test session starts ========================================================================================= platform linux -- Python 3.6.9, pytest-7.0.1, pluggy-1.0.0 -- /usr/bin/python3 cachedir: .pytest_cache rootdir: /home/bingwang/work/sonic/sonic-buildimage-master/src/sonic-swss plugins: flaky-3.7.0 collected 2 items tests/test_pfcwd.py::TestPfcwdFunc::test_pfcwd_software_single_queue PASSED [ 50%] tests/test_pfcwd.py::TestPfcwdFunc::test_pfcwd_software_multi_queue PASSED sudo pytest test_buffer_traditional.py ===================================================================================================================== test session starts ====================================================================================================================== platform linux -- Python 3.7.5, pytest-7.1.1, pluggy-1.0.0 rootdir: /home/bingwang/work/sonic/sonic-buildimage-master/src/sonic-swss/tests collected 1 item test_buffer_traditional.py .
1 parent 88fad97 commit 5329c39

11 files changed

Lines changed: 308 additions & 78 deletions

File tree

cfgmgr/buffermgr.cpp

Lines changed: 130 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,11 @@ Create/update two tables: profile (in m_cfgBufferProfileTable) and port buffer (
133133
}
134134
}
135135
*/
136-
task_process_status BufferMgr::doSpeedUpdateTask(string port, bool admin_up)
136+
task_process_status BufferMgr::doSpeedUpdateTask(string port)
137137
{
138-
vector<FieldValueTuple> fvVectorPg, fvVectorProfile;
139138
string cable;
140139
string speed;
140+
string pfc_enable;
141141

142142
if (m_cableLenLookup.count(port) == 0)
143143
{
@@ -152,47 +152,70 @@ task_process_status BufferMgr::doSpeedUpdateTask(string port, bool admin_up)
152152
return task_process_status::task_success;
153153
}
154154

155-
speed = m_speedLookup[port];
155+
if (m_portStatusLookup.count(port) == 0)
156+
{
157+
// admin_statue is not available yet. This can happen when notification of `PORT_QOS_MAP` table
158+
// comes first.
159+
SWSS_LOG_INFO("pfc_enable status is not available for port %s", port.c_str());
160+
return task_process_status::task_need_retry;
161+
}
162+
163+
if (m_portPfcStatus.count(port) == 0)
164+
{
165+
// PORT_QOS_MAP is not ready yet. The notification is cleared, and buffer pg
166+
// will be handled when `pfc_enable` in `PORT_QOS_MAP` table is available
167+
SWSS_LOG_INFO("pfc_enable status is not available for port %s", port.c_str());
168+
return task_process_status::task_success;
169+
}
170+
pfc_enable = m_portPfcStatus[port];
156171

157-
string buffer_pg_key = port + m_cfgBufferPgTable.getTableNameSeparator() + LOSSLESS_PGS;
172+
speed = m_speedLookup[port];
158173
// key format is pg_lossless_<speed>_<cable>_profile
159174
string buffer_profile_key = "pg_lossless_" + speed + "_" + cable + "_profile";
160175
string profile_ref = buffer_profile_key;
176+
177+
vector<string> lossless_pgs = tokenize(pfc_enable, ',');
161178

162-
m_cfgBufferPgTable.get(buffer_pg_key, fvVectorPg);
163-
164-
if (!admin_up && m_platform == "mellanox")
179+
if (m_portStatusLookup[port] == "down" && m_platform == "mellanox")
165180
{
166-
// Remove the entry in BUFFER_PG table if any
167-
if (!fvVectorPg.empty())
181+
for (auto lossless_pg : lossless_pgs)
168182
{
169-
for (auto &prop : fvVectorPg)
183+
// Remove the entry in BUFFER_PG table if any
184+
vector<FieldValueTuple> fvVectorPg;
185+
string buffer_pg_key = port + m_cfgBufferPgTable.getTableNameSeparator() + lossless_pg;
186+
187+
m_cfgBufferPgTable.get(buffer_pg_key, fvVectorPg);
188+
if (!fvVectorPg.empty())
170189
{
171-
if (fvField(prop) == "profile")
190+
for (auto &prop : fvVectorPg)
172191
{
173-
if (fvValue(prop) == profile_ref)
192+
if (fvField(prop) == "profile")
174193
{
175-
SWSS_LOG_NOTICE("Removing PG %s from port %s which is administrative down", buffer_pg_key.c_str(), port.c_str());
176-
m_cfgBufferPgTable.del(buffer_pg_key);
177-
}
178-
else
179-
{
180-
SWSS_LOG_NOTICE("Not default profile %s is configured on PG %s, won't reclaim buffer", fvValue(prop).c_str(), buffer_pg_key.c_str());
194+
if (fvValue(prop) == profile_ref)
195+
{
196+
SWSS_LOG_NOTICE("Removing PG %s from port %s which is administrative down", buffer_pg_key.c_str(), port.c_str());
197+
m_cfgBufferPgTable.del(buffer_pg_key);
198+
}
199+
else
200+
{
201+
SWSS_LOG_NOTICE("Not default profile %s is configured on PG %s, won't reclaim buffer", fvValue(prop).c_str(), buffer_pg_key.c_str());
202+
}
181203
}
182204
}
183205
}
184206
}
185207

186208
return task_process_status::task_success;
187209
}
188-
210+
189211
if (m_pgProfileLookup.count(speed) == 0 || m_pgProfileLookup[speed].count(cable) == 0)
190212
{
191-
SWSS_LOG_ERROR("Unable to create/update PG profile for port %s. No PG profile configured for speed %s and cable length %s",
192-
port.c_str(), speed.c_str(), cable.c_str());
193-
return task_process_status::task_invalid_entry;
213+
SWSS_LOG_ERROR("Unable to create/update PG profile for port %s. No PG profile configured for speed %s and cable length %s",
214+
port.c_str(), speed.c_str(), cable.c_str());
215+
return task_process_status::task_invalid_entry;
194216
}
195217

218+
vector<FieldValueTuple> fvVectorProfile;
196219
// check if profile already exists - if yes - skip creation
197220
m_cfgBufferProfileTable.get(buffer_profile_key, fvVectorProfile);
198221
// Create record in BUFFER_PROFILE table
@@ -213,9 +236,10 @@ task_process_status BufferMgr::doSpeedUpdateTask(string port, bool admin_up)
213236

214237
fvVectorProfile.push_back(make_pair("pool", INGRESS_LOSSLESS_PG_POOL_NAME));
215238
fvVectorProfile.push_back(make_pair("xon", m_pgProfileLookup[speed][cable].xon));
216-
if (m_pgProfileLookup[speed][cable].xon_offset.length() > 0) {
239+
if (m_pgProfileLookup[speed][cable].xon_offset.length() > 0)
240+
{
217241
fvVectorProfile.push_back(make_pair("xon_offset",
218-
m_pgProfileLookup[speed][cable].xon_offset));
242+
m_pgProfileLookup[speed][cable].xon_offset));
219243
}
220244
fvVectorProfile.push_back(make_pair("xoff", m_pgProfileLookup[speed][cable].xoff));
221245
fvVectorProfile.push_back(make_pair("size", m_pgProfileLookup[speed][cable].size));
@@ -227,20 +251,28 @@ task_process_status BufferMgr::doSpeedUpdateTask(string port, bool admin_up)
227251
SWSS_LOG_NOTICE("Reusing existing profile '%s'", buffer_profile_key.c_str());
228252
}
229253

230-
/* Check if PG Mapping is already then log message and return. */
231-
for (auto& prop : fvVectorPg)
254+
for (auto lossless_pg : lossless_pgs)
232255
{
233-
if ((fvField(prop) == "profile") && (profile_ref == fvValue(prop)))
256+
vector<FieldValueTuple> fvVectorPg;
257+
string buffer_pg_key = port + m_cfgBufferPgTable.getTableNameSeparator() + lossless_pg;
258+
259+
m_cfgBufferPgTable.get(buffer_pg_key, fvVectorPg);
260+
261+
/* Check if PG Mapping is already then log message and return. */
262+
for (auto& prop : fvVectorPg)
234263
{
235-
SWSS_LOG_NOTICE("PG to Buffer Profile Mapping %s already present", buffer_pg_key.c_str());
236-
return task_process_status::task_success;
264+
if ((fvField(prop) == "profile") && (profile_ref == fvValue(prop)))
265+
{
266+
SWSS_LOG_NOTICE("PG to Buffer Profile Mapping %s already present", buffer_pg_key.c_str());
267+
continue;
268+
}
237269
}
238-
}
239270

240-
fvVectorPg.clear();
271+
fvVectorPg.clear();
241272

242-
fvVectorPg.push_back(make_pair("profile", profile_ref));
243-
m_cfgBufferPgTable.set(buffer_pg_key, fvVectorPg);
273+
fvVectorPg.push_back(make_pair("profile", profile_ref));
274+
m_cfgBufferPgTable.set(buffer_pg_key, fvVectorPg);
275+
}
244276
return task_process_status::task_success;
245277
}
246278

@@ -346,6 +378,47 @@ void BufferMgr::doBufferMetaTask(Consumer &consumer)
346378
}
347379
}
348380

381+
/*
382+
Parse PORT_QOS_MAP to retrieve on which queue PFC is enable, and
383+
cached in a map
384+
*/
385+
void BufferMgr::doPortQosTableTask(Consumer &consumer)
386+
{
387+
SWSS_LOG_ENTER();
388+
389+
auto it = consumer.m_toSync.begin();
390+
while (it != consumer.m_toSync.end())
391+
{
392+
KeyOpFieldsValuesTuple tuple = it->second;
393+
string port_name = kfvKey(tuple);
394+
string op = kfvOp(tuple);
395+
if (op == SET_COMMAND)
396+
{
397+
bool update_pfc_enable = false;
398+
for (auto itp : kfvFieldsValues(tuple))
399+
{
400+
if (fvField(itp) == "pfc_enable")
401+
{
402+
if (m_portPfcStatus.count(port_name) == 0 || m_portPfcStatus[port_name] != fvValue(itp))
403+
{
404+
m_portPfcStatus[port_name] = fvValue(itp);
405+
update_pfc_enable = true;
406+
}
407+
SWSS_LOG_INFO("Got pfc enable status for port %s status %s", port_name.c_str(), fvValue(itp).c_str());
408+
break;
409+
}
410+
}
411+
if (update_pfc_enable)
412+
{
413+
// The return status is ignored
414+
doSpeedUpdateTask(port_name);
415+
}
416+
}
417+
it = consumer.m_toSync.erase(it);
418+
}
419+
420+
}
421+
349422
void BufferMgr::doTask(Consumer &consumer)
350423
{
351424
SWSS_LOG_ENTER();
@@ -399,6 +472,12 @@ void BufferMgr::doTask(Consumer &consumer)
399472
return;
400473
}
401474

475+
if (table_name == CFG_PORT_QOS_MAP_TABLE_NAME)
476+
{
477+
doPortQosTableTask(consumer);
478+
return;
479+
}
480+
402481
auto it = consumer.m_toSync.begin();
403482
while (it != consumer.m_toSync.end())
404483
{
@@ -422,7 +501,6 @@ void BufferMgr::doTask(Consumer &consumer)
422501
}
423502
else if (m_pgfile_processed && table_name == CFG_PORT_TABLE_NAME)
424503
{
425-
bool admin_up = false;
426504
for (auto i : kfvFieldsValues(t))
427505
{
428506
if (fvField(i) == "speed")
@@ -431,39 +509,34 @@ void BufferMgr::doTask(Consumer &consumer)
431509
}
432510
if (fvField(i) == "admin_status")
433511
{
434-
admin_up = ("up" == fvValue(i));
512+
m_portStatusLookup[port] = fvValue(i);
435513
}
436514
}
437515

438516
if (m_speedLookup.count(port) != 0)
439517
{
440518
// create/update profile for port
441-
task_status = doSpeedUpdateTask(port, admin_up);
519+
task_status = doSpeedUpdateTask(port);
442520
}
521+
}
443522

444-
if (task_status != task_process_status::task_success)
445-
{
523+
switch (task_status)
524+
{
525+
case task_process_status::task_failed:
526+
SWSS_LOG_ERROR("Failed to process table update");
527+
return;
528+
case task_process_status::task_need_retry:
529+
SWSS_LOG_INFO("Unable to process table update. Will retry...");
530+
++it;
531+
break;
532+
case task_process_status::task_invalid_entry:
533+
SWSS_LOG_ERROR("Failed to process invalid entry, drop it");
534+
it = consumer.m_toSync.erase(it);
535+
break;
536+
default:
537+
it = consumer.m_toSync.erase(it);
446538
break;
447-
}
448539
}
449540
}
450-
451-
switch (task_status)
452-
{
453-
case task_process_status::task_failed:
454-
SWSS_LOG_ERROR("Failed to process table update");
455-
return;
456-
case task_process_status::task_need_retry:
457-
SWSS_LOG_INFO("Unable to process table update. Will retry...");
458-
++it;
459-
break;
460-
case task_process_status::task_invalid_entry:
461-
SWSS_LOG_ERROR("Failed to process invalid entry, drop it");
462-
it = consumer.m_toSync.erase(it);
463-
break;
464-
default:
465-
it = consumer.m_toSync.erase(it);
466-
break;
467-
}
468541
}
469542
}

cfgmgr/buffermgr.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
namespace swss {
1212

1313
#define INGRESS_LOSSLESS_PG_POOL_NAME "ingress_lossless_pool"
14-
#define LOSSLESS_PGS "3-4"
1514

1615
#define BUFFERMGR_TIMER_PERIOD 10
1716

@@ -28,6 +27,8 @@ typedef std::map<std::string, speed_map_t> pg_profile_lookup_t;
2827

2928
typedef std::map<std::string, std::string> port_cable_length_t;
3029
typedef std::map<std::string, std::string> port_speed_t;
30+
typedef std::map<std::string, std::string> port_pfc_status_t;
31+
typedef std::map<std::string, std::string> port_admin_status_t;
3132

3233
class BufferMgr : public Orch
3334
{
@@ -56,17 +57,22 @@ class BufferMgr : public Orch
5657

5758
pg_profile_lookup_t m_pgProfileLookup;
5859
port_cable_length_t m_cableLenLookup;
60+
port_admin_status_t m_portStatusLookup;
5961
port_speed_t m_speedLookup;
6062
std::string getPgPoolMode();
6163
void readPgProfileLookupFile(std::string);
6264
task_process_status doCableTask(std::string port, std::string cable_length);
63-
task_process_status doSpeedUpdateTask(std::string port, bool admin_up);
65+
task_process_status doSpeedUpdateTask(std::string port);
6466
void doBufferTableTask(Consumer &consumer, ProducerStateTable &applTable);
6567

6668
void transformSeperator(std::string &name);
6769

6870
void doTask(Consumer &consumer);
6971
void doBufferMetaTask(Consumer &consumer);
72+
73+
port_pfc_status_t m_portPfcStatus;
74+
void doPortQosTableTask(Consumer &consumer);
75+
7076
};
7177

7278
}

cfgmgr/buffermgrd.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,8 @@ int main(int argc, char **argv)
215215
CFG_BUFFER_QUEUE_TABLE_NAME,
216216
CFG_BUFFER_PORT_INGRESS_PROFILE_LIST_NAME,
217217
CFG_BUFFER_PORT_EGRESS_PROFILE_LIST_NAME,
218-
CFG_DEVICE_METADATA_TABLE_NAME
218+
CFG_DEVICE_METADATA_TABLE_NAME,
219+
CFG_PORT_QOS_MAP_TABLE_NAME
219220
};
220221
cfgOrchList.emplace_back(new BufferMgr(&cfgDb, &applDb, pg_lookup_file, cfg_buffer_tables));
221222
}

orchagent/pfcwdorch.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -399,9 +399,9 @@ void PfcWdSwOrch<DropHandler, ForwardHandler>::enableBigRedSwitchMode()
399399
continue;
400400
}
401401

402-
if (!gPortsOrch->getPortPfc(port.m_port_id, &pfcMask))
402+
if (!gPortsOrch->getPortPfcWatchdogStatus(port.m_port_id, &pfcMask))
403403
{
404-
SWSS_LOG_ERROR("Failed to get PFC mask on port %s", port.m_alias.c_str());
404+
SWSS_LOG_ERROR("Failed to get PFC watchdog mask on port %s", port.m_alias.c_str());
405405
return;
406406
}
407407

@@ -443,9 +443,9 @@ void PfcWdSwOrch<DropHandler, ForwardHandler>::enableBigRedSwitchMode()
443443
continue;
444444
}
445445

446-
if (!gPortsOrch->getPortPfc(port.m_port_id, &pfcMask))
446+
if (!gPortsOrch->getPortPfcWatchdogStatus(port.m_port_id, &pfcMask))
447447
{
448-
SWSS_LOG_ERROR("Failed to get PFC mask on port %s", port.m_alias.c_str());
448+
SWSS_LOG_ERROR("Failed to get PFC watchdog mask on port %s", port.m_alias.c_str());
449449
return;
450450
}
451451

@@ -489,7 +489,7 @@ bool PfcWdSwOrch<DropHandler, ForwardHandler>::registerInWdDb(const Port& port,
489489

490490
uint8_t pfcMask = 0;
491491

492-
if (!gPortsOrch->getPortPfc(port.m_port_id, &pfcMask))
492+
if (!gPortsOrch->getPortPfcWatchdogStatus(port.m_port_id, &pfcMask))
493493
{
494494
SWSS_LOG_ERROR("Failed to get PFC mask on port %s", port.m_alias.c_str());
495495
return false;

orchagent/port.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@ class Port
139139
std::vector<sai_object_id_t> m_queue_ids;
140140
std::vector<sai_object_id_t> m_priority_group_ids;
141141
sai_port_priority_flow_control_mode_t m_pfc_asym = SAI_PORT_PRIORITY_FLOW_CONTROL_MODE_COMBINED;
142-
uint8_t m_pfc_bitmask = 0;
142+
uint8_t m_pfc_bitmask = 0; // PFC enable bit mask
143+
uint8_t m_pfcwd_sw_bitmask = 0; // PFC software watchdog enable
143144
uint16_t m_tpid = DEFAULT_TPID;
144145
uint32_t m_nat_zone_id = 0;
145146
uint32_t m_vnid = VNID_NONE;

0 commit comments

Comments
 (0)