diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 4f01e291a6d2..fa4acacd9190 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -105,7 +105,7 @@ bool OrchDaemon::init() }; gCrmOrch = new CrmOrch(m_configDb, CFG_CRM_TABLE_NAME); - gPortsOrch = new PortsOrch(m_applDb, ports_tables, m_chassisAppDb); + gPortsOrch = new PortsOrch(m_applDb, m_stateDb, ports_tables, m_chassisAppDb); TableConnector stateDbFdb(m_stateDb, STATE_FDB_TABLE_NAME); gFdbOrch = new FdbOrch(m_applDb, app_fdb_tables, stateDbFdb, gPortsOrch); diff --git a/orchagent/port.h b/orchagent/port.h index f6abce87b01d..ca9977075f4e 100644 --- a/orchagent/port.h +++ b/orchagent/port.h @@ -100,7 +100,7 @@ class Port uint32_t m_mtu = DEFAULT_MTU; uint32_t m_speed = 0; // Mbps std::string m_learn_mode = "hardware"; - bool m_autoneg = false; + int m_autoneg = -1; // -1 means not set, 0 = disabled, 1 = enabled bool m_admin_state_up = false; bool m_init = false; bool m_l3_vni = false; @@ -133,6 +133,9 @@ class Port uint32_t m_fdb_count = 0; uint32_t m_up_member_count = 0; uint32_t m_maximum_headroom = 0; + std::vector m_adv_speeds; + sai_port_interface_type_t m_interface_type; + std::vector m_adv_interface_types; /* * Following two bit vectors are used to lock diff --git a/orchagent/portsorch.cpp b/orchagent/portsorch.cpp index 335d1d8d35a6..26e543341c5e 100755 --- a/orchagent/portsorch.cpp +++ b/orchagent/portsorch.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "net/if.h" @@ -28,6 +29,7 @@ #include "countercheckorch.h" #include "notifier.h" #include "fdborch.h" +#include "stringutility.h" #include "subscriberstatetable.h" extern sai_switch_api_t *sai_switch_api; @@ -102,6 +104,13 @@ static map loopback_mode_map = { "mac", SAI_PORT_INTERNAL_LOOPBACK_MODE_MAC } }; +static map autoneg_mode_map = +{ + { "on", 1 }, + { "off", 0 } +}; + +// Interface type map used for gearbox static map interface_type_map = { { "none", SAI_PORT_INTERFACE_TYPE_NONE }, @@ -115,6 +124,47 @@ static map interface_type_map = { "kr4", SAI_PORT_INTERFACE_TYPE_KR4 } }; +// Interface type map used for auto negotiation +static map interface_type_map_for_an = +{ + { "cr", SAI_PORT_INTERFACE_TYPE_CR }, + { "cr2", SAI_PORT_INTERFACE_TYPE_CR2 }, + { "cr4", SAI_PORT_INTERFACE_TYPE_CR4 }, + { "sr", SAI_PORT_INTERFACE_TYPE_SR }, + { "sr2", SAI_PORT_INTERFACE_TYPE_SR2 }, + { "sr4", SAI_PORT_INTERFACE_TYPE_SR4 }, + { "lr", SAI_PORT_INTERFACE_TYPE_LR }, + { "lr4", SAI_PORT_INTERFACE_TYPE_LR4 }, + { "kr", SAI_PORT_INTERFACE_TYPE_KR }, + { "kr4", SAI_PORT_INTERFACE_TYPE_KR4 }, + { "caui", SAI_PORT_INTERFACE_TYPE_CAUI }, + { "gmii", SAI_PORT_INTERFACE_TYPE_GMII }, + { "sfi", SAI_PORT_INTERFACE_TYPE_SFI }, + { "xlaui", SAI_PORT_INTERFACE_TYPE_XLAUI }, + { "kr2", SAI_PORT_INTERFACE_TYPE_KR2 }, + { "caui4", SAI_PORT_INTERFACE_TYPE_CAUI4 }, + { "xaui", SAI_PORT_INTERFACE_TYPE_XAUI }, + { "xfi", SAI_PORT_INTERFACE_TYPE_XFI }, + { "xgmii", SAI_PORT_INTERFACE_TYPE_XGMII } +}; + +static const std::string& getValidInterfaceTypes() +{ + static std::string validInterfaceTypes; + if (validInterfaceTypes.empty()) + { + std::ostringstream oss; + for (auto &iter : interface_type_map_for_an) + { + oss << iter.first << " "; + } + validInterfaceTypes = oss.str(); + boost::to_upper(validInterfaceTypes); + } + + return validInterfaceTypes; +} + const vector port_stat_ids = { SAI_PORT_STAT_IF_IN_OCTETS, @@ -231,8 +281,9 @@ static char* hostif_vlan_tag[] = { * bridge. By design, SONiC switch starts with all bridge ports removed from * default VLAN and all ports removed from .1Q bridge. */ -PortsOrch::PortsOrch(DBConnector *db, vector &tableNames, DBConnector *chassisAppDb) : +PortsOrch::PortsOrch(DBConnector *db, DBConnector *stateDb, vector &tableNames, DBConnector *chassisAppDb) : Orch(db, tableNames), + m_portStateTable(stateDb, STATE_PORT_TABLE_NAME), port_stat_manager(PORT_STAT_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, PORT_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, true), port_buffer_drop_stat_manager(PORT_BUFFER_DROP_STAT_FLEX_COUNTER_GROUP, StatsMode::READ, PORT_BUFFER_DROP_STAT_POLLING_INTERVAL_MS, true), queue_stat_manager(QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, QUEUE_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, true) @@ -1591,77 +1642,88 @@ bool PortsOrch::isSpeedSupported(const std::string& alias, sai_object_id_t port_ // This method will return false iff we get a list of supported speeds and the requested speed // is not supported // Otherwise the method will return true (even if we received errors) + initPortSupportedSpeeds(alias, port_id); + + const auto &supp_speeds = m_portSupportedSpeeds[port_id]; + if (supp_speeds.empty()) + { + // we don't have the list for this port, so return true to change speed anyway + return true; + } + return std::find(supp_speeds.begin(), supp_speeds.end(), speed) != supp_speeds.end(); +} + +void PortsOrch::getPortSupportedSpeeds(const std::string& alias, sai_object_id_t port_id, PortSupportedSpeeds &supported_speeds) +{ sai_attribute_t attr; sai_status_t status; + const auto size_guess = 25; // Guess the size which could be enough - // "Lazy" query of supported speeds for given port - // Once received the list will be stored in m_portSupportedSpeeds - if (!m_portSupportedSpeeds.count(port_id)) - { - const auto size_guess = 25; // Guess the size which could be enough + PortSupportedSpeeds speeds(size_guess); - std::vector speeds(size_guess); + // two attempts to get our value, first with the guess, other with the returned value + for (int attempt = 0; attempt < 2; ++attempt) + { + attr.id = SAI_PORT_ATTR_SUPPORTED_SPEED; + attr.value.u32list.count = static_cast(speeds.size()); + attr.value.u32list.list = speeds.data(); - for (int attempt = 0; attempt < 2; ++attempt) // two attempts to get our value - { // first with the guess, - // other with the returned value - attr.id = SAI_PORT_ATTR_SUPPORTED_SPEED; - attr.value.u32list.count = static_cast(speeds.size()); - attr.value.u32list.list = speeds.data(); + status = sai_port_api->get_port_attribute(port_id, 1, &attr); + if (status != SAI_STATUS_BUFFER_OVERFLOW) + { + break; + } - status = sai_port_api->get_port_attribute(port_id, 1, &attr); - if (status != SAI_STATUS_BUFFER_OVERFLOW) - { - break; - } + // if our guess was wrong, retry with the correct value + speeds.resize(attr.value.u32list.count); + } - speeds.resize(attr.value.u32list.count); // if our guess was wrong - // retry with the correct value + if (status == SAI_STATUS_SUCCESS) + { + speeds.resize(attr.value.u32list.count); + supported_speeds.swap(speeds); + } + else + { + if (status == SAI_STATUS_BUFFER_OVERFLOW) + { + // something went wrong in SAI implementation + SWSS_LOG_ERROR("Failed to get supported speed list for port %s id=%" PRIx64 ". Not enough container size", + alias.c_str(), port_id); } - - if (status == SAI_STATUS_SUCCESS) + else if (SAI_STATUS_IS_ATTR_NOT_SUPPORTED(status) || + SAI_STATUS_IS_ATTR_NOT_IMPLEMENTED(status) || + status == SAI_STATUS_NOT_IMPLEMENTED) { - speeds.resize(attr.value.u32list.count); - m_portSupportedSpeeds[port_id] = speeds; + // unable to validate speed if attribute is not supported on platform + // assuming input value is correct + SWSS_LOG_WARN("Unable to validate speed for port %s id=%" PRIx64 ". Not supported by platform", + alias.c_str(), port_id); } else { - if (status == SAI_STATUS_BUFFER_OVERFLOW) - { - // something went wrong in SAI implementation - SWSS_LOG_ERROR("Failed to get supported speed list for port %s id=%" PRIx64 ". Not enough container size", - alias.c_str(), port_id); - } - else if (SAI_STATUS_IS_ATTR_NOT_SUPPORTED(status) || - SAI_STATUS_IS_ATTR_NOT_IMPLEMENTED(status) || - status == SAI_STATUS_NOT_IMPLEMENTED) - { - // unable to validate speed if attribute is not supported on platform - // assuming input value is correct - SWSS_LOG_WARN("Unable to validate speed for port %s id=%" PRIx64 ". Not supported by platform", - alias.c_str(), port_id); - } - else - { - SWSS_LOG_ERROR("Failed to get a list of supported speeds for port %s id=%" PRIx64 ". Error=%d", - alias.c_str(), port_id, status); - } - m_portSupportedSpeeds[port_id] = {}; // use an empty list, - // we don't want to get the port speed for this port again - return true; // we can't check if the speed is valid, so return true to change the speed + SWSS_LOG_ERROR("Failed to get a list of supported speeds for port %s id=%" PRIx64 ". Error=%d", + alias.c_str(), port_id, status); } + supported_speeds.clear(); // return empty } +} - const PortSupportedSpeeds &supp_speeds = m_portSupportedSpeeds[port_id]; - if (supp_speeds.size() == 0) +void PortsOrch::initPortSupportedSpeeds(const std::string& alias, sai_object_id_t port_id) +{ + if (!m_portSupportedSpeeds.count(port_id)) { - // we don't have the list for this port, so return true to change speed anyway - return true; + return; } - - return std::find(supp_speeds.begin(), supp_speeds.end(), speed) != supp_speeds.end(); + PortSupportedSpeeds supported_speeds; + getPortSupportedSpeeds(alias, port_id, supported_speeds); + m_portSupportedSpeeds[port_id] = supported_speeds; + vector v; + std::string supported_speeds_str = swss::join(',', supported_speeds.begin(), supported_speeds.end()); + v.emplace_back(std::make_pair("supported_speeds", supported_speeds_str)); + m_portStateTable.set(alias, v); } /* @@ -1821,17 +1883,44 @@ bool PortsOrch::getPortSpeed(sai_object_id_t id, sai_uint32_t &speed) return status == SAI_STATUS_SUCCESS; } -bool PortsOrch::setPortAdvSpeed(sai_object_id_t port_id, sai_uint32_t speed) +bool PortsOrch::setPortAdvSpeeds(sai_object_id_t port_id, std::vector& speed_list) { SWSS_LOG_ENTER(); sai_attribute_t attr; sai_status_t status; - vector speeds; - speeds.push_back(speed); attr.id = SAI_PORT_ATTR_ADVERTISED_SPEED; - attr.value.u32list.list = speeds.data(); - attr.value.u32list.count = static_cast(speeds.size()); + attr.value.u32list.list = speed_list.data(); + attr.value.u32list.count = static_cast(speed_list.size()); + + status = sai_port_api->set_port_attribute(port_id, &attr); + + return status == SAI_STATUS_SUCCESS; +} + +bool PortsOrch::setPortInterfaceType(sai_object_id_t port_id, sai_port_interface_type_t interface_type) +{ + SWSS_LOG_ENTER(); + sai_attribute_t attr; + sai_status_t status; + + attr.id = SAI_PORT_ATTR_INTERFACE_TYPE; + attr.value.u32 = static_cast(interface_type); + + status = sai_port_api->set_port_attribute(port_id, &attr); + + return status == SAI_STATUS_SUCCESS; +} + +bool PortsOrch::setPortAdvInterfaceTypes(sai_object_id_t port_id, std::vector &interface_types) +{ + SWSS_LOG_ENTER(); + sai_attribute_t attr; + sai_status_t status; + + attr.id = SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE; + attr.value.u32list.list = interface_types.data(); + attr.value.u32list.count = static_cast(interface_types.size()); status = sai_port_api->set_port_attribute(port_id, &attr); if (status != SAI_STATUS_SUCCESS) @@ -2074,6 +2163,7 @@ sai_status_t PortsOrch::removePort(sai_object_id_t port_id) } m_portCount--; + m_portSupportedSpeeds.erase(port_id); SWSS_LOG_NOTICE("Remove port %" PRIx64, port_id); return status; @@ -2351,8 +2441,15 @@ void PortsOrch::doPortTask(Consumer &consumer) uint32_t mtu = 0; uint32_t speed = 0; string learn_mode; + string an_str; int an = -1; int index = -1; + string adv_speeds_str; + string interface_type_str; + string adv_interface_types_str; + vector adv_speeds; + sai_port_interface_type_t interface_type; + vector adv_interface_types; for (auto i : kfvFieldsValues(t)) { @@ -2407,10 +2504,28 @@ void PortsOrch::doPortTask(Consumer &consumer) /* Set autoneg and ignore the port speed setting */ else if (fvField(i) == "autoneg") { - an = (fvValue(i) == "on"); + an_str = fvValue(i); + } + + /* Set advertised speeds */ + if (fvField(i) == "adv_speeds") + { + adv_speeds_str = fvValue(i); + } + + /* Set interface type */ + if (fvField(i) == "interface_type") + { + interface_type_str = fvValue(i); + } + + /* Set advertised interface type */ + if (fvField(i) == "adv_interface_types") + { + adv_interface_types_str = fvValue(i); } /* Set port serdes Pre-emphasis */ - else if (fvField(i) == "preemphasis") + if (fvField(i) == "preemphasis") { getPortSerdesVal(fvValue(i), attr_val); serdes_attr.insert(serdes_attr_pair(SAI_PORT_SERDES_ATTR_PREEMPHASIS, attr_val)); @@ -2527,6 +2642,7 @@ void PortsOrch::doPortTask(Consumer &consumer) throw runtime_error("PortsOrch initialization failure."); } + initPortSupportedSpeeds(get<0>(it->second), m_portListLaneMap[it->first]); it++; } @@ -2565,115 +2681,213 @@ void PortsOrch::doPortTask(Consumer &consumer) } else { - if (an != -1 && (!p.m_an_cfg || an != p.m_autoneg)) + + if (!an_str.empty()) { - if (setPortAutoNeg(p.m_port_id, an)) + if (autoneg_mode_map.find(an_str) == autoneg_mode_map.end()) { - SWSS_LOG_NOTICE("Set port %s AutoNeg to %u", alias.c_str(), an); - p.m_autoneg = an; - p.m_an_cfg = true; - m_portList[alias] = p; + SWSS_LOG_ERROR("Failed to parse autoneg value: %s", an_str.c_str()); + // Invalid auto negotiation mode configured, don't retry + it = consumer.m_toSync.erase(it); + continue; + } + + an = autoneg_mode_map[an_str]; + if (an != p.m_autoneg) + { + if (p.m_admin_state_up) + { + /* Bring port down before applying speed */ + if (!setPortAdminStatus(p, false)) + { + SWSS_LOG_ERROR("Failed to set port %s admin status DOWN to set port autoneg mode", alias.c_str()); + it++; + continue; + } + + p.m_admin_state_up = false; + m_portList[alias] = p; + } - // Once AN is changed - // - no speed specified: need to reapply the port speed or port adv speed accordingly - // - speed specified: need to apply the port speed or port adv speed by the specified one - // Note: one special case is - // - speed specified as existing m_speed: need to apply even they are the same - auto old_speed = p.m_speed; - p.m_speed = 0; - auto new_speed = speed ? speed : old_speed; - if (new_speed) + if (setPortAutoNeg(p.m_port_id, an)) { - // Modify the task in place - kfvFieldsValues(t).emplace_back("speed", to_string(new_speed)); - // Fallthrough to process `speed' - speed = new_speed; + SWSS_LOG_NOTICE("Set port %s AutoNeg from %d to %d", alias.c_str(), p.m_autoneg, an); + p.m_autoneg = an; + m_portList[alias] = p; + } + else + { + SWSS_LOG_ERROR("Failed to set port %s AN from %d to %d", alias.c_str(), p.m_autoneg, an); + it++; + continue; } - } - else - { - SWSS_LOG_ERROR("Failed to set port %s AN to %u", alias.c_str(), an); - it++; - continue; } } - /* - * When AN is enabled, set the port adv speed, otherwise change the port speed. - * - * 1. Get supported speed list and validate if the target speed is within the list - * 2. Get the current port speed and check if it is the same as the target speed - * 3. Set port admin status to DOWN before changing the speed - * 4. Set port speed - */ - - SWSS_LOG_DEBUG("Set port %s speed to %u -> %u", alias.c_str(), p.m_speed, speed); if (speed != 0) { if (speed != p.m_speed) { - m_portList[alias] = p; + if (!isSpeedSupported(alias, p.m_port_id, speed)) + { + SWSS_LOG_ERROR("Unsupported port speed %u", speed); + // Speed not supported, dont retry + it = consumer.m_toSync.erase(it); + continue; + } - if (p.m_autoneg) + // for backward compatible, if p.m_autoneg != 1, toggle admin status + if (p.m_admin_state_up && p.m_autoneg != 1) { - if (setPortAdvSpeed(p.m_port_id, speed)) - { - SWSS_LOG_NOTICE("Set port %s advertised speed to %u", alias.c_str(), speed); - } - else + /* Bring port down before applying speed */ + if (!setPortAdminStatus(p, false)) { - SWSS_LOG_ERROR("Failed to set port %s advertised speed to %u", alias.c_str(), speed); + SWSS_LOG_ERROR("Failed to set port %s admin status DOWN to set speed", alias.c_str()); it++; continue; } + + p.m_admin_state_up = false; + m_portList[alias] = p; } - else + + if (!setPortSpeed(p, speed)) { - if (!isSpeedSupported(alias, p.m_port_id, speed)) + SWSS_LOG_ERROR("Failed to set port %s speed from %u to %u", alias.c_str(), p.m_speed, speed); + it++; + continue; + } + + SWSS_LOG_NOTICE("Set port %s speed from %u to %u", alias.c_str(), p.m_speed, speed); + p.m_speed = speed; + m_portList[alias] = p; + } + else + { + /* Always update Gearbox speed on Gearbox ports */ + setGearboxPortsAttr(p, SAI_PORT_ATTR_SPEED, &speed); + } + } + + if (!adv_speeds_str.empty()) + { + boost::to_lower(adv_speeds_str); + if (!getPortAdvSpeedsVal(adv_speeds_str, adv_speeds)) + { + // Invalid advertised speeds configured, dont retry + it = consumer.m_toSync.erase(it); + continue; + } + + if (adv_speeds != p.m_adv_speeds) + { + if (p.m_admin_state_up && p.m_autoneg == 1) + { + /* Bring port down before applying speed */ + if (!setPortAdminStatus(p, false)) { + SWSS_LOG_ERROR("Failed to set port %s admin status DOWN to set interface type", alias.c_str()); it++; continue; } - if (p.m_admin_state_up) - { - /* Bring port down before applying speed */ - if (!setPortAdminStatus(p, false)) - { - SWSS_LOG_ERROR("Failed to set port %s admin status DOWN to set speed", alias.c_str()); - it++; - continue; - } + p.m_admin_state_up = false; + m_portList[alias] = p; + } - p.m_admin_state_up = false; - m_portList[alias] = p; + auto ori_adv_speeds = swss::join(',', p.m_adv_speeds.begin(), p.m_adv_speeds.end()); + if (!setPortAdvSpeeds(p.m_port_id, adv_speeds)) + { + + SWSS_LOG_ERROR("Failed to set port %s advertised speed from %s to %s", alias.c_str(), + ori_adv_speeds.c_str(), + adv_speeds_str.c_str()); + it++; + continue; + } + SWSS_LOG_NOTICE("Set port %s advertised speed from %s to %s", alias.c_str(), + ori_adv_speeds.c_str(), + adv_speeds_str.c_str()); + p.m_adv_speeds.swap(adv_speeds); + m_portList[alias] = p; + } + } - if (!setPortSpeed(p, speed)) - { - SWSS_LOG_ERROR("Failed to set port %s speed to %u", alias.c_str(), speed); - it++; - continue; - } - } - else + if (!interface_type_str.empty()) + { + boost::to_lower(interface_type_str); + if (!getPortInterfaceTypeVal(interface_type_str, interface_type)) + { + // Invalid interface type configured, dont retry + it = consumer.m_toSync.erase(it); + continue; + } + + if (interface_type != p.m_interface_type) + { + if (p.m_admin_state_up && p.m_autoneg == 0) + { + /* Bring port down before applying speed */ + if (!setPortAdminStatus(p, false)) { - /* Port is already down, setting speed */ - if (!setPortSpeed(p, speed)) - { - SWSS_LOG_ERROR("Failed to set port %s speed to %u", alias.c_str(), speed); - it++; - continue; - } + SWSS_LOG_ERROR("Failed to set port %s admin status DOWN to set interface type", alias.c_str()); + it++; + continue; } - SWSS_LOG_NOTICE("Set port %s speed to %u", alias.c_str(), speed); + + p.m_admin_state_up = false; + m_portList[alias] = p; } - p.m_speed = speed; + + if (!setPortInterfaceType(p.m_port_id, interface_type)) + { + SWSS_LOG_ERROR("Failed to set port %s interface type to %s", alias.c_str(), interface_type_str.c_str()); + it++; + continue; + } + + SWSS_LOG_NOTICE("Set port %s interface type to %s", alias.c_str(), interface_type_str.c_str()); + p.m_interface_type = interface_type; m_portList[alias] = p; } - else + } + + if (!adv_interface_types_str.empty()) + { + boost::to_lower(adv_interface_types_str); + if (!getPortAdvInterfaceTypesVal(adv_interface_types_str, adv_interface_types)) { - /* Always update Gearbox speed on Gearbox ports */ - setGearboxPortsAttr(p, SAI_PORT_ATTR_SPEED, &speed); + // Invalid advertised interface types configured, dont retry + it = consumer.m_toSync.erase(it); + continue; + } + + if (adv_interface_types != p.m_adv_interface_types && p.m_autoneg == 1) + { + if (p.m_admin_state_up) + { + /* Bring port down before applying speed */ + if (!setPortAdminStatus(p, false)) + { + SWSS_LOG_ERROR("Failed to set port %s admin status DOWN to set interface type", alias.c_str()); + it++; + continue; + } + + p.m_admin_state_up = false; + m_portList[alias] = p; + } + + if (!setPortAdvInterfaceTypes(p.m_port_id, adv_interface_types)) + { + SWSS_LOG_ERROR("Failed to set port %s advertised interface type to %s", alias.c_str(), adv_interface_types_str.c_str()); + it++; + continue; + } + + SWSS_LOG_NOTICE("Set port %s advertised interface type to %s", alias.c_str(), adv_interface_types_str.c_str()); + p.m_adv_interface_types.swap(adv_interface_types); + m_portList[alias] = p; } } @@ -4743,6 +4957,15 @@ void PortsOrch::doTask(NotificationConsumer &consumer) } updatePortOperStatus(port, status); + if (status == SAI_PORT_OPER_STATUS_UP) + { + sai_uint32_t speed; + if (getPortOperSpeed(port, speed)) + { + SWSS_LOG_NOTICE("%s oper speed is %d", port.m_alias.c_str(), speed); + updateDbPortOperSpeed(port, speed); + } + } /* update m_portList */ m_portList[port.m_alias] = port; @@ -4798,6 +5021,20 @@ void PortsOrch::updatePortOperStatus(Port &port, sai_port_oper_status_t status) notify(SUBJECT_TYPE_PORT_OPER_STATE_CHANGE, static_cast(&update)); } +void PortsOrch::updateDbPortOperSpeed(Port &port, sai_uint32_t speed) +{ + SWSS_LOG_ENTER(); + + vector tuples; + FieldValueTuple tuple("speed", to_string(speed)); + tuples.push_back(tuple); + m_portTable->set(port.m_alias, tuples); + + // We don't set port.m_speed = speed here, because CONFIG_DB still hold the old + // value. If we set it here, next time configure any attributes related port will + // cause a port flapping. +} + /* * sync up orchagent with libsai/ASIC for port state. * @@ -4829,6 +5066,16 @@ void PortsOrch::refreshPortStatus() SWSS_LOG_INFO("%s oper status is %s", port.m_alias.c_str(), oper_status_strings.at(status).c_str()); updatePortOperStatus(port, status); + + if (status == SAI_PORT_OPER_STATUS_UP) + { + sai_uint32_t speed; + if (getPortOperSpeed(port, speed)) + { + SWSS_LOG_INFO("%s oper speed is %d", port.m_alias.c_str(), speed); + updateDbPortOperSpeed(port, speed); + } + } } } @@ -4856,6 +5103,30 @@ bool PortsOrch::getPortOperStatus(const Port& port, sai_port_oper_status_t& stat return true; } +bool PortsOrch::getPortOperSpeed(const Port& port, sai_uint32_t& speed) const +{ + SWSS_LOG_ENTER(); + + if (port.m_type != Port::PHY) + { + return false; + } + + sai_attribute_t attr; + attr.id = SAI_PORT_ATTR_OPER_SPEED; + + sai_status_t ret = sai_port_api->get_port_attribute(port.m_port_id, 1, &attr); + if (ret != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to get oper speed for %s", port.m_alias.c_str()); + return false; + } + + speed = static_cast(attr.value.u32); + + return true; +} + bool PortsOrch::getSaiAclBindPointType(Port::Type type, sai_acl_bind_point_type_t &sai_acl_bind_type) { @@ -5033,6 +5304,86 @@ void PortsOrch::getPortSerdesVal(const std::string& val_str, } } +bool PortsOrch::getPortAdvSpeedsVal(const std::string &val_str, + std::vector &speed_values) +{ + SWSS_LOG_ENTER(); + + if (val_str == "all") + { + return true; + } + + uint32_t speed_val; + std::string speed_str; + std::istringstream iss(val_str); + + try + { + while (std::getline(iss, speed_str, ',')) + { + speed_val = (uint32_t)std::stoul(speed_str); + speed_values.push_back(speed_val); + } + } + catch (const std::invalid_argument &e) + { + SWSS_LOG_ERROR("Failed to parse adv_speeds value: %s", val_str.c_str()); + return false; + } + std::sort(speed_values.begin(), speed_values.end()); + return true; +} + +bool PortsOrch::getPortInterfaceTypeVal(const std::string &s, + sai_port_interface_type_t &interface_type) +{ + SWSS_LOG_ENTER(); + + auto iter = interface_type_map_for_an.find(s); + if (iter != interface_type_map_for_an.end()) + { + interface_type = interface_type_map_for_an[s]; + return true; + } + else + { + const std::string &validInterfaceTypes = getValidInterfaceTypes(); + SWSS_LOG_ERROR("Failed to parse interface_type value %s, valid interface type includes: %s", + s.c_str(), validInterfaceTypes.c_str()); + return false; + } +} + +bool PortsOrch::getPortAdvInterfaceTypesVal(const std::string &val_str, + std::vector &type_values) +{ + SWSS_LOG_ENTER(); + if (val_str == "all") + { + return true; + } + + sai_port_interface_type_t interface_type ; + std::string type_str; + std::istringstream iss(val_str); + bool valid; + + while (std::getline(iss, type_str, ',')) + { + valid = getPortInterfaceTypeVal(type_str, interface_type); + if (!valid) { + const std::string &validInterfaceTypes = getValidInterfaceTypes(); + SWSS_LOG_ERROR("Failed to parse adv_interface_types value %s, valid interface type includes: %s", + val_str.c_str(), validInterfaceTypes.c_str()); + return false; + } + type_values.push_back(static_cast(interface_type)); + } + std::sort(type_values.begin(), type_values.end()); + return true; +} + /* Bring up/down Vlan interface associated with L3 VNI*/ bool PortsOrch::updateL3VniStatus(uint16_t vlan_id, bool isUp) { diff --git a/orchagent/portsorch.h b/orchagent/portsorch.h index a2d669c26384..9560cedcd505 100755 --- a/orchagent/portsorch.h +++ b/orchagent/portsorch.h @@ -74,7 +74,7 @@ struct VlanMemberUpdate class PortsOrch : public Orch, public Subject { public: - PortsOrch(DBConnector *db, vector &tableNames, DBConnector *chassisAppDb); + PortsOrch(DBConnector *db, DBConnector *stateDb, vector &tableNames, DBConnector *chassisAppDb); bool allPortsReady(); bool isInitDone(); @@ -162,6 +162,7 @@ class PortsOrch : public Orch, public Subject unique_ptr m_stateBufferMaximumValueTable; unique_ptr m_flexCounterTable; unique_ptr m_flexCounterGroupTable; + Table m_portStateTable; std::string getQueueWatermarkFlexCounterTableKey(std::string s); std::string getPriorityGroupWatermarkFlexCounterTableKey(std::string s); @@ -268,12 +269,14 @@ class PortsOrch : public Orch, public Subject bool setBridgePortAdminStatus(sai_object_id_t id, bool up); bool isSpeedSupported(const std::string& alias, sai_object_id_t port_id, sai_uint32_t speed); + void getPortSupportedSpeeds(const std::string& alias, sai_object_id_t port_id, PortSupportedSpeeds &supported_speeds); + void initPortSupportedSpeeds(const std::string& alias, sai_object_id_t port_id); bool setPortSpeed(Port &port, sai_uint32_t speed); bool getPortSpeed(sai_object_id_t id, sai_uint32_t &speed); bool setGearboxPortsAttr(Port &port, sai_port_attr_t id, void *value); bool setGearboxPortAttr(Port &port, dest_port_type_t port_type, sai_port_attr_t id, void *value); - bool setPortAdvSpeed(sai_object_id_t port_id, sai_uint32_t speed); + bool setPortAdvSpeeds(sai_object_id_t port_id, std::vector& speed_list); bool getQueueTypeAndIndex(sai_object_id_t queue_id, string &type, uint8_t &index); @@ -285,11 +288,19 @@ class PortsOrch : public Orch, public Subject bool setPortAutoNeg(sai_object_id_t id, int an); bool setPortFecMode(sai_object_id_t id, int fec); + bool setPortInterfaceType(sai_object_id_t id, sai_port_interface_type_t interface_type); + bool setPortAdvInterfaceTypes(sai_object_id_t id, std::vector &interface_types); bool getPortOperStatus(const Port& port, sai_port_oper_status_t& status) const; void updatePortOperStatus(Port &port, sai_port_oper_status_t status); + bool getPortOperSpeed(const Port& port, sai_uint32_t& speed) const; + void updateDbPortOperSpeed(Port &port, sai_uint32_t speed); + void getPortSerdesVal(const std::string& s, std::vector &lane_values); + bool getPortAdvSpeedsVal(const std::string &s, std::vector &speed_values); + bool getPortInterfaceTypeVal(const std::string &s, sai_port_interface_type_t &interface_type); + bool getPortAdvInterfaceTypesVal(const std::string &s, std::vector &type_values); bool setPortSerdesAttribute(sai_object_id_t port_id, std::map> &serdes_attr); @@ -301,6 +312,8 @@ class PortsOrch : public Orch, public Subject sai_acl_bind_point_type_t &sai_acl_bind_type); void initGearbox(); bool initGearboxPort(Port &port); + + //map key is tuple of map, sai_object_id_t> m_systemPortOidMap; diff --git a/tests/mock_tests/aclorch_ut.cpp b/tests/mock_tests/aclorch_ut.cpp index 5a3b7cff2683..00b532d7ceef 100644 --- a/tests/mock_tests/aclorch_ut.cpp +++ b/tests/mock_tests/aclorch_ut.cpp @@ -317,7 +317,7 @@ namespace aclorch_test }; ASSERT_EQ(gPortsOrch, nullptr); - gPortsOrch = new PortsOrch(m_app_db.get(), ports_tables, m_chassis_app_db.get()); + gPortsOrch = new PortsOrch(m_app_db.get(), m_state_db.get(), ports_tables, m_chassis_app_db.get()); ASSERT_EQ(gCrmOrch, nullptr); gCrmOrch = new CrmOrch(m_config_db.get(), CFG_CRM_TABLE_NAME); diff --git a/tests/mock_tests/portsorch_ut.cpp b/tests/mock_tests/portsorch_ut.cpp index 778e290d6925..365c5144b5b6 100644 --- a/tests/mock_tests/portsorch_ut.cpp +++ b/tests/mock_tests/portsorch_ut.cpp @@ -145,7 +145,9 @@ namespace portsorch_test }; ASSERT_EQ(gPortsOrch, nullptr); - gPortsOrch = new PortsOrch(m_app_db.get(), ports_tables, m_chassis_app_db.get()); + + gPortsOrch = new PortsOrch(m_app_db.get(), m_state_db.get(), ports_tables, m_chassis_app_db.get()); + vector buffer_tables = { APP_BUFFER_POOL_TABLE_NAME, APP_BUFFER_PROFILE_TABLE_NAME, APP_BUFFER_QUEUE_TABLE_NAME, @@ -274,7 +276,7 @@ namespace portsorch_test }; ASSERT_EQ(gPortsOrch, nullptr); - gPortsOrch = new PortsOrch(m_app_db.get(), ports_tables, m_chassis_app_db.get()); + gPortsOrch = new PortsOrch(m_app_db.get(), m_state_db.get(), ports_tables, m_chassis_app_db.get()); vector buffer_tables = { APP_BUFFER_POOL_TABLE_NAME, APP_BUFFER_PROFILE_TABLE_NAME, APP_BUFFER_QUEUE_TABLE_NAME, @@ -344,7 +346,7 @@ namespace portsorch_test }; ASSERT_EQ(gPortsOrch, nullptr); - gPortsOrch = new PortsOrch(m_app_db.get(), ports_tables, m_chassis_app_db.get()); + gPortsOrch = new PortsOrch(m_app_db.get(), m_state_db.get(), ports_tables, m_chassis_app_db.get()); vector buffer_tables = { APP_BUFFER_POOL_TABLE_NAME, APP_BUFFER_PROFILE_TABLE_NAME, APP_BUFFER_QUEUE_TABLE_NAME, @@ -489,7 +491,7 @@ namespace portsorch_test }; ASSERT_EQ(gPortsOrch, nullptr); - gPortsOrch = new PortsOrch(m_app_db.get(), ports_tables, m_chassis_app_db.get()); + gPortsOrch = new PortsOrch(m_app_db.get(), m_state_db.get(), ports_tables, m_chassis_app_db.get()); vector buffer_tables = { APP_BUFFER_POOL_TABLE_NAME, APP_BUFFER_PROFILE_TABLE_NAME, APP_BUFFER_QUEUE_TABLE_NAME, diff --git a/tests/test_port_an.py b/tests/test_port_an.py index f5bb86ffcc33..93add09b9ab2 100644 --- a/tests/test_port_an.py +++ b/tests/test_port_an.py @@ -30,13 +30,12 @@ def test_PortAutoNegForce(self, dvs, testlog): adb.wait_for_field_match("ASIC_STATE:SAI_OBJECT_TYPE_PORT", port_oid, expected_fields) def test_PortAutoNegCold(self, dvs, testlog): - db = swsscommon.DBConnector(0, dvs.redis_sock, 0) tbl = swsscommon.ProducerStateTable(db, "PORT_TABLE") - # set autoneg = true and speed = 1000 - fvs = swsscommon.FieldValuePairs([("autoneg","on"), ("speed", "1000")]) + # set autoneg = true and adv_speeds = 1000 + fvs = swsscommon.FieldValuePairs([("autoneg","on"), ("adv_speeds", "1000")]) tbl.set("Ethernet0", fvs) @@ -56,8 +55,47 @@ def test_PortAutoNegCold(self, dvs, testlog): elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_SPEED": assert fv[1] == "1:1000" - # set speed = 100 - fvs = swsscommon.FieldValuePairs([("speed", "100")]) + # set adv_speeds = 100,1000 + fvs = swsscommon.FieldValuePairs([("adv_speeds", "100,1000")]) + + tbl.set("Ethernet0", fvs) + + time.sleep(1) + + (status, fvs) = atbl.get(dvs.asicdb.portnamemap["Ethernet0"]) + assert status == True + + assert "SAI_PORT_ATTR_AUTO_NEG_MODE" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_ADVERTISED_SPEED" in [fv[0] for fv in fvs] + for fv in fvs: + if fv[0] == "SAI_PORT_ATTR_AUTO_NEG_MODE": + assert fv[1] == "true" + elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_SPEED": + assert fv[1] == "2:100,1000" + + # set adv_interface_types = CR2 + fvs = swsscommon.FieldValuePairs([("adv_interface_types", "CR2")]) + + tbl.set("Ethernet0", fvs) + + time.sleep(1) + + (status, fvs) = atbl.get(dvs.asicdb.portnamemap["Ethernet0"]) + assert status == True + + assert "SAI_PORT_ATTR_AUTO_NEG_MODE" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_ADVERTISED_SPEED" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE" in [fv[0] for fv in fvs] + for fv in fvs: + if fv[0] == "SAI_PORT_ATTR_AUTO_NEG_MODE": + assert fv[1] == "true" + elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_SPEED": + assert fv[1] == "2:100,1000" + elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE": + assert fv[1] == "1:SAI_PORT_INTERFACE_TYPE_CR2" + + # set adv_interface_types = CR2,CR4 + fvs = swsscommon.FieldValuePairs([("adv_interface_types", "CR2,CR4")]) tbl.set("Ethernet0", fvs) @@ -66,14 +104,19 @@ def test_PortAutoNegCold(self, dvs, testlog): (status, fvs) = atbl.get(dvs.asicdb.portnamemap["Ethernet0"]) assert status == True + assert "SAI_PORT_ATTR_AUTO_NEG_MODE" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_ADVERTISED_SPEED" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE" in [fv[0] for fv in fvs] for fv in fvs: if fv[0] == "SAI_PORT_ATTR_AUTO_NEG_MODE": assert fv[1] == "true" elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_SPEED": - assert fv[1] == "1:100" + assert fv[1] == "2:100,1000" + elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE": + assert fv[1] == "2:SAI_PORT_INTERFACE_TYPE_CR2,SAI_PORT_INTERFACE_TYPE_CR4" # change autoneg to false - fvs = swsscommon.FieldValuePairs([("autoneg","off")]) + fvs = swsscommon.FieldValuePairs([("autoneg","off"), ("speed", "100")]) tbl.set("Ethernet0", fvs) @@ -84,14 +127,17 @@ def test_PortAutoNegCold(self, dvs, testlog): assert "SAI_PORT_ATTR_AUTO_NEG_MODE" in [fv[0] for fv in fvs] assert "SAI_PORT_ATTR_ADVERTISED_SPEED" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE" in [fv[0] for fv in fvs] assert "SAI_PORT_ATTR_SPEED" in [fv[0] for fv in fvs] for fv in fvs: if fv[0] == "SAI_PORT_ATTR_AUTO_NEG_MODE": assert fv[1] == "false" elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_SPEED": - assert fv[1] == "1:100" + assert fv[1] == "2:100,1000" elif fv[0] == "SAI_PORT_ATTR_SPEED": assert fv[1] == "100" + elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE": + assert fv[1] == "2:SAI_PORT_INTERFACE_TYPE_CR2,SAI_PORT_INTERFACE_TYPE_CR4" # set speed = 1000 fvs = swsscommon.FieldValuePairs([("speed", "1000")]) @@ -103,59 +149,106 @@ def test_PortAutoNegCold(self, dvs, testlog): (status, fvs) = atbl.get(dvs.asicdb.portnamemap["Ethernet0"]) assert status == True + assert "SAI_PORT_ATTR_AUTO_NEG_MODE" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_ADVERTISED_SPEED" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_SPEED" in [fv[0] for fv in fvs] for fv in fvs: if fv[0] == "SAI_PORT_ATTR_AUTO_NEG_MODE": assert fv[1] == "false" elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_SPEED": - assert fv[1] == "1:100" + assert fv[1] == "2:100,1000" elif fv[0] == "SAI_PORT_ATTR_SPEED": assert fv[1] == "1000" + elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE": + assert fv[1] == "2:SAI_PORT_INTERFACE_TYPE_CR2,SAI_PORT_INTERFACE_TYPE_CR4" - def test_PortAutoNegWarm(self, dvs, testlog): + # set interface_type = CR4 + fvs = swsscommon.FieldValuePairs([("interface_type", "CR4")]) + tbl.set("Ethernet0", fvs) - db = swsscommon.DBConnector(0, dvs.redis_sock, 0) - cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0) - sdb = swsscommon.DBConnector(6, dvs.redis_sock, 0) + time.sleep(1) - tbl = swsscommon.ProducerStateTable(db, "PORT_TABLE") - ctbl = swsscommon.Table(cdb, "PORT") - stbl = swsscommon.Table(sdb, "PORT_TABLE") + (status, fvs) = atbl.get(dvs.asicdb.portnamemap["Ethernet0"]) + assert status == True - # set autoneg = true and speed = 1000 - fvs = swsscommon.FieldValuePairs([("autoneg","on"), ("speed", "1000")]) - ctbl.set("Ethernet0", fvs) + assert "SAI_PORT_ATTR_AUTO_NEG_MODE" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_ADVERTISED_SPEED" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_SPEED" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_INTERFACE_TYPE" in [fv[0] for fv in fvs] + for fv in fvs: + if fv[0] == "SAI_PORT_ATTR_AUTO_NEG_MODE": + assert fv[1] == "false" + elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_SPEED": + assert fv[1] == "2:100,1000" + elif fv[0] == "SAI_PORT_ATTR_SPEED": + assert fv[1] == "1000" + elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE": + assert fv[1] == "2:SAI_PORT_INTERFACE_TYPE_CR2,SAI_PORT_INTERFACE_TYPE_CR4" + elif fv[0] == "SAI_PORT_ATTR_INTERFACE_TYPE": + assert fv[1] == "SAI_PORT_INTERFACE_TYPE_CR4" - time.sleep(1) + # set interface_type = CR2 + fvs = swsscommon.FieldValuePairs([("interface_type", "CR2")]) + tbl.set("Ethernet0", fvs) - adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) + time.sleep(1) - atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_PORT") (status, fvs) = atbl.get(dvs.asicdb.portnamemap["Ethernet0"]) assert status == True assert "SAI_PORT_ATTR_AUTO_NEG_MODE" in [fv[0] for fv in fvs] assert "SAI_PORT_ATTR_ADVERTISED_SPEED" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_SPEED" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_INTERFACE_TYPE" in [fv[0] for fv in fvs] for fv in fvs: if fv[0] == "SAI_PORT_ATTR_AUTO_NEG_MODE": - assert fv[1] == "true" + assert fv[1] == "false" elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_SPEED": - assert fv[1] == "1:1000" + assert fv[1] == "2:100,1000" + elif fv[0] == "SAI_PORT_ATTR_SPEED": + assert fv[1] == "1000" + elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE": + assert fv[1] == "2:SAI_PORT_INTERFACE_TYPE_CR2,SAI_PORT_INTERFACE_TYPE_CR4" + elif fv[0] == "SAI_PORT_ATTR_INTERFACE_TYPE": + assert fv[1] == "SAI_PORT_INTERFACE_TYPE_CR2" - # set speed = 100 - fvs = swsscommon.FieldValuePairs([("speed", "100")]) + def test_PortAutoNegWarm(self, dvs, testlog): + + db = swsscommon.DBConnector(0, dvs.redis_sock, 0) + cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0) + sdb = swsscommon.DBConnector(6, dvs.redis_sock, 0) + tbl = swsscommon.ProducerStateTable(db, "PORT_TABLE") + ctbl = swsscommon.Table(cdb, "PORT") + stbl = swsscommon.Table(sdb, "PORT_TABLE") + + # set autoneg = true and speed = 1000 + fvs = swsscommon.FieldValuePairs([("autoneg","on"), + ("adv_speeds", "100,1000"), + ("adv_interface_types", "CR2,CR4")]) ctbl.set("Ethernet0", fvs) time.sleep(1) + adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) + + atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_PORT") (status, fvs) = atbl.get(dvs.asicdb.portnamemap["Ethernet0"]) assert status == True + assert "SAI_PORT_ATTR_AUTO_NEG_MODE" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_ADVERTISED_SPEED" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE" in [fv[0] for fv in fvs] for fv in fvs: if fv[0] == "SAI_PORT_ATTR_AUTO_NEG_MODE": assert fv[1] == "true" elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_SPEED": - assert fv[1] == "1:100" + assert fv[1] == "2:100,1000" + elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE": + assert fv[1] == "2:SAI_PORT_INTERFACE_TYPE_CR2,SAI_PORT_INTERFACE_TYPE_CR4" # set admin up cfvs = swsscommon.FieldValuePairs([("admin_status", "up")]) @@ -186,11 +279,14 @@ def test_PortAutoNegWarm(self, dvs, testlog): assert "SAI_PORT_ATTR_AUTO_NEG_MODE" in [fv[0] for fv in fvs] assert "SAI_PORT_ATTR_ADVERTISED_SPEED" in [fv[0] for fv in fvs] + assert "SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE" in [fv[0] for fv in fvs] for fv in fvs: if fv[0] == "SAI_PORT_ATTR_AUTO_NEG_MODE": assert fv[1] == "true" elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_SPEED": - assert fv[1] == "1:100" + assert fv[1] == "2:100,1000" + elif fv[0] == "SAI_PORT_ATTR_ADVERTISED_INTERFACE_TYPE": + assert fv[1] == "2:SAI_PORT_INTERFACE_TYPE_CR2,SAI_PORT_INTERFACE_TYPE_CR4" finally: # disable warm restart