Skip to content

Commit 490744e

Browse files
committed
[Fast-linkup] Added orchagents support
Signed-off-by: Yair Raviv <[email protected]>
1 parent dd9cf3d commit 490744e

File tree

10 files changed

+413
-0
lines changed

10 files changed

+413
-0
lines changed

orchagent/orchdaemon.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,13 @@ bool OrchDaemon::init()
177177
TableConnector conf_asic_sensors(m_configDb, CFG_ASIC_SENSORS_TABLE_NAME);
178178
TableConnector conf_switch_hash(m_configDb, CFG_SWITCH_HASH_TABLE_NAME);
179179
TableConnector conf_switch_trim(m_configDb, CFG_SWITCH_TRIMMING_TABLE_NAME);
180+
TableConnector conf_switch_fast_linkup(m_configDb, CFG_SWITCH_FAST_LINKUP_TABLE_NAME);
180181
TableConnector conf_suppress_asic_sdk_health_categories(m_configDb, CFG_SUPPRESS_ASIC_SDK_HEALTH_EVENT_NAME);
181182

182183
vector<TableConnector> switch_tables = {
183184
conf_switch_hash,
184185
conf_switch_trim,
186+
conf_switch_fast_linkup,
185187
conf_asic_sensors,
186188
conf_suppress_asic_sdk_health_categories,
187189
app_switch_table

orchagent/port/portcnt.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ class PortConfig final
9898
bool is_set = false;
9999
} link_training; // Port link training
100100

101+
struct {
102+
bool value;
103+
bool is_set = false;
104+
} fast_linkup; // Port fast link-up enable
105+
101106
struct {
102107
std::string value;
103108
bool is_set = false;

orchagent/port/porthlpr.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,32 @@ bool PortHelper::parsePortLinkTraining(PortConfig &port, const std::string &fiel
697697
return true;
698698
}
699699

700+
bool PortHelper::parsePortFastLinkup(PortConfig &port, const std::string &field, const std::string &value) const
701+
{
702+
SWSS_LOG_ENTER();
703+
704+
if (value.empty())
705+
{
706+
SWSS_LOG_ERROR("Failed to parse field(%s): empty value is not allowed", field.c_str());
707+
return false;
708+
}
709+
if (value == "true")
710+
{
711+
port.fast_linkup.value = true;
712+
}
713+
else if (value == "false")
714+
{
715+
port.fast_linkup.value = false;
716+
}
717+
else
718+
{
719+
SWSS_LOG_ERROR("Failed to parse field(%s): invalid value(%s)", field.c_str(), value.c_str());
720+
return false;
721+
}
722+
port.fast_linkup.is_set = true;
723+
return true;
724+
}
725+
700726
template<typename T>
701727
bool PortHelper::parsePortSerdes(T &serdes, const std::string &field, const std::string &value) const
702728
{
@@ -1092,6 +1118,13 @@ bool PortHelper::parsePortConfig(PortConfig &port) const
10921118
return false;
10931119
}
10941120
}
1121+
else if (field == PORT_FAST_LINKUP)
1122+
{
1123+
if (!this->parsePortFastLinkup(port, field, value))
1124+
{
1125+
return false;
1126+
}
1127+
}
10951128
else if (field == PORT_UNRELIABLE_LOS)
10961129
{
10971130
if (!this->parsePortUnreliableLos(port, field, value))

orchagent/port/porthlpr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,5 @@ class PortHelper final
7373
bool parsePortPtIntfId(PortConfig &port, const std::string &field, const std::string &value) const;
7474
bool parsePortPtTimestampTemplate(PortConfig &port, const std::string &field, const std::string &value) const;
7575
bool parsePortMediaType(PortConfig &port, const std::string &field, const std::string &value) const;
76+
bool parsePortFastLinkup(PortConfig &port, const std::string &field, const std::string &value) const;
7677
};

orchagent/port/portschema.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,4 @@
105105
#define PORT_MODE "mode"
106106
#define PORT_UNRELIABLE_LOS "unreliable_los"
107107
#define PORT_MEDIA_TYPE "media_type"
108+
#define PORT_FAST_LINKUP "fast_linkup"

orchagent/portsorch.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,12 @@ PortsOrch::PortsOrch(DBConnector *db, DBConnector *stateDb, vector<table_name_wi
969969
m_defaultVlan = attrs[1].value.oid;
970970
}
971971

972+
//Fast link-up per-port attribute support
973+
if (gSwitchOrch->querySwitchCapability(SAI_OBJECT_TYPE_PORT, SAI_PORT_ATTR_FAST_LINKUP_ENABLED))
974+
{
975+
m_fastLinkupPortAttrSupported = true;
976+
}
977+
972978
if (gMySwitchType != "dpu")
973979
{
974980
// System Ports not supported on dpu
@@ -3442,6 +3448,28 @@ bool PortsOrch::getPortAdvSpeeds(const Port& port, bool remote, string& adv_spee
34423448
return rc;
34433449
}
34443450

3451+
task_process_status PortsOrch::setPortFastLinkupEnabled(Port &port, bool enable)
3452+
{
3453+
SWSS_LOG_ENTER();
3454+
3455+
if (!m_fastLinkupPortAttrSupported)
3456+
{
3457+
SWSS_LOG_NOTICE("Fast link-up is not supported on this platform");
3458+
return task_success;
3459+
}
3460+
sai_attribute_t attr;
3461+
attr.id = SAI_PORT_ATTR_FAST_LINKUP_ENABLED;
3462+
attr.value.booldata = enable;
3463+
sai_status_t status = sai_port_api->set_port_attribute(port.m_port_id, &attr);
3464+
if (status != SAI_STATUS_SUCCESS)
3465+
{
3466+
SWSS_LOG_ERROR("Failed to set fast_linkup %d on port %s", enable, port.m_alias.c_str());
3467+
return handleSaiSetStatus(SAI_API_PORT, status);
3468+
}
3469+
SWSS_LOG_INFO("Set port %s fast_linkup %s", port.m_alias.c_str(), enable ? "true" : "false");
3470+
return task_success;
3471+
}
3472+
34453473
task_process_status PortsOrch::setPortUnreliableLOS(Port &port, bool enabled)
34463474
{
34473475
SWSS_LOG_ENTER();
@@ -4654,6 +4682,19 @@ void PortsOrch::doPortTask(Consumer &consumer)
46544682
}
46554683
}
46564684

4685+
// Handle fast_linkup boolean
4686+
if (pCfg.fast_linkup.is_set)
4687+
{
4688+
auto status = setPortFastLinkupEnabled(p, pCfg.fast_linkup.value);
4689+
// For fast_linkup attribute, task_need_retry is not a meaningful return, so treat any failure as a permanent failure and erase the task.
4690+
if (status != task_success)
4691+
{
4692+
SWSS_LOG_ERROR("Failed to set port %s fast_linkup to %s", p.m_alias.c_str(), pCfg.fast_linkup.value ? "true" : "false");
4693+
it = taskMap.erase(it);
4694+
continue;
4695+
}
4696+
}
4697+
46574698
if (pCfg.link_event_damping_algorithm.is_set)
46584699
{
46594700
if (p.m_link_event_damping_algorithm != pCfg.link_event_damping_algorithm.value)

orchagent/portsorch.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ class PortsOrch : public Orch, public Subject
264264

265265
bool setPortPtIntfId(const Port& port, sai_uint16_t intf_id);
266266
bool setPortPtTimestampTemplate(const Port& port, sai_port_path_tracing_timestamp_type_t ts_type);
267+
task_process_status setPortFastLinkupEnabled(Port &port, bool enable);
267268

268269
private:
269270
unique_ptr<CounterNameMapUpdater> m_counterNameMapUpdater;
@@ -373,6 +374,7 @@ class PortsOrch : public Orch, public Subject
373374
bool saiHwTxSignalSupported = false;
374375
bool saiTxReadyNotifySupported = false;
375376
bool m_supportsHostIfTxQueue = false;
377+
bool m_fastLinkupPortAttrSupported = false;
376378

377379
swss::SelectableTimer *m_port_state_poller = nullptr;
378380

orchagent/switchorch.cpp

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
20552250
bool SwitchOrch::bindAclTableToSwitch(acl_stage_type_t stage, sai_object_id_t table_id)
20562251
{

0 commit comments

Comments
 (0)