Очередной вопрос про шейперы на 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, насколько я сумел выяснить после долгой возни, это, похоже, невозможно. Хотя с другой стороны, возможность создавать вложенные классы есть - но раз всё равно не работают, то зачем?