Tailscale version 1.54 or later used with OpenWrt 24.10 or later (which uses kernel 6.6) enables UDP throughput improvements via transport layer offloading.
Namely, tuning two features may show improved throughput:
rx-udp-gro-forwarding
: Enables UDP Generic Receive Offload (GRO) forwarding, which aggregates incoming UDP packets to reduce CPU overhead on receive.rx-gro-list
: If disabled (off), it prevents multiple flows from being aggregated simultaneously which simplifies flow handling and performance on some workloads.
Note
These changes should be applied to the physical device(s) which will actually be performing the UDP encapsulation of tailscale traffic.
- Install
ethtool
opkg update
opkg install ethtool
- Apply the changes:
Note
Substitute eth1
below for the device that routes your Tailscale traffic. In most configurations, this is your WAN device.
ethtool -K eth1 rx-gro-list off
ethtool -K eth1 rx-udp-gro-forwarding on
- Test the changes before and after before committing them permanently with something similar to the following commands.
You want to verify:
- Packet aggregation is working as measured by reduced packets/sec on the wire with GRO enabled (verify with tools like:
ethtool -S <interface> | grep udp
ornetstat -su
) - CPU usage is reduced. Lower CPU usage on the receiver compared to the same test with
rx-udp-gro-forwarding
turned off - High throughput is achieved near line rate (e.g., 1 Gbps, 10Gbps, etc) without packetloss.
Note
You will need the iperf3
package installed for this. The sender side flags below are just a suggestion. Full iperf3
usage is outside the scope of this document.
Receiver
iperf3 --server
Sender
iperf3 --client <remote_addr> --udp --bitrate 1G --length 1400 --time 10
If you're satisfied with the results and want it to persist across reboots.
- Create
/etc/config/ethtool
ether using uci or by creating the file manually. The following example will useuci
:
Note
Substitute eth1
below for the device that routes your Tailscale traffic. In most configurations, this is your WAN device.
touch /etc/config/ethtool
uci set ethtool.eth1=device
uci set ethtool.eth1.rx_gro_list='off'
uci set ethtool.eth1.rx_udp_gro_forwarding='on'
uci commit
- Create the following file in
/etc/hotplug.d/iface/90-ethtool
#!/bin/sh
# shellcheck disable=SC3043
#
# Author: Josh Enders <[email protected]>
# License: CC BY-NC 4.0
# https://gist.github.com/joshenders/1baa9de07c1b7af489f14c30d4667e40
[ "${ACTION}" = "ifup" ] || exit 0
# shellcheck source=/dev/null
. /lib/functions.sh
config_load ethtool
log_crit() { logger -t "$0" -p crit "$1"; }
log_info() { logger -t "$0" -p info "$1"; }
apply_settings() {
local config feature ifname option value
ifname="$1"
config=$(uci show ethtool."${ifname}" | sed -n "s/^ethtool.${ifname}\.\([^=]*\)=.*/\1/p")
for option in ${config}; do
config_get value "${ifname}" "${option}"
feature=$(echo "${option}" | tr '_' '-')
if [ -n "${value}" ]; then
{
ethtool -K "${ifname}" "${feature}" "${value}" \
&& log_info "${feature} set to ${value} on ${ifname}";
} || log_crit "Failed to set ${feature} to ${value} on ${ifname}"
else
log_crit "Failed to set ${feature} to ${value} on ${ifname}"
fi
done
}
config_foreach apply_settings device
- Append
/etc/hotplug.d/iface/90-ethtool
to/etc/sysupgrade.conf
to preserve this file during upgrades.
echo '/etc/hotplug.d/iface/90-ethtool' >> /etc/sysupgrade.conf
In your
/etc/config/network
, thewan
interface is using theeth0
device:I don’t have an easy way to test this but I’m somewhat skeptical the hotplug drop-in will ever run if you define:
Are there
ifup
hotplug events for those? Is thewan
interface in Linux just an alias of the parent device and does ethtool reference or resolve that the settings need to be applied to the parent interface? Honestly, I’m not sure.Have you tested rebooting and verifying the ethtool settings are being properly set?
In your case, (imho) irregardless of all the interface aliasing sugar that OpenWrt does to simplify configuration, the ethtool settings should probably be applied to the
eth0
interface as that’s the actual physical device of your ppoe connection.That’s being said, your feedback is really helpful. If there could ever be a
-
in the device name, my drop-in will fail as it did for you. I’ll go ahead and add a utility function to transform the device name into a uci-safe value. There may even be an existing helper function in/lib/functions.sh
.