Skip to content

Commit 1b69b8e

Browse files
committed
[vslib] Fix VS SAI reporting 0xFFFFFFFF oper speed for virtio NICs
When running on KVM/virtio, /sys/class/net/ethN/speed returns -1 (unknown). vs_get_oper_speed() reads this into uint32_t, which wraps to 4294967295 (0xFFFFFFFF) and gets reported as the oper speed. Fix: - Read sysfs speed as int32_t and check for <= 0 (invalid) - When invalid, log a warning and return false - In refresh_port_oper_speed(), fall back to SAI_PORT_ATTR_SPEED (configured speed) instead of returning SAI_STATUS_FAILURE This ensures VS ports show the correct configured speed (e.g. 40G) rather than garbage values on virtual NICs. Added unit tests: - test_refresh_port_oper_speed_configured_speed: verifies oper speed equals configured speed when m_useConfiguredSpeedAsOperSpeed=true - test_refresh_port_oper_speed_down_port: verifies oper speed is 0 for operationally down ports - test_refresh_port_oper_speed_fallback_no_tap: verifies fallback to configured speed when vs_get_oper_speed fails (no TAP device) Signed-off-by: Rustiqly <[email protected]>
1 parent 6f06210 commit 1b69b8e

File tree

5 files changed

+230
-3
lines changed

5 files changed

+230
-3
lines changed

tests/aspell.en.pws

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,3 +490,8 @@ IPFix
490490
ipfix
491491
SNR
492492
tparam
493+
NIC
494+
NICs
495+
oper
496+
sysfs
497+
virtio

unittest/vslib/TestSwitchBCM56850.cpp

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,3 +561,206 @@ TEST(SwitchBCM56850, test_port_autoneg_fec_override_support)
561561
EXPECT_EQ(attr_capability.set_implemented, false);
562562
EXPECT_EQ(attr_capability.get_implemented, false);
563563
}
564+
565+
TEST(SwitchBCM56850, test_refresh_port_oper_speed_configured_speed)
566+
{
567+
/*
568+
* Test that refresh_port_oper_speed returns the administratively
569+
* configured port speed when m_useConfiguredSpeedAsOperSpeed is true,
570+
* i.e., it propagates SAI_PORT_ATTR_SPEED to SAI_PORT_ATTR_OPER_SPEED
571+
* without consulting sysfs.
572+
*/
573+
574+
auto sc = std::make_shared<SwitchConfig>(0, "");
575+
auto signal = std::make_shared<Signal>();
576+
auto eventQueue = std::make_shared<EventQueue>(signal);
577+
578+
sc->m_saiSwitchType = SAI_SWITCH_TYPE_NPU;
579+
sc->m_switchType = SAI_VS_SWITCH_TYPE_BCM56850;
580+
sc->m_bootType = SAI_VS_BOOT_TYPE_COLD;
581+
sc->m_useTapDevice = false;
582+
sc->m_laneMap = LaneMap::getDefaultLaneMap(0);
583+
sc->m_eventQueue = eventQueue;
584+
sc->m_useConfiguredSpeedAsOperSpeed = true;
585+
586+
auto scc = std::make_shared<SwitchConfigContainer>();
587+
588+
scc->insert(sc);
589+
590+
SwitchBCM56850 sw(
591+
0x2100000000,
592+
std::make_shared<RealObjectIdManager>(0, scc),
593+
sc);
594+
595+
sai_attribute_t attr;
596+
597+
attr.id = SAI_SWITCH_ATTR_INIT_SWITCH;
598+
attr.value.booldata = true;
599+
600+
ASSERT_EQ(sw.initialize_default_objects(1, &attr), SAI_STATUS_SUCCESS);
601+
602+
// Get the port list
603+
sai_object_id_t port_list[64];
604+
605+
attr.id = SAI_SWITCH_ATTR_PORT_LIST;
606+
attr.value.objlist.count = 64;
607+
attr.value.objlist.list = port_list;
608+
609+
ASSERT_EQ(sw.get(SAI_OBJECT_TYPE_SWITCH, "oid:0x2100000000", 1, &attr), SAI_STATUS_SUCCESS);
610+
ASSERT_GT(attr.value.objlist.count, (uint32_t)0);
611+
612+
auto port_id = port_list[0];
613+
auto sport = sai_serialize_object_id(port_id);
614+
615+
// Set port oper status to UP so refresh_port_oper_speed uses configured speed path
616+
attr.id = SAI_PORT_ATTR_OPER_STATUS;
617+
attr.value.s32 = SAI_PORT_OPER_STATUS_UP;
618+
ASSERT_EQ(sw.set(SAI_OBJECT_TYPE_PORT, sport, &attr), SAI_STATUS_SUCCESS);
619+
620+
// Set configured speed to 40000
621+
attr.id = SAI_PORT_ATTR_SPEED;
622+
attr.value.u32 = 40000;
623+
ASSERT_EQ(sw.set(SAI_OBJECT_TYPE_PORT, sport, &attr), SAI_STATUS_SUCCESS);
624+
625+
// Call refresh_port_oper_speed — with m_useConfiguredSpeedAsOperSpeed=true,
626+
// it should use configured speed (40000) instead of querying sysfs
627+
ASSERT_EQ(sw.refresh_port_oper_speed(port_id), SAI_STATUS_SUCCESS);
628+
629+
// Verify oper speed matches configured speed
630+
attr.id = SAI_PORT_ATTR_OPER_SPEED;
631+
ASSERT_EQ(sw.get(SAI_OBJECT_TYPE_PORT, sport, 1, &attr), SAI_STATUS_SUCCESS);
632+
EXPECT_EQ(attr.value.u32, (uint32_t)40000);
633+
}
634+
635+
TEST(SwitchBCM56850, test_refresh_port_oper_speed_down_port)
636+
{
637+
/*
638+
* Test that refresh_port_oper_speed returns 0 for ports that are
639+
* operationally down, regardless of configured speed.
640+
*/
641+
642+
auto sc = std::make_shared<SwitchConfig>(0, "");
643+
auto signal = std::make_shared<Signal>();
644+
auto eventQueue = std::make_shared<EventQueue>(signal);
645+
646+
sc->m_saiSwitchType = SAI_SWITCH_TYPE_NPU;
647+
sc->m_switchType = SAI_VS_SWITCH_TYPE_BCM56850;
648+
sc->m_bootType = SAI_VS_BOOT_TYPE_COLD;
649+
sc->m_useTapDevice = false;
650+
sc->m_laneMap = LaneMap::getDefaultLaneMap(0);
651+
sc->m_eventQueue = eventQueue;
652+
653+
auto scc = std::make_shared<SwitchConfigContainer>();
654+
655+
scc->insert(sc);
656+
657+
SwitchBCM56850 sw(
658+
0x2100000000,
659+
std::make_shared<RealObjectIdManager>(0, scc),
660+
sc);
661+
662+
sai_attribute_t attr;
663+
664+
attr.id = SAI_SWITCH_ATTR_INIT_SWITCH;
665+
attr.value.booldata = true;
666+
667+
ASSERT_EQ(sw.initialize_default_objects(1, &attr), SAI_STATUS_SUCCESS);
668+
669+
// Get a port
670+
sai_object_id_t port_list[64];
671+
672+
attr.id = SAI_SWITCH_ATTR_PORT_LIST;
673+
attr.value.objlist.count = 64;
674+
attr.value.objlist.list = port_list;
675+
676+
ASSERT_EQ(sw.get(SAI_OBJECT_TYPE_SWITCH, "oid:0x2100000000", 1, &attr), SAI_STATUS_SUCCESS);
677+
ASSERT_GT(attr.value.objlist.count, (uint32_t)0);
678+
679+
auto port_id = port_list[0];
680+
auto sport = sai_serialize_object_id(port_id);
681+
682+
// Port is down by default — refresh should set oper speed to 0
683+
attr.id = SAI_PORT_ATTR_OPER_STATUS;
684+
attr.value.s32 = SAI_PORT_OPER_STATUS_DOWN;
685+
ASSERT_EQ(sw.set(SAI_OBJECT_TYPE_PORT, sport, &attr), SAI_STATUS_SUCCESS);
686+
687+
// Set configured speed to 40000 (should be ignored for down ports)
688+
attr.id = SAI_PORT_ATTR_SPEED;
689+
attr.value.u32 = 40000;
690+
ASSERT_EQ(sw.set(SAI_OBJECT_TYPE_PORT, sport, &attr), SAI_STATUS_SUCCESS);
691+
692+
ASSERT_EQ(sw.refresh_port_oper_speed(port_id), SAI_STATUS_SUCCESS);
693+
694+
attr.id = SAI_PORT_ATTR_OPER_SPEED;
695+
ASSERT_EQ(sw.get(SAI_OBJECT_TYPE_PORT, sport, 1, &attr), SAI_STATUS_SUCCESS);
696+
EXPECT_EQ(attr.value.u32, (uint32_t)0);
697+
}
698+
699+
TEST(SwitchBCM56850, test_refresh_port_oper_speed_fallback_no_tap)
700+
{
701+
/*
702+
* Test that when m_useConfiguredSpeedAsOperSpeed is false and no TAP
703+
* device exists (vs_get_oper_speed fails), refresh_port_oper_speed
704+
* falls back to configured speed instead of failing.
705+
*/
706+
707+
auto sc = std::make_shared<SwitchConfig>(0, "");
708+
auto signal = std::make_shared<Signal>();
709+
auto eventQueue = std::make_shared<EventQueue>(signal);
710+
711+
sc->m_saiSwitchType = SAI_SWITCH_TYPE_NPU;
712+
sc->m_switchType = SAI_VS_SWITCH_TYPE_BCM56850;
713+
sc->m_bootType = SAI_VS_BOOT_TYPE_COLD;
714+
sc->m_useTapDevice = false;
715+
sc->m_laneMap = LaneMap::getDefaultLaneMap(0);
716+
sc->m_eventQueue = eventQueue;
717+
sc->m_useConfiguredSpeedAsOperSpeed = false;
718+
719+
auto scc = std::make_shared<SwitchConfigContainer>();
720+
721+
scc->insert(sc);
722+
723+
SwitchBCM56850 sw(
724+
0x2100000000,
725+
std::make_shared<RealObjectIdManager>(0, scc),
726+
sc);
727+
728+
sai_attribute_t attr;
729+
730+
attr.id = SAI_SWITCH_ATTR_INIT_SWITCH;
731+
attr.value.booldata = true;
732+
733+
ASSERT_EQ(sw.initialize_default_objects(1, &attr), SAI_STATUS_SUCCESS);
734+
735+
// Get a port
736+
sai_object_id_t port_list[64];
737+
738+
attr.id = SAI_SWITCH_ATTR_PORT_LIST;
739+
attr.value.objlist.count = 64;
740+
attr.value.objlist.list = port_list;
741+
742+
ASSERT_EQ(sw.get(SAI_OBJECT_TYPE_SWITCH, "oid:0x2100000000", 1, &attr), SAI_STATUS_SUCCESS);
743+
ASSERT_GT(attr.value.objlist.count, (uint32_t)0);
744+
745+
auto port_id = port_list[0];
746+
auto sport = sai_serialize_object_id(port_id);
747+
748+
// Set port to UP
749+
attr.id = SAI_PORT_ATTR_OPER_STATUS;
750+
attr.value.s32 = SAI_PORT_OPER_STATUS_UP;
751+
ASSERT_EQ(sw.set(SAI_OBJECT_TYPE_PORT, sport, &attr), SAI_STATUS_SUCCESS);
752+
753+
// Set configured speed
754+
attr.id = SAI_PORT_ATTR_SPEED;
755+
attr.value.u32 = 100000;
756+
ASSERT_EQ(sw.set(SAI_OBJECT_TYPE_PORT, sport, &attr), SAI_STATUS_SUCCESS);
757+
758+
// Without TAP devices, vs_get_oper_speed will fail (no host interface)
759+
// refresh_port_oper_speed should fall back to configured speed
760+
ASSERT_EQ(sw.refresh_port_oper_speed(port_id), SAI_STATUS_SUCCESS);
761+
762+
// Verify oper speed equals configured speed (fallback)
763+
attr.id = SAI_PORT_ATTR_OPER_SPEED;
764+
ASSERT_EQ(sw.get(SAI_OBJECT_TYPE_PORT, sport, 1, &attr), SAI_STATUS_SUCCESS);
765+
EXPECT_EQ(attr.value.u32, (uint32_t)100000);
766+
}

unittest/vslib/TestSwitchBCM81724.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,10 @@ TEST(SwitchBCM81724, refresh_read_only)
147147

148148
attr.id = SAI_PORT_ATTR_OPER_SPEED;
149149

150-
EXPECT_NE(sw.get(SAI_OBJECT_TYPE_PORT, strPortId, 1, &attr), SAI_STATUS_SUCCESS);
150+
// After clearing hostif_info_map, vs_get_oper_speed() fails (no TAP device),
151+
// but refresh_port_oper_speed() now falls back to configured speed instead
152+
// of returning SAI_STATUS_FAILURE (see SwitchStateBase.cpp fix for virtio NICs)
153+
EXPECT_EQ(sw.get(SAI_OBJECT_TYPE_PORT, strPortId, 1, &attr), SAI_STATUS_SUCCESS);
151154

152155
//std::cout << sw.dump_switch_database_for_warm_restart();
153156
}

vslib/SwitchStateBase.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2655,7 +2655,11 @@ sai_status_t SwitchStateBase::refresh_port_oper_speed(
26552655
}
26562656
else if (!vs_get_oper_speed(port_id, attr.value.u32))
26572657
{
2658-
return SAI_STATUS_FAILURE;
2658+
// Fall back to configured speed when oper speed is unavailable
2659+
// (e.g. virtio NICs report -1 for speed in sysfs)
2660+
2661+
attr.id = SAI_PORT_ATTR_SPEED;
2662+
CHECK_STATUS(get(SAI_OBJECT_TYPE_PORT, port_id, 1, &attr));
26592663
}
26602664
}
26612665

vslib/SwitchStateBaseHostif.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -906,9 +906,21 @@ bool SwitchStateBase::vs_get_oper_speed(
906906
return false;
907907
}
908908

909-
ifs >> speed;
909+
int32_t speed_value = 0;
910+
911+
ifs >> speed_value;
910912
ifs.close();
911913

914+
if (speed_value <= 0)
915+
{
916+
SWSS_LOG_WARN("Invalid speed %d read from %s, will use configured speed",
917+
speed_value, veth_speed_filename.c_str());
918+
919+
return false;
920+
}
921+
922+
speed = static_cast<uint32_t>(speed_value);
923+
912924
return true;
913925
}
914926

0 commit comments

Comments
 (0)