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:
On a drawing the qdiscs and classes look like this:
#!/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