Posted by & filed under Programming & Sysadmin.

Things that use ftp or p2p to transfer data tend to abuse the upload bandwidth on asymmetric broadband (dsl/cable) links. When the upload link is saturated, the download can suffer from high latency. This causes other applications or other computers sharing the same link, to crawl, even though there is download capacity available.

Linux Traffic Control is a bit complicated, but as long as you have tc and iproute2 installed, you can throttle your upload speed using simple shell script like this:


# configures upload (outgoing) bandwidth
# does nothing directly to change download bandwidth
#
# set LOCAL_IP, INT, TOTAL_BW, and LIMITED_CLASS_BW, PORT and FILTER
#
# FILTER defaults to filtering by IP (all outgoing traffic is throttled).
# Set it to 'PORT' to filter by source port instead, to
# slow webserver traffic for example, also set PORT to '80'
# PORT is not used when FILTER is set to IP
####### configure this stuff!! ########
LOCAL_IP='192.168.1.64'
INT='wlan0'
TOTAL_BW='1mbit'
LIMITED_CLASS_BW='128kbit'
FILTER='IP'
PORT='80'
#######################

# these are probably okay as is
TC='/sbin/tc'
TOTAL_BURST='15k'

if [ $1 == 'on' ]; then
$TC qdisc del dev $INT root handle 1: htb default 30
$TC qdisc add dev $INT root handle 1: htb default 30
$TC class add dev $INT parent 1: classid 1:1 htb rate $TOTAL_BW burst $TOTAL_BURST
$TC class add dev $INT parent 1:1 classid 1:10 htb rate $TOTAL_BW burst $TOTAL_BURST quantum 3000
$TC class add dev $INT parent 1:1 classid 1:30 htb rate 1kbit ceil $LIMITED_CLASS_BW burst $TOTAL_BURST quantum 3000
$TC qdisc add dev $INT parent 1:10 handle 10: sfq perturb 10
$TC qdisc add dev $INT parent 1:30 handle 30: sfq perturb 10
U32="$TC filter add dev $INT protocol ip parent 1:0 prio 1 u32"
if [ $FILTER == 'PORT' ]; then
$U32 match ip sport $PORT 0xffff flowid 1:30
else
$U32 match ip src $LOCAL_IP/32 flowid 1:30
fi
else
$TC qdisc del dev $INT root
fi
# end

You’ll need to configure the top section for your use. You can filter by outgoing port or by your IP. This must be run as root, or with sudo.

You can use something like iftop to verify that this works as expected.

If you want a GUI for it, here’s a quick python script that will bring up a couple of buttons to enable/disable the throttling of your upload speed. It must also be run as root!

#!/usr/bin/env python

# SlowMyUpload

import pygtk
import os
pygtk.require('2.0')
import gtk

class SlowMyUpload:
def callback(self, widget, data):
if data == "Slow My Upload":
#print "%s was pressed" % data
os.system('./tc.sh on')
print "tc config is now:"
os.system('/sbin/tc -s qdisc ls dev wlan0')
print "nuse iftop or similar to verify that things are working correctlyn"
else:
#print "%s was pressed" % data
os.system('./tc.sh off')
print "tc config is now:"
os.system('/sbin/tc -s qdisc ls dev wlan0')

def delete_event(self, widget, event, data=None):
print "shutting down user interface.n shutting down tcn"
os.system('./tc.sh off')
print "tc config is now:"
os.system('/sbin/tc -s qdisc ls dev wlan0')
print "ndonen"
gtk.main_quit()
return False

def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_title("Slow My Upload")
self.window.connect("delete_event", self.delete_event)
self.window.set_border_width(10)
self.box1 = gtk.HBox(False, 0)
self.window.add(self.box1)
self.button1 = gtk.Button("Slow My Upload")
self.button1.connect("clicked", self.callback, "Slow My Upload")
self.box1.pack_start(self.button1, True, True, 0)
self.button1.show()
self.button2 = gtk.Button("Remove Bandwidth Limit")
self.button2.connect("clicked", self.callback, "Remove Limit")
self.box1.pack_start(self.button2, True, True, 0)
self.button2.show()
self.box1.show()
self.window.show()

def main():
gtk.main()

if __name__ == "__main__":
hello = SlowMyUpload()
main()

If I have time, I’ll improve on the interface, and allow more settings from the desktop. However, since it must be run as root, it’s a bit of a can of worms to deal with privilege escalation on the desktop, given the myriad ways this is handled in various linux distros.