Évolution des performances de la table de routage sous Linux

Vincent Bernat

Dans des ar­ticles pré­cé­dents, j’ai ex­pli­qué com­ment le noyau Li­nux gé­rait les tables de rou­tage IPv4 et IPv6. J’ai suivi l’évo­lu­tion des per­for­mances de re­cherche entre Li­nux 2.6.32 et 4.16 pour IPv4, avec l’im­pact des mi­ti­ga­tions contre Melt­down et Spectre, ainsi qu’entre Li­nux 2.6.39 et 4.18 pour IPv6. Cet ar­ticle met à jour ces chiffres jusqu’à Li­nux 7.3 et ex­pose les res­pon­sables de chaque ré­gression ! 🕵️‍♂️

J’ai me­suré les per­for­mances sur un AMD EPYC 8024P, un pro­ces­seur Zen 4c loué à Sca­le­way tour­nant à 2,4 GHz sans le mode turbo. J’ai com­pilé les noyaux avec GCC 10.2 : cette ver­sion convient à la fois aux noyaux les plus an­ciens et aux plus récents.

IPv6#

Évolution des performances de la recherche dans la table de routage IPv6 entre
Linux 4.14 et Linux 7.3
Évolution des performances de la recherche dans la table de routage IPv6. Les versions avec un astérisque ont la mitigation pour SRSO désactivée.

J’ai testé quatre scénarios :

  • une vue com­plète et ré­cente avec en­vi­ron 260 000 préfixes ;
  • une vue com­plète da­tant de 2017 avec en­vi­ron 40 000 préfixes ;
  • un en­semble de 40 000 pré­fixes /48 or­ga­ni­sés de fa­çon à ob­te­nir un ré­sul­tat deux fois sur trois ;
  • un en­semble de 40 000 pré­fixes /128 choi­sis aléa­toi­re­ment de fa­çon à ce qu’une re­cherche sur 400 réussisse.

Pour Li­nux 4.15, Wei Wang a rem­placé le ver­rou par du RCU et un ver­rou tour­nant dans le com­mit 66f5d6ce53e6. Pour Li­nux 4.18, Da­vid Ahern a amé­lioré les struc­tures de don­nées im­pli­quées dans la re­cherche. Pour Li­nux 5.9, Brian Vaz­quez a re­tiré des ap­pels in­di­rects coû­teux dans le com­mit 55cced4f813b.

L’im­por­tante ré­gres­sion de 200 ns in­tro­duite dans Li­nux 6.5 a ba­layé toutes ces amé­lio­ra­tions. Cette ver­sion im­plé­mente une mi­ti­ga­tion pour la vul­né­ra­bi­lité « Spe­cu­la­tive Re­turn Stack Over­flow », af­fec­tant les pro­ces­seurs AMD, dans le com­mit fb3bd914b3ec. Cette mi­ti­ga­tion ajoute en­vi­ron 20 cycles à chaque re­tour de fonc­tion. Elle a en­suite été por­tée sur des noyaux plus an­ciens (5.10, 5.15, 6.1 et 6.4). Pour rendre les ré­sul­tats plus li­sibles, je l’ai désac­ti­vée pour ces ver­sions via l’op­tion spec_​rstack_​overflow=off.

Vous pou­vez consul­ter les vul­né­ra­bi­li­tés im­pac­tant votre pro­ces­seur et les mi­ti­ga­tions ap­pli­quées avec la com­mande lscpu. Cer­taines mi­ti­ga­tions dé­pendent du mi­cro­code et du mi­cro­lo­giciel1.

$ 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#

Évolution des performances de la recherche dans la table de routage IPv4 entre
Linux 4.14 et Linux 7.3
Évolution des performances de la recherche dans la table de routage IPv4. Les versions avec un astérisque ont la mitigation pour SRSO désactivée.

J’ai testé trois scénarios :

  • une vue com­plète et ré­cente avec plus de 1 000 000 de préfixes ;
  • un sous-en­semble d’une vue com­plète de 2017 avec 500 000 préfixes ;
  • un en­semble de 500 000 pré­fixes /32 contigus.

L’im­pact de 30 ns dû à la mi­ti­ga­tion de SRSO dans Li­nux 6.5 est plus pe­tit que pour IPv6 car la re­cherche d’une route IPv4 tra­verse moins de fonc­tions : en­vi­ron 4 pour IPv4 et 25 pour IPv6.

Dans Li­nux 5.11, j’ai in­tro­duit une ré­gres­sion dans le com­mit c0c5a60f0f13 après avoir cor­rigé le com­por­te­ment de net.​ipv4.​conf.​all.​ignore_​routes_​with_​linkdown2 ! En consé­quence, la fonc­tion ip_​ignore_​linkdown() dé­pense 5 cycles sup­plé­men­taires pour ré­pondre car elle doit suivre trois poin­teurs sup­plé­men­taires. La fonc­tion fib_​lookup() l’ap­pelle dans le code suivant :

if (ip_ignore_linkdown(nhc->nhc_dev) &&
    nhc->nhc_flags & RTNH_F_LINKDOWN &&
    !(fib_flags & FIB_LOOKUP_IGNORE_LINKSTATE))
    return false;

En chan­geant l’ordre des condi­tions, nous pou­vons évi­ter l’ap­pel à ip_​ignore_​linkdown() dans la ma­jo­rité 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 dis­tri­bu­tion des temps de re­cherche avant d’ap­pli­quer ce cor­rec­tif au-des­sus 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 re­pré­sente la fonc­tion de ré­par­ti­tion. Après l’ap­pli­ca­tion du cor­rec­tif, la mé­diane s’est amé­lio­ré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’im­pact des mi­ti­ga­tions, vous pou­vez les désac­ti­ver avec mitigations=​off, n’en désac­ti­ver qu’une seule avec spec_​rstack_​overflow=​off ou vous pro­té­ger à par­tir de Li­nux 6.17 d’un en­semble de vec­teurs d’at­taque avec mitigations=​auto,no_​user_kernel.

L’im­pact va­rie for­te­ment se­lon le pro­ces­seur. Par exemple, sur un Xeon W-2295, un pro­ces­seur In­tel de 2020 orienté bu­reau­tique, l’im­pact des mi­ti­ga­tions est de seule­ment quelques cycles pour IPv4 et moins de 3 % pour IPv6. La mi­ti­ga­tion qui ra­len­tit le plus est celle pour la vul­né­ra­bi­lité « In­di­rect Tar­get Se­lec­tion » qui a été cor­ri­gée avec l’ar­chi­tec­ture Sap­phire Rapids.


En met­tant de côté les ré­gres­sions in­tro­duites par les mi­ti­ga­tions des at­taques contre les pro­ces­seurs, les per­for­mances d’IPv4 ont dé­cliné len­te­ment tan­dis que celles d’IPv6 se sont amé­lio­rées avant de se sta­bi­li­ser. Si les per­for­mances de rou­tage sont im­por­tantes, vous avez plu­sieurs pos­si­bilités :