Évolution des performances de la table de routage sous Linux
Vincent Bernat
Dans des articles précédents, j’ai expliqué comment le noyau Linux gérait les tables de routage IPv4[1] et IPv6[2]. J’ai suivi l’évolution des performances de recherche entre Linux 2.6.32 et 4.16 pour IPv4[3], avec l’impact des mitigations contre Meltdown et Spectre[4], ainsi qu’entre Linux 2.6.39 et 4.18 pour IPv6[5]. Cet article met à jour ces chiffres jusqu’à Linux 7.3 et expose les responsables de chaque régression ! 🕵️♂️
J’ai mesuré les performances sur un AMD EPYC 8024P[6], un processeur Zen 4c[7] loué à Scaleway[8] tournant à 2,4 GHz sans le mode turbo. J’ai compilé les noyaux avec GCC 10.2 : cette version convient à la fois aux noyaux les plus anciens et aux plus récents.
IPv6#
J’ai testé quatre scénarios :
- une vue complète et récente avec environ 260 000 préfixes ;
- une vue complète datant de 2017 avec environ 40 000 préfixes ;
- un ensemble de 40 000 préfixes /48 organisés de façon à obtenir un résultat deux fois sur trois ;
- un ensemble de 40 000 préfixes /128 choisis aléatoirement de façon à ce qu’une recherche sur 400 réussisse.
Pour Linux 4.15, Wei Wang a remplacé le verrou par du RCU et un verrou tournant dans le commit 66f5d6ce53e6[9]. Pour Linux 4.18, David Ahern a amélioré les structures de données impliquées dans la recherche[10]. Pour Linux 5.9, Brian Vazquez a retiré des appels indirects coûteux dans le commit 55cced4f813b[11].
L’importante régression de 200 ns introduite dans Linux 6.5 a balayé toutes
ces améliorations. Cette version implémente une mitigation pour la vulnérabilité
« Speculative Return Stack Overflow[12] », affectant les processeurs AMD,
dans le commit fb3bd914b3ec[13]. Cette mitigation ajoute environ 20 cycles à
chaque retour de fonction. Elle a ensuite été portée sur des noyaux plus anciens
(5.10, 5.15, 6.1 et 6.4). Pour rendre les résultats plus lisibles, je l’ai
désactivée pour ces versions via l’option spec_rstack_overflow=off.
Vous pouvez consulter les vulnérabilités impactant votre processeur et les
mitigations appliquées avec la commande lscpu. Certaines mitigations dépendent
du microcode et du micrologiciel1.
$ 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#
J’ai testé trois scénarios :
- une vue complète et récente avec plus de 1 000 000 de préfixes ;
- un sous-ensemble d’une vue complète de 2017 avec 500 000 préfixes ;
- un ensemble de 500 000 préfixes /32 contigus.
L’impact de 30 ns dû à la mitigation de SRSO dans Linux 6.5 est plus petit que pour IPv6 car la recherche d’une route IPv4 traverse moins de fonctions : environ 4 pour IPv4 et 25 pour IPv6.
Dans Linux 5.11, j’ai introduit une régression dans le commit
c0c5a60f0f13[17] après avoir corrigé le comportement de
net.ipv4.conf.all.ignore_routes_with_linkdown2 ! En conséquence, la
fonction ip_ignore_linkdown()[18] dépense 5 cycles
supplémentaires pour répondre car elle doit suivre trois pointeurs
supplémentaires. La fonction fib_lookup()[19] l’appelle dans le
code suivant[20] :
if (ip_ignore_linkdown(nhc->nhc_dev) &&
nhc->nhc_flags & RTNH_F_LINKDOWN &&
!(fib_flags & FIB_LOOKUP_IGNORE_LINKSTATE))
return false;
En changeant l’ordre des conditions, nous pouvons éviter l’appel à
ip_ignore_linkdown() dans la majorité des cas où le lien n’est pas inactif :
if (nhc->nhc_flags & RTNH_F_LINKDOWN &&
!(fib_flags & FIB_LOOKUP_IGNORE_LINKSTATE) &&
ip_ignore_linkdown(nhc->nhc_dev))
return false;
Voici la distribution des temps de recherche avant d’appliquer ce correctif[22] au-dessus de net-next3 :
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
La nuance de gris la plus claire représente la fonction de répartition. Après l’application du correctif, la médiane s’est améliorée de 132 à 126 cycles4 :
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 des mitigations#
Pour réduire l’impact des mitigations, vous pouvez les désactiver avec
mitigations=off, n’en désactiver qu’une seule avec
spec_rstack_overflow=off ou vous protéger à partir de Linux 6.17 d’un ensemble
de vecteurs d’attaque[23] avec mitigations=auto,no_user_kernel.
L’impact varie fortement selon le processeur. Par exemple, sur un Xeon W-2295[24], un processeur Intel de 2020 orienté bureautique, l’impact des mitigations est de seulement quelques cycles pour IPv4 et moins de 3 % pour IPv6. La mitigation qui ralentit le plus est celle pour la vulnérabilité « Indirect Target Selection[25] » qui a été corrigée avec l’architecture Sapphire Rapids[26].
En mettant de côté les régressions introduites par les mitigations des attaques contre les processeurs[27], les performances d’IPv4 ont décliné lentement tandis que celles d’IPv6 se sont améliorées avant de se stabiliser. Si les performances de routage sont importantes, vous avez plusieurs possibilités :
- choisir un processeur différent tel qu’un AMD Zen 5[28], un Xeon de quatrième génération[26] ou peut-être un ARM Neoverse V2[29] ;
- désactiver partiellement ou totalement les mitigations ;
- contourner le routage avec XDP/eBPF5 ;
- déléguer le routage[30] à la carte réseau.
- https://vincent.bernat.ch/fr/blog/2017-ipv4-table-routage-linux
- https://vincent.bernat.ch/fr/blog/2017-ipv6-table-routage-linux
- https://vincent.bernat.ch/fr/blog/2017-progres-ipv4-table-routage-linux
- https://meltdownattack.com/
- https://vincent.bernat.ch/fr/blog/2017-progres-ipv6-table-routage-linux
- https://www.amd.com/en/products/processors/server/epyc/4th-generation-9004-and-8004-series/amd-epyc-8024p.html
- https://fr.wikipedia.org/wiki/Zen_4#Zen_4c
- https://www.scaleway.com/fr/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/