diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 9e9b097fe4..76ad18da09 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -1150,10 +1150,10 @@ bool PortsOrch::setPortFec(Port &port, sai_port_fec_mode_t mode) if (searchRef != m_portSupportedFecModes.end()) { auto &supportedFecModes = searchRef->second; - if (!supportedFecModes.empty()) + if (!supportedFecModes.unknown) { bool found = false; - for (auto supportedFecMode : supportedFecModes) + for (auto supportedFecMode : supportedFecModes.fecModes) { if (mode == supportedFecMode) { @@ -1964,9 +1964,7 @@ void PortsOrch::getPortSupportedFecModes(const std::string& alias, sai_object_id { sai_attribute_t attr; sai_status_t status; - const auto size = fec_mode_reverse_map.size(); - - PortSupportedFecModes fecModes(size); + auto &fecModes = supported_fecmodes.fecModes; attr.id = SAI_PORT_ATTR_SUPPORTED_FEC_MODE; attr.value.s32list.count = static_cast(fecModes.size()); @@ -1976,7 +1974,7 @@ void PortsOrch::getPortSupportedFecModes(const std::string& alias, sai_object_id if (status == SAI_STATUS_SUCCESS) { fecModes.resize(attr.value.u32list.count); - supported_fecmodes.swap(fecModes); + supported_fecmodes.unknown = false; } else { @@ -1994,7 +1992,8 @@ void PortsOrch::getPortSupportedFecModes(const std::string& alias, sai_object_id alias.c_str(), port_id, status); } - supported_fecmodes.clear(); // return empty + fecModes.clear(); // return empty + supported_fecmodes.unknown = true; } } @@ -2006,14 +2005,15 @@ void PortsOrch::initPortSupportedFecModes(const std::string& alias, sai_object_i return; } PortSupportedFecModes supported_fec_modes; + supported_fec_modes.fecModes.resize(fec_mode_reverse_map.size()); getPortSupportedFecModes(alias, port_id, supported_fec_modes); m_portSupportedFecModes[port_id] = supported_fec_modes; vector v; std::string supported_fec_modes_str; - if (!supported_fec_modes.empty()) + if (!supported_fec_modes.fecModes.empty()) { bool first = true; - for(auto fec : supported_fec_modes) + for(auto fec : supported_fec_modes.fecModes) { if (first) first = false; diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index 0cacc4b92c..1870533869 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -28,7 +28,12 @@ #define PG_DROP_STAT_COUNTER_FLEX_COUNTER_GROUP "PG_DROP_STAT_COUNTER" typedef std::vector PortSupportedSpeeds; -typedef std::vector PortSupportedFecModes; +typedef struct +{ + std::vector fecModes; + // unknown is true in case fetching SAI_PORT_ATTR_SUPPORTED_FEC_MODE is not supported by vendor SAI + bool unknown; +} PortSupportedFecModes; static const map oper_status_strings = { diff --git a/tests/mock_tests/portsorch_ut.cpp b/tests/mock_tests/portsorch_ut.cpp index 664425fe43..2c9c3fe6a0 100644 --- a/tests/mock_tests/portsorch_ut.cpp +++ b/tests/mock_tests/portsorch_ut.cpp @@ -92,6 +92,7 @@ namespace portsorch_test } bool testing_fec; + bool not_support_fetching_fec; vector mock_port_fec_modes = {SAI_PORT_FEC_MODE_RS, SAI_PORT_FEC_MODE_FC}; sai_status_t _ut_stub_sai_get_port_attribute( @@ -102,13 +103,20 @@ namespace portsorch_test sai_status_t status; if (testing_fec && attr_count == 1 && attr_list[0].id == SAI_PORT_ATTR_SUPPORTED_FEC_MODE) { - uint32_t i; - for (i = 0; i < attr_list[0].value.s32list.count && i < mock_port_fec_modes.size(); i++) + if (not_support_fetching_fec) { - attr_list[0].value.s32list.list[i] = mock_port_fec_modes[i]; + status = SAI_STATUS_NOT_IMPLEMENTED; + } + else + { + uint32_t i; + for (i = 0; i < attr_list[0].value.s32list.count && i < mock_port_fec_modes.size(); i++) + { + attr_list[0].value.s32list.list[i] = mock_port_fec_modes[i]; + } + attr_list[0].value.s32list.count = i; + status = SAI_STATUS_SUCCESS; } - attr_list[0].value.s32list.count = i; - status = SAI_STATUS_SUCCESS; } else { @@ -117,6 +125,20 @@ namespace portsorch_test return status; } + uint32_t _sai_set_port_fec_count; + int32_t _sai_port_fec_mode; + sai_status_t _ut_stub_sai_set_port_attribute( + _In_ sai_object_id_t port_id, + _In_ const sai_attribute_t *attr) + { + if (testing_fec && attr[0].id == SAI_PORT_ATTR_FEC_MODE) + { + _sai_set_port_fec_count++; + _sai_port_fec_mode = attr[0].value.s32; + } + return pold_sai_port_api->set_port_attribute(port_id, attr); + } + void _hook_sai_buffer_and_queue_api() { ut_sai_buffer_api = *sai_buffer_api; @@ -134,6 +156,7 @@ namespace portsorch_test ut_sai_port_api = *sai_port_api; pold_sai_port_api = sai_port_api; ut_sai_port_api.get_port_attribute = _ut_stub_sai_get_port_attribute; + ut_sai_port_api.set_port_attribute = _ut_stub_sai_set_port_attribute; sai_port_api = &ut_sai_port_api; } @@ -313,6 +336,7 @@ namespace portsorch_test std::deque entries; testing_fec = true; + not_support_fetching_fec = false; // Get SAI default ports to populate DB auto ports = ut_helper::getInitialSaiPorts(); @@ -331,6 +355,8 @@ namespace portsorch_test // create ports static_cast(gPortsOrch)->doTask(); + uint32_t current_sai_api_call_count = _sai_set_port_fec_count; + entries.push_back({"Ethernet0", "SET", { {"fec", "rs"} @@ -340,6 +366,9 @@ namespace portsorch_test static_cast(gPortsOrch)->doTask(); entries.clear(); + ASSERT_EQ(_sai_set_port_fec_count, ++current_sai_api_call_count); + ASSERT_EQ(_sai_port_fec_mode, SAI_PORT_FEC_MODE_RS); + vector ts; gPortsOrch->dumpPendingTasks(ts); @@ -353,6 +382,9 @@ namespace portsorch_test consumer->addToSync(entries); static_cast(gPortsOrch)->doTask(); + ASSERT_EQ(_sai_set_port_fec_count, current_sai_api_call_count); + ASSERT_EQ(_sai_port_fec_mode, SAI_PORT_FEC_MODE_RS); + gPortsOrch->dumpPendingTasks(ts); ASSERT_EQ(ts.size(), 1); ASSERT_EQ(ts[0], "PORT_TABLE:Ethernet0|SET|fec:none"); @@ -361,6 +393,55 @@ namespace portsorch_test _unhook_sai_buffer_and_queue_api(); } + TEST_F(PortsOrchTest, PortNotSupportedFecModes) + { + _hook_sai_buffer_and_queue_api(); + Table portTable = Table(m_app_db.get(), APP_PORT_TABLE_NAME); + std::deque entries; + + testing_fec = true; + not_support_fetching_fec = true; + // Get SAI default ports to populate DB + auto ports = ut_helper::getInitialSaiPorts(); + + for (const auto &it : ports) + { + portTable.set(it.first, it.second); + } + + // Set PortConfigDone + portTable.set("PortConfigDone", { { "count", to_string(ports.size()) } }); + + // refill consumer + gPortsOrch->addExistingData(&portTable); + + // Apply configuration : + // create ports + static_cast(gPortsOrch)->doTask(); + + uint32_t current_sai_api_call_count = _sai_set_port_fec_count; + + entries.push_back({"Ethernet0", "SET", + { + {"fec", "rs"} + }}); + auto consumer = dynamic_cast(gPortsOrch->getExecutor(APP_PORT_TABLE_NAME)); + consumer->addToSync(entries); + static_cast(gPortsOrch)->doTask(); + entries.clear(); + + ASSERT_EQ(_sai_set_port_fec_count, ++current_sai_api_call_count); + ASSERT_EQ(_sai_port_fec_mode, SAI_PORT_FEC_MODE_RS); + + vector ts; + + gPortsOrch->dumpPendingTasks(ts); + ASSERT_TRUE(ts.empty()); + + testing_fec = false; + _unhook_sai_buffer_and_queue_api(); + } + TEST_F(PortsOrchTest, PortReadinessColdBoot) { Table portTable = Table(m_app_db.get(), APP_PORT_TABLE_NAME);