La QoS (Quality of Service) permet de prioriser le traffic passant par une interface réseau. En voici une mise en oeuvre sur OpenWrt.

Le script proposé divise le traffic sortant en 5 classes de priorité qui sont les suivantes :

  • 1 - ping, DNS, ack : super rapide
  • 2 - jeux, SSH : haute priorité, stabilité
  • 3 - serveurs locaux : un bon débit, temps de réponse acceptable
  • 4 - utilisateurs : surf et mail(classe par défaut)
  • 5 - peer 2 peer

Télécharger le script qos.

La première section du script permet de définir un débit moyen garanti et un débit maximum pour la connection réseau et pour chacune des classes. Adaptez ces valeurs en fonction du débit fourni par votre connection Internet.

MAX_DL=10000
MAX_DL_BURST=200
MAX_UP=2000
MAX_UP_BURST=40

AVER_PRIO=200
MAX_PRIO=200

AVER_JEUX=300
MAX_JEUX=300

AVER_SERVEURS=200
MAX_SERVEURS=1000

AVER_UTILISATEURS=300
MAX_UTILISATEURS=1000

AVER_P2P=50
MAX_P2P=500

Avant toute chose, les modules nécessaires au fonctionnement de la QoS sont chargés. Si vous rencontrez des erreurs lors du chargement de des modules, vérifiez que les paquets correspondants sont bien installés.

echo 'Chargement des modules' >> $log 2>> $log
insmod sch_htb >> $log 2>> $log
insmod sch_tbf >> $log 2>> $log
insmod sch_sfq >> $log 2>> $log
insmod cls_u32 >> $log 2>> $log
insmod cls_fw >> $log 2>> $log
insmod sch_ingress >> $log 2>> $log
insmod ipt_connmark >> $log 2>> $log
insmod ipt_CONNMARK >> $log 2>> $log
insmod ipt_ipp2p >> $log 2>> $log

On procède tout d'abord à la suppression des règles existantes.

echo 'Suppression des tables' >> $log 2>> $log
tc qdisc del dev $WAN root >> $log 2>> $log
tc qdisc del dev $WAN ingress >> $log 2>> $log

Puis vient la création des différentes classes. On utilise un gestionnaire HTB (Hierarchical Token Bucket) pour l'ensemble des règles. Ce gestionnaire à l'avantage de bien s'adapter aux variations d'utilisation du réseau. Pour en savoir plus sur HTB, consultez les pages de Martin Devera (devik).

echo '*** Création des classes ***' >> $log 2>> $log

echo 'Création de la racine HTB' >> $log 2>> $log
tc qdisc add dev $WAN root handle 1: htb default 40 >> $log 2>> $log

echo 'Limitation globale du lien' >> $log 2>> $log
tc class add dev $WAN parent 1: classid 1:1 htb
rate ${MAX_UP}kbit ceil ${MAX_UP}kbit burst ${MAX_UP_BURST}k >> $log 2>> $log

echo 'Classe ping' >> $log 2>> $log
tc class add dev $WAN parent 1:1 classid 1:10 htb
rate ${AVER_PRIO}kbit ceil ${MAX_PRIO}kbit burst 50k prio 0 >> $log 2>> $log

echo 'Classe jeux' >> $log 2>> $log
tc class add dev $WAN parent 1:1 classid 1:20 htb
rate ${AVER_JEUX}kbit ceil ${MAX_JEUX}kbit burst 50k prio 1 >> $log 2>> $log

echo 'Classe serveurs' >> $log 2>> $log
tc class add dev $WAN parent 1:1 classid 1:30 htb
rate ${AVER_SERVEURS}kbit ceil ${MAX_SERVEURS}kbit burst 50k prio 2 >> $log 2>> $log

echo 'Classe utilisateurs' >> $log 2>> $log
tc class add dev $WAN parent 1:1 classid 1:40 htb
rate ${AVER_UTILISATEURS}kbit ceil ${MAX_UTILISATEURS}kbit burst 30k prio 3 >> $log 2>> $log

echo 'Classe p2p' >> $log 2>> $log
tc class add dev $WAN parent 1:1 classid 1:50 htb
rate ${AVER_P2P}kbit ceil ${MAX_P2P}kbit burst 5k prio 4 >> $log 2>> $log

Une fois les classes créées, nous les attachons à un gestionnaire SFQ, qui va répartir la bande passante de manière (presque) équitable entre les divers flux sortant d'une queue HTB.

echo 'Gestion des classes' >> $log 2>> $log
tc qdisc add dev $WAN parent 1:10 handle 10: sfq perturb 10 >> $log 2>> $log
tc qdisc add dev $WAN parent 1:20 handle 20: sfq perturb 10 >> $log 2>> $log
tc qdisc add dev $WAN parent 1:30 handle 30: sfq perturb 10 >> $log 2>> $log
tc qdisc add dev $WAN parent 1:40 handle 40: sfq perturb 10 >> $log 2>> $log
tc qdisc add dev $WAN parent 1:50 handle 50: sfq perturb 10 >> $log 2>> $log

Passant maintenant à la création des filtres, qui vont aiguiller le traffic dans les différentes classes.

La première classe recevra le traffic ICMP (pour fournir un faible ping), les requetes DNS, les paquets ACK des connections TCP et le traffic VPN.

echo 'Classe 1' >> $log 2>> $log
echo ' - ICMP' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 0
u32 match ip protocol 1 0xff flowid 1:10 >> $log 2>> $log
echo ' - ACK' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 0
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 >> $log 2>> $log
echo ' - DNS' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 0
u32 match ip dport 53 0xff flowid 1:10 >> $log 2>> $log
echo ' - VPN' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 1 u32
match ip dport 1723 0xffff flowid 1:10 >> $log 2>> $log

La seconde classe récupère le traffic issu des connections SSH.

echo 'Classe 2' >> $log 2>> $log
# le bit Délai Minimum du champ TOS (ssh, PAS scp) est dirigé vers 1:10
echo ' - Champ TOS' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 5 u32
match ip tos 0x10 0xff flowid 1:20 >> $log 2>> $log
echo ' - serveur SSH' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 5 u32
match ip dport 22 0xffff flowid 1:20 >> $log 2>> $log
echo ' - client SSH' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 5 u32
match ip sport 22 0xffff flowid 1:20 >> $log 2>> $log

Mais ce n'est pas tout ! Cette seconde classe garantit surtout une haute priorité à tout le traffic généré par les jeux en réseau.

echo ' - serveur DC' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 5 u32
match ip sport 14567 0xffff flowid 1:20 >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 5 u32
match ip sport 14667 0xffff flowid 1:20 >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 5 u32
match ip sport 14690 0xffff flowid 1:20 >> $log 2>> $log
echo ' - serveur CZ' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 5 u32
match ip sport 27015 0xffff flowid 1:20 >> $log 2>> $log
echo ' - serveur Q3' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 5 u32
match ip sport 27960 0xffff flowid 1:20 >> $log 2>> $log
echo ' - serveur TS' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 5 u32
match ip sport 8767 0xffff flowid 1:20 >> $log 2>> $log

echo ' - client DC' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 5 u32
match ip dport 14567 0xffff flowid 1:20 >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 5 u32
match ip dport 14667 0xffff flowid 1:20 >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 5 u32
match ip dport 14690 0xffff flowid 1:20 >> $log 2>> $log
echo ' - client CZ' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 5 u32
match ip dport 27015 0xffff flowid 1:20 >> $log 2>> $log
echo ' - client Q3' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 5 u32
match ip dport 27960 0xffff flowid 1:20 >> $log 2>> $log
echo ' - client TS' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 5 u32
match ip dport 8767 0xffff flowid 1:20 >> $log 2>> $log

La troisième classe récupère le traffic provenant d'éventuels serveurs HTTP et FTP en local.

echo 'Classe 3' >> $log 2>> $log
echo ' - HTTP' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 10 u32
match ip sport 80 0xffff flowid 1:30 >> $log 2>> $log
echo ' - HTTPS' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 10 u32
match ip sport 443 0xffff flowid 1:30 >> $log 2>> $log
echo ' - FTP' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 10 u32
match ip sport 20 0xffff flowid 1:30 >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 10 u32
match ip sport 21 0xffff flowid 1:30 >> $log 2>> $log
#tc filter add dev $WAN parent 1: protocol ip prio 10 u32
#match ip sport 49152 0xc000 flowid 1:30 >> $log 2>> $log
#tc filter add dev $WAN parent 1: protocol ip prio 10 u32
#match ip sport 65535 0xc000 flowid 1:30 >> $log 2>> $log

Vient ensuite le traffic utilisateur (surf web et mails).

tc filter add dev $WAN parent 1: protocol ip prio 20 u32 
match ip dport 80 0xffff flowid 1:40 >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 20 u32
match ip dport 443 0xffff flowid 1:40 >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 20 u32
match ip dport 8080 0xffff flowid 1:40 >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 20 u32
match ip dport 25 0xffff flowid 1:40 >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 20 u32
match ip dport 143 0xffff flowid 1:40 >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 20 u32
match ip dport 993 0xffff flowid 1:40 >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip prio 20 u32
match ip dport 995 0xffff flowid 1:40 >> $log 2>> $log

Et enfin le traffic peer to peer, donc peu important. Remarquez ici l'utilisation d'iptables et mangle.

echo 'Classe 5' >> $log 2>> $log
echo ' - initialisation mangle' >> $log 2>> $log
/usr/sbin/iptables -t mangle -F
/usr/sbin/iptables -t mangle -X
echo ' - Récupération du marquage des connexions' >> $log 2>> $log
/usr/sbin/iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
echo ' - Elimination des connexions déjà marquées' >> $log 2>> $log
/usr/sbin/iptables -t mangle -A PREROUTING -m mark ! --mark 0 -j ACCEPT

echo ' - Création des règles de gestion du traffic P2P'
/usr/sbin/iptables -t mangle -N p2p_mangle
/usr/sbin/iptables -t mangle -A PREROUTING -m ipp2p --ipp2p -j p2p_mangle

echo ' - Redirection des connexions TCP P2P marquées' >> $log 2>> $log
tc filter add dev $WAN parent 1: protocol ip handle 50 fw flowid 1:50

echo ' - Marquage du traffic P2P' >> $log 2>> $log
/usr/sbin/iptables -t mangle -A p2p_mangle -m ipp2p --ipp2p -j MARK --set-mark 50 >> $log 2>> $log

echo ' - Sauvegarde des marques pour la durée de la connexion' >> $log 2>> $log
/usr/sbin/iptables -t mangle -A PREROUTING -j CONNMARK --save-mark

Pour finir, une partie sur la limitation (très controversée) du traffic descendant. Cette règle a pour but de supprimer des paquets reçus trop vite depuis votre FAI dans le but de diminuer sa queue d'émission. Ceci supprime donc sa queue d'émission, et assure ainsi un traffic plus dynamique.

echo 'Création ingress' >> $log 2>> $log
tc qdisc add dev $WAN handle ffff: ingress >> $log 2>> $log
echo 'Limitation de la queue de téléchargement' >> $log 2>> $log
tc filter add dev $WAN parent ffff: protocol ip prio 1 u32 match ip src
0.0.0.0/0 police rate ${MAX_DL}kbit burst ${MAX_DL_BURST}k drop flowid :1 >> $log 2>> $log