Ключевые слова:htb, cbq, bandwidth, limit, traffic, linux, iptables, imq, (найти похожие документы)
From: <Иван Песин (ipesin at post.Lviv.UA>
Date: Mon, 3 Oct 2003 14:31:37 +0000 (UTC)
Subject: Управление входящим и исходящим трафиком в Linux: HTB и IMQ
Оригинал: http://gazette.linux.ru.net/rus/articles/adsl_bandwidth_management-howto.html
ADSL Bandwidth Management HOWTO
Дэн Синглетери (Dan Singletary) <dvsing@sonicspike.net>
Перевод на русский: (с) Иван Песин (ipesin at post.Lviv.UA)
_________________________________________________________________
Содержание
1. Введение
1.1. Новые версии этого документа
1.2. Электронный список рассылки
1.3. Отказ от ответственности
1.4. Авторские права и лицензия
1.5. Обратная связь и исправления
2. Исходные данные
2.1. Предпосылки
2.2. Схема
2.3. Очереди пакетов
3. Как это работает
3.1. Ограничение исходящего трафика на Linux при помощи очереди HTB
3.2. Создание приоритетных очередей с алгоритмом HTB
3.3. Классификация исходящих пакетов при помощи iptables
3.4. Еще несколько наладок...
3.5. Попытка ограничить входящий трафик
4. Реализация
4.1. Пояснение
4.2. Скрипт: myshaper
5. Тестирование новой очереди
6. Хорошо, все работает!! Что дальше?
7. Ссылки по теме
1. Введение
Назначение данного документа -- привести пример управления исходящим
трафиком по ADSL (или кабельному) соединению с Internet. Проблема
заключается в том, что большинство ADSL-подключений ограничены
128Кбитами на исходящем потоке. Следовательно, при заполненной очереди
в ADSL-модеме, новым пакетам необходимо 2-3 секунды, что бы пройти
очередь и уйти в Internet. Это не позволяет комфортно работать с
интерактивными приложениями, такими как telnet и
многопользовательскими играми.
_________________________________________________________________
1.1. Новые версии этого документа
Последнюю версию этого документа всегда можно загрузить из Сети по
адресу: http://www.tldp.org.
Следующие версии этого документа так же загружаются на многие веб- и
ftp-сайты, связанные с Linux; в том числе на сайт LDP
http://www.tldp.org.
_________________________________________________________________
1.2. Электронный список рассылки
По вопросам управления полосой пропускания ADSL обращайтесь в список
рассылки ADSL Bandwidth Management
(http://jared.sonicspike.net/mailman/listinfo/adsl-qos)
_________________________________________________________________
1.3. Отказ от ответственности
Ни автор, ни распространители, ни любой другой контрибьютор данного
документа HOWTO, не несет никакой ответственности за физический,
финансовый, моральный или любой другой ущерб, понесенный при
выполнении рекомендаций данного документа.
_________________________________________________________________
1.4. Авторские права и лицензия
Авторскими правами на данный документ обладает Дэн Синглетери (Dan
Singletary), 2002. Документ распространяется в соответствии с
условиями лицензии GNU Free Documentation License.
_________________________________________________________________
1.5. Обратная связь и исправления
Если у вас есть вопросы или комментарии относительно этого документа,
с автором можно связаться по адресу dvsing@sonicspike.net. (mailto:dvsing@sonicspike.net)
_________________________________________________________________
2. Исходные данные
2.1. Предпосылки
Приведенный в этом документе метод должен работать на разных
Linux-конфигурациях, но проверялся он лишь на следующей:
* Red Hat Linux 7.3
* ядро 2.4.18-5 с полной поддержкой качества обслуживания (QoS) и
некоторыми дополнительными патчами (которые, возможно, будут
включены в последующие версии ядра):
+ Дисциплина обработки очереди HTB -
http://luxik.cdi.cz/~devik/qos/htb/ (http://luxik.cdi.cz/%7Edevik/qos/htb/)
Примечание: было отмечено, что в дистрибутивах Mandrake (8.1,
8.2) начиная с ядер версии 2.4.18-3 уже присутствует патч
HTB.
Прим.пер.: Дисциплина [обработки] очереди -- это алгоритм
обработки очереди пакетов. Для краткости, в тексте будет
употребляться словосочетание "очередь HTB".
+ Устройство IMQ - http://luxik.cdi.cz/~patrick/imq/ (http://luxik.cdi.cz/%7Epatrick/imq/)
* iptables v1.2.6a или старше (версия iptables поставляемая с Red
Hat 7.3 не содержит модуля проверки длины)
Замечание: предыдущие версии этого документа описывали метод
управления полосой пропускания для которого было необходимо
накладывать патч на очередь sch_prio. Позже выяснилось, что данный
патч совершенно не нужен. Не взирая ни на что, методы описанные в этом
документе обеспечат лучшие результаты (однако, на момент написания
данного документа, указанные два патча ядра являются необходимыми. :)
Удачного "патченья".)
_________________________________________________________________
2.2. Схема
Для упрощения, все упоминания сетевых устройств и конфигурации в этом
документе будут соответствовать нижеприведенной сетевой диаграмме:
<-- 128kbit/s -------------- <-- 10Mbit -->
Internet <--------------------> | ADSL-модем | <--------------------
1.5Mbit/s --> -------------- |
| eth0
V
----------------------
| Linux-маршрутизатор
----------------------
| .. | eth1..ethN
| |
V V
ЛВС
_________________________________________________________________
2.3. Очереди пакетов
Очереди пакетов -- это пулы, в которых хранятся данные сетевого
устройства, пока они не могут быть отправлены. Большинство очередей
используют алгоритм FIFO (первый пришел, первый ушел), если их
специальным образом не настраивали. Это означает, что только что
поступившие пакеты будут переданы лишь после того, как отправятся все
уже ожидающие отправки данные. Все это время, поступившие пакеты будут
сохранятся в очереди.
_________________________________________________________________
2.3.1. Исходящий поток
При использовании ADSL-модемов, полоса пропускания распределяется
ассиметрично, обычно на 1,5Мбитный входящий поток и 128Кбитный
исходящий. Но, несмотря на эти значения, обмен между
Linux-маршрутизатором и ADSL-модемом обычно осуществляется на скорости
10Мбит/с. Если же маршрутизатор подключен и к локальной сети на
скорости 10Мб/с, то никакой организации очередей для данных идущих из
ЛВС в Интернет осуществляться НЕ БУДЕТ. Пакеты будут отсылаться с eth0
с той же скоростью, с которой они получаются из локальной сети. В
результате, очередь сформируется в ADSL-модеме, поскольку туда они
поступают со скоростью 10Мбит/с, а отсылаются лишь со скоростью
128Кбит/с. В конце концов, когда очередь в ADSL-модеме переполнится,
приходящие пакеты будут просто уничтожаться. Протокол TCP обрабатывает
такое поведения, и соответствующим образом изменяет размер окна, чтобы
максимально эффективно использовать доступную полосу пропускания.
Хотя комбинация очередей пакетов и протокола TCP позволяет максимально
эффективно использовать полосу пропускания, большие очереди типа FIFO
могут вызвать значительные задержки трафика.
Другой тип очереди, похожий на FIFO -- это "n-полосная приоритетная
очередь". В ней вместо одной очереди пакетов используется n очередей
типа FIFO, в каждую из которых пакет попадает в зависимости от своего
типа. С помощью этой очереди можно задать для пакетов протокола FTP
более низкий приоритет, чем для пакетов telnet. Тогда, даже во время
загрузки с FTP-серверов, сеансы telnet сохранят интерактивность.
Этот документ был пересмотрен для использования нового алгоритма
обработки очередей в linux. Он называется Hierarchical Token Bucket
(HTB). Алгоритм HTB похож на алгоритм вышеописанной "n-полосной
приоритетной очереди", но позволяет задавать полосу пропускания для
каждого класса (каждой "полосы" - Прим.пер.) трафика. Кроме того, вы
можете определять классы трафика внутри других классов, таким образом
создавая иерархию классов. Полное описание HTB не входит в рамки
данного документа, за информацией обращайтесь на сайт
http://www.lartc.org (http://www.lartc.org/)
_________________________________________________________________
2.3.2. Входящий поток
Входящий трафик вашего ADSL-модема точно так же помещается в очередь,
только она находится у вашего провайдера. Из-за этого вы не можете
прямо контролировать как обрабатывается очередь и какому типу трафика
отдается приоритет. Единственный способ избежать задержек в этом
случае -- не позволять другим посылать к вам данные слишком быстро.
Но, к сожалению, вы не имеете контроля над скоростью входящего
трафика. Однако, учитывая что большая часть вашего трафика -- это TCP,
есть несколько путей замедлить входящий поток данных:
* Умышленно терять входящие пакеты: протокол TCP избегает перегрузки
каналов. Это значит, что при посылке данных, протокол TCP шлет
пакеты, пока они не начинают теряться. Этот момент определяется и
тогда уменьшается окно передачи протокола TCP. Такое поведение
длится на протяжении всей передачи данных, чтобы максимально
использовать доступную полосу пропускания.
* Манипулировать извещениями о размере окна: при передаче по
протоколу TCP, получатель шлет отправителю поток
пакетов-подтверждений (ACK). В такой ACK-пакет включается
информация о размере окна, то есть о максимальном разрешенном
количестве неподтвержденных пакетов. Управляя этим значением мы
можем принудительно понизить скорость передачи источника. На
данный момент не существует (свободной) Linux-реализации
управления потоком такого типа (хотя, возможно, я работаю над
таковой!).
_________________________________________________________________
3. Как это работает
Есть два основных шага, нужных для оптимизации исходящей полосы
пропускания. В первую очередь, мы должны найти способ не допускать
образования очереди в ADSL-модеме, поскольку там мы не имеем никакого
контроля над ней. Для того, чтобы это сделать мы ограничим полосу
пропускания интерфейса eth0 до значения немного меньшего, чем реальная
исходящая полоса ADSL-модема. Это приведет к тому, что очередь
образуется на Linux-маршрутизаторе.
Вторым шагом будет настройка приоритетного алгоритма обработки очереди
на маршрутизаторе. Ниже, мы познакомимся с алгоритмом, позволяющем
присвоить интерактивному трафику telnet и сетевых игр более высокий
приоритет, чем остальному.
Благодаря использованию очереди HTB стает возможным ограничить полосу
пропускания и выполнить приоритетную обработку очереди, не допуская
при этом "голодания" отдельных классов. Этого нельзя было достичь
применяя метод, описанный в 0.1 пересмотре этого документа.
Наконец, последним шагом будет настройка брандмауэра для маркировки
пакетов с помощью fwmark.
_________________________________________________________________
3.1. Ограничение исходящего трафика на Linux при помощи очереди HTB
Несмотря на то, что скорость соединения между маршрутизатором и
модемом 10Мбит/с, модем может отсылать данные со скоростью только
128кбит/с. Данные, которые модем получает с превышением этой скорости,
попадают в очередь. Следовательно, ping-пакет посланный с
маршрутизатора уйдет немедленно, но ему может понадобиться несколько
секунд, чтобы попасть в Internet, если очередь модема содержит
какие-то данные. К сожалению, большинство модемов ADSL не
предоставляют инструментов настройки алгоритмов обработки их очереди и
задания ее длины. Потому, наше первое задание заключается в изменении
места хранения исходящей очереди пакетов таким образом, чтобы мы могли
ею управлять.
Мы сделаем это при помощи очереди HTB: ограничим скорость посылки
пакетов к ADSL модему. Несмотря на то, что наша скорость исходящего
потока равна 128kbit/s, нам нужно будет ограничить скорость до
меньшего значения. Если мы хотим уменьшить задержки, нам необходимо
быть полностью УВЕРЕННЫМИ, что ни один пакет никогда не будет
задерживаться в модеме. С помощью экспериментов я обнаружил, что
ограничение исходящего потока данных до 90kbit/s обеспечивает мне
около 95% полосы пропускания, от той, что я получаю без использования
HTB. Настроив ограничение HTB с такой скоростью, мы избежим
образования очереди на ADSL модеме.
_________________________________________________________________
3.2. Создание приоритетных очередей с алгоритмом HTB
Замечание: предыдущие данные этого раздела (который раньше назывался
"Создание N-полосных приоритетных очередей") оказались не совсем
верные. Действительно, БЫЛА возможность классифицировать пакеты по
отдельным полосам приоритетной очереди только при помощи поля fwmark,
однако это было очень слабо документировано в 0.1 версии этого
документа
На данном этапе мы еще не выполнили никаких изменений в
производительности канала. Мы просто перенесли очередь FIFO из
ADSL-модема на маршрутизатор. Кроме того, по умолчанию размер очереди
Linux равен 100 пакетом, что еще хуже! Но не надолго...
Каждому классу в очереди HTB может быть назначен приоритет. Помещая
разные типы трафика в разные классы и задавая им приоритеты, мы можем
управлять обработкой очереди. HTB позволяет это делать, избегая
"голодания" других классов, поскольку можно задать минимальную
гарантированную скорость для каждого класса. Кроме того, HTB позволяет
нам сказать классу использовать свободную полосу пропускания другого
класса до определенного порога.
После того, как мы определим наши классы, нам будет нужно настроить
фильтрацию трафика по классам. Для этого существует несколько
способов, но в этом документе описан только один -- с использованием
известных программ iptables/ipchains, которые нужны для маркировки
пакетов. После чего, фильтры будут распределять трафик по классам HTB
очереди, основываясь на маркировке пакетов.
_________________________________________________________________
3.3. Классификация исходящих пакетов при помощи iptables
Примечание: изначально в этом документе использовалась утилита
ipchains. Теперь используется более новая утилита iptables.
Последним шагом в настройке вашего маршрутизатора для приоритезации
интерактивного трафика -- это настройка брандмауэра для маркировки
пакетов. Это делается установкой поля fwmark.
Не вдаваясь в подробности, ниже приведен простой пример, как можно
разбить исходящий трафик на четыре класса, с наивысшим классом 0x00:
1. Смаркировать ВСЕ пакеты как 0x03. Это поместит все пакеты в
очередь с наименьшим приоритетом.
2. Маркировать ICMP пакеты как 0x00. Мы хотим, чтобы ping показывал
нам задержку для класса с наибольшим приоритетом.
3. Маркировать все пакеты с портом назначения меньше 1024 как 0x01.
Это даст приоритет разным сетевым сервисам, типа Telnet и SSH.
Командный порт FTP также попадет в этот диапазон, однако передача
FTP-данных работает с портами выше 1024, потому он останется в
очереди 0x03.
4. Маркировать все пакеты с портом назначения 25 (SMTP) как 0x03.
Если кто-то пошлет почту с большим присоединением, это не
отразится на интерактивном трафике.
5. Маркировать все пакеты предназначенные для игрового сервера как
0x02. Это даст достаточный приоритет игрокам, но не отразится на
системных интерактивных приложениях.
Маркировать все "маленькие" пакеты как 0х02. Исходящих ACK пакеты
должны быстро уходить, чтобы загрузка выполнялась эффективней. Это
возможно при помощи специального модуля iptables.
Очевидно, что этот пример может быть модифицирован под ваши нужды.
_________________________________________________________________
3.4. Еще несколько наладок...
Есть еще две вещи, которые вы можете сделать для уменьшения задержек.
Во-первых, вы можете уменьшить значение mtu. Уменьшение этого значения
позволит уменьшить среднее время ожидания для посылки приоритетного
пакета, если максимальный пакет с меньшим приоритетом уже послан. Но
уменьшение этого значения также приведет к небольшой утере эффективной
полосы пропускания, поскольку каждый пакет несет в себе как минимум 40
байт заголовков протоколов IP и TCP.
Во-вторых, вы можете уменьшить длину вашей очереди со стандартных 100
пакетов, так как для посылки такого количества пакетов по ADSL линии
может потребоваться до 10 секунд, с mtu равным 1500 байтам.
_________________________________________________________________
3.5. Попытка ограничить входящий трафик
Используя Intermediate Queuing Device (IMQ), можно пропускать все
входящие пакеты через очередь, совершенно тем же образом, как и
исходящие. Приоритезация в этом случае намного проще. Поскольку мы
можем только (попытаться) контролировать входящий TCP трафик, мы
поместим весь не-TCP трафик в класс 0x00, а весь TCP трафик -- в класс
0x01. Кроме того мы можем поместить все "маленькие" TCP пакеты в класс
0x00, поскольку скорее всего это ACK пакеты к уже отосланным исходящим
пакетам. Для класса 0х00 мы будем использовать стандартную очередь
FIFO, а для класса 0х01 -- очередь Random Early Drop (RED). RED умеет
лучше чем FIFO (tail-drop) контролировать TCP, поскольку он начинает
терять пакеты до того, как очередь переполняется, с тем, что бы
попробовать понизить скорость входящего потока. Мы ограничим оба
класса до некоторой максимальной скорости, которая немного меньше
настоящего максимума вашего ADSL модема.
_________________________________________________________________
3.5.1. Почему сложно организовать ограничение скорости входящего трафика
Мы хотим ограничить скорость входящего трафика, чтобы избежать
переполнения очереди у провайдера, который иногда буфферизирует до
пяти секунд потока данных. Проблема заключается в том, что на данный
момент существует единственный способ это сделать -- терять заведомо
корректные пакеты. А эти пакеты уже отняли часть полосы пропускания
вашего ADSL модема и лишь для того, чтобы быть уничтожеными в надежде,
что следующие пакеты будут прибывать с меньшей скоростью. Утерянные
пакеты будут переданы повторно. что в конечном счете займет больше
полосы пропускания. Когда мы ограничиваем трафик, мы ограничиваем
количество пакетов в момент времени допускаемых в нашу сеть. Потому
фактическая скорость входящего потока выше, из-за пакетов которые мы
уничтожаем. В результате, нам будет необходимо ограничить нашу
скорость входящего потока намного ниже, чем действительная скорость
ADSL модема чтобы достичь малой задержки. На практике, мне пришлось
ограничить мой 1.5Мбит/сек ADSL модем до 700Кбит/сек с тем, чтобы
обеспечить приемлемую задержку при пяти одновременных закачках. Чем
больше у вас TCP соединений, тем большая часть полосы пропускания
будет теряться, и тем ниже вам придется ставить ограничение скорости.
Намного лучший способ управления входящим TCP трафиком заключается в
манипулировании окном TCP, но на время написания этого документа не
существует ни одного такого (свободного) решения для Linux (насколько
я знаю...).
_________________________________________________________________
4. Реализация
После всех объяснений, пришло время реализовать управления полосой
пропускания на Linux.
_________________________________________________________________
4.1. Пояснение
Задача ограничения скорости трафика посылаемого к DSL-модему не так
проста, как это может показаться. Большинство DSL модемов -- это
ethernet-мосты, которые просто передают данные между вашим
linux-маршрутизатором и шлюзом вашего провайдера. Опять же,
большинство модемов используют протокол ATM для передачи данных на
канальном уровне. ATM передает данные фиксированными фрагментам по 53
байта. Из них 5 байт -- это заголовок, а 48 оставшихся байт
используются для данных. Даже если вы шлете 1 байт данных, полоса
пропускания используется на 53 байта, поскольку размер ячейки ATM
равен 53 байтам. Это значит, что если вы передаете обычный пакет TCP
ACK, который состоит из 0 байт данных + 20 байт заголовка TCP + 20
байт заголовка IP + 18 байт заголовка Ethernet. В действительности же,
несмотря на то, что полезных данных всего 40 байт (заголовки TCP и
IP), минимальное количество данных в одном Ethernet-пакете равно 46
байтам, потому оставшиеся 6 байт будут заполнены нулями. В свою
очередь это значит, что размер пакета Ethernet плюс заголовок будет
равен 18 + 46 = 64 байтам.Для того, чтобы отправить 64 байта данных по
ATM, нужно передать две ячейки ATM, которые займут 106 байт трафика.
Следовательно, на каждом TCP ACK пакете вы теряете 42 байта полосы
пропускания. Все было бы нормально, если бы Linux рассчитывал
инкапсуляцию, используемую DSL модемом, но Linux учитывает лишь
заголовки TCP, IP и 14 байт MAC адреса (Linux не учитывает 4 байта
контрольной суммы, поскольку это обрабатывается на аппаратном уровне).
Linux не считает минимальный пакет Ethernet равным 46, но и не
учитывает фиксированный размер ячейки ATM.
Все это значит, что вам будет нужно ограничить исходящий поток до
немного меньшей скорости, чем ваша реальная (до тех пор, пока у нас не
будет пакетного планировщика, учитывающего разные использующиеся типы
инкапсуляции). Вам может показаться, что вы выбрали неплохое
ограничение полосы пропускания, но когда вы начнете загружать что-то
большое, обнаружится что задержка превышает 3 секунды. Скорее всего,
это связано именно с этими маленькими ACK-пакетами, неучтенными Linux.
Я работал над решением этой проблемы в течении нескольких месяцев и
достиг кое-каких результатов, которые вскоре будут доступны для
тестирования. Решение основано на использовании очереди
пользовательского уровня, вместо системы качества обслуживания linux.
Я реализовал простую HTB-очередь в пользовательском пространстве. Это
решение (пока что) умеет регулировать исходящий трафик НАСТОЛЬКО
ХОРОШО, что даже при массовой загрузке (несколько потоков) и сильном
исходящем трафике (gnutella, несколько потоков) ПИКОВЫЕ задержки равны
400ms, в то время как на свободном канале они равны 15ms. За подробной
информацией об этом методе QoS обращайтесь в список рассылки, или
проверяйте этот документ на предмет обновлений.
_________________________________________________________________
4.2. Скрипт: myshaper
Ниже приведен листинг скрипта, который я использую для контроля над
полосой пропускания на моем Linux-маршрутизаторе. Он использует
некоторые из концепций приведенных в этом документе. Исходящий трафик
распределяется в 7 очередей, в зависимости от его типа. Входящий
трафик распределяется по двум очередям, причем пакеты TCP имеют
меньший приоритет. Ограничения приведенные в скрипте неплохо работают
в моей конфигурации, но для вас их возможно придется менять.
Этот скрипт основан на ADSL WonderShaper, с сайта LARTC (http://www.lartc.org/) website.
#!/bin/bash
#
# myshaper - Скрипт установки приоритетов и ограничения трафика для DSL/кабельн
ых модемов.
# Основан на ADSL/Cable wondershaper (www.lartc.org)
#
# Написан Дэном Синглетери (Dan Singletary 8/7/02)
#
# ПРИМЕЧАНИЕ!! - Полагается, что ваше ядро имеет соответствующие патчи
# для поддержки очереди HTB и устройства IMQ. Эти патчи
# доступны по адресам:
# (дополнение: будущие ядра могут включать указанные патчи)
#
# http://luxik.cdi.cz/~devik/qos/htb/
# http://luxik.cdi.cz/~patrick/imq/
#
# Конфигурационные настройки для myshaper:
# DEV - укажите интерфейс "ethX", к которому подключен DSL/кабельный модем
# RATEUP - укажите здесь значение, которое несколько ниже
# исходящей пропускной способности DSL/кабельного модема.
# У меня есть DSL-линия с параметрами 1500/128. Мне подошло
# значение RATEUP=90 для исходящего потока в 128kbps.
# Однако, в вашем случае это значение может быть другим.
# RATEDN - укажите здесь значение, несколько меньшее входящей
# пропускной возможности DSL/кабельного модема.
#
#
# Немного теории по использованию imq для ограничения входящего потока:
#
# Нет никакой возможности прямо ограничить скорость с которой информация
# шлется к вам другими хостами в Internet. Для ограничения входящего
# потока, мы должны положиться на алгоритмы избежания перегрузок протокола
# TCP. Следовательно, МЫ МОЖЕМ ЛИШЬ ПОПЫТАТЬСЯ ОГРАНИЧИТЬ СКОРОСТЬ
# ВХОДЯЩЕГО ПОТОКА TCP СОЕДИНЕНИЙ. Это значит, что весь не-tcp трафик
# должен помещаться в высокоприоритетный класс, поскольку уничтожение
# не-tcp пакетов скорее всего приведет к их повторной передаче, которая
# будет только увеличивать загрузку канала.
# Мы попробуем ограничить входящий TCP трафик с помощью потери tcp пакетов,
# когда переполнится очередь HTB. Сама очередь будет настроена на пропускную
# способность (RATEDN) немного меньшую реальной входящей пропускной
# способности. С помощью потери TCP пакетов, мы сэмулируем ситуацию
# аналогичную переполнению очереди у нашего провайдера. Преимущество этого
# метода в том, что у нашего провайдера очередь переполняться не будет,
# потому что протокол TCP будет понижать скорость передачи в ответ на
# потерю пакетов.
# Выгода от использования приоритетной дисциплины обработки очереди
# заключается в том, что мы можем задать типы трафика, пакеты котороых
# НЕ будут теряться, помещая их в высокоприоритетные очереди (ssh,
# telnet, etc). Этот способ работает благодаря тому, что в первую очередь
# обрабатываются приоритетные пакеты, однако, при этом пакеты из остальных
# очередей все равно будут получать минимальную гарантированую полосу
# пропускания (в данном скрипте каждая очередь получает как минимум
# 1/7 часть полосы пропускания).
#
# Повторим ключевые моменты:
# * Потеря tcp-пакета ведет к понижению скорости передачи пакетов
# передающим узлом, благодаря алгоритму предотвращения перегрузок.
# * Мы не получаем никакой выгоды от потери не-ТСP пакетов. Фактически, если
# эти пакеты важны, они будут переданы повторно. Поэтому мы попытаемся никогда
# не терять такие пакеты. Это означает, что интенсивные TCP-соединения не
# будут влиять на другие протоколы, не поддерживающие повторную передачу как TCP.
# * Понижение скорости входящего TCP-трафика следует выполнять так, чтобы
# суммарная пропускная способность была ниже, чем физическая пропускная возможность
# устройства (ADSL/кабельного модема). Это нужно для того, чтобы пакеты не
# задерживались в очереди у провайдера (DSLAM, кабельном концентраторе, и т.п.).
# Поскольку, по наблюдениям, это оборудование помещает в очередь примерно 4 секунды
# потока данных на скорости 6 мегабит, отсутствие этой очереди означает меньшее
# время задержки.
#
# Объяснение (вопросы, возникающие до тестирования):
# * Скажется ли ограничение входящего трафика этим способом на производительности при
# больших закачках?
# - Сразу отвечу: нет! Если повысить приоритет ACK-пакетов (размер <64б)
# мы сможем максимально использовать полосу пропускания, не тратя ее на
# повторную передачу уже полученных пакетов.
#
# ПРИМЕЧАНИЕ: Следующая настройка предназначения для моего соединения:
# 1.5M/128K ADSL via Pacific Bell Internet (SBC Global Services)
DEV=eth0
RATEUP=90
RATEDN=700 # Обратите внимание, что это значительно меньше реального значения
1500.
# Из-за этого вы можете не захотеть использовать ограничение входящего трафика
# пока оно не будет реализовано лучше, например на основе изменения размера окна.
#
# Конец раздела настроек
#
if [ "$1" = "status" ]
then
echo "[qdisc]"
tc -s qdisc show dev $DEV
tc -s qdisc show dev imq0
echo "[class]"
tc -s class show dev $DEV
tc -s class show dev imq0
echo "[filter]"
tc -s filter show dev $DEV
tc -s filter show dev imq0
echo "[iptables]"
iptables -t mangle -L MYSHAPER-OUT -v -x 2> /dev/null
iptables -t mangle -L MYSHAPER-IN -v -x 2> /dev/null
exit
fi
# Сбросить все в известное состояние (очищеное)
tc qdisc del dev $DEV root 2> /dev/null > /dev/null
tc qdisc del dev imq0 root 2> /dev/null > /dev/null
iptables -t mangle -D POSTROUTING -o $DEV -j MYSHAPER-OUT 2> /dev/null > /dev/null
iptables -t mangle -F MYSHAPER-OUT 2> /dev/null > /dev/null
iptables -t mangle -X MYSHAPER-OUT 2> /dev/null > /dev/null
iptables -t mangle -D PREROUTING -i $DEV -j MYSHAPER-IN 2> /dev/null > /dev/null
iptables -t mangle -F MYSHAPER-IN 2> /dev/null > /dev/null
iptables -t mangle -X MYSHAPER-IN 2> /dev/null > /dev/null
ip link set imq0 down 2> /dev/null > /dev/null
rmmod imq 2> /dev/null > /dev/null
if [ "$1" = "stop" ]
then
echo "Shaping removed on $DEV."
exit
fi
###########################################################
#
# Ограничение исходящего потока (ограничивает пропускную способность до RATEUP)
# установить размер очереди, соответствующий двухсекундной задержке на низкоприоритетном трафике
ip link set dev $DEV qlen 30
# изменяем значение mtu на исходящем устройстве. Понижение значения mtu уменьшит задержку, но
# и немного понизит пропускную способность из-за увеличения числа
# заголовков протоколов IP и TCP .
ip link set dev $DEV mtu 1000
# добавить корневую дисциплину HTB
tc qdisc add dev $DEV root handle 1: htb default 26
# добавить общее ограничение скорости по классу
tc class add dev $DEV parent 1: classid 1:1 htb rate ${RATEUP}kbit
# добавляем подклассы - мы гарантируем каждаму классу МИНИМУМ "честную часть" полосы пропускания.
# Этим способом мы избегаем возможности "голодания" классов. Каждому классу
# разрешается занимать всю полосу пропускания, если другие классы не
# используются.
tc class add dev $DEV parent 1:1 classid 1:20 htb rate $[$RATEUP/7]kbit ceil ${RATEUP}kbit prio 0
tc class add dev $DEV parent 1:1 classid 1:21 htb rate $[$RATEUP/7]kbit ceil ${RATEUP}kbit prio 1
tc class add dev $DEV parent 1:1 classid 1:22 htb rate $[$RATEUP/7]kbit ceil ${RATEUP}kbit prio 2
tc class add dev $DEV parent 1:1 classid 1:23 htb rate $[$RATEUP/7]kbit ceil ${RATEUP}kbit prio 3
tc class add dev $DEV parent 1:1 classid 1:24 htb rate $[$RATEUP/7]kbit ceil ${RATEUP}kbit prio 4
tc class add dev $DEV parent 1:1 classid 1:25 htb rate $[$RATEUP/7]kbit ceil ${RATEUP}kbit prio 5
tc class add dev $DEV parent 1:1 classid 1:26 htb rate $[$RATEUP/7]kbit ceil ${RATEUP}kbit prio 6
# подключаем дисциплины обработки очереди к подклассам - здесь мы используем SFQ для каждого класса.
# SFQ обеспечит почти честное деление полосы пропусканиямежду соединениями
# внутри каждого класса.
tc qdisc add dev $DEV parent 1:20 handle 20: sfq perturb 10
tc qdisc add dev $DEV parent 1:21 handle 21: sfq perturb 10
tc qdisc add dev $DEV parent 1:22 handle 22: sfq perturb 10
tc qdisc add dev $DEV parent 1:23 handle 23: sfq perturb 10
tc qdisc add dev $DEV parent 1:24 handle 24: sfq perturb 10
tc qdisc add dev $DEV parent 1:25 handle 25: sfq perturb 10
tc qdisc add dev $DEV parent 1:26 handle 26: sfq perturb 10
# направляем трафик в классы по fwmark - мы направляем трафик в классы, в соответствии со значением
# fwmark установленном на пакете (мы будем устанавливать это
# значение утилитой iptables позже). Обратите внимание, что
# выше мы установили класс по умолчанию1:26, так что
# немаркированные пакеты (или с неизвестными значениями fwmark
# будут направлены в низкоприоритетный класс.
tc filter add dev $DEV parent 1:0 prio 0 protocol ip handle 20 fw flowid 1:20
tc filter add dev $DEV parent 1:0 prio 0 protocol ip handle 21 fw flowid 1:21
tc filter add dev $DEV parent 1:0 prio 0 protocol ip handle 22 fw flowid 1:22
tc filter add dev $DEV parent 1:0 prio 0 protocol ip handle 23 fw flowid 1:23
tc filter add dev $DEV parent 1:0 prio 0 protocol ip handle 24 fw flowid 1:24
tc filter add dev $DEV parent 1:0 prio 0 protocol ip handle 25 fw flowid 1:25
tc filter add dev $DEV parent 1:0 prio 0 protocol ip handle 26 fw flowid 1:26
# добавить цепочку MYSHAPER-OUT в таблицу mangle - сейчас мы настроим таблицу,которую будем
# использовать для фильтрациии установки fwmark
iptables -t mangle -N MYSHAPER-OUT
iptables -t mangle -I POSTROUTING -o $DEV -j MYSHAPER-OUT
# маркируем пакеты с помощью fwmark - устанавливаем значения 20-26 в зависимости от
# нужного класса. Высший приоритет - 20.
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport 0:1024 -j MARK --set-mark 23
# Низкоприоритетный трафик
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 0:1024 -j MARK --set-mark 23
# ""
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 20 -j MARK --set-mark 26
# порт ftp-data, низкий приоритет
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 5190 -j MARK --set-mark 23
# интернет-пейджер aol
iptables -t mangle -A MYSHAPER-OUT -p icmp -j MARK --set-mark 20
# ICMP (ping) - высокий приоритет,
# будем удивлять друзей
iptables -t mangle -A MYSHAPER-OUT -p udp -j MARK --set-mark 21
# распознавание имен DNS (маленькие пакеты)
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport ssh -j MARK --set-mark 22
# secure shell
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport ssh -j MARK --set-mark 22
# secure shell
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport telnet -j MARK --set-mark 22
# telnet (ew...)
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport telnet -j MARK --set-mark 22
# telnet (ew...)
iptables -t mangle -A MYSHAPER-OUT -p ipv6-crypt -j MARK --set-mark 24
# IPSec - мы не знаем полезную нагрузку, однако...
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport http -j MARK --set-mark 25
# локальный веб-сервер
iptables -t mangle -A MYSHAPER-OUT -p tcp -m length --length :64 -j MARK --set-mark 21 # маленькие пакеты
# скорее всего ACK-пакеты
iptables -t mangle -A MYSHAPER-OUT -m mark --mark 0 -j MARK --set-mark 26
# избыточно - смаркировать все неотмаркированые
# пакеты как 26 (низкий проиритет)
# Конец ограничения исходящего потока
#
####################################################
echo "Outbound shaping added to $DEV. Rate: ${RATEUP}Kbit/sec."
# Раскомментируйте следующую строку, если хотите ограничить только исходящий трафик.
# exit
####################################################
#
# Ограничение входящего потока (ограничивает пропускную способность до RATEDN)
# убедимся, что модуль imq загружен
modprobe imq numdevs=1
ip link set imq0 up
# добавляем дисциплину - низкоприоритетный класс по умолчанию 1:21
tc qdisc add dev imq0 handle 1: root htb default 21
# добавляем общее ограничение скорости по классу
tc class add dev imq0 parent 1: classid 1:1 htb rate ${RATEDN}kbit
# добавляем подклассы - TCP traffic in 21, non TCP traffic in 20
#
tc class add dev imq0 parent 1:1 classid 1:20 htb rate $[$RATEDN/2]kbit ceil ${RATEDN}kbit prio 0
tc class add dev imq0 parent 1:1 classid 1:21 htb rate $[$RATEDN/2]kbit ceil ${RATEDN}kbit prio 1
# подключаем дисциплины обработки очереди к подклассам - здесь мы используем SFQ для каждого класса.
# SFQ обеспечит почти честное деление полосы пропусканиямежду соединениями
# внутри каждого класса.
tc qdisc add dev imq0 parent 1:20 handle 20: sfq perturb 10
tc qdisc add dev imq0 parent 1:21 handle 21: red limit 1000000 min 5000 max 100000 avpkt 1000 burst 50
# направляем трафик в классы по fwmark - мы направляем трафик в классы, в соответствии со значением
# fwmark установленном на пакете (мы будем устанавливать это
# значение утилитой iptables позже). Обратите внимание, что
# выше мы установили класс по умолчанию1:26, так что
# немаркированные пакеты (или с неизвестными значениями fwmark
# будут направлены в низкоприоритетный класс.
tc filter add dev imq0 parent 1:0 prio 0 protocol ip handle 20 fw flowid 1:20
tc filter add dev imq0 parent 1:0 prio 0 protocol ip handle 21 fw flowid 1:21
# добавить цепочку MYSHAPER-OUT в таблицу mangle - сейчас мы настроим таблицу,которую будем
# использовать для фильтрациии установки fwmark
iptables -t mangle -N MYSHAPER-IN
iptables -t mangle -I PREROUTING -i $DEV -j MYSHAPER-IN
# маркируем пакеты с помощью fwmark - устанавливаем значения 20-26 в зависимости от
# нужного класса. Высший приоритет - 20.
iptables -t mangle -A MYSHAPER-IN -p ! tcp -j MARK --set-mark 20 #
# Маркировать не-tcp пакеты как высокоприоритетные
iptables -t mangle -A MYSHAPER-IN -p tcp -m length --length :64 -j MARK --set-mark 20 # маленькие TCP-пакеты - вероято ACK
iptables -t mangle -A MYSHAPER-IN -p tcp --dport ssh -j MARK --set-mark 20 # secure shell
iptables -t mangle -A MYSHAPER-IN -p tcp --sport ssh -j MARK --set-mark 20 # secure shell
iptables -t mangle -A MYSHAPER-IN -p tcp --dport telnet -j MARK --set-mark 20 # telnet (ew...)
iptables -t mangle -A MYSHAPER-IN -p tcp --sport telnet -j MARK --set-mark 20 # telnet (ew...)
iptables -t mangle -A MYSHAPER-IN -m mark --mark 0 -j MARK --set-mark 21 # избыточно - маркировать немаркированные
#
пакеты как 26 (низкий приоритет)
# Наконец, пропустить все эти пакеты через imq0
iptables -t mangle -A MYSHAPER-IN -j IMQ
# Конец ограничения входящего потока
#
####################################################
echo "Inbound shaping added to $DEV. Rate: ${RATEDN}Kbit/sec."
_________________________________________________________________
5. Тестирование новой очереди
Самый простой способ проверить ваши настройки -- занять канал
низкоприоритетным трафиком. Как это сделать зависит от ваших настроек.
Будем считать, что вы пометили трафик telnet и ping в
высокоприоритетную очередь (меньшее значение fwmark), следовательно
порты выше 1024 (которые используются при FTP-передаче) имеют меньший
приоритет. Теперь, если вы инициируете FTP загрузку на удаленный узел,
для того чтобы занять канал и запустите ping на ваш шлюз (хост с
другой стороны DSL линии), то заметите, что время задержки возросло
незначительно по сравнению с тем, что было до настройки приоритетов.
Задержки до100ms обычно говорят о верной настройке, тогда как задержка
более одной-двух секунд означает неверную настройку.
_________________________________________________________________
6. Хорошо, все работает!! Что дальше?
Теперь, когда вы успешно начали управлять своей полосой пропускания,
вам стоит задуматься над тем как это использовать. Как-никак вы за это
же платите?!
* Пользуйтесь клиентом Gnutella и ПРЕДОСТАВЛЯЙТЕ ДОСТУП К СВОИМ
ФАЙЛАМ без существенного снижения производительности сетевого
соединения
* Запустите свой веб-сервер, который не будет мешать вам играть в
Quake
_________________________________________________________________
7. Ссылки по теме
* Bandwidth Controller для Windows - http://www.bandwidthcontroller.com
* dsl_qos_queue (http://www.sonicspike.net/software#dsl_qos_queue) - (beta) для Linux.
Нет необходимости в патченьи ядра, улучшенная производительность
Copyright (c) 2001-2003, Dan Singletary
> Манипулировать извещениями о размере окна: при передаче по протоколу TCP, получатель шлет отправителю поток пакетов-подтверждений (ACK). В такой ACK-пакет включается информация о размере окна, то есть о максимальном разрешенном количестве неподтвержденных пакетов. Управляя этим значением мы можем принудительно понизить скорость передачи источника. На данный момент не существует (свободной) Linux-реализации управления потоком такого типа (хотя, возможно, я работаю над таковой!).
Статья старая. Но проблема до сих пор актуальная. Решена ли она сейчас в далеком будущем?