Throttling Bandwidth on Apache

Dear All,

There seems to be many different ways of controlling bandwidth usage of downloads of content from Apache2. Does anyone know which is the standard module deployed/deployable in OpenSuse?

Thanks in advance.

Welcome to the wonderful (and complicated) world of traffic shaping. First of all, you should do a lot of reading here: Linux advanced Routing & Traffic Control HOWTO. Once you understand it, the answer is: YES, it can be done. The name of the command line tool is ‘tc’ (see: man tc). To get you started, I can give you an example of a shell script using tc. Be warned: it will be completely useless for you, unless you tweak/adapt it for your purpose.

The script can be named ‘bwthrottle’ and put under /usr/sbin (must be run as root).

#!/bin/bash
#
# The Ultimate Setup For Your Internet Connection At Home
# 
#
# Set the following values to somewhat less than your actual download
# and uplink speed. In kilobits
DOWNLINK=600
UPLINK=360
#DEV=ppp0
DEVEXT=eth1
DEVINT=eth0
DEV=$DEVEXT

# Calculate Weight
DLW=$(($DOWNLINK / 10))
ULW=$(($UPLINK / 10))

AVPKTA=64   
AVPKTB=1100
 
APP="bwthrottle"

if test -z "$1" ; then
        echo "Control bandwidth throttle"
        echo "Usage: $APP show|status|start|stop|reload"
        exit
fi
  
# set variables
TC="/usr/sbin/tc"

# define functions

clean() {
        # clean existing down- and uplink qdiscs, hide errors
        $TC qdisc del dev $DEV root    2> /dev/null > /dev/null
        RETVALONE=$?
        $TC qdisc del dev $DEV ingress 2> /dev/null > /dev/null
        RETVALTWO=$?
}
stop() {
        echo -n "Stopping $APP ... "
        clean
        if test $(($RETVALONE + $RETVALTWO)) -eq $((0)) ; then
                echo "done"
        else
                echo "failed (return values root/ingress = $RETVALONE/$RETVALTWO)"
        fi
}

start() {
        declare -a RV
        echo -n "Starting $APP ... "
        ###### uplink
        # install root CBQ
        $TC qdisc add dev $DEV root handle 1: cbq avpkt 500 \
                bandwidth 100mbit cell 8 mpu 64
        RV[1]=$?

        # shape everything at $UPLINK speed - this prevents huge queues in
        # your DSL modem which destroy latency:
        # main class
        $TC class add dev $DEV parent 1: classid 1:1 cbq \
                rate ${UPLINK}kbit allot 1500 prio 5 bounded isolated
        RV[2]=$?

        # high prio class 1:10:
        $TC class add dev $DEV parent 1:1 classid 1:10 cbq \
                rate ${UPLINK}kbit allot 1600 prio 1 avpkt $AVPKTA
        RV[3]=$?

        # bulk and default class 1:20 - gets slightly less traffic, 
        # and a lower priority:
        $TC class add dev $DEV parent 1:1 classid 1:20 cbq \
                rate $[9*$UPLINK/10]kbit allot 1600 prio 2 avpkt $AVPKTB
        RV[4]=$?

        # both get Stochastic Fairness:
        $TC qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10
        RV[5]=$?
        $TC qdisc add dev $DEV parent 1:20 handle 20: sfq perturb 10
        RV[6]=$?

        ###############
        # start filters
        # TOS Minimum Delay (ssh, NOT scp) in 1:10:
        $TC filter add dev $DEV parent 1:0 protocol ip prio 10 u32 \
                match ip tos 0x10 0xff  flowid 1:10
        RV[7]=$?

        # ICMP (ip protocol 1) in the interactive class 1:10 so we 
        # can do measurements & impress our friends:
        $TC filter add dev $DEV parent 1:0 protocol ip prio 11 u32 \
                match ip protocol 1 0xff flowid 1:10
        RV[8]=$?

        # To speed up downloads while an upload is going on,
        # put ACK packets in the interactive class:
        $TC filter add dev $DEV parent 1: 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 1:10
        RV[9]=$?

        # rest is 'non-interactive' ie 'bulk' and ends up in 1:20
        $TC filter add dev $DEV parent 1: protocol ip prio 13 u32 \
                match ip dst 0.0.0.0/0 flowid 1:20
        RV[10]=$?

        ########## 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:
        $TC qdisc add dev $DEV handle ffff: ingress
        RV[11]=$?

        # 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 src 0.0.0.0/0 police rate ${DOWNLINK}kbit \  
                burst 10k drop flowid :1
        RV[12]=$?

        # sum errors if any
        ERRCOUNT=0
        for COUNT in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
                ERRCOUNT=$(($ERRCOUNT + ${RV$COUNT]}))
        done

        # report success
        if test $ERRCOUNT == 0 ; then
                echo "done"
        else
                echo -n "failed (return codes ="
                for COUNT in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
                        if test $((${RV$COUNT]})) -gt $((0)) ; then
                                echo -n " $COUNT]=${RV$COUNT]}"   
                        fi
                done
                echo ")"
        fi
}
report() {
        $TC -s qdisc show dev $DEV
        $TC -s class show dev $DEV
}
 
roottest() {
        if ! test "$EUID" == 0 ; then
                echo "Must be root to run!"
                exit 1
        fi
}

# Execute functions
case "$1" in

        show|status) report
        ;;

        stop) roottest
        stop
        ;;  

        start) roottest
        start
        ;;   

        reload) roottest
        stop
        sleep 1
        start  
        ;;     

        *) echo "ERROR: unknown argument $1"
        ;;
esac
exit 0

Thanks for your response. I’ll have to read up on this