diff --git a/orchagent/countercheckorch.cpp b/orchagent/countercheckorch.cpp index aa46758626be..c2d3239bd973 100644 --- a/orchagent/countercheckorch.cpp +++ b/orchagent/countercheckorch.cpp @@ -52,13 +52,11 @@ void CounterCheckOrch::mcCounterCheck() { SWSS_LOG_ENTER(); - sai_attribute_t attr; - attr.id = SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL; - for (auto& i : m_mcCountersMap) { auto oid = i.first; auto mcCounters = i.second; + uint8_t pfcMask = 0; Port port; if (!gPortsOrch->getPort(oid, port)) @@ -69,15 +67,12 @@ void CounterCheckOrch::mcCounterCheck() auto newMcCounters = getQueueMcCounters(port); - sai_status_t status = sai_port_api->get_port_attribute(port.m_port_id, 1, &attr); - if (status != SAI_STATUS_SUCCESS) + if (!gPortsOrch->getPortPfc(port.m_port_id, &pfcMask)) { - SWSS_LOG_ERROR("Failed to get PFC mask on port %s: %d", port.m_alias.c_str(), status); + SWSS_LOG_ERROR("Failed to get PFC mask on port %s", port.m_alias.c_str()); continue; } - uint8_t pfcMask = attr.value.u8; - for (size_t prio = 0; prio != mcCounters.size(); prio++) { bool isLossy = ((1 << prio) & pfcMask) == 0; @@ -104,14 +99,12 @@ void CounterCheckOrch::pfcFrameCounterCheck() { SWSS_LOG_ENTER(); - sai_attribute_t attr; - attr.id = SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL; - for (auto& i : m_pfcFrameCountersMap) { auto oid = i.first; auto counters = i.second; auto newCounters = getPfcFrameCounters(oid); + uint8_t pfcMask = 0; Port port; if (!gPortsOrch->getPort(oid, port)) @@ -120,15 +113,12 @@ void CounterCheckOrch::pfcFrameCounterCheck() continue; } - sai_status_t status = sai_port_api->get_port_attribute(port.m_port_id, 1, &attr); - if (status != SAI_STATUS_SUCCESS) + if (!gPortsOrch->getPortPfc(port.m_port_id, &pfcMask)) { - SWSS_LOG_ERROR("Failed to get PFC mask on port %s: %d", port.m_alias.c_str(), status); + SWSS_LOG_ERROR("Failed to get PFC mask on port %s", port.m_alias.c_str()); continue; } - uint8_t pfcMask = attr.value.u8; - for (size_t prio = 0; prio != counters.size(); prio++) { bool isLossy = ((1 << prio) & pfcMask) == 0; diff --git a/orchagent/pfcactionhandler.cpp b/orchagent/pfcactionhandler.cpp index 538b4d2e06c4..8c29fcb36974 100644 --- a/orchagent/pfcactionhandler.cpp +++ b/orchagent/pfcactionhandler.cpp @@ -321,23 +321,18 @@ PfcWdLossyHandler::PfcWdLossyHandler(sai_object_id_t port, sai_object_id_t queue { SWSS_LOG_ENTER(); - sai_attribute_t attr; - attr.id = SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL; + uint8_t pfcMask = 0; - sai_status_t status = sai_port_api->get_port_attribute(port, 1, &attr); - if (status != SAI_STATUS_SUCCESS) + if (!gPortsOrch->getPortPfc(port, &pfcMask)) { - SWSS_LOG_ERROR("Failed to get PFC mask on port 0x%lx: %d", port, status); + SWSS_LOG_ERROR("Failed to get PFC mask on port 0x%lx", port); } - uint8_t pfcMask = attr.value.u8; - attr.id = SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL; - attr.value.u8 = static_cast(pfcMask & ~(1 << queueId)); + pfcMask = static_cast(pfcMask & (1 << queueId)); - status = sai_port_api->set_port_attribute(port, &attr); - if (status != SAI_STATUS_SUCCESS) + if (!gPortsOrch->setPortPfc(port, pfcMask)) { - SWSS_LOG_ERROR("Failed to get PFC mask on port 0x%lx: %d", port, status); + SWSS_LOG_ERROR("Failed to set PFC mask on port 0x%lx", port); } } @@ -345,25 +340,18 @@ PfcWdLossyHandler::~PfcWdLossyHandler(void) { SWSS_LOG_ENTER(); - sai_attribute_t attr; - attr.id = SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL; + uint8_t pfcMask = 0; - sai_status_t status = sai_port_api->get_port_attribute(getPort(), 1, &attr); - if (status != SAI_STATUS_SUCCESS) + if (!gPortsOrch->getPortPfc(getPort(), &pfcMask)) { - SWSS_LOG_ERROR("Failed to get PFC mask on port 0x%lx: %d", getPort(), status); - return; + SWSS_LOG_ERROR("Failed to get PFC mask on port 0x%lx", getPort()); } - uint8_t pfcMask = attr.value.u8; - attr.id = SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL; - attr.value.u8 = static_cast(pfcMask | (1 << getQueueId())); + pfcMask = static_cast(pfcMask | (1 << getQueueId())); - status = sai_port_api->set_port_attribute(getPort(), &attr); - if (status != SAI_STATUS_SUCCESS) + if (!gPortsOrch->setPortPfc(getPort(), pfcMask)) { - SWSS_LOG_ERROR("Failed to set PFC mask on port 0x%lx: %d", getPort(), status); - return; + SWSS_LOG_ERROR("Failed to set PFC mask on port 0x%lx", getPort()); } } diff --git a/orchagent/pfcwdorch.cpp b/orchagent/pfcwdorch.cpp index de892e30d4f2..58bb35125de2 100644 --- a/orchagent/pfcwdorch.cpp +++ b/orchagent/pfcwdorch.cpp @@ -351,12 +351,11 @@ void PfcWdSwOrch::enableBigRedSwitchMode() m_bigRedSwitchFlag = true; // Write to database that each queue enables BIG_RED_SWITCH auto allPorts = gPortsOrch->getAllPorts(); - sai_attribute_t attr; - attr.id = SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL; for (auto &it: allPorts) { Port port = it.second; + uint8_t pfcMask = 0; if (port.m_type != Port::PHY) { @@ -364,15 +363,12 @@ void PfcWdSwOrch::enableBigRedSwitchMode() continue; } - // use portorch api to get lossless tc in future. - sai_status_t status = sai_port_api->get_port_attribute(port.m_port_id, 1, &attr); - if (status != SAI_STATUS_SUCCESS) + if (!gPortsOrch->getPortPfc(port.m_port_id, &pfcMask)) { - SWSS_LOG_ERROR("Failed to get PFC mask on port %s: %d", port.m_alias.c_str(), status); + SWSS_LOG_ERROR("Failed to get PFC mask on port %s", port.m_alias.c_str()); return; } - uint8_t pfcMask = attr.value.u8; for (uint8_t i = 0; i < PFC_WD_TC_MAX; i++) { sai_object_id_t queueId = port.m_queue_ids[i]; @@ -403,21 +399,20 @@ void PfcWdSwOrch::enableBigRedSwitchMode() for (auto & it: allPorts) { Port port = it.second; + uint8_t pfcMask = 0; + if (port.m_type != Port::PHY) { SWSS_LOG_INFO("Skip non-phy port %s", port.m_alias.c_str()); continue; } - // use portorch api to get lossless tc in future after asym PFC is available. - sai_status_t status = sai_port_api->get_port_attribute(port.m_port_id, 1, &attr); - if (status != SAI_STATUS_SUCCESS) + if (!gPortsOrch->getPortPfc(port.m_port_id, &pfcMask)) { - SWSS_LOG_ERROR("Failed to get PFC mask on port %s: %d", port.m_alias.c_str(), status); + SWSS_LOG_ERROR("Failed to get PFC mask on port %s", port.m_alias.c_str()); return; } - uint8_t pfcMask = attr.value.u8; for (uint8_t i = 0; i < PFC_WD_TC_MAX; i++) { if ((pfcMask & (1 << i)) == 0) @@ -456,18 +451,15 @@ void PfcWdSwOrch::registerInWdDb(const Port& port, { SWSS_LOG_ENTER(); - sai_attribute_t attr; - attr.id = SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL; + uint8_t pfcMask = 0; - sai_status_t status = sai_port_api->get_port_attribute(port.m_port_id, 1, &attr); - if (status != SAI_STATUS_SUCCESS) + if (!gPortsOrch->getPortPfc(port.m_port_id, &pfcMask)) { - SWSS_LOG_ERROR("Failed to get PFC mask on port %s: %d", port.m_alias.c_str(), status); + SWSS_LOG_ERROR("Failed to get PFC mask on port %s", port.m_alias.c_str()); return; } set losslessTc; - uint8_t pfcMask = attr.value.u8; for (uint8_t i = 0; i < PFC_WD_TC_MAX; i++) { if ((pfcMask & (1 << i)) == 0) diff --git a/orchagent/port.h b/orchagent/port.h index 4f955dab51e8..f2bedad5bc36 100644 --- a/orchagent/port.h +++ b/orchagent/port.h @@ -83,6 +83,8 @@ class Port std::set m_members; std::vector m_queue_ids; std::vector m_priority_group_ids; + sai_port_priority_flow_control_mode_t m_pfc_asym = SAI_PORT_PRIORITY_FLOW_CONTROL_MODE_COMBINED; + uint8_t m_pfc_bitmask = 0; }; } diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 866dcb34e55d..9ca03b04b7c1 100644 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -48,6 +48,12 @@ static map fec_mode_map = { "fc", SAI_PORT_FEC_MODE_FC } }; +static map pfc_asym_map = +{ + { "on", SAI_PORT_PRIORITY_FLOW_CONTROL_MODE_SEPARATE }, + { "off", SAI_PORT_PRIORITY_FLOW_CONTROL_MODE_COMBINED } +}; + const vector portStatIds = { SAI_PORT_STAT_IF_IN_OCTETS, @@ -515,6 +521,125 @@ bool PortsOrch::setPortFec(sai_object_id_t id, sai_port_fec_mode_t mode) return true; } +bool PortsOrch::getPortPfc(sai_object_id_t portId, uint8_t *pfc_bitmask) +{ + SWSS_LOG_ENTER(); + + Port p; + + if (!getPort(portId, p)) + { + SWSS_LOG_ERROR("Failed to get port object for port id 0x%lx", portId); + return false; + } + + *pfc_bitmask = p.m_pfc_bitmask; + + return true; +} + +bool PortsOrch::setPortPfc(sai_object_id_t portId, uint8_t pfc_bitmask) +{ + SWSS_LOG_ENTER(); + + sai_attribute_t attr; + Port p; + + if (!getPort(portId, p)) + { + SWSS_LOG_ERROR("Failed to get port object for port id 0x%lx", portId); + return false; + } + + if (p.m_pfc_asym == SAI_PORT_PRIORITY_FLOW_CONTROL_MODE_COMBINED) + { + attr.id = SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL; + } + else if (p.m_pfc_asym == SAI_PORT_PRIORITY_FLOW_CONTROL_MODE_SEPARATE) + { + attr.id = SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL_TX; + } + else + { + SWSS_LOG_ERROR("Incorrect asymmetric PFC mode: %u", p.m_pfc_asym); + return false; + } + + attr.value.u8 = pfc_bitmask; + + sai_status_t status = sai_port_api->set_port_attribute(portId, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set PFC 0x%x to port id 0x%lx (rc:%d)", attr.value.u8, portId, status); + return false; + } + + if (p.m_pfc_bitmask != pfc_bitmask) + { + p.m_pfc_bitmask = pfc_bitmask; + m_portList[p.m_alias] = p; + } + + return true; +} + +bool PortsOrch::setPortPfcAsym(Port &port, string pfc_asym) +{ + SWSS_LOG_ENTER(); + + sai_attribute_t attr; + uint8_t pfc = 0; + + if (!getPortPfc(port.m_port_id, &pfc)) + { + return false; + } + + try + { + port.m_pfc_asym = pfc_asym_map.at(pfc_asym); + } + catch (...) + { + SWSS_LOG_ERROR("Incorrect asymmetric PFC mode: %s", pfc_asym.c_str()); + return false; + } + + m_portList[port.m_alias] = port; + + attr.id = SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL_MODE; + attr.value.s32 = (int32_t) port.m_pfc_asym; + + sai_status_t status = sai_port_api->set_port_attribute(port.m_port_id, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set PFC mode %d to port id 0x%lx (rc:%d)", port.m_pfc_asym, port.m_port_id, status); + return false; + } + + if (!setPortPfc(port.m_port_id, pfc)) + { + return false; + } + + if (port.m_pfc_asym == SAI_PORT_PRIORITY_FLOW_CONTROL_MODE_SEPARATE) + { + attr.id = SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL_RX; + attr.value.u8 = static_cast(0xff); + + sai_status_t status = sai_port_api->set_port_attribute(port.m_port_id, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set RX PFC 0x%x to port id 0x%lx (rc:%d)", attr.value.u8, port.m_port_id, status); + return false; + } + } + + SWSS_LOG_INFO("Set asymmetric PFC %s to port id 0x%lx", pfc_asym.c_str(), port.m_port_id); + + return true; +} + bool PortsOrch::bindAclTable(sai_object_id_t id, sai_object_id_t table_oid, sai_object_id_t &group_member_oid, acl_stage_type_t acl_stage) { SWSS_LOG_ENTER(); @@ -1282,6 +1407,7 @@ void PortsOrch::doPortTask(Consumer &consumer) set lane_set; string admin_status; string fec_mode; + string pfc_asym; uint32_t mtu = 0; uint32_t speed = 0; int an = -1; @@ -1326,6 +1452,10 @@ void PortsOrch::doPortTask(Consumer &consumer) fec_mode = fvValue(i); } + /* Set port asymmetric PFC */ + if (fvField(i) == "pfc_asym") + pfc_asym = fvValue(i); + /* Set autoneg and ignore the port speed setting */ if (fvField(i) == "autoneg") { @@ -1594,6 +1724,20 @@ void PortsOrch::doPortTask(Consumer &consumer) SWSS_LOG_ERROR("Unknown fec mode %s", fec_mode.c_str()); } } + + if (pfc_asym != "") + { + if (setPortPfcAsym(p, pfc_asym)) + { + SWSS_LOG_NOTICE("Set port %s asymmetric PFC to %s", alias.c_str(), pfc_asym.c_str()); + } + else + { + SWSS_LOG_ERROR("Failed to set port %s asymmetric PFC to %s", alias.c_str(), pfc_asym.c_str()); + it++; + continue; + } + } } } else diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index fc1d2ae52b64..e39a9c9f780b 100644 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -71,7 +71,11 @@ class PortsOrch : public Orch, public Subject void updateDbPortOperStatus(sai_object_id_t id, sai_port_oper_status_t status); bool bindAclTable(sai_object_id_t id, sai_object_id_t table_oid, sai_object_id_t &group_member_oid, acl_stage_type_t acl_stage = ACL_STAGE_INGRESS); + bool getPortPfc(sai_object_id_t portId, uint8_t *pfc_bitmask); + bool setPortPfc(sai_object_id_t portId, uint8_t pfc_bitmask); + void generateQueueMap(); + private: unique_ptr m_counterTable; unique_ptr
m_portTable; @@ -146,6 +150,7 @@ class PortsOrch : public Orch, public Subject bool setPortPvid (Port &port, sai_uint32_t pvid); bool getPortPvid(Port &port, sai_uint32_t &pvid); bool setPortFec(sai_object_id_t id, sai_port_fec_mode_t mode); + bool setPortPfcAsym(Port &port, string pfc_asym); bool setBridgePortAdminStatus(sai_object_id_t id, bool up); diff --git a/orchagent/qosorch.cpp b/orchagent/qosorch.cpp index e4c5c96d16cf..66fb70d13eb4 100644 --- a/orchagent/qosorch.cpp +++ b/orchagent/qosorch.cpp @@ -1348,16 +1348,11 @@ task_process_status QosOrch::handlePortQosMapTable(Consumer& consumer) if (pfc_enable) { - sai_attribute_t attr; - attr.id = SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL; - attr.value.u8 = pfc_enable; - - sai_status_t status = sai_port_api->set_port_attribute(port.m_port_id, &attr); - if (status != SAI_STATUS_SUCCESS) + if (!gPortsOrch->setPortPfc(port.m_port_id, pfc_enable)) { - SWSS_LOG_ERROR("Failed to apply PFC bits 0x%x to port %s, rv:%d", - pfc_enable, port_name.c_str(), status); + SWSS_LOG_ERROR("Failed to apply PFC bits 0x%x to port %s", pfc_enable, port_name.c_str()); } + SWSS_LOG_INFO("Applied PFC bits 0x%x to port %s", pfc_enable, port_name.c_str()); } } diff --git a/tests/test_pfc.py b/tests/test_pfc.py new file mode 100644 index 000000000000..19cfc50e269d --- /dev/null +++ b/tests/test_pfc.py @@ -0,0 +1,101 @@ +import time +from swsscommon import swsscommon + + +def getBitMaskStr(bits): + + mask = 0 + + for b in bits: + mask = mask | 1 << b + + return str(mask) + + +def setPortPfc(dvs, port_name, pfc_queues): + + cfg_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + port_qos_tbl = swsscommon.Table(cfg_db, 'PORT_QOS_MAP') + fvs = swsscommon.FieldValuePairs([('pfc_enable', ",".join(str(q) for q in pfc_queues))]) + port_qos_tbl.set(port_name, fvs) + + time.sleep(1) + + +def setPortPfcAsym(dvs, port_name, pfc_asym): + + cfg_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, dvs.redis_sock, 0) + + port_tbl = swsscommon.Table(cfg_db, 'PORT') + fvs = swsscommon.FieldValuePairs([('pfc_asym', pfc_asym)]) + port_tbl.set(port_name, fvs) + + time.sleep(1) + + +def getPortOid(dvs, port_name): + + cnt_db = swsscommon.DBConnector(swsscommon.COUNTERS_DB, dvs.redis_sock, 0) + port_map_tbl = swsscommon.Table(cnt_db, 'COUNTERS_PORT_NAME_MAP') + + for k in port_map_tbl.get('')[1]: + if k[0] == port_name: + return k[1] + + return '' + + +def getPortAttr(dvs, port_oid, port_attr): + + asic_db = swsscommon.DBConnector(swsscommon.ASIC_DB, dvs.redis_sock, 0) + port_tbl = swsscommon.Table(asic_db, 'ASIC_STATE:SAI_OBJECT_TYPE_PORT:{0}'.format(port_oid)) + + for k in port_tbl.get('')[1]: + if k[0] == port_attr: + return k[1] + + return '' + + +def test_PfcAsymmetric(dvs): + + port_name = 'Ethernet0' + pfc_queues = [ 3, 4 ] + + # Configure default PFC + setPortPfc(dvs, port_name, pfc_queues) + + # Get SAI object ID for the interface + port_oid = getPortOid(dvs, port_name) + + # Verify default PFC is set to configured value + pfc = getPortAttr(dvs, port_oid, 'SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL') + assert pfc == getBitMaskStr(pfc_queues) + + # Enable asymmetric PFC + setPortPfcAsym(dvs, port_name, 'on') + + # Verify PFC mode is set to 'SEPARATE' + pfc_mode = getPortAttr(dvs, port_oid, 'SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL_MODE') + assert pfc_mode == 'SAI_PORT_PRIORITY_FLOW_CONTROL_MODE_SEPARATE' + + # Verify TX PFC is set to previous PFC value + pfc_tx = getPortAttr(dvs, port_oid, 'SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL_TX') + assert pfc_tx == pfc + + # Verify RX PFC is set to 0xFF (255) + pfc_rx = getPortAttr(dvs, port_oid, 'SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL_RX') + assert pfc_rx == '255' + + # Disable asymmetric PFC + setPortPfcAsym(dvs, port_name, 'off') + + # Verify PFC mode is set to 'COMBINED' + pfc_mode = getPortAttr(dvs, port_oid, 'SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL_MODE') + assert pfc_mode == 'SAI_PORT_PRIORITY_FLOW_CONTROL_MODE_COMBINED' + + # Verify PFC is set to TX PFC value + pfc = getPortAttr(dvs, port_oid, 'SAI_PORT_ATTR_PRIORITY_FLOW_CONTROL') + assert pfc == pfc_tx +