HTB Linux traffic control with Debian

Posted by Lennart Weijl on 11 February 2012 | 0 Comments

Tags: , , ,

Traffic shaping (also known as "packet shaping") is an attempt to control computer network traffic in order to optimize or guarantee performance, lower latency, and/or increase usable bandwidth by delaying packets that meet a certain criteria. More specifically, traffic shaping is any action on a set of packets (often called a stream or a flow) which imposes additional delay on those packets such that they conform to some predetermined constraint (a contract or traffic profile). Traffic shaping provides a means to control the volume of traffic being sent into and/or from a network in a specified period (bandwidth throttling), or the maximum rate at which the traffic is sent (rate limiting). This control can be accomplished in many ways and for many reasons; however traffic shaping is always achieved by delaying packets.

Although the HOWTO of (Linux Advanced Routing & Traffic Control HOWTO) is a bit outdated, it's still a very good reference in my opinion and I would advice to read it for better understanding what traffic control is. When you're done reading it, you should be able make a TC-script like the one I wrote and offer on this page.

I am writing this page for people who get the principal of traffic control, read the HOWTO of LARTC, but can't get it to work properly on their setup. I will try to explain how to implement the Hierarchical Token Bucket queueing discipline by using an example case. I hope this approach will clarifies things some more.

1. What is Hierarchical Token Bucket?

"Martin Devera (<devik>) rightly realised that CBQ is complex and does not seem optimized for many typical situations. His Hierarchical approach is well suited for setups where you have a fixed amount of bandwidth which you want to divide for different purposes, giving each purpose a guaranteed bandwidth, with the possibility of specifying how much bandwidth can be borrowed.

HTB works just like CBQ but does not resort to idle time calculations to shape. Instead, it is a classful Token Bucket Filter - hence the name. It has only a few parameters, which are well documented on his site.

As your HTB configuration gets more complex, your configuration scales well. With CBQ it is already complex even in simple cases! HTB3 (check its homepage for details on HTB versions) is now part of the official kernel sources (from 2.4.20-pre1 and 2.5.31 onwards). However, maybe you still need to get a HTB3 patched version of 'tc': HTB kernel and userspace parts must be the same major version, or 'tc' will not work with HTB.

If you already have a modern kernel, or are in a position to patch your kernel, by all means consider HTB." - (2002). Retrieved 11 february 2012 from

1.1. Reading material

2. Example case

2.1. Type of configuration

What I am looking for is a way to slow down uploads to the outside world, yet let various applications share the bandwidth so it won't exceed the maximum upload speed. Also some applications should get more upload speed then others, yet allowing the possibility of borrowing speed from eachother. I'll try to explain some more with an example.

Let's say my maximum upload speed is 6mbit. I have a webserver and a POP3 server. I want the webserver to consume no more than 4mbit and the POP3 server no more than 1mbit. When the webserver is not fully using the assigned bandwidth, the POP3 server is allowed to borrow speed from the webserver (and vice versa). Though both servers cannot exceed the maximum bandwidth. This way I can still browse the web myself, with the 1mbit I do not specify.

In short:

  1. Maximum upload speed of 6mbit
  2. Upload speed is shared by the webserver (4mbit), POP3 server (1mbit)
  3. The webserver is allowed to borrow unused speed from the POP3 server
  4. The POP3 server is allowed to borrow unused speed from the webserver
  5. Other traffic is allowed to borrow unused speed from the POP3 server and the webserver
  6. All traffic cannot exceed the maximum bandwidth of 6mbit

2.2. Example traffic control script


echo "\nConfiguring traffic control.."

# Set some variables
BURST="120kb" # burst is BANDWIDTH*timer resolution (tr is 10ms on i386)

# Load rules
echo "\tRemoving old tree on ${IF}"
# Remove old tree on ${IF}
${TC} qdisc del dev ${IF} root

echo "\tAttaching HTB qdisc to ${IF}"
# Attach a HTB (Hierarchical Token Bucket) Queueing Discipline to ${IF}
${TC} qdisc add dev ${IF} root handle 1: htb default 40

echo "\tAdding classes to HTB qdisc"
# This is the parent and default class inside the HTB hierarchy
${TC} class add dev ${IF} parent 1: classid 1:1 htb \
rate ${BANDWIDTH} ceil ${BANDWIDTH} burst ${BURST}

echo "\tSetting application cap rates"
# These are the capped HTTP and POP3 queues
${TC} class add dev ${IF} parent 1:1 classid 1:10 htb \
rate ${HTTP_CAP} ceil ${BANDWIDTH} burst ${BURST}
${TC} class add dev ${IF} parent 1:1 classid 1:20 htb \
rate ${POP3_CAP} ceil ${BANDWIDTH} burst ${BURST}

# Default queue
${TC} class add dev ${IF} parent 1:1 classid 1:30 htb \
rate 10kbit ceil ${BANDWIDTH} burst ${BURST}

echo "\tSetting up SFQ beneath the queue classes"
# Set SFQ beneath the queue classes; HTB author recommends it!
${TC} qdisc add dev ${IF} parent 1:10 handle 10: sfq perturb 10
${TC} qdisc add dev ${IF} parent 1:20 handle 20: sfq perturb 10
${TC} qdisc add dev ${IF} parent 1:30 handle 30: sfq perturb 10

echo "\tSetting up filters to recognize data"
# These filters grab HTTP and HTTPS by port and put it in the right queue
${TC} filter add dev ${IF} protocol ip parent 1:0 prio 1 \
u32 match ip sport 80 0xffff flowid 1:10
${TC} filter add dev ${IF} protocol ip parent 1:0 prio 1 \
u32 match ip sport 443 0xffff flowid 1:10

# These filters grab POP3 and POP3S by port and put it in the right queue
${TC} filter add dev ${IF} protocol ip parent 1:0 prio 1 \
u32 match ip sport 110 0xffff flowid 1:20
${TC} filter add dev ${IF} protocol ip parent 1:0 prio 1 \
u32 match ip sport 995 0xffff flowid 1:20

echo "\t\vAll done!\n"