diff options
-rwxr-xr-x | localqos | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/localqos b/localqos new file mode 100755 index 0000000..b969bd1 --- /dev/null +++ b/localqos @@ -0,0 +1,268 @@ +#!/bin/bash +# +# Shaper to share two connection more or less equally among a number of users. +# By Rune Kock, rune.kock@gmail.com +# +# Inspired by Jim diGriz's QoS Scheduler (http://www.digriz.org.uk/jdg-qos-script/) +# and by the WRR example. +# +# Dependencies +# ------------ +# 1) HTB3, RED (has been in the kernel for years) +# 3) iptables utility (www.netfilter.org) +# 4) tc utility (developer.osdl.org/dev/iproute2) +# 6) WRR patch (www.zz9.dk/wrr) and tc patch +# 7) IMQ patch (www.linuximq.net) and iptables patch NOTE: in AA-configuration!!! +# 8) atm and nohyst patches (http://ace-host.stuart.id.au/russell/files/tc/tc-atm/) + +# This script can be edited to support more than one ADSL line. +# Each WAN-line is shaped independently -- not quite fair, but the easiest +# (probably the only) way to do it. + +# Script parameters: +# stop removes QOS setup +# ...any other... removes QOS setup if any, then sets new QOS. + +# debug on....comment out if you want BASH script debugging off +# set -x + +# load configuration from external file +. /etc/qos/config + + +############# Functions for each ADSL line ###################### +function REMOVE-QOS +{ + local IFACE=$1 # e.g. eth0 + local DWIMQ=$2 # e.g. 0 + + $TC qdisc del dev imq$DWIMQ root &> /dev/null + $TC qdisc del dev $IFACE root &> /dev/null + + $IPTABLES -t mangle -D PREROUTING -i $IFACE -j IMQ --todev $DWIMQ &> /dev/null + $IP link set imq$DWIMQ down &> /dev/null +} +#----------------------------------------------------------------- +function QOS-UPLINK +{ + local IFACE=$1 + local UPLIMIT=$2 + local WRR_CLIENTS=$3 + local OVERHEAD=$4 + local PUBIP=$5 + + # more description below at QOS-DOWNLINK + + # The effect of these settings: + # - the maximum priority is 10x minimum. + # - it takes 25 hours without activity to gain maximum priority + # - it takes 90 Mbyte transferred data to be bumped to mimimum priority + + local WRR_WEIGHT1_MODE=1 + local WRR_WEIGHT1_INCR=0.00001 + local WRR_WEIGHT1_DECR=0.00000001 + local WRR_WEIGHT1_MIN=0.1 + local WRR_WEIGHT1_MAX=1.0 + local WRR_WEIGHT1_VAL=1.0 + + # Use HTB to limit the total speed + $TC qdisc add dev $IFACE root handle 8000: htb default 12 + $TC class add dev $IFACE parent 8000: classid 8000:1 htb \ + rate ${UPLIMIT}kbit ceil ${UPLIMIT}kbit overhead $OVERHEAD atm nohyst + + # Create 3 HTB classes for high priority local, normal priority local, + # and normal priority client traffic. + $TC class add dev $IFACE parent 8000:1 classid 8000:10 htb\ + rate $[$UPLIMIT/3]kbit ceil ${UPLIMIT}kbit overhead $OVERHEAD atm nohyst prio 2 + $TC class add dev $IFACE parent 8000:1 classid 8000:11 htb \ + rate $[$UPLIMIT/3]kbit ceil ${UPLIMIT}kbit overhead $OVERHEAD atm nohyst prio 1 + $TC class add dev $IFACE parent 8000:1 classid 8000:12 htb \ + rate $[$UPLIMIT/3]kbit ceil ${UPLIMIT}kbit overhead $OVERHEAD atm nohyst prio 1 + + # To distinguish between local packet and packets originating from the lan, we have + # told Shorewall to give the latter mark 1. (IP source cannot be used, because we are now + # operating after NAT, so everything has our public IP as source). + # Put local packets < 512 bytes in 8000:10 + $TC filter add dev $IFACE protocol ip parent 8000:0 prio 1 u32 \ + match mark 0 0xffff match u16 0x0000 0xfe00 at 2 flowid 8000:10 + # Put other local packets in 8000:11 + $TC filter add dev $IFACE protocol ip parent 8000:0 prio 1 u32 \ + match mark 0 0xffff flowid 8000:11 + # Non-local packets defaults to 8000:12 + + # Client traffic is shared according to ip-address by WRR (the masqueraded source address) + $TC qdisc add dev $IFACE parent 8000:12 handle 1000: wrr sour masq $WRR_CLIENTS 0 + $TC qdisc change handle 1000: dev $IFACE wrr qdisc wmode1=$WRR_WEIGHT1_MODE wmode2=0 + + # Each WRR class gets a RED queue. + # RED drops or ECN-marks packets according to queue-length. + # At <=2kbyte the chance of a RED action is 0%. At 100kbyte it is 100%. + # Hopefully, the sender will get the picture at around 15kbytes. + local RED_MIN=2000 # Start shaping if average queue exceeds 2 kbyte + local RED_MAX=100000 # Full shaping at 100kbytes + local RED_LIMIT=100000 # Absolut maximum queue size + local RED_PROB=1.0 # The probability of dropping/marking a packet when + # queue >= max. Man-page suggests 0.01 or 0.02 + local RED_AVPKT=500 # man-page suggests 1000 + local RED_BURST=8 # man-page suggests (min+min+max)/(3*avpkt) + # (but they use min and max a lot differently than we do). + + for LOOP in `seq 1 $WRR_CLIENTS` + do + local LOOP_HEX=$(printf %X $LOOP) + $TC qdisc add dev $IFACE parent 1000:$LOOP_HEX handle $[1000+$LOOP]: \ + red probability $RED_PROB \ + limit ${RED_LIMIT} min ${RED_MIN} max ${RED_MAX} \ + avpkt ${RED_AVPKT} burst $RED_BURST ecn + + $TC class change classid 1000:$LOOP_HEX dev $IFACE \ + wrr min1=$WRR_WEIGHT1_MIN max1=$WRR_WEIGHT1_MAX \ + decr1=$WRR_WEIGHT1_DECR incr1=$WRR_WEIGHT1_INCR \ + weight1=$WRR_WEIGHT1_VAL + done +} + +#---------------------------------------------------------------- +function QOS-DOWNLINK +{ + local IFACE=$1 + local DWLIMIT=$2 + local WRR_CLIENTS=$3 + local OVERHEAD=$4 + local PUBIP=$5 + + # The following parameters defines the way heavy downloaders are gradually + # given a lesser share than new downloaders (a burst effect). + # Each class has a weight that is dynamically modified as follows: + # (Actually, there are two identical sets of parameters, but I can see absolutely + # no reason to use the second, so it's always inactive). + + # The effect of these settings: + # - the maximum priority is 10x minimum. + # - it takes 25 hours without activity to gain maximum priority + # - it takes 900 Mbyte transferred data to be bumped to mimimum priority + + local WRR_WEIGHT1_MODE=1 + # 0: The weight parameter is not modified + # 1: The weight parameter is decremented by decr*<packet size> + # 2: As if wmode is 1, but also multiply with number of machines waiting + # to transfer data + # 3: As if wmode is 1, but multiplied with the sum of the priorities of the + # machines waiting divided by the priority of this machine. + + local WRR_WEIGHT1_INCR=0.00001 + # Every second the weight parameter is incremented by this value. If + # weight1 reaches 1.0 it is not incremented further. + # The default value is 0.0. + + local WRR_WEIGHT1_DECR=0.000000001 + # Every time a packet is sent the weight parameter is modified depending + # on the value of wmode for the qdisc + + local WRR_WEIGHT1_MIN=0.1 + # min: (0<min) + # This is a lower bound for weight. + # The default value for this parameter is 1.0. + + local WRR_WEIGHT1_MAX=1.0 + # max: (0<max) + # This is a upper bound for weight. + # The default value for this parameter is 1.0. + + local WRR_WEIGHT1_VAL=1.0 + # weight: (min<=weight<=1.0) + # As mentioned above the used weight of the class is proportional to + # this value. The default value is 1.0. + + # Use HTB to limit the speed + $TC qdisc add dev $IFACE root handle 8000: htb default 12 + $TC class add dev $IFACE parent 8000: classid 8000:1 htb \ + rate ${DWLIMIT}kbit ceil ${DWLIMIT}kbit overhead $OVERHEAD atm nohyst + + # Create 3 HTB classes for high priority local, normal priority local, + # and normal priority client traffic. + $TC class add dev $IFACE parent 8000:1 classid 8000:10 htb\ + rate $[$DWLIMIT/3]kbit ceil ${DWLIMIT}kbit overhead $OVERHEAD atm nohyst prio 2 + $TC class add dev $IFACE parent 8000:1 classid 8000:11 htb \ + rate $[$DWLIMIT/3]kbit ceil ${DWLIMIT}kbit overhead $OVERHEAD atm nohyst prio 1 + $TC class add dev $IFACE parent 8000:1 classid 8000:12 htb \ + rate $[$DWLIMIT/3]kbit ceil ${DWLIMIT}kbit overhead $OVERHEAD atm nohyst prio 1 + + # Put local packets < 512 bytes in 8000:10 + # (IMQ in AA configuration grabs the packets after NAT, so we can test on destination). + $TC filter add dev $IFACE protocol ip parent 8000:0 prio 1 u32 \ + match ip dst $PUBIP match u16 0x0000 0xfe00 at 2 flowid 8000:10 + + # Put other local packets in 8000:11 + $TC filter add dev $IFACE protocol ip parent 8000:0 prio 1 u32 \ + match ip dst $PUBIP flowid 8000:11 + # Non-local packets defaults to 8000:12 + + # Share according to ip-address by WRR + $TC qdisc add dev $IFACE parent 8000:12 handle 1000: wrr dest ip $WRR_CLIENTS 0 + $TC qdisc change handle 1000: dev $IFACE wrr qdisc wmode1=$WRR_WEIGHT1_MODE wmode2=0 + + # Each WRR class gets a RED queue. + # RED drops or ECN-marks packets according to queue-length. + # At 2kbyte the chance of a RED action is 0%. At 1Mbyte it is 100%. + # Hopefully, the sender will get the picture at around 10-20kbytes. + local RED_MIN=2000 # Start shaping if average queue exceeds 1 kbyte + local RED_MAX=1000000 # Full shaping at 1Mbytes + local RED_LIMIT=1000000 # Absolut maximum queue size + local RED_PROB=1.0 # The probability of dropping/marking a packet when + # queue >= max. Man-page suggests 0.01 or 0.02 + local RED_AVPKT=1000 # man-page suggests 1000 + local RED_BURST=2 # man-page suggests (min+min+max)/(3*avpkt) + # (but they use min and max a lot differently than we do). + + for LOOP in `seq 1 $WRR_CLIENTS` + do + local LOOP_HEX=$(printf %X $LOOP) + $TC qdisc add dev $IFACE parent 1000:$LOOP_HEX handle $[1000+$LOOP]: \ + red probability $RED_PROB \ + limit ${RED_LIMIT} min ${RED_MIN} max ${RED_MAX} \ + avpkt ${RED_AVPKT} burst $RED_BURST ecn + + $TC class change classid 1000:$LOOP_HEX dev $IFACE \ + wrr min1=$WRR_WEIGHT1_MIN max1=$WRR_WEIGHT1_MAX \ + decr1=$WRR_WEIGHT1_DECR incr1=$WRR_WEIGHT1_INCR \ + weight1=$WRR_WEIGHT1_VAL + done +} +#----------------------------------------------------------------------- +function IFACE-SETUP +{ + local IFACE=$1 + local DWIMQ=$2 + + $IPTABLES -t mangle -I PREROUTING -i $IFACE -j IMQ --todev $DWIMQ + $IP link set imq$DWIMQ up +} + +############################################################################## + +############## Remove QOS configuration ########################## + +REMOVE-QOS $IF1 0 # Once for each ADSL-line +# REMOVE-QOS $IF2 1 + +# removing imq (version 2.6.14-imq1) causes kernel panic +#$MODPROBE -r imq &> /dev/null + +if ( [ "$1" = "stop" ] ) +then + exit +fi + +############## Set up QOS configuration ########################### + +$MODPROBE imq numdevs=$LINES + +QOS-UPLINK $IF1 $UPLIMIT1 $CLIENTS $UPOVERHEAD1 $PUBLICIP1 # Once for each ADSL-line +# QOS-UPLINK $IF2 $UPLIMIT2 $CLIENTS $UPOVERHEAD2 $PUBLICIP2 + +QOS-DOWNLINK imq0 $DWLIMIT1 $CLIENTS $DWOVERHEAD1 $PUBLICIP1 # Once for each ADSL-line +# QOS-DOWNLINK imq1 $DWLIMIT2 $CLIENTS $DWOVERHEAD2 $PUBLICIP2 + +IFACE-SETUP $IF1 0 # Once for each ADSL-line +# IFACE-SETUP $IF2 1 |