LINUX.ORG.RU

Вложенные шейперы на tc - возможно?

 ,


0

2

Очередной вопрос про шейперы на tc. Использую дисциплину htb. Есть канал конечной пропускной способности, который делится между двумя классами пользователей, например так:

class htb 1:2 root rate 50Mbit ceil 50Mbit 
class htb 1:10 parent 1:2 leaf 10: prio 1 rate 30Mbit ceil 40Mbit 
class htb 1:20 parent 1:2 leaf 20: prio 2 rate 20Mbit ceil 40Mbit 

При этом qdisc, естественно:

qdisc htb 1: root refcnt 2 r2q 40 default 90 
qdisc sfq 10: parent 1:10 limit 127p quantum 1472b perturb 10sec
qdisc sfq 20: parent 1:20 limit 127p quantum 1472b perturb 10sec
Описание filter опускаю. Они есть и работают :-). Описание дефолтного класса 90 (куда попадает трафик, которого нет в filter) тоже.

Здесь все понятно: для пользователей (описанных в tc filters, естественно) из класса 10 и из класса 20 доступна макс. скорость по 40 Мбит (ceil), но поскольку канал всего 50, то, если суммарный трафик больше чем 50, класс 10 (prio 1) будет «выдавливать» класс 20 (prio 2). В пределе, когда все пытаются грузить канал по максимуму, установится соотношение между классами 30/20 (согласно rate). Это давно и много раз испытано и работает.

А теперь хочу сделать «вложенный шейпер». Т.е. под классом 20 сделать еще несколько классов так, чтобы скорости распределялись между ними, но ограничивались не «верхним» интерфейсом, а параметрами класса 20.

Например так:

class htb 1:201 parent 1:20 leaf 201: prio 2 rate 10Mbit ceil 25Mbit 
class htb 1:202 parent 1:20 leaf 202: prio 2 rate 10Mbit ceil 25Mbit 
хочется из этого получить:

Работает только класс 201. Тогда, если в канале есть место (трафика в классе 10 мало, классу 20 можно выделить до 40 Мбит/с), то класс 201 получает до 25 Мбит. Если нет (классу 20 выделяется 20), от и класс 201 ограничивается этими 20.

Если работают 201 и 202, то они «дерутся» между собой за место, доступное в классе 20, в пределе, когда класс 20 больше 20 Мбит предоставить не может, а 201 и 202 «хотят» по максимуму - каждый получит по 10 Мбит.

В общем, логичное, вроде, желание. Однако, тут налетаем на принципиальное ограничение, которое называется «шейпится только краевой класс». При попытке сделать вышеописанную конфигурацию и поместить каких-то пользователей в классы 201 и 202 через filter, получаем:

class htb 1:2 root rate 50Mbit ceil 50Mbit 
class htb 1:10 parent 1:2 leaf 10: prio 1 rate 30Mbit ceil 40Mbit 
class htb 1:20 parent 1:2 rate 20Mbit ceil 40Mbit 
class htb 1:201 parent 1:20 leaf 201: prio 2 rate 10Mbit ceil 25Mbit 
class htb 1:202 parent 1:20 leaf 202: prio 2 rate 10Mbit ceil 25Mbit 

qdisc htb 1: root refcnt 2 r2q 40 default 90 
qdisc sfq 10: parent 1:10 limit 127p quantum 1472b perturb 10sec
qdisc sfq 201: parent 1:201 limit 127p quantum 1472b perturb 10sec
qdisc sfq 202: parent 1:201 limit 127p quantum 1472b perturb 10sec

Класс 20 после этого перестает быть «краевым» (исчезает leaf) и по факту не работает (ничего не поменяется, если его из конфигурации исключить, a для 201 и 201 сделать parent 1:2, т.е. весь интерфейс), очередь (qdisc) для класса 20 исчезает, как и приоритет у класса. Даже если в filter описаны правила, направляющие трафик как в классы 201 и 201, так и прямо в класс 20 - трафик, направленный «прямо в класс 20» этим классом не обрабатывается и улетает в default. А 201 и 202 напрямую конкурируют с классом 10. Например, если трафика в классе 10 нет, то и 201 и 202 могут получить все 50 Мбит канала (по 25 каждый). А не определенные в их «родительском» классе максимальные 40. С другой стороны, если работают только 10 и 201, то 10 «выдавит» 201 до соотношения 40/10. А хотелось бы, чтобы 201 получал в таком случае определенные в его «родительском» классе классе 20.

Вопрос - можно какими-то стандартными средствами tc реализовать «вложенный шейпер»? Возможно, используя не htb, а другую дисциплину. С htb, насколько я сумел выяснить после долгой возни, это, похоже, невозможно. Хотя с другой стороны, возможность создавать вложенные классы есть - но раз всё равно не работают, то зачем?


class htb 1:2 root rate 50Mbit ceil 50Mbit 
class htb 1:10 parent 1:2 leaf 10: prio 1 rate 30Mbit ceil 40Mbit 
class htb 1:20 parent 1:2 rate 20Mbit ceil 40Mbit 

40+40 != 50, htb подстроит гарантированную скорость как ему будет удобнее(с учетом prio, но это не абсолют, большое количество трафика для 1:20 засрет тебе канал невзирая на prio).

Например, если трафика в классе 10 нет, то и 201 и 202 могут получить все 50 Мбит канала (по 25 каждый). А не определенные в их «родительском» классе максимальные 40.

Только что проверил - в отсутствии трафика в классе 10 суммарная загрузка канала у меня составила именно 40, а не 50. Кури что не так у тебя в системе

Вот выхлоп iperf(2 потока на разные IP):

на IP 172.30.13.64:

[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.00  sec  25.8 MBytes  21.7 Mbits/sec    5             sender
[  4]   0.00-10.00  sec  25.6 MBytes  21.5 Mbits/sec                  receiver

на IP 172.30.13.254:

[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-10.00  sec  20.7 MBytes  17.3 Mbits/sec    3             sender
[  4]   0.00-10.00  sec  20.6 MBytes  17.2 Mbits/sec                  receiver

Адаптированный скрипт для tc, используемый мною в тестах:

#!/bin/sh
IFACE=eth1

tc qdisc del dev ${IFACE} root 2>/dev/null

tc qdisc add dev ${IFACE} root handle 1: htb
tc class add dev ${IFACE} parent 1:0 classid 1:2 htb rate 50Mbit quantum 1500
tc class add dev ${IFACE} parent 1:2 classid 1:10 htb prio 1 rate 30Mbit ceil 40Mbit quantum 1500
tc class add dev ${IFACE} parent 1:2 classid 1:20 htb rate 20Mbit ceil 40Mbit quantum 1500
tc class add dev ${IFACE} parent 1:20 classid 1:201 htb prio 2 rate 10Mbit ceil 25Mbit quantum 1500
tc class add dev ${IFACE} parent 1:20 classid 1:202 htb prio 2 rate 10Mbit ceil 25Mbit quantum 1500

tc qdisc add dev ${IFACE} parent 1:201 handle 201: pfifo limit 127
tc qdisc add dev ${IFACE} parent 1:202 handle 202: pfifo limit 127

tc filter add dev ${IFACE} parent 1:0 protocol ip u32 match ip dst 172.30.13.64/32 flowid 1:201
tc filter add dev ${IFACE} parent 1:0 protocol ip u32 match ip dst 172.30.13.254/32 flowid 1:202

Update: прогнал тест с sfq вместо pfifo(ибо ты используешь именно его как leaf-класс) - картина не изменилась

Pinkbyte ★★★★★ ()
Последнее исправление: Pinkbyte (всего исправлений: 1)
Ответ на: комментарий от Pinkbyte

Ваша правда. На еальной установке перемудрил с rate в «нижних» классах. Если всё делать честно, то работает, как хотелось бы (сумма скоростей в «Нижних классах» не больше, чем ceil в родительском и не меньше чем rate в родительском, как соседний с «родительским» класс не грузи.

Но как только перестает выполнятся правило «сумма rate не больше, чем rate родительского класса» - начинаются всякие чудеса при попытке нагрузить канал по максимуму. Для начала - ограничения верхних классов работать перестают, всем выделяется по rate, а то, что сумма их больше, чем ограничение в верхнем классе - это по боку. Ну и вся логика шейпинга выше уровнями тоже рассыпается.

А как бы так сделать, что сумма скоростей дочерних классов не могла превысить rate родительского (не взирая на то, что в тех дочерних про rate написано)?

mik73 ()
Ответ на: комментарий от mik73

А как бы так сделать, что сумма скоростей дочерних классов не могла превысить rate родительского (не взирая на то, что в тех дочерних про rate написано)?

Никак. В LARTC об этом прямо написано:

Notes: The ceil for a class should always be at least as high as the rate. Also, the ceil for a class should always be at least as high as the ceil of any of its children.

Резюмируя: ceil родительского класса должен быть равен или превышать ceil любого из дочерних(не обязательно их сумму).

Но: при загрузке всех дочерних классов если суммарная загрузка превысит ceil родительского класса - htb разбалансирует как ему будет удобнее.

Если начать воспринимай ceil как «максимальную гарантированную скорость», то всё становится на свои места. Ты не можешь гарантировать скорость в нижестоящих классах, если вышестоящий её не способен предоставить.

Pinkbyte ★★★★★ ()
Последнее исправление: Pinkbyte (всего исправлений: 1)
Ответ на: комментарий от Pinkbyte

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

Естественно. Но после этого возможны два сценария:

1. Как в htb - если сумма гарантированных скоростейц (rate) в дочерних классах выше, чем ограничение в их родительском - плюнуть на ограничение в родительском и все раздать дочерним их rate (обещанную минимальную скорость), заимствуя её из других классов, кроме родительского, которые еще не уперлись в rate. Не взирая на заданные ограничения, приоритеты и т.п. Обещал классу rate - предоставляй до последнего, даже за счет ущерба другим.

2. встречалось на практике, но не знаю чем сделать - считать «главным» для нижележащих классов ограничение родительского класса. И если сумма обещанного нижним больше, чем ограничение rate в родителmском - держаться за ограничение в родительском, роняя дочернии ниже, чем им обещано. Но из соседних с родительским ничего не заимствовать.

вот вопрос - как реализовать второй сценарий? понятно, что не на htb. но есть варианты?

mik73 ()
Ответ на: комментарий от mik73

Как в htb - если сумма гарантированных скоростейц (rate) в дочерних классах выше, чем ограничение в их родительском - плюнуть на ограничение в родительском и все раздать дочерним их rate (обещанную минимальную скорость), заимствуя её из других классов,

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

Pinkbyte ★★★★★ ()