Combing traffic - dynamic shaper on Linux
Suppose you have a home network (or not a home network, but a network of a small office) with Internet access through a not very high-speed channel. And there are a lot of users, and everyone wants to download something, but with maximum speed. Here we are faced with the task of how to distribute our Internet channel between users as efficiently as possible so that they do not interfere with each other. In this article I will describe how you can solve such a problem using a Linux server.
Let us formulate what we want to get as a result:
1. So that the channel is equally divided between users.
2. That the channel was not idle in vain.
3. So that online games, ssh and telnet do not “lag” even when the channel is fully loaded, for example, torrents.
If the Internet will be used by 10 users at the same time, everyone will have at their disposal 1/10 of the channel, if only one user is currently active, he will use the entire channel himself.
This can be achieved using the HTB package scheduler , which has been included in the linux kernel since version 2.4.20.
You can configure the shaper using the tc command, but for a more convenient and intuitive setup, I recommend downloading the htb.init script . They use a set of configuration files for htb configuration, so named that when sorting alphabetically, their names allow you to visually imagine the tree of shaper classes and conveniently edit it.
Suppose that we have a server on the server eth0 interface through which we are connected to the Internet, and eth1, which "looks" in the local network.
You can only control traffic coming from the interface, so for eth0 there will be rules for uploading user traffic, and for - eth1 there will be download traffic.
By default, the htb.init configuration files are located in / etc / htb /. To begin, we will write the shaping rules for upload traffic, we will have them simple.
We create a file with the name eth0 (the “watching” Internet interface), we will write the following lines into it:
DEFAULT=20
R2Q=1
The DEFAULT parameter sets the class number to which traffic will be assigned by default - usually this is the class with the lowest priority. The R2Q parameter affects the operation of the channel separation algorithm and depends on the channel width. I selected its value empirically, for my outgoing channel in 2 Mbit.
Next, create the eth0-2.full2MBit file for the class that includes all the available Internet feed. The file name consists of the interface name and class id, after the point there is a semantic name of the class, it is used as a comment and is ignored by the system. RATE is our guaranteed band, CEIL is the maximum band. Since I have a channel with a guaranteed maximum bandwidth of 2 Mbit, then these parameters are equal for me.
RATE=2Mbit
CEIL=2Mbit
Now we will create one file for each traffic class that we will have. I myself created separate classes for ssh traffic, as well as World Of Warcraft and Counter Strike games traffic, although you can make one class for all high-priority traffic.
An example for ssh is to create an eth0-2 file : 10.ssh . The colon name contains the id of the parent class 2 and the id of the current class is 10. The identifiers for the class can be chosen arbitrarily.
# class for outgoing ssh
RATE=128Kbit
CEIL=2Mbit
RULE=*:22
PRIO=1
BURST=100Kb
The RATE parameter specifies the guaranteed band for this class, in CEIL - the maximum. We allocate 128 KBit for ssh (at least) and allow it to download the entire channel (I upload files via sftp). PRIO sets the priority of the traffic class (1 - maximum, the higher the number - the lower the priority). BURST sets the maximum amount of traffic that will be transmitted at maximum speed before proceeding with the transfer of data from other classes. By setting this parameter to a sufficiently high value, we achieve that ssh traffic will be transmitted with minimal delay.
RULE sets the rule by which traffic to this class will be selected.
The format is RULE = [[saddr [/ prefix]] [: port [/ mask]],] [daddr [/ prefix]] [: port [/ mask]]
Pay attention to the comma! RULE = *: 22 denotes traffic with a destination port of 22, and RULE = *: 22 denotes traffic with an outgoing port of 22.
We also create classes for other types of traffic, and a class for “default” traffic with id 20 (we indicated at the beginning that it is in class number 20 that traffic should be directed “by default”). In it, we indicate the used channel separation discipline LEAF = sfq, so that upload is equally divided between TCP sessions of different users.
For eth1, the rules will be almost the same, only taking into account that the total channel width is 100 Mbit, because we want to be able to access the local resources of the server at full speed, a separate class of 2 MBit is allocated for Internet traffic, with children added as descendants classes of individual users, the division into classes I did by IP addresses. For each user, you can specify the maximum and guaranteed speed, as well as priority.
After editing the configuration, restart htb.init:
/etc/init.d/htb.init restart
And the traffic shaping rules immediately take effect.
During the process of composing the rules, it is usually necessary to visualize the traffic somehow, for debugging and monitoring purposes, so I decided to write a plugin for the munin server monitoring system that would visualize the distribution of the HTB traffic classes. I decided to display loading only leaf classes of the tree, since they usually carry the semantic load.
You can download the plugin from the official munin plugin repository, it is called qos_ , just copy it to the plugins folder munin / usr / share / munin / plugins / and in the plugins folder used / etc / munin / plugins make a symbolic link to it like qos_eth1, where eth1 is the name of the interface on which to monitor the load.
In the plugin configuration file, you can add the following:
[qos_eth1]
env.ignore_queue1_10 yes
env.label_name1_31 Viperet
env.label_name1_32 Cornet
The env.ignore_queue parameter allows not displaying the class state with the specified id on the graph, and the env.label_name parameter allows specifying a human-readable label for the class on the graph.
The result should be something like this:
I want to note that I have a somewhat atypical situation, two Internet channels of 2 and 1 Mbit, and for each user there is a 2 Mbit download speed limit, so the graph shows that if one user is active, his speed is cut by 2 Mbit, and if several - the total speed can reach three. More than 20 people work on such a rather “tight” channel, and they feel quite comfortable without interfering with each other.
This picture is from a real server, and it is updated every 5 minutes and displays the current picture of the channel loading.
UPD: posted an example htb.init config