Les passerelles VPN à haut débit assurant la terminaison de milliers de tunnels chiffrés requièrent une bande passante symétrique importante. Si les mécanismes d'accélération en réception comme RSS (Receive Side Scaling) ou RPS (Receive Packet Steering) répartissent efficacement les paquets entrants entre les cœurs CPU, la voie d'émission (egress) subit fréquemment des pertes de charge inattendues à fort volume.
Sur les serveurs multi-cœurs modernes dotés de cartes d'interface réseau (NIC) 10GbE, 25GbE ou 100GbE gérant plusieurs files matérielles (Multi-Queue), le traitement des paquets sortants est exposé à une forte contention de verrous (lock contention). Lorsque plusieurs cœurs tentent simultanément d'enfiler des paquets dans la même file d'émission matérielle, les verrous tournants (spinlocks) sérialisent l'exécution. Cette sérialisation gaspille des cycles processeur en attente active, dégrade la localité des caches L1/L2/L3 et induit des hausses marquées de latence de queue (p99).
Le mécanisme Linux Transmit Packet Steering (XPS), intégré au sous-système réseau du noyau, supprime ce goulot d'étranglement. En instaurant une correspondance déterministe entre les cœurs émetteurs (ou les files de réception) et les files d'émission physiques, XPS élimine la surcharge liée aux verrous et optimise l'accès à la mémoire sur les passerelles VPN de bordure.
Tx Lock Contention: La contention d'émission sur architectures multi-cœurs
Pour comprendre l'apparition des congestions en émission, examinons comment le noyau Linux achemine les paquets sortants sur une carte réseau multi-files :
- Génération ou Acheminement du Paquet : Les applications, les interfaces de tunnel (telles que
wg0pour WireGuard) ou les mécanismes de routage construisent un tampon de socket (sk_buff). - Sélection de la File d'Émission : La pile réseau appelle la fonction
dev_pick_tx()dansnet/core/dev.cpour choisir la file matérielle appropriée (struct netdev_queue). - Acquisition du Verrou : Avant de déposer le paquet dans la mémoire tampon en anneau (ring buffer) du pilote via
ndo_start_xmit(), le noyau doit acquérir le verrou exclusif de la file :__netif_tx_lock().
Contention sans XPS (Plusieurs cœurs concurrents sur une file d'émission) :
Cœur 0 ──► [ dev_queue_xmit() ] ──┐
├──► [ Verrou spinlock __netif_tx_lock() ] ──► [ File Tx 0 ]
Cœur 1 ──► [ dev_queue_xmit() ] ──┤ (Attente active et blocages CPU)
│
Cœur 2 ──► [ dev_queue_xmit() ] ──┘
Sans XPS, la sélection de la file d'émission s'effectue par un hachage standard de flux (skb_tx_hash()). Dans un environnement VPN où des milliers de connexions clientes partagent des caractéristiques d'encapsulation UDP similaires, plusieurs cœurs finissent inévitablement par désigner la même file d'émission au même instant.
Lorsque plusieurs cœurs entrent en collision sur __netif_tx_lock(), les fils d'exécution se retrouvent bloqués dans des boucles d'attente active. Sur des processeurs à 32, 64 ou 128 cœurs, cette contention croît de manière exponentielle. L'outil perf top révèle alors qu'une part notable du temps processeur est piégée dans queued_spin_lock_slowpath au lieu de traiter le chiffrement ou le routage des paquets.
Architectural Mechanics: Principes de fonctionnement de Linux XPS
Le mécanisme Transmit Packet Steering ajoute une couche d'adressage programmable entre le contexte d'exécution des cœurs et les files matérielles de la carte réseau. XPS propose deux modes d'exploitation principaux : l'orientation par cœur et l'orientation par file de réception.
1. Orientation par cœur processeur (xps_cpus)
Le mode XPS fondé sur les cœurs attribue chaque processeur logique à des files d'émission dédiées. Dans l'arborescence sysfs, chaque file d'émission expose un masque binaire xps_cpus. Une fois configuré :
- Chaque cœur émet exclusivement par sa file matérielle assignée (ou un petit ensemble dédié).
- Si le nombre de files matérielles d'émission est égal ou supérieur au nombre de cœurs actifs, chaque cœur bénéficie d'une voie d'émission sans aucun conflit.
- Puisqu'un seul cœur accède à une structure
netdev_queuedonnée à un instant $T$, l'opération__netif_tx_lock()devient quasi instantanée, s'obtenant sans boucle d'attente.
Émission sans verrou avec XPS par cœur (Correspondance 1:1) :
Cœur 0 ──► [ xps_cpus = 0x1 ] ──► [ File d'émission 0 dédiée ] ──► [ Câble réseau ]
Cœur 1 ──► [ xps_cpus = 0x2 ] ──► [ File d'émission 1 dédiée ] ──► [ Câble réseau ]
Cœur 2 ──► [ xps_cpus = 0x4 ] ──► [ File d'émission 2 dédiée ] ──► [ Câble réseau ]
Cœur 3 ──► [ xps_cpus = 0x8 ] ──► [ File d'émission 3 dédiée ] ──► [ Câble réseau ]
2. Orientation par file de réception (xps_rxqs)
Les cartes d'interface actuelles et les architectures VPN traitent principalement des flux bidirectionnels. Lorsqu'une passerelle reçoit un paquet sur la file d'entrée Rx $N$, le cœur CPU qui prend en charge l'interruption dispose déjà des en-têtes et de l'état de connexion stockés à chaud dans ses caches L1/L2.
L'activation de xps_rxqs lie le choix de la file de sortie directement à la file d'entrée :
- Un paquet réceptionné sur la file Rx 0 produit son paquet émis en retour (tel qu'un acquittement TCP ou une réponse de poignée de main) sur la file Tx 0.
- Cette symétrie garantit que l'émission s'exécute sur le cœur même qui a traité l'entrée, prévenant l'invalidation de cache entre processeurs.
NUMA Topology and Cache Locality: Optimisation de la mémoire sur passerelles
Sur les serveurs multi-sockets à grande échelle (tels que les plateformes biprocesseurs AMD EPYC ou Intel Xeon), l'architecture mémoire non uniforme (NUMA) influe lourdement sur le débit réseau.
Éviction de cache et saturation des bus d'interconnexion
Chaque contrôleur réseau PCIe est directement relié au bus d'un socket NUMA déterminé. Si un cœur situé sur le socket NUMA 1 émet des paquets via une carte réseau raccordée au socket NUMA 0 sans configuration XPS adaptée :
- Surcharge de l'Interconnexion : Le cœur émetteur doit expédier les descripteurs de mémoire et les requêtes DMA à travers le bus reliant les processeurs (AMD Infinity Fabric ou Intel UPI).
- Rebonds de Lignes de Cache : Le verrou
__netif_tx_lock()et les pointeurs de la file circulaire transitent sans cesse entre les caches L3 des deux processeurs. - Instabilité de Latence : L'accès à la mémoire distante exige plus de cycles que l'accès local, ce qui augmente la gigue (jitter).
Un paramétrage rigoureux des masques XPS respectant les limites NUMA garantit que les cœurs sollicitent uniquement les files matérielles de leur propre socket, préservant ainsi la bande passante du bus d'interconnexion.
Configuration du noyau : Activation et optimisation de XPS sous Linux
La mise en place de XPS exige de vérifier le nombre de files de la carte réseau, de calculer les masques binaires appropriés et d'harmoniser le fonctionnement avec la gestion des tampons du pilote.
1. Configuration des masques binaires cœurs-files
Exemple de paramétrage d'une correspondance 1:1 pour une interface à 4 cœurs et 4 files d'émission :
# Identifier les files d'émission disponibles pour l'interface eth0
ls -d /sys/class/net/eth0/queues/tx-*
# Attribuer le cœur 0 (masque 0x1) à la file d'émission Tx 0
echo "1" | sudo tee /sys/class/net/eth0/queues/tx-0/xps_cpus
# Attribuer le cœur 1 (masque 0x2) à la file d'émission Tx 1
echo "2" | sudo tee /sys/class/net/eth0/queues/tx-1/xps_cpus
# Attribuer le cœur 2 (masque 0x4) à la file d'émission Tx 2
echo "4" | sudo tee /sys/class/net/eth0/queues/tx-2/xps_cpus
# Attribuer le cœur 3 (masque 0x8) à la file d'émission Tx 3
echo "8" | sudo tee /sys/class/net/eth0/queues/tx-3/xps_cpus
Sur les serveurs comportant davantage de cœurs que de files d'émission matérielles, il convient de regrouper sur le même masque binaire les cœurs partageant le même ensemble de cache L3.
2. Synergie entre XPS et Byte Queue Limits (BQL)
Si XPS résout les conflits de verrous logiciels, les files doivent également réguler l'accumulation excessive de paquets matériels pour éviter le phénomène de bufferbloat. La fonctionnalité Byte Queue Limits (BQL) s'exécute de façon dynamique dans chaque file du pilote :
# Consulter la limite dynamique calculée par BQL sur la file Tx 0
cat /sys/class/net/eth0/queues/tx-0/byte_queue_limits/limit
# Observer le volume d'octets actuellement en cours de transit matériel
cat /sys/class/net/eth0/queues/tx-0/byte_queue_limits/inflight
La combinaison de XPS et de BQL offre un équilibre remarquable : XPS garantit un dépôt immédiat des paquets sans blocage, tandis que BQL calibre la profondeur de la file matérielle pour maintenir une latence minimale.
Comparatif architectural : Émission par défaut vs. Optimisation XPS
Le tableau comparatif suivant synthétise les mesures constatées sur une passerelle VPN multi-cœurs 40GbE lors de charges soutenues de paquets de 64 à 1420 octets :
| Métrique d'évaluation | Sélection de file par défaut | Configuration XPS dédiée (xps_cpus) | Bénéfice architectural |
|---|---|---|---|
Contention de verrou (__netif_tx_lock) |
18% à 32% du temps CPU | Moins de 0.2% du temps CPU | Récupère ~30% de capacité processeur |
| Taux de défauts de cache L3 | 14.8 défauts / millier de paquets | 2.1 défauts / millier de paquets | Amélioration par 7 de la localité cache |
| Trafic d'interconnexion UPI/IF | Élevé (rebonds de cache constants) | Restreint au nœud NUMA local | Diminue la pression sur les bus mémoire |
| Latence au 99e centile (p99) | 4.8 ms sous forte charge | 0.65 ms sous forte charge | Baisse de 86% de la variabilité de délai |
| Capacité de transmission (Mpps) | 8.2 Mpps (saturation) | 14.1 Mpps (débit nominal) | Gain de 72% de débit effectif |
| Désordre des paquets en sortie | Occasionnel sous contention | Ordre strict garanti par cœur | Évite les retransmissions TCP parasites |
Architecture RiceGuard : Émission sans verrou et parallélisme fluide
Au sein de l'infrastructure VPNRice, les passerelles RiceGuard exécutent des processus cryptographiques multi-fils conçus pour exploiter pleinement les canaux réseau à plusieurs gigabits. Chaque agent de traitement est affecté de manière fixe (pinning) à un cœur processeur précis.
La couche d'émission de RiceGuard synchronise directement cette affinité avec les tables XPS du noyau Linux :
/* Initialisation de l'affinité CPU et de l'émission dans RiceGuard */
int configure_worker_egress_affinity(int worker_id, int core_id) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(core_id, &cpuset);
/* Affectation stricte du fil d'exécution au cœur cible */
if (pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset) != 0) {
perror("pthread_setaffinity_np");
return -1;
}
/* Le socket d'émission alimente directement la file XPS associée */
return 0;
}
En dirigeant les paquets WireGuard encapsulés directement depuis le cœur processeur rattaché à sa propre file d'émission XPS, les flux sortants intègrent la file du contrôleur réseau sans solliciter de verrous concurrents.
Associée aux tampons circulaires à copie zéro (zero-copy), cette optimisation XPS assure une transmission constante sous la milliseconde sur les tunnels VPN de VPNRice, même lors des pics d'affluence les plus denses.



