← Blog

Dataplane

VPP : un graphe de nœuds de paquets

Le Vector Packet Processing achemine des lots de paquets à travers un graphe orienté — et c'est pour cela qu'il est rapide.

Router les paquets vite tient moins d’algorithmes astucieux que du respect de la machine. Les CPU modernes détestent les surprises : un cache d’instructions froid, un branchement imprévisible, un accès mémoire que le préchargeur n’avait pas vu venir — chacun bloque le pipeline pendant des dizaines ou des centaines de cycles. Au débit de ligne 10 GbE, cela fait 14,88 Mpps pour des trames de 64 octets, soit environ 67 nanosecondes par paquet. Vous n’avez pas de cycles à gaspiller en défauts de cache.

VPP (Vector Packet Processing) est le dataplane au cœur de SiHA, et toute sa conception est bâtie autour du fait de garder le CPU heureux. Deux idées font le gros du travail : les vecteurs et le graphe.

Des lots, pas des paquets

Un routeur naïf traite un paquet à la fois : tirer un paquet de la carte réseau, le faire passer par tout le chemin de forwarding — parser l’Ethernet, chercher la route, appliquer les ACL, réécrire les en-têtes, transmettre — puis recommencer. Chaque paquet reparcourt le même code, et chaque paquet paie le coût de ramener ce code dans le cache d’instructions.

VPP inverse cela. Il prend les paquets de DPDK en rafales et les traite comme un vecteur — un lot de jusqu’à 256 paquets qui voyagent ensemble à travers le chemin de forwarding. Au lieu d’exécuter tout le chemin pour un seul paquet, VPP exécute une étape du chemin pour le vecteur entier, puis remet le vecteur à l’étape suivante.

Le graphe

Ce chemin de forwarding est un graphe orienté de nœuds. Chaque nœud est un petit morceau de code focalisé : ethernet-input parse les en-têtes L2, ip4-lookup fait la recherche FIB, ip4-rewrite écrit les nouveaux en-têtes, et des nœuds de fonctionnalité comme acl et nat44 font exactement ce que leur nom indique. Le voyage d’un paquet est une marche à travers ce graphe, de nœud en nœud, et le vecteur y circule d’un bloc.

Le nœud est l’unité de travail, et le vecteur est l’unité d’ordonnancement. La boucle interne d’un nœud ressemble à « pour chaque paquet de ce vecteur, fais mon unique tâche ».

Pourquoi les vecteurs sont rapides

C’est l’intuition centrale, et ce n’est pas de la magie — c’est de l’efficacité de cache.

  • Cache d’instructions chaud. Le code d’un nœud est chargé dans le cache d’instructions une fois par vecteur, puis exécuté sur les N paquets. La boucle naïve un-paquet-à-la-fois recharge le code de tout le chemin de forwarding pour chaque paquet individuel. Amortir la récupération du code sur un lot est d’où provient l’essentiel du gain.
  • Préchargeur efficace. Parce que le nœud sait qu’il a N paquets en file, il peut précharger les données du paquet i+1 pendant qu’il travaille sur le paquet i. La latence mémoire est masquée au lieu de bloquer le cœur.
  • Coûts fixes amortis. Le surcoût d’appel de fonction, la mise en place de la boucle, la comptabilité par nœud — tout est divisé sur le vecteur au lieu d’être payé par paquet.

Le plus beau, c’est que cela s’améliore sous la charge. Une interface plus occupée délivre de plus grandes rafales, ce qui signifie de plus grands vecteurs, ce qui signifie un meilleur amortissement. L’efficacité de VPP monte précisément quand vous en avez le plus besoin.

Les plugins sont des nœuds du graphe

Les fonctionnalités dans VPP sont simplement des nœuds que vous insérez dans le graphe. C’est ce qui en fait une plateforme plutôt qu’un pipeline figé. dpdk_plugin injecte les paquets depuis la carte réseau ; acl_plugin, nat44 et vrrp_plugin ajoutent des nœuds de filtrage, de translation et de haute disponibilité ; linux_cp fait le pont avec le noyau de l’hôte. Activer une fonctionnalité sur une interface, c’est, mécaniquement, câbler un nœud dans le chemin que ces paquets empruntent.

Comment SiHA le pilote

VPP tourne entièrement en espace utilisateur en tant que processus unique — aucun module noyau sur le chemin rapide. Sur l’appliance SiHA, il est supervisé comme un enfant du superviseur PID 1, recyclé et contrôlé par la santé comme n’importe quel autre daemon.

Le plan de contrôle de SiHA programme VPP via son API binaire en utilisant govpp. Chaque fonctionnalité a un fin wrapper Go — interfaces, ACL, NAT, LB — qui traduit les ressources COSI déclaratives en les appels d’API binaire correspondants. Ces wrappers sont aussi l’endroit où nous absorbons quelques bizarreries amont de VPP pour que le reste du plan de contrôle n’ait pas à en avoir connaissance ; les fichiers de wrapper documentent chaque contournement avec une note Why:.

La configuration propre du dataplane — le startup.conf de VPP — est possédée par le plan de contrôle, pas éditée à la main sur la machine. Lorsqu’un opérateur pousse un DataplaneConfig, SiHA re-génère le fichier et redémarre VPP avec un apply en deux phases à contrôle de santé : snapshot de la config actuelle comme dernier état bon connu, écriture de la nouvelle, redémarrage, puis sondage. Si VPP ne revient pas sain, SiHA restaure la config du dernier état bon connu et refuse de réessayer la révision défaillante jusqu’à ce que l’opérateur l’édite. Le dataplane ne se retrouve jamais coincé dans une boucle de crash parce que quelqu’un a fait une faute de frappe dans une config.

Toute la conception est un pari : que la vitesse de forwarding vient de la discipline de cache, et que la sûreté vient d’un plan de contrôle déclaratif qui traite la config du dataplane comme du code — pas de tours de passe-passe sur le chemin rapide.

Vous voulez voir comment le plan de contrôle et le dataplane s’assemblent de bout en bout ? Lisez la vue d’ensemble de l’architecture.