Шукати в цьому блозі

Показ дописів із міткою tcng. Показати всі дописи
Показ дописів із міткою tcng. Показати всі дописи

субота, 29 вересня 2012 р.

Шейпим трафик, используя ifb и hash фильтры tc

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

Итак, есть следующая схема сети:

На сервере присутствуют две сетевых карты:
  • eth0 - ip 192.168.0.10/24, смотрит в мир и на ней поднят nat
    iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 192.168.0.10
  • eth1 - ip 192.168.200.254/24, смотрит в локальную сеть.
Шейпить можно только исходящий трафик с интерфейса. Для клиентов (pc0 - ip 192.168.200.10 и pc1 - ip 192.168.200.20) скорость закачки (download) шейпим на интерфейсе eth1, т.к. для этого интерфейса трафик будет исходящим в сторону клиента.

Логично для отдачи (upload) использовать eth0, но тут есть один нюанс, на этом интерфейсе прописан nat и шейпить на нем исходящий трафик от клиентов не получиться. Чтобы решить данную проблему, завернём весь входящий трафик от клиентов на интерфейсе eth1 в виртуальный интерфейс ifb0, тем более, на данный момент, поддержка IFB есть в ядре.

Для начала нарежем download:
  • Создаем корневую дисциплину на интерфейсе eth1:
    tc qdisc add dev eth1 root handle 1: htb default 20
  • Далее создаем корневой класс для наших клиентских классов. Скорость у него будет 1 mbit, для тестов достаточно:
    tc class add dev eth1 parent 1: classid 1:1 htb rate 1024kbit
  • Теперь создадим таблицу 10 на 256 ячеек:
    tc filter add dev eth1 parent 1:0 prio 1 handle 10: protocol ip u32 divisor 256
  • Создаем фильтр, направлящий весь трафик в хеш таблицу с ID 10:
    tc filter add dev eth1 parent 1:0 protocol ip u32 ht 800:: match ip dst 192.168.200.0/24 hashkey mask 0x000000ff at 16 link 10:
  • Ну а теперь нарежем скорость для наших двух клиентов, для pc0 - 256 kbit, а для pc1 - 512 kbit:
    • Создаем класс 100 со скоростью 256 kbit для pc0:
      tc class add dev eth1 parent 1:1 classid 1:100 htb rate 256kbit ceil 256kbit prio 2 quantum 15365
    • Создаем дисциплину шейпирования для конечного класса:
      tc qdisc add dev eth1 parent 1:100 handle 100: sfq perturb 10
    • Заворачиваем весть трафик для ip 192.168.200.10 в класс 100:
      tc filter add dev eth1 protocol ip prio 2 u32 ht 10:a: match ip dst 192.168.200.10/32 flowid 1:100
    • То же самое, но для pc1:
      tc class add dev eth1 parent 1:1 classid 1:200 htb rate 512kbit ceil 512kbit prio 2 quantum 15365
      tc qdisc add dev eth1 parent 1:200 handle 200: sfq perturb 10
      tc filter add dev eth1 protocol ip prio 2 u32 ht 10:14: match ip dst 192.168.200.20/32 flowid 1:200
  • Весь трафик, который не подпадает под указанные правила будет заворачиваться в класс по умолчанию 20:
    tc class add dev eth1 parent 1:1 classid 1:20 htb rate 32kbit ceil 32kbit prio 2 quantum 15365
    tc qdisc add dev eth1 parent 1:20 handle 20: sfq perturb 10

Теперь upload. Для этого будем использовать виртуальный интерфейс ifb0, куда будет заворачиваться весь входящий трафик от пользователей на интерфейс eth1.
  • Подключаем модуль ядра для ifb:
    modprobe ifb
  • Поднимаем интерфейс ifb0:
    ip link set dev ifb0 up
  • Создаем корневую дисциплину для входящего трафика на интерфейсе eth1:
    tc qdisc add dev eth1 ingress
  • Теперь непосредственно заворачиваем трафик в ifb0:
    tc filter add dev eth1 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0
  • А далее по аналогии с исходящим трафиком с интерфейса eth1:
    • Создаем корневую дисциплину и класс:
      tc qdisc add dev ifb0 root handle 1: htb default 20
      tc class add dev ifb0 parent 1: classid 1:1 htb rate 1024kbit
    • Описываем правила для pc0:
      tc class add dev ifb0 parent 1:1 classid 1:100 htb rate 256kbit ceil 256kbit prio 2 quantum 15365
      tc qdisc add dev ifb0 parent 1:100 handle 100: sfq perturb 10
      tc filter add dev ifb0 protocol ip prio 2 u32 ht 800:: match ip src 192.168.200.10/32 flowid 1:100
    • Теперь для pc1:
      tc class add dev ifb0 parent 1:1 classid 1:200 htb rate 512kbit ceil 512kbit prio 2 quantum 15365
      tc qdisc add dev ifb0 parent 1:200 handle 200: sfq perturb 10
      tc filter add dev ifb0 protocol ip prio 2 u32 ht 800:: match ip src 192.168.200.20/32 flowid 1:200
  • Ну и про класс по умолчанию не забываем:
    tc class add dev ifb0 parent 1:1 classid 1:20 htb rate 32kbit ceil 32kbit prio 2 quantum 15365
    tc qdisc add dev ifb0 parent 1:20 handle 20: sfq perturb 10
    
ps: ht 10:14: ; ht 10:a: ; ht 800:: - это значения не в десятичной, а шестнадцатеричной системе исчисления.

четвер, 4 червня 2009 р.

Как настроить шейпер на локальную сеть, с корректным/справедливым делением входящего и исходящего трафика?

Вместо предисловия.
Задача, для простых конфигураций, состоит из двух этапов решения.
В качестве препроцессора для формирования tc будем использовать tcng. Категорически советую общественности наконец обратить внимание на этот замечательный инструментарий.
Как правило задача ограничить ширину канала из Интернета к локальным хостам не вызывает особых проблем, ведь этот трафик для сервера, по отношению к клиентским хостам, определяется как egress. В основном "мучения" наступают когда надо ограничить ширину канала из локалки в Интернет. Ниже мы постараемся решить и эту небольшую проблему.

Вводные данные.
Пусть ISP на eth0 - 100Мбит/с, и на нём поднимается ppp0. Пропускная способность ppp0 - 1Мбит/с . Локалка eth1 - 100Мбит/с.
Предположим, что ip адрес выданный провайдером на ppp0 - 100.100.100.100, а на eth1 поднят адрес 10.100.1.1/24. В локальной сети есть четыре привилегированных адреса (10.100.1.254, 10.100.1.253, 10.100.1.252 и 10.100.1.251) на которых поровну делится половина канала в Интернет (512Кбит/с по 128Кбит/с на каждый хост), остальные хосты в сети работают на второй половине канала (512Кбит/с) и нас особо не интересует как они между собой поделят эту скорость.

Первый этап решения.
Описываем правила iptables для трафика приходящего к нам из локалки и уходящий в Интернет:
Код:
*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
[0:0] -A PREROUTING -s 10.100.1.254/32 -j MARK --set-xmark 1001
[0:0] -A PREROUTING -s 10.100.1.254/32 -j RETURN
[0:0] -A PREROUTING -s 10.100.1.253/32 -j MARK --set-xmark 2002
[0:0] -A PREROUTING -s 10.100.1.253/32 -j RETURN
[0:0] -A PREROUTING -s 10.100.1.252/32 -j MARK --set-xmark 3003
[0:0] -A PREROUTING -s 10.100.1.252/32 -j RETURN
[0:0] -A PREROUTING -s 10.100.1.251/32 -j MARK --set-xmark 4004
[0:0] -A PREROUTING -s 10.100.1.251/32 -j RETURN
COMMIT
В приведенном примере трафик маркируется в PREROUTING, хотя это транзитный трафик и его с таким же успехом можно промаркировать в цепочке FORWARD таблицы mangle.

Дальше, рисуем скрипт для tcng:
Код:
#define IFACE0  ppp0
#define LOCALRT 102400
#define RATE    1024
#define R2Q     7

$rate01 = (RATE/2)/4;
$rate02 = (RATE/2)/4;
$rate03 = (RATE/2)/4;
$rate04 = (RATE/2)/4;
$rate_other = RATE/2;

dev IFACE0 {
egress {
class (<$mark01>)       if meta_nfmark==1001;
class (<$mark02>)       if meta_nfmark==2002;
class (<$mark03>)       if meta_nfmark==3003;
class (<$mark04>)       if meta_nfmark==4004;
class (<$low>)          if 1;
htb ( rate LOCALRT kbps, r2q R2Q ) {
class ( rate RATE kbps ) {
$mark01 = class ( rate $rate01 kbps ) { sfq(); }
$mark02 = class ( rate $rate02 kbps ) { sfq(); }
$mark03 = class ( rate $rate03 kbps ) { sfq(); }
$mark04 = class ( rate $rate04 kbps ) { sfq(); }
$low = class ( rate $rate_other kbps ) { sfq(); }
}
}
}
}
Преобразуем скрипт tcng в правила tc:
Код:
$ tcng -r linuxforum.ru-topic-79544.ppp0.tcc
tc qdisc del dev ppp0 root
tc qdisc del dev ppp0 ingress

# ================================ Device ppp0 ================================

tc qdisc add dev ppp0 handle 1:0 root dsmark indices 8 default_index 0
tc qdisc add dev ppp0 handle 2:0 parent 1:0 htb r2q 7
tc class add dev ppp0 parent 2:0 classid 2:1 htb rate 128000bps
tc class add dev ppp0 parent 2:1 classid 2:2 htb rate 16000bps
tc qdisc add dev ppp0 handle 3:0 parent 2:2 sfq
tc class add dev ppp0 parent 2:1 classid 2:3 htb rate 16000bps
tc qdisc add dev ppp0 handle 4:0 parent 2:3 sfq
tc class add dev ppp0 parent 2:1 classid 2:4 htb rate 16000bps
tc qdisc add dev ppp0 handle 5:0 parent 2:4 sfq
tc class add dev ppp0 parent 2:1 classid 2:5 htb rate 16000bps
tc qdisc add dev ppp0 handle 6:0 parent 2:5 sfq
tc class add dev ppp0 parent 2:1 classid 2:6 htb rate 64000bps
tc qdisc add dev ppp0 handle 7:0 parent 2:6 sfq
tc filter add dev ppp0 parent 2:0 protocol all prio 1 tcindex mask 0x7 shift 0
tc filter add dev ppp0 parent 2:0 protocol all prio 1 handle 5 tcindex classid 2:6
tc filter add dev ppp0 parent 2:0 protocol all prio 1 handle 4 tcindex classid 2:5
tc filter add dev ppp0 parent 2:0 protocol all prio 1 handle 3 tcindex classid 2:4
tc filter add dev ppp0 parent 2:0 protocol all prio 1 handle 2 tcindex classid 2:3
tc filter add dev ppp0 parent 2:0 protocol all prio 1 handle 1 tcindex classid 2:2
tc filter add dev ppp0 parent 1:0 protocol all prio 1 handle 1001 fw classid 1:1
tc filter add dev ppp0 parent 1:0 protocol all prio 1 handle 2002 fw classid 1:2
tc filter add dev ppp0 parent 1:0 protocol all prio 1 handle 3003 fw classid 1:3
tc filter add dev ppp0 parent 1:0 protocol all prio 1 handle 4004 fw classid 1:4
tc filter add dev ppp0 parent 1:0 protocol all prio 2 u32 match u32 0x0 0x0 at 0 classid 1:5
Что имеем на данном этапе? Спроектированный egress для интерфейса ppp0. Жёсткие ограничения в скорости установленные для наших локальных адресов 10.100.1.254, 10.100.1.253, 10.100.1.252 и 10.100.1.251. Все остальные хосты нашей сети используют остаток канала, который останется после распределения нагрузки этих хостов.

Второй этап решения.
Рисуем скрипт tcng для eth1:
Код:
#define IFACE0  eth1
#define LOCALRT 102400
#define RATE    1024
#define R2Q     7
#define MY_IP   10.100.1.1

$rate01 = (RATE/2)/4;
$rate02 = (RATE/2)/4;
$rate03 = (RATE/2)/4;
$rate04 = (RATE/2)/4;
$rate_other = RATE/2;

$localrate = LOCALRT-RATE;

dev IFACE0 {
egress {
class (<$local>)        if ip_src == MY_IP && ip_dst/24 == 10.100.1.0;
class (<$mark01>)       if ip_dst == 10.100.1.254;
class (<$mark02>)       if ip_dst == 10.100.1.253;
class (<$mark03>)       if ip_dst == 10.100.1.252;
class (<$mark04>)       if ip_dst == 10.100.1.251;
class (<$low>)          if ip_dst/24 == 10.100.1.0;
htb ( rate LOCALRT kbps, r2q R2Q ) {
class ( rate $localrate kbps ) {
$local = class ( rate $localrate kbps ) { sfq(); }
}
class ( rate RATE kbps ) {
$mark01 = class ( rate $rate01 kbps ) { sfq(); }
$mark02 = class ( rate $rate02 kbps ) { sfq(); }
$mark03 = class ( rate $rate03 kbps ) { sfq(); }
$mark04 = class ( rate $rate04 kbps ) { sfq(); }
$low = class ( rate $rate_other kbps ) { sfq(); }
}
}
}
}
Преобразуем скрипт tcng в правила tc:
Код:
$ tcng -r linuxforum.ru-topic-79544.eth1.tcc
tc qdisc del dev eth1 root
tc qdisc del dev eth1 ingress

# ================================ Device eth1 ================================

tc qdisc add dev eth1 handle 1:0 root dsmark indices 8 default_index 0
tc qdisc add dev eth1 handle 2:0 parent 1:0 htb r2q 7
tc class add dev eth1 parent 2:0 classid 2:1 htb rate 12672000bps
tc class add dev eth1 parent 2:1 classid 2:2 htb rate 12672000bps
tc qdisc add dev eth1 handle 3:0 parent 2:2 sfq
tc class add dev eth1 parent 2:0 classid 2:3 htb rate 128000bps
tc class add dev eth1 parent 2:3 classid 2:4 htb rate 16000bps
tc qdisc add dev eth1 handle 4:0 parent 2:4 sfq
tc class add dev eth1 parent 2:3 classid 2:5 htb rate 16000bps
tc qdisc add dev eth1 handle 5:0 parent 2:5 sfq
tc class add dev eth1 parent 2:3 classid 2:6 htb rate 16000bps
tc qdisc add dev eth1 handle 6:0 parent 2:6 sfq
tc class add dev eth1 parent 2:3 classid 2:7 htb rate 16000bps
tc qdisc add dev eth1 handle 7:0 parent 2:7 sfq
tc class add dev eth1 parent 2:3 classid 2:8 htb rate 64000bps
tc qdisc add dev eth1 handle 8:0 parent 2:8 sfq
tc filter add dev eth1 parent 2:0 protocol all prio 1 tcindex mask 0x7 shift 0
tc filter add dev eth1 parent 2:0 protocol all prio 1 handle 6 tcindex classid 2:8
tc filter add dev eth1 parent 2:0 protocol all prio 1 handle 5 tcindex classid 2:7
tc filter add dev eth1 parent 2:0 protocol all prio 1 handle 4 tcindex classid 2:6
tc filter add dev eth1 parent 2:0 protocol all prio 1 handle 3 tcindex classid 2:5
tc filter add dev eth1 parent 2:0 protocol all prio 1 handle 2 tcindex classid 2:4
tc filter add dev eth1 parent 2:0 protocol all prio 1 handle 1 tcindex classid 2:2
tc filter add dev eth1 parent 1:0 protocol all prio 1 u32 match u32 0xa640101 0xffffffff at 12 match u32 0xa640100 0xffffff00 at 16 classid 1:1
tc filter add dev eth1 parent 1:0 protocol all prio 1 u32 match u32 0xa6401fe 0xffffffff at 16 classid 1:2
tc filter add dev eth1 parent 1:0 protocol all prio 1 u32 match u32 0xa6401fd 0xffffffff at 16 classid 1:3
tc filter add dev eth1 parent 1:0 protocol all prio 1 u32 match u32 0xa6401fc 0xffffffff at 16 classid 1:4
tc filter add dev eth1 parent 1:0 protocol all prio 1 u32 match u32 0xa6401fb 0xffffffff at 16 classid 1:5
tc filter add dev eth1 parent 1:0 protocol all prio 1 u32 match u32 0xa640100 0xffffff00 at 16 classid 1:6
Собственно все. Не мудрствуя лукаво мы решили поставленную задачу.

Послесловие.
Естественно, что правила в tcng можно/нужно рисовать свои условия - они индивидуальны для каждого.
Этот пример носят лишь характер "для справки" и способствуют систематизации некоторых знаний :)

Ограничить скорость своего исходящего трафика (рецепт для Linux)

Есть ещё один неприятный момент при работе в Интернете, когда у Вас есть ограничение по скорости. Я не даром приводил задачу для начальных классов школы о втекающей и вытекающей в бассейн воде. Дело в том, что такая-же "петрушка" происходит и с тем трафиком которых является исходящим от Вас.

Предположим, что Вы покупаете канал в Интернет 256Кбит/с, а Ваша сетевая карта настроена в режиме 100Мбит/с (ну или 10Мбит/с - тут это не принципиально). Т.е. Вы будете отдавать на шлюз трафик со скоростью заведомо большей (и во много раз большей!) чем от Вас ожидают. Что при этом произойдёт? Ответ: ванная (стек ip) очень быстро заполнится и вода начнёт выливаться за края (трафик начнёт просто теряться. "лишний" трафик просто перестанет обрабатываться). Безусловно, что в механизме ip существуют механизмы которые контролируют передачу и если что-то где-то потерялось, то потерянный пакет будет отправлен заново - продублируется. Если пакет будет продублирован - это вызовет ненужную нагрузку на Ваш канал, так как этот трафик Вам реально не нужен, он-же был отправлен раньше и т.д. Пока все данные не будут отправлены этот "снежный ком" будет "катиться" и иногда приобретать лавинообразный характер.

Ну не знаю как там в "форточках" (Windows) но в Linux одно из решений этой "проблемы" - ограничить свой исходящий (egress) трафик самостоятельно, в пределах оговорённого Вашим тарифным пакетом, тем согласовав скорость с той, которую ожидает провайдер (оператор услуги):
Код:
# $1 - интерфейс, на котором ограничиваем пропускную способность
# удаляем дисциплины обработки очередей с интерфейса - переводим в состояние pfifo
tc qdisc del dev $1 root
# устанавливаем значение ds
tc qdisc add dev $1 handle 1:0 root dsmark indices 1 default_index 0
# ограничиваем исходящую скорость дисциплиной tbf на 1024Кбит/с (1Мбит/с)
tc qdisc add dev $1 handle 2:0 parent 1:0 tbf burst 3072 limit 20480 mtu 1408 rate 125000bps
Этот код надо вставить куда нибудь, где он будет выполняться после "подъема" интерфейса смотрящего в сторону оператора связи. Безусловно, что вместо $1 необходимо прописать свой реальный интерфейс :)

Кстати оригинальный вариант для tcng выглядит так:
Код:
#define IFACE0  eth3
#define MTU     1408B
#define RATE    1Mbps
#define BURST   3kB
#define LIMIT   20kB

dev IFACE0 {
egress {
tbf (mtu MTU,limit LIMIT,rate RATE,burst BURST);
}
}
Сохраняем в какой нибудь файл. Затем говорим:
Код:
~$ tcng filename.tcng
и получаем результат приведённый выше.

Конечно-же при помощи tcng и tc можно "нарисовать" более сложные политики/решения с дисциплинами htb и т.п., но данный топик для такого рода обсуждений не предназначен ;)

О! Чуть не забыл. Посмотреть какими дисциплинами в данный момент обрабатывается Ваша очередь можно так:
Код:
~$ sudo tc -s qdisc ls dev eth3
qdisc dsmark 1: indices 0x0001 default_index 0x0000
Sent 2040274 bytes 4253 pkt (dropped 10, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
qdisc tbf 2: parent 1: rate 1000Kbit burst 3Kb lat 136.0ms
Sent 2039684 bytes 4250 pkt (dropped 10, overlimits 1942 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
~$ sudo tc -s -d qdisc ls dev eth1
qdisc pfifo_fast 0: root bands 3 priomap  1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
Sent 119707 bytes 1087 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
Обратите внимание на dropped - это тот трафик которого от нас, в общем-то, не ждали и мы его не дали в сеть. Тем самым мы снизили нагрузку на оборудование сети, за что, наверное получили виртуальную "спасибу" от администраторов :)