Le dilemme de la latence : pourquoi les anneaux matériels déjouent l'AQM
Sur les passerelles VPN à haut débit et les nœuds de transit chiffrés, les ingénieurs réseau rencontrent fréquemment un paradoxe de performance déconcertant. Bien que des algorithmes avancés de gestion active de file d'attente (AQM) comme FQ-CoDel ou CAKE soient configurés sur l'interface réseau, les utilisateurs subissent des variations de latence de 50 à 150 millisecondes en période de forte charge. La voix sur IP subit des micro-coupures, les flux interactifs saccadent et le débit TCP devient instable.
La cause principale réside rarement dans la discipline de file d'attente logicielle (qdisc). La latence indésirable s'accumule plus bas dans la pile réseau, au sein de l'anneau de transmission (TX ring) du pilote matériel de la carte réseau (NIC).
Les adaptateurs Ethernet modernes recourent à des anneaux circulaires profonds (souvent 1024, 2048 voire 4096 descripteurs) pour prévenir toute sous-utilisation matérielle à pleine vitesse de ligne. Pour les flux TCP locaux ordinaires, le noyau Linux utilise TCP Small Queues (TSQ) pour limiter l'accumulation au niveau socket. Cependant, les passerelles VPN fonctionnent sur du trafic encapsulé :
[ Paquets TCP/UDP Applicatifs ] ---> [ Moteur de Tunnel VPN (WireGuard / IPsec) ]
|
v
[ Datagrammes UDP Externes ]
|
v
[ Pile Egress Linux ]
Les paquets internes sont chiffrés et regroupés dans des datagrammes UDP externes. Pour la pile réseau Linux, ce flux apparaît comme du trafic UDP sans contrôle de congestion direct de couche socket. Lorsque le moteur VPN émet des salves massives vers l'anneau TX matériel, les descripteurs se remplissent instantanément.
Tant que les paquets restent piégés dans l'anneau matériel du pilote, les algorithmes AQM de la qdisc logicielle ne peuvent ni les réordonner, ni appliquer de délestage précoce (CoDel drop). Les paquets prioritaires à faible latence (DNS, poignées de main WireGuard, paquets vocaux) se retrouvent coincés derrière des méga-trames de transfert de fichiers.
Fonctionnement interne de dql : l'automate d'adaptation par octets
Pour résoudre ce bufferbloat matériel au niveau pilote, le noyau Linux intègre le sous-système Byte Queue Limits (BQL), propulsé par la bibliothèque générique Dynamic Queue Limits (DQL) située dans lib/dynamic_queue_limits.c.
Conçu par Tom Herbert, BQL déplace le point d'accumulation depuis l'anneau matériel opaque vers la qdisc logicielle administrable. Contrairement aux approches naïves basées sur le comptage fixe de paquets, BQL raisonne exclusivement en octets réels. En effet, un descripteur contenant une trame minimale de 64 octets consomme le même espace de descripteur qu'une trame agrégée TSO/GSO de 64 Ko, mais nécessite mille fois moins de temps de transmission sur le support physique.
+-------------------------------------------------------------+
| Discipline de File d'Attente (qdisc) |
| FQ-CoDel / CAKE / PFIFO_FAST |
+-------------------------------------------------------------+
|
netdev_tx_sent_queue(dev_queue, bytes)
v
+-------------------------------------------------------------+
| Anneau de Transmission Matériel (TX Ring) |
| Capacité maximale : 1024 descripteurs |
| Limite dynamique BQL : ~3 000 à 12 000 octets |
+-------------------------------------------------------------+
|
(Transmission filaire physique)
|
netdev_tx_completed_queue(dev_queue, pkts, bytes)
v
+-------------------------------------------------------------+
| Moteur d'Ajustement dql.c |
| Mesure du temps d'assèchement et mise à jour limit |
+-------------------------------------------------------------+
L'algorithme maintient un modèle dynamique d'exécution piloté par trois variables clés :
num_queued: le volume total d'octets actuellement soumis à la carte et non encore acquittés par interruption de fin de transmission.adj_limit: la limite courante d'octets autorisés dans le pilote avant arrêt de la file logicielle.lowest_slack: le niveau minimal de réserve d'octets observé au cours d'un intervalle de mesure.
Le cycle d'évaluation de dynamic_queue_limits.c
À chaque envoi de trame, le pilote invoque netdev_tx_sent_queue(). Si num_queued dépasse la limite calculée, BQL stoppe la file de transmission logicielle (netif_tx_stop_queue()). L'anneau matériel ne reçoit plus de nouveaux paquets ; les trames suivantes s'empilent dans la qdisc logicielle, où FQ-CoDel peut les prioriser.
Lorsque la carte termine l'émission physique et lève une interruption d'achèvement (NAPI poll), le pilote exécute netdev_tx_completed_queue(). L'automate évalue alors la performance :
- Cas de sur-dimensionnement (slack > 0) : si l'anneau a toujours contenu des octets en réserve pendant tout le cycle sans jamais risquer la famine, la limite était trop large. BQL réduit
adj_limitpour resserrer le tampon matériel et minimiser la latence. - Cas d'assèchement (starvation) : si l'anneau s'est entièrement vidé avant l'arrivée de la salve suivante, le matériel a risqué l'inactivité. BQL augmente progressivement
adj_limitpour garantir que le plein débit de la ligne soit atteint sans goulot d'étranglement.
Grâce à ce mécanisme d'asservissement en boucle fermée, la quantité de données dans le pilote matériel est maintenue au strict minimum requis pour saturer le lien physique (souvent moins de 6 à 12 Ko sur une liaison 10 Gbps, soit moins de 50 microsecondes de rétention).
BQL face aux spécificités des passerelles VPN UDP
Sur une passerelle VPN moderne opérant sous WireGuard, RiceGuard ou IPsec, BQL joue un rôle capital pour préserver la qualité de service sous charge intense :
1. Neutralisation du burst d'agrégation GSO/GRO
Les tunnels VPN utilisent souvent Generic Segmentation Offload (GSO). Lorsqu'un client distant télécharge un fichier volumineux, le noyau regroupe les paquets en super-trames de 64 Ko avant de les chiffrer. Sans BQL, quelques super-trames suffisent à monopoliser l'anneau TX matériel pour plusieurs dizaines de millisecondes. Avec BQL, dès que 12 Ko sont transmis au pilote, la file matérielle se verrouille, contraignant les super-trames suivantes à patienter dans la qdisc.
2. Efficacité totale de FQ-CoDel
Dès lors que le surplus de trafic est maintenu dans la qdisc logicielle, FQ-CoDel sépare les flux par hachage de quadruplet (adresses et ports source/destination). Les petits paquets de contrôle VPN (keepalives, échanges de clés, paquets vocaux UDP) empruntent des files distinctes et dépassent immédiatement les gros flux de transfert de fichiers volumineux.
3. Préservation de l'arbre hiérarchique RiceGuard
Dans les passerelles déployant RiceGuard avec répartition multi-tunnels et files virtuelles, BQL assure que les priorités strictes accordées aux utilisateurs interactifs sont immédiatement reflétées sur le câble, sans être gommées par un anneau de carte réseau saturé de trames asynchrones.
Diagnostic et inspection de BQL sous Linux
Sur un serveur VPN Linux de production, l'état de BQL est directement accessible via le système de fichiers virtuel sysfs. Pour chaque interface réseau matérielle et chaque file de transmission (TX queue), le sous-système exporte ses métriques dans /sys/class/net/<interface>/queues/tx-<N>/byte_queue_limits/ :
# Lister les interfaces réseau et examiner les paramètres BQL sur eth0 tx-0
ls -la /sys/class/net/eth0/queues/tx-0/byte_queue_limits/
# Paramètres consultables :
# - limit : limite actuelle calculée dynamiquement par DQL (en octets)
# - limit_max : plafond absolu configurable
# - limit_min : plancher minimal pour prévenir la famine
# - hold_time : fenêtre temporelle de stabilisation (en millisecondes)
# - bytes : cumul des octets transmis
# - packets : cumul des paquets transmis
Pour observer l'ajustement dynamique en direct pendant un test de charge sur une passerelle VPN :
watch -n 1 'for q in /sys/class/net/eth0/queues/tx-*/byte_queue_limits/limit; do
echo -n "$q: "; cat "$q";
done'
Si le fichier byte_queue_limits est absent du répertoire queues/tx-0, cela indique que le pilote de la carte réseau n'implémente pas les fonctions BQL (netdev_tx_sent_queue et netdev_tx_completed_queue). La grande majorité des pilotes Ethernet modernes pour serveurs (e1000e, igb, ixgbe, i40e, ice, bnxt_en, mlx4, mlx5) supportent nativement BQL.
Guide de configuration pour passerelle VPN haute performance
Pour tirer le meilleur parti de BQL sur une passerelle VPN Linux, voici les recommandations éprouvées en production :
1. Associer BQL à un ordonnanceur moderne (CAKE ou FQ-CoDel)
BQL n'est pas un ordonnanceur à lui seul ; il est le gardien qui rend les ordonnanceurs logiciels efficaces. Configurez CAKE ou FQ-CoDel par défaut :
# Appliquer fq_codel ou cake sur l'interface physique externe
sudo tc qdisc replace dev eth0 root fq_codel ecn
2. Conserver les anneaux matériels à leur taille standard
Une erreur fréquente d'administration consiste à réduire manuellement la taille de l'anneau de descripteurs via ethtool -G eth0 tx 128 pour tenter de réduire la latence. Cette manipulation dégrade les performances à très haut débit car le matériel risque l'assèchement en cas de pic de charge CPU. Avec BQL actif, vous pouvez conserver des anneaux profonds (1024 ou 2048 descripteurs) : BQL régulera automatiquement la quantité d'octets réellement injectée sans risque de latence excessive.
3. Vérification des interfaces virtuelles
Notez que les interfaces virtuelles pures comme wg0 (WireGuard) ou tun0 n'utilisent pas d'anneau matériel physique et ne disposent donc pas de BQL dans leur pseudo-pilote. Le contrôle BQL s'exerce sur l'interface physique externe (eth0, enp1s0) qui transporte les paquets UDP chiffrés sortants vers Internet.
L'activation conjointe de BQL et d'une qdisc équitable au niveau de la passerelle garantit une latence minimale constante et une réactivité instantanée pour l'ensemble des tunnels VPN connectés.



