15.8. Le Conditionneur de Trafic Ultime : Faible temps de latence, Téléchargement vers l'amont et l'aval rapide

Note : ce script a récemment été mis à niveau et il ne marchait avant qu'avec les clients Linux de votre réseau ! Vous devriez donc le mettre à jour si vous avez des machines Windows ou des Macs dans votre réseau qui n'étaient pas capables de télécharger plus rapidement pendant que d'autres étaient en train de télécharger vers l'amont.

J'ai essayé de créer le Saint Graal :

Maintenir à tout moment un faible temps de latence pour le trafic interactif

Ceci signifie que la récupération ou la transmission de fichiers ne doivent pas perturber SSH ou même telnet. Ceci est la chose la plus importante, car même un temps de latence de 200ms est important pour pouvoir travailler confortablement.

Autoriser le 'surf' à des vitesses raisonnables pendant que l'on télécharge vers l'amont ou vers l'aval

Même si http est un trafic de masse, les autres trafics ne doivent pas trop le noyer.

Etre sûr que le téléchargement vers l'amont ne va pas faire du tort aux téléchargements vers l'aval et aux autres éléments autour

Le principal phénomène observé est la forte réduction de la vitesse de téléchargement vers l'aval quand il y a du trafic montant.

Il s'avère que tout ceci est possible, au prix d'une minuscule réduction de la bande passante. La présence de grandes files d'attente sur les dispositifs d'accès domestiques, comme le câble ou les modems DSL, explique pourquoi les téléchargements vers l'amont, vers l'aval et ssh se pénalisent mutuellement.

La prochaine partie explique en profondeur ce qui provoque les retards, et comment nous pouvons les corriger. Vous pouvez sans danger la passer et aller directement au script si vous vous fichez de la façon dont la magie opère.

15.8.1. Pourquoi cela ne marche t-il pas bien par défaut ?

Les FAI savent que leurs performances ne sont seulement jugées que sur la vitesse à laquelle les personnes peuvent télécharger vers l'aval. En plus de la bande passante disponible, la vitesse de téléchargement est lourdement influencée par la perte des paquets, qui gêne sérieusement les performances de TCP/IP. Les grandes files d'attente peuvent aider à prévenir la perte des paquets, et augmenter les téléchargements. Les FAI configurent donc de grandes files d'attente.

Ces grandes files d'attente endommagent cependant l'interactivité. Une frappe doit d'abord parcourir la file d'attente du flux montant, ce qui peut prendre plusieurs secondes, et aller jusqu'à l'hôte distant. Elle est alors traitée, conduisant à un paquet de retour qui doit traverser la file d'attente du flux descendant, localisée chez votre FAI, avant qu'elle n'apparaisse sur l'écran.

Cet HOWTO nous enseigne plusieurs manières de modifier et traiter la file d'attente mais, malheureusement, toutes les files d'attente ne nous sont pas accessibles. Les files d'attente du FAI sont sans limites et la file d'attente du flux montant réside probablement dans votre modem câble ou votre périphérique DSL. Il se peut que vous soyez capable ou non de le configurer. La plupart du temps, ce ne sera pas le cas.

Et après ? Etant donné que nous ne pouvons pas contrôler ces files d'attente, elles doivent disparaître et être transférées sur notre routeur Linux. Heureusement, ceci est possible.

Limiter la vitesse de téléchargement vers l'amont (upload)

En limitant notre vitesse de téléchargement vers l'amont à une vitesse légèrement plus faible que la vitesse réelle disponible, il n'y a pas de files d'attente mises en place dans notre modem. La file d'attente est maintenant transférée vers Linux.

Limiter la vitesse de téléchargement vers l'aval (download)

Ceci est légèrement plus rusé dans la mesure où nous ne pouvons pas vraiment influencer la vitesse à laquelle Internet nous envoie les données. Nous pouvons cependant rejeter les paquets qui arrivent trop vite, ce qui provoque le ralentissement de TCP/IP jusqu'au débit désiré. Comme nous ne voulons pas supprimer inutilement du trafic, nous configurons une vitesse de rafale ('burst') plus grande.

Maintenant que nous avons fait ceci, nous avons éliminé totalement la file d'attente du flux descendant (sauf pour de courtes rafales de données), et obtenu la possibilité de gérer la file d'attente du flux montant avec toute la puissance Linux.

Il nous reste à nous assurer que le trafic interactif se retrouve au début de la file d'attente du flux montant. Pour être sûr que le flux montant ne va pas pénaliser le flux descendant, nous déplaçons également les paquets ACK au début de la file d'attente. C'est ce qui provoque normalement un énorme ralentissement quand du trafic de masse est généré dans les deux sens. Les paquets ACK du trafic descendant rentrent en concurrence avec le trafic montant et sont donc ralentis.

Si nous avons fait tout ceci, nous obtenons les mesures suivantes en utilisant l'excellente connexion ADSL de xs4all, en Hollande :

Temps de latence de base :
round-trip min/avg/max = 14.4/17.1/21.7 ms

Sans le conditionneur de trafic, lors d'un téléchargement vers l'aval :
round-trip min/avg/max = 560.9/573.6/586.4 ms

Sans le conditionneur de trafic, lors d'un téléchargement vers l'amont :
round-trip min/avg/max = 2041.4/2332.1/2427.6 ms

Avec le conditionneur, lors d'un téléchargement vers l'amont à 220kbit/s :
round-trip min/avg/max = 15.7/51.8/79.9 ms

Avec le conditionneur, lors d'un téléchargement vers l'aval à 850kbit/s :
round-trip min/avg/max = 20.4/46.9/74.0 ms

Lors d'un téléchargement vers l'amont, les téléchargements vers l'aval s'effectuent à environ
80 % de la vitesse maximale disponible et 90% pour les téléchargements vers
l'amont. Le temps de latence augmente alors jusqu'à 850 ms ; je n'ai pas encore
déterminé la raison de ce phénomène.

Ce que vous pouvez attendre de ce script dépend largement de votre vitesse de lien réelle. Quand vous téléchargez vers l'amont à pleine vitesse, il y aura toujours un paquet devant votre frappe de clavier. Ceci est la limite basse de votre temps de latence. Pour la calculer, divisez votre MTU par la vitesse du flux montant. Les valeurs classiques seront un peu plus élevées que ça. Diminuez votre MTU pour un meilleur effet !

Voici deux versions de ce script, une avec l'excellent HTB de Devik, et l'autre avec CBQ qui est présent dans chaque noyau Linux, contrairement à HTB. Les deux ont été testés et marchent correctement.

15.8.2. Le script (CBQ)

Marche avec tous les noyaux. A l'intérieur du gestionnaire de mise en file d'attente CBQ, nous plaçons deux SFQ pour être sûr que de multiples flux de masse ne vont pas mutuellement se pénaliser.

Le trafic descendant est réglementé en utilisant un filtre tc contenant un Token Bucket Filter.

Vous pourriez améliorer ce script en ajoutant 'bounded' aux lignes qui démarrent avec 'tc class add .. classid 1:20'. Si vous avez diminué votre MTU, diminuez aussi les nombres allot & avpkt !

#!/bin/bash 

# La configuration ultime pour votre connexion Internet domestique
# 
# Configurez les valeurs suivantes avec des valeurs légèrement inférieures que 
# vos vitesses de flux montant et descendant. Exprimé en kilobits.
DOWNLINK=800
UPLINK=220
DEV=ppp0

# Nettoie les gestionnaires de sortie et d'entrés, cache les erreurs
tc qdisc del dev $DEV root    2> /dev/null > /dev/null
tc qdisc del dev $DEV ingress 2> /dev/null > /dev/null

###### Flux montant (uplink)

# installe CBQ à la racine

tc qdisc add dev $DEV root handle 1: cbq avpkt 1000 bandwidth 10mbit 

# Le trafic est mis en forme à une vitesse de $UPLINK. Ceci évite
# d'énormes files d'attente dans votre modem DSL qui pénalisent le temps de
# latence.
# Classe principale

tc class add dev $DEV parent 1: classid 1:1 cbq rate ${UPLINK}kbit \
allot 1500 prio 5 bounded isolated 

# classe de priorité supérieure 1:10:

tc class add dev $DEV parent 1:1 classid 1:10 cbq rate ${UPLINK}kbit \
   allot 1600 prio 1 avpkt 1000

# la classe par défaut et pour le trafic de masse 1:20. Reçoit légèrement
# moins que le trafic et a une priorité plus faible :
# bulk and default class 1:20 - gets slightly less traffic, 
#  and a lower priority:

tc class add dev $DEV parent 1:1 classid 1:20 cbq rate $[9*$UPLINK/10]kbit \
   allot 1600 prio 2 avpkt 1000

# Les deux sont gérées par SFQ :
tc qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev $DEV parent 1:20 handle 20: sfq perturb 10

# Démarrage des filtres
# le bit Délai Minimum du champ TOS (ssh, PAS scp) est dirigé vers
# 1:10 :
tc filter add dev $DEV parent 1:0 protocol ip prio 10 u32 \
      match ip tos 0x10 0xff  flowid 1:10
# ICMP (ip protocol 1) est dirigé vers la classe interactive 1:10 de telle
# sorte que nous pouvons réaliser des mesures et impressionner nos
# amis :
tc filter add dev $DEV parent 1:0 protocol ip prio 11 u32 \
        match ip protocol 1 0xff flowid 1:10

# Pour accélérer les téléchargements vers l'aval lors de la présence d'un
# flux montant, les paquets ACK sont placés dans la classe
# interactive :

tc filter add dev $DEV parent 1: protocol ip prio 12 u32 \
   match ip protocol 6 0xff \
   match u8 0x05 0x0f at 0 \
   match u16 0x0000 0xffc0 at 2 \
   match u8 0x10 0xff at 33 \
   flowid 1:10

# Le reste est considéré 'non-interactif' cad 'de masse' et fini dans 1:20

tc filter add dev $DEV parent 1: protocol ip prio 13 u32 \
   match ip dst 0.0.0.0/0 flowid 1:20

########## Flux descendant (downlink) #############
# Ralentir le flux descendant à une valeur légèrement plus faible que votre
# vitesse réelle de manière à éviter la mise en file d'attente chez notre
# FAI. Faites des tests pour voir la vitesse maximum à laquelle vous pouvez
# le configurer. Les FAI ont tendance à avoir *d'énormes* files d'attente
# pour s'assurer de la rapidité des gros téléchargements.
#
# attache la réglementation d'entrée (ingress policer) :

tc qdisc add dev $DEV handle ffff: ingress

# Filtre *tout* (0.0.0.0/0), rejette tout ce qui arrive trop
# rapidement :

tc filter add dev $DEV parent ffff: protocol ip prio 50 u32 match ip src \
   0.0.0.0/0 police rate ${DOWNLINK}kbit burst 10k drop flowid :1

Si vous voulez que ce script soit exécuté par ppp à la connexion, copiez-le dans /etc/ppp/ip-up.d.

Si les deux dernières lignes conduisent à une erreur, mettez à jour l'outil tc avec la dernière version !

15.8.3. Le script (HTB)

Le script suivant nous permet d'atteindre tous nos buts en utilisant la merveilleuse file d'attente HTB. Voir le chapitre correspondant. Cela vaut la peine de mettre à jour votre noyau !

#!/bin/bash

# La configuration ultime pour votre connexion Internet domestique
# 
# Configurez les valeurs suivantes avec des valeurs légèrement inférieures que 
# vos vitesses de flux montant et descendant. Exprimé en kilobits.
DOWNLINK=800
UPLINK=220
DEV=ppp0

#Nettoie les gestionnaires de sortie et d'entrés, cache les erreurs
tc qdisc del dev $DEV root    2> /dev/null > /dev/null
tc qdisc del dev $DEV ingress 2> /dev/null > /dev/null

###### Flux montant (uplink)

# installe HTB à la racine, le trafic ira par défaut vers 1:20 :

tc qdisc add dev $DEV root handle 1: htb default 20

# Le trafic est mis en forme à une vitesse de $UPLINK. Ceci évite
# d'énormes files d'attente dans votre modem DSL qui pénalisent le temps de
# latence.

tc class add dev $DEV parent 1: classid 1:1 htb rate ${UPLINK}kbit burst 6k

# la classe de haute priorité 1:10 :

tc class add dev $DEV parent 1:1 classid 1:10 htb rate ${UPLINK}kbit \
   burst 6k prio 1

# bulk & default class 1:20 - gets slightly less traffic, 
# and a lower priority:

tc class add dev $DEV parent 1:1 classid 1:20 htb rate $[9*$UPLINK/10]kbit \
   burst 6k prio 2

# Les deux sont gérées par SFQ :
tc qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev $DEV parent 1:20 handle 20: sfq perturb 10

# le bit Délai Minimum du champ TOS (ssh, PAS scp) est dirigé vers
# 1:10 :
tc filter add dev $DEV parent 1:0 protocol ip prio 10 u32 \
      match ip tos 0x10 0xff  flowid 1:10

# ICMP (ip protocol 1) est dirigé vers la classe interactive 1:10 de telle
# sorte que nous pouvons réaliser des mesures et impressionner nos
# amis :
tc filter add dev $DEV parent 1:0 protocol ip prio 10 u32 \
        match ip protocol 1 0xff flowid 1:10

# Pour accélérer les téléchargements vers l'aval lors de la présence d'un
# flux montant, les paquets ACK sont placés dans la classe
# interactive :

tc filter add dev $DEV parent 1: protocol ip prio 10 u32 \
   match ip protocol 6 0xff \
   match u8 0x05 0x0f at 0 \
   match u16 0x0000 0xffc0 at 2 \
   match u8 0x10 0xff at 33 \
   flowid 1:10

# Le reste est considéré 'non-interactif' cad 'de masse' et fini dans 1:20


########## Flux descendant (downlink) #############
# Ralentir le flux descendant à une valeur légèrement plus faible que votre
# vitesse rélle de manière à éviter la mise en file d'attente chez notre
# FAI. Faites des tests pour voir la vitesse maximum à laquelle vous pouvez
# le configurer. Les FAI ont tendance à avoir *d'énormes* files d'attente
# pour s'assurer de la rapidité des gros téléchargements.
#
# attache la réglementation d'entrée (ingress policer) :

tc qdisc add dev $DEV handle ffff: ingress

# Filtre *tout* (0.0.0.0/0), rejette tout ce qui arrive trop
# rapidement :

tc filter add dev $DEV parent ffff: protocol ip prio 50 u32 match ip src \
   0.0.0.0/0 police rate ${DOWNLINK}kbit burst 10k drop flowid :1

Si vous voulez que ce script soit exécuté par ppp à la connexion, copiez-le dans /etc/ppp/ip-up.d.

Si les deux dernières lignes conduisent à une erreur, mettez à jour l'outil tc avec la dernière version !