Automatic upload speed throttling

As I’ve discussed before, the broadband service we receive from Virgin is subject to caps on the traffic on the line during certain times of day (see this post I wrote). Virgin have a relatively complex system for throttling your speed based on the amount you download and upload within certain times. I have a script which performs a backup of my data from my server at home to my work computer using rsync over SSH. This means that I sometimes have a large amount of data to upload during the day. Since Virgin’s upload restrictions apply between 1500 and 2000 during which time you are permitted to upload a maximum of 1.5GB. What this means is that for five hours, the average transfer rate must not exceed 300MB per hour, which equates to a transfer speed of 83.3 kB/s. I searched for a way to limit my server’s upload speed and came across tc (which is a kernel extension which must be enabled in your .config). Slackware’s kernel config includes the necessary parts as modules, so when you use the tc command, they are automatically loaded.

I found a good example which described what I wanted to achieve (limit my uploads to 83.3 kB/s) here. Using the examples on that page, I wrote a little script to allow me to start and stop the limited uploads easily:

#!/bin/bash

# Script to throttle uploads during the times when Virgin
# won’t allow unlimited uploads.
#
# Those times are between 1500 and 2000 no more than
# 1.5GB must be uploaded, so the upload speed needs to be
# capped at 83.3kB/s.

maxRate=83.3kbps
burstRate=100000kbps
interface=eth0

clearRule(){
        # First things first, clear the old rule
        tc qdisc del dev eth0 root
}

makeRule(){
        # Now add the throttling rule
        tc qdisc add dev $interface root handle 1:0 htb default 10
        tc class add dev $interface parent 1:0 classid 1:10 htb rate $maxRate ceil $burstRate prio 0
}

listRules(){
        tc -s qdisc ls dev $interface
}

case “$1” in
        ‘start’)
                clearRule
                makeRule
        ;;
        ‘stop’)
                clearRule
        ;;
        ‘status’)
                listRules
        ;;
        *)
                echo “Usage: $0 {start|stop|status}”
        ;;
esac

You’ll note I’ve set a $burstRate value of 100MB/s. This is probably not necessary, but with the same $burstRate value as used in $maxRate, I was seeing significant slowdown in the responsiveness of the remote session; I hope this high burst rate will alleviate that slowdown.

I saved this script somewhere where root only could get it and then added the following cronjobs to root’s crontab:

# Add networking throttling between 1500 and 2000
00 15 * * * /root/throttle_uploads.sh start
00 20 * * * /root/throttle_uploads.sh stop

So far, the process appears to be working, insofar as my daily uploads from home to work have slowed to approximately 80kB/s during the times when Virgin monitor uploads.