Performance evolution of route lookup on Linux
Vincent Bernat
In previous articles, I explained how the Linux kernel implements IPv4[1] and IPv6[2] routing tables, and I showed the performance improvement of route lookups from Linux 2.6.32 to 4.16 for IPv4[3]—including the impact of the Meltdown and Spectre mitigations[4]—as well as from Linux 2.6.39 to 4.18 for IPv6[5]. 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[6], a Zen 4c CPU[7], rented from Scaleway[8], 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[9]. In Linux 4.18, David Ahern improved the data structures used by route lookup[10]. In Linux 5.9, Brian Vazquez removed expensive indirect calls in commit 55cced4f813b[11].
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[12],” a vulnerability affecting AMD processors, in commit
fb3bd914b3ec[13]. 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[17] after
fixing the behavior of net.ipv4.conf.all.ignore_routes_with_linkdown!2
As a result, the ip_ignore_linkdown()[18] function spends
around 5 additional cycles to return a result as it needs to follow three
additional pointers. fib_lookup()[19] eventually calls it in the
following code[20]:
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[22] 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[23] 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[24], 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[25] vulnerability, which is fixed since the Sapphire Rapids[26] architecture.
If we set aside the regressions introduced by the mitigations against CPU attacks[27], 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[28], a fourth generation Xeon CPU[26], or maybe an ARM Neoverse V2[29]; disable some or all the mitigations; bypass routing with XDP/eBPF;5 or offload routing[30] to the network card.
Note
Maytham Alsudany[32] reviewed a first draft of this article. Any errors are still mine!
- https://vincent.bernat.ch/en/blog/2017-ipv4-route-lookup-linux
- https://vincent.bernat.ch/en/blog/2017-ipv6-route-lookup-linux
- https://vincent.bernat.ch/en/blog/2017-performance-progression-ipv4-route-lookup-linux
- https://meltdownattack.com/
- https://vincent.bernat.ch/en/blog/2017-performance-progression-ipv6-route-lookup-linux
- https://www.amd.com/en/products/processors/server/epyc/4th-generation-9004-and-8004-series/amd-epyc-8024p.html
- https://en.wikipedia.org/wiki/Zen_4#Zen_4c
- https://www.scaleway.com/en/elastic-metal/
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=66f5d6ce53e665477d2a33e8f539d4fa4ca81c83
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0565de29cbd65b378147d36f9642f93a046240dc
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=55cced4f813bece01f96256d96f283b9210d19ee
- https://docs.kernel.org/admin-guide/hw-vuln/srso.html
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fb3bd914b3ec28f5fb697ac55c4846ac2d542855
- https://www.amd.com/en/resources/product-security/bulletin/amd-sb-7029.html
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e7862eda309ecfccc36bb5558d937ed3ace07f3f
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=acaa4b5c4c854b5009f4d4a5395b2609ad0f4937
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c0c5a60f0f1311bcf08bbe735122096d6326fb5b
- https://elixir.bootlin.com/linux/v7.3.1/source/include/linux/inetdevice.h#L265
- https://elixir.bootlin.com/linux/v7.3.1/source/include/net/ip_fib.h#L374
- https://elixir.bootlin.com/linux/v7.3.1/source/net/ipv4/fib_trie.c#L1406
- https://elixir.bootlin.com/linux/v7.3.1/source/net/ipv6/addrconf.c#L940
- https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git/commit/?id=5fe3653f13b9d0549d8e8f6c181cf2dcbc67b06a
- https://docs.kernel.org/admin-guide/hw-vuln/attack_vector_controls.html
- https://www.intel.com/content/www/us/en/products/sku/198011/intel-xeon-w2295-processor-24-75m-cache-3-00-ghz/specifications.html
- https://docs.kernel.org/admin-guide/hw-vuln/indirect-target-selection.html
- https://en.wikipedia.org/wiki/Sapphire_Rapids
- https://docs.kernel.org/admin-guide/hw-vuln/
- https://en.wikipedia.org/wiki/Zen_5
- https://en.wikipedia.org/wiki/ARM_Neoverse#Neoverse_V2
- https://www.gtp-guard.org/articles/5g-upf-pump-up-the-volume/
- https://docs.ebpf.io/linux/helper-function/bpf_fib_lookup/
- https://maytham.aezign.au/