#!/bin/bash # encoding: UTF-8 # # Maciej BliziƄski, http://automatthias.wordpress.com/ # # References: # http://www.voip-info.org/wiki/view/QoS+Linux+with+HFSC # http://www.nslu2-linux.org/wiki/HowTo/EnableTrafficShaping # http://www.cs.cmu.edu/~hzhang/HFSC/main.html # Specify parameters of your xDSL. Give values slightly lower than the # nominal ones. For example, my line is 256/128, so I specify 240/100. # Uplink and downlink speeds DOWNLINK=1800 UPLINK=1800 # Device that connects you to the Internet DEV=eth0 # Action to be performed ACTION=$1 # IP addresses of the VoIP phones, # if none, set VOIPIPS="" VOIPIPS="" # Interactive class: SSH Terminal, DNS and gaming (Quake) INTERACTIVEPORTS="22 23 53 3389 5900" # VoIP telephony VOIPPORTS="5060:5100 10000:11000 5000:5059 8000:8016 5004 1720 1731 4569" #VOIPPORTS="" # WWW, jabber and IRC BROWSINGPORTS="80 443 8080" # The lowest priority traffic: eDonkey, Bittorrent, etc. P2PPORTS="110 25 21 143 445 137:139 4662 4664 6881:6999" ######################################################################## # Configuration ends here ######################################################################## function check_device() { if [ -z "$DEV" ] ; then echo "$0: stop requires a device, aborting." exit -1 fi } case "$ACTION" in status) check_device echo "[qdisc]" tc -s qdisc show dev $DEV echo "" echo "[class]" tc -s class show dev $DEV echo "" echo "[filter]" tc -s filter show dev $DEV echo "" echo "[iptables]" iptables -t mangle -L THESHAPER -v -x 2> /dev/null exit ;; stop) check_device # Reset everything to a known state (cleared) tc qdisc del dev $DEV root > /dev/null 2>&1 tc qdisc del dev $DEV ingress > /dev/null 2>&1 # Flush and delete tables iptables -t mangle --delete POSTROUTING -o $DEV -j THESHAPER > /dev/null 2>&1 iptables -t mangle --flush THESHAPER 2> /dev/null > /dev/null iptables -t mangle --delete-chain THESHAPER 2> /dev/null > /dev/null echo "Shaping removed on $DEV." exit ;; start) check_device if [ -z "$DOWNLINK" ] ; then echo "$0: start requires a downlink speed, aborting." exit -1 fi if [ -z "$UPLINK" ] ; then echo "$0: start requires an uplink speed, aborting." exit -1 fi # Traffic classes: # 1:2 Interactive (SSH, DNS, ACK, Quake) # 1:3 Low latency (VoIP) # 1:4 Browsing (HTTP, HTTPs) # 1:5 Default # 1:6 Low priority (p2p, pop3, smtp, etc) # add HFSC root qdisc tc qdisc add dev $DEV root handle 1: hfsc default 5 # add main rate limit class tc class add dev $DEV parent 1: classid 1:1 hfsc \ sc rate ${UPLINK}kbit ul rate ${UPLINK}kbit # Interactive traffic: guarantee realtime full uplink for 50ms, then # 5/10 of the uplink tc class add dev $DEV parent 1:1 classid 1:2 hfsc \ rt m1 ${UPLINK}kbit d 50ms m2 $((5*$UPLINK/10))kbit \ ls m1 ${UPLINK}kbit d 50ms m2 $((7*$UPLINK/10))kbit \ ul rate ${UPLINK}kbit # VoIP: guarantee full uplink for 200ms, then 3/10 tc class add dev $DEV parent 1:1 classid 1:3 hfsc \ sc m1 ${UPLINK}kbit d 200ms m2 $((3*$UPLINK/10))kbit \ ul rate ${UPLINK}kbit # Browsing: Don't guarantee anything for the first second, then # guarantee 1/10 tc class add dev $DEV parent 1:1 classid 1:4 hfsc \ sc m1 0 d 1s m2 $((1*$UPLINK/10))kbit \ ul rate ${UPLINK}kbit # Default traffic: don't guarantee anything for the first two seconds, # then guarantee 1/20 tc class add dev $DEV parent 1:1 classid 1:5 hfsc \ sc m1 0 d 2s m2 $((1*$UPLINK/20))kbit \ ul rate ${UPLINK}kbit # Default traffic: don't guarantee anything for the first 10 seconds, # then guarantee 1/20 tc class add dev $DEV parent 1:1 classid 1:6 hfsc \ sc m1 0 d 10s m2 $((1*$UPLINK/20))kbit \ ul rate ${UPLINK}kbit # add THESHAPER chain to the mangle table in iptables iptables -t mangle --new-chain THESHAPER iptables -t mangle --insert POSTROUTING -o $DEV -j THESHAPER # To speed up downloads while an upload is going on, put short ACK # packets in the interactive class: iptables -t mangle -A THESHAPER \ -p tcp \ -m tcp --tcp-flags FIN,SYN,RST,ACK ACK \ -m length --length :64 \ -j CLASSIFY --set-class 1:2 # put large (512+) icmp packets in browsing category iptables -t mangle -A THESHAPER \ -p icmp \ -m length --length 512: \ -j CLASSIFY --set-class 1:4 # ICMP (ip protocol 1) in the interactive class iptables -t mangle -A THESHAPER \ -p icmp \ -m length --length :512 \ -j CLASSIFY --set-class 1:2 setclassbyport() { port=$1 CLASS=$2 iptables -t mangle -A THESHAPER -p udp --sport $port -j CLASSIFY --set-class $CLASS iptables -t mangle -A THESHAPER -p udp --dport $port -j CLASSIFY --set-class $CLASS iptables -t mangle -A THESHAPER -p tcp --sport $port -j CLASSIFY --set-class $CLASS iptables -t mangle -A THESHAPER -p tcp --dport $port -j CLASSIFY --set-class $CLASS } for port in $INTERACTIVEPORTS; do setclassbyport $port 1:2; done for port in $VOIPPORTS; do setclassbyport $port 1:3; done for port in $BROWSINGPORTS; do setclassbyport $port 1:4; done for port in $P2PPORTS; do setclassbyport $port 1:6; done for VOIP in $VOIPIPS do iptables -t mangle -A THESHAPER --src $VOIP -j CLASSIFY --set-class 1:3 iptables -t mangle -A THESHAPER --dst $VOIP -j CLASSIFY --set-class 1:3 done # Try to control the incoming traffic as well. # Set up ingress qdisc tc qdisc add dev $DEV handle ffff: ingress # Filter everything that is coming in too fast # It's mostly HTTP downloads that keep jamming the downlink, so try to restrict # them to 6/10 of the downlink. tc filter add dev $DEV parent ffff: protocol ip prio 50 \ u32 match ip src 0.0.0.0/0 \ match ip protocol 6 0xff \ match ip sport 80 0xffff \ police rate $((6*${DOWNLINK}/10))kbit \ burst 10k drop flowid :1 tc filter add dev $DEV parent ffff: protocol ip prio 50 \ u32 match ip src 0.0.0.0/0 \ match ip protocol 6 0xff \ match ip dport 80 0xffff \ police rate $((6*${DOWNLINK}/10))kbit \ burst 10k drop flowid :1 ;; *) echo "$0 [ACTION] [device]" echo "ACTION := { start [downlink] [uplink] | stop | status }" exit ;; esac