From 1a1631d3b8e4245ad4f12f60cfa34998d491f293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Blizi=C5=84ski?= Date: Tue, 22 Nov 2011 11:08:45 +0000 Subject: [PATCH] Initial commit --- README | 1 + hfsc | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+) create mode 100644 README create mode 100644 hfsc diff --git a/README b/README new file mode 100644 index 0000000..f26781f --- /dev/null +++ b/README @@ -0,0 +1 @@ +HFSC traffic shaping helper script diff --git a/hfsc b/hfsc new file mode 100644 index 0000000..add80b5 --- /dev/null +++ b/hfsc @@ -0,0 +1,217 @@ +#!/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=$3 +UPLINK=$4 + +# Device that connects you to the Internet +DEV=$2 + +# 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" +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