@@ -84,6 +84,7 @@ extern bool gMultiAsicVoq;
8484#define PORT_STATE_POLLING_SEC 5
8585#define PORT_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS 1000
8686#define PORT_BUFFER_DROP_STAT_POLLING_INTERVAL_MS 60000
87+ #define PORT_PHY_ATTR_FLEX_COUNTER_POLLING_INTERVAL_MS 10000
8788#define QUEUE_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS 10000
8889#define QUEUE_WATERMARK_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS 60000
8990#define PG_WATERMARK_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS 60000
@@ -223,6 +224,13 @@ static map<sai_queue_type_t, string> sai_queue_type_string_map =
223224 {SAI_QUEUE_TYPE_UNICAST_VOQ, " SAI_QUEUE_TYPE_UNICAST_VOQ" },
224225};
225226
227+ const vector<sai_port_attr_t > port_phy_attr_ids =
228+ {
229+ SAI_PORT_ATTR_RX_SIGNAL_DETECT, // RX signal detection per lane
230+ SAI_PORT_ATTR_FEC_ALIGNMENT_LOCK, // FEC alignment lock status per lane
231+ SAI_PORT_ATTR_RX_SNR // Receive Signal-to-Noise Ratio per lane
232+ };
233+
226234const vector<sai_port_stat_t > port_stat_ids =
227235{
228236 SAI_PORT_STAT_IF_IN_OCTETS,
@@ -708,6 +716,7 @@ PortsOrch::PortsOrch(DBConnector *db, DBConnector *stateDb, vector<table_name_wi
708716 m_portStateTable(stateDb, STATE_PORT_TABLE_NAME),
709717 m_portOpErrTable(stateDb, STATE_PORT_OPER_ERR_TABLE_NAME),
710718 port_stat_manager(PORT_STAT_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, PORT_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, false ),
719+ port_phy_attr_manager(PORT_PHY_ATTR_FLEX_COUNTER_GROUP, StatsMode::READ, PORT_PHY_ATTR_FLEX_COUNTER_POLLING_INTERVAL_MS, false ),
711720 gb_port_stat_manager(true ,
712721 PORT_STAT_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ,
713722 PORT_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, false ),
@@ -720,6 +729,7 @@ PortsOrch::PortsOrch(DBConnector *db, DBConnector *stateDb, vector<table_name_wi
720729 wred_queue_stat_manager(WRED_QUEUE_STAT_COUNTER_FLEX_COUNTER_GROUP, StatsMode::READ, QUEUE_STAT_FLEX_COUNTER_POLLING_INTERVAL_MS, false ),
721730 counter_managers({
722731 ref (port_stat_manager),
732+ ref (port_phy_attr_manager),
723733 ref (port_buffer_drop_stat_manager),
724734 ref (queue_stat_manager),
725735 ref (queue_watermark_manager),
@@ -1069,6 +1079,9 @@ PortsOrch::PortsOrch(DBConnector *db, DBConnector *stateDb, vector<table_name_wi
10691079 /* Query Path Tracing capability */
10701080 checkPathTracingCapability ();
10711081
1082+ /* Query PORT_PHY_ATTR capabilities */
1083+ queryPortPhyAttrCapabilities ();
1084+
10721085 /* Initialize the stats capability in STATE_DB */
10731086 initCounterCapabilities (gSwitchId );
10741087
@@ -4065,6 +4078,18 @@ void PortsOrch::registerPort(Port &p)
40654078 gb_port_stat_manager.setCounterIdList (p.m_line_side_id ,
40664079 CounterType::PORT, gbport_counter_stats, p.m_switch_id );
40674080 }
4081+ if (flex_counters_orch->getPortPhyAttrCounterState ())
4082+ {
4083+ if (!m_supported_phy_attrs.empty ())
4084+ {
4085+ if (p.m_type == Port::Type::PHY && verifyPortSupportsAllPhyAttr (p.m_port_id , p.m_alias .c_str ()))
4086+ {
4087+ auto port_phy_attr_stats = generateCounterStats (m_supported_phy_attrs, sai_serialize_port_attr);
4088+ port_phy_attr_manager.setCounterIdList (p.m_port_id ,
4089+ CounterType::PORT_PHY_ATTR, port_phy_attr_stats);
4090+ }
4091+ }
4092+ }
40684093 if (flex_counters_orch->getPortBufferDropCountersState ())
40694094 {
40704095 auto port_buffer_drop_stats = generateCounterStats (port_buffer_drop_stat_ids, sai_serialize_port_stat);
@@ -4170,6 +4195,13 @@ void PortsOrch::deInitPort(string alias, sai_object_id_t port_id)
41704195 {
41714196 wred_port_stat_manager.clearCounterIdList (p.m_port_id );
41724197 }
4198+ if (!m_supported_phy_attrs.empty ())
4199+ {
4200+ if (p.m_type == Port::Type::PHY && verifyPortSupportsAllPhyAttr (p.m_port_id , p.m_alias .c_str ()))
4201+ {
4202+ port_phy_attr_manager.clearCounterIdList (p.m_port_id );
4203+ }
4204+ }
41734205
41744206 /* remove port name map from counter table */
41754207 m_counterNameMapUpdater->delCounterNameMap (alias);
@@ -8916,6 +8948,134 @@ void PortsOrch::generatePortBufferDropCounterMap()
89168948 m_isPortBufferDropCounterMapGenerated = true ;
89178949}
89188950
8951+ void PortsOrch::queryPortPhyAttrCapabilities ()
8952+ {
8953+ for (const auto & attr_id : port_phy_attr_ids)
8954+ {
8955+ sai_attr_capability_t capability;
8956+
8957+ sai_status_t status = sai_query_attribute_capability (
8958+ gSwitchId ,
8959+ SAI_OBJECT_TYPE_PORT,
8960+ attr_id,
8961+ &capability
8962+ );
8963+
8964+ auto meta = sai_metadata_get_attr_metadata (SAI_OBJECT_TYPE_PORT, attr_id);
8965+ std::string attr_id_str = std::to_string (attr_id);
8966+ const char * attr_name = meta ? meta->attridname : attr_id_str.c_str ();
8967+
8968+ if (status == SAI_STATUS_SUCCESS && capability.get_implemented )
8969+ {
8970+ m_supported_phy_attrs.push_back (attr_id);
8971+ SWSS_LOG_NOTICE (" PORT_PHY_ATTR: Attribute %s is SUPPORTED for GET" ,
8972+ attr_name);
8973+ }
8974+ else
8975+ {
8976+ SWSS_LOG_NOTICE (" PORT_PHY_ATTR: Attribute %s is NOT supported (status=%d, get_implemented=%d)" ,
8977+ attr_name, status, capability.get_implemented );
8978+ }
8979+ }
8980+ }
8981+
8982+ bool PortsOrch::verifyPortSupportsAllPhyAttr (sai_object_id_t port_id, const char * port_name)
8983+ {
8984+ // Verify port supports ALL SERDES attributes
8985+ // Query with count=0 to check if attribute is supported (expect BUFFER_OVERFLOW)
8986+
8987+ // Check RX_SIGNAL_DETECT
8988+ sai_attribute_t port_attr;
8989+ port_attr.id = SAI_PORT_ATTR_RX_SIGNAL_DETECT;
8990+ port_attr.value .portlanelatchstatuslist .count = 0 ;
8991+ port_attr.value .portlanelatchstatuslist .list = nullptr ;
8992+
8993+ sai_status_t status = sai_port_api->get_port_attribute (port_id, 1 , &port_attr);
8994+ if (status != SAI_STATUS_BUFFER_OVERFLOW)
8995+ {
8996+ SWSS_LOG_ERROR (" PORT_PHY_ATTR: Port %s does not support RX_SIGNAL_DETECT attribute (status=%d)" ,
8997+ port_name, status);
8998+ return false ;
8999+ }
9000+ SWSS_LOG_DEBUG (" PORT_PHY_ATTR: Port %s supports RX_SIGNAL_DETECT attribute (count=%d)" ,
9001+ port_name, port_attr.value .portlanelatchstatuslist .count );
9002+
9003+ // Check FEC_ALIGNMENT_LOCK
9004+ port_attr.id = SAI_PORT_ATTR_FEC_ALIGNMENT_LOCK;
9005+ port_attr.value .portlanelatchstatuslist .count = 0 ;
9006+ port_attr.value .portlanelatchstatuslist .list = nullptr ;
9007+
9008+ status = sai_port_api->get_port_attribute (port_id, 1 , &port_attr);
9009+ if (status != SAI_STATUS_BUFFER_OVERFLOW)
9010+ {
9011+ SWSS_LOG_ERROR (" PORT_PHY_ATTR: Port %s does not support FEC_ALIGNMENT_LOCK attribute (status=%d)" ,
9012+ port_name, status);
9013+ return false ;
9014+ }
9015+ SWSS_LOG_DEBUG (" PORT_PHY_ATTR: Port %s supports FEC_ALIGNMENT_LOCK attribute (count=%d)" ,
9016+ port_name, port_attr.value .portlanelatchstatuslist .count );
9017+
9018+ // Check RX_SNR
9019+ port_attr.id = SAI_PORT_ATTR_RX_SNR;
9020+ port_attr.value .portsnrlist .count = 0 ;
9021+ port_attr.value .portsnrlist .list = nullptr ;
9022+
9023+ status = sai_port_api->get_port_attribute (port_id, 1 , &port_attr);
9024+ if (status != SAI_STATUS_BUFFER_OVERFLOW)
9025+ {
9026+ SWSS_LOG_ERROR (" PORT_PHY_ATTR: Port %s does not support RX_SNR attribute (status=%d)" ,
9027+ port_name, status);
9028+ return false ;
9029+ }
9030+ SWSS_LOG_DEBUG (" PORT_PHY_ATTR: Port %s supports RX_SNR attribute (count=%d)" ,
9031+ port_name, port_attr.value .portsnrlist .count );
9032+ return true ;
9033+ }
9034+
9035+ void PortsOrch::generatePortPhyAttrCounterMap ()
9036+ {
9037+ if (m_supported_phy_attrs.empty ())
9038+ {
9039+ SWSS_LOG_WARN (" PORT_PHY_ATTR: No PHY attributes supported on this platform" );
9040+ return ;
9041+ }
9042+
9043+ auto port_phy_attr_stats = generateCounterStats (m_supported_phy_attrs, sai_serialize_port_attr);
9044+
9045+ for (const auto & it: m_portList)
9046+ {
9047+ if (it.second .m_type == Port::Type::PHY && verifyPortSupportsAllPhyAttr (it.second .m_port_id , it.second .m_alias .c_str ()))
9048+ {
9049+ SWSS_LOG_DEBUG (" PORT_PHY_ATTR: Setting counter ID list for port %s" ,
9050+ it.second .m_alias .c_str ());
9051+
9052+ port_phy_attr_manager.setCounterIdList (it.second .m_port_id ,
9053+ CounterType::PORT_PHY_ATTR, port_phy_attr_stats);
9054+ }
9055+ }
9056+ }
9057+
9058+ void PortsOrch::clearPortPhyAttrCounterMap ()
9059+ {
9060+ for (const auto & it: m_portList)
9061+ {
9062+ // Clear counter stats only for PHY ports that were previously configured
9063+ if (it.second .m_type != Port::Type::PHY)
9064+ {
9065+ continue ;
9066+ }
9067+
9068+ SWSS_LOG_DEBUG (" PORT_PHY_ATTR: Clearing counter ID list for port %s" , it.second .m_alias .c_str ());
9069+
9070+ port_phy_attr_manager.clearCounterIdList (it.second .m_port_id );
9071+ }
9072+ }
9073+
9074+ const std::vector<sai_port_attr_t >& PortsOrch::getPortPhyAttrIds () const
9075+ {
9076+ return port_phy_attr_ids;
9077+ }
9078+
89199079/* ***
89209080* Func Name : generateWredPortCounterMap
89219081* Parameters : None
0 commit comments