QoS sous Linux

avril 04, 2013  |   Blog   |     |   Commentaires fermés sur QoS sous Linux

Introduction

Nous allons voir dans cette article comment il est possible d’appréhender la QoS (Quality Of Service) au travers d’un routeur Linux.

Tout d’abord, les prérequis sont les suivants :
Un routeur Linux
Netfilter/iptables
tc

Il faut aussi noter qu’il est aisé d’effectuer de la qualité de service sur ce qui est émis par un réseau mais quasi impossible de contrôler ce qui est reçu.

Dans la suite de cet article, nous imaginerons vouloir effectuer de la QoS sur des flux sortants répartis en 5 catégories :
ICMP
DNS/NTP/SNMP
SSH
HTTP(S) / FTP / …
Les autres, servis en derniers

Nous créerons une politique de QoS pour une ligne SDSL à 5Mbps connectée sur eth0 et un LAN 100Mbps connecté sur eth1.

Netfilter

Pour commencer, comme dit dans les prérequis, il est nécessaire d’avoir à sa disposition un routeur avec iptables permettant de contrôler le firewall fourni par Linux. Plus particulièrement nous aurons besoin de la table mangle qui permet de modifier les paquets le traversant.

Grâce à cette table, nous allons marquer les paquets via le champ nfmark fourni par Netfilter qui sera ensuite interprété par tc afin de savoir dans quelle file d’attente le paquet va être placé.

Ce qui donne avec notre scénario :

Nous marquons les paquets les plus prioritaires ICMP avec le marqueur 10 :

 iptables -t mangle -A POSTROUTING -p icmp -o eth0 -j MARK --set-mark 10

Nous marquons les paquets UDP (DNS/NTP/SNMP) avec le marqueur 20 :

 iptables -t mangle -A POSTROUTING -p udp --dport 53 -o eth0 -j MARK --set-mark 20
 iptables -t mangle -A POSTROUTING -p udp --dport 123 -o eth0 -j MARK --set-mark 20
 iptables -t mangle -A POSTROUTING -p udp --dport 161:162 -o eth0 -j MARK --set-mark 20

Nous marquons les paquets SSH avec le marqueur 30 :

 iptables -t mangle -A POSTROUTING -p tcp --dport 22 -o eth0 -j MARK --set-mark 30

Nous marquons les paquets HTTP(S)/FTP/IMAP avec le marqueur 40 :

 iptables -t mangle -A POSTROUTING -p tcp --dport 80 -o eth0 -j MARK --set-mark 40
 iptables -t mangle -A POSTROUTING -p tcp --dport 443 -o eth0 -j MARK --set-mark 40
 iptables -t mangle -A POSTROUTING -p tcp --dport 20:21 -o eth0 -j MARK --set-mark 40
 iptables -t mangle -A POSTROUTING -p tcp --dport 143 -o eth0 -j MARK --set-mark 40
 iptables -t mangle -A POSTROUTING -p tcp --dport 993 -o eth0 -j MARK --set-mark 40

Maintenant que nos paquets sont marqués, nous pouvons créer l’arbre de QoS avec tc.

TC

Le binaire Linux pour contrôler la QoS est tc pour traffic control. Cet utilitaire permet de configurer qdisc (qui signifie Queuing Discipline) et permet donc de gérer le fonctionnement des files d’attente.

Avec tc il est possible de gérer différent type de file comme FIFO (First In First Out), bFIFO (FIFO avec granularité par bytes), pFIFO (FIFO avec granularité par paquet), RED (Random Early Detection), HTB (Hierarchical Token Bucket), …

Dans cet article, nous allons utiliser htb (pour plus de détails sur le fonctionnement, consulter la ref[3]).

Avec tc, la QoS sous linux est gérée sous la forme d’arbre sur l’interface sortante des paquets.

Nous allons donc commencer par créer la racine de l’interface eth0 par laquelle les paquets sont émis après le routage :

tc qdisc add dev eth0 root handle 1: htb default 100

Explication de la ligne :
eth0 -> interface sortante
1: -> ID de la racine 1 (0 étant la racine par défaut sans QoS)
htb -> qdisc à appliquer
default 100 -> feuille par défaut à appliquer

Nous créons ensuite une branche pour la ligne SDSL de 5Mbps :

tc class add dev eth0 parent 1:0 classid 1:5 htb rate 5mbit mtu 1500

Explication de la ligne :
eth0 -> interface sortante
1:0 -> Noeud / racine parent de la branche (ici le 1)
classid 1:5 -> id de la branche (on commence ici à 5)
htb -> qdisc à appliquer
rate 5mbit -> débit max de la branche
mtu 1500 -> taille maximale des paquets

Enfin, nous pouvons créer nos feuilles suivant les catégories :

 tc class add dev eth0 parent 1:5 classid 1:10 htb rate 500kbit ceil 5mbit prio 1
 tc class add dev eth0 parent 1:5 classid 1:20 htb rate 500kbit ceil 5mbit prio 2
 tc class add dev eth0 parent 1:5 classid 1:30 htb rate 1mbit ceil 5mbit prio 3
 tc class add dev eth0 parent 1:5 classid 1:40 htb rate 3mbit ceil 5mbit prio 4
 tc class add dev eth0 parent 1:5 classid 1:100 htb rate 1mbit ceil 5mbit prio 7

Explication des lignes :
parent 1:5 -> On rattache tous ces paramètres à la branche 1:5
classid 1:10 – 1:40 -> On affecte les id de 10 a 40 à ces politiques
htb -> On utilise toujours la meme qdisc
rate xxxkbit -> On garantit xxxkbit de bande passante pour ce flux
ceil 5mbit -> On autorise à utiliser jusqu’à la valeur définie par “ceil” si les autres flux ne consomment pas la totalité de ce qui leur est alloué
prio x -> indique la priorité de la politique (0 étant la plus prioritaire)

Noter la politique 100 définie comme la classe par défaut servant de collecteur pour les flux non marqués par netfilter.

Il ne reste plus qu’à indiquer à tc quel marquage correspond à quelle politique.

 tc filter add dev eth0 parent 1: protocol ip prio 1 handle 10 fw flowid 1:10
 tc filter add dev eth0 parent 1: protocol ip prio 2 handle 20 fw flowid 1:20
 tc filter add dev eth0 parent 1: protocol ip prio 3 handle 30 fw flowid 1:30
 tc filter add dev eth0 parent 1: protocol ip prio 4 handle 40 fw flowid 1:40

Nous pouvons alors observer que les flux passent bien dans les politiques grâce à la commande :

 tc -s class show dev eth0

Qui affichera un paragraphe du type suivant par classe :

class htb 1:10 parent 1:5 prio 7 rate 100000bit ceil 5000Kbit burst 1600b cburst 1600b
  Sent 8006 bytes 53 pkt (dropped 0, overlimits 0 requeues 0)
  rate 584bit 1pps backlog 0b 0p requeues 0
  lended: 53 borrowed: 0 giants: 0
  tokens: 1870000 ctokens: 37407

Nous verrons alors le total des octets/paquets envoyés ainsi que le débit consommé en instantané par la classe (ici 1,936 kbits soit 2 paquets par seconde)

Qualité de service entrante

Comme dit plus haut, il est quasi impossible de contrôler les flux entrants sur un routeur, il est toutefois possible, grâce à TCP, d’en réguler l’arrivée. En effet, en utilisant les mecanismes de TCP il est possible de réguler une transmission soit :
en jetant des paquets : Provoque des retransmissions et divise le débit d’émission de la source
en retardant les acquittements : La fenêtre TCP se remplit de sorte que la source ne peut plus envoyer de paquets.

Il est donc possible d’appliquer sur eth1 la même logique qu’expliquée tout au long de cet article.

Conclusion

Au final, il est relativement aisé de créer une QoS sous linux grâce au couple iptables/tc.
Il faut toutefois garder à l’esprit que la QoS s’applique sur l’interface de sortie du flux et qu’il est beaucoup plus aisé de contrôler ce qu’on envoie plutôt que ce que l’on reçoit.

Bibliographie

[1] http://www.linuxembedded.fr/2011/06/utiliser-tc-pour-optimiser-lupload/
[2] http://tldp.org/HOWTO/Traffic-Control-HOWTO/classless-qdiscs.html
[3] http://tldp.org/HOWTO/Traffic-Control-HOWTO/classful-qdiscs.html
[4] http://wiki.linuxwall.info/doku.php/fr:ressources:dossiers:networking:qos_traffic_control
[5] http://linux.die.net/man/8/tc-bfifo

Les commentaires sont fermés.