Performance evolution of route lookup on Linux
In previous articles, I explained how the Linux kernel implements IPv4 and IPv6 routing tables, and I showed the performance improvement of route lookups from Linux 2.6.32 to 4.16 for IPv4—including the impact of the Meltdown and Spectre mitigations—as well as from Linux 2.6.39 to 4.18 for IPv6. This article updates the numbers through Linux 7.3 and investigates the perpetrator responsible for the performance regressions! 🕵️♂️
I ran the following benchmarks on an AMD EPYC 8024P, a Zen 4c CPU, rented from Scaleway, running at 2.4 GHz with CPU boost disabled. I compiled the kernels with GCC 10.2: this version can compile older kernels as well as the current ones.
IPv6
I tested four scenarios:
- a recent full view with about 260,000 prefixes,
- a full view from 2017 with about 40,000 prefixes,
- a set of 40,000 /48 prefixes, such that 2 lookups out of 3 match, and
- a set of 40,000 random /128 prefixes, such that 1 lookup out of 400 matches.
In Linux 4.15, Wei Wang improved the lookup performance by replacing the read-write lock with an RCU and a spinlock in commit 66f5d6ce53e6. In Linux 4.18, David Ahern improved the data structures used by route lookup. In Linux 5.9, Brian Vazquez removed expensive indirect calls in commit 55cced4f813b.
The major 200 ns regression introduced in Linux 6.5 wiped out all these
improvements. This version implements a mitigation for "Speculative Return
Stack Overflow," a vulnerability affecting AMD processors, in commit
fb3bd914b3ec. This mitigation adds about 20 cycles on each function return.
It was backported to older kernels (5.10, 5.15, 6.1, and 6.4). To keep the
results legible, I disabled the mitigation for these versions with
spec_rstack_overflow=off on the kernel command-line.
You can check the vulnerabilities impacting your CPU and their mitigations with
lscpu. Some mitigations may depend on the microcode or on the
firmware.1
$ lscpu | grep '^Vuln'
Vulnerability Gather data sampling: Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit: Not affected
Vulnerability L1tf: Not affected
Vulnerability Mds: Not affected
Vulnerability Meltdown: Not affected
Vulnerability Mmio stale data: Not affected
Vulnerability Reg file data sampling: Not affected
Vulnerability Retbleed: Not affected
Vulnerability Spec rstack overflow: Mitigation; Safe RET
Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Vulnerability Spectre v2: Mitigation; Retpolines; IBPB conditional; IBRS_FW; STIBP always-on; RSB filling; PBRSB-eIBRS Not affected; BHI Not affected
Vulnerability Srbds: Not affected
Vulnerability Tsa: Vulnerable: Clear CPU buffers attempted, no microcode
Vulnerability Tsx async abort: Not affected
Vulnerability Vmscape: Mitigation; IBPB before exit to userspace
IPv4
I tested three scenarios:
- a recent full view with more than 1,000,000 prefixes,
- a subset of a full view from 2017 with 500,000 prefixes, and
- a set of 500,000 contiguous /32 prefixes.
The 30 ns impact of the mitigation for SRSO in Linux 6.5 is smaller than for IPv6 because IPv4 route lookups traverse fewer functions: around 4 function calls for IPv4 compared to 25 for IPv6.
In Linux 5.11, I introduced a regression in commit c0c5a60f0f13 after
fixing the behavior of net.ipv4.conf.all.ignore_routes_with_linkdown!2
As a result, the ip_ignore_linkdown() function spends
around 5 additional cycles to return a result as it needs to follow three
additional pointers. fib_lookup() eventually calls it in the
following code:
if (ip_ignore_linkdown(nhc->nhc_dev) &&
nhc->nhc_flags & RTNH_F_LINKDOWN &&
!(fib_flags & FIB_LOOKUP_IGNORE_LINKSTATE))
return false;
If we reorder the conditions, we avoid calling ip_ignore_linkdown() for the
most common case where the link isn't down:
if (nhc->nhc_flags & RTNH_F_LINKDOWN &&
!(fib_flags & FIB_LOOKUP_IGNORE_LINKSTATE) &&
ip_ignore_linkdown(nhc->nhc_dev))
return false;
Here's the distribution of lookup times before applying the patch on top of net-next:3
min=128 max=4657 count=994104 95th=134 90th=133 50th=132 mad=0
value │ ┊ count
128 │ 120
129 │ 2232
130 │▒ 25224
131 │▒▒▒▒▒▒▒▒▒▒▒▒▒░ 264264
132 │▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░ 516480
133 │▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 126864
134 │▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 21624
The lighter shade depicts the cumulative distribution function. After applying the patch, the median improved from 132 to 126 cycles:4
min=124 max=208839 count=994104 95th=128 90th=127 50th=126 mad=0
value │ ┊ count
124 │ 576
125 │▒▒ 49440
126 │▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░ 584904
127 │▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 284592
128 │▒▒░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ 45288
Impact of mitigations
To reduce the impact of mitigations, you can disable all of them with
mitigations=off, disable only a specific one like with
spec_rstack_overflow=off, or protect against only some attack vectors with
mitigations=auto,no_user_kernel, starting from Linux 6.17.
The impact is also quite different depending on the CPU. For example, on a Xeon W-2295, an Intel desktop CPU from 2020, the impact of the mitigations is only a few cycles for IPv4, and less than 3% for IPv6. The main contributor is the mitigation for the Indirect Target Selection vulnerability, which is fixed since the Sapphire Rapids architecture.
If we set aside the regressions introduced by the mitigations against CPU attacks, the performance of IPv4 is declining slowly over time while IPv6 has improved in the past and is currently stable. If routing performance is important, you have several options: choose a different CPU like an AMD Zen 5 CPU, a fourth generation Xeon CPU, or maybe an ARM Neoverse V2; disable some or all the mitigations; bypass routing with XDP/eBPF;5 or offload routing to the network card.
Note
Maytham Alsudany reviewed a first draft of this article. Any errors are still mine!
-
The microcode was out of date on my machine as I forgot to install the
amd64-microcodepackage. As it only impacts TSA, our benchmark is unaffected. Spectre v2 mitigation did not enable automatic IBRS, because of SEV-SNP being enabled in the firmware. With automatic IBRS, the impact of SRSO should be smaller. ↩ -
Despite
ipvXin its title, the commit only changes the behavior of the IPv4 code. The IPv6 version overwrites the value of each device inaddrconf_fixup_linkdown(). ↩ -
Linux 7.5 will be the first stable release including this fix. ↩
-
At 2.4 GHz, one cycle is about 0.42 ns. ↩
-
This requires avoiding
bpf_fib_lookup(), which relies on the same kernel lookup. ↩
09 November, 2026 08:07PM by Vincent Bernat

















