| Linux Advanced Routing & Traffic Control HOWTO | ||
|---|---|---|
| Назад | Глава 14. Специализированные дисциплины управления очередями. | Вперед |
Esteve Camps
Этот текст -- отрывки из моих тезисов Поддержка QoS в Linux, сентябрь 2000 года.
Исходные документы:
Примеры, прилагаемые к дистрибутиву iproute2
White Paper-QoS protocols and architectures и IP QoS Frequently Asked Questions.
Прежде всего, было бы неплохо, если бы вы предварительно ознакомились с RFC, посвященными данной теме (RFC2474, RFC2475, RFC2597 и RFC2598) по адресам: IETF DiffServ working Group и домашняя страничка проекта diffserv.
Dsmark -- это дисциплина организации очереди, которая предлагает возможности, необходимые в "Differentiated Services" (известной также, как DiffServ, или просто -- DS). DiffServ -- фактически одна из двух архитектур QoS (вторая называется "Integrated Services"), которая базируется на значении поля DS в заголовке IP-пакетов.
Одним из первых решений в IP, которое предлагало некоторый уровень QoS, был "Type of Service" (Тип Обслуживания) -- поле TOS в IP-заголовке. Изменяя это поле, можно было выбрать высокую/низкую пропускную способность, минимальную задержку или высокую надежность. Но это решение не обеспечивало достаточной гибкости, которую требовали вновь появляющиеся услуги (например, приложения реального времени, интерактивные приложения и т.п.). С появлением новых требований, появились и новые архитектуры. Одна из них -- DiffServ, которая подменяет первые шесть битов ToS в пакете IPv4 или октет "класс трафика" в пакете IPv6, полем, с названием DS, в котором можно указать до 64 классов трафика.
Differentiated Services (Дифференцированное Обслуживание) ориентирован на группы. Имеется ввиду, что эта технология ничего не знает о потоках, она ориентирована на группы, а применяемые правила зависят от того, к какой группе направляется пакет.
Сеть маршрутизаторов с поддержкой механизмов DiffServ называют "облаком DiffServ" (или "доменом DiffServ"). Классификация, формирование и установка меток (под установкой меток понимается установка значений в поле DS) происходит на входе в "облако". Внутри домена метка определяет -- какой уровень QoS должен применяться к трафику внутренними маршрутизаторами сети.
Самым большим преимуществом модели DiffServ является то, что она действует на границе "облака". После того как данные пересекли границу, внутренним маршрутизаторам можно не заниматься поддержанием информации о статусе QoS и полностью сосредоточиться на своей основной функции -- маршрутизации.
Фактически, внутри своих локальных доменов, вы можете диктовать любую политику обслуживания, но при соединении с другими DS-доменами вы должны следовать Соглашению об Уровне Обслуживания (SLA).
К этому моменту у вас наверняка возникла масса вопросов. Diffsrv -- это много больше, чем я смог сказать. Вы должны понять, что я не в состоянии в 50 строках изложить содержимое трех RFC. :-)
Как уже было определено выше, в случае с 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.
Эта дисциплина выполняет следующие шаги:
Если вставлена инструкция 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
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 0x2e tcindex classid 2:1 pass_on
(Это неполный код, я просто привел часть примера EFCBQ, включенного в состав дистрибутива
iproute2).
Будем исходить из предположения, что мы получаем пакет, помеченный как EF. Если вы прочитаете RFC2598, то увидите, что рекомендуемое значение DSCP для EF трафика -- 101110. Это означает, что в поле DS будет записано 10111000 (не забывайте, что младшие биты в поле TOS не используются в DS), или 0xb8, в шестнадцатиричном представлении.
TC INDEX
FILTER
+---+ +-------+ +---+-+ +------+ +-+ +-------+
| | | | | | | |FILTER| +-+ +-+ | | | |
| |----->| MASK | -> | | | -> |HANDLE|->| | | | -> | | -> | |
| | . | =0xfc | | | | |0x2E | | +----+ | | | | |
| | . | | | | | +------+ +--------+ | | | |
| | . | | | | | | | | |
-->| | . | SHIFT | | | | | | | |-->
| | . | =2 | | | +----------------------------+ | | |
| | | | | | CBQ 2:0 | | |
| | +-------+ +---+--------------------------------+ | |
| | | |
| +-------------------------------------------------------------+ |
| DSMARK 1:0 |
+-------------------------------------------------------------------------+
Полученный пакет имеет значение 0xb8 в поле DS. Дисциплина с идентификатором 1:0 считывает это значение
и помещает его в skb->tc_index. На следующем шаге (вторая строка в примере), описанный фильтр выполняет
следующие действия:
Value1 = skb->tc_index & MASK
Key = Value1 >> SHIFT
В нашем примере MASK=0xFC и SHIFT=2.
Value1 = 10111000 & 11111100 = 10111000
Key = 10111000 >> 2 = 00101110 -> 0x2E (в шестнадцатиричном виде)
Возвращаемое значение будет соответствовать фильтру внутренней qdisc (в примере, идентификатор 2:0).
Если фильтр с заданным идентификатором найден, то условия фильтра будут проверены (в случае, если фильтр
включает в себя эти условия) и будет возвращен classid (в нашем примере classid 2:1), который далее
будет записан в skb->tc_index. Если фильтр не будет найден, то результат будет зависеть от
объявления флага fall_through. Если объявление fall_through присутствует, то его значение будет
воспринято как classid. В противном случае продолжится просмотр остальных фильтров. Будьте предельно
внимательны, при использовании флага fall_through -- его использование рекомендуется только в том случае,
когда значение skb->tc_index и идентификаторы классов ссвязаны простыми (в смысле несложными)
отношениями.
И последние два параметра, которые мы опишем, это hash и pass_on. Первый из них определяет размер хеш-таблицы. Pass_on -- означает, что если не будет найден classid, равный результату этого фильтра, то необходимо попробовать применить следующий фильтр. Действие по-умолчанию -- fall_through (см. следующую таблицу).
В заключение посмотрим -- какие значения параметров TCINDEX допустимы:
TC Name Value Default
-----------------------------------------------------------------
Hash 1...0x10000 Зависит от реализации
Mask 0...0xffff 0xffff
Shift 0...15 0
Fall through / Pass_on Flag Fall_through
Classid Major:minor None
Police ..... None
Это очень мощный тип фильтров. Кроме того, он может использоваться не только в конфигурации
DiffServ, но и как любой другой тип фильтров.
Я настоятельно рекомендую вам внимательно просмотреть все примеры DiffServ, включаемые в дистрибутив iproute2. Со своей стороны я обещаю, что дополню этот текст, как только найду время. Все, что я здесь описал -- есть результат длительных экспериментов. Я буду весьма признателен, если вы сообщите мне об обнаруженных ошибках.
| Назад | В начало документа | Вперед |
| Алгоритм Кларка-Шенкера-Чанга. | К началу раздела | Ingress qdisc. |