Skip to content

Commit d189ce6

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, set speed=0, and return false - In refresh_port_oper_speed(), set attr.value.u32=0 (unknown) instead of returning SAI_STATUS_FAILURE - When m_useConfiguredSpeedAsOperSpeed is true, configured speed is used as oper speed (bypassing sysfs entirely) This ensures VS ports show 0 (unknown) rather than garbage values on virtual NICs. With the companion sai.profile change (#25428), VS ports will show the correct configured speed. 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 when vs_get_oper_speed fails (no TAP device) Signed-off-by: Rustiqly <rustiqly@users.noreply.github.com>
1 parent 6519cf9 commit d189ce6

File tree

5 files changed

+231
-3
lines changed

5 files changed

+231
-3
lines changed

tests/aspell.en.pws

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,3 +495,8 @@ SNR
495495
tparam
496496
ICMP
497497
UDP
498+
NIC
499+
NICs
500+
oper
501+
sysfs
502+
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+
* reports 0 instead of a bogus value.
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 report 0 when sysfs is unavailable
760+
ASSERT_EQ(sw.refresh_port_oper_speed(port_id), SAI_STATUS_SUCCESS);
761+
762+
// Verify oper speed is 0 (no valid sysfs speed, no fallback to configured)
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)0);
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: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2659,7 +2659,10 @@ sai_status_t SwitchStateBase::refresh_port_oper_speed(
26592659
}
26602660
else if (!vs_get_oper_speed(port_id, attr.value.u32))
26612661
{
2662-
return SAI_STATUS_FAILURE;
2662+
// Report 0 when sysfs speed is unavailable/invalid
2663+
// (e.g. virtio NICs report -1 for speed in sysfs)
2664+
2665+
attr.value.u32 = 0;
26632666
}
26642667
}
26652668

vslib/SwitchStateBaseHostif.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -906,9 +906,23 @@ 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+
speed = 0;
920+
921+
return false;
922+
}
923+
924+
speed = static_cast<uint32_t>(speed_value);
925+
912926
return true;
913927
}
914928

0 commit comments

Comments
 (0)