
Suppose you have a home network (or not a home network, but a small office network) 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 face the task of how to distribute our Internet channel as efficiently as possible among users so that they do not interfere with each other. In this article I will describe how this problem can be solved using a Linux server.
We formulate what we want to get as a result:
1. To share the channel equally between users.
2. To channel in vain not idle.
3. So that online games, ssh and telnet do not “lag” even when the channel is fully loaded, for example, torrents.
If 10 users use the Internet at the same time, each will receive 1/10 of the channel, if only one user is active at the moment, he will use the entire channel himself.
This can be achieved using the
HTB package scheduler, which is 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 configuring htb, so that when sorting alphabetically, their names allow you to visually imagine the tree of the shaper classes and conveniently edit it.
Suppose that on our server there is an interface eth0, through which we are connected to the Internet, and eth1, which “looks” to the local network.
')
You can control only outgoing traffic from the interface, so for eth0 there will be rules for uploading user traffic, and for - eth1 - download traffic.
By default, the htb.init configuration files are in / etc / htb /. To begin with, we will write the rules of shaping for upload traffic, we will have them simple.
Create a file with the name
eth0 (“looking” on the Internet), we will write the following lines to it:
DEFAULT=20
R2Q=1
The DEFAULT parameter specifies the class number to which the “default” traffic will be assigned — usually 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 in an empirical way, for my outgoing channel in 2 Mbit.
Next, create the file
eth0-2.full2MBit , for the class that includes the entire available Internet channel. The file name consists of the interface name and class id, after the point the semantic name of the class comes, is used as a comment and is ignored by the system.
RATE=2Mbit
CEIL=2Mbit
RATE is our guaranteed band, CEIL is the maximum band. Since I have a channel with a guaranteed maximum bandwidth of 2 Mbit, these parameters are equal for me.
Now we will create one file for each traffic class that we have. I created separate classes for ssh traffic, as well as the traffic of World of Warcraft and Counter Strike games, although you can make one class for all high-priority traffic.
Ssh example - create
eth0-2: 10.ssh file . In the file name, a colon contains the id of the parent class 2 and the id of the current class is 10. You can select arbitrary identifiers for the class.
# class for outgoing ssh
RATE=128Kbit
CEIL=2Mbit
RULE=*:22
PRIO=1
BURST=100Kb
The RATE parameter indicates the guaranteed band for this class, in CEIL - the maximum. We allocate for ssh 128 KBit (at a minimum) and allow it to download the entire channel (I upload files via sftp). PRIO sets the priority of the traffic class (1 is the maximum; the higher the number, the lower the priority). BURST sets the maximum amount of traffic that will be transmitted at maximum speed before going on to transfer data from other classes. By setting this parameter to a sufficiently high value, we ensure that ssh traffic will be transmitted with minimal delays.
RULE sets the rule by which traffic to this class will be selected.
Format - RULE = [[saddr [/ prefix]] [: port [/ mask]],] [daddr [/ prefix]] [: port [/ mask]]
Pay attention to the comma! RULE = *: 22 denotes traffic whose destination port is 22, and RULE = *: 22 denotes traffic whose outgoing port is 22.
We will also create classes for other types of traffic, and a class for traffic “by default” with id 20 (we indicated first that it is to class number 20 that traffic should be sent “by default”). In it, we indicate the used discipline of division of the channel LEAF = sfq, in order for the upload to be 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 local server resources at full speed, a separate class of 2 MBit is allocated for Internet traffic, which added descendants 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 rules of shaping traffic immediately take effect.
In the process of compiling the rules, there is usually a need to somehow visualize traffic for debugging and monitoring purposes, so I decided to write a plugin for the munin server monitoring system, which would visualize the distribution of traffic classes over HTB classes. I decided to print only the tree leaf classes, since they usually carry the meaning.
You can download the plugin from the munin plugin's official repository, it is called
qos_ , just copy it to the munin / usr / share / munin / plugins / plug-ins folder and in the folder of used plug-ins / etc / munin / plugins make a symbolic link like qos_eth1, where eth1 is the name of the interface on which you want to monitor the download.
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 to display the state of the class with the specified id on the graph, and the env.label_name parameter to set the intelligible label for the class on the graph.
In the end, it should be something like this:
I want to note that I have a somewhat atypical situation, two Internet channels for 2 and 1 Mbit, and for each user a limit of 2 Mbit download speeds, so the graph shows that if one user is active, his speed is reduced by 2 Mbit, and if several - the total speed can reach three. More than 20 people work on such a fairly “close” 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 load.
UPD: posted
an example config htb.init