Что такое шейпинг сети

Причесываем трафик — динамический шейпер на Linux


Предположим у вас есть домашняя сеть (или не домашняя, а сеть небольшого офиса) с выходом в интернет через не очень скоростной канал. А пользователей — много, и каждый хочет что-то скачивать, да с максимальной скоростью. Вот тут перед нами встатет задача, как максимально эффективно распределить наш интернет-канал между пользователями так, чтобы они не мешали друг другу. В этой статье я опишу, как можно решить такую задачу с помощью Linux-сервера.

Сформулируем, что же мы хотим получить в результате:
1. Чтобы канал поровну делился между пользователями.
2. Чтобы канал зря не простаивал.
3. Чтобы онлайн-игры, ssh и telnet не «лагали» даже при полной загрузке канала, например торрентами.

Если интернетом будут одновременно пользоваться 10 пользователей — каждый получит в свое распоряжение 1/10 часть канала, если в данный момент активен только один пользователь — он будет использовать весь канал сам.
Добиться этого можно используя планировщик пакетов HTB, который входит в ядро linux начиная с версии 2.4.20.

Можно конфигурировать шейпер с помощью команды tc, но для более удобной и наглядной настройки я рекомендую скачать скрипт htb.init. Они использует для конфигурации htb набор конфигурационных файлов, именуемых так, что при сортировке по алфавиту их имена позволяют визуально представить себе дерево классов шейпера и удобно его редактировать.
Предположим, что у нас на сервере есть интерфейс eth0, через который мы подключены к интернет, и eth1, который «смотрит» в локальную сеть.

Управлять можно только исходящим из интерфейса трафиком, поэтому для eth0 будут правила для upload трафика пользователей, а для — eth1 — download трафика.

По умолчанию конфигурационные файлы htb.init находятся в /etc/htb/. Для начала напишем правила шейпинга для upload трафика, они у нас будут простые.
Создаем файл с именем eth0 (интерейс «смотрящий» в интернет), в него напищем следующие строки:
DEFAULT=20
R2Q=1

Параметр DEFAULT задает номер класса, к которому будет относиться трафик «по умолчанию» — обычно это класс с минимальным приоритетом. Параметр R2Q влияет на работу алгоритма разделения канала и зависит от ширины канала. Я подбирал его значение эмпирическим путем, для моего исходящего канала в 2 Mbit.

Далее, создадим файл eth0-2.full2MBit, для класса включающего в себя весь доступный интернет-канал. Имя файла состоит из имени интерфейса и id класса, после точки идет смысловое имя класса, используется как комментарий и системой игнорируется.
RATE=2Mbit
CEIL=2Mbit

RATE — это наша гарантированная полоса, CEIL — максимальная полоса. Так как у меня канал с гарантированной максимальной полосой в 2 Mbit, то эти параметры у меня равны.

Теперь мы создадим по одному файлу для каждого класса трафика, который у нас будет. Я у себя создал отдельные классы для ssh трафика, а так же трафика игр World Of Warcraft и Counter Strike, хотя вы можете сделать для всего высокоприоритетного трафика один класс.

Пример для ssh — создаем файл eth0-2:10.ssh. В имени файла через двоеточие указан id родительского класса 2 и id текущего класса — 10. Идентификаторы для класса вы можете выбирать произвольно.
# class for outgoing ssh
RATE=128Kbit
CEIL=2Mbit
RULE=*:22
PRIO=1
BURST=100Kb

В параметре RATE указана гарантированная полоса для этого класса, в CEIL — максимальная. Мы выделяем для ssh 128 KBit (как минимум) и разрешаем ему загрузить весь канал (я закачивать файлы по sftp). PRIO задает приоритет класса трафика (1- максимальный, чем больше число — тем меньш приоритет). BURST задает максимальный объем трафика, который будет передан на максимальной скорости перед тем, как перейти к передаче данных из дургих классов. Установив этот параметр в достаточно высокое значение мы добиваемся того, что трафик ssh будет передан с минимальными задержками.
RULE задает правило, по которому будет отбираться трафик в этот класс.
Формат — RULE=[[saddr[/prefix]][:port[/mask]],][daddr[/prefix]][:port[/mask]]
Обратите внимание на запятую! RULE=*:22 обозначает трафик, у которого порт назначения 22, а RULE=*:22, обозначает трафик, у которого исходящий порт — 22.

Создадим так же классы для других видов трафика, и класс для трафика «по умолчанию» с id 20 (мы указали вначале что именно в класс номер 20 надо направлять трафик «по умолчанию»). В нем укажем используемую дисциплину разделения канала LEAF=sfq, для того чтобы upload поровну делился между TCP сессиями разных пользователей.

Для eth1 правила будут почти такие же, только с учетом что общая ширина канала — 100 Mbit, мы ведь хотим чтобы можно было обращаться к локальным ресурсам сервера на полной скорости, для интернет-трафика выделен отдельный класс на 2 MBit, у которого как потомки добавлены классы отдельных пользователей, разделение по классам я делал по IP адресам. Для каждого пользователя можно указать максимальную и гарантированную скорость, а так же приоритет.

После правки конфигурации перезапускаем htb.init:
/etc/init.d/htb.init restart
И правила шейпинга трафика сразу же вступают в силу.

В процессе состевления правил обычно возникает необходимость как-то визуализировать трафик, в целях отладки и мониторинга, поэтому решил написать плагин для системы мониторинга серверов munin, который бы визуализировал распределение по классам HTB трафика. Выводить решил загрузку только классов-листьев дерева, так как именно они обычно несут смысловую нагрузку.
Скачать плагин вы можете из официального репозитория плагинов munin, называется он qos_, просто скопируйте его в папку плагинов munin /usr/share/munin/plugins/ и в папке используемых плагинов /etc/munin/plugins сделайте на него символическую ссылку вида qos_eth1, где eth1 — имя интерфейса, на котором нужно мониторить загрузку.
В файле конфигурации плагинов можно добавить следущее:
[qos_eth1]
env.ignore_queue1_10 yes
env.label_name1_31 Viperet
env.label_name1_32 Cornet

Параметр env.ignore_queue позволяет не отображать на графике состояние класса с указанным id, а параметр env.label_name — задать человекопонятную метку для класса на графике.

В итоге должно получиться что то такое:

Хочу заметить, что у меня несколько нетипичная ситуация, два интернет канала на 2 и 1 Mbit, и для каждого пользователя ограничение в 2 Mbit скорости загрузки, поэтому на графике видно, что если активен один пользователь — его скорость урезается на 2 Mbit, а если несколько — суммарная скорость может достигать и трех. На таком достаточно «тесном» канале работают более 20 человек, и вполне комфортно себя чувствуют, не мешая друг другу.
Эта картинка с реально действующего сервера, и она обновляется каждые 5 минут и отображает актуальную картину загрузки канала.

Источник

Управление трафиком: очереди и шейпинг

Почти все приложения, использующие Интернет, работают через TCP (RFC 793) поверх IP. Протокол IP всего лишь передает пакеты, не заботясь о том, что они могут быть поврежденными, идти в неправильном порядке и т.д. К тому же IP не позволяет адресовать пакет какой-либо конкретной программе. Все эти недостатки устраняются уровнем выше – в TCP. Его характеристики следующие:
Потоковый интерфейс: Все байты информации, отправляемые одним приложением с одной стороны, придут к приложению-получателю с другой стороны в той же последовательности, в какой были посланы. Нет никакого ограничения на размер сообщенния: TCP сам разбивает по своему усмотрению информацию на пакеты.
Достоверность и надежность: Для каждого сегмента (пакета) TCP вычисляет контрольную сумму и отбрасывает его, если она неправильная. Он повторяет пересылку до тех пор, пока не получит подтверждение от получателя о правильном приеме или пока не убедится в том, что канал невозможно использовать и не выйдет время ожидания.
Мультиплексирование: TCP использует механизм портов для осуществления мультиплексирования, тем самым позволяя приложениям-отправителям адресовать данные конкретным приложениям-получателям. Например, веб-серверы, как правило, используют порт 80. Когда браузер соединяется с сервером, он также указывает и порт источника. При этом веб-страница отсылается именно ему. Обычно серверные порты имеют значение меньше 1024 (хотя и не всегда); клиентские порты обычно находятся в диапазоне от 1024 и выше.
Предотвращение перегрузки канала: Наконец, TCP имеет контроль загрузки линии, который позволяет ему определить, не теряются ли ресурсы из-за посылки большего объема трафика, чем может передавать канал.

предотвращение перегрузки канала в TCP

Кроме встроенного простого механизма самосинхронизации, основанного на «окне», ограничивающем количество пересылаемой информации, TCP имеет еще четыре дополнительных механизма, осуществляющих регулировку загрузки канала: медленный старт, предотвращение перегрузки, быстрая перепосылка и быстрое восстановление. Алгоритмы этих механизмов описаны в RFC 2001.

медленный старт
После инициализации соединения, другая сторона сообщает TCP объем данных, приготовленных в буфере. Это значение называется «предложенным размером окна». На установление соединения уходит 3 пакета: инициализирующий пакет с установленным SYN-битом, ответ от хоста-получателя с установленными битами SYN/ACK и финальный пакет от хоста-инициатора с установленным битом ACK.
После вышеописанной процедуры установления соединения локальный (и удаленный) TCP может передавать данные до тех пор, пока окно не заполнится. После этого он должен подождать подтверждений о приеме некоторой части информации. Только после их получения он может продолжить передачу. При получении от удаленного TCP слишком большого значения размера предложенного окна, локальный TCP не начинает сразу же использовать окно полностью. Это необходимо потому что на пути может встретится низкоскоростное соединение, и маршрутизатор, подключенный к нему не сможет буферизировать все накапливающиеся данные пока они не будут переданы через соединение. Таким образом, передающая сторона использует окно предотвращения перегрузки в дополнение к предложенному окну. Окно предотвращения перегрузки сначала имеет размер, равный максимальному размеру сегмента. После получения каждого уведомления о приеме данных, размер этого окна удваивается. Если размер сегмента равен 1460 байтам (что соответствует 1500-байтному пакету Ethernet минус IP- и TCP-заголовки), и приемник предлагает 8192-байтное окно, передатчик установит размер окна предотвращения перегрузки в 1460 байт, передаст первый пакет и будет ждать подтверждения. После получения первого подтверждения, размер окна увеличится до 2920 байт, и предадутся 2 пакета. После получения следующего подтверждения размер окна становится равным 5840 байтам, позволяя пересылать 4 пакета. Один пакет еще не подтвержден, поэтому пересылаются 3 пакета. После получения подтверждения, размер окна увеличится до предложенного.

Читайте также:  как мошенники обманывают с кредитами

защита от перегрузки
Защита от перегрузки предлагает другую переменную: границу медленного старта (slow start threshold size (ssthresh)). При инициализации соединения значение ssthresh устанавливается равным 65535 байтам (максимально возможное предложенное окно). Если информация не теряется, алгоритм затяжного пуска будет увеличивать размер окна до тех пор, пока он не станет максимальным. Если же TCP получает пришедшее не по порядку подтверждение, в силу вступает механизм предотвращения перегрузки. В данном случае под пришедшим не по порядку подтверждением подразумевается подтверждение о приеме информации, которая уже была передана, и подтверждение о ее приеме было получено. Это происходит при потере пакета: принимающий TCP отправляет передающему подтверждение на информацию до потерянного пакета, говоря примерно следующее: « Я все еще жду информацию, следующую за тем, что я сейчас подтверждаю» Такая схема необходима из-за того, что подтверждения TCP кумулятивны, т.е. нельзя сказать: «Я получил байты 1000-1499, но потерял 500-999»
После получения повторяющегося подтверждения, передающий TCP принимает неподтвержденную информацию за трагически погибшую из-за перегрузки канала. При этом ssthresh и размер окна предотвращения перегрузки устанавливаются равными половине текущего размера окна до тех пор, пока он равен как минимум двум максимальным размерам сегмента. После этого, окну разрешается увеличиваться очень медленно, чтобы сразу же не вернуться к состоянию перегрузки. Если передающий TCP длительное время не получает никаких подтверждений, он определяет эту ситуацию как массивную перегрузку и инициирует механизм затяжного пуска, понижая при этом значение ssthresh. Таким образом, до тех пор, пока размер окна предотвращения перегрузки меньше или равен значению ssthresh, используется затяжной пуск (окно удваивается после каждого подтверждения), а после него – предотвращение перегрузки (окно медленно увеличивается).

быстрая перепослылка и восстановление
Если TCP получает подряд три идущих не по порядку подтверждения, он решает, что один пакет был потерян (одно или два неправильных подтверждения воспринимаются им как изменение очередности передачи пакетов в сети). После этого он пересылает пакет заново, не дожидаясь тайм-аута. Значение ssthresh устанавливается так же, как и при защите от перегрузки, но размер «перегрузочного» окна принимается равным ssthresh плюс три максимальных сегмента (размер равен количеству информации, успешно полученной приемником, определенному по идущим не по порядку подтверждениям). В результате TCP замедляется, но не сильно, так как при этом через него все еще проходит достаточно большой объем данных.

влияние потери пакетов и задержек на работу TCP

В результате работы вышеописанных механизмов TCP сильно замедляется при потере большого числа пакетов. Ситуация ухудшается, когда время прохождения пакетов туда и обратно (RTT) большое из-за того, что использование окон ограничивает пропускную способность TCP до размера окна, деленного на время прохождения пакетов туда и обратно. Это означает, что даже с максимальным размером окна в 64 кб (без включения высокопроизводительных расширений TCP), производительность TCP на трансконтинентальной линии с задержкой прохождения пакетов туда и обратно в 70 мс не превысит 900 кбит/с. При потере пакета это значение уменьшается вдвое и возвращается к назад только после сотен успешных подтверждений. Таким образом, даже случайная потеря пакета может существенно снизить эффективность использования пропускной способности территориально протяженного соединения TCP-сессией.
Поведение двух основных категорий не-TCP приложений в условиях потери пакетов различно. К первой категории можно отнести мультимедиа (потоковое аудио и видео), ко второй – приложения, основанные на небольших транзакциях, не требующих большого количества служебной информации вроде DNS. Как правило, потоковые аудио и видео не слишком чувствительны к потере пакетов, тем не менее, от нее несколько пострадает качество. Что же касается вещей вроде разрешения имен DNS, то потеря пакетов существенно замедлит индивидуальные транзакции (для них наступает тайм-аут и требуется повторение). Из-за того, что не-TCP приложения не имеют адекватной реакции на потерю пакетов, часто бывает так, что они увеличивают перегрузку канала, продолжая посылать больший объем трафика, чем может передавать соединение.
Несмотря на то, что некоторые потерянные пакеты – результат ошибок в битах на физическом уровне или временных проблем с маршрутизацией, основная причина потерь – перегрузка канала чрезмерным трафиком. Рассмотрим ситуацию, когда, например, скорость подключения маршрутизатора к популярному направлению равна 155 Мбит/с, а для этого направления со скоростью 200 Мбит/с приходит трафик. Первое, что сделает маршрутизатор – поставит пакеты, которые невозможно переслать немедленно, в очередь. IP-трафику свойственны кратковременные вспышки активности длительностью от секунды до нескольких секунд. Очередь сглаживает подобные неоднородности. Ценой этого являются некоторые дополнительные задержки пакетов, но, по крайней мере, пакеты не теряются. Тем не менее, если чрезмерно интенсивный трафик передается длительное время, очередь может переполниться. При этом маршрутизатору ничего не остается, кроме как отбрасывать все входящие пакеты, до тех пор, пока очередь переполнена. Это называется «отбрасывать хвост» («tail drop»). Механизмы защиты от перегрузки разработаны именно для этой ситуации, таким образом, в данном случае все TCP-сессии замедлятся, при этом перегрузка должна исчезнуть. Однако может возникнуть более сложный случай перегрузки, когда трафик представляет собой множество коротких TCP-сессий (например, web или email). В этом случае количества инициализирующих пакетов (в это время TCP еще находится режиме затяжного пуска) может хватить, чтобы вызвать перегрузку. Не-TCP приложения также легко могут вызвать перегрузку, так как они не обладают механизмами защиты от нее.

образование очередей

Образование очередей происходит только в случае, когда интерфейс слишком занят. Если же он свободен, то пакеты передаются без всякой дополнительной обработки. Все стандартные очереди работают по принципу FIFO (first in, first out): пакет, который пришел раньше всех, будет передан первым и т.д. Если очередь заполнена до отказа и приходят новые пакеты, то происходит «отброс хвоста». Более изощренные способы организации очередей часто используют несколько очередей. Пакеты классифицируются в соответствии с потребностями пользователя и затем сортируются по соответствующим очередям. Затем, при освобождении интерфейса, с помощью специального алгоритма выбирается очередь, пакет из которой будет отправлен. Например, маршрутизаторы Cisco поддерживают несколько стратегий организации очередей: FIFO, WQF, RED, по приоритету, произвольные. Следует отметить, что все специальные методики организации очередей дают эффект только в случаях, когда невозможно немедленно отправить пакет через интерфейс. Если же интерфейс свободен и в очереди не находится пакетов, то новый пакет пересылается сразу же.

FIFO
Стратегия FIFO – самая простая. При ее использовании пакеты передаются в том же порядке, в каком приходят. Как правило, ее применяют на быстрых интерфейсах. Чтобы ее включить, необходимо отключить все остальные механизмы организации очередей:

!
interface Serial0
no fair-queue
!

взвешенные очереди (Weighted fair queuing, WQF)
Механизмы, использующие очереди с весами, пытаются разделить пропускную способность между несколькими потоками данных (обычно это TCP-сессии), таким образом, чтобы потоки с большой активностью не захватывали монопольно соединение. Как правило, WQF применяется для низкоскоростных интерфейсов. Включить WQF можно следующим образом:

Читайте также:  дивиденды с иис на банковский счет бкс

!
interface Serial0
fair-queue
!

опознание перегрузки (Random early detect, RED)
При переполнении очереди RED начинает отбрасывать пакеты для предотвращения перегрузки канала. Больше всего RED обращает внимания на сессии с наибольшим объемом трафика, поэтому именно они замедляются в первую очередь. При использовании опознания перегрузки с весами (Weighted random early detect), в первую очередь будут отбрасываться пакеты с наименьшим приоритетом. В отличие от WFQ, очередей с приоритетами и произвольных очередей, RED не требовательна к процессорному времени и может применяться на высокоскоростных интерфейсах. Она нуждается в размере очереди на передачу большем, чем стандартные 40 пакетов, чтобы иметь возможность начать отброс пакетов заранее и избежать «отброса хвоста».

!
interface Ethernet0
random-detect
hold-queue 200 out
!

Кстати, в RFC 2309 проблемная группа проектирования Интернет (IETF) рекомендует использовать RED в Интернет-маршрутизаторах.

очереди с приоритетами
При использовании этой методики, трафик классифицируется по приоритетам. Приоритет может быть высоким, нормальным, средним и низким. Если в потоке имеется высокоприоритетный трафик, то он передается в первую очередь, затем передается трафик со средним приоритетом и т.д. Это может замедлить низкоприоритетный трафик или даже совсем остановить его в случае, когда высокоприоритетный трафик забирает всю пропускную способность канала. В нижеописанном примере показано, как включить очереди с приоритетами и установить средний приоритет для DNS и низкий для FTP.

шейпинг и ограничение скорости трафика

При применении шейпинга, происходит подсчет трафика для конкретного интерфейса. Шейпинг может применяться ко всему трафику или же только к тому, который удовлетворяет какому-либо списку. Это происходит не зависимо от того, свободен ли интерфейс, или в очереди находятся пакеты. Когда трафик достигает некоторого заданного пользователем значения, следующие поступающие пакеты становятся в очередь и задерживаются. Таким образом, потребляемая пропускная способность ограничивается на настраиваемое значение.
Ограничение скорости, иногда называемое также ограничением трафика похоже на шейпинг. Отличие заключается в том, что чрезмерный трафик обрабатывается отдельно от обычного, по правилам, настраиваемым пользователем. Наиболее распространенный способ обработки лишнего трафика – отброс его, но существуют и другие способы, например, уменьшение значения поля приоритета в IP-заголовке. В следующем примере включается шейпинг для одного интерфейса и ограничение скорости для другого.

!
interface Serial0
traffic-shape rate 128000 8000 8000 1000
!
interface Serial1
rate-limit output 128000 8000 8000 conform-action transmit exceed-action drop
!

Шейпинг и ограничение скорости обычно применяются, когда необходимо ограничить доступную клиенту пропускную способность, если, например, оплачена низкая, а подключение производится по интерфейсу, имеющему высокую пропускную способность. Однако в данном случае лучше не применять ограничение скорости, так как оно отбрасывает много пакетов, заставляя TCP думать, что линия перегружена. Посему он замедляется, но спустя некоторое время опять пытается ускорить темп, вызывая тем самым очередную потерю пакетов. Шейпинг же всего лишь замедляет пакеты, так что через некоторое время TCP адаптируется к доступной пропускной способности. В следующем примере показана производительность FTP на соединении с применением ограничения скорости до 128к.

ftp>put testfile
local: testfile remote: testfile
150 Opening BINARY mode data connection for ‘testfile’.
100% |**********************************| 373 KB 00:00 ETA
226 Transfer complete.
382332 bytes sent in 35.61 seconds (10.48 KB/s)

Как видно, пропускная способность для FTP составила 84 кбит/с, т.е. примерно две трети от доступной. Как будет вести себя та же передача, на том же соединении, но с применением шейпинга, показано ниже:

ftp>put testfile
local: testfile remote: testfile
150 Opening BINARY mode data connection for ‘testfile’.
100% |**********************************| 373 KB 00:00 ETA
226 Transfer complete.
382332 bytes sent in 24.73 seconds (15.10 KB/s)

На сей раз производительность составила 121 кбит/с, что всего лишь на несколько процентов меньше доступной, учитывая служебную информацию TCP, IP и соединения.
Кроме отбивания атак типа «отказ в обслуживании», ограничение скорости имеет еще одно потенциальное применение, так как в отличие от шейпинга и других механизмов организации очередей может быть применено и к входящему трафику. Когда провайдер договаривается с клиентом о некоторой пропускной способности, он может использовать шейпинг для ограничения доступной клиенту входящей пропускной способности. Но так как невозможно применить шейпинг к входящим в интерфейс пакетам, на клиента возлагается задача шейпинга его исходящего трафика. Для того чтобы убедиться, что клиент не превышает оговоренный лимит трафика, провайдер может дополнительно применить ограничение скорости на входящий трафик.

Iljitsch van Beijnum, перевод Дмитрия Герусса.

Сетевые решения. Статья была опубликована в номере 01 за 2003 год в рубрике технологии

Источник

Каждому по потребностям: ограничение полосы пропускания на Linux-овом шлюзе

Содержание статьи

Допустим, существует офис некой компании X, и в нем числится около ста
сотрудников, каждый из которых может выходить в интернет через шлюз. Скорость
внешнего канала составляет 100 Мбит. Системный администратор справился с
настройкой шлюза в силу своих способностей – что и посчитал достаточным для
правильного функционирования сети. К чему это привело? К увольнению
недальновидного (или ленивого) админа.

Со временем большинство сотрудников начали жаловаться на «тормоза» интернета,
а другие, наоборот, заметили, что могут качать торренты в рабочее время на очень
внушительных скоростях. Говоря админским языком, в сети образовались заторы,
вызванные теми, кто в тот момент активно ее использовал. Стомегабитный канал
распределялся неравномерно между пользователями, и каждый мог занять его весь.
Остальным приходилось ждать.

Краткий сценарий

Решение проблемы: разделение канала между сотрудниками с ограничением
скорости! Сеть будет функционировать на «5+», если каждый сотрудник получит в
распоряжение отдельный канал, скорость которого будет составлять 1 Мбит. Тогда
отдельно взятый интернет-пользователь не сможет занять больше причитающейся ему
доли и отобрать часть канала у других. С точки зрения компании, это еще и
отличный способ экономии (после разделения канала оказывается, что его суммарная
пропускная способность даже излишне высока) и ведения статистики по трафику для
отдельно взятого сотрудника.

Обычно для разделения канала с ограничением скорости используются возможности
операционной системы IOS, на которой функционирует сетевое оборудование Cisco
(дешевые решения от других производителей, таких, как Dlink, Trendnet и Netgear,
вообще не обладают такой возможностью). Однако особой необходимости тратить
баснословные суммы на аппаратные шлюзы от Cisco нет. Ядро Linux уже более пяти
лет как содержит в себе код сложной и весьма функциональной подсистемы
управления трафиком Traffic Control, которая по некоторым параметрам даже
обходит IOS.

Подсистема Traffic Control

Подсистема Traffic Control поддерживает множество методов
классификации, приоритезации, разделения и ограничения трафика (как исходящего,
так и входящего). Она очень гибка в настройке, но сложна в понимании. Поэтому мы
уделим значительную часть статьи теоретическому материалу и лишь затем приступим
к решению задачи с помощью HTB – одной из наиболее гибких и популярных дисциплин
Traffic Control.

Подсистема управления трафиком Linux позволяет делать следующее:

Отметим, что ограничение без потерь возможно только в отношении исходящего
трафика. Стек протоколов TCP/IP не предусматривает возможности заставить
удаленную сторону слать пакеты медленнее (и это правильно).

В обработке трафика участвуют три ключевых сущности: дисциплины обработки
пакетов, классы и фильтры. Настройка эффективной системы ограничения трафика
невозможна без понимания механизмов их работы, роли и связи друг с другом. Мы в
подробностях рассмотрим каждую из них:

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

Linux действует таким же образом. Но формат представления очереди и алгоритм
ее обработки, в совокупности называемые дисциплиной обработки пакетов, в нем
заменяемы! По умолчанию используется дисциплина pfifo_fast, реализующая очередь
FIFO. Пользуясь утилитой tc, администратор может заменить ее на другую
дисциплину, которая будет переупорядочивать пакеты (планирование), задерживать
их на определенное время (шейпинг) или выполнять другие действия.

Дисциплины классов

Traffic Control не был бы столь гибким, если бы не позволял разбивать
трафик на классы с помощью классовой дисциплины и набора ее подклассов.
Схематически классовая дисциплина очень похожа на файловую систему, c тем лишь
исключением, что ее корень или классы (каталоги) могут содержать либо дисциплину
(файл), либо подклассы (подкаталоги). Одно из двух. Классовые дисциплины и
классы предназначены для построения дерева выбора. Сначала весь трафик
разбивается на несколько общих классов (например, трафик до Отдела-1, трафик до
специализированных внутренних серверов и т.д.), а затем каждый из них
разбивается на несколько подклассов (например, трафик до DNS-сервера Отдела-1),
за которыми уже могут быть закреплены дисциплины.

Читайте также:  график выдачи пенсий военнослужащим в 2021 году в беларуси

Чтобы управлять тем, дисциплиной какого класса будет обработан определенный
тип трафика, классовые дисциплины позволяют подключать к себе фильтры. Это дает
возможность «завернуть» определенный трафик в один из ее подклассов. Фильтры
используют классификаторы для идентификации пакетов нужного типа и как бы
говорят ядру: «Этот вид трафика должен обрабатываться с помощью дисциплины вот
этого класса». Существует несколько разных классификаторов. Самыми популярными
являются u32 и fw. Первый позволяет выделять пакеты по исходящим адресам и
адресам назначения, портам, парам «хост:порт», типам протокола и типу сервиса.
Второй классифицирует пакеты путем чтения маркировок, записанных брандмауэром
iptables/netfilter (цель MARK).

Утилита tc

Для конфигурирования подсистемы управления трафиком предназначена утилита tc
из пакета iproute2. Она принимает набор команд в качестве аргументов, с помощью
которых можно создавать классы, привязывать к ним дисциплины и добавлять
фильтры. Синтаксис ее похож на синтаксис команды ipfw из операционной системы
FreeBSD, так что знакомые с ним быстро освоятся.

Для примера рассмотрим простейший вариант использования:

# tc qdisc add dev eth0 root tbf rate 256kbit \
latency 50ms burst 1540

Эта команда устанавливает ограничение для всего исходящего трафика в 256
Кбит/с. Разберем подробнее все аргументы tc:

Способ указания скоростей и других величин в утилите tc несколько отличается
от общепринятого, поэтому следующую табличку придется запомнить:

Формат указания скорости в утилите tc

mbps = 1024 kbps = 1024 * 1024 bps => Байт/с
mbit = 1024 kbit => Кбит/с
mb = 1024 kb = 1024 * 1024 b => Байт

Заменить стандартную корневую дисциплину на любую бесклассовую совсем
несложно, но на таком коне далеко не уедешь. Для создания разветвленной системы
управления трафиком нужны классовые дисциплины, классы, фильтры и целое дерево
дисциплин. Чтобы настроить все это, может понадобиться не один десяток команд.
Мы рассмотрим несколько вводных примеров, перед тем как перейти к обсуждению
дисциплины HTB.

Пример дерева дисциплин

Подключим дисциплину prio в качестве корневой и назначим ей имя (дескриптор)
«1:0»:

# tc qdisc add dev eth0 root handle 1:0 prio

Результат этой команды: дисциплина prio, подключенная в качестве корня, и три
класса (1:1, 1:2 и 1:3) внутри нее, к каждому из которых подключена дисциплина
FIFO.

Мы вольны заменить любую из дисциплин, подключенных к классам, чем и
воспользуемся для подключения дисциплины sfq с дескриптором «10:0» к классу
«1:1»:

# tc qdisc add dev eth0 parent 1:1 handle 10:0 sfq

Это обеспечит справедливое разделение канала между интерактивными
приложениями (они имеют наивысший приоритет). Чтобы остальные приложения, такие
как менеджеры закачек и torrent-клиенты (которые обычно шлют пакеты с меньшим
приоритетом в поле TOS), не мешали интерактивным, ограничим для них скорость:

# tc qdisc add dev eth0 parent 1:2 handle 20:0 tbf \
rate 512kbit buffer 3200 limit 3000
# tc qdisc add dev eth0 parent 1:3 handle 30:0 tbf \
rate 256kbit buffer 6400 limit 3000

Такая схема будет плохо работать в реальной жизни, но для примера вполне
годится.

Теперь сделаем так, чтобы весь SSH-трафик имел наивысший приоритет. Для этого
закрепим за корневой дисциплиной prio фильтр, который будет перенаправлять
пакеты с портом назначения 22 в дисциплину класса «1:1».

# tc filter add dev eth0 parent 1:0 protocol ip prio 1 \
u32 match ip dport 22 0xffff flowid 1:1

Рассмотрим подробнее механизм подключения фильтров.

Это все. Мы получили разветвленную систему управления трафиком, выполнив
всего пять команд.

Классовая дисциплина HTB

Еще в первый релиз системы Traffic Control была включена классовая
дисциплина CBQ (Class-Based Queue), предназначенная для реализации сложных
систем управления и ограничения трафика. CBQ завоевала большую популярность
благодаря своей гибкости, но была очень сложна, запутана и обладала рядом
ограничений (тут и необходимость заранее указывать максимальную пропускную
способность канала, и неэффективный алгоритм шейпинга).

Поэтому в скором времени появилась более эффективная и простая в
использовании альтернатива под названием HTB (Hierarchical Token
Bucket
). Классовая дисциплина HTB предназначена для разделения полосы
пропускания между различными видами трафика, каждому из которых может быть
предоставлена полоса гарантированной ширины. Она не обладает гибкостью CBQ, но
гораздо более проста в настройке и лишена ее недостатков. Именно на HTB сегодня
принято строить сложные и эффективные системы ограничения трафика.

Мы же создадим симбиоз этих двух систем, когда трафик сначала будет
разбиваться на подклассы, соответствующие подсетям, а уже потом на отдельные
классы для каждого пользователя.

Для начала создадим работоспособную систему, основанную только на втором
варианте решения задачи. Подключим дисциплину HTB в качестве корневой:

# tc qdisc add dev eth0 root handle 1: htb default 15

Опция «default 15» говорит о том, что весь неклассифицированный фильтрами
трафик должен быть обработан с помощью дисциплин класса «1:15». Создадим
корневой класс, под который будет попадать весь трафик (это нужно для реализации
заимствования):

# tc class add dev eth0 parent 1: classid 1:1 htb \
rate 100mbps ceil 100mbps

Создадим в нем пять подклассов для пяти наших подсетей. Директору и IT-отделу
выделим 30-мегабитный канал с возможностью его расширения (заимствования) вплоть
до 100 Мбит в случаях, когда остальные каналы не заняты:

# tc class add dev eth0 parent 1:1 classid 1:11 \
htb rate 30mbps ceil 100mbps

Для маркетологов выделим 20-мегабитный канал:

# tc class add dev eth0 parent 1:1 classid 1:12 \
htb rate 20mbps

Менеджерам – 10 Мбит/с:

# tc class add dev eth0 parent 1:1 classid 1:13 htb rate 10mbps

Секретарям – 5 Мбит/с:

# tc class add dev eth0 parent 1:1 classid 1:14 htb rate 5mbps

И – 40 Мбит/с на всех остальных:

# tc class add dev eth0 parent 1:1 classid 1:15 htb rate 40mbps

По умолчанию к вновь созданным классам подключены дисциплины, реализующие
очередь FIFO. Это нам не подходит. Чтобы канал равномерно распределялся между
всеми участниками подсети, мы должны подключить к ним дисциплину sfq:

# tc qdisc add dev eth0 parent 1:11 handle 10:0 sfq perturb 10
# tc qdisc add dev eth0 parent 1:12 handle 20:0 sfq perturb 10
# tc qdisc add dev eth0 parent 1:13 handle 30:0 sfq perturb 10
# tc qdisc add dev eth0 parent 1:14 handle 40:0 sfq perturb 10
# tc qdisc add dev eth0 parent 1:15 handle 50:0 sfq perturb 10

Теперь подключим фильтры, которые будут классифицировать трафик:

# tc filter add dev eth0 protocol ip parent 1:0 prio 1 \
u32 match ip src 172.16.1.0/24 flowid 1:11
# tc filter add dev eth0 protocol ip parent 1:0 prio 1 \
u32 match ip src 172.16.2.0/24 flowid 1:12
# tc filter add dev eth0 protocol ip parent 1:0 prio 1 \
u32 match ip src 172.16.3.0/24 flowid 1:13
# tc filter add dev eth0 protocol ip parent 1:0 prio 1 \
u32 match ip src 172.16.4.0/24 flowid 1:14

Для «всех остальных» фильтр не нужен, потому как мы уже указали дефолтовый
класс неклассифицированного трафика.

Все, система будет работать, но не обеспечит жесткого ограничения для каждого
пользователя (если, например, в определенный момент времени интернетом будет
пользоваться только один менеджер, ему достанутся все 10 Мбит, отведенные для
всех менеджеров). Жесткое ограничение можно реализовать, если вместо дисциплин
подключить к классам другие классы HTB, по одному на каждого пользователя, и
создать соответствующие фильтры.

Для примера, установим ограничение в 256 Кбит/с для пользователя,
находящегося в подсети «все остальные». Сначала добавим к «классу-подсети» новый
«класс-пользователь»:

# tc class add dev eth0 parent 1:15 classid 1:150 \
htb rate 256kbps

# tc filter add dev eth0 protocol ip parent 1:15 prio 1 \
u32 match ip src 172.16.1.32 flowid 1:150

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

Источник

Академический образовательный портал