@@ -167,6 +167,7 @@ SwitchOrch::SwitchOrch(DBConnector *db, vector<TableConnector>& connectors, Tabl
167167 querySwitchPortMirrorCapability ();
168168 querySwitchHashDefaults ();
169169 setSwitchIcmpOffloadCapability ();
170+ setFastLinkupCapability ();
170171
171172 auto executorT = new ExecutableTimer (m_sensorsPollerTimer, this , " ASIC_SENSORS_POLL_TIMER" );
172173 Orch::addExecutor (executorT);
@@ -1476,6 +1477,10 @@ void SwitchOrch::doTask(Consumer &consumer)
14761477 {
14771478 doCfgSwitchTrimmingTableTask (consumer);
14781479 }
1480+ else if (tableName == CFG_SWITCH_FAST_LINKUP_TABLE_NAME)
1481+ {
1482+ doCfgSwitchFastLinkupTableTask (consumer);
1483+ }
14791484 else if (tableName == CFG_SUPPRESS_ASIC_SDK_HEALTH_EVENT_NAME)
14801485 {
14811486 doCfgSuppressAsicSdkHealthEventTableTask (consumer);
@@ -2051,6 +2056,196 @@ bool SwitchOrch::querySwitchCapability(sai_object_type_t sai_object, sai_attr_id
20512056 }
20522057}
20532058
2059+ void SwitchOrch::setFastLinkupCapability ()
2060+ {
2061+ SWSS_LOG_ENTER ();
2062+
2063+ std::vector<FieldValueTuple> fvVector;
2064+
2065+ // Determine support by checking create/set capability on polling time attribute (enabled in real SAI)
2066+ bool supported = querySwitchCapability (SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_FAST_LINKUP_POLLING_TIMEOUT);
2067+ m_fastLinkupCap.supported = supported;
2068+
2069+ if (!supported)
2070+ {
2071+ fvVector.emplace_back (SWITCH_CAPABILITY_TABLE_FAST_LINKUP_CAPABLE, " false" );
2072+ set_switch_capability (fvVector);
2073+ return ;
2074+ }
2075+
2076+ fvVector.emplace_back (SWITCH_CAPABILITY_TABLE_FAST_LINKUP_CAPABLE, " true" );
2077+
2078+ // Query allowed ranges if supported by SAI
2079+ {
2080+ sai_attribute_t attr;
2081+ attr.id = SAI_SWITCH_ATTR_FAST_LINKUP_POLLING_TIMEOUT_RANGE;
2082+ sai_status_t status = sai_switch_api->get_switch_attribute (gSwitchId , 1 , &attr);
2083+ if (status == SAI_STATUS_SUCCESS)
2084+ {
2085+ m_fastLinkupCap.has_ranges = true ;
2086+ m_fastLinkupCap.polling_min = attr.value .u16range .min ;
2087+ m_fastLinkupCap.polling_max = attr.value .u16range .max ;
2088+ fvVector.emplace_back (
2089+ SWITCH_CAPABILITY_TABLE_FAST_LINKUP_POLLING_TIMER_RANGE,
2090+ to_string (m_fastLinkupCap.polling_min ) + " ," + to_string (m_fastLinkupCap.polling_max ));
2091+ }
2092+ else
2093+ {
2094+ SWSS_LOG_ERROR (" Failed to get fast linkup polling range: %s" , sai_serialize_status (status).c_str ());
2095+ }
2096+ }
2097+
2098+ {
2099+ sai_attribute_t attr;
2100+ attr.id = SAI_SWITCH_ATTR_FAST_LINKUP_GUARD_TIMEOUT_RANGE;
2101+ sai_status_t status = sai_switch_api->get_switch_attribute (gSwitchId , 1 , &attr);
2102+ if (status == SAI_STATUS_SUCCESS)
2103+ {
2104+ m_fastLinkupCap.has_ranges = true ;
2105+ m_fastLinkupCap.guard_min = attr.value .u16range .min ;
2106+ m_fastLinkupCap.guard_max = attr.value .u16range .max ;
2107+ fvVector.emplace_back (
2108+ SWITCH_CAPABILITY_TABLE_FAST_LINKUP_GUARD_TIMER_RANGE,
2109+ to_string (m_fastLinkupCap.guard_min ) + " ," + to_string (m_fastLinkupCap.guard_max ));
2110+ }
2111+ else
2112+ {
2113+ SWSS_LOG_ERROR (" Failed to get fast linkup guard range: %s" , sai_serialize_status (status).c_str ());
2114+ }
2115+ }
2116+ set_switch_capability (fvVector);
2117+ }
2118+
2119+ bool SwitchOrch::setSwitchFastLinkup (const FastLinkupConfig &cfg)
2120+ {
2121+ SWSS_LOG_ENTER ();
2122+
2123+ if (!m_fastLinkupCap.supported )
2124+ {
2125+ SWSS_LOG_NOTICE (" Fast link-up is not supported on this platform" );
2126+ return false ;
2127+ }
2128+
2129+ // Validate ranges if known
2130+ if (cfg.has_polling && m_fastLinkupCap.has_ranges )
2131+ {
2132+ if (cfg.polling_time < m_fastLinkupCap.polling_min || cfg.polling_time > m_fastLinkupCap.polling_max )
2133+ {
2134+ SWSS_LOG_NOTICE (" Invalid polling_time %u; allowed [%u,%u]" , cfg.polling_time , m_fastLinkupCap.polling_min , m_fastLinkupCap.polling_max );
2135+ return false ;
2136+ }
2137+ }
2138+ if (cfg.has_guard && m_fastLinkupCap.has_ranges )
2139+ {
2140+ if (cfg.guard_time < m_fastLinkupCap.guard_min || cfg.guard_time > m_fastLinkupCap.guard_max )
2141+ {
2142+ SWSS_LOG_NOTICE (" Invalid guard_time %u; allowed [%u,%u]" , cfg.guard_time , m_fastLinkupCap.guard_min , m_fastLinkupCap.guard_max );
2143+ return false ;
2144+ }
2145+ }
2146+
2147+ // Apply attributes conditionally
2148+ sai_status_t status;
2149+ if (cfg.has_polling )
2150+ {
2151+ sai_attribute_t attr;
2152+ attr.id = SAI_SWITCH_ATTR_FAST_LINKUP_POLLING_TIMEOUT;
2153+ attr.value .u16 = cfg.polling_time ;
2154+ status = sai_switch_api->set_switch_attribute (gSwitchId , &attr);
2155+ if (status != SAI_STATUS_SUCCESS)
2156+ {
2157+ SWSS_LOG_NOTICE (" Failed to set FAST_LINKUP_POLLING_TIME=%u: %s" , cfg.polling_time , sai_serialize_status (status).c_str ());
2158+ return false ;
2159+ }
2160+ }
2161+
2162+ if (cfg.has_guard )
2163+ {
2164+ sai_attribute_t attr;
2165+ attr.id = SAI_SWITCH_ATTR_FAST_LINKUP_GUARD_TIMEOUT;
2166+ attr.value .u8 = cfg.guard_time ;
2167+ status = sai_switch_api->set_switch_attribute (gSwitchId , &attr);
2168+ if (status != SAI_STATUS_SUCCESS)
2169+ {
2170+ SWSS_LOG_NOTICE (" Failed to set FAST_LINKUP_GUARD_TIME=%u: %s" , cfg.guard_time , sai_serialize_status (status).c_str ());
2171+ return false ;
2172+ }
2173+ }
2174+
2175+ if (cfg.has_ber )
2176+ {
2177+ sai_attribute_t attr;
2178+ attr.id = SAI_SWITCH_ATTR_FAST_LINKUP_BER_THRESHOLD;
2179+ attr.value .u8 = cfg.ber_threshold ;
2180+ status = sai_switch_api->set_switch_attribute (gSwitchId , &attr);
2181+ if (status != SAI_STATUS_SUCCESS)
2182+ {
2183+ SWSS_LOG_NOTICE (" Failed to set FAST_LINKUP_BER_THRESHOLD=%u: %s" , cfg.ber_threshold , sai_serialize_status (status).c_str ());
2184+ return false ;
2185+ }
2186+ }
2187+ SWSS_LOG_INFO (" Fast link-up set: polling_time=%s, guard_time=%s, ber_threshold=%s" ,
2188+ cfg.has_polling ? std::to_string (cfg.polling_time ).c_str () : " N/A" ,
2189+ cfg.has_guard ? std::to_string (cfg.guard_time ).c_str () : " N/A" ,
2190+ cfg.has_ber ? std::to_string (cfg.ber_threshold ).c_str () : " N/A" );
2191+ return true ;
2192+ }
2193+
2194+ void SwitchOrch::doCfgSwitchFastLinkupTableTask (Consumer &consumer)
2195+ {
2196+ SWSS_LOG_ENTER ();
2197+
2198+ auto &map = consumer.m_toSync ;
2199+ auto it = map.begin ();
2200+
2201+ while (it != map.end ())
2202+ {
2203+ auto keyOpFieldsValues = it->second ;
2204+ auto key = kfvKey (keyOpFieldsValues);
2205+ auto op = kfvOp (keyOpFieldsValues);
2206+
2207+ if (op == SET_COMMAND)
2208+ {
2209+ FastLinkupConfig cfg;
2210+ for (const auto &cit : kfvFieldsValues (keyOpFieldsValues))
2211+ {
2212+ auto fieldName = fvField (cit);
2213+ auto fieldValue = fvValue (cit);
2214+ if (fieldName == " polling_time" )
2215+ {
2216+ try { cfg.polling_time = to_uint<uint16_t >(fieldValue); cfg.has_polling = true ; }
2217+ catch (...) { SWSS_LOG_ERROR (" Invalid polling_time value %s" , fieldValue.c_str ()); }
2218+ }
2219+ else if (fieldName == " guard_time" )
2220+ {
2221+ try { cfg.guard_time = to_uint<uint8_t >(fieldValue); cfg.has_guard = true ; }
2222+ catch (...) { SWSS_LOG_ERROR (" Invalid guard_time value %s" , fieldValue.c_str ()); }
2223+ }
2224+ else if (fieldName == " ber_threshold" )
2225+ {
2226+ try { cfg.ber_threshold = to_uint<uint8_t >(fieldValue); cfg.has_ber = true ; }
2227+ catch (...) { SWSS_LOG_ERROR (" Invalid ber_threshold value %s" , fieldValue.c_str ()); }
2228+ }
2229+ else
2230+ {
2231+ SWSS_LOG_WARN (" Unknown field %s in SWITCH_FAST_LINKUP" , fieldName.c_str ());
2232+ }
2233+ }
2234+
2235+ if (!setSwitchFastLinkup (cfg))
2236+ {
2237+ SWSS_LOG_ERROR (" Failed to configure fast link-up from CONFIG_DB" );
2238+ }
2239+ }
2240+ else
2241+ {
2242+ SWSS_LOG_ERROR (" Unsupported operation %s for SWITCH_FAST_LINKUP" , op.c_str ());
2243+ }
2244+
2245+ it = map.erase (it);
2246+ }
2247+ }
2248+
20542249// Bind ACL table (with bind type switch) to switch
20552250bool SwitchOrch::bindAclTableToSwitch (acl_stage_type_t stage, sai_object_id_t table_id)
20562251{
0 commit comments