QUIC pour le noyau Linux
(lwn.net)- Le premier patch intégrant officiellement le protocole QUIC au noyau Linux a été soumis
- L’objectif est d’améliorer plusieurs limites de TCP (latence, head-of-line blocking, ossification du protocole due aux équipements intermédiaires, etc.)
- QUIC, basé sur UDP, prend en charge le multistream et le chiffrement de bout en bout, et son intégration au noyau pourrait élargir son usage sur davantage de plateformes et de matériels
- Les performances de l’implémentation initiale dans le noyau ont été mesurées comme inférieures à celles de TCP existant et de kernel TLS, mais des gains sont attendus avec le hardware offloading et les optimisations à venir
- Le support est actuellement activement discuté dans Samba, SMB/NFS basés sur le noyau, curl et d’autres projets, mais l’intégration dans la branche principale devrait encore prendre du temps
Contexte de l’émergence de QUIC et limites de TCP
- QUIC a été conçu pour résoudre divers problèmes de TCP sur l’Internet actuel
- L’expérience web se dégrade à cause de la latence induite par le 3-way handshake de TCP, de l’absence de bon support du multistream et du phénomène de head-of-line blocking en cas de perte de paquets
- Les métadonnées de TCP sont transmises sans chiffrement, ce qui crée un risque de fuite d’informations, et les middleboxes de l’Internet filtrent le trafic à partir des informations de connexion, ce qui a conduit à l’ossification du protocole
- Les tentatives d’amélioration de TCP (par exemple Multipath TCP) ne fonctionnent correctement que si elles se font passer pour du TCP classique
Caractéristiques de QUIC et avantages techniques
- QUIC fonctionne au-dessus de UDP et peut établir une connexion rapidement, sans 3-way handshake séparé lors du processus de connexion
- Son architecture de transmission multistream évite qu’une perte de paquets n’affecte l’ensemble des flux
- Les données de transport liées à QUIC sont toujours chiffrées de bout en bout (sur la base de TLS), empêchant les équipements intermédiaires d’accéder aux messages internes
- Dans tout environnement réseau où les paquets UDP peuvent circuler, QUIC peut lui aussi fonctionner normalement
Aperçu du patch d’intégration de QUIC dans le noyau Linux
- Le patch soumis introduit un nouveau type de protocole, IPPROTO_QUIC, permettant d’utiliser l’appel système socket() existant
- Comme avec TCP, on peut utiliser les appels bind(), connect(), listen() et accept(), mais le traitement ultérieur présente des différences
- La gestion de session TLS ainsi que les processus d’authentification et de chiffrement sont pris en charge dans l’espace utilisateur, et l’handshake TLS doit être terminé à chaque extrémité après l’établissement de la connexion avant de pouvoir échanger des données
- Après la connexion initiale, le résultat de la négociation TLS peut être mis en cache, ce qui accélère fortement les reconnexions entre deux systèmes
Défis de performances et perspectives
- L’implémentation de QUIC dans le noyau qui a été soumise reste pour l’instant en retrait, en termes de performances, par rapport à kernel TLS et TCP
- Un débit inférieur d’un facteur pouvant aller jusqu’à 3 par rapport à l’in-kernel TLS, et jusqu’à 4 fois inférieur à TCP même quand le chiffrement est désactivé
- Parmi les causes avancées figurent l’absence de prise en charge du segmentation offloading, des copies de données supplémentaires dans le chemin d’émission et le processus de chiffrement des en-têtes
- On s’attend à une amélioration des performances à mesure que le support du hardware offloading sera ajouté et que l’implémentation in-kernel sera optimisée
Adoption actuelle et perspectives
- Les discussions autour du support in-kernel de QUIC sont actives dans de nombreux projets, notamment les serveurs/clients Samba, les systèmes de fichiers SMB et NFS du noyau, ainsi que curl
- Le patch représente environ 9 000 lignes et ne contient pour l’instant que du code de support bas niveau. L’implémentation complète est annoncée dans des patchs supplémentaires
- Les discussions de revue de code et d’intégration viennent tout juste de commencer, et son usage réel demandera encore du temps
- Sachant que l’intégration du protocole Homa dans le noyau a récemment nécessité 11 soumissions sur 9 mois, l’entrée de QUIC dans la branche principale n’est pas attendue avant 2026 au plus tôt
1 commentaires
Commentaire Hacker News
ssl_preread_server_nameà une configuration NGINX pourproxy_passles requêtes de certains domaines vers une autre instance NGINXLa première instance ne fait que transmettre le flux TLS brut (avec
proxy_protocol), et la seconde se charge de la terminaison TLS réelleCette approche est efficace pour mettre en place un basculement : si le chemin principal du serveur tombe, on met à jour l’enregistrement DNS A vers le NGINX de la machine de secours, et cette instance route ensuite les requêtes de certains domaines vers le backend d’origine via un chemin séparé
C’est pratique car il n’est pas nécessaire de dupliquer toute la configuration TLS
En revanche, cette méthode n’est pas applicable à HTTP/3
HTTP/3 repose sur QUIC, fonctionne sur UDP, et chiffre le SNI pendant le handshake, donc impossible de faire un routage par domaine avec
ssl_preread_server_nameJe me demande s’il existe une alternative pour prendre en charge le routage basé sur le SNI avec HTTP/3, ou s’il faut rester sur HTTP/1.1 ou HTTP/2 over TLS si l’on a besoin de cette fonctionnalité
En pratique, le comportement varie selon l’implémentation du client (voir l’état du support des enregistrements HTTPS dans Chromium, lien vers l’issue), mais si une connexion QUIC échoue, le client bascule de manière transparente vers HTTP/1.1/2, tout en respectant aussi l’en-tête Alt-Svc
Pour un basculement planifié, on peut aussi cesser d’envoyer l’en-tête Alt-Svc et attendre qu’un timeout se produise vers l’instance alternative
Si le routage QUIC est vraiment nécessaire, heureusement les informations SNI sont toujours présentes dans le premier paquet, donc un routage par inspection de paquets est possible
Le udpgrm de Cloudflare peut servir de référence, et cela fonctionne tant qu’il n’y a pas d’ECH (Encrypted Client Hello)
En présence d’ECH, le routeur doit disposer de la clé de déchiffrement pour pouvoir prendre une décision de routage, et il est aussi possible de concevoir un basculement en cascade au niveau du protocole
On peut voir une implémentation concrète dans cet exemple udpgrm
Si un attaquant accède à ce serveur, il lui est de toute façon facile d’émettre de nouveaux certificats SSL, donc au lieu de compliquer les choses avec un système de basculement sophistiqué, il est probablement plus rationnel de terminer TLS directement
Personnellement, je n’ai jamais réussi à reproduire moi-même les gains de performance ou de fiabilité de QUIC
Je fais des tests depuis des années, mais je finis généralement par le désactiver pour des raisons de performance
Le basculement basé sur le DNS aussi met en pratique plusieurs minutes à se propager, et pour des clients simples comme les navigateurs, le basculement se produit mal
Du coup, j’utilise directement un gestionnaire
onerrorpour charger un second cheminPar exemple, j’utilise ce type de code pour le suivi publicitaire, et j’expose aussi
fetchde la même façon via un wrapperCette méthode est de loin la plus efficace parmi toutes celles que j’ai essayées
Même si le navigateur échoue à établir une connexion QUIC (y compris si elle est annoncée dans le DNS), il revient automatiquement à HTTP/1 ou HTTP/2 over TLS, donc on peut conserver exactement la même stratégie de basculement
L’une des caractéristiques de conception de HTTP/3 est précisément de ne pas exposer les informations de l’endpoint jusqu’à la couche TLS
Personnellement, je vois cela comme un avantage
HAProxy peut faire du proxy TLS brut, mais pas du routage basé sur le nom d’hôte
Cloudflare tunnel dispose d’une fonctionnalité particulière qui permet un routage par nom d’hôte sans terminaison TLS, mais pour l’utiliser il faut aussi relier le DNS à Cloudflare
Voir la BD xkcd associée
Je me demande si la même limite existe aussi dans un environnement TCP+TLS lorsqu’Encrypted Client Hello est utilisé
Je pense que la réponse serait à peu près la même
J’ai l’impression que cette discussion va justement dans le sens d’une résolution progressive de ce type de problèmes
À l’avenir, un support matériel au niveau des cartes réseau pourrait aussi devenir possible
En revanche, comme la majorité du trafic Internet circule aujourd’hui entre mobiles et serveurs, c’est sur ce segment que QUIC et HTTP/3 montrent vraiment leur intérêt
Pour les autres usages, on peut très bien continuer à utiliser TCP
Elle donnera sans doute l’impression de plusieurs connexions comme aujourd’hui, tout en étant mise en cache en interne
Personnellement, j’aimerais bien recevoir explicitement un objet connexion et ouvrir les flux séparément, mais pour l’instant l’approche actuelle me va aussi
D’après cette discussion, si ce n’est pas une extension, alors le serveur peut lui aussi créer de nouveaux flux après l’établissement de la connexion
Côté client, comme il s’agit en réalité de flux, il est difficile de les abstraire comme des « connexions » distinctes, et il semble qu’une abstraction API entièrement nouvelle soit nécessaire au fond
J’imagine probablement une structure où un nouveau descripteur de fichier est reçu via
recvmsgpour chaque nouveau fluxJ’aimerais avoir la robustesse de Mosh face aux problèmes réseau, tout en conservant toutes les fonctionnalités d’OpenSSH (SFTP, SOCKS, port forwarding, gestion d’état, roaming, etc.)
Je me demande si OpenSSH pourrait exploiter un support au niveau du noyau
Voir Mosh
Il vaudrait sans doute mieux créer un protocole de connexion séparé basé sur QUIC
Plusieurs approches sont en cours au stade du prototype
Pourtant, on dit que l’implémentation noyau actuelle de QUIC est 3 à 4 fois plus lente que Linux, tout en ajoutant que l’écart de performances devrait bientôt se réduire
Si la vitesse est censée être l’avantage de QUIC, pourquoi l’utiliser s’il est en pratique plus lent ?
L’auteur de la PR dit aussi qu’une partie de la dégradation des performances vient de la conception même du protocole ; y a-t-il donc encore quelque chose à corriger séparément dans TCP ?
En gros, cela se résume à « ce n’est pas encore optimisé »
Par exemple, absence de segmentation offload, copies de données supplémentaires sur le chemin de transmission, surcoût lié au chiffrement des en-têtes, etc., et tout cela a de fortes chances d’être corrigé
Ici, les benchmarks ont été réalisés dans un environnement très idéal
En réalité, dans un environnement mobile, la variabilité du réseau est forte, ce qui met en évidence les limites structurelles de TCP
En pratique, on implémente déjà souvent au-dessus de TCP des fonctionnalités proches de QUIC, comme avec HTTP/2
Au fond, QUIC est une pile réseau complète qui opère à partir de la couche 5 du modèle OSI, tandis que TCP est plutôt un moteur de couche 3, donc la comparaison structurelle est difficile
Surtout, l’un des avantages de QUIC est l’établissement et le rétablissement plus rapides des connexions, avec continuité de session même lors de changements d’IP
Sa structure en flux multiplexés et non bloquants simplifie radicalement la conception des protocoles de plus haut niveau
Une fois cette structure intégrée au noyau, la marge d’optimisation des performances devient énorme
À l’avenir, au lieu d’empiler des solutions multicouches sur les limites de TCP, il faudra probablement utiliser bien plus souvent au quotidien des bases avancées comme QUIC
Lorsqu’il y a perte de paquets, tout ce qui suit est retardé jusqu’à récupération complète de la transmission (HOL blocking), ce qui constitue une limite structurelle importante
Ce n’est pas seulement une question de débit, mais bien d’amélioration de la latence
Voir ce document technique
Le principal goulot d’étranglement vient des changements de contexte entre noyau et espace utilisateur
Le user-space networking (par exemple l’accès direct à la NIC) élimine les entrées dans le noyau
À l’inverse, fournir des fonctionnalités dans l’espace noyau (par exemple
sendfile, in-kernel TLS, NIC offloading, DMA direct du disque vers la NIC) réduit lui aussi les changements de contexte globaux et les copies de donnéesLes piles QUIC actuelles ne profitent réellement d’aucun des deux avantages
L’entrée/sortie des paquets repose sur des syscalls, et il reste impossible d’éviter les copies de données
Avec de l’I/O batchée comme
io_uring, on réduit les changements de contexte, mais pas les copies elles-mêmesIl y a soit l’approche kernel bypass + DMA, soit l’approche de type
sendfile/ktls qui exclut l’espace utilisateur, et l’implémentation noyau de QUIC ne bénéficie d’aucun des deux avantagesSi l’on peut écrire directement dans la NIC via DMA ou si l’on passe par un syscall noyau, la différence de performances est importante
Le user-space networking n’est vraiment convaincant que lorsqu’on dispose de ce type de transition de privilège et de structure DMA
Cela n’est vraiment exploité que par de très grandes entreprises (MOFAANG, etc.)
En théorie, on espère que
io_uringgénéralisera ce type d’avantages, mais ce n’est pas encore mûr pour un usage réelC’est pour cela que TCP/IP reste dans le noyau des principaux OS
J’avais l’impression que le rôle du noyau était la gestion de la mémoire, du matériel et des tâches ; n’est-il pas plus logique de traiter les protocoles au-dessus d’IP en userland ?
À l’inverse, séparer ces piles en espace utilisateur peut aussi améliorer les performances dans certains autres cas
Comme TCP/UDP arbitrent dans le noyau le routage des sockets sur la base des ports, plusieurs programmes peuvent utiliser TCP/UDP simultanément
QUIC fonctionne au-dessus d’UDP, donc l’argument de cette discussion reste malgré tout pertinent
Cela souligne surtout qu’on ne peut pas faire fonctionner en espace utilisateur uniquement des protocoles situés directement au-dessus d’IP
J’espère que l’Internet sera un peu plus rapide à l’avenir
Dans des environnements comme la 5G, on ne ressentira peut-être pas vraiment la différence, mais cela reste une avancée utile
Je trouve intéressant qu’il existe une structure de handshake distincte au niveau du lien
Ce n’est pas tout à fait ce que j’imaginais, moi qui pensais que QUIC intégrait TLS en natif
Cela dit, je pense que cette technologie pourrait quand même réduire davantage la latence dans les jeux
Quand les ressources de calcul et l’efficacité réseau augmentent, la demande augmente elle aussi
Pour les jeux ou le calcul scientifique, ce n’est pas grave si cela permet de meilleurs résultats
Mais sur le Web, cela a souvent des effets pervers, avec davantage de publicité, de traçage et de JavaScript
bind(),connect(),listen(),accept(), mais que la structure change ensuite en utilisant les syscallssendmsg()etrecvmsg()J’aurais aussi aimé une explication sur le choix de cette approche, et sur la raison pour laquelle on n’a pas créé des syscalls séparés spécifiquement adaptés à QUIC