@@ -166,6 +166,7 @@ SwitchOrch::SwitchOrch(DBConnector *db, vector<TableConnector>& connectors, Tabl
166166 querySwitchPortEgressSampleCapability ();
167167 querySwitchHashDefaults ();
168168 setSwitchIcmpOffloadCapability ();
169+ setFastLinkupCapability ();
169170
170171 auto executorT = new ExecutableTimer (m_sensorsPollerTimer, this , " ASIC_SENSORS_POLL_TIMER" );
171172 Orch::addExecutor (executorT);
@@ -1475,6 +1476,10 @@ void SwitchOrch::doTask(Consumer &consumer)
14751476 {
14761477 doCfgSwitchTrimmingTableTask (consumer);
14771478 }
1479+ else if (tableName == CFG_SWITCH_FAST_LINKUP_TABLE_NAME)
1480+ {
1481+ doCfgSwitchFastLinkupTableTask (consumer);
1482+ }
14781483 else if (tableName == CFG_SUPPRESS_ASIC_SDK_HEALTH_EVENT_NAME)
14791484 {
14801485 doCfgSuppressAsicSdkHealthEventTableTask (consumer);
@@ -1993,6 +1998,196 @@ bool SwitchOrch::querySwitchCapability(sai_object_type_t sai_object, sai_attr_id
19931998 }
19941999}
19952000
2001+ void SwitchOrch::setFastLinkupCapability ()
2002+ {
2003+ SWSS_LOG_ENTER ();
2004+
2005+ std::vector<FieldValueTuple> fvVector;
2006+
2007+ // Determine support by checking create/set capability on polling time attribute (enabled in real SAI)
2008+ bool supported = querySwitchCapability (SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_FAST_LINKUP_POLLING_TIMEOUT);
2009+ m_fastLinkupCap.supported = supported;
2010+
2011+ if (!supported)
2012+ {
2013+ fvVector.emplace_back (SWITCH_CAPABILITY_TABLE_FAST_LINKUP_CAPABLE, " false" );
2014+ set_switch_capability (fvVector);
2015+ return ;
2016+ }
2017+
2018+ fvVector.emplace_back (SWITCH_CAPABILITY_TABLE_FAST_LINKUP_CAPABLE, " true" );
2019+
2020+ // Query allowed ranges if supported by SAI
2021+ {
2022+ sai_attribute_t attr;
2023+ attr.id = SAI_SWITCH_ATTR_FAST_LINKUP_POLLING_TIMEOUT_RANGE;
2024+ sai_status_t status = sai_switch_api->get_switch_attribute (gSwitchId , 1 , &attr);
2025+ if (status == SAI_STATUS_SUCCESS)
2026+ {
2027+ m_fastLinkupCap.has_ranges = true ;
2028+ m_fastLinkupCap.polling_min = attr.value .u16range .min ;
2029+ m_fastLinkupCap.polling_max = attr.value .u16range .max ;
2030+ fvVector.emplace_back (
2031+ SWITCH_CAPABILITY_TABLE_FAST_LINKUP_POLLING_TIMER_RANGE,
2032+ to_string (m_fastLinkupCap.polling_min ) + " ," + to_string (m_fastLinkupCap.polling_max ));
2033+ }
2034+ else
2035+ {
2036+ SWSS_LOG_ERROR (" Failed to get fast linkup polling range: %s" , sai_serialize_status (status).c_str ());
2037+ }
2038+ }
2039+
2040+ {
2041+ sai_attribute_t attr;
2042+ attr.id = SAI_SWITCH_ATTR_FAST_LINKUP_GUARD_TIMEOUT_RANGE;
2043+ sai_status_t status = sai_switch_api->get_switch_attribute (gSwitchId , 1 , &attr);
2044+ if (status == SAI_STATUS_SUCCESS)
2045+ {
2046+ m_fastLinkupCap.has_ranges = true ;
2047+ m_fastLinkupCap.guard_min = attr.value .u16range .min ;
2048+ m_fastLinkupCap.guard_max = attr.value .u16range .max ;
2049+ fvVector.emplace_back (
2050+ SWITCH_CAPABILITY_TABLE_FAST_LINKUP_GUARD_TIMER_RANGE,
2051+ to_string (m_fastLinkupCap.guard_min ) + " ," + to_string (m_fastLinkupCap.guard_max ));
2052+ }
2053+ else
2054+ {
2055+ SWSS_LOG_ERROR (" Failed to get fast linkup guard range: %s" , sai_serialize_status (status).c_str ());
2056+ }
2057+ }
2058+ set_switch_capability (fvVector);
2059+ }
2060+
2061+ bool SwitchOrch::setSwitchFastLinkup (const FastLinkupConfig &cfg)
2062+ {
2063+ SWSS_LOG_ENTER ();
2064+
2065+ if (!m_fastLinkupCap.supported )
2066+ {
2067+ SWSS_LOG_NOTICE (" Fast link-up is not supported on this platform" );
2068+ return false ;
2069+ }
2070+
2071+ // Validate ranges if known
2072+ if (cfg.has_polling && m_fastLinkupCap.has_ranges )
2073+ {
2074+ if (cfg.polling_time < m_fastLinkupCap.polling_min || cfg.polling_time > m_fastLinkupCap.polling_max )
2075+ {
2076+ SWSS_LOG_NOTICE (" Invalid polling_time %u; allowed [%u,%u]" , cfg.polling_time , m_fastLinkupCap.polling_min , m_fastLinkupCap.polling_max );
2077+ return false ;
2078+ }
2079+ }
2080+ if (cfg.has_guard && m_fastLinkupCap.has_ranges )
2081+ {
2082+ if (cfg.guard_time < m_fastLinkupCap.guard_min || cfg.guard_time > m_fastLinkupCap.guard_max )
2083+ {
2084+ SWSS_LOG_NOTICE (" Invalid guard_time %u; allowed [%u,%u]" , cfg.guard_time , m_fastLinkupCap.guard_min , m_fastLinkupCap.guard_max );
2085+ return false ;
2086+ }
2087+ }
2088+
2089+ // Apply attributes conditionally
2090+ sai_status_t status;
2091+ if (cfg.has_polling )
2092+ {
2093+ sai_attribute_t attr;
2094+ attr.id = SAI_SWITCH_ATTR_FAST_LINKUP_POLLING_TIMEOUT;
2095+ attr.value .u16 = cfg.polling_time ;
2096+ status = sai_switch_api->set_switch_attribute (gSwitchId , &attr);
2097+ if (status != SAI_STATUS_SUCCESS)
2098+ {
2099+ SWSS_LOG_NOTICE (" Failed to set FAST_LINKUP_POLLING_TIME=%u: %s" , cfg.polling_time , sai_serialize_status (status).c_str ());
2100+ return false ;
2101+ }
2102+ }
2103+
2104+ if (cfg.has_guard )
2105+ {
2106+ sai_attribute_t attr;
2107+ attr.id = SAI_SWITCH_ATTR_FAST_LINKUP_GUARD_TIMEOUT;
2108+ attr.value .u8 = cfg.guard_time ;
2109+ status = sai_switch_api->set_switch_attribute (gSwitchId , &attr);
2110+ if (status != SAI_STATUS_SUCCESS)
2111+ {
2112+ SWSS_LOG_NOTICE (" Failed to set FAST_LINKUP_GUARD_TIME=%u: %s" , cfg.guard_time , sai_serialize_status (status).c_str ());
2113+ return false ;
2114+ }
2115+ }
2116+
2117+ if (cfg.has_ber )
2118+ {
2119+ sai_attribute_t attr;
2120+ attr.id = SAI_SWITCH_ATTR_FAST_LINKUP_BER_THRESHOLD;
2121+ attr.value .u8 = cfg.ber_threshold ;
2122+ status = sai_switch_api->set_switch_attribute (gSwitchId , &attr);
2123+ if (status != SAI_STATUS_SUCCESS)
2124+ {
2125+ SWSS_LOG_NOTICE (" Failed to set FAST_LINKUP_BER_THRESHOLD=%u: %s" , cfg.ber_threshold , sai_serialize_status (status).c_str ());
2126+ return false ;
2127+ }
2128+ }
2129+ SWSS_LOG_INFO (" Fast link-up set: polling_time=%s, guard_time=%s, ber_threshold=%s" ,
2130+ cfg.has_polling ? std::to_string (cfg.polling_time ).c_str () : " N/A" ,
2131+ cfg.has_guard ? std::to_string (cfg.guard_time ).c_str () : " N/A" ,
2132+ cfg.has_ber ? std::to_string (cfg.ber_threshold ).c_str () : " N/A" );
2133+ return true ;
2134+ }
2135+
2136+ void SwitchOrch::doCfgSwitchFastLinkupTableTask (Consumer &consumer)
2137+ {
2138+ SWSS_LOG_ENTER ();
2139+
2140+ auto &map = consumer.m_toSync ;
2141+ auto it = map.begin ();
2142+
2143+ while (it != map.end ())
2144+ {
2145+ auto keyOpFieldsValues = it->second ;
2146+ auto key = kfvKey (keyOpFieldsValues);
2147+ auto op = kfvOp (keyOpFieldsValues);
2148+
2149+ if (op == SET_COMMAND)
2150+ {
2151+ FastLinkupConfig cfg;
2152+ for (const auto &cit : kfvFieldsValues (keyOpFieldsValues))
2153+ {
2154+ auto fieldName = fvField (cit);
2155+ auto fieldValue = fvValue (cit);
2156+ if (fieldName == " polling_time" )
2157+ {
2158+ try { cfg.polling_time = to_uint<uint16_t >(fieldValue); cfg.has_polling = true ; }
2159+ catch (...) { SWSS_LOG_ERROR (" Invalid polling_time value %s" , fieldValue.c_str ()); }
2160+ }
2161+ else if (fieldName == " guard_time" )
2162+ {
2163+ try { cfg.guard_time = to_uint<uint8_t >(fieldValue); cfg.has_guard = true ; }
2164+ catch (...) { SWSS_LOG_ERROR (" Invalid guard_time value %s" , fieldValue.c_str ()); }
2165+ }
2166+ else if (fieldName == " ber_threshold" )
2167+ {
2168+ try { cfg.ber_threshold = to_uint<uint8_t >(fieldValue); cfg.has_ber = true ; }
2169+ catch (...) { SWSS_LOG_ERROR (" Invalid ber_threshold value %s" , fieldValue.c_str ()); }
2170+ }
2171+ else
2172+ {
2173+ SWSS_LOG_WARN (" Unknown field %s in SWITCH_FAST_LINKUP" , fieldName.c_str ());
2174+ }
2175+ }
2176+
2177+ if (!setSwitchFastLinkup (cfg))
2178+ {
2179+ SWSS_LOG_ERROR (" Failed to configure fast link-up from CONFIG_DB" );
2180+ }
2181+ }
2182+ else
2183+ {
2184+ SWSS_LOG_ERROR (" Unsupported operation %s for SWITCH_FAST_LINKUP" , op.c_str ());
2185+ }
2186+
2187+ it = map.erase (it);
2188+ }
2189+ }
2190+
19962191// Bind ACL table (with bind type switch) to switch
19972192bool SwitchOrch::bindAclTableToSwitch (acl_stage_type_t stage, sai_object_id_t table_id)
19982193{
0 commit comments