From: Anton Shuko (SG) <sg@sg.tomsk.ru.>
Newsgroups: email
Date: Mon, 19 Dec 2005 14:31:37 +0000 (UTC)
Subject: Управление трафиком на роутере небольшой сети под Linux
Подключился я однажды к adsl и обнаружил, что хотя у него неплохие
характеристики 8/1 mbit in/out, но бывают ситуации, когда разные потоки
трафика начинают мешать работе, играм... Даже пинг до гейта поднимался с
8ms до 200-300ms. Усугубляло ситуацию, что я был не единственным пользователем
этого подключения. Т.е. я вдруг могу (хотя и нежелательно) притормозить выкачивание
чего-то, когда хочется поиграть в quake, но что делать с другими пользователями?
Зарезать их на время игры - это конечно сильно :) но нежелательно. Неудобно даже
свои процессы постоянно прибивать/запускать. Ну и просто портится КПД канала. Ради
нескольких процентов трафика и минимальных лагов убивать все остальное... Поэтому
начал копать то, что наваяли в линуксе для разделения траффика по приоритетам и
ограничения полосы. Применил это для роутера, который подключен в интернет через
adsl модем и раздает его пользователям через какой-то сетевой интерфейс (у меня
их несколько и они объединены в виртуальный интерфейс bridge). Хотя это можно
применять и для других ситуаций с некоторыми изменениями.
И результат этого представляю вам на растерзание :)
Для ограничения трафика я решил использовать только входящие в стандартное
ядро (2.4, 2.6) модули. Это QoS, netfilter и стандартны пакеты для работы с
ядром, входящие в большиство дистрибутивов iproute2, iptables. Для большинства
случаев этого достаточно.
Эксперименты показали, что эффективно управлять потоками пакетов можно только
при неполной загрузке канала в обоих направлениях. Т.е. нужно ограничить скорость
канала. Это очень важно! Достаточно забить одно направление на 100% и качество
связи упадет. Решать что важнее: ограничить пропускную способность канала на 10-30%
или маяться с лагами в момент, когда он полностью забит - личное дело каждого.
Я описываю метод с ограничением скорости канала.
Теперь совсем немного теории. Мы не можем управлять входящим трафиком, который
поступает adsl модему на вход. И это факт. Но большинство ip потоков зависят
от исходящего трафика и от дропания или задержки пакетов. Именно ip, а не
только tcpip. Так пишут во всех руководствах. Но я не буду управлять входящим
трафиком через задержку исходящего, как обычно советуют. Не потому что это
невозможно, а потому что это сложно и требуется долгая настройка, а потом и
постоянная подстройка.
Например: тянем что-то по ftp. Входящий трафик 8mbit, а исходящий всего 200kbit,
что в разы меньше пропускной способности исходящего канала. Т.е. для ограничения
входящего ftp трафика надо сделать исходящий меньше 200kbit. Но это только
примерная величина и её нужно подгонять. А ситуация может меняться...
Есть еще один важный момент: adsl модем - устройство с разной пропускной способностью
для исходящих и входящих пакетов. Поэтому нужно ограничивать исходящий с роутера
или сети трафик даже в том случае, если он не является подтверждением для входящих
потоков. Например, поставили у себя какой-то ftp/www/игровой сервер, а так же в сети
могут жить любители пирингового обмена. И своим небольшим (в 10 раз меньше входящего)
трафиком они могут сильно испортить качество канала. Значит нужно делить исходящий
трафик на исходящий с хоста или сети и подтверждение входящих пакетов.
Будем решать эту проблему в лоб, т.е. ограничивать исходящий трафик для исходящих
потоков отдельно и входящий для входящих тоже отдельно :) Для примера берем мою сеть.
ppp0 - интерфейс для выхода в интернет
br0 - интерфейс локальной сети
На ppp0 будем контролировать только исходящий трафик и все ограничения делать
исходя из скорости передачи adsl модема наружу. Политику ограничений строить так,
чтобы не забить исходящий канал и только. Кроме некоторых особых ситуаций.
На br0 будем контролировать тоже только исходящий трафик (стандартная
реализация QoS в линуксе не позволяет делать это для исходящего). Но т.к. это
маршрутизатор, то это будет и контроль входящего на ppp0 траффика :)
В обоих направлениях траффик делится на несколько каналов с разным уровнем
приоритета. Каждая канал имеет свою минимальную гарантированную полосу
пропускания и максимальную, доступную в случае, когда канал не занят более
приоритетным траффиком.
Если вы используете стандартное ядро из дистрибутива, то скорее всего все
нужное уже есть в модулях к нему и можете не читать следующий параграф.
Настройка ядра
Для тех, кто собирает ядра сам, я дам общие советы. Вряд ли они нуждаются в
разжевывании до мелочей :) Я буду давать названия для ядра 2.6. Для 2.4
используются аналогичные, но с другими путями. Сам я пользуюсь для конфигурации
командой make menuconfig и поэтому все будет описываться именно для этого
варианта конфигурации, но для случая make xconfig разницы никакой.
ICMP="match ip protocol 1 0xff"
TCP="match ip protocol 6 0xff"
UDP="match ip protocol 17 0xff"
DPORT="match ip dport"
SPORT="match ip sport"
SRC="match ip src"
DST="match ip dst"
U32="protocol ip u32"
Сделано это для запуска из ip-up/ip-down скрипта ppp.
xxx_OUT - относится к adsl интерфейсу, исходящему потоку.
xxx_IN - относится к интерфейсу локальной сети, но входящему на adsl модем
потоку :)
Ставлю ограничение 650kbit для исходящего потока и 6000kbit для входящего.
status(){
echo "[qdisc out]"
tc -s -d qdisc show dev $DEV_OUT
echo
echo "[class out]"
tc -s -d class show dev $DEV_OUT
echo
echo "[filter out]"
tc -s filter show dev $DEV_OUT
echo
echo "-----------------------------------------------------------------"
echo "[qdisc in]"
tc -s -d qdisc show dev $DEV_IN
echo
echo "[class in]"
tc -s -d class show dev $DEV_IN
echo
echo "[filter in]"
tc -s filter show dev $DEV_IN
exit
}
Без комментариев
stop(){
tc qdisc del dev $DEV_OUT root 2> /dev/null > /dev/null
tc qdisc del dev $DEV_IN root 2> /dev/null > /dev/null
}
Сбрасываю все в начальное состояние
start_out(){
ip link set dev $DEV_OUT qlen $QLEN_OUT mtu $MTU_OUT
tc qdisc add dev $DEV_OUT root handle 1: htb default 17
tc class add dev $DEV_OUT parent 1: classid 1:1 htb rate ${RATE_OUT}kbit
tc class add dev $DEV_OUT parent 1:1 classid 1:10 htb rate $[$RATE_OUT/8]kbit ceil $[$RATE_OUT/3]kbit prio 0
tc class add dev $DEV_OUT parent 1:1 classid 1:11 htb rate 20kbit prio 1
tc class add dev $DEV_OUT parent 1:1 classid 1:12 htb rate $[$RATE_OUT/8]kbit ceil $[$RATE_OUT/3]kbit prio 2
tc class add dev $DEV_OUT parent 1:1 classid 1:13 htb rate $[$RATE_OUT/8]kbit ceil $[$RATE_OUT/3]kbit prio 3
tc class add dev $DEV_OUT parent 1:1 classid 1:14 htb rate $[$RATE_OUT/8]kbit ceil $[$RATE_OUT/3]kbit prio 4
tc class add dev $DEV_OUT parent 1:1 classid 1:15 htb rate $[$RATE_OUT/8]kbit ceil ${RATE_OUT}kbit prio 5
tc class add dev $DEV_OUT parent 1:1 classid 1:17 htb rate $[$RATE_OUT/8]kbit ceil ${RATE_OUT}kbit prio 7
Разделил исходящий трафик на 8 полос с разным приоритетом и разной пропускной способностью
каждой полосы. Одну полосу (classid 1:16) пока ничем не занял - резерв.
rate - гарантированная полоса пропускания.
ceil - максимальная, если очереди с более высоким приоритетом незагружены
prio - приоритет полосы. 0 - максимальный
остальную абракадабру вычитывайте в документации
Еще один момент. Трафик, не попадающий в полосы 1:10 - 1:16, по умолчанию идет в 1:17
Ниже будут заданы фильтры, которые направляют пакеты в нужные полосы (классы).
Прошу обратить внимание на prio. Чем меньше, тем выше. Это не имеет отношения
к приоритету полос. Это приоритет для выборки пакета фильтром. Иначе может
получиться, что сначала отработает
Важный момент. Тут не отслеживается тип пакета. Формат udp и tcp пакета
одинаковый в самом начале и поэтому можно проверять условие на dest port сразу
для этих двух протоколов.
Самым приоритетным для меня считаются исходящие соединения на внешние ssh/telnet сервера.
К тому же я использую нестандартные порты типа 222, 2200 Так же хочу, чтобы эти
же сервисы, которые подняты на роутере, были доступны снаружи без тормозов.
Выше стоит максимальное ограничение скорости в 1/3. Нечего забивать
канал всякими scp и sftp !
Пропускаю тут запросы к днс серверам наружу. Так же у меня есть днс сервер на хосте
и он должен отвечать на запросы. С таким приоритетом маркировать пакеты для своих любимых
сетевых игр, именно поэтому максимальная скорость разрешена в 1/3
например:
Все прочие udp пакеты. Возможно, некоторые пиринговые сети будут жить в этой полосе.
Но в основном для игрушек, которые не попали в более приоритетную полосу.
Хочу использовать rdp на внешних серверах без сильных тормозов, но и не хочу
мешать игрушкам. Так же есть некий компьютер в локальной сети, на который можно
зайти по rdp снаружи. Где-то в другом скрипте сделан dnat.
Веб серфинг пусть получит приоритет повыше. Сюда же добавлять icq, irc, smtp, pop3 ...
Тут же ограничиваю свои веб и почтовые сервисы. Приоритет выше, чем у пакетов
по умолчанию.
echo "Outbound shaping added to $DEV_OUT. Rate: ${RATE_OUT}Kbit/sec."
}
К каждому классу добавляются алгоритмы обработки очереди
можно вместо sfq выбрать другой тип очереди, например esfq
esfq не входит в стандартное ядро и поэтому нужно устанавливать этот
модуль отдельно (http://fatooh.org/esfq-2.6/)
Процедура для ограничения исходящего трафика закончена.
Тут используются обычно src port вместо dst port, потому что это входящий трафик.
Хотя никто не мешает вам сделать другие политики и наслаждаться бардаком :)
tc qdisc add dev $DEV_IN parent 1:2 handle 2: pfifo
Использую самую простую и легкую для процессора очередь pfifo для исходящего
с роутера трафика (не транзитный!)
if [ $4 = "1.2.3.4" ]; then
/etc/iproute2/rt_add $5 # это у меня создаются дополнительные таблицы и маршруты роутинга
# для локальной сети и для самого роутера для своих, особых целей
/etc/ppp/adsl_qos start $1 $4
fi
в /etc/ppp/ip-down:
if [ $4 = "1.2.3.4" ]; then
/etc/iproute2/rt_del $5
/etc/ppp/adsl_qos stop $1 $4
fi
Проверку можно и не делать, но у меня еще есть и dialup сервер :) и/или
туннель на pppd
Все. Если циферки RATE_IN/RATE_OUT подобраны правильно, то максимальная пропускная
способность канала пострадает не сильно, но зато высокоприоритетные потоки
не будут лагать даже при сильной загрузке в обоих направлениях одновременно.
Скорость входящих потоков реально зажимается без прямого воздействия на
исходящие и дропы пакетов минимальны. Скорее всего это происходит из-за
притормаживания пакета в очереди. Разумеется, от флуда это не спасет, но эти
случаи лечат обычно административными методами.
Если критично, что ограничиваются пакеты на интерфейсе локальной сети,
то нужно ставить IMQ модуль и переносить обработку с $DEV_IN на интерфейс imq#
Часть информации и заготовка для скрипта взято отсюда:
http://gazette.linux.ru.net/rus/articles/adsl_bandwidth_management-howto.html
Другие полезные ссылки по QoS:
http://www.lartc.org
http://gazette.linux.ru.net/rus/articles/taleLinuxTC.html
http://luxik.cdi.cz/~devik/qos/htb/manual/userg.htm
tcp, udp пинг. Самое то для проверки работы QoS:
http://wiki.hping.org/
imq модуль для создания виртуального интерфейса. Появляется возможность обрабатывать
входящий трафик на ppp устройстве, а не на интерфейсе локальной сети:
http://www.linuximq.net/
esfq алгоритм обработки очереди. Полезен, когда нужно распределить канал
примерно поровну между пользователями, вне зависимости от того, сколько каждый
из них использует потоков. Давить наглых регетчиков-многопоточников!!! :)
http://fatooh.org/esfq-2.6/
Разные полезные модули. В том числе для борьбы с p2p:
http://kem.p.lodz.pl/~peter/qnet/
1010 Прочтений • [Управление трафиком на роутере небольшой сети под Linux (qos adsl traffic linux bandwidth iproute2 shaper)] [08.05.2012] [Комментариев: 0]