QoS with Linux using PRIO and HTB

I have used the Wondershaper and other QoS scripts for Linux, and they were surely better than nothing, but they were never perfect. The problem is that they all use fair queing schemes where one connection cannot steal all the bandwidth, but this is exactly what I want. When I use VoIP I don't want any other traffic sent out on my link when there is VoIP data that wants to go out. I solved it using the following script:



#!/bin/bash

 TC=/sbin/tc

 DEV=eth1

 if [[ "$1" = "prio" ]
 then
        CEIL=170
        DOWNLINK=768
 else
        CEIL=370
        DOWNLINK=2048
 fi

 # low priority OUTGOING traffic - you can leave this blank if you want
 # low priority source netmasks
 NOPRIOHOSTSRC=

 # low priority destination netmasks
 NOPRIOHOSTDST=

 # low priority source ports
 NOPRIOPORTSRC=

 # low priority destination ports
 NOPRIOPORTDST=

 if [[ "$1" = "status" ]
 then
        $TC -s qdisc ls dev $DEV
        $TC -s class ls dev $DEV
        exit
 fi

 # clean existing down- and uplink qdiscs, hide errors
 $TC qdisc del dev $DEV root    2> /dev/null > /dev/null
 $TC qdisc del dev $DEV ingress 2> /dev/null > /dev/null

 if [[ "$1" = "stop" ]
 then
        exit
 fi

 ###### uplink

 $TC qdisc add dev ${DEV} root handle 1: prio bands 2 priomap 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 $TC qdisc add dev ${DEV} parent 1:1 handle 11: pfifo
 $TC qdisc add dev ${DEV} parent 1:2 handle 12: htb r2q 3

 $TC class add dev ${DEV} parent 12: classid 12:1 htb rate ${CEIL}kbit burst 2k

 $TC class add dev ${DEV} parent 12:1 classid 12:10 htb \
    rate $[[50*$CEIL/100]kbit ceil ${CEIL}kbit burst 2k prio 1
 $TC class add dev ${DEV} parent 12:1 classid 12:11 htb \
    rate $[[30*$CEIL/100]kbit ceil ${CEIL}kbit burst 2k prio 2
 $TC class add dev ${DEV} parent 12:1 classid 12:12 htb \
    rate $[[20*$CEIL/100]kbit ceil ${CEIL}kbit burst 2k prio 3

 $TC qdisc add dev ${DEV} parent 12:10 handle 1210: sfq perturb 10
 $TC qdisc add dev ${DEV} parent 12:11 handle 1211: sfq perturb 10
 $TC qdisc add dev ${DEV} parent 12:12 handle 1212: sfq perturb 10

 # VoIP traffic always get first in line
 $TC filter add dev ${DEV} parent 1: prio 1 protocol ip u32 \
    match ip tos 0x68 0xff \
    match ip protocol 0x11 0xff \
    flowid 1:1

 $TC filter add dev ${DEV} parent 1: prio 1 protocol ip u32 \
    match ip tos 0xb8 0xff \
    match ip protocol 0x11 0xff \
    flowid 1:1

 # All non-VoIP traffic on the second band
 $TC filter add dev ${DEV} parent 1: protocol ip prio 3 u32 \
    match ip src 0.0.0.0/0 \
    flowid 1:2

 # TOS Minimum Delay
 $TC filter add dev ${DEV} parent 12: protocol ip prio 10 u32 \
    match ip tos 0x10 0xff \
    flowid 12:10

 # ICMP (ip protocol 1) in the interactive class
 $TC filter add dev ${DEV} parent 12: protocol ip prio 11 u32 \
        match ip protocol 1 0xff flowid 12:10

 # To speed up downloads while an upload is going on, put ACK packets in
 # the interactive class:
 $TC filter add dev ${DEV} parent 12: protocol ip prio 12 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 12:10

 # some traffic however suffers a worse fate

 for a in $NOPRIOPORTDST
 do
        $TC filter add dev $DEV parent 12: protocol ip prio 30 u32 \
            match ip protocol 0x6 0xff \
            match ip dport $a 0xffff \
            flowid 12:12
 done

 for a in $NOPRIOPORTSRC
 do
        $TC filter add dev $DEV parent 12: protocol ip prio 31 u32 \
            match ip protocol 0x6 0xff \
            match ip sport $a 0xffff \
            flowid 12:12
 done

 for a in $NOPRIOHOSTSRC
 do
        $TC filter add dev $DEV parent 12: protocol ip prio 32 u32 \
            match ip protocol 0x6 0xff \
            match ip src $a \
            flowid 12:12
 done

 for a in $NOPRIOHOSTDST
 do
        $TC filter add dev $DEV parent 12: protocol ip prio 33 u32 \
            match ip protocol 0x6 0xff \
            match ip dst $a \
            flowid 12:12
 done

 # rest is 'non-interactive' ie 'bulk' and ends up in the default queue
 $TC filter add dev ${DEV} parent 12: protocol ip prio 20 u32 \
    match ip src 0.0.0.0/0 \
    flowid 12:11

 ########## downlink #############
 # slow downloads down to somewhat less than the real speed  to prevent
 # queuing at our ISP. Tune to see how high you can set it.
 # ISPs tend to have *huge* queues to make sure big downloads are fast
 #
 # attach ingress policer:

 if [[ "$1" = "prio" ]
 then

 $TC qdisc add dev $DEV handle ffff: ingress

 # filter *everything* to it (0.0.0.0/0), drop everything that's
 # coming in too fast:

 $TC filter add dev $DEV parent ffff: protocol ip prio 50 u32 \
   match ip protocol 0x6 0xff police rate ${DOWNLINK}kbit burst 10k drop \
   flowid :1

 fi


On a drawing the qdiscs and classes look like this:

Comments