The ETHTOOL_GSET ioctl can report the speed as -1 (SPEED_UNKNOWN)
while the link is down or autonegotiating. The value passes the
nonzero check and is latched until the next update, up to 2^minpoll
seconds after the link is back up, corrupting the RX timestamp
correction of packets received in that interval (-752 us instead of
+7.5 us for a 94-octet frame at 100 Mb/s).
Ignore non-positive speeds to keep the last known speed.
---
Notes:
This is the same shape as the recently merged "socket: ignore zero
if_index in timestamping pktinfo": a kernel value that can mean
"unknown" consumed as data. It was verified on the same system
(BeagleBone Black, cpsw, SMSC LAN8710 PHY polled with no link
interrupt, Linux 6.6.58, 100 Mb/s full duplex).
Measurements from that system:
- A loop making the same ETHTOOL_GSET ioctl as
update_interface_speed() read a steady 100. Across seven
autonegotiation restarts forced with ethtool -r, it returned
0xffffffff (-1 as int) for 2 to 3 seconds each time, bracketed by
valid readings on both sides. No packets were received while it
read -1 (the link is really down); with continuous 200 packet/s
UDP traffic, the first packet with a valid HW receive timestamp
arrived 157 ms after the last -1 reading.
- A debug chronyd latched the value, logging "Updated speed of
eth0 to -1 Mb/s": reading the PHC does not need the link, so the
speed polling continues through the outage.
- The corruption, measured at the protocol level with chronyd
serving NTP queries at 50/s (hwtimestamp minpoll 2 to widen the
update gate): after one restart, 22 consecutive replies over
0.46 s carried receive timestamps offset by -761 us on average,
against a baseline jitter within +-60 us (nominal -752 us for
the 94-octet frames), starting after the link was back up and
ending at the next speed update. After another restart there was
no corruption: the 4-second poll interval sampled past the
3-second window, so a link event corrupts timestamps only if a
poll lands inside its window.
Guarding at the extraction keeps the last known speed, which seemed
preferable to testing for a positive speed at the use site (that
would leave the -1 stored and skip the correction entirely, keeping
the +7.5 us transposition error) or to dropping the HW timestamp
(valid timestamps would be discarded for up to 2^minpoll seconds
after every link event). A real speed change during the window still
corrects at the stale speed for up to 2^minpoll seconds, but that
staleness is inherent to the polling design and bounded by the
transposition time at the slower speed.
ntp_io_linux.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/ntp_io_linux.c b/ntp_io_linux.c
index 3144246..91ff766 100644
--- a/ntp_io_linux.c
+++ b/ntp_io_linux.c
@@ -333,6 +333,10 @@ update_interface_speed(struct Interface *iface)
link_speed = ethtool_cmd_speed(&cmd);
+ /* Ignore an unknown speed to keep the last known value */
+ if (link_speed <= 0)
+ return;
+
if (iface->link_speed != link_speed) {
iface->link_speed = link_speed;
DEBUG_LOG("Updated speed of %s to %d Mb/s", iface->name, link_speed);
--
2.43.0
--
To unsubscribe email [email protected] with "unsubscribe"
in the subject.
For help email [email protected] with "help" in the
subject.
Trouble? Email [email protected].