LINUX QOS USING HTB
Détails
Le but de ce howto est de mettre en place un mécanisme de qualité de service sur votre passerelle Linux.
Cela permettra de classifier les paquets qui traversent votre passerelle et de limiter ou de mettre des priorités
à certain des flux. Il y a plusieurs type de classement et queues utilisable sous Linux mais je n'aborde ici que HTB. Versions :
- iproute2-2.6.11-050330 / Custom Build ou Debian Package |
Avant de commencer la mise en place, il est important de connaitre la bande passante exacte dont vous disposez. Dans mon cas,
aprés des tests j'obtenais environ 11000 Kbits/s en download, mais pour que la QOS fonctionne correctement avec HTB il faut se laisser
une marge de "gestion" qui dans la pratique s'élève environ a 10 ou 15%. Donc pour ma ligne j'ai décidé d'arrondir à 10000 kbits/s,
c'est cette valeur qui determinera ma bande passante maximal dans HTB.
Une fois cela fait il vous aussi connaitre votre trafic (web, mail, etc...), savoir la part du gateau que vous voulez attribuer à chaque
type de trafic et comment selon les cas la bande passante doit être répartie. C'est à partir de cette réflexion que l'on construira l'arbre
HTB. (voir schèma)
Mais passons à la pratique pour mieux appréhender tout ça. Nous utiliserons iptables et Netfilter pour marquer les paquets. Je ne rentrerais pas dans les détails du fonctionnement d'iptables ici mais un exemple de règles que j'utilise devrait suffire. Comme traditionnellement il va falloir vous assurez que votre noyau gère la QOS, HTB, Netfilter et les différentes options dont nous aurons besoin. Pour informations voici les options que j'utilise, elles ne sont pas forcéments toutes indispensables ici mais pour tout vous avouer je suis trop faignant pour faire un tri spécifique pour ce howto :)
# # IP: Netfilter Configuration # CONFIG_IP_NF_CONNTRACK=y CONFIG_IP_NF_CONNTRACK_MARK=y CONFIG_IP_NF_FTP=y CONFIG_IP_NF_TFTP=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_LIMIT=y CONFIG_IP_NF_MATCH_IPRANGE=y CONFIG_IP_NF_MATCH_MAC=y CONFIG_IP_NF_MATCH_PKTTYPE=y CONFIG_IP_NF_MATCH_MARK=y CONFIG_IP_NF_MATCH_MULTIPORT=y CONFIG_IP_NF_MATCH_HELPER=y CONFIG_IP_NF_MATCH_STATE=y CONFIG_IP_NF_MATCH_CONNTRACK=y CONFIG_IP_NF_MATCH_CONNMARK=y CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_TARGET_REJECT=y CONFIG_IP_NF_TARGET_IMQ=y CONFIG_IP_NF_TARGET_LOG=y CONFIG_IP_NF_TARGET_ULOG=y CONFIG_IP_NF_NAT=y CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=y CONFIG_IP_NF_TARGET_REDIRECT=y CONFIG_IP_NF_TARGET_NETMAP=y CONFIG_IP_NF_NAT_FTP=y CONFIG_IP_NF_NAT_TFTP=y CONFIG_IP_NF_MANGLE=y CONFIG_IP_NF_TARGET_MARK=y CONFIG_IP_NF_TARGET_CLASSIFY=y CONFIG_IP_NF_TARGET_CONNMARK=y # # QoS and/or fair queueing # CONFIG_NET_SCHED=y CONFIG_NET_SCH_CLK_JIFFIES=y # # Queueing/Scheduling # CONFIG_NET_SCH_HTB=y CONFIG_NET_SCH_SFQ=y # # Classification # CONFIG_NET_CLS=y CONFIG_NET_CLS_TCINDEX=y CONFIG_NET_CLS_ROUTE4=y CONFIG_NET_CLS_ROUTE=y CONFIG_NET_CLS_FW=y CONFIG_NET_ESTIMATOR=y
Vous aurez aussi besoin si vous voulez controller le trafic entrant du patch IMQ
qui crée des interfaces virtuelles que vous alimenterez via des règles Netfilter, il sert en plus par exemple si vous avez plusieurs
sous réseaux internes possedant chacun son interface (voir la page pour la mise en oeuvre). Vous pouvez ainsi regrouper le trafic entrant dans l'imq pour faire de la qos groupé
pour toutes les interfaces sortantes sur vos LAN.
Pour faciliter les modifications ultérieures il est préférable de mettre toutes les informations (interfaces sur lesquelles on va appliquer
la qos, identifiants de classes...)dans des variables auxquelles nous feront référence par la suite. Voilà à quoi peut ressembler un tel fichier :
SCRIPTS=/etc/network/scripts IPTABLES=/usr/local/bin/iptables IP=/usr/local/sbin/ip TC=/usr/local/sbin/tc IF_QOSIN=imq1 #HTB CLASS CLASSPROD=10 CLASSPOSTPROD=20 CLASSHIGHPRIO=30 HIGHPRIO=0 MAIL=1 HTTP=2 FTP=3 P2P=4
Bien entendu les informations ci-dessus sont spécifiques à mon systeme, à vous de les adapter à vos besoins. On peut maintenant commencer à écrire notre script de gestion de la qos. On declare d'abord que l'on desire une queue différente sur l'interface où le trafic doit être modulé, on specifie aussi que tout ce qui ne sera pas classifié ira dans la classe par défaut d'id 1000. On crée ensuite une classe racine avec notre valeur de bande passante à 10000 kbits/s :
. /etc/network/scripts/common $TC qdisc add dev $IF_QOSIN root handle 1:0 htb default 1000 $TC class add dev $IF_QOSIN parent 1:0 classid 1:1 htb rate 10000kbit
On continue ensuite par déclarer notre classe Prod et ses filles. On rajoute donc une classe d'id 1:10 avec une
bande passante normale de 3000 kbits/s et qui peut monter jusqu'au maximum (10000 kbits/s) si personne d'autre
ne l'utilise (directive ceil).
Puis vient le tour des sous classes correspondantes à nos type de flux qui elles sont des
terminaisons. Nous avons le mail, le ftp et le web, chacun peut avoir 1000 kbits/s et jusqu'a la totalité de la bande passante
si elle est disponible. Je leur attribue aussi une priorité de 1 à toute (directive prio).
Enfin pour plus d'égalité
je change le type de queue de ces terminaisons en SFQ
au lieu de la pfifo_fast classique de Linux. Quelques explications, dans ma classe mails par exemple, il peut y avoir une multitude de
connections d'utilisateurs différents, SFQ va assurer une répartition "équitable" de la bande passante de
cette classe sur toutes les connections de la queue.
$TC class add dev $IF_QOSIN parent 1:1 classid 1:$CLASSPROD htb rate 3000kbit ceil 10000kbit $TC class add dev $IF_QOSIN parent 1:$CLASSPROD classid 1:$CLASSPROD$MAIL htb rate 1000kbit \ ceil 10000kbit prio 1 $TC qdisc add dev $IF_QOSIN parent 1:$CLASSPROD$MAIL handle $CLASSPROD$MAIL: sfq perturb 10 $TC class add dev $IF_QOSIN parent 1:$CLASSPROD classid 1:$CLASSPROD$HTTP htb rate 1000kbit \ ceil 10000kbit prio 1 $TC qdisc add dev $IF_QOSIN parent 1:$CLASSPROD$HTTP handle $CLASSPROD$HTTP: sfq perturb 10 $TC class add dev $IF_QOSIN parent 1:$CLASSPROD classid 1:$CLASSPROD$FTP htb rate 1000kbit \ ceil 10000kbit prio 1 $TC qdisc add dev $IF_QOSIN parent 1:$CLASSPROD$FTP handle $CLASSPROD$FTP: sfq perturb 10
Les instructions qui suivent sont des filtres qui permettent de diriger les paquets dans les bonnes classes selon leur marquage par Netfilter. Par exemple pour le mail si le paquet est marqué 101 alors il sera traité par la classe d'id 1:101 et ainsi de suite :
$TC filter add dev $IF_QOSIN parent 1:0 protocol ip handle $CLASSPROD$MAIL fw flowid 1:$CLASSPROD$MAIL $TC filter add dev $IF_QOSIN parent 1:0 protocol ip handle $CLASSPROD$HTTP fw flowid 1:$CLASSPROD$HTTP $TC filter add dev $IF_QOSIN parent 1:0 protocol ip handle $CLASSPROD$FTP fw flowid 1:$CLASSPROD$FTP
Vous avez compris le principe on refait donc la même chose pour la classe PostProd et ses filles.
Passons à la classe haute priorité qui est un peu différente, déjà on lui attribue une classe spécifique
au même niveau que Prod et Postprod pour qu'elle puisse emprunter directement de la bande passante à la classe racine
et on positionne en plus à chaque fille une priorité de 0.
Tous les paquets qui arriveront dans les classes filles de haute priorité seront donc envoyés en premiers, il faut donc faire attention
aux types de flux que l'on va classifier de la sorte car cela peut interdire l'accés à la bande passante des autres flux. Mais
c'est plutôt pratique pour les vidéos conférences du patron par exemple...
$TC class add dev $IF_QOSIN parent 1:1 classid 1:$CLASSHIGHPRIO htb rate 3000kbit ceil 10000kbit $TC class add dev $IF_QOSIN parent 1:$CLASSHIGHPRIO classid 1:$CLASSPROD$HIGHPRIO htb rate 1500kbit \ ceil 10000kbit prio 0 $TC qdisc add dev $IF_QOSIN parent 1:$CLASSPROD$HIGHPRIO handle $CLASSPROD$HIGHPRIO: sfq perturb 10 $TC class add dev $IF_QOSIN parent 1:$CLASSHIGHPRIO classid 1:$CLASSPOSTPROD$HIGHPRIO htb rate 1500kbit \ ceil 10000kbit prio 0 $TC qdisc add dev $IF_QOSIN parent 1:$CLASSPOSTPROD$HIGHPRIO handle $CLASSPOSTPROD$HIGHPRIO: sfq perturb 10 $TC filter add dev $IF_QOSIN parent 1:0 protocol ip handle $CLASSPROD$HIGHPRIO fw flowid 1:$CLASSPROD$HIGHPRIO $TC filter add dev $IF_QOSIN parent 1:0 protocol ip handle $CLASSPOSTPROD$HIGHPRIO \ fw flowid 1:$CLASSPOSTPROD$HIGHPRIO
Enfin on declare la classe par défaut d'id 1000 avec une priorité 2 (la plus basse dans notre exemple). Ainsi tout ce qui n'est pas marqué par iptables se retrouvera dans cette classe de basse priorité et de bande passante limitée.
$TC class add dev $IF_QOSIN_FREE parent 1:1 classid 1:1000 htb rate 1000kbit ceil 10000kbit prio 2 $TC qdisc add dev $IF_QOSIN_FREE parent 1:1000 handle 1000: sfq perturb 10
Notre arbre est donc fini, il ne reste maintenant plus qu'a classifier le trafic avec iptables, comme promis voici un petit exemple qui devrait se suffire à lui même...
#Creation d'une chaine qui recoit tout le trafic de l'exterieur vers la prod $IPTABLES -t mangle -N QOS-OUT-PROD $IPTABLES -t mangle -A FORWARD -i $IF_OUT -d 192.168.0.0/24 -j QOS-OUT-PROD #ICMP $IPTABLES -t mangle -A QOS-OUT-PROD -p icmp -j MARK --set-mark $CLASSPROD$HIGHPRIO #DNS $IPTABLES -t mangle -A QOS-OUT-PROD -p udp --sport 53 -j MARK --set-mark $CLASSPROD$HIGHPRIO $IPTABLES -t mangle -A QOS-OUT-PROD -p tcp --sport 53 -j MARK --set-mark $CLASSPROD$HIGHPRIO #MESSENGER $IPTABLES -t mangle -A QOS-OUT-PROD -p tcp -m multiport --sports 1863,5190,5222 -j MARK \ --set-mark $CLASSPROD$HIGHPRIO #MAIL POP3,IMAP & SMTP $IPTABLES -t mangle -A QOS-OUT-PROD -p tcp -m multiport --sports 110,143,25 -j MARK --set-mark $CLASSPROD$MAIL #HTTP,HTTPS $IPTABLES -t mangle -A QOS-OUT-PROD -p tcp -m multiport --sports 80,443 -j MARK --set-mark $CLASSPROD$HTTP #FTP $IPTABLES -t mangle -A QOS-OUT-PROD -p tcp --sport 21 -j MARK --set-mark $CLASSPROD$FTP $IPTABLES -t mangle -A QOS-OUT-PROD -p tcp -m helper --helper ftp -j MARK --set-mark $CLASSPROD$FTP $IPTABLES -t mangle -A QOS-OUT-PROD -j ACCEPT
Voilà tout est prêt, il n'y à plus qu'a tester tout ça, vous pouvez utilisez la commande tc pour afficher ce qui se passe dans les classes et les queues. Le mieux est de se faire quelques graphiques d'utilisation à partir des classes que l'on a mis en place, mais cela fera surement l'objet d'un autre howto. Une dernière info, si vous voulez classifier le peer to peer par exemple aller voir du côté de ipp2P il est remis à jour assez régulièrement et fonctionne trés bien.