Claus-Theodor Riegg
9 years
Andreas Vöst
2 years
Stefan Langenmaier
3 years
Claus-Theodor Riegg
8 years
Andreas Vöst
2 years
Claus-Theodor Riegg
10 years
Marc Dierig
2 years
Andreas Vöst
2 years
Claus-Theodor Riegg
6 years
Claus-Theodor Riegg
10 years
Emma Heinle
1 year

Slow downloads on Linux when connected via Ethernet and WiFi at the same time (ARP Flux)

Posted . Visible to the public.

Problem

Your laptop is connected via Ethernet (e.g. through a dock) and Wi-Fi at the same time, and both connections are in the same network. IPv4 transfers are much slower than the wired link should allow, or the speed varies a lot.

Typical signs:

  • ip route get <remote-ip> shows the wired interface, but the interface counters show that most of the downloaded data arrives on the Wi-Fi interface.
  • Turning Wi-Fi off makes the transfer fast immediately.
  • Right after turning Wi-Fi off, new connections may hang for a short time.
  • IPv6 traffic is usually not affected.

To check which interface actually receives the data, compare the receive counters before and after
a download:

cat /sys/class/net/<wired-if>/statistics/rx_bytes /sys/class/net/<wifi-if>/statistics/rx_bytes

You can see the cause directly by capturing ARP traffic for the IP address of your wired interface:

sudo tcpdump -eni any 'arp and host <wired-ip>'

If the problem is present, both interfaces answer the router's request, and the Wi-Fi interface
answers with its own MAC address:

<wired-if> Out ... Reply <wired-ip> is-at <wired-mac>
<wifi-if>  Out ... Reply <wired-ip> is-at <wifi-mac>

Cause

By default, Linux answers ARP requests for any of its local IP addresses on any interface (arp_ignore=0). When both interfaces are in the same network, they both receive the router's ARP request for the wired IP address, and both reply. The router stores the reply it receives last. That is usually the one sent over Wi-Fi, because Wi-Fi is slower to deliver it. As a result, outgoing traffic leaves through the cable, but incoming traffic comes back over Wi-Fi.

Solution

Configure the kernel so that each interface answers ARP requests only for its own IP address, and uses only its own IP address as the sender in ARP requests:

# Save the current values
sysctl net.ipv4.conf.all.arp_ignore net.ipv4.conf.all.arp_announce | tee ~/arp-sysctl-before.txt

# Apply immediately
sudo sysctl -w net.ipv4.conf.all.arp_ignore=1 net.ipv4.conf.all.arp_announce=2

# Keep the setting after a reboot
printf 'net.ipv4.conf.all.arp_ignore = 1\nnet.ipv4.conf.all.arp_announce = 2\n' \
  | sudo tee /etc/sysctl.d/60-arp-flux.conf

For both settings, the kernel uses the higher of the value for all and the value for the interface. Setting all is therefore enough, and it also covers interfaces that appear later, e.g. when you plug in a dock.

The router may still have the Wi-Fi MAC address stored for a short while. It is replaced the next time the router refreshes its ARP entry, usually within seconds to a few minutes.

Revert

sudo rm /etc/sysctl.d/60-arp-flux.conf
sudo sysctl -w net.ipv4.conf.all.arp_ignore=0 net.ipv4.conf.all.arp_announce=0

Use the values from ~/arp-sysctl-before.txt if they were not 0.

Profile picture of Emma Heinle
Emma Heinle
License
Source code in this card is licensed under the MIT License.