⬆️ ⬇️

Shaping traffic to Linux. Part 2

The second part of the article about managing traffic in Linux. The article provides examples of traffic prioritization (QoS) and discusses the use of hash tables when filtering traffic (fast hash tables), the use of which can significantly increase performance.

In the first part, we stopped at generating configs of average complexity for htbinit. Today we will talk about prioritizing traffic and using hash tables in filters. I mean, you read the first part of the article.

Suppose we are tired of user comments about high ping, tired of the constant children's cries on the forum that it is impossible to play counter-strike: “terrible lags”, or “my pages are loading slowly, vkontakte opened 10 minutes”, and writing that All measurements need to be made when the "torrent" is disabled.

Therefore, our conscience would be clear, and we couldn’t say without a doubt: “the problem is on the side of the provider providing this service” (designate the direction of movement towards the south pole) - let's take care of traffic prioritization.



Priorities set in this order:

1. icmp

2. udp

3. tcp port 80

4. bulk traffic



Consider the restriction of the band on the internal interface, we will manage the "download speed"

I will remind you.

In a simple form of presentation, the traffic cutting algorithm looks like this:

1. Create a root discipline for the interface and specify the class where the unclassified traffic will fall.

2. Create a root class and determine the width of the channel.

3. Create a child class for subscriber shaping.

4. Create a shaping discipline for the subscriber class.

5. Create a filter to classify subscriber traffic.

')

Example

#!/bin/bash



# "" eht1

/sbin/tc qdisc del dev eth1 root handle 1: htb default 15

#

/sbin/tc qdisc add dev eth1 root handle 1: htb default 15

#

/sbin/tc class add dev eth1 parent 1: classid 1:1 htb rate 10Mbit ceil 10Mbit



#

/sbin/tc class add dev eth1 parent 1:1 classid 1:10 htb rate 512kbit ceil 512kbit



# 4

/sbin/tc class add dev eth1 parent 1:10 classid 1:11 htb rate 1kbit ceil 512kbit prio 1

/sbin/tc class add dev eth1 parent 1:10 classid 1:12 htb rate 1kbit ceil 512kbit prio 2

/sbin/tc class add dev eth1 parent 1:10 classid 1:13 htb rate 1kbit ceil 512kbit prio 3

/sbin/tc class add dev eth1 parent 1:10 classid 1:14 htb rate 1kbit ceil 512kbit prio 4



#

/sbin/tc qdisc add dev eth1 parent 1:11 handle 11: sfq perturb 10

/sbin/tc qdisc add dev eth1 parent 1:12 handle 12: sfq perturb 10

/sbin/tc qdisc add dev eth1 parent 1:13 handle 13: sfq perturb 10

/sbin/tc qdisc add dev eth1 parent 1:14 handle 14: sfq perturb 10



4 ,

/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 1 u32 match ip dst 192.168.2.2/32 match ip protocol 1 0xff flowid 1:11

/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 2 u32 match ip dst 192.168.2.2/32 match ip protocol 17 0xff flowid 1:12

/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 3 u32 match ip dst 192.168.2.2/32 match ip protocol 6 0xff match ip sport 80 0xffff flowid 1:13

/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 4 u32 match ip dst 192.168.2.2/32 flowid 1:14




* This source code was highlighted with Source Code Highlighter .




I think from the example that for the implementation of prioritizing traffic, we have created a separate class for each. Next, create filters, and the smaller the prio, the greater the priority of traffic. In general, the rules are processed according to how they were added, in the case of priorities, the rules with the highest priority are served first.

You can also give each class a RATE equal to one-fourth of the RATE of the client's root class, which is already certain.

I want to draw attention to the fact that we had to create 4 filters, for that, ip, and if ip is 3-4 thousand, then we will get a huge linear list of rules - as a result, the performance will fall below the baseboard.

To avoid this, we use “fast” hash tables.

About what a hash table you can look at Wikipedia.

Create 4 tables of 256 cells, each of the tables will evaluate one of the octets of the un address.

And ultimately, instead of searching the entire list, as it would have been in the classic version, we will reduce the number of checks and significantly reduce the load.

Example.

#

/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32

# 4

/sbin/tc filter add dev eth1 parent 1:0 handle 10: protocol ip u32 divisor 256

/sbin/tc filter add dev eth1 parent 1:0 handle 11: protocol ip u32 divisor 256

/sbin/tc filter add dev eth1 parent 1:0 handle 12: protocol ip u32 divisor 256

/sbin/tc filter add dev eth1 parent 1:0 handle 13: protocol ip u32 divisor 256

# ID 10

/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 801:: match ip dst 0.0.0.0/0 hashkey mask 0xff000000 at 16 link 10:

# 10 , 192, 11

/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 10:c0: match ip dst 192.0.0.0/8 hashkey mask 0xff0000 at 16 link 11:

# 11 , 168, 12

/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 11:a8: match ip dst 192.168.0.0/16 hashkey mask 0xff00 at 16 link 12:

# 12 , 2, 13

/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 12:2: match ip dst 192.168.2.0/24 hashkey mask 0xff at 16 link 13:



# 13 , 4 ,

/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 1 u32 ht 13:2: match ip dst 192.168.2.2/32 match ip protocol 1 0xff flowid 1:11

/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 2 u32 ht 13:2: match ip dst 192.168.2.2/32 match ip protocol 17 0xff flowid 1:12

/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 3 u32 ht 13:2: match ip dst 192.168.2.2/32 match ip protocol 6 0xff match ip sport 80 0xffff flowid 1:13

/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 4 u32 ht 13:2: match ip dst 192.168.2.2/32 flowid 1:14




* This source code was highlighted with Source Code Highlighter .


Below is a listing of the violin-generating rules for tc including prioritization and hash filters.

The creak is fully working, I think it will not be difficult to modify it for yourself.

When switching from linear filters to the table hash, the load dropped almost 4 times.

#!/bin/bash

mysql= "mysql -ppass -u user -h host"

# , ,

echo "select ext_iface from system.shaper_view group by ext_iface;" |$mysql|sed 1d|

awk '{

print "/sbin/tc qdisc del dev "$1" root handle 1: htb default 15";

print "/sbin/tc qdisc add dev "$1" root handle 1: htb default 15";

print "/sbin/tc class add dev "$1" parent 1: classid 1:1 htb rate 10Mbit ceil 10Mbit";

print "/sbin/tc filter add dev "$1" parent 1:1 prio 10 protocol ip u32";

print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32";

print "/sbin/tc filter add dev "$1" parent 1:0 handle 10: protocol ip u32 divisor 256";

print "/sbin/tc filter add dev "$1" parent 1:0 handle 11: protocol ip u32 divisor 256";

print "/sbin/tc filter add dev "$1" parent 1:0 handle 12: protocol ip u32 divisor 256";

print "/sbin/tc filter add dev "$1" parent 1:0 handle 13: protocol ip u32 divisor 256";

print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32 ht 801:: match ip dst 0.0.0.0/0 hashkey mask 0xff000000 at 16 link 10:";

}'


# , ,

echo "select int_iface from system.shaper_view group by int_iface;" |$mysql|sed 1d|

awk '{

print "/sbin/tc qdisc del dev "$1" root handle 1: htb default 15";

print "/sbin/tc qdisc add dev "$1" root handle 1: htb default 15";

print "/sbin/tc class add dev "$1" parent 1: classid 1:1 htb rate 10Mbit ceil 10Mbit";

print "/sbin/tc filter add dev "$1" parent 1:1 prio 10 protocol ip u32";

print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32";

print "/sbin/tc filter add dev "$1" parent 1:0 handle 10: protocol ip u32 divisor 256";

print "/sbin/tc filter add dev "$1" parent 1:0 handle 11: protocol ip u32 divisor 256";

print "/sbin/tc filter add dev "$1" parent 1:0 handle 12: protocol ip u32 divisor 256";

print "/sbin/tc filter add dev "$1" parent 1:0 handle 13: protocol ip u32 divisor 256";

print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32 ht 801:: match ip src 0.0.0.0/0 hashkey mask 0xff000000 at 12 link 10:";

}'




# , ,

echo "select user_id,ip,speed,int_iface,ext_iface from system.shaper_view order by user_id;" |$mysql|sed 1d|

awk '

BEGIN{

buf=0;

class_id=255;

tc_class="/sbin/tc class add dev";

tc_qdisc="/sbin/tc qdisc add dev";

tc_filter="/sbin/tc filter add dev";

}

{

if(buf!=$1)

{

printf "%s%x%s\n", "# ",class_id," "class_id" "$2;

client_speed=$3*128;

printf "%s%x%s\n",tc_class" "$4" parent 1:1 classid 1:",++class_id," htb rate "client_speed"bps ceil "client_speed"bps";

printf "%s%x%s\n",tc_class" "$5" parent 1:1 classid 1:",class_id," htb rate "client_speed"bps ceil "client_speed"bps";

client_class=class_id;

printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 1";

printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 1";

printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";

printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";

printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 2";

printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 2";

printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";

printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";

printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 3";

printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 3";

printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";

printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";

printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 4";

printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 4";

printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";

printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";

}

split($2,ip,".");

if (ht_1[ip[1]]!=1)

{

printf "%s%x%s\n",tc_filter" "$4" parent 1:0 protocol ip u32 ht 10:",ip[1],": match ip dst "ip[1]".0.0.0/8 hashkey mask 0xff0000 at 16 link 11:";

printf "%s%x%s\n",tc_filter" "$5" parent 1:0 protocol ip u32 ht 10:",ip[1],": match ip src "ip[1]".0.0.0/8 hashkey mask 0xff0000 at 12 link 11:";

ht_1[ip[1]]=1;

}

if (ht_2[ip[2]]!=1)

{

printf "%s%x%s\n",tc_filter" "$4" parent 1:0 protocol ip u32 ht 11:",ip[2],": match ip dst "ip[1]"."ip[2]".0.0/16 hashkey mask 0xff00 at 16 link 12:";

printf "%s%x%s\n",tc_filter" "$5" parent 1:0 protocol ip u32 ht 11:",ip[2],": match ip src "ip[1]"."ip[2]".0.0/16 hashkey mask 0xff00 at 12 link 12:";

ht_2[ip[2]]=1;

}

if (ht_3[ip[3]]!=1)

{

printf "%s%x%s\n",tc_filter" "$4" parent 1:0 protocol ip u32 ht 12:",ip[3],": match ip dst "ip[1]"."ip[2]"."ip[3]".0/24 hashkey mask 0xff at 16 link 13:";

printf "%s%x%s\n",tc_filter" "$5" parent 1:0 protocol ip u32 ht 12:",ip[3],": match ip src "ip[1]"."ip[2]"."ip[3]".0/24 hashkey mask 0xff at 12 link 13:";

ht_3[ip[3]]=1;

}

printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 1 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 match ip protocol 1 0xff flowid 1:",client_class

printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 1 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 match ip protocol 1 0xff flowid 1:",client_class

printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 2 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 match ip protocol 17 0xff flowid 1:",++client_class

printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 2 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 match ip protocol 17 0xff flowid 1:",client_class

printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 3 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 match ip protocol 6 0xff match ip sport 80 0xffff flowid 1:",++client_class

printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 3 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 match ip protocol 6 0xff match ip dport 80 0xffff flowid 1:",client_class

printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 4 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 flowid 1:",++client_class

printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 4 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 flowid 1:",client_class

buf=$1;

}'


* This source code was highlighted with Source Code Highlighter .


I hope this opus helped you understand the basics of traffic management in Linux.

Source: https://habr.com/ru/post/89002/



All Articles