Linux QoS Configuration Using TC
In this Document we will go through QoS configuration example using Linux Traffic Control (TC).
Required Linux Modules
root@dent-1:/usr/src/linux-5.16.9# lsmod
Module Size Used by
sch_htb 36864 1
QoS Configuration Example
The requirement in this example as follows:
PC1
should have 100 mbps upload speed to the Server.PC2
should have 75 mbps upload speed to the Server.PC3
should have 25 mbps upload speed to the Server.
We will use Hierarchy Token Bucket (HTB) classfull QDISC, this classful QDISC allows us to create different classes with different speed limits and attach them to the same interface's QDISC.
Topology
Configuration
Configuration steps:
- Create
HTB QDISC
on linkenp0s12
with handle-id8003:
. - Create 3 child
Classes
for that QDISC with:- classid
8003:1
with rate limit =100mbps
. - classid
8003:2
with rate limit =75mbps
. - classid
8003:1
with rate limit =25mbps
.
- classid
- Create a
Flower
Filter for theQDISC
with three rules to classify the traffic:Rule 10
that matchPC1
ip (192.168.1.1/32) and set the classid to8003:1
.Rule 20
that matchPC2
ip (192.168.1.2/32) and set the classid to8003:2
.Rule 30
that matchPC3
ip (192.168.1.3/32) and set the classid to8003:3
.
In this Example we attached the three classes directly to the QDISC
, however we can create a Top-Level parent
class to limit the overall speed of the link to 200, and then create child class of that parent class,
and each class will have its own limit, also it's recommended to set the overall limit to a value less than the
interface speed to make sure that to keep the enqueueing in the QDISC level instead of interface HW level.
- ONM-CLI
- IPROUTE2
- NETCONF
qdiscs-iproute2
qdisc enp0s12 root
handle 8003:
qdisc-kind htb
exit
exit
classes-iproute2
class enp0s12 8003: 8003:1
qdisc-options htb rate 100mbit
exit
class enp0s12 8003: 8003:2
qdisc-options htb rate 75mbit
exit
class enp0s12 8003: 8003:3
qdisc-options htb rate 25mbit
exit
exit
tc-filters-iproute2
qdisc-filter enp0s12 8003:
rule 10
filter flower match src_ip 192.168.1.1/32
filter flower classid 8003:1
exit
rule 20
filter flower match src_ip 192.168.1.2/32
filter flower classid 8003:2
exit
rule 30
filter flower match src_ip 192.168.1.3/32
filter flower classid 8003:3
exit
exit
tc qdisc replace dev enp0s12 parent root handle 8003: htb
tc class add dev enp0s12 parent 8003: classid 8003:1 htb prio 0 rate 100mbit
tc class add dev enp0s12 parent 8003: classid 8003:2 htb prio 0 rate 75mbit
tc class add dev enp0s12 parent 8003: classid 8003:3 htb prio 0 rate 25mbit
tc filter add dev enp0s12 parent 8003: pref 10 protocol ip handle 0x1 flower src_ip 192.168.1.1/32 classid 8003:1
tc filter add dev enp0s12 parent 8003: pref 20 protocol ip handle 0x1 flower src_ip 192.168.1.2/32 classid 8003:2
tc filter add dev enp0s12 parent 8003: pref 30 protocol ip handle 0x1 flower src_ip 192.168.1.3/32 classid 8003:3
<config>
<tc-filters>
<qdisc-filter>
<dev>enp0s12</dev>
<parent>8003:</parent>
<netns>1</netns>
<rule>
<pref>10</pref>
<flower>
<match>
<src_ip>192.168.1.1/32</src_ip>
</match>
<classid>8003:1</classid>
</flower>
</rule>
<rule>
<pref>20</pref>
<flower>
<match>
<src_ip>192.168.1.2/32</src_ip>
</match>
<classid>8003:2</classid>
</flower>
</rule>
<rule>
<pref>30</pref>
<flower>
<match>
<src_ip>192.168.1.3/32</src_ip>
</match>
<classid>8003:3</classid>
</flower>
</rule>
</qdisc-filter>
</tc-filters>
<qdiscs>
<qdisc>
<dev>enp0s12</dev>
<parent>root</parent>
<netns>1</netns>
<handle>8003:</handle>
<qdisc-kind>htb</qdisc-kind>
</qdisc>
</qdiscs>
<classes>
<class>
<dev>enp0s12</dev>
<parent>8003:</parent>
<classid>8003:1</classid>
<netns>1</netns>
<htb>
<rate>100mbit</rate>
</htb>
</class>
<class>
<dev>enp0s12</dev>
<parent>8003:</parent>
<classid>8003:2</classid>
<netns>1</netns>
<htb>
<rate>75mbit</rate>
</htb>
</class>
<class>
<dev>enp0s12</dev>
<parent>8003:</parent>
<classid>8003:3</classid>
<netns>1</netns>
<htb>
<rate>25mbit</rate>
</htb>
</class>
</classes>
</config>
There are other parameters in the classes that we can use to control the traffic flow like:
- priority: to give different enqueue priorities.
- ceil: Maximum rate at which a class can send, if its parent has bandwidth to spare. Defaults to the configured rate, which implies no borrowing
- burst: Amount of bytes that can be burst at ceil speed, in excess of the configured rate. Should be at least as high as the highest burst of all children.
Verify
We will test the speed using iperf3
with the server (192.168.1.10) as iperf server.
Before the QoS config, all three PCs have around 200+mbps upload speed.
PC3
rate before the Config:
root@PC3:~# iperf3 -c 192.168.1.10
Connecting to host 192.168.1.10, port 5201
[ 5] local 192.168.1.3 port 41860 connected to 192.168.1.10 port 5201
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 261 MBytes 219 Mbits/sec 314 sender
[ 5] 0.00-10.04 sec 259 MBytes 216 Mbits/sec receiver
PC3
after the QoS config:
root@PC3:~# iperf3 -c 192.168.1.10
Connecting to host 192.168.1.10, port 5201
[ 5] local 192.168.1.3 port 58770 connected to 192.168.1.10 port 5201
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 29.9 MBytes 25.0 Mbits/sec 0 sender
[ 5] 0.00-10.56 sec 28.8 MBytes 22.9 Mbits/sec receiver
PC2
after QoS config:
root@PC2:~# iperf3 -c 192.168.1.10
Connecting to host 192.168.1.10, port 5201
[ 5] local 192.168.1.2 port 52900 connected to 192.168.1.10 port 5201
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 88.0 MBytes 73.9 Mbits/sec 691 sender
[ 5] 0.00-10.18 sec 85.6 MBytes 70.6 Mbits/sec receiver
PC1
after QoS:
root@PC1:~# iperf3 -c 192.168.1.10
Connecting to host 192.168.1.10, port 5201
[ 5] local 192.168.1.1 port 38994 connected to 192.168.1.10 port 5201
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 114 MBytes 95.4 Mbits/sec 1068 sender
[ 5] 0.00-10.19 sec 112 MBytes 91.9 Mbits/sec receiver
To have more accurate rate limiting it's recommended to create top-level Class with the overall rate limit,
and then attach the child classes to the top-level class instead of attaching them directly to the QDISC
.
Troubleshooting
- We can check the class statistics to check the drops and over limits:
root@dent-1:~# tc -s class show dev enp0s12
class htb 8003:10 root prio 0 rate 100Mbit ceil 100Mbit burst 1600b cburst 1600b
Sent 122884864 bytes 81193 pkt (dropped 0, overlimits 10886 requeues 0)
backlog 0b 0p requeues 0
lended: 11101 borrowed: 0 giants: 0
tokens: 1917 ctokens: 1917
class htb 8003:20 root prio 0 rate 75Mbit ceil 75Mbit burst 1584b cburst 1584b
Sent 190621351 bytes 125948 pkt (dropped 0, overlimits 17333 requeues 0)
backlog 0b 0p requeues 0
lended: 17495 borrowed: 0 giants: 0
tokens: 2546 ctokens: 2546
class htb 8003:30 root prio 0 rate 25Mbit ceil 25Mbit burst 1600b cburst 1600b
Sent 33907347 bytes 22418 pkt (dropped 0, overlimits 6864 requeues 0)
backlog 0b 0p requeues 0
lended: 6893 borrowed: 0 giants: 0
tokens: 7670 ctokens: 7670