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.

Dynamic DNS services and ddclient

Since changing from O2 to Virgin broadband, I’ve had to hope my dynamic external IP address didn’t change too often. As it turns out, Virgin appear to have a very slow turnover of IPs for home customers, since I’ve had the same one since we changed. I wrote a little script to scrape my IP from http://checkip.dyndns.org every 10 minutes and save the output do Dropbox, but this seemed less than optimal.

I recently read about a nifty little client called ddclient. If your router doesn’t support updating a dynamic DNS service (such as www.dyndns.org) for you, then having a tool like ddclient do it for you is pretty handy.

It’s a little perl utility, which on Slackware requires some external dependencies (perl-IO-Socket-SSL, Net-SSLeay, libwww-perl, perl-html-parser and perl-html-tagset) available from SlackBuilds.org. Set up is pretty straightforward, and the default configuration file (/etc/ddclient/ddclient.conf) is pretty comprehensive. I found, however, it was a bit overwhelming, and the documentation on the website was more useful. In the end, my configuration looked like this:

# Stripped down version of the config file.
# Easier to manage, I think.

daemon=600                      # update every 10 minutes
syslog=yes                      # write to syslog
mail=root                       # all messages go to root
mail-failure=root               # failures sent to root too
pid=/var/run/ddclient.pid       # runtime pid file
# host setup
ssl=yes                         # use ssl when updating hostname
protocol=dyndns2                # using dyndns.org
use=web, web=checkip.dyndns.org/, web-skip=’IP Address’
#use=web                        # get ip from internet
login=myusername                # username
password=mypassword             # duh…
my.hostname.com                 # my hostname

I set the daemon to run every ten minutes and it uses www.dyndns.org to update the IP associated with my.hostname.com. I altered the line use=web to use=web, web=checkip.dyndns.org/, web-skip=’IP Address’ because I was getting errors with ddclient finding the checkip.dyndns.org address. In theory, this forces ddclient to parse the output from checkip.dyndns.org correctly.

In the end, ddclient does a very similar thing to my suboptimal approach, though it updates my dyndns account for me rather than me having to do so from the Dropbox text file to which my script saved my IP address.

Virgin DNS

Virgin Broadband intercept invalid DNS requests and supply their own results. Whilst this is convenient to some extent, it does mean they’re interfering with the way things were designed to work. Fortunately, however, it’s easy enough to turn off.

Virgin provide a service to turn off this DNS interception here. A word of caution, you can only apply this change from your home connection.

Bandwidth with Virgin Cable Broadband

We recently switched from o2’s ADSL to Virgin’s cable broadband. I knew that Virgin did traffic management, but I hadn’t really paid it much attention. However, after one evening of particularly slow (think 56k modem-slow) internet, I decided to look into it a bit more.

Stumbling my way through the internet, I came across a tool called iperf. Given two Linux computers, it would tell you the network speed between those two computers. I installed iperf on my Slackware server from SlackBuilds.org and compiled a copy at work on a Red Hat 5 machine. I know that the connection at work is much much faster than my home one, so I was confident I’d be measuring the bandwidth as limited by my home connection rather than by work’s connection.

On the server, I launched the following command:

iperf -s -f k

By default, iperf runs on port 5001, so I opened the appropriate port on the Virgin Media Hub (a NETGEAR VMDG280 Wireless ‘N’ Cable Gateway modem and wireless router combo).

This starts the server (-s) and outputs results in kilobits per second (-f k). On the client at work, I wrote a little bash script (beware line-wrapping):

#!/bin/bash
OUT=$(iperf -c www.example.com -P 4 -f k -w 256k -t 60 | grep SUM)

DATE=$(date +%Y%m%dT%H%M%S)

printf “$DATE ” >> $HOME/logs/bw.log

echo “$OUT” >> $HOME/logs/bw.log

(I’ve replaced my home IP with www.example.com, obviously).This little script saves the output of iperf in $OUT. The switches do the following:
-c – client mode
-P 4 – runs four parallel client threads
-f k – outputs in kilobits per second
-w 256kย – sets the TCP window size to 256k
-t 60ย – sets a sixty second transmit window
The line of interest for the iperf output is the SUM line, so I grep for that to save the results in $OUT.ย The rest of the script just saves the result with a timestamp to a log file.
I run this in cron every ten minutes on the client:

*/10 * * * * $HOME/scripts/bw.sh

To graph the results, I use the Generic Mapping Tools (GMT) package (SlackBuild available here) to plot the results. Figure 1 shows the analysis for the last two days or so:
bw
Figure 1: Bandwidth at home for a 40 hour period. Visible is the 75% bandwidth reduction from 1900 to 0000 on the 19th April.
Since I can now see exactly what the bandwidth at home is every 10 minutes, I decided to try and find out how exactly Virgin were limiting the speed. Some deft searching revealed this page, which outlines their traffic management policy. N.B. this is for areas which have received the upstream upgrade, for those that haven’t, this is the appropriate page.
Although the table is a bit opaque, it can be summarised as follows for the Large bundle:
  • Between 1000 and 1500, downloads must not exceed 3GB (600MB/hr)
  • Between 1600 and 2100, downloads must not exceed 1.5GB (300MB/hr)
  • Between 1500 and 2000, uploads must not exceed 1.5GB (300MB/hr)
The rest of the time, any amount of traffic is permitted, and no traffic management will be imposed. Traffic management is a 75% reduction in connection speed (from 10 megabits per second to 2.5 megabits per second in our case) for 5 hours. Interestingly, from 1500 every day, you get one hour to download as much as you like, and it won’t count towards your total for traffic management.

Comparing the bandwidth in Figure 1 and this traffic management information, we were traffic managed on the 19th April between 1900 and midnight. However, I have to say, you get what you pay for the rest of the time: Virgin’s Large bundle (10 megabit line) really is very close to 10 megabits per second most of the time (generally around 9.8 megbits per second).

I do have a script running which backs up my server to my computer at work (when it’s on), but it does incremental backups, and those are scheduled to run at 0440 i.e. in the middle of the night, when there’s no limit on traffic.

Between 1500 and 2100 I don’t consider us to be a particularly vociferous household when it comes to consumption of material online, yet we still fall into the “very small proportion of customers who are downloading and/or uploading an unusually high amount“. There’s only two of us, and we don’t watch iPlayer very often. We might watch a video every now and then online, but we’re certainly not downloading 600MB of content every hour for five hours straight.