Why My Raspberry Pi Had 20% Packet Loss on Gigabit Ethernet
The link looked healthy: 1 Gbit/s, full duplex, no obvious errors. Yet I was losing packets constantly. The culprit turned out to be Energy Efficient Ethernet.
Raspberry Pi · Networking · Troubleshooting
A link that looked completely normal
I ran into this while building Time01, my Raspberry Pi 5 based GNSS time server. Shortly after the first boot, I noticed that the Ethernet connection was behaving strangely. Pings from my Mac to Time01 regularly showed around 15–25% packet loss.
From Time01 to my Ubuntu server I saw roughly 20% loss, and even the local gateway was losing around 16.7% of packets. What made the problem confusing was that the Ethernet interface looked perfectly healthy.
ethtool reported:
Speed: 1000Mb/s
Duplex: Full
Auto-negotiation: on
Link detected: yesThe normal interface statistics did not show an obvious amount of RX errors, carrier errors or collisions either. From the outside, this looked like a perfectly normal Gigabit Ethernet link. Yet the packet loss was very real.
Finding the culprit
After checking the obvious things, I eventually looked at Energy Efficient Ethernet, or EEE. EEE allows an Ethernet link to reduce its power consumption when there is little traffic. Usually this happens completely transparently, but hardware combinations do not always behave perfectly together. On Time01 I checked it with:
sudo ethtool --show-eee eth0
The result was:
EEE status: enabled - active
So I disabled it temporarily:
sudo ethtool --set-eee eth0 eee off
Then I repeated the test. 50 packets transmitted 50 packets received 0% packet loss. Average latency to the gateway was around 0.382 ms. The packet loss had simply disappeared. That was a pretty satisfying moment.
Nothing about the reported link speed had changed. It was still Gigabit Ethernet, still full duplex, and still using the same cable and network path. The only thing I had changed was EEE.
I can't say exactly which low-level interaction between the Raspberry Pi 5 Ethernet hardware and the rest of the network caused it. What I could prove was much simpler: with EEE active the link lost packets, and with EEE disabled it did not.
Making the fix survive a reboot. A manual command was useful for proving the cause, but Time01 is supposed to be an appliance. I did not want to SSH into it and disable EEE again after every reboot.
So I created a small systemd service:
[Unit]
Description=Disable Energy Efficient Ethernet on eth0
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/sbin/ethtool --set-eee eth0 eee off
RemainAfterExit=yesThe service is enabled at boot, which means EEE is automatically disabled whenever Time01 starts. During the final reboot test for Time01, I checked it again:
sudo ethtool --show-eee eth0and got:
EEE status: disabledThe fix had become part of the permanent Time01 configuration.
What I learned
The thing I found most interesting about this problem was how healthy the connection looked at first. 1 Gbit/s. Full duplex. Link detected. No giant pile of interface errors.
If I had only looked at those values, I could easily have concluded that Ethernet was fine and started debugging somewhere completely different. Instead, a simple ping test showed that the connection was absolutely not fine.
It was another reminder that a status such as link up only tells you part of the story. Sometimes the most useful test is still the simplest one: actually send traffic through the system and see what happens.
And now Time01 has one slightly unusual boot service whose entire job is basically:
please don't make the Ethernet energy efficient.