Шейпим трафик Linux при помощи tc

Друзья, приветствую. Одной из важнейших задач системного администратора является управление и справедливое разделение полосы пропускания между всеми сотрудниками в компании, где он работает. Под справедливым я понимаю именно выделение приоритетов, а не чью-то прихоть.

Изначально, мой первый шлюз сети Интернет представлял собой машинку на FreeBSD 8.2 с пересобранным ядром под поддержку dummynet и файрволла ipfw с 128 мегабайтами оперативы на борту. Поскольку эта версия морально устарела, да и захотелось перейти на что-то более современное (как минимум по железу), решено было осваивать другой шейпер трафика, так как пайпы и очереди в FreeBSD мне дались не очень хорошо.

Решено было переходить на CentOS (который я сейчас изучаю в рамках подготовки к RHCSA) и iproute2 (а именно tc). Первое впечатление от tc – во-от такие глаза “О_О” и вопрос “как это вообще можно понять?”. А сейчас ничего, втягиваюсь потихоньку. Поэтому и хочу оформить своё понимание в виде статьи, чтобы и себе на будущее и вам всем для справки, вдруг кто не знает эти инструменты.

Итак, в своей работе я буду использовать две виртуальные машины, CentOS 6.7 на борту – прототип шлюза, и linux microcore 3.8 – как рабочая машинка для теста (это ядро весьма легковесно и не нагружает мой нубук).

Статья будет дополняться, так как у tc много интересных вещей есть (разные типа дисциплин), каждая из которых заслуживает определённой доли внимания, а обо всех сразу я рассказать не смогу. Поэтому по мере изучения я буду делать выкладки здесь.

Итак, приступим.

Создадим скриптовый файл:

# vi /etc/tc.conf

следующего содержания:

#!/bin/bash
IF=eth0
tc qdisc del dev $IF root
tc qdisc add dev $IF root handle 1:0 htb default 10
tc class add dev $IF parent 1:0 classid 1:1 htb rate 100mbit
tc class add dev $IF parent 1:1 classid 1:10 htb rate 2mbit ceil 3mbit prio 0
#9999/TCP
tc class add dev $IF parent 1:1 classid 1:20 htb rate 4mbit ceil 7mbit prio 0
#10000/TCP
tc class add dev $IF parent 1:1 classid 1:21 htb rate 10mbit ceil 12mbit prio 0
#IPTABLES RULES#
iptables -t mangle -F OUTPUT
iptables -t mangle -A OUTPUT -o $IF -p tcp -m multiport --dports 9999 -j CLASSIFY --set-class 1:20
iptables -t mangle -A OUTPUT -o $IF -p tcp -m multiport --dports 10000 -j CLASSIFY --set-class 1:21

Не забываем сделать файл исполняемым:

# chmod +x /etc/tc.conf

Выполняем его.

Внимательный читатель наверняка уже всё понял, но я лучше перескажу порционно, дабы не запутаться, ибо у меня был небольшой затык в tc (не конкретно тут, а в других дисциплинах).

IF=eth0

Мы задали наш интерфейс, обращённый в локальную сеть. Именно этот трафик мы будем резать.

tc qdisc del dev $IF root

Удалили корневую дисциплину на порту eth0.

tc qdisc add dev $IF root handle 1:0 htb default 10

Добавили корневую дисциплину на порт типа htb Hierarchical Token Bucket, по этой дисциплине под каждый вид трафика выделяется собственная полоса, кроме того по умолчанию мы задали класс 10. Очень желательно задавать класс по умолчанию, (то есть такой, который не соответствует никаким другим классам), если этого не сделать – этот трафик будет считаться трафиком нулевого класса и возьмёт всю скорость интерфейса.

Здесь важно понимать иерархичность классов. Вот смотрите, в корневой дисциплине мы задали класс 1:0 – корень.

tc class add dev $IF parent 1:0 classid 1:1 htb rate 100mbit

Далее мы указали новый класс 1:1, который является вложенным в 1:0 (parent), и уже у него определили скорость 100mbit. То есть на все классы, вложенные в 1:1 будет выделяться не больше 100mbit скорость. По хорошему здесь мы должны указать потолок провайдера.

tc class add dev $IF parent 1:1 classid 1:10 htb rate 2mbit ceil 3mbit prio 0

А тут мы указали вложенный класс 1:10 (который вложен в 1:1), и для него скорость 2mbit с возможностью заимствования до 3mbit (если полоса свободна). В самом деле, заимствование может нам помочь. Если на какую-то группу пользователей выделено, к примеру, 10 мбит/с, а на каждого из них по 1 мбит/с, то, в случае, если работает только один – нет смысла ему резать до 1 мбит/с. Пусть берёт всё, что позволено его группе (10). Но как только появится второй (следующие) они будут делить эту десятку между собой, но не больше.

Кстати, класс 1:10 тут – это именно класс по умолчанию (см. несколько шагов вперёд).

#9999/TCP
tc class add dev $IF parent 1:1 classid 1:20 htb rate 4mbit ceil 7mbit prio 0

Здесь мы задали 20 класс и скорость на 4 мбит/с с ростом до 7мбит/с соответственно. Аналогично и 21 класс, я не буду его расписывать.

Ну а дальше самое интересное:

#IPTABLES RULES#
iptables -t mangle -F OUTPUT
iptables -t mangle -A OUTPUT -o $IF -p tcp -m multiport --dports 9999 -j CLASSIFY --set-class 1:20
iptables -t mangle -A OUTPUT -o $IF -p tcp -m multiport --dports 10000 -j CLASSIFY --set-class 1:21

Здесь мы берём на вооружение наш файрволл iptables и задаём правила метки трафика. В первом случае мы берём весь исходящий трафик через интерфейс eth0, протокол tcp и порт назначения 9999 и метим его классом 1:20, во втором случае – 1:21! Вроде бы всё понятно.

А теперь посмотрим, как себя будет вести трафик. Замерять скорость будем iperf.

Запускаем на принимающей стороне:

# iperf -s

Принимающая сторона
Принимающая сторона

А на нашем сервере:

# iperf -c 192.168.10.10

это IP адрес сервера (принимающей стороны).

Класс по умолчанию (1:10)
Класс по умолчанию (1:10)

Скорость 3 Мбит/с, это как раз скорость класса по умолчанию, так как мы не задали дополнительных параметров.

Теперь запустим сервер (принимающую сторону) с параметрами:

# iperf -s -p 9999

А на передающей стороне:

# iperf -c 192.168.10.10 -p 9999

Класс 1:20
Класс 1:20

Скорость уже 7 Мбит/с, что соответствует классу 1:20, которым мы метим весь трафик идущий на 9999 порт протокола tcp.

Ну и аналогично проверим порт 10000:

Класс 1:21
Класс 1:21

Как видите, ничего сложного нет. Подобным образом можно метить трафик от (к) конкретных IP адресов, протоколов и портов, чтобы задать собственные классы/приоритеты. Чтож, попробую реализовать эту систему на практике.


Скину фрагмент своего рабочего варианта, в случае использования линуксового шлюза:

#Локалка
LAN=eth0
#Internet
WAN=eth1
tc qdisc del dev $LAN root
tc qdisc add dev $LAN root handle 1:0 htb default 10
tc class add dev $LAN parent 1:1 classid 1:10 htb rate 1mbit ceil 1mbit prio 0
tc class add dev $LAN parent 1:0 classid 1:1 htb rate 14mbit
#Соседям 6 Мбит/с
tc class add dev $LAN parent 1:1 classid 1:20 htb rate 6mbit ceil 6mbit prio 0
tc class add dev $LAN parent 1:20 classid 1:21 htb rate 512kbit ceil 6mbit prio 0
tc class add dev $LAN parent 1:20 classid 1:22 htb rate 1mbit ceil 6mbit prio 0
#Себе 8 Мбит/с
tc class add dev $LAN parent 1:1 classid 1:30 htb rate 8mbit ceil 8mbit prio 0
iptables -F OUTPUT
iptables -F INPUT
iptables -F FORWARD
iptables -t nat -F POSTROUTING
iptables -t mangle -A POSTROUTING -d 192.168.1.13 -j CLASSIFY --set-class 1:22
iptables -t mangle -A POSTROUTING -d 192.168.1.9 -j CLASSIFY --set-class 1:22
iptables -t mangle -A FORWARD -i $WAN -j ACCEPT
iptables -t mangle -A FORWARD -o $WAN -j ACCEPT
iptables -t nat -A POSTROUTING -o $WAN -j MASQUERADE

Для тестов замерили скорость Speedtest-ом на хосте с IP 192.168.1.9, показало 6 Мбит. Затем на хосте .1.13 – тоже 6 Мбит. А затем запустили Speedtest одновременно. На первом хосте в среднем 3,3 Мбит, на втором в среднем 3,1 Мбит (один чуть раньше запустил, похоже), так что распределение полосы я считаю справедливым.

Итак, у меня есть два больших класса 1:20 и 1:30. Я делю канал в 14 Мбит на два – 6 и 8 соответственно. Пожалуй, даже правильнее будет мне сделать чуток по другому:

  • 1:1 – 14mbit
  • 1:20 – 6mbit
  • 1:30 – 8mbit ceil 14mbit, чтобы себе брать свободный поток, если он будет.

Затем каждый большой класс поделить на пользователей и дать им соответственно необходимый минимум с возможностью ceil до потолка большого класса. И, пожалуй, нужно продумать такой момент, чтобы доступ к локальным ресурсам сервера (файловые шары) не резался, а шёл по скорости LAN (100 Мбит), а также думаю сделать небольшой веб-интерфейс и составной конфиг, чтобы каждый админ мог наруливать лимиты.

Ещё бы сюда Squid прикрутить, тогда, пожалуй, правила придётся немного поменять.

Интересно? Поделись с другом
Litl-Admin.ru

Comments:

Leave a Reply