Sign up for PayPal and start accepting credit card payments instantly.

March 08, 2009

How To Easily Manage Bandwidth In Linux

An Easy Method to Control Bandwidth on Linux Using tc (traffic control)

I'll show you how to easily manage your precious internet bandwidth in Linux. The distribution of Linux that I'm using here is Fedora Core 4, so if you happen to have any trouble with the following information and script then it just might be caused by our different system if you're using any other than Fedora Core 4.

It's very frustrating to experience crawling slow internet connection. Sometimes you just have a question in your head that needs answer fast and like always you decide to consult the good old Google. So you fired up your Mozilla and type in the term in the search bar then stomp enter, but the progress status keeps circling while you stare blankly at the white screen in front of you. You keep on waiting hoping the screen instantly filled with Google image and its search box, but three minutes just passed and the white screen just won’t go away.

What actually has happened? The admin of the network you’re on told you it’s 128/1024 kbps (kilobits per second, for Kilobytes it would be capitalized K as in Kbps) upstream/downstream connection and it’s 1:00 AM where only you and another one sleepy staff are on the network, it shouldn’t be lagged this bad when there’s only few people on the line. So you asked the Network Administrator who happen to be tinkering with something in the room just across you; only to found out that the upstream bandwidth has all been sucked up by the uploading process initiated by that one sleepy staff, apparently he’s uploading something big to his email. This shouldn’t have happened if you have QoS controller running on the network router. The QoS stands for Quality of Service which basically means Bandwidth Management.

Linux have already a built-in bandwidth controller program called tc. To understand how tc works you must have a mental image of a tree structure, a tree structure goes like this:

All the circles are called nodes. There are three types of nodes. The first is root, it’s the mother of all nodes, and no other nodes came before it. The second is parent; parent is a node that has other nodes under it, which are its children. And the last one is leaf, which means no other nodes under it.

In tc we just basically defining nodes. There are another two types of nodes in tc, they are class and qdisc. Class is a node that has children which also make it as a parent, apart as a parent the main role of a class is limiting bandwidth. Think of a class as a valve, you can control the speed of Ethernet packets with it. qdisc stands for Queuing Discipline, it’s always a leaf node, and its main role is just that, queuing packets. In our tree structure image the class can have positions at A, B, C, E, F, and the qdisc at D, G, and H.

Here the fun begins. To create a working bandwidth management configuration in tc, we do four main things:
  1. Attach the root of our nodes to an Ethernet interface. If you don’t know an interface just think of it as a digital form of your LAN card and you refer to it as eth0, eth1, or eth2 according to the number of your LAN cards.
  2. Define classes which control the speed of Ethernet packets.
  3. Define qdisc for each class that doesn’t have any children.
  4. Define rules in mangle table to mark packets with a number which is the id of the class that we want the packet to go to.
To make your life easier I just wrote a script that you can immediately use with a little configuration, here it is:

Save the following in a file named setband
---BEGINNING OF FILE---

#!/bin/bash

#################
### FUNCTIONS ###

DEV=
QDISC=1

root() {
DEV=$1
tc qdisc del dev $DEV root
tc qdisc add dev $DEV root handle $QDISC:0 htb
}

class() {
PRIO=
if [[ -n $5 ]]; then
PRIO="prio $5"
fi
tc class add dev $DEV parent $QDISC:$1 classid $QDISC:$2 htb rate $3 ceil $4 $PRIO
}

leaf() {
class $1 $2 $3 $4 $5
tc qdisc add dev $DEV parent $QDISC:$2 handle $2:0 sfq perturb 5 quantum 1500
tc filter add dev $DEV parent $QDISC:0 protocol ip handle $2 fw flowid $QDISC:$2
}

##############################
### RUN USER CONFIGURATION ###

name=`basename $0`
#path=`echo $0 | sed -e s/$name//`
path=`dirname $0`

source $path/bandconf

---END OF FILE---
And save the following in a file named bandconf
---BEGINNING OF FILE---

# upstream interface
UPIF=eth0

# downstream interface
DNIF=eth1

# upstream bandwidth
UP=128kbit

# downstream bandwidth
DN=1024kbit

#-----------------------------------------------------------------
# UPSTREAM - eth0 connected to your ISP
root $UPIF

# this class is a child of root, root have id of 0
# this class id is 1
class 0 1 $UP $UP

# don't be fooled by the following leaf statement.
# it's actually a call to a function named leaf which
# creates a htb class with specified bandwidth limit
# then creates a qdisc under it with a type of sfq qdisc,
# and finally creates a filter on the root to direct packets
# marked by iptables to the newly created class
# (see the content of setband file)
leaf 1 101 32kbit 64kbit

# limit speed of packets marked with 102 to 16kbit/s
# and when there are more bandwidth in its parent allow
# it to borrow up to 50kbit/s
leaf 1 102 16kbit 50kbit

#-----------------------------------------------------------------
# DOWNSTREAM - eth1 connected to your LAN
root $DNIF

# this class is a child of root, root have id of 0
# this class id is 2
class 0 2 $DN $DN

# limit speed of packets marked with 101 to 256kbit/s
# and when there are more bandwidth in its parent allow
# it to borrow up to 1024kbit/s
# 101 here is not the same as 101 in upstream configuration
# because it rooted on different ethernet interface
leaf 2 101 256kbit 1024kbit

# limit speed of packets marked with 102 to 256kbit/s
# and when there are more bandwidth in its parent allow
# it to borrow up to 768kbit/s
leaf 2 102 256kbit 768kbit

#-----------------------------------------------------------------
# PACKETS MARKING

OURNET=192.168.0.0/16

# these rules mark packets with upstream direction
iptables -t mangle -A FORWARD -s 192.168.10.1 -d ! $OURNET -j MARK --set-mark 101
iptables -t mangle -A FORWARD -s 192.168.10.2 -d ! $OURNET -j MARK --set-mark 102

# these rules mark packets with downstream direction
iptables -t mangle -A FORWARD -d 192.168.10.1 -s ! $OURNET -j MARK --set-mark 101
iptables -t mangle -A FORWARD -d 192.168.10.2 -s ! $OURNET -j MARK --set-mark 102

---END OF FILE---
After you created the files change their mode so you can execute them:
chmod +x setband bandconf
Then edit /etc/rc.local and add the following line so the configuration takes effect every system reboot:
/etc/band/setband
Change /etc/band if you put the files on different directory.

Don't forget to edit the UPSTREAM, DOWNSTREAM, and MARKING sections to fit your needs.

No comments: