# Traffic shaping with tc

## l_bratch

I'm currently using the following script:

```
tc qdisc add dev eth0 root handle 1: htb default 10

tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit

tc class add dev eth0 parent 1:1 classid 1:10 htb rate 100mbit prio 1

tc class add dev eth0 parent 1:1 classid 1:20 htb rate 200kbit prio 2

tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10

tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10

tc filter add dev eth0 parent 1: protocol ip u32 match ip dst 192.168.0.2 flowid 1:10

tc filter add dev eth0 parent 1: protocol ip u32 match ip dst 192.168.0.3 flowid 1:20

tc filter add dev eth0 parent 1: protocol ip u32 match ip dst 192.168.0.16 flowid 1:20

tc filter add dev eth0 parent 1: protocol ip u32 match ip dst 192.168.0.17 flowid 1:20

tc filter add dev eth0 parent 1: protocol ip u32 match ip dst 192.168.0.61 flowid 1:20
```

Which is modified from here https://forums.gentoo.org/viewtopic-t-225863-highlight-shaping.html.

What I have is the following setup:

192.168.0.34 which has an ADSL connection on ppp0, and shares it through eth0 to the other clients (listed in the above script).

The ADSL connection is a 1024 kbit/s down and 384 kbit/s up line.

I want 192.168.0.2 to get priority with all traffic, so if it wants to download at 100 kB/s (the approximate maximum the line can do), it can do that when no other clients are using the connection.

With my current script this happens, and the other clients are limited at 25 kB/s (200 kbit/s).  When the other clients are downloading at their full 25 kB/s, 192.168.0.2 gets approximately 75 kB/s download speeds.

However I want to change the script to acheive the following:

Any single client gets 100 kB/s if none others are using the line, but if 192.168.0.2 tries to download, it gets priority so that the other clients drop to a combined total of around 20 kB/s, giving 192.168.0.2 around 80 kB/s.

I hope that was clear enough.  How can I do this?

----------

## frostschutz

The way you've done it is wrong. You have a 100mbit root class, with a 100mbit child class (thus all available bandwidth is already accounted for), and add a 200kbit class on top of that. This means your root class is over-allocated, the result is unpredictable. Having the child class rates add up to the parent class rate is one of the main rules when building HTB trees.

What you need, is:

- a 100mbit class if you have LAN traffic going over the device (shell access to the router etc)

This class needs to have at least two children: a 1024kbit class for Internet traffic, and a TOTAL-1024kbit class for LAN traffic.

Now you want to prioritize clients. No problem, create child classes for them. Since you want to group the classes (one group that can use 80%, another that can use 20% of bandwidth), create a child class for each group with the according settings.

Now you're pretty much done. Put the 192.168.0.2 traffic into the 80% class, and the others in the 20% class.

----------

## l_bratch

Thanks for the reply, the first bit is now looking like this:

```
tc qdisc add dev eth0 root handle 1: htb default 10

tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit

tc class add dev eth0 parent 1:1 classid 1:10 htb rate 1024kbit prio 1

tc class add dev eth0 parent 1:1 classid 1:20 htb rate 101376kbit prio 2

tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10

tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10
```

I think this is right so far?

However you mention creating further child classes for the prioritizing of clients - how can I create these when I've already maxed out out the size of the root class with child classes?

----------

## l_bratch

I've taken a completely different approach, which is now looking something like this:

```
tc qdisc add dev eth0 root handle 1: htb default 10

tc class add dev eth0 parent 1: classid 1:1 htb rate 800kbps ceil 800kbps burst 2k

tc class add dev eth0 parent 1:1 classid 1:10 htb rate 720kbps ceil 800kbps burst 2k prio 0

tc class add dev eth0 parent 1:1 classid 1:11 htb rate 80kbps ceil 800kbps burst 2k prio 1

tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10

tc qdisc add dev eth0 parent 1:11 handle 11: sfq perturb 10

tc filter add dev eth0 parent 1: protocol ip u32 match ip dst 192.168.0.2 flowid 1:10

tc filter add dev eth0 parent 1: protocol ip u32 match ip dst 192.168.0.4 flowid 1:11

tc filter add dev eth0 parent 1: protocol ip u32 match ip dst 192.168.0.16 flowid 1:11

tc filter add dev eth0 parent 1: protocol ip u32 match ip dst 192.168.0.17 flowid 1:11

tc filter add dev eth0 parent 1: protocol ip u32 match ip dst 192.168.0.61 flowid 1:11
```

But this is working as I expected.  I'm testing by downloading large files on 192.168.0.2 and 192.168.0.4, but they both end up getting about 50 kB/s.  Even though I'd expect 192.168.0.2 to get 90kB/s, and 192.168.0.4 to get 10kB/s.

Any idea?  I'm struggling with this (new to it)

----------

## plut0

I think you guys are confusing kilobits with kibits.  1mbit = 1000kbit

http://en.wikipedia.org/wiki/Kbit/s

The sum of the childs bandwidth should not be more than the parents bandwidth.  I suggest looking into the Token Bucket Filter (TBF) algorithm for best throttling results.

 *Quote:*   

> TBF is very precise, network- and processor friendly. It should be your first choice if you simply want to slow an interface down!

 

http://lartc.org/howto/lartc.qdisc.classless.html#AEN691

----------

## l_bratch

 *plut0 wrote:*   

> I think you guys are confusing kilobits with kibits.  1mbit = 1000kbit
> 
> http://en.wikipedia.org/wiki/Kbit/s

 But tc defines mbit kbit and such like so:

http://lartc.org/howto/lartc.qdisc.html

 *Quote:*   

> The sum of the childs bandwidth should not be more than the parents bandwidth.

 

I realise that now, but am not doing that in my last example am I?

 *Quote:*   

> I suggest looking into the Token Bucket Filter (TBF) algorithm for best throttling results.
> 
>  *Quote:*   TBF is very precise, network- and processor friendly. It should be your first choice if you simply want to slow an interface down! 
> 
> http://lartc.org/howto/lartc.qdisc.classless.html#AEN691

 

Thanks for the tip - I'm looking into that now.  Can it prioritize like I'm trying to do though?

Edit:

It doesn't seem like TBF can give priority to different clients like I need.

----------

## l_bratch

Well I finally got it working.  :Very Happy: 

I kept rereading your post frostschutz until the obvious dawned on me - the classes weren't limitting the bandwidth because they usage never went over the defined bandwidth of 100Mbit.  So I now have the following script:

```
#!/bin/bash

# Clear

tc qdisc del dev eth0 root    # Clear any previous stuff

# Shaping

## Setup

tc qdisc add dev eth0 root handle 1: htb default 10

tc class add dev eth0 parent 1: classid 1:1 htb rate 800kbit ceil 100mbit    # Set the max speed allowed to be 800 kbit/s

tc class add dev eth0 parent 1:1 classid 1:10 htb rate 200kbit ceil 100mbit prio 0    # Limit to 200 kbit/s by default, by go up to 100mbit/s when not under load

tc class add dev eth0 parent 1:1 classid 1:20 htb rate 100mbit ceil 100mbit prio 1    # Seperate class for specified IPs - rate ignores default max speed

## Filters

tc filter add dev eth0 parent 1: protocol ip u32 match ip dst 192.168.0.2 flowid 1:20    # This machine should always get priority with the bandwidth

tc filter add dev eth0 parent 1: protocol ip u32 match ip src 192.168.0.34 flowid 1:20    # Made sure LAN traffic - anything originating from the local machine (192.168.0.34) - isn't limited at all
```

Thanks for your help.

----------

## plut0

For communcation systems 1mbit = 1000kbit.  The example you posted is the conversion tc uses for rate, which may be correct.  Heres a quick example to demonstrate what I am talking about:

```
# tc qdisc add dev eth0 handle 1: root htb default 50

# tc class add dev eth0 parent 1: classid 1:1 htb rate 1mbit ceil 1gbit

# tc class show dev eth0

class htb 1:1 root prio 0 rate 1000Kbit ceil 1000Mbit burst 2849b cburst

1251250b

```

You will notice it converted 1mbit to 1000Kbit and 1gbit to 1000Mbit.  Keep this in mind when calculating bandwidth.

 *Quote:*   

> It doesn't seem like TBF can give priority to different clients like I need.

 

The classful queue HTB gives you priorities, you want to continue using this.  However, try using TBF instead of SFQ for your classless queue.

----------

## frostschutz

I'm sorry, but your setup is still wrong.

```
tc class add dev eth0 parent 1: classid 1:1 htb rate 800kbit ceil 100mbit    # Set the max speed allowed to be 800 kbit/s
```

The qdisc has unlimited bandwidth. A root class with a ceil of 100mbit is not limited by anything, so this is effectively a 100mbit class.

```
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 200kbit ceil 100mbit prio 0    # Limit to 200 kbit/s by default, by go up to 100mbit/s when not under load

tc class add dev eth0 parent 1:1 classid 1:20 htb rate 100mbit ceil 100mbit prio 1    # Seperate class for specified IPs - rate ignores default max speed
```

Now you're adding a 200kbit and a 100mbit child class to the (supposedly) 800kbit class of yours. Results are random at best.

In my first reply I was thinking more of a tree like class structure like this:

```

HTB qdisc (unlimited)

|

\--- HTB root class (100mbit)

     |

     \--- HTB local class (100mbit minus 1000kbit)

     \--- HTB internet class (1000kbit)

          |

          \--- HTB internet group A (800kbit:1000kbit)

          \--- HTB internet group B (200kbit:1000kbit)

               |

               \--- ...

```

Sum of the child class rates must equal the parent class rate. In this example, local + internet = root class rate, group A + group B = internet class rate and so on.

----------

