Dataplane
DPDK : s'échapper du noyau
Pourquoi SiHA confie ses cartes réseau à l'espace utilisateur et ne laisse jamais un paquet toucher la pile réseau Linux.
La pile réseau Linux est un prodige de généralité. Elle parle tous les protocoles, gère tous les cas particuliers, et c’est exactement le mauvais outil pour une appliance dont le travail entier consiste à déplacer les paquets d’un fil à un autre aussi vite que physiquement possible.
Le coût de demander au noyau de router
Suivez un seul paquet à travers un chemin noyau conventionnel et comptez le surcoût :
- La carte réseau lève une interruption à l’arrivée. Au débit de ligne, cette interruption se déclenche des millions de fois par seconde, et chacune est un changement de contexte hors de ce que faisait le CPU.
- La trame est transférée par DMA dans un tampon de socket noyau, puis copiée à travers la frontière noyau/espace utilisateur lorsque votre application la lit.
- Lire et écrire signifie des appels système — davantage de changements de contexte, davantage de pollution du cache.
- La pile générique parcourt chaque couche (hooks netfilter, recherche de route, qdiscs) pour chaque paquet, que vous en ayez besoin ou non.
Rien de tout cela n’a d’importance à quelques milliers de paquets par seconde. Mais le débit de ligne 10 GbE est de 14,88 Mpps pour des trames de 64 octets — ce qui laisse environ 67 nanosecondes par paquet. Un seul défaut de cache peut faire exploser ce budget. À 25 et 100 GbE, le surcoût par paquet de la pile générique domine tout simplement ; le CPU passe tout son temps sur la comptabilité et rien sur le routage.
DPDK : donnez la carte réseau à l’espace utilisateur
DPDK — le Data Plane Development Kit — inverse le modèle. Au lieu que le noyau possède la carte réseau et vous prête les paquets, l’application possède directement la carte réseau.
Le périphérique est délié de son pilote noyau et relié à un pilote capable de
fonctionner en espace utilisateur — vfio-pci, ou uio_pci_generic quand le
noyau n’est pas verrouillé (lockdown). À partir de là, un poll-mode driver
(PMD) mappe les anneaux de descripteurs de la carte directement dans l’espace
d’adressage de l’application et les lit dans une boucle serrée. Pas d’interruptions.
Pas de tampons de socket. Pas de passage par la pile générique.
Les techniques qui rendent cela rapide :
- Poll-mode au lieu d’interruptions. Un cœur épinglé tourne en lisant l’anneau RX. Il n’y a pas de latence d’interruption parce qu’il n’y a pas d’interruptions.
- Hugepages. Les tampons de paquets et les anneaux vivent dans des pages de 2 Mo ou 1 Go, de sorte que le TLB couvre des gigaoctets de mémoire avec une poignée d’entrées — bien moins de défauts sur le chemin critique.
- DMA zéro-copie. La carte transfère par DMA les trames directement dans des
structures
mbufen espace utilisateur. L’application traite les octets mêmes que le matériel a écrits ; rien n’est copié pour les lui remettre. - Run-to-completion sur des cœurs épinglés. Un paquet est reçu, classifié, transformé et transmis sur un seul cœur sans jamais être remis à un ordonnanceur.
- RX en rafale. Le pilote récupère un lot de paquets par sondage, amortissant le coût par appel et gardant le cache d’instructions chaud.
Le compromis : un cœur qui ne dort jamais
Il n’y a pas de repas gratuit. Un cœur en poll-mode reste à 100 % de CPU qu’un seul paquet ou quatorze millions arrivent — il tourne toujours, demandant « quelque chose enfin ? ».
Vous échangez un cœur CPU entier contre une latence déterministe sous la microseconde et un débit au niveau de la ligne. Sur un serveur généraliste, ce serait du gaspillage. Sur un firewall / routeur / répartiteur de charge dont la raison d’être même est le routage, c’est exactement le bon compromis.
Comment SiHA le câble
Sur une appliance SiHA, les cartes de données se lient à DPDK par défaut — le contournement du noyau n’est pas un bouton de réglage optionnel, c’est la référence. Quelques spécificités découlent du fait de tourner sur un OS d’appliance immuable et à démarrage sécurisé :
- Les hugepages sont réservées au démarrage via la ligne de commande du noyau, avant que quoi que ce soit d’autre ne réclame de la mémoire, de sorte que le pool est toujours disponible et jamais fragmenté.
- Le pilote de liaison s’auto-sélectionne. Sous SecureBoot imposé, le noyau est
verrouillé (lockdown), ce qui bloque le mappage des BAR PCI d’
uio_pci_generic— SiHA lie doncvfio-pciet passe par l’IOMMU. Quand le noyau n’est pas verrouillé (le build de debug), il se rabat suruio_pci_generic. L’appliance détermine cela toute seule en lisant l’état de lockdown ; l’opérateur déclare une interface, pas un pilote. - Un repli
af-packetreste disponible pour le débogage. Lorsque vous avez besoin que le noyau voie les trames — pour untcpdumprapide, ou pour isoler si un problème est dans le dataplane ou sur le fil — vous pouvez basculer une interface en modeaf-packetet la rendre à la pile. C’est lent, et ce n’est pas grave, parce que cela n’existe que pour les moments où vous fixez quelque chose qui ne devrait pas se produire.
Ce qui tourne par-dessus
DPDK amène les paquets dans l’espace utilisateur au débit de ligne — mais une
boucle de sondage brute n’est pas un firewall. Quelque chose doit classifier,
router, faire du NAT et répartir la charge sur ces mbuf une fois qu’ils
arrivent. Ce quelque chose, c’est VPP, le moteur de forwarding vectorisé que SiHA
pilote comme dataplane, et c’est là que l’histoire devient intéressante.
Plus de détails sur la manière dont VPP transforme un flux de trames brutes en un routeur configuré de façon déclarative sur le blog.