QoS в Linux: фильтр U32

15 Фев
2012

Так повелось, что фильтр U32 в подсистеме управления трафиком ядра Linux считается простым и понятным, а потому в подробном документировании не нуждается. Например, в LARTC (Linux Advanced Routing and Traffic Control) про него лишь несколько абзацев. Но на самом деле U32 устроен гораздо сложнее и интереснее. Кому интересно, добро пожаловать под кат.


Сопоставление


И так, основная функция фильтра U32 в том, что он берёт некоторый блок данных из пакета, и сравнивает его с заданным значением. Если значения совпадают, то мы выполняем некоторые действия над пакетом. Блок данных в пакете задаётся следующими параметрами:

  • Размер блока данных. Определяется параметрами U32/U16/U8. Интуитивно понятно, что цифры — это длина блока в битах. Ядерная часть фильтра оперирует 32хбитными блоками.
  • Битовая маска. Нужна для того, если вы хотите проверить не весь блок данных, а только отдельные его биты. Естественна, длина маски должна совпадать с длиной блока. На блок накладывается маска с помощью операции побитового И, и результат этой операции уже сравнивается с заданным значением.
  • Смещение от начала пакета. Все смещения выравниваются по 32хбитной границе. Тут не всё так очевидно, как кажется, и позже мы об этом поговорим, но пока этого упрощения достаточно. Смещение, равное нулю, в большинстве случаев, соответствует началу заголовка сетевого уровня, т.е. началу IPv4/IPv6 пакета.


Например, возьмём следующий пример команды tc:

tc filter add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
u32 \
match u32 0xc0a80100 0xffffff00 at 12 \
classid 1:8


Мы добавляем фильтр типа u32 с приоритетом 10 к дисциплине 1:0 устройства eth0. И если сопоставление удачно, то пакет попадёт в класс 1:8. Седьмая строка нам особенно интересна, рассмотрим её подробно:

  • match u32 — задаёт начало условия сопоставления и размер блока данных, который будет взят из пакета.
  • 0xc0a80100 — это значение, с которым мы будем сравнивать байты из пакета.
  • 0xffffff00 — битовая маска, которая будет накладываться на данные из пакета, и результат уже будет сравниваться с тем, что мы задали. Если наше значение и маскированный блок данных равны, то выполняются определённые действия. В конечном итоге этим действием является классифицирование пакета.
  • at 12 — смещение от начала пакета IP (на это указывает параметр protocol ip в первой строке), по которому находится начало блока данных. Если этот параметр не указан, то смещение считается равным нулю.


Этими действиями мы проверяем адрес источника (в этом можно убедиться, если взглянуть на формат заголовка IPv4), и если он принадлежит подсети 192.168.1.0/24, то отправляем пакет в класс 1:8. Естественно, постоянно копаться в RFC слишком утомительно, да и всех смещений не упомнишь, поэтому tc предоставляет синтаксический сахар для часто употребляемых случаев. Например, наш пример становится гораздо понятнее, если записать его так:

tc filter add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
u32 \
match ip src 192.168.1.0/24 \
classid 1:8


В одной команде можно указать несколько параметров «match», причём сопоставление будет успешно только в том случае, если все условия будут выполняться. Отправим все пакеты с адресом источника 192.168.1.0/24 и значением ToS равным 0x10 (интерактивный трафик) в класс 1:1:

tc filter add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
u32 \
match ip src 192.168.1.0/24 \
match ip tos 0x10 0x1e \
classid 1:1


Проверим, правильно ли всё работает:
#смотрим наш фильтр
~$ tc -s -s f ls dev eth0
filter parent 1: protocol ip pref 10 u32
filter parent 1: protocol ip pref 10 u32 fh 800: ht divisor 1
filter parent 1: protocol ip pref 10 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1  (rule hit 1911 success 0)

  match c0a80100/ffffff00 at 12 (success 0 )
  match 00100000/001e0000 at 0 (success 0 )

#если задать ключ -p, то tc будет некоторые смещения преобразовывать
#в более удобочитаемый вид, а другие - скрывать
~$ tc -s -s -p f ls dev eth0
filter parent 1: protocol ip pref 10 u32
filter parent 1: protocol ip pref 10 u32 fh 800: ht divisor 1
filter parent 1: protocol ip pref 10 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1  (rule hit 3413 success 0)

  match IP src 192.168.1.0/24 (success 0 )  (success 0 )

#пингуем что-нибудь с заданным адресом источника и значением ToS
$ ping -f -I 192.168.1.1 -Q 0x10 www.ya.ru
PING ya.ru (93.158.134.3) from 192.168.1.1 : 56(84) bytes of data.
 
--- ya.ru ping statistics ---
107 packets transmitted, 107 received, 0% packet loss, time 619ms
rtt min/avg/max/mdev = 4.492/5.240/7.560/0.536 ms, ipg/ewma 5.842/5.403 ms

#смотрим, отрабатывает ли фильтр как положено
~$ tc -s -s f ls dev eth0
filter parent 1: protocol ip pref 10 u32 
filter parent 1: protocol ip pref 10 u32 fh 800: ht divisor 1 
filter parent 1: protocol ip pref 10 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1  (rule hit 354903 success 107)

  match c0a80100/ffffff00 at 12 (success 107 ) 
  match 00100000/001e0000 at 0 (success 107 )


Как видите, всё работает как и должно — пакеты попадают в нужный класс. Но если внимательно посмотреть на вывод tc, то некоторые моменты нам ещё неизвестны. Например, эти загадочные значения fh 800::800. Это так называемые хэндлы (использую кальку с английского «handle») — идентификаторы фильтров внутри U32.

Каждый хэндл отдельного фильтра состоит из трёх шестнадцатеричных цифр и уникален в пределах пространства фильтра U32. В нашем случае это хэндл 800::800. Нас сейчас интересует лишь последняя цифра — номер добавляемого фильтра. Если его не указывать, то система сама назначает его — следующий за самым старшим, начиная с 0x800. Номер фильтра находится в диапазоне от 0x001 до 0xfff. Можно вручную указать номер фильтра соответствующим параметром:

tc filter add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
handle ::1 \
u32 \
match ip src 192.168.1.0/24 \
match ip tos 0x10 0x1e \
classid 1:1


Фильтры выполняются в порядке следования их номеров.

Связывание


Пусть мы вешаем пару фильтров на дисциплину:

tc filter add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
handle ::1 \
u32 \
match ip src 192.168.1.0/24 \
match ip tos 0x10 0x1e \
classid 1:1

tc filter add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
handle ::2 \
u32 \
match ip src 192.168.1.0/24 \
match ip tos 0x08 0x1e \
classid 1:2


Оба фильтра будут иметь одинаковый префикс — первые два числа хэндла (800::). Если представить их записанными друг за другом в порядке следования номера — последнего номера хэндла, то получится некоторый список фильтров:

список 800:0:
::1 - ip src 192.168.1.0/24 tos 0x10 -> classid 1:1
::2 - ip src 192.168.1.0/24 tos 0x08 -> classid 1:2


Так как в фильтрах одного списка хэндлы различаются лишь последними числами, то сам список можно идентифицировать первыми двумя числами хэндлов — их префиксом (800:0). Как ранее говорилось, фильтры выполняются в порядке их следования. Если в каком-то из фильтров сопоставление было успешным, то выполняется некоторое действие и U32 завершает работу. Если же мы дошли до конца списка, и так и не получили ни одного успешного сопоставления, то фильтр U32 вернёт наверх неклассифицированный пакет.

u32 simple flow chart

Кроме классифицирования, действием может быть выполнение другого списка фильтров. Делается это с помощью параметра «link» вместо «classid», например, вот так:

tc filter add \
dev eth0 \
parent 1: \
prio 10 \
protocol ip \
handle ::2 \
u32 \
match ip src 192.168.1.0/24 \
link 1:


Если пакет имеет адрес источника из подсети 192.168.1.0/24, то начинает выполняться список фильтров с хэндлом 1:0. Если в нём не окажется успешных совпадений, мы вернёмся в прежний список 800:0 и продолжим его выполнение. В свою очередь, фильтры из списка 1:0 могут ссылаться на другие списки, а те на третьи и т.д. И так до семи переходов (кому этого мало, то можете изменить в исходниках ядра макроподстановку TC_U32_MAXDEPTH, а потом его перекомпилировать).



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

Хэширование


До этого мы рассматривали списки фильтров. Но на самом деле они являются лишь частью большей структуры, называемой хэш-таблицей. Хэш-таблица, в данном случае, представляет собой массив ячеек (англ. array of buckets), в каждой из которых хранится по одному списку фильтров.

В хэндлах первое число — это номер хэш-таблицы, а второе — это номер ячейки. Номера хэш-таблиц находятся в диапазоне от 0x000 до 0xfff, а ячеек — от 0x00 до 0xff. Количество ячеек может быть от 1 до 256, причём оно должно быть степенью двойки (другое значение не получится задать). Хэш-таблица с номером 0x800 называется корневой и состоит из одной ячейки, она создаётся автоматически. Работа фильтра всегда начинается с выполнения списка в ячейке 800:0.

Хэш-таблица создаётся следующей командой:

tc filter add \
dev eth0 \
parent 1: pref 10 \
protocol ip \
handle 1: \
u32 divisor 1


Где «handle 1:» задаёт номер хэш-таблицы, а «divisor 1» — количество ячеек в ней (в данном случае хэш-таблица имеет лишь одну ячейку).

Расширим наш пример с классифицированием по адресу источника и полю ToS с помощью переходов по спискам:

#добавляем классовую дисциплину prio с восемью дочерними классами
~$ tc q add \
dev eth0 \
root \
est 0.1s 10s \
handle 1: \
prio bands 8

#добавляем хэш-таблицу 1: с одной ячейкой
~$ tc f add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
handle 1: \
u32 \
divisor 1

#добавляем сопоставление по айпи-адресу источника
~$ tc f add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
handle ::1 \
u32 \
match ip src 192.168.1.0/24 \
link 1:

#добавляем сопоставление по полю ToS в хэш-таблицу 1:
~$ tc f add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
handle ::1 \
u32 \
ht 1: \
match ip tos 0x08 0x1e \
classid 1:3

~$ tc f add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
handle ::2 \
u32 \
ht 1: \
match ip tos 0x10 0x1e \
classid 1:1

#для того, чтобы показать, что происходит возврат в прежний
#список, добавим ещё одно правило
~$ tc f add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
handle ::2 \
u32 \
match ip src 192.168.1.0/24 \
classid 1:7

#просмотрим наши фильтры
~$ tc -s f ls dev eth0
filter parent 1: protocol ip pref 10 u32
filter parent 1: protocol ip pref 10 u32 fh 1: ht divisor 1
filter parent 1: protocol ip pref 10 u32 fh 1::1 order 1 key ht 1 bkt 0 flowid 1:3 (rule hit 0 success 0)

  match 00080000/001e0000 at 0 (success 0 )
filter parent 1: protocol ip pref 10 u32 fh 1::2 order 2 key ht 1 bkt 0 flowid 1:1 (rule hit 0 success 0)

  match 00100000/001e0000 at 0 (success 0 )
filter parent 1: protocol ip pref 10 u32 fh 800: ht divisor 1
filter parent 1: protocol ip pref 10 u32 fh 800::1 order 1 key ht 800 bkt 0 link 1: (rule hit 33900 success 0)

  match c0a80100/ffffff00 at 12 (success 0 )
filter parent 1: protocol ip pref 10 u32 fh 800::2 order 2 key ht 800 bkt 0 flowid 1:7 (rule hit 3583 success 0)

  match c0a80100/ffffff00 at 12 (success 0 )

#а теперь проверим работу, послав пакеты с различными значениями
#ToS из подсети 192.168.1.0/24, а затем проверив значения счётчиков
~$ ping -fc10 -I 192.168.1.1 -Q 0x08 8.8.8.8
~$ ping -fc15 -I 192.168.1.1 -Q 0x10 www.kernel.org
~$ ping -fc25 -I 192.168.1.1 -Q 0xaa www.habrahabr.ru

#смотрим ещё раз счётчики
~$ tc -s f ls dev eth0
filter parent 1: protocol ip pref 10 u32 
filter parent 1: protocol ip pref 10 u32 fh 1: ht divisor 1 
filter parent 1: protocol ip pref 10 u32 fh 1::1 order 1 key ht 1 bkt 0 flowid 1:3 (rule hit 50 success 10)

  match 00080000/001e0000 at 0 (success 10 ) 
filter parent 1: protocol ip pref 10 u32 fh 1::2 order 2 key ht 1 bkt 0 flowid 1:1 (rule hit 40 success 15)

  match 00100000/001e0000 at 0 (success 15 ) 
filter parent 1: protocol ip pref 10 u32 fh 800: ht divisor 1 
filter parent 1: protocol ip pref 10 u32 fh 800::1 order 1 key ht 800 bkt 0 link 1: (rule hit 578192 success 0)

  match c0a80100/ffffff00 at 12 (success 50 ) 
filter parent 1: protocol ip pref 10 u32 fh 800::2 order 2 key ht 800 bkt 0 flowid 1:7 (rule hit 547850 success 25)

  match c0a80100/ffffff00 at 12 (success 25 ) 


Но с помощью параметра «link» можно ссылаться только на списки фильтров, находящиеся в ячейке с номером 0. Как же тогда проверять списки в других ячейках? Для этого используется параметр «hashkey» и механизм хэширования. Смысл хэширования в U32 в том, что номер ячейки, на которую надо перейти, система получает на основе данных из пакета. Нужно это для сокращения количества проверок. В отличие от списка, время просмотра которого линейно зависит от количества фильтров в нём, хэширование выполняется за константное время. На больших количествах фильтров использование хэширования позволяет добиться на порядок большей производительности, чем с использованием одних только списков и переходов.



Перепишем наш предыдущий пример с использованием хэширования.

#добавляем хэш-таблицу с номером 1: на 32 ячейки
~$ tc f add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
handle 1: \
u32 \
divisor 32

#номер ячейки в данном случае совпадает со значением ToS
~$ tc f add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
handle 1:08:1 \
u32 \
ht 1:08 \
match u32 0 0 \
classid 1:3

~$ tc f add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
handle 1:10:1 \
u32 \
ht 1:10 \
match u32 0 0 \
classid 1:1

#все пакеты с адреcом источника 192.168.1.0/24 отправляем
#на проверку в хэш-таблицу 1: в ячейку равным значению полю ToS
~$ tc f add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
handle ::1 \
u32 \
match ip src 192.168.1.0/24 \
link 1: \
hashkey mask 0x001f0000 at 0

#правило для проверки того, что неклассифицированные пакеты
#возвращаются обратно в корневую таблицу
~$ tc f add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
handle ::2 \
u32 \
match ip src 192.168.1.0/24 \
classid 1:7

#посылаем пакеты с различным значением ToS
~$ ping -fc10 -I 192.168.1.1 -Q 0x08 8.8.8.8
~$ ping -fc30 -I 192.168.1.1 -Q 0x10 www.kernel.org
~$ ping -fc50 -I 192.168.1.1 -Q 0xaa www.habrahabr.ru

#и проверяем значения счётчиков фильтров
~$ tc -s f ls dev eth0
filter parent 1: protocol ip pref 10 u32
filter parent 1: protocol ip pref 10 u32 fh 1: ht divisor 32
filter parent 1: protocol ip pref 10 u32 fh 1:8:1 order 1 key ht 1 bkt 8 flowid 1:3 (rule hit 10 success 10)

  match 00000000/00000000 at 0 (success 10 )
filter parent 1: protocol ip pref 10 u32 fh 1:10:1 order 1 key ht 1 bkt 10 flowid 1:1 (rule hit 30 success 30)

  match 00000000/00000000 at 0 (success 30 )
filter parent 1: protocol ip pref 10 u32 fh 800: ht divisor 1
filter parent 1: protocol ip pref 10 u32 fh 800::1 order 1 key ht 800 bkt 0 link 1: (rule hit 30135 success 0)

  match c0a80100/ffffff00 at 12 (success 90 )
    hash mask 001f0000 at 0
filter parent 1: protocol ip pref 10 u32 fh 800::2 order 2 key ht 800 bkt 0 flowid 1:7  (rule hit 27250 success 50)

  match c0a80100/ffffff00 at 12 (success 50 )


Рассмотрим алгоритм хэширования в ядре 2.6 и более поздних на нашем примере:

  • Взять 32хбитное слово по смещению «at», указанному в параметре «hashkey». Так как смещение у нас нулевое, то берутся первые 32 бита IP-пакета.
  • Наложить на него битовую маску из того же параметра. Битовая маска у нас равна «0x001f0000», что соответствует положению поля ToS.
  • Результат сдвинуть в сторону младших разрядов на n-бит. Значение n вычисляется из маски и равно количествую младших нулевых бит в ней. В нашей маске количество младших нулевых бит равно 16, значит на эти 16 бит и будет сдвинуто маскированное двойное слово. После этого, значение ToS окажется в младших пяти разрядах.
  • На получившееся значение наложить маску 0xff. В данном случае это ничего не изменит. В других случаях это обнилит все октеты кроме младшего.
  • И в конце, если в целевой таблице меньше 256 ячеек, на результат накладывается битовая маска, равная числу k. Значение k на один меньше, чем ячеек в хэш-таблице, на которую будет переход. В нашей целевой таблице 32 ячейки, а значит значение k будет равно 31. После наложения этой маски наш результат гарантировано не будет больше количества ячеек.


В общем, ничего сложного. Но к сожалению, tc не предоставляет никаких средств для упрощения написания смещений в это случае, так что не получится написать что-нибудь вроде «hashkey ip tos». Другая сложность, это определение, в какую именую ячейку помещать фильтры. Тут путь только один — вручную считать хэш (в tc есть параметр sample, который позволяет автоматически высчитывать хэш для того, чтобы поместить фильтр в нужную ячейку, но алгоритм хэширования до сих пор от ядра 2.4 и для свежих ядер не подходит).

Смещения


Всё было бы совсем замечательно, если бы заголовки имели фиксированную длину. Но, к сожалению, это не так — заголовки могут иметь дополнительные элементы, что очень сильно затрудняет сопоставление по полям заголовков следующих уровней. К счастью, в U32 предусмотрено и это. Эта фича называется «header offsets» и предназначена для того, что бы узнать смещение следующего элемента из самого пакета.

Но сначала ознакомимся с двумя новыми понятиями фильтра U32: постоянное смещение (для краткости будем обозначать его как «permoff») и временное смещение (обозначим его как «tempoff»). Значение permoff всегда прибавляется ко всем указываемым смещениям при следующем и дальнейших переходах, осуществляемых с помощью параметра «link», и используется для вычисления новых значений permoff и tempoff. Значение tempoff прибавляется лишь к указываемым смещениям только при следующем переходе, и на дальнейшие переходы не влияет. При возвращении обратно в предыдущий список значения откатываются. Например, permoff равно нулю при выполнении списка 1:0, и у нас появилось успешное сопоставление, а новое значение permoff стало равным 20, при этом мы перешли к выполнению списка 2:5. В этом случае, ко всем указанным смещениям в фильтрах списка 2:5 будет прибавлено значение 20. Если в списке 2:5 у нас будет успешное сопоставление с переходом на список 3:12, и указано изменение постоянного смещения на 5, то новое значение permoff станет равным 25. И при выполнении списка 3:12 ко всем смещениям будет прибавляться уже значение 25. Если в списке 3:12 не будет успешных сопоставлений, то U32 вернётся назад к списку 2:5 и permoff снова станет равным 20. Если же и там не будет успешных сопоставлений, и мы вернёмся в список 1:0, то permoff станет уже равным нулю. По сути, мы просто ставим нулевое смещение равным началу пакета следующего уровня. Изначально значения permoff и tempoff равны нулю.

Заглянем в RFC (можно и в википедию, или куда-нибудь ещё) и посмотрим на формат заголовка IPv4. К счастью для нас, в нём предусмотрено специальное поле, значение которого равно длине заголовка в двойных словах. И мы можем использовать эту информацию для того. чтобы вычислить положение заголовка следующего уровня.

Делается это примерно так:

tc filter add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
u32 \
match ip src 192.168.1.0/24 \
match protocol 0x01 0xff
link 1: \
offset at 0 mask 0x0f00 shift 6 plus 0 eat 


Рассмотрим последнюю строку подробно и что при этом происходит:
  • offset — собственно и говорит о том, что мы изменяем значения permoff или tempoff, если сопоставление успешно и будет переход к списку 1:0
  • Система берёт одинарное слово по смещению, указаному в параметре «at». В нашем случае, он равен нулю, поэтому будут взяты первые 16 бит пакета.
  • Далее, на полученное из пакета значение накладывается битовая маска. У нас она равна 0x0f00, что соответствует положению поля длины заголовка IP. Допустим, что у нас в этом поле находится значение 5 (в двоичном представлении 0101). В двоичном формате результат предыдущих операций будет равен значению 0000.0101.0000.0000.
  • Мы знаем, что значение поля длины заголовка IP равно длине заголовка в двойных словах. А значит нам надо полученное значение каким-то образом преобразовать в байты. Дело осложняется тем, что в результате у нас нужные биты дополнительно смещены. Сместим значение так, чтобы оно оказалось в младших октетах (то есть сдвинем в сторону младших разрядов на 8) и получим 0000.0101. В одном двойном слове 4 байта, значит нам это значение нужно умножить на 4, что равносильно сдвигу в сторону старших разрядов на 2. После сдвига получим 0001.0100. Теперь сложим число бит, на которые мы сдвигали значения, считая, что двигаясь в сторону младших рязрядов это положительное число, а в сторону старших — отрицательное. Получаем 8 — 2 = 6. В итоге, чтобы получить длину заголовка в байтах, нам надо будет изначальное маскированное значение сдвинуть на шесть бит в сторону младших рязрядов. Сдвиг вправо задаётся параметром «shift». После всех операций мы получили значение 20.
  • К полученному значению прибавляется значение параметра «plus». В нашем случае, это 0, поэтому ничего и не прибавляется.
  • И параметр «eat» говорит, что вычисленное значение прибавляется к значению «permoff». Иначе будет вычисляться значение «tempoff».
  • В результате, при выполнении фильтров из списка 1:0, нулевое смещение будет соответствовать началу следующего заголовка (в нашем случае ICMP), и мы можем строить фильтры на основе сопоставления его полей, например, проверяя значения кода ICMP сообщения. Если же вы изменяете значение tempoff, то в вызванном списке надо явно его указывать, используя для смещений выражение «nexthdr+».


После этого, мы можем добавлять в список 1:0 фильтры с сопоставлением по типу ICMP сообщения. Например, пакеты ICMP типа Echo-Request отправим в класс 1:8.

~$tc f add \
dev eth0 \
parent 1: \
pref 10 \
protocol ip \
handle 1::1 \
u32 \
ht 1: \
match u8 0x08 0xff \
classid 1:8

#посмотрим на счётчики фильтров
~$ sudo tc -s f ls dev eth0
filter parent 1: protocol ip pref 10 u32 
filter parent 1: protocol ip pref 10 u32 fh 1: ht divisor 1 
filter parent 1: protocol ip pref 10 u32 fh 1::1 order 1 key ht 1 bkt 0 flowid 1:8  (rule hit 0 success 0)
  
match 08000000/ff000000 at 0 (success 0 ) 
filter parent 1: protocol ip pref 10 u32 fh 800: ht divisor 1 
filter parent 1: protocol ip pref 10 u32 fh 800::1 order 1 key ht 800 bkt 0 link 1:  (rule hit 48553 success 0)
  
  match c0a80100/ffffff00 at 12 (success 0 ) 
  match 00010000/00ff0000 at 8 (success 0 ) 
    offset 0f00>>6 at 0  eat

#отправим несколько эхо-реквестов
~$ ping -fc5 -I 192.168.1.1 www.ixbt.com

#и снова взглянем на значения счётчиков
~$ tc -s f ls dev eth0
filter parent 1: protocol ip pref 10 u32 
filter parent 1: protocol ip pref 10 u32 fh 1: ht divisor 1 
filter parent 1: protocol ip pref 10 u32 fh 1::1 order 1 key ht 1 bkt 0 flowid 1:8  (rule hit 5 success 5)
  
  match 08000000/ff000000 at 0 (success 5 ) 
filter parent 1: protocol ip pref 10 u32 fh 800: ht divisor 1 
filter parent 1: protocol ip pref 10 u32 fh 800::1 order 1 key ht 800 bkt 0 link 1:  (rule hit 149972 success 0)

  match c0a80100/ffffff00 at 12 (success 5 ) 
  match 00010000/00ff0000 at 8 (success 5 ) 
    offset 0f00>>6 at 0  eat 


В общем-то и всё. Спасибо за внимание.

Источник


Оригинал — The u32 filter. — автор, к сожалению, мне неизвестен.
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх