#!/bin/sh
#
# local-tc: Configures traffic control (QoS) using tc.
#
# Recommended activation:
# 	# update-rc.d local-tc start 99 S .
#
# Heavily based upon The Ultimate Traffic Conditioner,
# http://lartc.org/howto/lartc.cookbook.ultimate-tc.html
#
# Ivan Vilata i Balaguer <ivan at selidor dot net>, 2003.
#
# Do what you want with this, but acknowledgement is welcome.
# Of course there is NO WARRANTY of any kind.


# The device to be regulated.
DEV=eth0

# Limits of total bandwidth (a little lower than the raw ones, in kbit).
BW_DOWN=$((256 * 85 / 100))	# Downlink (incoming) bandwidth.
BW_UP=$((128 * 85 / 100))	# Uplink (outgoing) bandwidth.

# Traffic classes and their bandwidths.
BW_UP_BULK=$(($BW_UP * 90 / 100))	# Non-interactive traffic.
BW_UP_P2P=64				# Low priority / low bandwidth.

# r2q = slower rate / 1500  (in bytes)
R2Q=$(($BW_UP_P2P * 1000 / 8 / 1500))


TC=/sbin/tc

# Is tc there?
test -x $TC || exit 0


case $1 in
    start)
	echo -n "Starting traffic control:"
	echo -n " $DEV"

	# Shape outgoing traffic...

	# Install root HTB, point default traffic to 1:20.
	$TC qdisc add dev $DEV root handle 1: htb default 20 r2q $R2Q

	# Shape everything at $BW_UP speed - this prevents huge queues in your
	# DSL modem which destroy latency.
	$TC class add dev $DEV parent 1: classid 1:1 \
	    htb rate ${BW_UP}kbit burst 6k

	# High priority class 1:10 gets all outgoing bandwidth and the highest
	# priority.
	$TC class add dev $DEV parent 1:1 classid 1:10 \
	    htb rate ${BW_UP}kbit burst 6k prio 1

	# Bulk and default class 1:20 gets slightly less bandwidth and a lower
	# priority.
	$TC class add dev $DEV parent 1:1 classid 1:20 \
	    htb rate ${BW_UP_BULK}kbit burst 6k prio 2

	# Class 1:30 gets a limited bandwidth and the lowest priority.
	$TC class add dev $DEV parent 1:1 classid 1:30 \
	    htb rate ${BW_UP_P2P}kbit burst 6k prio 3


	# Connections in each class share bandwidth fairly.
	$TC qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10
	$TC qdisc add dev $DEV parent 1:20 handle 20: sfq perturb 10
	$TC qdisc add dev $DEV parent 1:30 handle 30: sfq perturb 10


	# Low latency traffic goes into class 1:10, according to its ToS.
	$TC filter add dev $DEV parent 1:0 protocol ip prio 10 u32 \
	    match ip tos 0x10 0xff  flowid 1:10

	# ICMP also goes into low latency class 1:10 (for measurements).
	$TC filter add dev $DEV parent 1:0 protocol ip prio 10 u32 \
	    match ip protocol 1 0xff flowid 1:10

	# To speed up downloads while an upload is going on, ACK packets go
	# into the low latency class 1:10.
	$TC filter add dev $DEV parent 1: protocol ip prio 10 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

	# P2P traffic goes into limited bandwidth class 1:30.
	$TC filter add dev $DEV protocol ip parent 1:0 prio 1 u32 \
	    match ip sport 3673 0xffff flowid 1:30

	$TC filter add dev $DEV protocol ip parent 1:0 prio 1 u32 \
	    match ip sport 3823 0xffff flowid 1:30

	# The remaining traffic goes into default class 1:20.


	# Police input traffic...

	# Attach ingress policer.
	$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 to prevent queuing at our ISP.
	$TC filter add dev $DEV parent ffff: protocol ip prio 50 u32 \
	    match ip src 0.0.0.0/0 \
	    police rate ${BW_DOWN}kbit burst 10k drop flowid :1

	echo '.'
	;;
    stop)
	echo -n "Stopping traffic control:"
	echo -n " $DEV"
	# Remove output and input qdiscs.
	$TC qdisc del dev $DEV root
	$TC qdisc del dev $DEV ingress
	echo '.'
	;;
    restart)
	$0 stop
	$0 start
	;;
    force-reload)
	$0 stop
	$0 start
	;;
    *)
	echo "Usage: /etc/init.d/local-tc {start|stop|restart|force-reload}"
	exit 1
	;;
esac

exit 0
