Как уже было определено выше, в случае с DiffServ, пограничные и внутренние узлы различаются между собой. Это два важных пункта на пути трафика. Оба типа узлов выполняют классификацию трафика. Результат классификации может использоваться для различной DS-обработки, прежде чем пакет уйдет в сеть. Код diffserv представляет пакет в виде структуры sk_buff, в которой имеется поле skb->tc_index. В данном поле сохраняется результат начальной классификации, который может использоваться для различной интерпретации DS на пограничных и внутренних маршрутизаторах.
Значение skb->tc_index изначально устанавливается дисциплиной DSMARK qdisc для каждого входящего пакета, в соответствии с полем DS в IP-заголовке. Кроме того, классификатор cls_tcindex считывает, целиком или частично, значение skb->tcindex и использует его для выбора нужного класса.
Для начала рассмотрим команду DSMARK qdisc и ее параметры:
… dsmark indices INDICES [ default_index DEFAULT_INDEX ] [ set_tc_index ]
Каково назначение этих параметров?
• indices: размер таблицы пар маска-значение. Максимальное значение 2^n, где n >= 0.
• Default_index: индекс в таблице, принимаемый по-умолчанию, если классификатор не находит ни одного совпадения.
• Set_tc_index: инструкция, которая считывает значение поля DS и записывает его в skb->tc_index.
14.3.5. Как работает SCH_DSMARK.
Эта дисциплина выполняет следующие шаги:
• Если вставлена инструкция set_tc_index, то считывается поле DS и сохраняется в skb->tc_index.
• Вызывается классификатор. Он возвращает идентификатор класса, который будет сохранен в skb->tc_index. Если такой класс не найден, то используется класс по-умолчанию из параметра default_index. Если ни set_tc_index, ни default_index не объявлены, то результат может оказаться непредсказуемым.
• После этого управление передается внутренней qdisc, где вы можете повторно использовать результаты фильтрации. Идентификатор класса, возвращаемый внутренней qdisc, запоминается в skb->tc_index. Это значение будет использоваться в качестве индекса таблицы маска-значение. Конечный результат, который будет связан с пакетом, получается из выражения:
New_Ds_field = (Old_DS_field & mask) | value
• Таким образом, конечный результат получается в результате объединения по "И" ds_field и маски, и затем объединения по "ИЛИ" с параметром value. Следующая диаграмма иллюстрирует этот процесс:
skb->ihp->tos
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >
| | ^
| -- Если объявлена инструкция set_tc_index, | | <-----Значение поля
| то значение DS переписывается в skb->tc_index | |O DS может измениться
| A| |R
+-|-+ +------+ +---+-+ внутренняя +-+ +---N|-----|----+
| | | | tc |--->| | |--> . . . -->| | | D| | |
| | |----->|index |--->| | | Qdisc | |---->| v | |
| | | |filter|--->| | | +---------------+ | ---->(mask,value) |
-->| O | +------+ +-|-+--------------^----+ / | (. , .) |
| | | ^ | | | | (. , .) |
| | +----------|---------|----------------|-------|--+ (. , .) |
| | sch_dsmark | | | | |
+-|------------|---------|----------------|-------|------------------+
| | | <- tc_index -> | |
| |(read) | может | | <--------------Индекс в таблице
| | | измениться | | (mask,value)
v | v v |
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->
skb->tc_index
Как установить метку? Просто измените mask и value класса. См. следующий код:
tc class change dev eth0 classid 1:1 dsmark mask 0x3 value 0xb8
Это изменение пары (mask,value) в хеш-таблице, пометит пакеты, принадлежащие классу 1:1.
Теперь перейдем к описанию фильтра TC_INDEX. Кроме всего прочего, фильтр TC_INDEX может использоваться и в других конфигурациях, а не только в тех, которые включают DS услуги.
Базовый синтаксис команды, объявляющей фильтр TC_INDEX:
… tcindex [ hash SIZE ] [ mask MASK ] [ shift SHIFT ]
[ pass_on | fall_through ]
[ classid CLASSID ] [ police POLICE_SPEC ]
Ниже приводится пример, который описывает работу TC_INDEX (обратите внимание на места, выделенные жирным шрифтом:
tc qdisc add dev eth0 handle 1:0 root dsmark indices 64 set_tc_index
tc filter add dev eth0 parent 1:0 protocol ip prio 1 tcindex mask 0xfc shift 2
tc qdisc add dev eth0 parent 1:0 handle 2:0 cbq bandwidth 10Mbit cell 8 avpkt 1000 mpu 64
# EF traffic class
tc class add dev eth0 parent 2:0 classid 2:1 cbq bandwidth 10Mbit rate 1500Kbit avpkt 1000 prio 1 bounded isolated allot 1514 weight 1 maxburst 10
# Packet fifo qdisc for EF traffic
tc qdisc add dev eth0 parent 2:1 pfifo limit 5
tc filter add dev eth0 parent 2:0 protocol ip prio 1 handle 0x2etcindex classid 2:1 pass_on
(Это неполный код, я просто привел часть примера EFCBQ, включенного в состав дистрибутива iproute2).
Будем исходить из предположения, что мы получаем пакет, помеченный как EF. Если вы прочитаете RFC2598, то увидите, что рекомендуемое значение DSCP для EF трафика — 101110. Это означает, что в поле DS будет записано 10111000 (не забывайте, что младшие биты в поле TOS не используются в DS), или 0xb8, в шестнадцатиричном представлении.
Читать дальше