HOWTO Traffic shaping
Un article de Gentoo Linux Wiki.
Cet article doit être mis en page au format en vigueur sur le wiki, pour garder une certaine intégrité dans l'apparence des articles..
Cet article doit être nettoyé, c'est à dire corrigé et mis en forme..
Cette page est en cours de traduction par Saigneur, depuis la page http://gentoo-wiki.com/HOWTO_Packet_Shaping
| Méthodes d'installation • CD Live • Noyau et matériel • Portables et Notebooks • Portage • Système • Réseaux et Services • Serveur X • Logiciels fréquemment utilisés • Autres |
Sommaire |
[modifier] Introduction
Les programmes Peer to peer (P2P) deviennent chaque jour plus populaires, leur utilisation sature les connexions Internet, et engorgent le trafic des autres applications sur la connexion. Quand un utilisateur sature sa connexion Internet, la navigation web devient laborieuse. Des programmes comme bittorrent, et autres clients P2P saturent principalement le flux montant (upload) de la connexion, et même si les logiciels peuvent limiter le taux d'upload, ils ne le font pas toujours. La solution passe par la qualité de service (traffic shaping).
L'idée de base de cette notion est de faire des priorités sur les paquets sortants. Comme les débits en upload pour l'ADSL sont relativement faibles, on va avoir plusieurs classes de paquets. Par exemple d'un coté les petits paquets UDP des jeux (quake, ennemy territory) qui doivent sortir vite et consomment peu de bande passante ; d'un autre, les transferts de fichers en ftp ou p2p qui consomment beaucoup de bande mais ne sont pas prioritaires.
[modifier] La solution
Tout d'abord, vous devez comprendre quelques petites choses sur la mise en file d'attente. L'explication qui suit est simplifiée, mais vous donnera une idée sur ce qui se passe. Notre scénario est une connexion Internet 2048/128, la machine un Linux avec deux cartes ethernet, et un réseau avec plusieurs clients.
- Le modem xDSL a l'adresse interne 192.168.2.1
- La machine Linux a les adresses suivantes : eth0 192.168.1.1, eth1 192.168.2.2 et 192.168.2.1 comme passerelle
- Les clients ont comme IP 192.168.1.16, 192.168.1.17, 192.168.1.18 et 192.168.1.1 en passerelle
http://gentoo-wiki.com/images/d/d7/Network.png
Voici ce qui se passe quand un client envoie un packet vers Internet:
- Le paquet part du client (192.168.1.16)
- Le paquet arrive à la passerelle eth0 (192.168.1.1)
- La passerelle route le paquet, et le met en file d'attente pour sortir
- Le paquet quitte eth1 (192.168.2.2)
- Le paquet arrive au modem xDSL (192.168.2.1)
- Le paquet entre dans la file d'attente de sortie du model xDSL
- Le paquet sort du modem et va sur Internet
La vitesse d'émission du modem est seulement de 128 Kb/s. Cela signifie que la machine Linux peut envoyer les données au modem xDSL plus vite que ce dernier ne peut les envoyer sur Internet. Que se passe-t-il quand la file d'attente de sortie est pleine ? Si cette file d'attente est de "5 secondes", un paquet mettra au moins 5 secondes pour sortir du modem. Très mauvais.
Comme on ne peut pas gérer la file d'attente du modem, nous allons gérer celle de la machine Linux. C'est là que le traffic shaping intervient. En diminuant la vitesse de sortie de eth0 à une vitesse inférieure à la vitesse d'upload du modem, l'engorgement est déplacé du modem à la passerelle Linux.
Et là, on peut contrôler la file d'attente, et la "tailler" à notre volonté.
[modifier] Pré-requis
Il n'y a pas besoin de grand chose. Un ordinateur tournant sous Gentoo Linux, avec deux cartes réseaux, suffira. Cela tourne sur un PC à 200MHz, mais une plus petite machine fera l'affaire.
[modifier] Noyau
Tout d'abord, il faut un noyau 2.4 ou 2.6 récent. Mettez le dans /usr/src, et faites pointer dessus le lien symbolique /usr/src/linux.
Pour les noyaux 2.4, il vous faudra appliquer le patch POM disponible sur http://netfilter.org. Le mot de passe est "cvs" (L'accès CVS peut ne pas fonctionner).
cvs -d :pserver:cvs@pserver.netfilter.org:/cvspublic login cvs -d :pserver:cvs@pserver.netfilter.org:/cvspublic co netfilter/userspace netfilter/patch-o-matic ./netfilter/patch-o-magic/runme extra
Quand le patch est appliqué, ils vous faut activer certaines options du noyau. Si ces options n'existent pas, réappliquer le patch POM.
Networking options --->
QoS and/or fair queueing --->
[*] QoS and/or fair queueing
<M> HTB packet scheduler
<M> SFQ queue
[*] QoS support
[*] Rate estimator
[*] Packet classifier API
<M> Firewall based classifier
[*] Traffic policing (needed for in/egress)
IP: Netfilter Configuration --->
<M> Connection tracking (required for masq/NAT)
<M> IP tables support (required for filtering/masq/NAT)
<M> limit match support
<M> MAC address match support
<M> Packet type match support
<M> netfilter MARK match support
<M> Multiple port match support
<M> TOS match support
<M> random match support
<M> recent match support
<M> ECN match support
<M> DSCP match support
<M> AH/ESP match support
<M> LENGTH match support
<M> TTL match support
<M> tcpmss match support
<M> Helper match support
<M> Connection state match support
<M> Connection mark match support
<M> Connection tracking match support
<M> Unclean match support (EXPERIMENTAL)
<M> Owner match support (EXPERIMENTAL)
<M> Packet filtering
<M> REJECT target support
<M> MIRROR target support (EXPERIMENTAL)
<M> Full NAT
<M> MASQUERADE target support
<M> REDIRECT target support
<M> Basic SNMP-ALG support (EXPERIMENTAL)
<M> Packet mangling
<M> TOS target support
<M> ECN target support
<M> DSCP target support
<M> MARK target support
<M> LOG target support
<M> CONNMARK target support
<M> ULOG target support
<M> TCPMSS target support
<M> ARP tables support
<M> ARP packet filtering
<M> ARP payload mangling
Compilez ce noyau, installez le, et bootez dessus. (NdT : j'ai pour ma part plutôt tendance à mettre toutes les options du noyau en "dur" plutôt qu'en module)
[modifier] Stratégie de shaping
Voici un exemple de ce à partir de quoi iptables peut travailler :
- Port
- Taille des paquets
- Type de traffic
Imaginons que vous voulez donner à bittorrent une priorité basse. Vous savez que cette application utilise les ports TCP 6881 à 6889. Iptables peut facilement suivre cela. Mais si un utilisateur trouve que ces ports ont une priorité trop basse, il peut changer le port d'utilisation de bittorrent. Il n'y a aucun moyen de connaître les ports utilisés par un programme p2p.
Réguler le traffic par taille de paquets présente plusieurs avantages. Vous pouvez donner aux petits paquets une priorité plus haute qu'aux gros paquets. Comme l'envoi de beaucoup de données se fait mieux en utilisant de gros paquets, on peut cibler les programmes P2P. Mais un client peut aussi changer la MTU de son interface sortante, et ainsi envoyer de petits paquets.
Ce que vous voulez est reconnaître les paquets selon leur contenu. Vous devrez faire en sorte qu'Iptables décortique chaque paquet et analyse les données pour déterminer s'il provient d'un P2P ou non. Il y a deux projets pour faire ceci :
- ipp2p http://www.ipp2p.org
- l7-filter http://l7-filter.sourceforge.net/
Ces deux projets sont bons et j'utilise ipp2p moi-même. J'ai juste essayé sur bittorrent, mais cela fonctionne bien. Voyez dans le dernier paragraphe ou cela, ou suivez les liens.
[modifier] Priorisation
Dans ce howto, nous allons créer quatre priorités :
- Interactif
- Divers
- Surf
- P2P
"Interactif" est pour les petits paquets qui requièrent un acheminement immédiat. Par exemple l'ICMP ou le SSH (cela inclut-il les ACK ?)
Divers est pour les autres paquets.
Surf est pour les paquets qui doivent passer rapidement, mais qui ne doivent pas perturber les "interactifs". Idéal pour HTTP ou SMTP
P2P est pour les programmes P2P et autres programmes uploadant beaucoup. Ils ont la priorité la plus faible possible.
[modifier] Iptables
Pas de surprise : il faut Iptables.
emerge net-firewall/iptables
Iptables permet de faire du NAT (Network Adresse Translation : traduction d'adresse IP) et marquer les paquets. Ce setup n'est PAS sécurisé. Il montre juste comment faire du NAT et marquer les paquets.
# Constantes LOCALNET="192.168.1.0/255.255.255.0" MARKPRIO1="1" MARKPRIO2="2" MARKPRIO3="3" MARKPRIO4="4" # Définir la politique iptables -P INPUT ACCEPT iptables -P OUTPUT ACCEPT iptables -P FORWARD ACCEPT iptables -t nat -P POSTROUTING ACCEPT iptables -t nat -P PREROUTING ACCEPT # Purger toutes les tables iptables -F INPUT iptables -F OUTPUT iptables -F FORWARD iptables -t nat -F POSTROUTING iptables -t nat -F PREROUTING iptables -t mangle -F OUTPUT iptables -t mangle -F FORWARD # NAT iptables -t nat -A POSTROUTING -s $LOCALNET -j MASQUERADE iptables -A FORWARD -m state --state ESTABLISHED,RELATED -d $LOCALNET -j ACCEPT # Définition du marquage des priorités # Prio 1 # icmp iptables -t mangle -A FORWARD -p icmp -j MARK --set-mark $MARKPRIO1 iptables -t mangle -A OUTPUT -p icmp -j MARK --set-mark $MARKPRIO1 # ssh iptables -t mangle -A FORWARD -p tcp --dport 22 -j MARK --set-mark $MARKPRIO1 iptables -t mangle -A OUTPUT -p tcp --dport 22 -j MARK --set-mark $MARKPRIO1 # non tcp iptables -t mangle -A FORWARD -p ! tcp -j MARK --set-mark $MARKPRIO1 iptables -t mangle -A OUTPUT -p ! tcp -j MARK --set-mark $MARKPRIO1 # Prio 2 # Prio 3 # http iptables -t mangle -A FORWARD -p tcp --dport 80 -j MARK --set-mark $MARKPRIO3 iptables -t mangle -A OUTPUT -p tcp --dport 80 -j MARK --set-mark $MARKPRIO3 # https iptables -t mangle -A FORWARD -p tcp --dport 443 -j MARK --set-mark $MARKPRIO3 iptables -t mangle -A OUTPUT -p tcp --dport 443 -j MARK --set-mark $MARKPRIO3 # smtp iptables -t mangle -A FORWARD -p tcp --dport 25 -j MARK --set-mark $MARKPRIO3 iptables -t mangle -A OUTPUT -p tcp --dport 25 -j MARK --set-mark $MARKPRIO3 # Prio 4 # packets > 1024 bytes iptables -t mangle -A FORWARD -p tcp -m length --length 1024: -j MARK --set-mark $MARKPRIO4 # bittorrent iptables -t mangle -A FORWARD -i eth0 -p tcp --sport 6881:6889 -j MARK --set-mark $MARKPRIO4 iptables -t mangle -A FORWARD -i eth0 -p tcp --dport 6881:6889 -j MARK --set-mark $MARKPRIO4
# Les paquets restants sont marqués selon le TOS (Type of Service) iptables -t mangle -A FORWARD -p tcp -m tos --tos Minimize-Delay -m mark --mark 0 -j MARK --set-mark $MARKPRIO1 iptables -t mangle -A FORWARD -p tcp -m tos --tos Maximize-Throughput -m mark --mark 0 -j MARK --set-mark $MARKPRIO2 iptables -t mangle -A FORWARD -p tcp -m tos --tos Minimize-Cost -m mark --mark 0 -j MARK --set-mark $MARKPRIO4 # Permettre le transfert du noyau echo 1 > /proc/sys/net/ipv4/ip_forward
[modifier] Comprendre le HTB
Que fait exactement le HTB ? HTB est un système qui partage la bande passante en plusieurs files d'attente. Pour chaque file d'attente (queue), on peut définir une part de la bande passante garantie (rate) qui est ce qu'obtiendra la file si l'interface est sollicitée au maximum. HTB permet également de redistribuer la bande passante quand une file d'attente ne l'utilise pas. Dans ce cas, on peut également définir une part maximale (ceil) pour chaque file, c'est-à-dire un taux qui ne sera jamais depassé. Il est important de garder à l'esprit que le HTB garantit la bande passante, et non l'interactivité. Le HTB ne compte pas les paquets, mais les octets. C'est pourquoi son réglage réclame de l'intelligence pour permettre une certaine interactivité. Voici une petite explication du fonctionnement interne.
[modifier] Qdiscs
Un qdisc est une file d'attente séparée. Dans ce howto, nous avons quatre priorités, donc quatre qdiscs. Aussi simple que ça !
[modifier] Taux
Un taux est une vitesse. Ici, notre upload est de 128 Kbit/s. Le taux détermine quelle fraction de bande passante est attribuée à un qdisc. Il est défini par l'option rate.
[modifier] Plafond
Un plafond est la quantité de bande passante maximum qu'un qdisc peut avoir. Il est défini par l'option ceil.
[modifier] Pointe
Il y a deux types de pointes :
- burst
- cburst
Les bursts déterminent de combien d'octets un qdsic peut dépasser le taux avant d'être arrêté. Les cbursts déterminent de combien d'octets un qdisc peut dépasser le plafond avant d'être arrêté.
[modifier] Quantum
Les quanta décrivent comment la bande passante est répartie entre qdiscs. Ils fonctionnent comme suivant :
- Tous les quanta pour tous les qdiscs sont ajoutés ensemble et la somme est mémorisée
- Chaque qdisc prend une priorité selon <math>\frac{quantum}{sum}</math>
Ceci est utilisé quand deux qdiscs ont les mêmes taux et plafond, mais doivent avoir des priorités différentes.
[modifier] Priorité
Comme son nom l'indique : donne une priorité aux qdisc. Plus le nombre est bas, plus la priorité est haute.
[modifier] Iproute2
Pour établir le HTB, il faut iproute2
emerge sys-apps/iproute2
Lancer ce script pour créer les quatre qdiscs et les définir :
#Constantes # Interface que vous voulez shaper # eth2, eth1 pour des connexions directes, ppp0 pour le xDSL # et autres connexions dialup (vérifier ifconfig) IFACE=eth2 # Marques de priorité MARKPRIO1="1" MARKPRIO2="2" MARKPRIO3="3" MARKPRIO4="4" # Taux UPRATE="152kbit" #P2PRATE=$UPRATE P2PRATE="128kbit" PRIORATE1="65kbit" PRIORATE2="46kbit" PRIORATE3="27kbit" PRIORATE4="8kbit" # Quanta QUANTUM1="12187" QUANTUM2="8625" QUANTUM3="5062" QUANTUM4="1500" # Burst BURST1="6k" BURST2="4k" BURST3="2k" BURST4="0k" CBURST1="3k" CBURST2="2k" CBURST3="1k" CBURST4="0k" # Définir la longueur de file d'attente pour IFACE ifconfig $IFACE txqueuelen 16 # Définir les règles de file d'attente tc qdisc add dev $IFACE root handle 1:0 htb default 103 r2q 1 # Définir la classe root tc class add dev $IFACE parent 1:0 classid 1:1 htb rate $UPRATE burst $BURST1 cburst $CBURST1 # Specifier les sous-classes tc class add dev $IFACE parent 1:1 classid 1:101 htb rate $PRIORATE1 ceil $UPRATE quantum $QUANTUM1 burst $BURST1 cburst $CBURST1 prio 0 tc class add dev $IFACE parent 1:1 classid 1:102 htb rate $PRIORATE2 ceil $UPRATE quantum $QUANTUM2 burst $BURST2 cburst $CBURST2 prio 1 tc class add dev $IFACE parent 1:1 classid 1:103 htb rate $PRIORATE3 ceil $UPRATE quantum $QUANTUM3 burst $BURST3 cburst $CBURST3 prio 2 tc class add dev $IFACE parent 1:1 classid 1:104 htb rate $PRIORATE4 ceil $P2PRATE quantum $QUANTUM4 burst $BURST4 cburst $CBURST4 prio 3 # Filtrage de paquets tc filter add dev $IFACE parent 1:0 protocol ip prio 0 handle $MARKPRIO1 fw classid 1:101 tc filter add dev $IFACE parent 1:0 protocol ip prio 1 handle $MARKPRIO2 fw classid 1:102 tc filter add dev $IFACE parent 1:0 protocol ip prio 2 handle $MARKPRIO3 fw classid 1:103 tc filter add dev $IFACE parent 1:0 protocol ip prio 3 handle $MARKPRIO4 fw classid 1:104 # Ajout des règles de file d'attente tc qdisc add dev $IFACE parent 1:101 sfq perturb 16 quantum $QUANTUM1 tc qdisc add dev $IFACE parent 1:102 sfq perturb 16 quantum $QUANTUM2 tc qdisc add dev $IFACE parent 1:103 sfq perturb 16 quantum $QUANTUM3 tc qdisc add dev $IFACE parent 1:104 sfq perturb 16 quantum $QUANTUM4
Si vous voulez recréer (modifier) les qdiscs, vous devez d'abord les supprimer : (Remplacer $IFACE par votre interface réseau : par exemple, eth2 ou ppp0)
tc qdisc del dev $IFACE root
[modifier] Classificateurs de paquets
Quels sont ils ? Ce sont des programmes qui ouvrent tous les paquets et en regardent le contenu pour déterminer s'ils sont du traffic P2P ou pas. Si le paquet est d'origine P2P, il est marqué et le shaper agit en conséquence.
[modifier] ipp2p
Note aux trouillards : on dirait que les gens de ipp2p apportent maintenant une solution avec support.
emerge net-firewall/ipp2p
Le rôle d'ipp2p est de marquer les paquets bittorrent. Cela se fait en traçant la connexion. Pour ma configuration d'ipp2p, je fais comme ça :
iptables -t mangle -A FORWARD -p tcp -m connmark --mark $MARKPRIO4 -j CONNMARK --restore-mark iptables -t mangle -A FORWARD -p tcp -m mark ! --mark 0 -j ACCEPT iptables -t mangle -A FORWARD -p tcp -m ipp2p --bit -j MARK --set-mark $MARKPRIO4 iptables -t mangle -A FORWARD -p tcp -m ipp2p --ipp2p -j MARK --set-mark $MARKPRIO4 iptables -t mangle -A FORWARD -p tcp -m ipp2p --ipp2p-data -j MARK --set-mark $MARKPRIO4 iptables -t mangle -A FORWARD -p tcp -j CONNMARK --save-mark
[modifier] l7-filter
L7-filter est un classificateur plus général qu'ipp2p. Les schémas de définition sont stockés dans un espace utilisateur, afin de pouvoir être facilement modifiés sans avoir à recompiler le noyau. Non essayé. Vous pouvez l'installer avec la commande suivante :
emerge l7-protocols
Une fois installé, apprenez à l'utiliser et ajoutez ici votre expérience ;) Après installation, faites ceci :
> echo "net-firewall/iptables extensions" >> /etc/portage/package.use > emerge --newuse iptables
pour avoir les objets partagés, vous devez utiliser l7-filter, et activer l'option l7 dans le noyau
Device Drivers -->
[*] Network support
Network options -->
[*] Network packet filtering -->
IP: Netfilter configuration -->
[*] Connection tracking flow accounting
<M> FTP protocol support
<M> Userspace queueing via NETLINK
<M> Layer 7 match support (EXPERIMENTAL)
Recompilez ensuite le noyau (exemple suivant avec genkernel) :
> genkernel --no-clean --no-mrproper all
Après ceci, il vous faudra ajouter des règles. Mais attention : vous devez spécifier des règles telles que les paquets allant dans les deux directions passent les filtres de l7. Cela signifie que les règles doivent gérer les INPUT ET les OUTPUT. C'est une des choses les plus tordues que vous aurez à faire.
Voici un exemple qui devrait fonctionner.
> iptables -t filter -A INPUT -m layer7 --l7proto edonkey -j ACCEPT > iptables -t filter -A OUTPUT -m layer7 --l7proto edonkey -j ACCEPT
Ou, pour les admins qui ne veulent pas de P2P :
> iptables -t filter -A FORWARD -m layer7 --l7proto edonkey -j DROP
Et maintenant, pour faire du shaping :
> iptables -t mangle -A FORWARD -m layer7 --l7proto edonkey -j MARK --set-mark 123
[modifier] Tests
[modifier] Graphes
Testons maintenant le bon fonctionnement. J'ai fait un script perl qui fait quelques graphes. Ceux-ci sont accessibles à l'adresse suivante : http://qos.kallenberg.dk
Ce script nécessite gnuplot pour faire les images
emerge media-gfx/gnuplot
Vous pouvez éditer le script pour déterminer à quelle fréquence refaire les images, et combien de graphes il doit y avoir. Pas besoin de serveur HTTP, mais c'est comme ça que ça fonctionne le mieux.
[modifier] Régler le taux d'upload
Une chose importante est de bien définir le taux d'upload. Si vous le réglez trop haut, la file d'attente se déportera sur le modem xDSL. Si vous la réglez trop bas, vous n'utiliserez pas toute votre bande passante. Il faut la régler comme il faut.
Pour tester cela :
- Lancez bittorrent
- Lancez des ping vers un serveur
- Connectez vous via SSH
Maintenant, jetez un oeil à la latence rapportée par les pings au fur et à mesure que vous changez le taux d'upload de bittorrent. Vous verrez quand le taux d'upload est trop haut.
Vous pouvez aussi tester avec le jeu "ennemy territory" : ce genre de jeu doit envoyer des tonnes de petits paquets en toute urgence. Appuyez sur "tab" pour vérifier votre latence.
[modifier] Liens
Vous êtes dans le brouillard, ou vous avez besoin d'en savoir plus ? Ca se comprend. La documentation sur la qualité de service est éparpillée sur le net, et parfois imprécise. En apprenant par moi-même, j'ai collecté ces liens :
- iptables http://netfilter.org/
- Linux Advanced Routing & Traffic Control http://www.lartc.org/
- l7-filter http://l7-filter.sourceforge.net/
- ipp2p http://ipp2p.org
- QoS graphs http://qos.kallenberg.dk/
- HTB Linux queuing discipline manual http://luxik.cdi.cz/~devik/qos/htb/manual/userg.htm
- http://www.docum.org/docum.org/
- Howto sur la gestion de bande passante ADSL http://www.tldp.org/HOWTO/ADSL-Bandwidth-Management-HOWTO/index.html
- Script de QoS de Jim diGriz's http://gentoo-wiki.com/index.php?title=HOWTO_Packet_Shaping&action=edit§ion=21
- Fair NAT for Linux Routers http://www.metamorpher.de/fairnat/
- http://www.ssi.bg/~ja/
- The WRR scheduler http://wipl-wrr.sourceforge.net/wrr.html
