Skip to content

Commit ad65b0a

Browse files
authored
Fix issue: sometimes PFC WD unable to create zero buffer pool (#2164)
What I did Fix issue: sometimes PFC WD is unable to create zero buffer pool. On some platforms, an ingress/egress zero buffer profile will be applied on the PG and queue which are under PFC storm. The zero buffer profile is created based on zero buffer pool. However, sometimes it fails to create zero buffer pool due to too many buffer pools existing in the system. Sometimes, there is a zero buffer pool existing on the system for reclaiming buffer. In that case, we can leverage it to create zero buffer profile for PFC WD. Why I did it Fix the issue via sharing the zero buffer pool between PFC WD and buffer orchagent How I verified it Manually test Run PFC WD test and PFC WD warm reboot test Run unit test Details if related The detailed flow is like this: PFC Storm detected: If there is a zero pool in PFC WD's cache, just create the zero buffer profile based on it Otherwise, fetching the zero pool from buffer orchagent If got one, create the zero buffer profile based on it Otherwise, create a zero buffer pool notify the zero buffer pool about the buffer orch In both cases, PFC WD should notify buffer orch to increase the reference number of the zero buffer pool. Buffer orchagent: When creating the zero buffer pool, check whether there is one. if yes, skip the SAI API create_buffer_pool increase the reference number. Before removing the zero buffer pool, decrease and check the reference number. if it is zero (after decreased), skip SAI API destroy_buffer_pool. When PFC WD decrease reference number: remove the zero buffer pool if the reference number becomes zero Notes We do not leverage the object_reference_map infrastructure to track the dependency because: it assumes the dependency will eventually be removed if an object is removed. that's NOT true in this scenario because the PFC storm can last for a relatively long time and even cross warm reboot. the interfaces differ. Signed-off-by: Stephen Sun <[email protected]>
1 parent 608acc3 commit ad65b0a

File tree

6 files changed

+531
-52
lines changed

6 files changed

+531
-52
lines changed

orchagent/bufferorch.cpp

+153-15
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,11 @@ BufferOrch::BufferOrch(DBConnector *applDb, DBConnector *confDb, DBConnector *st
4848
m_flexCounterTable(new ProducerTable(m_flexCounterDb.get(), FLEX_COUNTER_TABLE)),
4949
m_flexCounterGroupTable(new ProducerTable(m_flexCounterDb.get(), FLEX_COUNTER_GROUP_TABLE)),
5050
m_countersDb(new DBConnector("COUNTERS_DB", 0)),
51-
m_stateBufferMaximumValueTable(stateDb, STATE_BUFFER_MAXIMUM_VALUE_TABLE)
51+
m_stateBufferMaximumValueTable(stateDb, STATE_BUFFER_MAXIMUM_VALUE_TABLE),
52+
m_ingressZeroBufferPool(SAI_NULL_OBJECT_ID),
53+
m_egressZeroBufferPool(SAI_NULL_OBJECT_ID),
54+
m_ingressZeroPoolRefCount(0),
55+
m_egressZeroPoolRefCount(0)
5256
{
5357
SWSS_LOG_ENTER();
5458
initTableHandlers();
@@ -310,6 +314,65 @@ const object_reference_map &BufferOrch::getBufferPoolNameOidMap(void)
310314
return *m_buffer_type_maps[APP_BUFFER_POOL_TABLE_NAME];
311315
}
312316

317+
void BufferOrch::lockZeroBufferPool(bool ingress)
318+
{
319+
if (ingress)
320+
m_ingressZeroPoolRefCount++;
321+
else
322+
m_egressZeroPoolRefCount++;
323+
}
324+
325+
void BufferOrch::unlockZeroBufferPool(bool ingress)
326+
{
327+
sai_object_id_t pool = SAI_NULL_OBJECT_ID;
328+
if (ingress)
329+
{
330+
if (--m_ingressZeroPoolRefCount <= 0)
331+
{
332+
pool = m_ingressZeroBufferPool;
333+
m_ingressZeroBufferPool = SAI_NULL_OBJECT_ID;
334+
}
335+
}
336+
else
337+
{
338+
if (--m_egressZeroPoolRefCount <= 0)
339+
{
340+
pool = m_egressZeroBufferPool;
341+
m_egressZeroBufferPool = SAI_NULL_OBJECT_ID;
342+
}
343+
}
344+
345+
if (pool != SAI_NULL_OBJECT_ID)
346+
{
347+
auto sai_status = sai_buffer_api->remove_buffer_pool(pool);
348+
if (SAI_STATUS_SUCCESS != sai_status)
349+
{
350+
SWSS_LOG_ERROR("Failed to remove buffer pool, rv:%d", sai_status);
351+
task_process_status handle_status = handleSaiRemoveStatus(SAI_API_BUFFER, sai_status);
352+
if (handle_status != task_process_status::task_success)
353+
{
354+
return;
355+
}
356+
}
357+
else
358+
{
359+
SWSS_LOG_NOTICE("Zero buffer pool has been successfully removed");
360+
}
361+
}
362+
}
363+
364+
void BufferOrch::setZeroBufferPool(bool ingress, sai_object_id_t pool)
365+
{
366+
if (ingress)
367+
{
368+
m_ingressZeroBufferPool = pool;
369+
}
370+
else
371+
{
372+
m_egressZeroBufferPool = pool;
373+
}
374+
}
375+
313376
task_process_status BufferOrch::processBufferPool(KeyOpFieldsValuesTuple &tuple)
314377
{
315378
SWSS_LOG_ENTER();
@@ -318,6 +381,8 @@ task_process_status BufferOrch::processBufferPool(KeyOpFieldsValuesTuple &tuple)
318381
string map_type_name = APP_BUFFER_POOL_TABLE_NAME;
319382
string object_name = kfvKey(tuple);
320383
string op = kfvOp(tuple);
384+
sai_buffer_pool_type_t pool_direction = SAI_BUFFER_POOL_TYPE_INGRESS;
385+
bool creating_zero_pool = false;
321386

322387
SWSS_LOG_DEBUG("object name:%s", object_name.c_str());
323388
if (m_buffer_type_maps[map_type_name]->find(object_name) != m_buffer_type_maps[map_type_name]->end())
@@ -326,6 +391,17 @@ task_process_status BufferOrch::processBufferPool(KeyOpFieldsValuesTuple &tuple)
326391
SWSS_LOG_DEBUG("found existing object:%s of type:%s", object_name.c_str(), map_type_name.c_str());
327392
}
328393
SWSS_LOG_DEBUG("processing command:%s", op.c_str());
394+
if (object_name == "ingress_zero_pool")
395+
{
396+
creating_zero_pool = true;
397+
pool_direction = SAI_BUFFER_POOL_TYPE_INGRESS;
398+
}
399+
else if (object_name == "egress_zero_pool")
400+
{
401+
creating_zero_pool = true;
402+
pool_direction = SAI_BUFFER_POOL_TYPE_EGRESS;
403+
}
404+
329405
if (op == SET_COMMAND)
330406
{
331407
vector<sai_attribute_t> attribs;
@@ -372,6 +448,11 @@ task_process_status BufferOrch::processBufferPool(KeyOpFieldsValuesTuple &tuple)
372448
return task_process_status::task_invalid_entry;
373449
}
374450
attr.id = SAI_BUFFER_POOL_ATTR_TYPE;
451+
if (creating_zero_pool && pool_direction != static_cast<sai_buffer_pool_type_t>(attr.value.u32))
452+
{
453+
SWSS_LOG_ERROR("Wrong pool direction for pool %s", object_name.c_str());
454+
return task_process_status::task_invalid_entry;
455+
}
375456
attribs.push_back(attr);
376457
}
377458
else if (field == buffer_pool_mode_field_name)
@@ -437,18 +518,53 @@ task_process_status BufferOrch::processBufferPool(KeyOpFieldsValuesTuple &tuple)
437518
}
438519
else
439520
{
440-
sai_status = sai_buffer_api->create_buffer_pool(&sai_object, gSwitchId, (uint32_t)attribs.size(), attribs.data());
441-
if (SAI_STATUS_SUCCESS != sai_status)
521+
if (creating_zero_pool)
442522
{
443-
SWSS_LOG_ERROR("Failed to create buffer pool %s with type %s, rv:%d", object_name.c_str(), map_type_name.c_str(), sai_status);
444-
task_process_status handle_status = handleSaiCreateStatus(SAI_API_BUFFER, sai_status);
445-
if (handle_status != task_process_status::task_success)
523+
if (pool_direction == SAI_BUFFER_POOL_TYPE_INGRESS)
446524
{
447-
return handle_status;
525+
sai_object = m_ingressZeroBufferPool;
526+
}
527+
else if (pool_direction == SAI_BUFFER_POOL_TYPE_EGRESS)
528+
{
529+
sai_object = m_egressZeroBufferPool;
530+
}
531+
}
532+
533+
if (SAI_NULL_OBJECT_ID == sai_object)
534+
{
535+
sai_status = sai_buffer_api->create_buffer_pool(&sai_object, gSwitchId, (uint32_t)attribs.size(), attribs.data());
536+
if (SAI_STATUS_SUCCESS != sai_status)
537+
{
538+
SWSS_LOG_ERROR("Failed to create buffer pool %s with type %s, rv:%d", object_name.c_str(), map_type_name.c_str(), sai_status);
539+
task_process_status handle_status = handleSaiCreateStatus(SAI_API_BUFFER, sai_status);
540+
if (handle_status != task_process_status::task_success)
541+
{
542+
return handle_status;
543+
}
544+
}
545+
546+
SWSS_LOG_NOTICE("Created buffer pool %s with type %s", object_name.c_str(), map_type_name.c_str());
547+
}
548+
else
549+
{
550+
SWSS_LOG_NOTICE("No need to create buffer pool %s since it has been created", object_name.c_str());
551+
}
552+
553+
if (creating_zero_pool)
554+
{
555+
if (pool_direction == SAI_BUFFER_POOL_TYPE_INGRESS)
556+
{
557+
m_ingressZeroPoolRefCount++;
558+
m_ingressZeroBufferPool = sai_object;
559+
}
560+
else if (pool_direction == SAI_BUFFER_POOL_TYPE_EGRESS)
561+
{
562+
m_egressZeroPoolRefCount++;
563+
m_egressZeroBufferPool = sai_object;
448564
}
449565
}
566+
450567
(*(m_buffer_type_maps[map_type_name]))[object_name].m_saiObjectId = sai_object;
451-
SWSS_LOG_NOTICE("Created buffer pool %s with type %s", object_name.c_str(), map_type_name.c_str());
452568
// Here we take the PFC watchdog approach to update the COUNTERS_DB metadata (e.g., PFC_WD_DETECTION_TIME per queue)
453569
// at initialization (creation and registration phase)
454570
// Specifically, we push the buffer pool name to oid mapping upon the creation of the oid
@@ -470,18 +586,40 @@ task_process_status BufferOrch::processBufferPool(KeyOpFieldsValuesTuple &tuple)
470586
if (SAI_NULL_OBJECT_ID != sai_object)
471587
{
472588
clearBufferPoolWatermarkCounterIdList(sai_object);
473-
sai_status = sai_buffer_api->remove_buffer_pool(sai_object);
474-
if (SAI_STATUS_SUCCESS != sai_status)
589+
bool remove = true;
590+
if (sai_object == m_ingressZeroBufferPool)
475591
{
476-
SWSS_LOG_ERROR("Failed to remove buffer pool %s with type %s, rv:%d", object_name.c_str(), map_type_name.c_str(), sai_status);
477-
task_process_status handle_status = handleSaiRemoveStatus(SAI_API_BUFFER, sai_status);
478-
if (handle_status != task_process_status::task_success)
592+
if (--m_ingressZeroPoolRefCount > 0)
593+
remove = false;
594+
else
595+
m_ingressZeroBufferPool = SAI_NULL_OBJECT_ID;
596+
}
597+
else if (sai_object == m_egressZeroBufferPool)
598+
{
599+
if (--m_egressZeroPoolRefCount > 0)
600+
remove = false;
601+
else
602+
m_egressZeroBufferPool = SAI_NULL_OBJECT_ID;
603+
}
604+
if (remove)
605+
{
606+
sai_status = sai_buffer_api->remove_buffer_pool(sai_object);
607+
if (SAI_STATUS_SUCCESS != sai_status)
479608
{
480-
return handle_status;
609+
SWSS_LOG_ERROR("Failed to remove buffer pool %s with type %s, rv:%d", object_name.c_str(), map_type_name.c_str(), sai_status);
610+
task_process_status handle_status = handleSaiRemoveStatus(SAI_API_BUFFER, sai_status);
611+
if (handle_status != task_process_status::task_success)
612+
{
613+
return handle_status;
614+
}
481615
}
616+
SWSS_LOG_NOTICE("Removed buffer pool %s with type %s", object_name.c_str(), map_type_name.c_str());
617+
}
618+
else
619+
{
620+
SWSS_LOG_NOTICE("Will not remove buffer pool %s since it is still referenced", object_name.c_str());
482621
}
483622
}
484-
SWSS_LOG_NOTICE("Removed buffer pool %s with type %s", object_name.c_str(), map_type_name.c_str());
485623
auto it_to_delete = (m_buffer_type_maps[map_type_name])->find(object_name);
486624
(m_buffer_type_maps[map_type_name])->erase(it_to_delete);
487625
m_countersDb->hdel(COUNTERS_BUFFER_POOL_NAME_MAP, object_name);

orchagent/bufferorch.h

+13
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ class BufferOrch : public Orch
3737
static type_map m_buffer_type_maps;
3838
void generateBufferPoolWatermarkCounterIdList(void);
3939
const object_reference_map &getBufferPoolNameOidMap(void);
40+
sai_object_id_t getZeroBufferPool(bool ingress)
41+
{
42+
return ingress ? m_ingressZeroBufferPool : m_egressZeroBufferPool;
43+
}
44+
45+
void lockZeroBufferPool(bool ingress);
46+
void unlockZeroBufferPool(bool ingress);
47+
void setZeroBufferPool(bool direction, sai_object_id_t pool);
4048

4149
private:
4250
typedef task_process_status (BufferOrch::*buffer_table_handler)(KeyOpFieldsValuesTuple &tuple);
@@ -71,6 +79,11 @@ class BufferOrch : public Orch
7179
unique_ptr<DBConnector> m_countersDb;
7280

7381
bool m_isBufferPoolWatermarkCounterIdListGenerated = false;
82+
83+
sai_object_id_t m_ingressZeroBufferPool;
84+
sai_object_id_t m_egressZeroBufferPool;
85+
int m_ingressZeroPoolRefCount;
86+
int m_egressZeroPoolRefCount;
7487
};
7588
#endif /* SWSS_BUFFORCH_H */
7689

orchagent/pfcactionhandler.cpp

+60-26
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "logger.h"
44
#include "sai_serialize.h"
55
#include "portsorch.h"
6+
#include "bufferorch.h"
67
#include <vector>
78
#include <inttypes.h>
89

@@ -26,6 +27,7 @@
2627
extern sai_object_id_t gSwitchId;
2728
extern PortsOrch *gPortsOrch;
2829
extern AclOrch * gAclOrch;
30+
extern BufferOrch *gBufferOrch;
2931
extern sai_port_api_t *sai_port_api;
3032
extern sai_queue_api_t *sai_queue_api;
3133
extern sai_buffer_api_t *sai_buffer_api;
@@ -715,6 +717,25 @@ PfcWdZeroBufferHandler::ZeroBufferProfile &PfcWdZeroBufferHandler::ZeroBufferPro
715717
return instance;
716718
}
717719

720+
sai_object_id_t& PfcWdZeroBufferHandler::ZeroBufferProfile::getPool(bool ingress)
721+
{
722+
// If there is a cached zero buffer pool, just use it
723+
// else fetch zero buffer pool from buffer orch
724+
// If there is one, use it and increase the reference number.
725+
// otherwise, just return NULL OID
726+
// PfcWdZeroBufferHandler will create it later and notify buffer orch later
727+
auto &poolId = ingress ? m_zeroIngressBufferPool : m_zeroEgressBufferPool;
728+
if (poolId == SAI_NULL_OBJECT_ID)
729+
{
730+
poolId = gBufferOrch->getZeroBufferPool(ingress);
731+
if (poolId != SAI_NULL_OBJECT_ID)
732+
{
733+
gBufferOrch->lockZeroBufferPool(ingress);
734+
}
735+
}
736+
return poolId;
737+
}
738+
718739
sai_object_id_t PfcWdZeroBufferHandler::ZeroBufferProfile::getZeroBufferProfile(bool ingress)
719740
{
720741
SWSS_LOG_ENTER();
@@ -733,29 +754,39 @@ void PfcWdZeroBufferHandler::ZeroBufferProfile::createZeroBufferProfile(bool ing
733754

734755
sai_attribute_t attr;
735756
vector<sai_attribute_t> attribs;
757+
sai_status_t status;
736758

737-
// Create zero pool
738-
attr.id = SAI_BUFFER_POOL_ATTR_SIZE;
739-
attr.value.u64 = 0;
740-
attribs.push_back(attr);
759+
auto &poolId = getPool(ingress);
741760

742-
attr.id = SAI_BUFFER_POOL_ATTR_TYPE;
743-
attr.value.u32 = ingress ? SAI_BUFFER_POOL_TYPE_INGRESS : SAI_BUFFER_POOL_TYPE_EGRESS;
744-
attribs.push_back(attr);
761+
if (SAI_NULL_OBJECT_ID == poolId)
762+
{
763+
// Create zero pool
764+
attr.id = SAI_BUFFER_POOL_ATTR_SIZE;
765+
attr.value.u64 = 0;
766+
attribs.push_back(attr);
745767

746-
attr.id = SAI_BUFFER_POOL_ATTR_THRESHOLD_MODE;
747-
attr.value.u32 = SAI_BUFFER_POOL_THRESHOLD_MODE_DYNAMIC;
748-
attribs.push_back(attr);
768+
attr.id = SAI_BUFFER_POOL_ATTR_TYPE;
769+
attr.value.u32 = ingress ? SAI_BUFFER_POOL_TYPE_INGRESS : SAI_BUFFER_POOL_TYPE_EGRESS;
770+
attribs.push_back(attr);
771+
772+
attr.id = SAI_BUFFER_POOL_ATTR_THRESHOLD_MODE;
773+
attr.value.u32 = SAI_BUFFER_POOL_THRESHOLD_MODE_STATIC;
774+
attribs.push_back(attr);
749775

750-
sai_status_t status = sai_buffer_api->create_buffer_pool(
751-
&getPool(ingress),
776+
status = sai_buffer_api->create_buffer_pool(
777+
&poolId,
752778
gSwitchId,
753779
static_cast<uint32_t>(attribs.size()),
754780
attribs.data());
755-
if (status != SAI_STATUS_SUCCESS)
756-
{
757-
SWSS_LOG_ERROR("Failed to create dynamic zero buffer pool for PFC WD: %d", status);
758-
return;
781+
if (status != SAI_STATUS_SUCCESS)
782+
{
783+
SWSS_LOG_ERROR("Failed to create dynamic zero buffer pool for PFC WD: %d", status);
784+
return;
785+
}
786+
787+
// Pass the ownership to BufferOrch
788+
gBufferOrch->setZeroBufferPool(ingress, poolId);
789+
gBufferOrch->lockZeroBufferPool(ingress);
759790
}
760791

761792
// Create zero profile
@@ -766,15 +797,15 @@ void PfcWdZeroBufferHandler::ZeroBufferProfile::createZeroBufferProfile(bool ing
766797
attribs.push_back(attr);
767798

768799
attr.id = SAI_BUFFER_PROFILE_ATTR_THRESHOLD_MODE;
769-
attr.value.u32 = SAI_BUFFER_PROFILE_THRESHOLD_MODE_DYNAMIC;
800+
attr.value.u32 = SAI_BUFFER_PROFILE_THRESHOLD_MODE_STATIC;
770801
attribs.push_back(attr);
771802

772803
attr.id = SAI_BUFFER_PROFILE_ATTR_BUFFER_SIZE;
773804
attr.value.u64 = 0;
774805
attribs.push_back(attr);
775806

776-
attr.id = SAI_BUFFER_PROFILE_ATTR_SHARED_DYNAMIC_TH;
777-
attr.value.s8 = -8; // ALPHA_0
807+
attr.id = SAI_BUFFER_PROFILE_ATTR_SHARED_STATIC_TH;
808+
attr.value.s8 = 0;
778809
attribs.push_back(attr);
779810

780811
status = sai_buffer_api->create_buffer_profile(
@@ -793,16 +824,19 @@ void PfcWdZeroBufferHandler::ZeroBufferProfile::destroyZeroBufferProfile(bool in
793824
{
794825
SWSS_LOG_ENTER();
795826

796-
sai_status_t status = sai_buffer_api->remove_buffer_profile(getProfile(ingress));
797-
if (status != SAI_STATUS_SUCCESS)
827+
if (getProfile(ingress) != SAI_NULL_OBJECT_ID)
798828
{
799-
SWSS_LOG_ERROR("Failed to remove static zero buffer profile for PFC WD: %d", status);
800-
return;
829+
sai_status_t status = sai_buffer_api->remove_buffer_profile(getProfile(ingress));
830+
if (status != SAI_STATUS_SUCCESS)
831+
{
832+
SWSS_LOG_ERROR("Failed to remove static zero buffer profile for PFC WD: %d", status);
833+
return;
834+
}
801835
}
802836

803-
status = sai_buffer_api->remove_buffer_pool(getPool(ingress));
804-
if (status != SAI_STATUS_SUCCESS)
837+
auto &pool = ingress ? m_zeroIngressBufferPool : m_zeroEgressBufferPool;
838+
if (pool != SAI_NULL_OBJECT_ID)
805839
{
806-
SWSS_LOG_ERROR("Failed to remove static zero buffer pool for PFC WD: %d", status);
840+
gBufferOrch->unlockZeroBufferPool(ingress);
807841
}
808842
}

0 commit comments

Comments
 (0)