полезное по линуксу и iphone собрано все интересное мне лично (методом copy-paste из инета и не пыхтите насчет копирайта я ссылки на источник ставлю)

Показаны сообщения с ярлыком htb. Показать все сообщения
Показаны сообщения с ярлыком htb. Показать все сообщения

пятница, 26 ноября 2010 г.

Шейпирование трафика в Linux. Часть 2

Вторая часть статьи об управлении трафиком в Linux. В статье приведены примеры приоретизации трафика (QoS) и рассказано об использовании hash таблиц при фильтрации трафика (fast hash tables), использование которых позволяет существенно увеличить производительность.
В первой части мы остановились на генерации конфигов средней сложность для htbinit. Сегодня мы поговорим о приоретизации трафика и использовании хэш таблиц в фильтрах. Я подразумеваю, что Вы прочитали первую часть статьи .
Предположим, что нам надоели замечания пользователей о высоком пинге, надоели постоянные детские вопли на форуме о том, что в counter-strike играть невозможно: «лаги страшные», или «у меня странички медленно грузятся, вконтакте открывался 10 минут», а писать что все замеры нужно производить при отключенном «торренте» уже нету сил.
Посему тто бы наша совесть была чиста, и мы могли не кривя душой сказать: «проблема на стороне провайдера предоставляющего данный сервис»(обозначить направление движения в сторону южного полюса) — озаботимся приоретизацией трафика.

Приоритеты выставим в таком порядке:
1. icmp
2. udp
3. tcp port 80
4. bulk traffic

Рассмотрим ограничение полосы на внутреннем интерфейсе, управлять будем «скоростью скачивания».
Напомню.
В простом варианте изложения алгоритм нарезки трафика выглядит так:
1. Создаем корневую дисциплину для интерфейса и указываем класс куда будет попадать не классифицированный трафик.
2. Создаем корневой класс и определяем ширину канала.
3. Создаем дочерний класс для шейпирования абонента.
4. Создаем дисциплину шейпирования для класса абонента.
5. Создаем фильтра позволяющие классифицировать трафик абонента.

Пример

#!/bin/bash

#"Очищаем" интерфейс eht1
/sbin/tc qdisc del dev eth1 root handle 1: htb default 15
#Создаем заново дисциплину и указываем дефолтный класс
/sbin/tc qdisc add dev eth1 root handle 1: htb default 15
#Создаем общий для клиентов класс
/sbin/tc class add dev eth1 parent 1: classid 1:1 htb rate 10Mbit ceil 10Mbit

#Создаем корневой класс клиента
/sbin/tc class add dev eth1 parent 1:1 classid 1:10 htb rate 512kbit ceil 512kbit

#Создаем 4 подкласса для каждого из видов трафика
/sbin/tc class add dev eth1 parent 1:10 classid 1:11 htb rate 1kbit ceil 512kbit prio 1
/sbin/tc class add dev eth1 parent 1:10 classid 1:12 htb rate 1kbit ceil 512kbit prio 2
/sbin/tc class add dev eth1 parent 1:10 classid 1:13 htb rate 1kbit ceil 512kbit prio 3
/sbin/tc class add dev eth1 parent 1:10 classid 1:14 htb rate 1kbit ceil 512kbit prio 4

#Создаем дисциплины шейпирования для конечных классов
/sbin/tc qdisc add dev eth1 parent 1:11 handle 11: sfq perturb 10
/sbin/tc qdisc add dev eth1 parent 1:12 handle 12: sfq perturb 10
/sbin/tc qdisc add dev eth1 parent 1:13 handle 13: sfq perturb 10
/sbin/tc qdisc add dev eth1 parent 1:14 handle 14: sfq perturb 10

Создаем 4 фильтра, для каждого из видов трафика
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 1 u32 match ip dst 192.168.2.2/32 match ip protocol 1 0xff flowid 1:11
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 2 u32 match ip dst 192.168.2.2/32 match ip protocol 17 0xff flowid 1:12
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 3 u32 match ip dst 192.168.2.2/32 match ip protocol 6 0xff match ip sport 80 0xffff flowid 1:13
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 4 u32 match ip dst 192.168.2.2/32 flowid 1:14


* This source code was highlighted with Source Code Highlighter.


Думаю из примера видно, что для реализации приоретизиции трафика мы создали для каждого отдельный класс. Далее создаем фильтры, причем чем меньше prio, тем больше у трафика приоритет. Вообще правила обрабатываются согласно тому как их добавляли, в случае с приоритетами — первыми обслуживаются правила, имеющие наивысший приоритет.
Так же вы можете каждому из классов обзначить RATE равный одной четвертой от RATE корневого класса клиента, что бы уже наверняка.
Хочу обратить внимание, на то что нам пришлось создать 4 фильтра, для оного ип, а если ип 3-4 тысячи, то получим огромный линейный список правил — в итоге производительность упадет ниже плинтуса.
Что бы этого избежать воспользуемся «быстрыми» хэш таблицами.
О том, что такое хэш таблицы Вы можете посмотреть на Википедии.
Создадим 4 таблицы по 256 ячеек, каждая из таблиц будет оценивать один из октетов ип адреса.
И в конечном итоге, вместо поиска по всему списку, как это было бы в классическом варианте, мы уменьшим количество проверок и значительно снизим нагрузку.
Пример.
#Создаем корневой фильтр
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32
#Создаем 4 хеш таблицы для каждого октета
/sbin/tc filter add dev eth1 parent 1:0 handle 10: protocol ip u32 divisor 256
/sbin/tc filter add dev eth1 parent 1:0 handle 11: protocol ip u32 divisor 256
/sbin/tc filter add dev eth1 parent 1:0 handle 12: protocol ip u32 divisor 256
/sbin/tc filter add dev eth1 parent 1:0 handle 13: protocol ip u32 divisor 256
#Создаем фильтр направлящий весь трафик в хеш таблицу с ID 10
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 801:: match ip dst 0.0.0.0/0 hashkey mask 0xff000000 at 16 link 10:
#Добавляем правило в 10 хеш таблицу, если первый октет равен 192, то оправляем пакет в 11 хеш таблицу
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 10:c0: match ip dst 192.0.0.0/8  hashkey mask 0xff0000 at 16 link 11:
#Добавляем правило в 11 хеш таблицу, если второй октет равен 168, то оправляем пакет в 12 хеш таблицу
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 11:a8: match ip dst 192.168.0.0/16 hashkey mask 0xff00 at 16 link 12:
#Добавляем правило в 12 хеш таблицу, если третий октет равен 2, то оправляем пакет в 13 хеш таблицу
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 12:2: match ip dst 192.168.2.0/24 hashkey mask 0xff at 16 link 13:

#Добавляем правила в 13 хеш таблицу, оцениваем 4 октет и направляем в необходимый класс, в зависимости от вида трафика
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 1 u32 ht 13:2: match ip dst 192.168.2.2/32 match ip protocol 1 0xff flowid 1:11
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 2 u32 ht 13:2: match ip dst 192.168.2.2/32 match ip protocol 17 0xff flowid 1:12
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 3 u32 ht 13:2: match ip dst 192.168.2.2/32 match ip protocol 6 0xff match ip sport 80 0xffff flowid 1:13
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 4 u32 ht 13:2: match ip dst 192.168.2.2/32 flowid 1:14


* This source code was highlighted with Source Code Highlighter.

Ниже приведен листинг скрипка генерирующего правила для tc включающие в себя приоретизацию и хеш фильтры.
Скрип полностью рабочий, думаю не составит большого труда модифицировать его под себя.
При переходе с линейных фильтров на хеш таблицы нагрузка упала почти в 4 раза.
#!/bin/bash
mysql="mysql -ppass -u user -h host"
#создаем корневуй дсциплину, класс, корневой фильтр и тиблицы хешей для внешних интерфейсов
echo "select ext_iface from system.shaper_view group by ext_iface;"|$mysql|sed 1d|
awk '{
print "/sbin/tc qdisc del dev "$1" root handle 1: htb default 15";
print "/sbin/tc qdisc add dev "$1" root handle 1: htb default 15";
print "/sbin/tc class add dev "$1" parent 1: classid 1:1 htb rate 10Mbit ceil 10Mbit";
print "/sbin/tc filter add dev "$1" parent 1:1 prio 10 protocol ip u32";
print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 10: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 11: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 12: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 13: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32 ht 801:: match ip dst 0.0.0.0/0 hashkey mask 0xff000000 at 16 link 10:";
}'

#создаем корневуй дсциплину, класс, корневой фильтр и тиблицы хешей для внутренних интерфейсов
echo "select int_iface from system.shaper_view group by int_iface;"|$mysql|sed 1d|
awk '{
print "/sbin/tc qdisc del dev "$1" root handle 1: htb default 15";
print "/sbin/tc qdisc add dev "$1" root handle 1: htb default 15";
print "/sbin/tc class add dev "$1" parent 1: classid 1:1 htb rate 10Mbit ceil 10Mbit";
print "/sbin/tc filter add dev "$1" parent 1:1 prio 10 protocol ip u32";
print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 10: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 11: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 12: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 13: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32 ht 801:: match ip src 0.0.0.0/0 hashkey mask 0xff000000 at 12 link 10:";
}'


#создаем классы, фильтры,дисциплины и при необходимости заполняем таблицы хешей
echo "select user_id,ip,speed,int_iface,ext_iface from system.shaper_view order by user_id;"|$mysql|sed 1d|
awk '
BEGIN{
buf=0;
class_id=255;
tc_class="/sbin/tc class add dev";
tc_qdisc="/sbin/tc qdisc add dev";
tc_filter="/sbin/tc filter add dev";
}
{
if(buf!=$1)
  {
  printf "%s%x%s\n", "# ",class_id," "class_id" "$2;
  client_speed=$3*128;
  printf "%s%x%s\n",tc_class" "$4" parent 1:1 classid 1:",++class_id," htb rate "client_speed"bps ceil "client_speed"bps";
  printf "%s%x%s\n",tc_class" "$5" parent 1:1 classid 1:",class_id," htb rate "client_speed"bps ceil "client_speed"bps";
  client_class=class_id;
  printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 1";
  printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 1";
  printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 2";
  printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 2";
  printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 3";
  printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 3";
  printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 4";
  printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 4";
  printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  }
split($2,ip,".");
if (ht_1[ip[1]]!=1)
{
printf "%s%x%s\n",tc_filter" "$4" parent 1:0 protocol ip u32 ht 10:",ip[1],": match ip dst "ip[1]".0.0.0/8 hashkey mask 0xff0000 at 16 link 11:";
printf "%s%x%s\n",tc_filter" "$5" parent 1:0 protocol ip u32 ht 10:",ip[1],": match ip src "ip[1]".0.0.0/8 hashkey mask 0xff0000 at 12 link 11:";
ht_1[ip[1]]=1;
}
if (ht_2[ip[2]]!=1)
{
printf "%s%x%s\n",tc_filter" "$4" parent 1:0 protocol ip u32 ht 11:",ip[2],": match ip dst "ip[1]"."ip[2]".0.0/16 hashkey mask 0xff00 at 16 link 12:";
printf "%s%x%s\n",tc_filter" "$5" parent 1:0 protocol ip u32 ht 11:",ip[2],": match ip src "ip[1]"."ip[2]".0.0/16 hashkey mask 0xff00 at 12 link 12:";
ht_2[ip[2]]=1;
}
if (ht_3[ip[3]]!=1)
{
printf "%s%x%s\n",tc_filter" "$4" parent 1:0 protocol ip u32 ht 12:",ip[3],": match ip dst "ip[1]"."ip[2]"."ip[3]".0/24 hashkey mask 0xff at 16 link 13:";
printf "%s%x%s\n",tc_filter" "$5" parent 1:0 protocol ip u32 ht 12:",ip[3],": match ip src "ip[1]"."ip[2]"."ip[3]".0/24 hashkey mask 0xff at 12 link 13:";
ht_3[ip[3]]=1;
}
printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 1 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 match ip protocol 1 0xff flowid 1:",client_class
printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 1 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 match ip protocol 1 0xff flowid 1:",client_class
printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 2 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 match ip protocol 17 0xff flowid 1:",++client_class
printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 2 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 match ip protocol 17 0xff flowid 1:",client_class
printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 3 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 match ip protocol 6 0xff match ip sport 80 0xffff flowid 1:",++client_class
printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 3 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 match ip protocol 6 0xff match ip dport 80 0xffff flowid 1:",client_class
printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 4 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 flowid 1:",++client_class
printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 4 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 flowid 1:",client_class
buf=$1;
}'

* This source code was highlighted with Source Code Highlighter.

Надеюсь данный опус помог Вам вникнуть в основы управления трафиком в Linux.

Источник: http://habrahabr.ru/blogs/sysadm/89002/

Шейпирование трафика в Linux

Под катом описано как шейпировать трафик в Linux и что для этого нужно знать.
Осуществлять шейпирование трафика будем посредством утилиты tc из пакета iproute2.
Знания без которых нельзя осознать всю полноту управления трафиком в Linux:
Шейпировать можно только исходящий из интерфейса трафик. (в связи с чем возникает проблема с nat, о ней мы поговорим позже). Предположим, что имеется роутер между «интернетом» и абонентом. В роутер воткнуто две сетевые карты: eth0 смотрит на абонента, а eth1 в мир. Для ограничения «скорости скачивания» правила шейпирования описываем на eth0, для ограничения «отдачи» — на eth1.
Необходимо понимать разницу между rate и ceil. Rate — гарантированная полоса пропуская, Ceil — максимальная полоса которую может получить данный класс, rate не может быть больше ceil
Параметры rate и ceil для корневого класса должны совпадать. Таким образом мы определяем общую полосу пропускания.
Сумма Rate'ов классов-потомков, не должна превышать Rate родительского класса. Конечно можно не выполнять этот пункт, но тогда могут возникнуть проблемы с предоставлением «гарантированной полосы пропускания».
Идентификаторы классов указаны в шестнадцатеричной системе, и должны находиться в пределах от 2 до 2^16
Для промежуточных классов необязательно создавать дисциплины и фильтры.
Идентификаторы классов в пределах интерфейса должны быть уникальны.

В простом варианте изложения алгоритм нарезки трафика выглядит так:
1. Создаем корневую дисциплину для интерфейса и указываем класс куда будет попадать не классифицированный трафик.
2. Создаем корневой класс и определяем ширину канала.
3. Создаем дочерний класс для шейпирования абонента.
4. Создаем дисциплину шейпирования для класса абонента.
5. Создаем фильтра позволяющие классифицировать трафик абонента.

В принципе все просто, но в реальной жизни придется потратить много нервов, что бы добиться желаемого результата.
Один из способов добиться результата не тратя много нервов — использовать скрипт htbinit (взять его можно с sourceforge.net/projects/htbinit/). Синтаксис конфигов простой, создание классов тоже просто.
Для построения конфигураций средней сложность вполне достаточно.
Пример.
Имеется локальная сеть, средних размеров. Вам необходимо ограничивать скорость абонентов согласно прейскуранту, трансляция адресов (NAT) происходит на другом сервере.

Получение htbinit
debian:~# wget downloads.sourceforge.net/project/htbinit/HTB.init/0.8.5/htb.init-v0.8.5?use_mirror=surfnet
debian:~# mv htb.init-v0.8.5 /usr/local/sbin/
debian:~# cd /usr/local/sbin/
debian:/usr/local/sbin# mv htb.init-v0.8.5 htb.init
debian:/usr/local/sbin# chmod +x htb.init

По умолчанию htbinit хранит конфиги в папке /etc/sysconfig/htb.
debian:~# mkdir -p /etc/sysconfig/htb
Создаем коневую дисциплину для интерфейса eth0 (интерфейс смотрит в локальную сеть, «на абонента»)
debian:~# touch /etc/sysconfig/htb/eth0
Указываем в какой класс будет попадать трафик не попавший ни в один из фильтров
debian:~# mcedit /etc/sysconfig/htb/eth0
DEFAULT=42

Создаем корневой класс
debian:~# touch /etc/sysconfig/htb/eth0-2.root
debian:~# mcedit /etc/sysconfig/htb/eth0-2.root
RATE=100Mbit

Можно не указывать CEIL, тогда он автоматом будет равен RATE.

Создаем класс для не классифицированного трафика
debian:~# touch /etc/sysconfig/htb/eth0-2:42.root
debian:~# mcedit /etc/sysconfig/htb/eth0-2:42.root
RATE=4Kbit


Создаем общий клиентский класс. Пускай его ID будет равно «D» и всего для абонентов мы выделим 10 Мбит.
debian:~# touch /etc/sysconfig/htb/eth0-2:D.sumamry_cilents_class
debian:~# mcedit /etc/sysconfig/htb/eth0-2:D.sumamry_cilents_class
RATE=10Mbit


Теперь можно заняться абонентами.
Что бы ограничить скорость скачивания в 512 КБит абоненту Василию нужно:
Создать класс для абонента Василия. Пускай ID клиентов будут начинаться с 255. Весьма полезно, если потребуется создать какой либо «системный» класс.
debian:~# touch /etc/sysconfig/htb/eth0-2:D:100.client_login
Интерфейс, идентификатор класса и родительские классы описываются в названии конфига.
Запись eth0-2:D:100.client_login означает что
eth0- Данный класс принадлежит к интерфейсу eth0
2 Корневой класс
D Родительский класс (В нашем случае общий клиентский класс)
100 Идентификатор класса клента
client_login Мнемоническая составляющая названия файла, несет смысловую нагрузку, в генерации классов не используется

Название файла генерируется таким образом:
1. Интерфейс к которому принадлежит класс.
2. Разделитель "-"(минус)
3. ID корневого класса
4. Разделитель ":"(двоеточие)
5. ID родительского класса
6. Разделитель ":"(двоеточие)
7. ID клиентского класса
8. Разделитель "."(точка)
9. Мнемоническая составляющая названия файла
Пункты 5 и 6 могут отсутствовать, в зависимость от выбранной Вами стратегии шейпирования.

debian:~# mcedit /etc/sysconfig/htb/eth0-2:D:100.client_login
RATE=512Kbit
LEAF=sfq
RULE=0.0.0.0/0,client_ip/32

По минимуму в конфиге должно быть 3 строки.
RATE — полоса предоставляемая абоненту.
LEAF — указатель на то, что класс конечный и для него необходимо создать создать дисциплину, в нашем случае sfq («псевдочестное» распределение полосы)
RULE — определяем что попадает в класс.Фильтровать можно по ип адресам, подсетям ип адресов, портам. Количество записей RULE может быть более одной.

Если нам нужно шейпировать трафик и натить на том же руотере, то вместо RULE нужно использовать MARK. Единственное придется маркировать пакеты.
Пример скрипта генерирующего конфиги для htbinit в конфигурации с NATом.
#!/bin/bash
#определяем переменные
declare -a rules
inif="eth0"
outif="eth1"
vlan="10"
workdir="/home/netup"
vardir="${workdir}/var"
htb_dir="/etc/sysconfig/htb"

mysql="/usr/bin/mysql -h host -u user -ppassword -D base"
ipt="/usr/local/sbin/iptables"
IPT_UNLIM="UNLIM_"${vlan}
utm_rules="${vardir}/htb_rules_htb"
htb_rules="${vardir}/htb_rules_utm"

#подготавливаем конфиги при первом запуске
[ -e ${htb_rules} ] || touch ${htb_rules}
#полная регенерация конфигов
if [ "${1}" = "zopa" ];then
echo ""> ${htb_rules};
fi

#получаем данные (id в шестнадцатиричной системе)
echo "select id,ip,mask,speed from view_shaper order by id;"|$mysql|sed '1d' > ${utm_rules};
#если достучались к базе и есть разница с текущим конфигом
exp="${utm_rules} ${htb_rules}"
[ -s ${utm_rules} ] && if [ -n "`diff ${exp}`" ]
then

#удаляем конфиги надобность в которых отпала
for i in `diff ${exp}|awk '{if (NF==5)print $2}'|sort -n|uniq`
do
inshaper=${htb_dir}/${inif}-2:${i}.rule_${i};
[ -e ${inshaper} ] && rm ${inshaper};
outshaper=${htb_dir}/${outif}-2:${i}.rule_${i};
[ -e ${outshaper} ] && rm ${outshaper};
done;

#формируем новые конфиги
rules=(`diff ${exp}|grep "<"|awk '{if (NF==5)print $2,$3,$4,$5}'`)
for i in `seq 1 4 ${#rules[@]}`;
do
id=${rules[$i-1]};
ip=${rules[$i]};
mask=${rules[$i+1]};
rate=${rules[$i+2]};

#Формируем названия конфигов
inshaper=${htb_dir}"/"${inif}-2:${id}.rule_${id};
outshaper=${htb_dir}/${outif}-2:${id}.rule_${id};

#Рассчитываем марки для пакетов
inmark="0x"`echo "obase=16; $((0x${id}*2))"|bc`
outmark="0x"`echo "obase=16; $((0x${id}*2+1))"|bc`

#Удаляем «старые» правила маркировки
${ipt} -t mangle -S ${IPT_UNLIM}|grep -w ${ip}|awk -v ipt=${ipt} '{$1="-D";system(ipt" -t mangle "$0)}';
#Создаем конфиг и правила на внутреннем интерфейсе
if [ -e ${inshaper} ]; then
#echo "RULE="0.0.0.0/0,"${ip}"/"${mask}">> ${inshaper}
${ipt} -t mangle -A ${IPT_UNLIM} -s ${ip} -j MARK --set-mark ${inmark}
else
echo "RATE=4096bit" > ${inshaper}
echo "CEIL="$((${rate}*1024))"bit" >>${inshaper}
echo "LEAF=sfq" >> ${inshaper}
#echo "RULE=0.0.0.0/0,"${ip}"/"${mask}>> ${inshaper};
echo "MARK="${inmark}>> ${inshaper};
${ipt} -t mangle -A ${IPT_UNLIM} -d ${ip}/${mask} -j MARK --set-mark ${inmark}
fi

#Создаем конфиг и правила на внутреннем интерфейсе
if [ -e $outshaper ]; then
#echo "RULE="${ip}"/"${mask}",0.0.0.0/0" >> ${outshaper}
${ipt} -t mangle -A ${IPT_UNLIM} -s ${ip}/${mask} -j MARK --set-mark ${outmark}
else
echo "RATE=4096bit" > ${outshaper}
echo "CEIL="$((${rate}*1024))"bit" >> ${outshaper}
echo "LEAF=sfq" >> ${outshaper}
#echo "RULE="${ip}"/"${mask}",0.0.0.0/0" >> ${outshaper}
echo "MARK="${outmark}>> $outshaper;
${ipt} -t mangle -A ${IPT_UNLIM} -s ${ip}/${mask} -j MARK --set-mark ${outmark}
fi
echo $ip
done;
cp ${exp}
[ -e /var/cache/htb.init ] && rm /var/cache/htb.init
/usr/local/sbin/htb.init restart
fi


Для конфигураций до 1000-1500 фильтров такой вариант подойдет. Для более крупных уже нужно использовать быстрые хэш фильтры, о ни и о приоретизации трафика я расскажу в следующей статье.

Источник: http://habrahabr.ru/blogs/sysadm/88624/

среда, 14 апреля 2010 г.

Шейпирование трафика в Linux. Часть 2

Вторая часть статьи об управлении трафиком в Linux. В статье приведены примеры приоретизации трафика (QoS) и рассказано об использовании hash таблиц при фильтрации трафика (fast hash tables), использование которых позволяет существенно увеличить производительность.
В первой части мы остановились на генерации конфигов средней сложность для htbinit. Сегодня мы поговорим о приоретизации трафика и использовании хэш таблиц в фильтрах. Я подразумеваю, что Вы прочитали первую часть статьи .
Предположим, что нам надоели замечания пользователей о высоком пинге, надоели постоянные детские вопли на форуме о том, что в counter-strike играть невозможно: «лаги страшные», или «у меня странички медленно грузятся, вконтакте открывался 10 минут», а писать что все замеры нужно производить при отключенном «торренте» уже нету сил.
Посему тто бы наша совесть была чиста, и мы могли не кривя душой сказать: «проблема на стороне провайдера предоставляющего данный сервис»(обозначить направление движения в сторону южного полюса) — озаботимся приоретизацией трафика.

Приоритеты выставим в таком порядке:
1. icmp
2. udp
3. tcp port 80
4. bulk traffic

Рассмотрим ограничение полосы на внутреннем интерфейсе, управлять будем «скоростью скачивания».
Напомню.
В простом варианте изложения алгоритм нарезки трафика выглядит так:
1. Создаем корневую дисциплину для интерфейса и указываем класс куда будет попадать не классифицированный трафик.
2. Создаем корневой класс и определяем ширину канала.
3. Создаем дочерний класс для шейпирования абонента.
4. Создаем дисциплину шейпирования для класса абонента.
5. Создаем фильтра позволяющие классифицировать трафик абонента.

Пример

#!/bin/bash

#"Очищаем" интерфейс eht1
/sbin/tc qdisc del dev eth1 root handle 1: htb default 15
#Создаем заново дисциплину и указываем дефолтный класс
/sbin/tc qdisc add dev eth1 root handle 1: htb default 15
#Создаем общий для клиентов класс
/sbin/tc class add dev eth1 parent 1: classid 1:1 htb rate 10Mbit ceil 10Mbit

#Создаем корневой класс клиента
/sbin/tc class add dev eth1 parent 1:1 classid 1:10 htb rate 512kbit ceil 512kbit

#Создаем 4 подкласса для каждого из видов трафика
/sbin/tc class add dev eth1 parent 1:10 classid 1:11 htb rate 1kbit ceil 512kbit prio 1
/sbin/tc class add dev eth1 parent 1:10 classid 1:12 htb rate 1kbit ceil 512kbit prio 2
/sbin/tc class add dev eth1 parent 1:10 classid 1:13 htb rate 1kbit ceil 512kbit prio 3
/sbin/tc class add dev eth1 parent 1:10 classid 1:14 htb rate 1kbit ceil 512kbit prio 4

#Создаем дисциплины шейпирования для конечных классов
/sbin/tc qdisc add dev eth1 parent 1:11 handle 11: sfq perturb 10
/sbin/tc qdisc add dev eth1 parent 1:12 handle 12: sfq perturb 10
/sbin/tc qdisc add dev eth1 parent 1:13 handle 13: sfq perturb 10
/sbin/tc qdisc add dev eth1 parent 1:14 handle 14: sfq perturb 10

Создаем 4 фильтра, для каждого из видов трафика
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 1 u32 match ip dst 192.168.2.2/32 match ip protocol 1 0xff flowid 1:11
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 2 u32 match ip dst 192.168.2.2/32 match ip protocol 17 0xff flowid 1:12
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 3 u32 match ip dst 192.168.2.2/32 match ip protocol 6 0xff match ip sport 80 0xffff flowid 1:13
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 4 u32 match ip dst 192.168.2.2/32 flowid 1:14


* This source code was highlighted with Source Code Highlighter.


Думаю из примера видно, что для реализации приоретизиции трафика мы создали для каждого отдельный класс. Далее создаем фильтры, причем чем меньше prio, тем больше у трафика приоритет. Вообще правила обрабатываются согласно тому как их добавляли, в случае с приоритетами — первыми обслуживаются правила, имеющие наивысший приоритет.
Так же вы можете каждому из классов обзначить RATE равный одной четвертой от RATE корневого класса клиента, что бы уже наверняка.
Хочу обратить внимание, на то что нам пришлось создать 4 фильтра, для оного ип, а если ип 3-4 тысячи, то получим огромный линейный список правил — в итоге производительность упадет ниже плинтуса.
Что бы этого избежать воспользуемся «быстрыми» хэш таблицами.
О том, что такое хэш таблицы Вы можете посмотреть на Википедии.
Создадим 4 таблицы по 256 ячеек, каждая из таблиц будет оценивать один из октетов ип адреса.
И в конечном итоге, вместо поиска по всему списку, как это было бы в классическом варианте, мы уменьшим количество проверок и значительно снизим нагрузку.
Пример.
#Создаем корневой фильтр
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32
#Создаем 4 хеш таблицы для каждого октета
/sbin/tc filter add dev eth1 parent 1:0 handle 10: protocol ip u32 divisor 256
/sbin/tc filter add dev eth1 parent 1:0 handle 11: protocol ip u32 divisor 256
/sbin/tc filter add dev eth1 parent 1:0 handle 12: protocol ip u32 divisor 256
/sbin/tc filter add dev eth1 parent 1:0 handle 13: protocol ip u32 divisor 256
#Создаем фильтр направлящий весь трафик в хеш таблицу с ID 10
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 801:: match ip dst 0.0.0.0/0 hashkey mask 0xff000000 at 16 link 10:
#Добавляем правило в 10 хеш таблицу, если первый октет равен 192, то оправляем пакет в 11 хеш таблицу
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 10:c0: match ip dst 192.0.0.0/8  hashkey mask 0xff0000 at 16 link 11:
#Добавляем правило в 11 хеш таблицу, если второй октет равен 168, то оправляем пакет в 12 хеш таблицу
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 11:a8: match ip dst 192.168.0.0/16 hashkey mask 0xff00 at 16 link 12:
#Добавляем правило в 12 хеш таблицу, если третий октет равен 2, то оправляем пакет в 13 хеш таблицу
/sbin/tc filter add dev eth1 parent 1:0 protocol ip u32 ht 12:2: match ip dst 192.168.2.0/24 hashkey mask 0xff at 16 link 13:

#Добавляем правила в 13 хеш таблицу, оцениваем 4 октет и направляем в необходимый класс, в зависимости от вида трафика
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 1 u32 ht 13:2: match ip dst 192.168.2.2/32 match ip protocol 1 0xff flowid 1:11
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 2 u32 ht 13:2: match ip dst 192.168.2.2/32 match ip protocol 17 0xff flowid 1:12
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 3 u32 ht 13:2: match ip dst 192.168.2.2/32 match ip protocol 6 0xff match ip sport 80 0xffff flowid 1:13
/sbin/tc filter add dev eth1 parent 1:0 protocol ip prio 4 u32 ht 13:2: match ip dst 192.168.2.2/32 flowid 1:14


* This source code was highlighted with Source Code Highlighter.

Ниже приведен листинг скрипка генерирующего правила для tc включающие в себя приоретизацию и хеш фильтры.
Скрип полностью рабочий, думаю не составит большого труда модифицировать его под себя.
При переходе с линейных фильтров на хеш таблицы нагрузка упала почти в 4 раза.
#!/bin/bash
mysql="mysql -ppass -u user -h host"
#создаем корневуй дсциплину, класс, корневой фильтр и тиблицы хешей для внешних интерфейсов
echo "select ext_iface from system.shaper_view group by ext_iface;"|$mysql|sed 1d|
awk '{
print "/sbin/tc qdisc del dev "$1" root handle 1: htb default 15";
print "/sbin/tc qdisc add dev "$1" root handle 1: htb default 15";
print "/sbin/tc class add dev "$1" parent 1: classid 1:1 htb rate 10Mbit ceil 10Mbit";
print "/sbin/tc filter add dev "$1" parent 1:1 prio 10 protocol ip u32";
print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 10: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 11: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 12: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 13: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32 ht 801:: match ip dst 0.0.0.0/0 hashkey mask 0xff000000 at 16 link 10:";
}'

#создаем корневуй дсциплину, класс, корневой фильтр и тиблицы хешей для внутренних интерфейсов
echo "select int_iface from system.shaper_view group by int_iface;"|$mysql|sed 1d|
awk '{
print "/sbin/tc qdisc del dev "$1" root handle 1: htb default 15";
print "/sbin/tc qdisc add dev "$1" root handle 1: htb default 15";
print "/sbin/tc class add dev "$1" parent 1: classid 1:1 htb rate 10Mbit ceil 10Mbit";
print "/sbin/tc filter add dev "$1" parent 1:1 prio 10 protocol ip u32";
print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 10: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 11: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 12: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 handle 13: protocol ip u32 divisor 256";
print "/sbin/tc filter add dev "$1" parent 1:0 protocol ip u32 ht 801:: match ip src 0.0.0.0/0 hashkey mask 0xff000000 at 12 link 10:";
}'


#создаем классы, фильтры,дисциплины и при необходимости заполняем таблицы хешей
echo "select user_id,ip,speed,int_iface,ext_iface from system.shaper_view order by user_id;"|$mysql|sed 1d|
awk '
BEGIN{
buf=0;
class_id=255;
tc_class="/sbin/tc class add dev";
tc_qdisc="/sbin/tc qdisc add dev";
tc_filter="/sbin/tc filter add dev";
}
{
if(buf!=$1)
  {
  printf "%s%x%s\n", "# ",class_id," "class_id" "$2;
  client_speed=$3*128;
  printf "%s%x%s\n",tc_class" "$4" parent 1:1 classid 1:",++class_id," htb rate "client_speed"bps ceil "client_speed"bps";
  printf "%s%x%s\n",tc_class" "$5" parent 1:1 classid 1:",class_id," htb rate "client_speed"bps ceil "client_speed"bps";
  client_class=class_id;
  printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 1";
  printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 1";
  printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 2";
  printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 2";
  printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 3";
  printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 3";
  printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_class" "$4" parent 1:",client_class," classid 1:",++class_id," htb rate 1024bps ceil "client_speed"bps prio 4";
  printf "%s%x%s%x%s\n",tc_class" "$5" parent 1:",client_class," classid 1:",class_id," htb rate 1024bps ceil "client_speed"bps prio 4";
  printf "%s%x%s%x%s\n",tc_qdisc" "$4" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  printf "%s%x%s%x%s\n",tc_qdisc" "$5" parent 1:",class_id," handle ",class_id,": sfq perturb 10";
  }
split($2,ip,".");
if (ht_1[ip[1]]!=1)
{
printf "%s%x%s\n",tc_filter" "$4" parent 1:0 protocol ip u32 ht 10:",ip[1],": match ip dst "ip[1]".0.0.0/8 hashkey mask 0xff0000 at 16 link 11:";
printf "%s%x%s\n",tc_filter" "$5" parent 1:0 protocol ip u32 ht 10:",ip[1],": match ip src "ip[1]".0.0.0/8 hashkey mask 0xff0000 at 12 link 11:";
ht_1[ip[1]]=1;
}
if (ht_2[ip[2]]!=1)
{
printf "%s%x%s\n",tc_filter" "$4" parent 1:0 protocol ip u32 ht 11:",ip[2],": match ip dst "ip[1]"."ip[2]".0.0/16 hashkey mask 0xff00 at 16 link 12:";
printf "%s%x%s\n",tc_filter" "$5" parent 1:0 protocol ip u32 ht 11:",ip[2],": match ip src "ip[1]"."ip[2]".0.0/16 hashkey mask 0xff00 at 12 link 12:";
ht_2[ip[2]]=1;
}
if (ht_3[ip[3]]!=1)
{
printf "%s%x%s\n",tc_filter" "$4" parent 1:0 protocol ip u32 ht 12:",ip[3],": match ip dst "ip[1]"."ip[2]"."ip[3]".0/24 hashkey mask 0xff at 16 link 13:";
printf "%s%x%s\n",tc_filter" "$5" parent 1:0 protocol ip u32 ht 12:",ip[3],": match ip src "ip[1]"."ip[2]"."ip[3]".0/24 hashkey mask 0xff at 12 link 13:";
ht_3[ip[3]]=1;
}
printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 1 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 match ip protocol 1 0xff flowid 1:",client_class
printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 1 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 match ip protocol 1 0xff flowid 1:",client_class
printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 2 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 match ip protocol 17 0xff flowid 1:",++client_class
printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 2 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 match ip protocol 17 0xff flowid 1:",client_class
printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 3 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 match ip protocol 6 0xff match ip sport 80 0xffff flowid 1:",++client_class
printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 3 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 match ip protocol 6 0xff match ip dport 80 0xffff flowid 1:",client_class
printf "%s%x%s%x\n",tc_filter" "$4" parent 1:0 protocol ip prio 4 u32 ht 13:",ip[4],": match ip dst "$2"/32 hashkey mask 0x0 at 16 flowid 1:",++client_class
printf "%s%x%s%x\n",tc_filter" "$5" parent 1:0 protocol ip prio 4 u32 ht 13:",ip[4],": match ip src "$2"/32 hashkey mask 0x0 at 12 flowid 1:",client_class
buf=$1;
}'

* This source code was highlighted with Source Code Highlighter.

Надеюсь данный опус помог Вам вникнуть в основы управления трафиком в Linux.

Оригинал:  http://habrahabr.ru/blogs/sysadm/89002/

Шейпирование трафика в Linux

Знания без которых нельзя осознать всю полноту управления трафиком в Linux:
Шейпировать можно только исходящий из интерфейса трафик. (в связи с чем возникает проблема с nat, о ней мы поговорим позже). Предположим, что имеется роутер между «интернетом» и абонентом. В роутер воткнуто две сетевые карты: eth0 смотрит на абонента, а eth1 в мир. Для ограничения «скорости скачивания» правила шейпирования описываем на eth0, для ограничения «отдачи» — на eth1.
Необходимо понимать разницу между rate и ceil. Rate — гарантированная полоса пропуская, Ceil — максимальная полоса которую может получить данный класс, rate не может быть больше ceil
Параметры rate и ceil для корневого класса должны совпадать. Таким образом мы определяем общую полосу пропускания.
Сумма Rate'ов классов-потомков, не должна превышать Rate родительского класса. Конечно можно не выполнять этот пункт, но тогда могут возникнуть проблемы с предоставлением «гарантированной полосы пропускания».
Идентификаторы классов указаны в шестнадцатеричной системе, и должны находиться в пределах от 2 до 2^16
Для промежуточных классов необязательно создавать дисциплины и фильтры.
Идентификаторы классов в пределах интерфейса должны быть уникальны.

В простом варианте изложения алгоритм нарезки трафика выглядит так:
1. Создаем корневую дисциплину для интерфейса и указываем класс куда будет попадать не классифицированный трафик.
2. Создаем корневой класс и определяем ширину канала.
3. Создаем дочерний класс для шейпирования абонента.
4. Создаем дисциплину шейпирования для класса абонента.
5. Создаем фильтра позволяющие классифицировать трафик абонента.

В принципе все просто, но в реальной жизни придется потратить много нервов, что бы добиться желаемого результата.
Один из способов добиться результата не тратя много нервов — использовать скрипт htbinit (взять его можно с sourceforge.net/projects/htbinit/). Синтаксис конфигов простой, создание классов тоже просто.
Для построения конфигураций средней сложность вполне достаточно.
Пример.
Имеется локальная сеть, средних размеров. Вам необходимо ограничивать скорость абонентов согласно прейскуранту, трансляция адресов (NAT) происходит на другом сервере.

Получение htbinit
debian:~# wget downloads.sourceforge.net/project/htbinit/HTB.init/0.8.5/htb.init-v0.8.5?use_mirror=surfnet
debian:~# mv htb.init-v0.8.5 /usr/local/sbin/
debian:~# cd /usr/local/sbin/
debian:/usr/local/sbin# mv htb.init-v0.8.5 htb.init
debian:/usr/local/sbin# chmod +x htb.init

По умолчанию htbinit хранит конфиги в папке /etc/sysconfig/htb.
debian:~# mkdir -p /etc/sysconfig/htb
Создаем коневую дисциплину для интерфейса eth0 (интерфейс смотрит в локальную сеть, «на абонента»)
debian:~# touch /etc/sysconfig/htb/eth0
Указываем в какой класс будет попадать трафик не попавший ни в один из фильтров
debian:~# mcedit /etc/sysconfig/htb/eth0
DEFAULT=42

Создаем корневой класс
debian:~# touch /etc/sysconfig/htb/eth0-2.root
debian:~# mcedit /etc/sysconfig/htb/eth0-2.root
RATE=100Mbit

Можно не указывать CEIL, тогда он автоматом будет равен RATE.

Создаем класс для не классифицированного трафика
debian:~# touch /etc/sysconfig/htb/eth0-2:42.root
debian:~# mcedit /etc/sysconfig/htb/eth0-2:42.root
RATE=4Kbit


Создаем общий клиентский класс. Пускай его ID будет равно «D» и всего для абонентов мы выделим 10 Мбит.
debian:~# touch /etc/sysconfig/htb/eth0-2:D.sumamry_cilents_class
debian:~# mcedit /etc/sysconfig/htb/eth0-2:D.sumamry_cilents_class
RATE=10Mbit


Теперь можно заняться абонентами.
Что бы ограничить скорость скачивания в 512 КБит абоненту Василию нужно:
Создать класс для абонента Василия. Пускай ID клиентов будут начинаться с 255. Весьма полезно, если потребуется создать какой либо «системный» класс.
debian:~# touch /etc/sysconfig/htb/eth0-2:D:100.client_login
Интерфейс, идентификатор класса и родительские классы описываются в названии конфига.
Запись eth0-2:D:100.client_login означает что
eth0- Данный класс принадлежит к интерфейсу eth0
2 Корневой класс
D Родительский класс (В нашем случае общий клиентский класс)
100 Идентификатор класса клента
client_login Мнемоническая составляющая названия файла, несет смысловую нагрузку, в генерации классов не используется

Название файла генерируется таким образом:
1. Интерфейс к которому принадлежит класс.
2. Разделитель "-"(минус)
3. ID корневого класса
4. Разделитель ":"(двоеточие)
5. ID родительского класса
6. Разделитель ":"(двоеточие)
7. ID клиентского класса
8. Разделитель "."(точка)
9. Мнемоническая составляющая названия файла
Пункты 5 и 6 могут отсутствовать, в зависимость от выбранной Вами стратегии шейпирования.

debian:~# mcedit /etc/sysconfig/htb/eth0-2:D:100.client_login
RATE=512Kbit
LEAF=sfq
RULE=0.0.0.0/0,client_ip/32

По минимуму в конфиге должно быть 3 строки.
RATE — полоса предоставляемая абоненту.
LEAF — указатель на то, что класс конечный и для него необходимо создать создать дисциплину, в нашем случае sfq («псевдочестное» распределение полосы)
RULE — определяем что попадает в класс.Фильтровать можно по ип адресам, подсетям ип адресов, портам. Количество записей RULE может быть более одной.

Если нам нужно шейпировать трафик и натить на том же руотере, то вместо RULE нужно использовать MARK. Единственное придется маркировать пакеты.
Пример скрипта генерирующего конфиги для htbinit в конфигурации с NATом.
#!/bin/bash
#определяем переменные
declare -a rules
inif="eth0"
outif="eth1"
vlan="10"
workdir="/home/netup"
vardir="${workdir}/var"
htb_dir="/etc/sysconfig/htb"

mysql="/usr/bin/mysql -h host -u user -ppassword -D base"
ipt="/usr/local/sbin/iptables"
IPT_UNLIM="UNLIM_"${vlan}
utm_rules="${vardir}/htb_rules_htb"
htb_rules="${vardir}/htb_rules_utm"

#подготавливаем конфиги при первом запуске
[ -e ${htb_rules} ] || touch ${htb_rules}
#полная регенерация конфигов
if [ "${1}" = "zopa" ];then
echo ""> ${htb_rules};
fi

#получаем данные (id в шестнадцатиричной системе)
echo "select id,ip,mask,speed from view_shaper order by id;"|$mysql|sed '1d' > ${utm_rules};
#если достучались к базе и есть разница с текущим конфигом
exp="${utm_rules} ${htb_rules}"
[ -s ${utm_rules} ] && if [ -n "`diff ${exp}`" ]
then

#удаляем конфиги надобность в которых отпала
for i in `diff ${exp}|awk '{if (NF==5)print $2}'|sort -n|uniq`
do
inshaper=${htb_dir}/${inif}-2:${i}.rule_${i};
[ -e ${inshaper} ] && rm ${inshaper};
outshaper=${htb_dir}/${outif}-2:${i}.rule_${i};
[ -e ${outshaper} ] && rm ${outshaper};
done;

#формируем новые конфиги
rules=(`diff ${exp}|grep "<"|awk '{if (NF==5)print $2,$3,$4,$5}'`)
for i in `seq 1 4 ${#rules[@]}`;
do
id=${rules[$i-1]};
ip=${rules[$i]};
mask=${rules[$i+1]};
rate=${rules[$i+2]};

#Формируем названия конфигов
inshaper=${htb_dir}"/"${inif}-2:${id}.rule_${id};
outshaper=${htb_dir}/${outif}-2:${id}.rule_${id};

#Рассчитываем марки для пакетов
inmark="0x"`echo "obase=16; $((0x${id}*2))"|bc`
outmark="0x"`echo "obase=16; $((0x${id}*2+1))"|bc`

#Удаляем «старые» правила маркировки
${ipt} -t mangle -S ${IPT_UNLIM}|grep -w ${ip}|awk -v ipt=${ipt} '{$1="-D";system(ipt" -t mangle "$0)}';
#Создаем конфиг и правила на внутреннем интерфейсе
if [ -e ${inshaper} ]; then
#echo "RULE="0.0.0.0/0,"${ip}"/"${mask}">> ${inshaper}
${ipt} -t mangle -A ${IPT_UNLIM} -s ${ip} -j MARK --set-mark ${inmark}
else
echo "RATE=4096bit" > ${inshaper}
echo "CEIL="$((${rate}*1024))"bit" >>${inshaper}
echo "LEAF=sfq" >> ${inshaper}
#echo "RULE=0.0.0.0/0,"${ip}"/"${mask}>> ${inshaper};
echo "MARK="${inmark}>> ${inshaper};
${ipt} -t mangle -A ${IPT_UNLIM} -d ${ip}/${mask} -j MARK --set-mark ${inmark}
fi

#Создаем конфиг и правила на внутреннем интерфейсе
if [ -e $outshaper ]; then
#echo "RULE="${ip}"/"${mask}",0.0.0.0/0" >> ${outshaper}
${ipt} -t mangle -A ${IPT_UNLIM} -s ${ip}/${mask} -j MARK --set-mark ${outmark}
else
echo "RATE=4096bit" > ${outshaper}
echo "CEIL="$((${rate}*1024))"bit" >> ${outshaper}
echo "LEAF=sfq" >> ${outshaper}
#echo "RULE="${ip}"/"${mask}",0.0.0.0/0" >> ${outshaper}
echo "MARK="${outmark}>> $outshaper;
${ipt} -t mangle -A ${IPT_UNLIM} -s ${ip}/${mask} -j MARK --set-mark ${outmark}
fi
echo $ip
done;
cp ${exp}
[ -e /var/cache/htb.init ] && rm /var/cache/htb.init
/usr/local/sbin/htb.init restart
fi


Для конфигураций до 1000-1500 фильтров такой вариант подойдет. Для более крупных уже нужно использовать быстрые хэш фильтры, о ни и о приоретизации трафика я расскажу в следующей статье.

Оригинал: http://habrahabr.ru/blogs/sysadm/88624/