QOS sous Linux avec TC

L’objectif de cette article et de mettre en place un système de contrôle du trafic sortant d’un serveur. Admettons que ce serveur soit en DMZ et serve simultanément un réseau local et le net :

+----------+                         +-----+
| internet |=======>[SERVEUR]<=======| LAN |
+----------+                         +-----+

Le net est en 1Mbits/s et le LAN en 100Mbits/s. Les services sont de trois types :

  • dns,snmp,ntp… les services udp indispensables mais sans besoins de bande passante ;
  • ssh, indispensable quoi qu’il arrive ;
  • les services ftp,web,mail coûteux en bande passante mais pouvant éventuellement être ralentis.

Internet et le LAN n’ayant pas le même débit maximal, on va créer deux sous-arbres séparés ayant leurs règles propres.

Voilà comment on procède :

1. Netfilter permet de marquer les différents paquets. Cette marque apparaît dans le champ « nfmark » de la structure sk_buf qui représente chaque paquet dans le noyau. On va donc utiliser cela pour catégoriser nos différents flux sortants.

2. tc, le binaire de trafic control, va nous permettre de créer notre arbre root et les deux sous-arbres ainsi que leurs feuilles.

3. Afin de tester tout cela, un peu d’iptraf, de telnet et un vmware.

Netfilter MARK

Netfilter permet d’interagir directement avec la structure représentant un paquet dans le noyau. Cette structure, le sk_buff, possède un champ « __u32 nfmark » que l’on va renseigner et qui sera lu par le filtre de TC pour sélectionner la classe de destination du paquet.

En considérant que $IPT et le binaire iptables et que $LAN représente l’adresse du réseau local (ex : 192.168.1.0/24), le jeu de règles suivant permet de marquer 6 catégories de paquets :

echo " INTERNET #QOS Layer 1 : snmp, dns, ssh"
$IPT -t mangle -A OUTPUT -p udp ! -d $LAN -m multiport --sports 53,123,161:162 -j MARK --set-mark 1

echo " INTERNET #QOS Layer 2 : ssh"
$IPT -t mangle -A OUTPUT -p tcp ! -d $LAN --sport 22 -j MARK --set-mark 2

echo " INTERNET #QOS Layer 3 : services http, https, ftp, ..."
$IPT -t mangle -A OUTPUT -p tcp ! -d $LAN -m multiport --sports 20:21,25,80,443 -j MARK --set-mark 3

# mark du reseau local
echo " LAN #QOS Layer 1 : snmp, dns, ssh"
$IPT -t mangle -A OUTPUT -p udp -d $LAN -m multiport --sports 53,123,161:162 -j MARK --set-mark 4

echo " LAN #QOS Layer 2 : ssh"
$IPT -t mangle -A OUTPUT -p tcp -d $LAN --sport 22 -j MARK --set-mark 5

echo " LAN #QOS Layer 3 : services http, https, ftp, ..."
$IPT -t mangle -A OUTPUT -p tcp -d $LAN -m multiport --sports 20:21,25,80,443 -j MARK --set-mark 6 

On retrouve nos 3 catégories de flux, et nos deux réseaux, ce qui fait 6 catégories. On ne marque que les flux sortant de OUTPUT (ce qui nous laisse POSTROUTING pour loguer, au cas où).

Traffic Control

En Théorie

Trafic Control (TC) est un système de file d’attente avec priorité permettant de contrôler la façon dont les paquets sont transmis par le système. La base de TC est la Queuing Discipline (qdisc) qui représente la politique de scheduling appliquée à une file d’attente. Il existe différentes qdisc. Comme pour le scheduling processeur, on retrouve les méthodes FIFO, FIFO à plusieurs files, FIFO avec Round Robin à la sortie (SFQ). On a également un système Token Bucket Filter (TBF) qui attribue des tokens à une qdisc pour en limiter le débit (pas de token = pas de transmission → on attend d’en avoir un a dispo).

La politique que nous allons utiliser mélange ces techniques : c’est le HTB, pour Hierarchical Token Bucket. Il s’agit d’un algorithme qui mélange le SFQ et le TBF dans les feuilles d’un arbre.

HTB fait l’objet du chapitre 7 du Traffic Control Howto (http://tldp.org/HOWTO/Traffic-Control-HOWTO/classful-qdiscs.html). Aussi, plutôt que de paraphraser et de risquer d’insérer des bêtises, je vous renvoi directement à ce chapitre. Note : il vaut mieux commencer par la lecture du chapitre 6 pour comprendre les concepts à la base de HTB (http://tldp.org/HOWTO/Traffic-Control-HOWTO/classless-qdiscs.html).

En Pratique

Il faut tout d’abord créer une racine à l’arbre. Cette racine contient :

  • le nom de l’interface réseau (eth0),
  • le numéro de la racine (ici 1). 0 (zéro) est la racine par défaut n’appliquant pas de politique, donc allant à la vitesse du fil.
  • la politique à appliquer, on a donc dit que l’on prenait « htb »
  • et le numéro de la feuille (class) de l’arbre à prendre par défaut
tc qdisc add dev eth0 root handle 1: htb default 13

Sur cette racine, on va créer deux branches : une pour Internet, l’autre pour le LAN. Chacune de ces branches a un identifiant de classid (rattaché à la racine) et un débit propre (rate).

tc class add dev eth0 parent 1:0 classid 1:10 htb rate 1mbit mtu 1500
tc class add dev eth0 parent 1:0 classid 1:20 htb rate 100mbit mtu 1500

10 sera donc la branche Internet, et 20 la branche LAN.

Maintenant, sur ces branches, on va créer des classes (des feuilles). Pour chaque branche, on a 3 feuilles, conformément à ce que nous avons définit dans les MARK de Netfilter. Chaque classe a son débit propre, limité, et la somme des 3 débits égale le débit de la branche. On va rajouter une règle « ceil » qui autorise une classe à empreinter du débit jusqu’au maximum de la branche. Ceci étant possible si, bien sur, ce débit n’est pas utilisé par une autre classe. Enfin, on définit des priorités. La classe des services UDP passe d’abord (prio 1), mais son débit est limité sans empreint possible. Ensuite vient le SSH (prio 2), afin d’éviter de se retrouver avec une console qui rame lorsqu’un transfert est en cours. Enfin, les services (prio 3). Ils passeront en dernier, car ce sont les plus gourmands et les plus susceptibles de congestionner l’interface.

On a donc :

tc class add dev eth0 parent 1:10 classid 1:11 htb rate 200kbit prio 1
tc class add dev eth0 parent 1:10 classid 1:12 htb rate 200kbit ceil 1mbit prio 2
tc class add dev eth0 parent 1:10 classid 1:13 htb rate 600kbit ceil 1mbit prio 3

et

tc class add dev eth0 parent 1:20 classid 1:21 htb rate 1mbit prio 1
tc class add dev eth0 parent 1:20 classid 1:22 htb rate 20mbit ceil 100mbit prio 2
tc class add dev eth0 parent 1:20 classid 1:23 htb rate 60mbit ceil 100mbit prio 3

Nous avons maintenant d’un coté un arbre de contrôle de trafic, et d’un autre coté du marking de paquets. Il reste donc à relier les deux. Cela est fait avec les règles de filtrage. Ces règles sont très simples. On dit simplement à TC de regarder (handle) les paquets portant les marques 1 à 6 et de les envoyer aux chaines correspondantes. Un point important toutefois, les filtres doivent être rattachés à la racine « root » de l’arbre. Sinon, d’après ce que j’ai constaté, ils ne sont pas pris en compte.

D’abord, les filtres pour le LAN car cela va être l’essentiel du débit.

tc filter add dev eth0 parent 1:0 protocol ip prio 1 handle 4 fw flowid 1:21
tc filter add dev eth0 parent 1:0 protocol ip prio 2 handle 5 fw flowid 1:22
tc filter add dev eth0 parent 1:0 protocol ip prio 3 handle 6 fw flowid 1:23

Ensuite, les filtres pour le net.

tc filter add dev eth0 parent 1:0 protocol ip prio 4 handle 1 fw flowid 1:11
tc filter add dev eth0 parent 1:0 protocol ip prio 5 handle 2 fw flowid 1:12
tc filter add dev eth0 parent 1:0 protocol ip prio 6 handle 3 fw flowid 1:13

Une fois la politique en place, on peut visualiser l’arbre avec les commandes

tc -s qdisc show dev eth0
tc -s class show dev eth0

En version graphique, ca donne quelque chose de l’ordre de l’arbre suivant. La hauteur d’une feuille représente sa priorité (plus c’est haut, plus la priorité est basse, plus vite le paquet est processé). Les box en gris représentes les scheduler appliqués au paquet dans une classe (voir doc HTB).

Testons tout cela

Pour tester, y’a pas 36 méthodes, il faut charger l’interface et voir comment elle réagit. Une méthode simple consiste à lancer netcat comme serveur de zéro, c’est à dire qu’il renvoie au client le contenu de /dev/zero le plus vite possible. Au niveau du client, un simple telnet sur le port du netcat fera l’affaire.

Pour observer le débit de chaque connexion, j’utilise iptraf qui a l’avantage d’afficher le débit en temps réel. Cela permet d’observer à l’œil nu les effets du lancement et de la coupure de tel ou tel service.

Ce que l’on voit dans la capture d’écran ci-dessus, c’est la QoS sur la classe 13, qui a un débit limité à 600kbit/s mais peut empreinter jusqu’à 1mbits/s. On a donc trois connexions TCP qui se partage la ligne, et ce que nous montre iptraf c’est que les débits pour chaque connexion oscille entre 325 et 340kbits/s (1mbits/s divisé par 3). Il faut regarder le « TCP flow rate » en bas à droite.

Après, pour bien évaluer l’impact, il faut faire ce test en mixant des flux de différentes classes. J’ai fait le test avec SSH en plus des 3 connexions TCP précédentes, et ca marche plutôt bien. Latence minime (je faisais un cat de syslog quand même…) alors que sans la QOS c’est carrément la déconnexion de putty….

Pour les remarques/corrections/suggestions : julien{at}linuxwall.info

~~DISCUSSION~~

fr/ressources/dossiers/networking/qos_traffic_control.txt · Last modified: 2011/03/16 01:41 (external edit)
CC Attribution-Noncommercial-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0