Eeegw – part III – Quality Of Service aka QOS
Voici le script de QOS final basé sur CTB et PRIO (celui que j’utilise en production)
#!/bin/bash ### Script de reservation de bande passante par bragon ## On fixe quelques variables EXTERNAL_DOWNLINK_KBPS="6400" ## je sais downloader à ~800ko/s ma limite est donc a 6400 Kbps EXTERNAL_DL_IPSEC_KBPS="1024" EXTERNAL_DL_PPTP_KBPS="" EXTERNAL_DL_ICA_KBPS="" EXTERNAL_DL_TSE_KBPS="128" EXTERNAL_DL_SMTP_KBPS="512" EXTERNAL_DL_HTTP_KBPS="1024" EXTERNAL_DL_OTHERTCP_KBPS="2048" EXTERNAL_DL_OTHERTCP_PORT="2048" ## je sais uploader à environ 80Ko/s je fixe donc ma limite a 512 afin d'être sûr de ne pas engendrer de lag. EXTERNAL_UPLINK_KBPS="512" EXTERNAL_UL_IPSEC_KBPS="" EXTERNAL_UL_IPSEC_SHARE="" EXTERNAL_UL_PPTP_KBPS="" EXTERNAL_UL_PPTP_SHARE="" EXTERNAL_UL_ICA_KBPS="" EXTERNAL_UL_ICA_SHARE="" EXTERNAL_UL_TSE_KBPS="512" EXTERNAL_UL_TSE_SHARE="512" EXTERNAL_UL_SMTP_KBPS="256" EXTERNAL_UL_SMTP_SHARE="256" EXTERNAL_UL_HTTP_KBPS="32" EXTERNAL_UL_HTTP_SHARE="" EXTERNAL_UL_OTHERTCP_KBPS="" EXTERNAL_UL_OTHERTCP_SHARE="" EXTERNAL_UL_OTHERTCP_PORT="" EXTERNAL_UL_VOIP_KBPS="256" EXTERNAL_UL_VOIP_SHARE="isolated" EXTERNAL_DEV_BANDWIDTH="" ## CE script de QOS s'applique à toutes les interface dans MON cas cela convient. ## Je vous conseille de retirer votre interface LAN du match si vous avez plusieurs interfaces reseau. ## La commande va permettre de lister toutes les interfaces et d'appliquer les regles de QOS dessus. ## On match aussi les interfaces tap if [ -n "$EXTERNAL_DOWNLINK_KBPS" ] && [ -n "$EXTERNAL_UPLINK_KBPS" ] && echo $INTERFACE | egrep -q "(eth[023]|ppp[0-9]|ippp0|tap[0-3])" ; then #In kilobits DOWNLINK=$EXTERNAL_DOWNLINK_KBPS UPLINK=$EXTERNAL_UPLINK_KBPS BNDWIDTH=$EXTERNAL_DEV_BANDWIDTH if [ -z "$BNDWIDTH" ]; then BNDWIDTH="100mbit" fi ## on clean deja les parametres en tout premier lieu ## On vide toutes les regles pouvant deja etre en place. /sbin/tc qdisc del dev $EXTERNAL_IFACE root 2> /dev/null > /dev/null /sbin/tc qdisc del dev $EXTERNAL_IFACE ingress 2> /dev/null > /dev/null # install root CBQ # On met en place la policy root, les autres policies seront liées à celle-ci ## cbq avpkt : la taille moyenne des packets en bytes sont necessaire afin de calculer l'idle maximum ## bandwidth rate : pour determiner l'idle time cbq doit forcement connaitre la bande passante de l'interface physique. /sbin/tc qdisc add dev $EXTERNAL_IFACE root handle 1: cbq avpkt 1000 bandwidth $BNDWIDTH ## allot bytes : utile pour calculer le temps de transmission des packets entre tables, valeur liée à avpkt /sbin/tc class add dev $EXTERNAL_IFACE parent 1: classid 1:1 cbq rate ${UPLINK}kbit allot 1500 prio 5 bounded isolated # voip (udp sip 5060 et asterisk 4569) ## Tout ce qui match cette règle possede une reservation CBQ de $EXTERNAL_UL_VOIP_KBPS | priorité numéro 1 ! if [ -n "$EXTERNAL_UL_VOIP_KBPS" ]; then /sbin/tc class add dev $EXTERNAL_IFACE parent 1:1 classid 1:5 cbq rate ${EXTERNAL_UL_VOIP_KBPS}kbit allot 1600 prio 1 avpkt 1000 $EXTERNAL_UL_VOIP_SHARE ## pfifo : pure 'premier entré premier sortie' qdisc, évite la congestion de packet dans la classid 1:5 /sbin/tc qdisc add dev $EXTERNAL_IFACE parent 1:5 handle 5: pfifo limit 10 # sip prioritaire 5 ! ## filter: utile afin de savoir dans quel classfull qdisc, un packet va etre envoye. ## on peut filter les packets a partir de leur TOS : Type Of Service /sbin/tc filter add dev $EXTERNAL_IFACE parent 1:0 protocol ip prio 5 u32 match ip sport 5060 0xffff match ip protocol 17 0xff flowid 1:5 /sbin/tc filter add dev $EXTERNAL_IFACE parent 1:0 protocol ip prio 5 u32 match ip dport 5060 0xffff match ip protocol 17 0xff flowid 1:5 # rtp (tos 0x10 et udp) (voir le tableau recap de TOS) /sbin/tc filter add dev $EXTERNAL_IFACE parent 1:0 protocol ip prio 5 u32 match ip tos 0x10 0xff match ip protocol 17 0xff flowid 1:5 let UPLINK=UPLINK-EXTERNAL_UL_VOIP_KBPS fi # SMTP if [ -n "$EXTERNAL_UL_SMTP_KBPS" ]; then /sbin/tc class add dev $EXTERNAL_IFACE parent 1:1 classid 1:44 \ cbq rate ${EXTERNAL_UL_SMTP_KBPS}kbit allot 1600 prio 1 avpkt 1000 $EXTERNAL_UL_SMTP_SHARE /sbin/tc qdisc add dev $EXTERNAL_IFACE parent 1:44 handle 44: sfq perturb 10 /sbin/tc filter add dev $EXTERNAL_IFACE parent 1:0 protocol ip prio 44 u32 \ match ip dport 25 0xffff match ip protocol 6 0xFF match ip firstfrag flowid 1:44 /sbin/tc filter add dev $EXTERNAL_IFACE parent 1:0 protocol ip prio 44 u32 \ match ip dport 2525 0xffff match ip protocol 6 0xFF match ip firstfrag flowid 1:44 /sbin/tc filter add dev $EXTERNAL_IFACE parent 1:0 protocol ip prio 44 u32 \ match ip dport 587 0xffff match ip protocol 6 0xFF match ip firstfrag flowid 1:44 let UPLINK=UPLINK-EXTERNAL_UL_SMTP_KBPS fi # HTTP if [ -n "$EXTERNAL_UL_HTTP_KBPS" ]; then /sbin/tc class add dev $EXTERNAL_IFACE parent 1:1 classid 1:46 \ cbq rate ${EXTERNAL_UL_HTTP_KBPS}kbit allot 1600 prio 1 avpkt 1000 $EXTERNAL_UL_HTTP_SHARE /sbin/tc qdisc add dev $EXTERNAL_IFACE parent 1:46 handle 46: sfq perturb 10 /sbin/tc filter add dev $EXTERNAL_IFACE parent 1:0 protocol ip prio 46 u32 \ match ip dport 80 0xffff match ip protocol 6 0xFF match ip firstfrag flowid 1:46 let UPLINK=UPLINK-EXTERNAL_UL_HTTP_KBPS fi # OTHERTCP if [ -n "$EXTERNAL_UL_OTHERTCP_KBPS" ]; then /sbin/tc class add dev $EXTERNAL_IFACE parent 1:1 classid 1:48 \ cbq rate ${EXTERNAL_UL_OTHERTCP_KBPS}kbit allot 1600 prio 1 avpkt 1000 $EXTERNAL_UL_OTHERTCP_SHARE /sbin/tc qdisc add dev $EXTERNAL_IFACE parent 1:48 handle 48: sfq perturb 10 /sbin/tc filter add dev $EXTERNAL_IFACE parent 1:0 protocol ip prio 48 u32 \ match ip dport $EXTERNAL_UL_OTHERTCP_PORT 0xffff match ip protocol 6 0xFF match ip firstfrag \ flowid 1:48 let UPLINK=UPLINK-EXTERNAL_UL_OTHERTCP_KBPS fi if [ $UPLINK -gt 0 ]; then # classe interactive /sbin/tc class add dev $EXTERNAL_IFACE parent 1:1 classid 1:10 cbq rate ${UPLINK}kbit allot 1600 prio 2 avpkt 1000 /sbin/tc qdisc add dev $EXTERNAL_IFACE parent 1:10 handle 10: sfq perturb 10 # TOS Minimum Delay (ssh, NOT scp) in 1:10: donc on lui donne un priorité de 1000 /sbin/tc filter add dev $EXTERNAL_IFACE parent 1:0 protocol ip prio 1000 u32 match ip tos 0x10 0xff flowid 1:10 # ICMP (ip protocol 1) dans la classe interactive 1:10 donc on lui donne un priorité de 1001 /sbin/tc filter add dev $EXTERNAL_IFACE parent 1:0 protocol ip prio 1001 u32 match ip protocol 1 0xff flowid 1:10 # Pour accélérer le downaload lorsqu'un upload est en court il faut bien faire les ACK dans la classe interactive. /sbin/tc filter add dev $EXTERNAL_IFACE parent 1: protocol ip prio 1002 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 # classe bulk /sbin/tc class add dev $EXTERNAL_IFACE parent 1:1 classid 1:20 cbq rate $[9*$UPLINK/10]kbit \ allot 1600 prio 3 avpkt 1000 /sbin/tc qdisc add dev $EXTERNAL_IFACE parent 1:20 handle 20: sfq perturb 10 /sbin/tc filter add dev $EXTERNAL_IFACE parent 1: protocol ip prio 1003 u32 \ match ip dst 0.0.0.0/0 flowid 1:20 else echo "Error: no bandwidth left for uplink on $EXTERNAL_IFACE: $UPLINK" 1>&2 /sbin/tc qdisc del dev $EXTERNAL_IFACE root 2> /dev/null > /dev/null fi # # Il faut ralentir les download afin d'éviter que l'ISP mette en queue ce qui engendre le lag # Les ISP ont tendance à avoir des queues énormes afin d'être sûrs que les downloads seront rapides. # # police ingress: /sbin/tc qdisc add dev $EXTERNAL_IFACE handle ffff: ingress # voip # tout ce qui est voip ne doit pas être limité, donc on fait un match simple # iax2 /sbin/tc filter add dev $EXTERNAL_IFACE parent ffff: protocol ip prio 5 u32 \ match ip sport 4569 0xffff match ip protocol 17 0xff flowid :1 /sbin/tc filter add dev $EXTERNAL_IFACE parent ffff: protocol ip prio 5 u32 \ match ip dport 4569 0xffff match ip protocol 17 0xff flowid :1 # sip # priorite 5 ! /sbin/tc filter add dev $EXTERNAL_IFACE parent ffff: protocol ip prio 5 u32 \ match ip sport 5060 0xffff match ip protocol 17 0xff flowid :1 /sbin/tc filter add dev $EXTERNAL_IFACE parent ffff: protocol ip prio 5 u32 \ match ip dport 5060 0xffff match ip protocol 17 0xff flowid :1 /sbin/tc filter add dev $EXTERNAL_IFACE parent ffff: protocol ip prio 5 u32 \ match ip sport 5061 0xffff match ip protocol 17 0xff flowid :1 # rtp (tos 0x10 et udp) # priorte 5 ! /sbin/tc filter add dev $EXTERNAL_IFACE parent ffff: protocol ip prio 5 u32 \ match ip tos 0x10 0xff match ip protocol 17 0xff flowid :1 # SMTP if [ -n "$EXTERNAL_DL_SMTP_KBPS" ]; then /sbin/tc filter add dev $EXTERNAL_IFACE parent ffff: protocol ip prio 44 u32 \ match ip sport 25 0xffff match ip protocol 6 0xFF match ip firstfrag \ police rate ${EXTERNAL_DL_SMTP_KBPS}kbit burst 10k drop flowid :1 let DOWNLINK=DOWNLINK-EXTERNAL_DL_SMTP_KBPS fi # HTTP if [ -n "$EXTERNAL_DL_HTTP_KBPS" ]; then /sbin/tc filter add dev $EXTERNAL_IFACE parent ffff: protocol ip prio 46 u32 \ match ip sport 80 0xffff match ip protocol 6 0xFF match ip firstfrag \ police rate ${EXTERNAL_DL_HTTP_KBPS}kbit burst 10k drop flowid :1 let DOWNLINK=DOWNLINK-EXTERNAL_DL_HTTP_KBPS fi # OTHERTCP qui ne matchent pas les règles précédentes if [ -n "$EXTERNAL_DL_OTHERTCP_KBPS" ]; then /sbin/tc filter add dev $EXTERNAL_IFACE parent ffff: protocol ip prio 48 u32 \ match ip sport $EXTERNAL_DL_OTHERTCP_PORT 0xffff match ip protocol 6 0xFF match ip firstfrag \ police rate ${EXTERNAL_DL_OTHERTCP_KBPS}kbit burst 10k drop flowid :1 let DOWNLINK=DOWNLINK-EXTERNAL_DL_OTHERTCP_KBPS fi ##règles de burst if [ $DOWNLINK -gt 0 ]; then /sbin/tc filter add dev $EXTERNAL_IFACE parent ffff: protocol ip prio 1000 u32 \ match ip src 0.0.0.0/0 police rate ${DOWNLINK}kbit burst 10k drop flowid :1 else echo "Error: no bandwidth left for downlink on $EXTERNAL_IFACE: $DOWNLINK" 1>&2 /sbin/tc qdisc del dev $EXTERNAL_IFACE ingress 2> /dev/null > /dev/null fi # initial if (are the 2 required variables defined?) fi
N’hésitez pas à le tester, il déboite 🙂
Le saviez vous ?
“QoS” veut aussi dire “être désolé” en klingon.