| 
 | |
|  | 
| 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. | 
| Закладки на сайте Проследить за страницей | Created 1996-2025 by Maxim Chirkov Добавить, Поддержать, Вебмастеру |