I have an x86 mini PC (with an i5-4200U CPU) running OpenWrt 23.05 on bare metal. The CPU has two physical cores and four threads.
I have a symmetric 1Gb fibre internet connection, and until recently I was with an ISP who used simple DHCP / IPoE, and I could easily get the full 1Gb download and upload bandwidth.
In February I switched to a different ISP which uses PPPoE, and with default settings my router cannot attain the full 1Gb download speed - it tops out at about 800-850Mbps. The issue appears to be PPPoE encapsulation.
The NICs in my router have two RX and two TX hardware queues, and my (fairly limited) understanding is that the NIC attempts to distribute packets (and the associated interrupts) between the queues based on a hash calculated from certain properties of the packet - e.g. for TCPv4 packets the hash is calculated from the source and destination IP addresses and ports.
To calculate the hash, the NIC driver extracts the relevant values from the packets at known byte offsets. With my old DHCP ISP this worked as expected, with interrupts for incoming packets being distributed fairly evenly between the RX queues on CPUs 0 and 1.
I believe the problem is that PPPoE encapsulation means that the IPs and port numbers are not at the expected offsets in the incoming packets, so the NIC driver's hash function doesn't work properly. The end result appears to be that all of the interrupts (and presumably further processing of the packet) happen on one RX queue, on CPU 0, and this CPU doesn't have enough grunt on its own to achieve a gigabit download transfer rate.
Uploads are not affected - packets are distributed between the RX and TX queues on all other physical interfaces as expected, and my upload transfer rate is absolutely fine.
I have been reading around this topic for some time, but I couldn't find a way to address this problem. The offsets used by the NIC driver's hash function cannot be changed, irqbalance
just switches the problem to a different CPU, and enabling packet steering in the OpenWrt GUI doesn't make any noticeable difference. I also tried manually enabling Receive Packet Steering (RPS) on my physical WAN interface (eth0
), but this didn't help either.
However, yesterday I finally found something that does seem to help. I manually enabled RPS on the pppoe-wan
virtual interface (which has a single RX queue), like this:
echo e > /sys/class/net/pppoe-wan/queues/rx-0/rps_cpus
(CPUs 1, 2, and 3 => 1110 = 8 + 4 + 2 + 0 = 14 = 0xe)
I think this means that packets on the pppoe-wan
interface will be processed on CPUs 1, 2, and 3 - i.e. every CPU apart from CPU 0, which handles the RX interrupts for the underlying WAN hardware device eth0
.
With this setting in place I can now achieve the full gigabit transfer rate on downloads (~940Mbps), so this seems to work
My question is: is this actually the "correct" thing to do in this scenario? I can't find any information in this forum or elsewhere about anyone else having done this, and the script that implements the packet steering option in the OpenWrt GUI (/usr/libexec/network/packet-steering.sh
) seems to explicitly ignore virtual interfaces such as pppoe-wan
(I don't know why).
If this is the right thing to do, should the OpenWrt packet steering option be updated to do this automatically?