May 29, 2009

 Throttling Bandwidth using tc for linux

Scenario: Mail servers, particularly if you have a large amount of users, can be very demanding on bandwidth.  If the mail server is on a shared internet connection, you may require the atmail server to only use an allocated amount of bandwidth.
Solution: tc, short for traffic controller, is a commandline utility which has the ability to throttle uploads and downloads.

NOTE: tc is a tool that comes with the iproute package and is required.

Traffic controller is a very complicated tool to use, even for simple functions, but there is a script below which makes it very simple, if you are using it for throttling connections.

This script was taken from

#  tc uses the following units when passed as a parameter.
#  kbps: Kilobytes per second
#  mbps: Megabytes per second
#  kbit: Kilobits per second
#  mbit: Megabits per second
#  bps: Bytes per second
#       Amounts of data can be specified in:
#       kb or k: Kilobytes
#       mb or m: Megabytes
#       mbit: Megabits
#       kbit: Kilobits
#  To get the byte figure from bits, divide the number by 8 bit

# Name of the traffic control command.

# The network interface we're planning on limiting bandwidth.
IF=eth0             # Interface

# Download limit (in mega bits)
DNLD=1mbit          # DOWNLOAD Limit

# Upload limit (in mega bits)
UPLD=1mbit          # UPLOAD Limit

# IP address of the machine we are controlling
IP=     # Host IP

# Filter options for limiting the intended interface.
U32="$TC filter add dev $IF protocol ip parent 1:0 prio 1 u32"

start() {

# We'll use Hierarchical Token Bucket (HTB) to shape bandwidth.
# For detailed configuration options, please consult Linux man
# page.

$TC qdisc add dev $IF root handle 1: htb default 30
$TC class add dev $IF parent 1: classid 1:1 htb rate $DNLD
$TC class add dev $IF parent 1: classid 1:2 htb rate $UPLD
$U32 match ip dst $IP/32 flowid 1:1
$U32 match ip src $IP/32 flowid 1:2

# The first line creates the root qdisc, and the next two lines
# create two child qdisc that are to be used to shape download
# and upload bandwidth.
# The 4th and 5th line creates the filter to match the interface.
# The 'dst' IP address is used to limit download speed, and the
# 'src' IP address is used to limit upload speed.


stop() {

# Stop the bandwidth shaping.
$TC qdisc del dev $IF root


restart() {

# Self-explanatory.
sleep 1


show() {

# Display status of traffic control status.
$TC -s qdisc ls dev $IF


case "$1" in


echo -n "Starting bandwidth shaping: "
echo "done"


echo -n "Stopping bandwidth shaping: "
echo "done"


echo -n "Restarting bandwidth shaping: "
echo "done"


echo "Bandwidth shaping status for $IF:"
echo ""


echo "Usage: tc.bash {start|stop|restart|show}"

esac exit 0

Note that you will need to edit the variables at the top of the file to your own preferences.  There is no need for me to explain them here as the code has been well commented.
Once this has been completed, all you need to do is copy/paste the code above into a file, (say, /etc/init.d/shaping), change permissions to make it executable (chmod +x /etc/init.d/shaping) and then run:

# /etc/init.d/shaping start

Happy throttling.

Filed under: Atmail 5,Atmail 6,Optimization — info @ 10:03 pm


  1. Thanks for providing such a useful script, works like a charm!

    Comment by Latif Khalifa — July 29, 2009 @ 4:05 pm
  2. Nice script. I have tried it and its working. Keep up the good work

    Comment by Rod — February 18, 2010 @ 6:12 pm
  3. I can not figure out how to run a shell script on dd-wrt, so I just take some of the command lines and use them on my dd-wrt router. It’s working too. Thanks for the detailed comments^_^

    Comment by kidault — April 17, 2010 @ 4:17 am
  4. The tc man page states that SHAPING and SCHEDULING can occur ONLY on egress while POLICING and DROPPING can occur only on ingress. So I don’t understand:

    1. How we can control the bandwidth (SHAPING) available to a client making an upload to the server (ingress)

    2. I have tried running this script and the strange thing is that the incoming traffic is *indeed* delayed when I configure a lower bandwidth for upload. However the strange thing is that the filter I need to set is ‘$U32 match ip src $IP/32 flowid 1:2′ where the $IP is the IP of the host to which a file is being uploaded. I would imagine that this should be the ‘dst $IP’ because we are attempting to delay packets destined for this host. Could you clarify this?

    Comment by Aman — August 13, 2010 @ 8:26 pm

RSS feed for comments on this post. TrackBack URI

Leave a comment