LINUX.ORG.RU
решено ФорумAdmin

Каскад очередей в трафик шейпере (tc) не работает

 


0

1

Приветствую! Настроил каскад очередей с фильтрами: qdisc htb (1:0) -> class htb (1:10)-> qdisc htb (10:0)-> class htb(10:1) -> class htb (10:1xxx) Трафик попадает в листовые классы (10:1xxx). Но реального ограничения не происходит (проверял iperf’ом). Есть предположения, какие могут быть причины ? Заранее благодарен за ответы.


Ответ на: комментарий от Anoxemian

Сам факт того, что статистика tc -s -d class show dev wg0 показывает, что пакеты попадают в нужный класс не доказывает, что с точки зрения конфигурации все работает правильно ?

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

htb - это древовидная иерархия классов. Очереди прикреплены к оконечным классам. Пакет не может принадлежать нескольким классам.

Фраза «Каскад очередей» выглядит странно.

Сам факт того, что статистика tc -s -d class show dev wg0 показывает, что пакеты попадают в нужный класс не доказывает, что с точки зрения конфигурации все работает правильно ?

Кроме классов должны быть настроены еще и очереди со своими дисциплинами.

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

Фраза «Каскад очередей» выглядит странно.

У меня ассоциация с каскадным водопадом, когда один поток разбивается на несколько, а те в свою очередь еще на несколько. Алгоритм дисциплины/класса можно взять любой класовый (просто конкретно в моем случае это htb).

Кроме классов должны быть настроены еще и очереди со своими дисциплинами.

По дефолту, если у класса не указывать дочернюю дисциплину (очередь), то применяется pfifo.

Now we can optionally attach queuing disciplines to the leaf classes. If none is specified the default is pfifo.

iye
() автор топика

Приведу кусок скрипта конфигурации. Возможно, кто то увидит что то не правильное.

#!/usr/bin/bash

TC="/usr/sbin/tc"
OUT_IF="wg0"

$TC qdisc del dev $OUT_IF root handle 1: htb default 50
$TC qdisc add dev $OUT_IF root handle 1: htb default 50

$TC class add dev $OUT_IF parent 1: classid 1:1 htb rate 1000Mbit ceil 1000Mbit

$TC class add dev $OUT_IF parent 1:1 classid 1:10 htb rate 250Mbit ceil 250Mbit
$TC qdisc add dev $OUT_IF parent 1:10 handle 10: htb default 50
$TC class add dev $OUT_IF parent 10: classid 10:1 htb rate 20Mbit ceil 20Mbit
$TC class add dev $OUT_IF parent 10: classid 10:2 htb rate 230Mbit ceil 230Mbit

for (( i=1; i <= 254; i++ ))
do
	$TC class add dev $OUT_IF parent 10:1 classid 10:1$i htb rate 1kbit ceil 64kbit
	$TC class add dev $OUT_IF parent 10:2 classid 10:2$i htb rate 512kbit ceil 10Mbit
done

$TC filter add dev $OUT_IF parent 1:0 protocol ip u32
$TC filter add dev $OUT_IF parent 1:0 handle 2: protocol ip u32 divisor 256
$TC filter add dev $OUT_IF parent 1:0 protocol ip u32 ht 2:1: match ip dst 10.1.0.0/16 flowid 1:10

$TC filter add dev $OUT_IF parent 1:0 protocol ip prio 1 u32 match ip dst 10.0.0.0/8 hashkey mask 0xff0000 at 16 link 2:

$TC filter add dev $OUT_IF parent 10:0 protocol ip u32
$TC filter add dev $OUT_IF parent 10:0 handle 11: protocol ip u32 divisor 256
$TC filter add dev $OUT_IF parent 10:0 handle 12: protocol ip u32 divisor 256
$TC filter add dev $OUT_IF parent 10:0 handle 13: protocol ip u32 divisor 256

$TC filter add dev $OUT_IF parent 10:0 protocol ip u32 ht 11:1: match ip dst 10.1.1.0/24 hashkey mask 0xff at 16 link 12:
$TC filter add dev $OUT_IF parent 10:0 protocol ip u32 ht 11:2: match ip dst 10.1.2.0/24 hashkey mask 0xff at 16 link 13:

for (( i=1; i <= 254; i++ ))
do
	xi=$(printf "%x" $i)
	$TC filter add dev $OUT_IF parent 10:0 protocol ip u32 ht 12:$xi: match ip dst 10.1.1.$i/32 flowid 10:1$i
	$TC filter add dev $OUT_IF parent 10:0 protocol ip u32 ht 13:$xi: match ip dst 10.1.2.$i/32 flowid 10:2$i
done

$TC filter add dev $OUT_IF parent 10:0 protocol ip prio 1 u32 match ip dst 10.1.0.0/16 hashkey mask 0xff00 at 16 link 11:

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

Просто чтобы убедиться добавил очереди.

leaf_queue_id=100
for (( i=1; i <= 254; i++ ))
do
	$TC class add dev $OUT_IF parent 10:1 classid 10:1$i htb rate 1kbit ceil 64kbit
	$TC qdisc add dev $OUT_IF parent 10:1$i handle $leaf_queue_id: sfq perturb 10
	leaf_queue_id=$(( $leaf_queue_id + 1 ))
	$TC class add dev $OUT_IF parent 10:2 classid 10:2$i htb rate 512kbit ceil 10Mbit
	$TC qdisc add dev $OUT_IF parent 10:2$i handle $leaf_queue_id: sfq perturb 10
	leaf_queue_id=$(( $leaf_queue_id + 1 ))
done

Результат не изменился.

[ ID] Interval            Transfer    Bandwidth       Write/Err  Rtry     Cwnd/RTT(var)        NetPwr
[  1] 0.0000-1.0000 sec  8.50 MBytes  71.3 Mbits/sec  68/0          0     1502K/130888(305) us  68
[  1] 1.0000-2.0000 sec  10.6 MBytes  89.1 Mbits/sec  85/0         14     1180K/106638(143) us  104
[  1] 2.0000-3.0000 sec  10.5 MBytes  88.1 Mbits/sec  84/0          0     1289K/117066(275) us  94
[  1] 3.0000-4.0000 sec  10.4 MBytes  87.0 Mbits/sec  83/0          0     1372K/123913(396) us  88
[  1] 4.0000-5.0000 sec  10.4 MBytes  87.0 Mbits/sec  83/0          0     1436K/131344(1062) us  83
[  1] 5.0000-6.0000 sec  8.88 MBytes  74.4 Mbits/sec  71/0        130      523K/62988(188) us  148
[  1] 6.0000-7.0000 sec  7.75 MBytes  65.0 Mbits/sec  62/0          0      561K/64818(495) us  125
[  1] 7.0000-8.0000 sec  8.25 MBytes  69.2 Mbits/sec  66/0          0      583K/63456(379) us  136
[  1] 8.0000-9.0000 sec  8.38 MBytes  70.3 Mbits/sec  67/0          0      595K/67734(3684) us  130
[  1] 9.0000-10.0000 sec  8.38 MBytes  70.3 Mbits/sec  67/0          0      601K/68525(2287) us  128
[  1] 0.0000-10.2246 sec  92.1 MBytes  75.6 Mbits/sec  737/0        144      601K/66213(908) us  143

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

При этом пакеты проходят через 3 очереди, как и должны.

# tc -s -d -pretty qdisc show dev wg0 | grep "Sent 1"
 Sent 1428236 bytes 27287 pkt (dropped 0, overlimits 0 requeues 0) 
 Sent 1428236 bytes 27287 pkt (dropped 0, overlimits 0 requeues 0) 
 Sent 1428160 bytes 27286 pkt (dropped 0, overlimits 0 requeues 0)
iye
() автор топика
Ответ на: комментарий от iye

Sent 1428236 bytes 27287 pkt (dropped 0, overlimits 0 requeues 0)

Замечательно.

IMHO дерево разорвано на 2 части. Откуда взялся parent 10 ?

Я бы сделал так

$TC class add dev $OUT_IF parent 1:1 classid 1:10 htb rate 250Mbit ceil 250Mbit
$TC qdisc add dev $OUT_IF parent 1:10 handle 10: htb default 50
$TC class add dev $OUT_IF parent 1:10 classid 1:11 htb rate 20Mbit ceil 20Mbit
$TC class add dev $OUT_IF parent 1:10 classid 1:12 htb rate 230Mbit ceil 230Mbit
for (( i=1; i <= 254; i++ ))
do
        i0=`printf "%03d" $i`
        $TC class add dev $OUT_IF parent 1:11 classid 1:1$i0 htb rate 1kbit ceil 64kbit
	$TC class add dev $OUT_IF parent 1:12 classid 1:2$i0 htb rate 512kbit ceil 10Mbit
done

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

Замечательно.

Не очень понял, что именно.

Откуда взялся parent 10 ?

Это вторая (промежуточная) очередь, которая цепляется к классу корневой дисциплины вот тут:

$TC qdisc add dev $OUT_IF parent 1:10 handle 10: htb default 50

То есть корневая очередь 1:0 -> ее класс-ограничитель на 250мб 1:10 -> Промежуточная очередь 10:0 -> ее класс-ограничитель 10:1 на 250мб -> сабклассы с мелко нарезанными полосами.

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

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

Так же без промежуточной очереди втыкался в ограничение по количеству минорных идентификаторов для фильтров и единой таблицы, которую создает само ядро (800+).

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

Если есть где то ссылка в документации, что нельзя ставить каскадом htb очереди одну за другой, то прошу линк.

Но и упоминаний о такой возможности тоже нет.

https://tldp.org/en/Traffic-Control-HOWTO/ar01s07.html 7.1.6

This key concept in employing HTB bears repeating. Only leaf classes actually shape packets; packets are only delayed in these leaf classes. The inner classes (all the way up to the root class) exist to define how borrowing/lending occurs

Пропустить один пакет через 2 очереди, но без изменения класса можно при передаче данных через интерфейсы типа vlan (одна очередь на vlan, вторая на основном интерфейсе).

Не проверял, но с другими виртуальными составными интерфейсами ситуация скорее всего такая же (bridge, bond, macvlan, ipip, ipgre ...).

Так же без промежуточной очереди втыкался в ограничение по количеству минорных идентификаторов для фильтров и единой таблицы, которую создает само ядро (800+).

Выкинь эти фильтры и замени на iptables+ipset правило iptables с эксклюдом (комментарий) --map-mark заменить на --map-prio

Фильтры были сделаны когда iptables c ipset еще небыло, а был убогий ipchains.

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

Но и упоминаний о такой возможности тоже нет.

Сам по себе факт, что к классу можно прицепить очередь достаточен. Очереди должны быть праграммно эквиваленты (должны имплементировать один и тот же интерфейс).

Пропустить один пакет через 2 очереди, но без изменения класса можно при передаче данных через интерфейсы типа vlan (одна очередь на vlan, вторая на основном интерфейсе).

Не понятно, для чего нужно сохранять класс. Мне нужно последовательно сначала разбить трафик на несколько дочерних очередей, навесить на дочерние очереди корневой класс и его уже разбить на несколько более мелких.

Выкинь эти фильтры и замени на iptables+ipset

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

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

Не понятно, для чего нужно сохранять класс.

Сформулирую по-другому. Речь идет об составных интерфейсах типа vlan. Так вот нет возможности изменить класс пакету после прохождения первой очереди и попаданием во вторую очередь.

Так же без промежуточной очереди втыкался в ограничение по количеству минорных идентификаторов для фильтров и единой таблицы, которую создает само ядро (800+).

В варианте iptables + ipset нет таких ограничений (и нет проблем с NAT).

Если тебе нужно пакет пропустить через 2 очереди, то есть легальный вариант c ifb. Сначала через ifb со своими классами/очередями, а потом уже через исходящий интерфейс со своими классам/очередями, при этом можно повторно классифицировать пакет либо через -j CLASSIFY либо через -j SET)

vel ★★★★★
()

Я тут поэксперементировал с совсем простым вариантом, который вроде как гарантированно должен работать.

#!/usr/bin/bash

TC="/usr/sbin/tc"
OUT_IF="wg0"

$TC qdisc del dev $OUT_IF root handle 1: htb default 50
$TC qdisc add dev $OUT_IF root handle 1: htb default 50

$TC class add dev $OUT_IF parent 1: classid 1:1 htb rate 1000Mbit ceil 1000Mbit
$TC class add dev $OUT_IF parent 1:1 classid 1:30 htb rate 250Mbit ceil 250Mbit

for (( i=1; i <= 254; i++ ))
do
	$TC class add dev $OUT_IF parent 1:30 classid 1:3$i htb rate 512kbit ceil 10Mbit
done

$TC filter add dev $OUT_IF parent 1:0 protocol ip u32
$TC filter add dev $OUT_IF parent 1:0 handle 2: protocol ip u32 divisor 256
$TC filter add dev $OUT_IF parent 1:0 protocol ip prio 1 u32 match ip dst 10.3.2.0/24 hashkey mask 0xff at 16 link 2:

for (( i=1; i <= 254; i++ ))
do
	xi=$(printf "%x" $i)
	$TC filter add dev $OUT_IF parent 1:0 protocol ip u32 ht 2:$xi: match ip dst 10.3.2.$i/32 flowid 1:3$i
done

Так вот. Не работает. Хотя трафик попадает в классы. Видимо есть какой то системный нюанс.

# tc -s -d -pretty class show dev wg0 | grep "Sent 1"
 Sent 1524201 bytes 29227 pkt (dropped 0, overlimits 0 requeues 0) 
 Sent 1524201 bytes 29227 pkt (dropped 0, overlimits 0 requeues 0) 
 Sent 1524201 bytes 29227 pkt (dropped 0, overlimits 0 requeues 0) 
[ ID] Interval            Transfer    Bandwidth       Write/Err  Rtry     Cwnd/RTT(var)        NetPwr
[  1] 0.0000-1.0000 sec  7.50 MBytes  62.9 Mbits/sec  60/0          0      980K/84390(566) us  93
[  1] 1.0000-2.0000 sec  11.2 MBytes  94.4 Mbits/sec  90/0          0     1548K/135269(550) us  87
[  1] 2.0000-3.0000 sec  10.6 MBytes  89.1 Mbits/sec  85/0         17     1434K/102543(436) us  109
[  1] 3.0000-4.0000 sec  10.6 MBytes  89.1 Mbits/sec  85/0          5     1084K/98726(154) us  113
[  1] 4.0000-5.0000 sec  10.5 MBytes  88.1 Mbits/sec  84/0          0     1159K/108859(1517) us  101
[  1] 5.0000-6.0000 sec  10.4 MBytes  87.0 Mbits/sec  83/0          0     1214K/110599(295) us  98
[  1] 6.0000-7.0000 sec  11.1 MBytes  93.3 Mbits/sec  89/0          0     1257K/114964(593) us  101
[  1] 7.0000-8.0000 sec  9.88 MBytes  82.8 Mbits/sec  79/0         27      928K/84814(172) us  122
[  1] 8.0000-9.0000 sec  11.1 MBytes  93.3 Mbits/sec  89/0          0      988K/92610(1164) us  126
[  1] 9.0000-10.0000 sec  10.5 MBytes  88.1 Mbits/sec  84/0          0     1027K/79623(1133) us  138
[  1] 0.0000-10.1963 sec   104 MBytes  85.3 Mbits/sec  829/0         49     1032K/90405(1236) us  118
iye
() автор топика
Ответ на: комментарий от iye

В моей конфигурации 2 особенности:

  1. Шейпинг осуществляется на wireguard интерфейсе (что, думаю, очевидно из скрипта)
  2. Ось запускается под xen гипервизором

Не понятно, на сколько это имеет значение.

iye
() автор топика