NetEM examples of rules

Here are some basic examples of the netem utilisation. There are many more options available which are many more complicated. You can find some details in the tcmanual.pdf attached to this document.

What is a rule ?

A rule is a list of parameters we want to apply to a specific interface / traffic.
TC provide two kinds of features. On one hand : netem, and on the other and : tbf. All netem tools can be associated in the same rules just putting one after the other.

The rule has to be linked to an interface, and to a pipe or classId (see "how to build the tree").

Many examples of rules are giving in following steps

What is a filter ?

  • A filter is the way to specify which kind of traffic is linked to which rule. A lot of complex filters are available. In this tutorial, we are just using IP and port filter on IP protocol. I invite you to read the TC manual provided at the end of this document for more information
  • When you are using a rule with a filter, you also need to create an empty parameters rule which will be applied on other traffic. Otherwise all the traffic will go threw your rule with parameters.
  • Ip filtering just requests the Destination IP, whereas the Port filtering needs a mask which represent the port range on 4 bytes.

A filter on 5000 with ffff just filters on 5000. A fifteen range, with a mask fff0 filters from 5000-8 to 5000+7

How to build the tree

A lot of different ways to build a tree are available.
This one allows us to have unlimited number of rules on our computer

Creation of the root of the tree

tc qdisc add dev eth0 handle 1: root htb

then, we create the default root class which will be used by traffic not concerned by any rules

tc class add dev eth0 parent 1: classid 1:1 htb rate 1000Mbps

Then, we create children classes

tc class add dev eth0 parent 1:1 classid 1:11 htb rate 100Mbps
tc class add dev eth0 parent 1:1 classid 1:12 htb rate 100Mbps
tc class add dev eth0 parent 1:1 classid 1:13 htb rate 100Mbps

now we have to apply rules on each class/pipe


tc qdisc add dev eth0 parent 1:11 handle 10: netem delay 100ms
tc qdisc add dev eth0 parent 1:12 handle 20: netem loss 20% delay 100ms
tc qdisc add dev eth0 parent 1:13 handle 30: tbf rate 20kbit buffer 1600 limit 3000

at the end, we can apply filters

tc filter add dev eth0 protocol ip prio 1 u32 match ip protocol 17 0xff match ip dport 5000 0xffff match ip dst 192.168.1.1 flowid 1:11   ----  IP AND port filter
tc filter add dev eth0 protocol ip prio 1 u32 match ip dst 192.168.1.2 flowid 1:12   --- IP filter
tc filter add dev eth0 protocol ip prio 1 u32 match ip dport 5001 0xffff flowid 1:13   --- Port filter

How to use iperf

Iperf is a network tool to measure a lot of parameters on a link. We are going to use it to know delay, loss, and bandwidth between our nodes.

Basically, for those tests, we just need :

To measure loss => Server side : iperf -s -u -i 1 Client side : iperf -c 192.168.1.2 -u -b 10m

To check bandwidth => Server Side : iperf -s Client Side : iperf -c 192.168.1.2 -r

To measure the delay / latency, we just use ping

Delay, loss, and Netem features.

Delay can be set with 2 values. the first one is the delay itself, and the second one is the variation in the delay. It's written like "netem delay 50ms 20ms"
Loss can also use 2 values : the loss and the loss correlation, written "netem loss 50% 10%"

To use several netem features together, just put them one behind the other like : "netem delay 50ms 5ms loss 20%" ....

  • To check the delay, obviously we're going to use ping.
  • Before any rule was applied, delay looks like :
PING 10.0.1.3 (10.0.1.3): 56 data bytes
64 bytes from 10.0.1.3: icmp_seq=0 ttl=64 time=0.685 ms
64 bytes from 10.0.1.3: icmp_seq=1 ttl=64 time=0.114 ms
64 bytes from 10.0.1.3: icmp_seq=2 ttl=64 time=0.111 ms
64 bytes from 10.0.1.3: icmp_seq=3 ttl=64 time=0.113 ms
64 bytes from 10.0.1.3: icmp_seq=4 ttl=64 time=0.112 ms

Simple rule one the whole interface

tc qdisc add dev eth0 root netem delay 100ms

PING 10.0.1.3 (10.0.1.3): 56 data bytes
64 bytes from 10.0.1.3: icmp_seq=0 ttl=64 time=202.837 ms
64 bytes from 10.0.1.3: icmp_seq=1 ttl=64 time=101.073 ms
64 bytes from 10.0.1.3: icmp_seq=2 ttl=64 time=101.072 ms
64 bytes from 10.0.1.3: icmp_seq=3 ttl=64 time=101.072 ms

PING 10.0.1.4 (10.0.1.4): 56 data bytes
64 bytes from 10.0.1.4: icmp_seq=0 ttl=64 time=202.294 ms
64 bytes from 10.0.1.4: icmp_seq=1 ttl=64 time=101.073 ms
64 bytes from 10.0.1.4: icmp_seq=2 ttl=64 time=101.071 ms
64 bytes from 10.0.1.4: icmp_seq=3 ttl=64 time=101.076 ms

Except for the first request (due to ARP request maybe), one can notice that the delay is modified as required for all destinations

Delay on the whole interface with range

tc qdisc add dev eth0 root netem delay 100ms 20ms

PING 10.0.1.3 (10.0.1.3): 56 data bytes
64 bytes from 10.0.1.3: icmp_seq=4 ttl=64 time=65.083 ms
64 bytes from 10.0.1.3: icmp_seq=5 ttl=64 time=69.081 ms
64 bytes from 10.0.1.3: icmp_seq=6 ttl=64 time=56.086 ms
64 bytes from 10.0.1.3: icmp_seq=7 ttl=64 time=40.092 ms
64 bytes from 10.0.1.3: icmp_seq=8 ttl=64 time=43.090 ms
64 bytes from 10.0.1.3: icmp_seq=9 ttl=64 time=65.082 ms

The range is well seen in this example with a ping of 50ms +-20ms

Different delay on each destination

tc qdisc add dev eth0 handle 1: root htb --- root
tc class add dev eth0 parent 1: classid 1:1 htb rate 100Mbps --- parent class ID. Default way for traffic without rules
tc class add dev eth0 parent 1:1 classid 1:11 htb rate 100Mbps --- first child
tc class add dev eth0 parent 1:1 classid 1:12 htb rate 100Mbps ---second child
tc qdisc add dev eth0 parent 1:11 handle 10: netem delay 25ms 5ms ---rule for the first son
tc qdisc add dev eth0 parent 1:12 handle 20: netem delay 50ms 5ms ---rule for the second one
tc filter add dev eth1 protocol ip parent 1:0 prio 3 u32 match ip dst 192.168.0.97 flowid 1:11 --- filter on the first son
tc filter add dev eth1 protocol ip parent 1:0 prio 3 u32 match ip dst 192.168.0.96 flowid 1:12 --- filter on the 2nd son

PING 10.0.1.3 (10.0.1.3): 56 data bytes
64 bytes from 10.0.1.3: icmp_seq=1 ttl=64 time=21.099 ms
64 bytes from 10.0.1.3: icmp_seq=2 ttl=64 time=21.102 ms
64 bytes from 10.0.1.3: icmp_seq=3 ttl=64 time=24.098 ms
64 bytes from 10.0.1.3: icmp_seq=4 ttl=64 time=30.098 ms
64 bytes from 10.0.1.3: icmp_seq=5 ttl=64 time=21.099 ms

PING 10.0.1.4 (10.0.1.4): 56 data bytes
64 bytes from 10.0.1.4: icmp_seq=1 ttl=64 time=52.089 ms
64 bytes from 10.0.1.4: icmp_seq=2 ttl=64 time=51.090 ms
64 bytes from 10.0.1.4: icmp_seq=3 ttl=64 time=52.094 ms
64 bytes from 10.0.1.4: icmp_seq=4 ttl=64 time=50.089 ms

Differences between our 2 rules are well shown

The way it works is exactly the same for loss and other stuff netem.

Bandwidth management with Tbf

Tbf is a tool used by TC to manage bandwidth. Unfortunately it is not yet implemented in netem, so we don't know how to put tbf and netem stuff in the same rule.

  • To check the bandwidth, we are going to use iperf on both sides (client & server) :
  • Before any rule was applied, bandwidth looks like :
[  5] local 10.0.1.2 port 38289 connected with 10.0.1.3 port 5001

[ ID] Interval       Transfer     Bandwidth
[  5]  0.0-10.1 sec    114 MBytes  95.5 Mbits/sec

Debit limitation on the whole interface

tc qdisc add dev eth1 root tbf rate 20kbit buffer 1600 limit 3000

[  5] local 10.0.1.2 port 51521 connected with 10.0.1.3 port 5001

[ ID] Interval       Transfer     Bandwidth
[  5]  0.0-14.3 sec  40.0 KBytes  23.0 Kbits/sec

Debit limitation on a precise port (5000)-

...
tc qdisc add dev eth0 parent 1:11 handle 10: tbf rate 20kbit buffer 1600 limit 3000
tc filter add dev eth0 protocol ip parent 1:0 prio 3 u32 match ip dport 5000 0xfff flowid 1:11

[  5] local 10.0.1.2 port 53062 connected with 10.0.1.3 port 5001

[ ID] Interval       Transfer     Bandwidth
[  5]  0.0-10.0 sec    114 MBytes  95.5 Mbits/sec
[  5] local 10.0.1.2 port 36934 connected with 10.0.1.3 port 5000

[ ID] Interval       Transfer     Bandwidth
[  5]  0.0-13.4 sec  40.0 KBytes  24.4 Kbits/sec

One can see that the bandwidth limitation is only applied on our parameter

Netem and tbf applied on the same traffic

Netem and TBF cannot be put together in a rule.

The solution is to extend the tree so as to create a new branch linked to the same class. This branch is going to receive the second parameter.

the tree is built the same way as before

tc qdisc add dev eth0 handle 1: root htb
tc class add dev eth0 parent 1: classid 1:1 htb rate 1000Mbps
tc class add dev eth0 parent 1:1 classid 1:11 htb rate 1000Mbps

now we have to apply rules on each class/pipe

tc qdisc add dev eth0 parent 1:11 handle 10: netem delay 100ms
tc qdisc add dev eth0 parent 10:1 handle 101: tbf rate 20kbit buffer 16000 limit 30000

at the end, we can apply filters

tc filter add dev eth0 protocol ip prio 1 u32 match ip protocol 17 0xff match ip dport 5000 0xffff match ip dst 192.168.1.1 flowid 1:11