• 9.1. Понятие очереди и дисциплины обработки
  • 9.2. Простые бесклассовые дисцплины обработки очереди.
  • 9.2.1. pfifo_fast
  • 9.2.1.1. Параметры и использование
  • 9.2.2. Token Bucket Filter
  • 9.2.2.1. Параметры и использование
  • 9.2.2.2. Пример конфигурации
  • 9.2.3. Stochastic Fairness Queueing.
  • 9.2.3.1. Параметры и использование
  • 9.2.3.2. Пример конфигурации
  • 9.3. Какие типы дисциплин нужно использовать.
  • 9.4. Терминология
  • 9.5. Классовые дисциплины обработки очередей.
  • 9.5.1. Порядок движения пакетов внутри полноклассовых дисциплин и классов.
  • 9.5.2. Элементы дисциплины: корень, дескриптор, родительские элементы и элементы одного уровня.
  • 9.5.2.1. Как выполняется классификация с помощью фильтров.
  • 9.5.2.2. Как выполняется извлечение пакетов из очереди.
  • 9.5.3. Дисциплина PRIO.
  • 9.5.3.1. Параметры и порядок использования дисциплины PRIO.
  • 9.5.3.2. Пример конфигурации.
  • 9.5.4. Дисциплина CBQ.
  • 9.5.4.1. Шейпинг в CBQ.
  • 9.5.4.2. Характеристики классов в CBQ.
  • 9.5.4.3. Параметры CBQ, управляющие характером заимствования.
  • 9.5.4.4. Пример конфигурирования.
  • 9.5.4.5. Прочие параметры настройки CBQ: split и defmap.
  • 9.5.5. Hierarchical Token Bucket
  • 9.5.5.1. Пример конфигурации.
  • 9.6. Классификация пакетов с помощью фильтров.
  • 9.6.1. Ряд простых примеров фильтрации.
  • 9.6.2. Наиболее употребимые способы фильтрации.
  • 9.7. Intermediate queueing device.
  • 9.7.1. Пример конфигурирования.
  • Глава 9. Дисциплины обработки очередей для управления пропускной способностью

    Когда я узнал об этом, я был в полнейшем восторге. Linux 2.2/2.4 содержит все необходимое для управления полосой пропускания на уровне специализированных систем управления пропускной способностью.

    Linux предоставляет даже больше возможностей, чем FrameRelay и ATM.

    Чтобы избежать путаницы, утилита tc использует следующие единицы измерения для задания пропускной способности:

    mbps = 1024 kbps = 1024 * 1024 bps => byte/s

    mbit = 1024 kbit => kilo bit/s.

    mb = 1024 kb = 1024 * 1024 b => byte

    mbit = 1024 kbit => kilo bit

    Хранятся данные в bps и b.

    Но при выводе, tc использует сделующее соглашение:

    1Mbit = 1024 Kbit = 1024 * 1024 bps => byte/s

    9.1. Понятие очереди и дисциплины обработки

    Организация очереди (очередизация) определяет способ отсылки данных. Важно понимать, что мы можем управлять лишь скоростью передачи отправляемых данных.

    В том виде, в каком сейчас существует Internet, мы не можем контролировать объем входящего трафика. Это что-то вроде почтового ящика (не электронного!). Нет никакого способа влиять на то, какой объем почты приходит к вам, разве что общаясь с каждым респондентом.

    Однако, Internet, в большистве своем, основан на протоколе TCP/IP, а у него есть несколько свойств, которые могут нам помочь. TCP/IP не может узнать пропускной способности сети между двумя хостами, поэтому он начинает передавать данные все быстрее и быстрее (это называется "медленный старт"). Когда пакеты начинают теряться из-за перегрузки передающей среды, передача тормозится. На самом деле все немного сложнее и умнее, но об этом позже.

    Продолжая нашу аналогию, это можно сравнить с выбрасыванием половины вашей почты в надежде на то, что люди перестанут вам писать. Разница лишь в том, что в случае с Internet этот прием срабатывает :-)

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

    Кроме того, вы должны быть уверенны, что контролируете узкое место соединения. Так, если у вас есть 100-мегабитная сетевая карта и маршрутизатор с соединением в 256 Кбит/сек, вы должны убедиться, что не посылаете данных больше, чем ваш маршрутизатор может передать. Иначе канал будет контролировать маршрутизатор и именно он будет ограничивать доступную пропускную способность. Нам нужно, так сказать, "владеть очередью" и быть самым медленным звеном. К счастью это легко реализуется.

    9.2. Простые бесклассовые дисцплины обработки очереди.

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

    Они могут использоватся для ограничения пропускной способности интерфейса целиком, без какого-либо разделения по классам. Крайне важно, чтобы вы поняли назначение этого типа очередей перед тем, как мы перейдем к классовым дисциплинам!

    Наиболее распространенной дисциплиной является pfifo_fast — она используется по умолчанию.

    Каждая из дисциплин имеет свои достоинства и недостатки. Не все из них досконально протестированы.

    9.2.1. pfifo_fast

    Эта дисциплина работает, как видно из названия, по принципу "первым пришел, первым ушел" (First In, First Out). Это означает, что ни один пакет не получает специальной обработки. Однако это не совсем так. Данная очередь имеет три, так называемых, "полосы". В каждой "полосе" пакеты обрабатываются по принципу FIFO. Но полоса 1 не будет обслуживаться до тех пор, пока есть пакеты в полосе 0. Аналогично, пока есть пакеты в полосе 1, не обрабатывается полоса 2.

    Ядро учитывает значение поля пакета Type of Service, и направляет пакеты с установленным флагом 'минимальная задержка' в полосу 0.

    Не путайте эту простую бесклассовую дисциплину с классовой дисциплиной PRIO! Хотя они ведут себя похожим образом, pfifo_fast является бесклассовой и вы не можете добавлять к ней другие дисциплины командой tc.

    9.2.1.1. Параметры и использование

    Вы не можете конфигурировать pfifo_fast, поскольку ее параметры жестко "зашиты". Вот ее конфигурация по умолчанию:

    priomap

    Определяет отображение пакетных приоритетов, присвоенных ядром, в полосы. Отображение основывается на значении поля TOS, которое выглядит следующим образом:

       0     1     2     3     4     5     6     7

    +-----+-----+-----+-----+-----+-----+-----+-----+

    |                 |                       |     |

    |   PRECEDENCE    |          TOS          | MBZ |

    |                 |                       |     |

    +-----+-----+-----+-----+-----+-----+-----+-----+

    Четыре бита TOS (поле TOS) определяются так:

    Двоичн Десятичн Значение 
    1000 8 Минимизировать задержку (md)
    0100 4 Максимальная пропускная способность (mt)
    0010 2 Максимальная надежность (mr)
    0001 1 Минимальная стоимость (mmc)
    0000 0 Обычное обслуживание

    Поскольку справа еще есть 1 бит, реальное значение поля TOS вдвое больше значения битов TOS. Команда tcpdump –v –v выводит значение всего поля TOS, а не только четырех бит. Оно приведено в первой колонке таблицы:

    TOS Биты Значение Приоритет Linux Полоса
    0x0 0 Normal Service 0 Best Effort 1
    0x2 1 Minimize Monetary Cost 1 Filler 2
    0x4 2 Maximize Reliability 0 Best Effort 1
    0x6 3 mmc+mr 0 Best Effort 1
    0x8 4 Maximize Throughput 2 Bulk 2
    0xa 5 mmc+mt 2 Bulk 2
    0xc 6 mr+mt 2 Bulk 2
    0xe 7 mmc+mr+mt 2 Bulk 2
    0x10 8 Minimize Delay 6 Interactive 0
    0x12 9 mmc+md 6 Interactive 0
    0x14 10 mr+md 6 Interactive 0
    0x16 11 mmc+mr+md 6 Interactive 0
    0x18 12 mt+md 4 Int. Bulk 1
    0x1a 13 mmc+mt+md 4 Int. Bulk 1
    0x1c 4 mr+mt+md 4 Int. Bulk 1
    0x1e 15 mmc+mr+mt+md 4 Int. Bulk 1

    Куча цифр. Вторая колонка содержит значение четырех значимых битов поля TOS, а в третьей расшифровывается значение. Например, 15 означает минимальную стоимость (Minimal Monetary Cost), максимальную надежность (Maximum Reliability), максимальную полосу пропускания (Maximum Throughput) и минимальную задержку (Minimum Delay).

    В четвертой колонке приведены соответствующие уровни приоритетов, выставляемые ядром Linux.

    В последней колонке демонстрируется результат отображения в полосы по-умолчанию. В командной строке это выглядит так:

    1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1

    Это означает, что, например, приоритет 4 отображается в первую полосу. priomap позволяет задавать и более высокие приоритеты (> 7) , которые не соответствуют полю TOS, но они используются в других целях.

    Ниже приводится таблица из документа RFC 1349 (за подробной информацией обратитесь к этому документу). Она показывает, каким образом приложения могут выставлять биты TOS:  

    TELNET 1000 (minimize delay)
    FTP Control 1000 (minimize delay)
    Data 0100 (maximize throughput)
    TFTP 1000 (minimize delay)
    SMTP Command phase 1000 (minimize delay)
    DATA phase 0100 (maximize throughput)
    Domain Name Service UDP Query 1000 (minimize delay)
    TCP Query 0000
    Zone Transfer 0100 (maximize throughput)
    NNTP 0001 (minimize monetary cost)
    ICMP Errors 0000
    Requests 0000 (mostly)
    Responses <same as request> (mostly)
    txqueuelen

    Длина этой очереди определяется конфигурацией интерфейса, просмотреть которую можно командами ifconfig и ip. Для задания очереди длиной 10, выполните: ifconfig eth0 txqueuelen 10.

    Вы не можете управлять этим параметром при помощи утилиты tc.

    9.2.2. Token Bucket Filter

    Token Bucket Filter (TBF) простая дисциплина очереди, которая передает поступающие пакеты со скоростью не превышающей административно заданный порог, но с возможностью превышающих его коротких всплесков.

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

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

    Каждый прибывающий токен сопоставляеться с одним пакетом данных из очереди после чего удаляется. Связав этот алгоритм с двумя потоками — токенов и данных, получим три возможных ситуации:

    • Данные прибывают со скоростью равной скорости входящих токенов. В этом случае каждый пакет имеет соответствующий токен и проходит очередь без задержки.

    • Данные прибывают со скоростью меньшей скорости поступления токенов. В этом случае лишь часть существующих токенов будет уничтожаться, потому они станут накапливаться до размера буфера. Далее, накопленные токены могут использоваться при всплесках, для передачи данных со скоростью превышающей скорость пребывающих токенов.

    • Данные прибывают быстрее, чем токены. Это означает, что в буфере скоро не останеться токенов, что заставит дисциплину приостановить передачу данных. Эта ситуация называется "превышением". Если пакеты продолжают поступать, они начинают уничтожаться.

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

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

    Учтите, что в реальной реализации дисциплины, токены соответствуют байтам, а не пакетам.

    9.2.2.1. Параметры и использование

    Не смотря на то, что вам вероятно ничего не придется менять, дисциплина TBF имеет определенные параметры. В первую очередь это:

    limit
    или
    latency

    Limit — это количество байт, которые могут быть помещены в очередь ожидания токенов. Эту же величину можно задать параметром latency, который определяет максимальный "возраст" пакета в очереди TBF. В последнем случае, во внимание принимается размер буфера, скорость и, если задана, пиковая скорость (peakrate).

    burst/buffer/maxburst

    Размер буфера в байтах. Максимальное количество байт, для которых токены могут быть доступны мгновенно. В целом, чем больше граничная скорость, тем больше должен быть размер буфера. Например, для ограничения на скорости 10 мбит/с на платформе Intel, вам нужен буфер размером как минимум 10 Кбайт, чтоб достичь заявленной скорости!

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

    mpu

    Пакет нулевого размера все равно использует полосу пропускания. В сетях ethernet, любой пакет имеет размер не менее 64 байт. MPU задает минимальное количество токенов для пакета.

    rate

    Ограничение скорости.


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

    peakrate

    Если на момент поступление пакета есть свободные токены, пакет пройдет очередь без каких-либо задержек. Так сказать, со скоростью света. Возможно, это не совсем то, чего вы хотите, особенно если вы используете большой буфер.

    Параметр peakrate задает скорость, с которой элемент может проходить очередь. Согласно теории, это достигается организацией достаточной задержки между проходящими пакетами.

    mtu/minburst

    По умолчанию, значение mtu равно одному пакету, т.е. за раз проходит только один пакет.

    9.2.2.2. Пример конфигурации

    Простая, но очень полезная конфигурация:

    # tc qdisc add dev ppp0 root tbf rate 220kbit latency 50ms burst 1540

    Чем же она так замечательна? Если у вас есть сетевое устройство с большой очередью, такое как DSL или кабельный модем, а вы обмениваетесь с ним данными через быстрое соединение, например ethernet, вы обнаружите, что закачки полностью уничтожают возможность интерактивной работы.

    Это связано с тем, что закачки заполняют очередь модема, которая часто очень большая. Большой размер очереди позволяет достичь хороших результатов при передаче больших объемов данных, но ведь это не совсем то, что вам нужно. Вы хотите, чтобы оставалась интерактивность и вы могли бы делать еще что-то полезное во время закачки.

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

    Замените 220 Кбит на реальную скорость, минус несколько процентов. Если у вас действительно быстрый модем, можете немного увеличить параметр burst.

    9.2.3. Stochastic Fairness Queueing.

    Stochastic Fairness Queueing (SFQ) – простая реализация семейства алгоритмов справедливой очередизации. Она не так точна, как другие дисциплины, но требует меньше расчетов, и при этом поровну распределяет доступную полосу пропускания между сеансами.

    Ключевым понятием в SFQ является диалог (или поток), который приблизительно соответствует сеансу TCP или потоку UDP. Трафик делится на достаточное количество очередей типа FIFO, по одной на каждый диалог. После этого, все очереди обрабатываются в циклическом порядке, тем самым обеспечивая каждому сеансу равные шансы на передачу данных.

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

    Из-за использования хеша, несколько сессий могут попасть в одну и ту же очередь, что уменьшает шансы на передачу каждого сеанса. Для того, чтобы эта проблема не ощущалась, SFQ часто меняет алгоритм хеширования, поэтому, если сессии и попадут в одну очередь, длиться это будет лишь несколько секунд.

    Стоит заметить, что SFQ эффективен только если исходящий интерфейс полностью загружен! В противном случае очередь будет отсутствовать и, следовательно, никакого положительного эффекта наблюдаться не будет. Позже мы рассмотрим варианты комбинирования SFQ с другими дисциплинами для достижения наилучшего результата.

    В частности, применение SFQ на ethernet интерфейсе к которому подключен кабельный модем или DSL маршрутизатор совершенно бессмыслено без органичения полосы пропускания!

    9.2.3.1. Параметры и использование

    SFQ в значительной степени самоконфигурирующаяся:

    perturb

    Интервал изменения алгоритма хеширования. Если не задан – алгоритм меняться не будет, что не рекомендуется. Хорошим значением является 10 секунд.

    quantum

    Количество байт выводимых из очереди за один раз. По-умолчанию равно 1 пакету максимально возможного размера (MTU). Не устанавливайте этот параметр меньшим этого значения!

    limit

    Общее количество пакетов, которые могут быть помещены в очередь SFQ (последующие пакеты будут уничтожаться).

    9.2.3.2. Пример конфигурации

    Если у вас есть устройство, скорость соединения которого равна доступной полосе пропускания, например модем, следующий пример обеспечит разделение его возможностей между всеми пользователями:

    # tc qdisc add dev ppp0 root sfq perturb 10

    # tc –s –d qdisc ls

    qdisc sfq 800c: dev ppp0 quantum 1514b limit 128p flows 128/1024 perturb 10sec

     Sent 4812 bytes 62 pkts (dropped 0, overlimits 0)

     Число 800c: это автоматически присваиваемый дескриптор, параметр limit говорит, что в очереди может находиться до 128 пакетов. Доступно 1024 хеш-буфера, из которых 128 может быть активно (максимальное число пакетов в очереди). Каждые 10 секунд хеши будут перенастраиваться.

    9.3. Какие типы дисциплин нужно использовать.

    Обобщая вышесказанное: мы рассмотрели простые дисциплины очередей, которые управляют трафиком переупорядочиванием, задержкой или уничтожением пакетов.

    Следующие советы могут помочь при выборе типа применяемой дисциплины. Здесь также упоминаются некоторые дисциплины, описываемые в главе 14.

    • Чтобы просто ограничить скорость интерфейса, используйте Token Bucket Filter. Маштабируется до больших скоростей, при соответствующем увеличении буфера.

    • Если ваш канал полностью загружен и при этом вы не желаете допустить доминирование какого-либо сеанса, используйте SFQ.

    • Если вы хотите управлять скоротью магистральных каналов и хорошо понимаете как это делается, используйте Random Early Drop (описывается в главе14).

    • Для управления скоростью входящего трафика, который не пересылается, используйте ограничитель (Ingress Policer).

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

    • Если вам не нужно ограничивать полосу пропускания, но вы хотите видеть, справляется ли ваш интерфейс с нагрузкой, используйте очередь pfifo (не pfifo_fast). У нее нет внутренних полос, но она ведет учет использования очереди.

    • Наконец, вы можете использовать "человеческий" фактор. Использование технологических решений не всегда приводит к желаемым результатам. Пользователи враждебно относятся к техническим ограничениям. Доброе слово тоже может помочь в правильном распределении пропускной способности!

    9.4. Терминология

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

    Следующие описания являются вольной трактовкой документа draft-ietf-diffserv-model-06.txt — An Informal Management Model for Diffserv Routers (Неформальная Модель Управления для Маршрутизаторов, работающих под управлением Diffserv). Этот документ находится по адресу: http://www.ietf.org/internet-drafts/draft-ietf-diffserv-model-06.txt. В нем вы найдете строгие определения используемых терминов.

    Queueing Discipline (qdisc)

    Алгоритм управления очередью устройства, как входящей (ingress), так и исходящей (egress).

    root qdisc

    Корневая дисциплина организации очереди (qdisc), т.е. дисциплина применяемая к устройству.

    Classless qdisc

    Бесклассовая дисциплина организации очереди — дисциплина, которая воздействует на устройство целиком, без возможности классификации трафика.

    Classful qdisc

    Полноклассовая дисциплина организации очереди (qdisc). Может содержать множество классов и других дисциплин, которые в свою очередь могут являться полноклассовыми. Согласно этому определению, дисциплина pfifo_fast — полноклассовая, поскольку она содержит три полосы пропускания, которые фактически являются классами. Однако, с точки зрения пользователя (администратора сети), она является бесклассовой, так как принцип действия этих классов не может быть изменен с помощью утилиты tc.

    Classes

    Классы. Полноклассовые дисциплины организации очереди могут состоять из множества классов, каждый из которых является внутренним, по отношению к данной дисциплине. В свою очередь, классы так же могут содержать другие классы. Таким образом, класс может иметь, в качестве "родительского", другой класс или дисциплину. Краевой класс — это класс, который не имеет вложенных классов. Такой класс имеет единственную, присоединенную к нему, дисциплину организации очереди. Эта дисциплина отвечает за передачу данных из этого класса. При создании класса, к нему по-умолчанию присоединяется дисциплина fifo. При добавлении вложенного класса, дисциплина удаляется. Для краевых классов, созданная по-умолчанию дисциплина fifo может быть заменена на более подходящую вашим требованиям, вплоть до того, что можно назначить полноклассовую дисциплину, с набором своих внутренних классов!

    Classifier

    Классификатор. Каждая полноклассовая дисциплина должна "разбить" трафик по классам. Выполняется это с помощью классификаторов.

    Filter

    Фильтр. Классификация может выполняться и с помощью фильтров. Фильтры представляют собой ряд условий, благодаря которым выясняется – подпадает ли тот или иной пакет под действие фильтра.

    Scheduling

    Планирование. Дисциплины, с помощью классификаторов, могут изменять порядок прохождения пакетов. Процесс переупорядочивания называется Планированием. К слову, дисциплина pfifo_fast, упоминавшаяся выше, производит планирование.

    Shaping

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

    Policing

    Ограничение. Под этим термином подразумевается процесс задержки или сброса (умышленной потери) пакетов, с целью ограничения пропускной способности. В Linux под термином Policing подразумевается только сброс пакетов, если ограничение накладывается не на входящую очередь.

    Work-Conserving

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

    non-Work-Conserving

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

    Теперь, когда мы определились с терминологией, рассмотрим все вышесказанное на следующей диаграмме:

             Пользовательские программы

                         ^

                         |

         +---------------+-----------------------------------------+

         |               Y                                         |

         |    -------> IP Stack                                    |

         |   |              |                                      |

         |   |              Y                                      |

         |   |              Y                                      |

         |   ^              |                                      |

         |   |  / ----------> Forwarding ->                        |

         |   ^ /                           |                       |

         |   |/                            Y                       |

         |   |                             |                       |

         |   ^                             Y          /-qdisc1-\   |

         |   |                         Исходящий     /--qdisc2--\  |

      --->->Входящая                   Классификатор ---qdisc3---- | ->

         |  Дисциплина                               \--qdisc4--/  |

         |                                            \-qdiscN-/   |

         |                                                         |

         +---------------------------------------------------------+

    Большой объемлющий блок, на диаграмме, представляет собой ядро. Стрелка слева показывает входящий трафик. Он подается во входящую дисциплину, которая может содержать ряд фильтров, посредством которых отдельные пакеты могут быть отброшены (потеряны, отфильтрованы). Это называется Ограничением (Policing).

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

    Если пакет благополучно миновал эту стадию, то далее он может быть передан либо локальным приложениям (в этом случае он попадает в стек IP для дальнейшей обработки), либо в сеть, через исходящий классификатор, на другой узел сети. Пользовательские приложения так же могут отправлять данные в сеть, которые аналогичным образом движутся через исходящий классификатор. Исходящий классификатор "разбивает" трафик по очередям, каждая из которых имеет свою дисциплину организации. В случае конфигурации по-умолчанию имеется единственная исходящая очередь — pfifo_fast. Этот процесс называется "постановкой в очередь".

    Попав в соответствующую очередь, пакет ожидает, пока ядро передаст его сетевому интерфейсу. Этот процесс называется "выборка из очереди".

    Эта диаграмма годится и для случая с одним сетевым интерфейсом — не следует рассматривать стрелки на ней слишком буквально.

    9.5. Классовые дисциплины обработки очередей.

    Классовые дисциплины широко используются в случаях, когда тот или иной вид трафика необходимо обрабатывать по разному. Примером классовой дисциплины может служить CBQ — class based queueing (дисциплина обработки очередей на основе классов). Она настолько широко известна, что многие идентифицируют понятие "Дисциплина Обработки Очередей" с названием CBQ, однако это далеко не так.

    CBQ — один из старейших алгоритмов и кроме того — один из самых сложных. К сожалению он может далеко не все. Это может оказаться неожиданностью для тех, кто свято верит в то, что если какая-либо достаточно сложная технология распространяется без документации, то это лучшая технология из имеющихся вариантов.

    Чуть ниже мы поближе рассмотрим CBQ и его альтернативы.

    9.5.1. Порядок движения пакетов внутри полноклассовых дисциплин и классов.

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

    Фильтры, присоединенные к дисциплине, возвращают результат классификации (грубо говоря — класс пакета), после чего пакет передается в очередь, соответствующую заданному классу. Каждый из классов, в свою очередь, может состоять из подклассов и иметь свой набор фильтров, для выполнения более точной классификации свой доли трафика. В противном случае пакет обслуживается дисциплиной очереди класса.

    Кроме того, в большинстве случаев классовые дисциплины выполняют шейпинг (формирование) трафика, с целью переупорядочивания пакетов (например, с помощью SFQ) и управления скоростью их передачи. Это определенно необходимо в случае перенаправления трафика с высокоскоростного интерфейса (например, ethernet) на медленный (например, модем).

    9.5.2. Элементы дисциплины: корень, дескриптор, родительские элементы и элементы одного уровня.

    Каждый из интерфейсов имеет одну исходящую корневую дисциплину. По-умолчанию это, упоминавшаяся ранее дисциплина — pfifo_fast. Каждой дисциплине и каждому классу назначается уникальный дескриптор, который который может использоваться последующими инструкциями для ссылки на эти дисциплины и классы. Помимо исходящей дисциплины, интерфейс так же может иметь и входящую дисциплину, которая производит управление входящим трафиком.

    Дескрипторы дисциплин состоят из двух частей – старшего и младшего номеров, в виде: <старший>:<младший>. Корневой дисциплине общепринято присваивать дескриптор '1:', что эквивалентно записи '1:0'. Младший номер в дескрипторе любой дисциплины всегда '0'.

    Старшие номера дескрипторов классов всегда дублируют старший номер дескриптора своего "родителя". Старший номер должен быть уникальным в пределах блоков настроек для входящего и исходящего трафиков. Младший номер должен быть уникальным в пределах дисциплины и ее классов.

    9.5.2.1. Как выполняется классификация с помощью фильтров.

    Типичная иерархия может выглядеть следующим образом:

                          1:   корневая дисциплина

                          |

                         1:1    дочерний класс

                       /  |  \

                      /   |   \

                     /    |    \

                     /    |    \

                  1:10  1:11  1:12   дочерние классы

                   |      |     |

                   |     11:    |    краевой класс

                   |            |

                   10:         12:   дисциплины

                  /   \       /   \

               10:1  10:2   12:1  12:2   краевые классы

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

    Порядок классификации некоторого пакета может быть представлен в виде цепочки, например:

    1: → 1:1 → 1:12 → 12: → 12:2

    Таким образом, пакет помещается в очередь, которая управляется дисциплиной, присоединенной к классу 12:2. В данном примере, к каждому узлу дерева присоединен фильтр, который принимает решение — по какой ветви продолжить классификацию пакета. Но возможен и другой вариант:

    1: → 12:2

    В этом случае, фильтр, присоединенный к корню, сразу же классифицировал пакет, как принадлежащий классу 12:2.

    9.5.2.2. Как выполняется извлечение пакетов из очереди.

    Когда ядро решает, что пора извлечь очередной пакет из очереди и передать его сетевому интерфейсу, оно посылает запрос на извлечение корневой дисциплине. Далее этот запрос передается по цепочке классу 1:1, а от него всем элементам одного уровня — 10:, 11:, и 12:. В данном случае запрос полностью обходит все дерево, поскольку только класс 12:2 имеет пакет.

    Проще говоря, вложенные классы "общаются" ТОЛЬКО со своими "родительскими" дисциплинами и никогда не работают напрямую с интерфейсом. Только корневая дисциплина получает запрос на извлечение пакета из очереди напрямую от ядра!

    В результате, классы никода не получат запрос на извлечение раньше, чем это будет сделано их "родителями". А это как раз и есть то, что нам нужно: мы можем определить внутренний класс, который выполняет только планирование и дисциплину, которая отвечает за шейпинг.

    9.5.3. Дисциплина PRIO.

    Дисциплина PRIO фактически никак не ограничивает трафик, она лишь выполняет его классификацию на основе присоединенных к ней фильтров. Вы можете рассматривать дисциплину PRIO как более мощную версию pfifo_fast, в которой каждая из полос является отдельным классом, а не простой очередью FIFO.

    Постановка пакета в очередь выполняется дисциплиной PRIO на основе фильтров, заданных вами. По-умолчанию создаются три класса. Эти классы по-умолчанию содержат обычные дисциплины FIFO, но они могут быть заменены дисциплинами любого типа, какие вам только доступны.

    Когда необходимо извлечь пакет из очереди, то первым проверяется класс :1. Каждый последующий класс проверяется только в том случае, если в предыдущем нет ни одного пакета.

    Эта дисциплина может с успехом применяться в тех случаях, когда необходимо "раскидать" трафик по приоритетам, основываясь не только на флагах TOS. Вы можете так же добавить другие дисциплины к предопределенным классам, что повысит возможности управления трафиком, по сравнению с pfifo_fast.

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

    Формально, дисциплина PRIO относится к разряду планировщиков типа Work-Conserving.

    9.5.3.1. Параметры и порядок использования дисциплины PRIO.

    Применительно к данной дисциплине, утилита tc допускает следующие параметры:

    bands

    Число создаваемых полос. Каждая полоса фактически является классом. Если вы изменяете это число, то вы должны так же изменить и следующий параметр.

    priomap

    Если ваша конфигурация не предусматривает наличие фильтров, выполняющих классификацию трафика, то дисциплина PRIO присваивает приоритеты по-умолчанию.

    Все это работает точно так же, как и в случае с pfifo_fast.

    Каждая полоса является классом и имеет свой дескриптор, начиная с <старший_номер>:1 и заканчивая <старший_номер>:3, по умолчанию. Таким образом, если дисциплине PRIO присвоен дескриптор 12: , то класс-полоса с наивысшим приоритетом получит дескриптор 12:1.

    Повторюсь еще раз, полоса 0 получит младший номер дескриптора — 1! Полоса 1 — 2 и так далее.

    9.5.3.2. Пример конфигурации.

    В качестве примера создадим такое дерево:

                 1:   корневая дисциплина

               / | \

              /  |  \

             /   |   \

           1:1  1:2  1:3    классы

            |    |    |

           10:  20:  30:    дисциплины

           sfq  tbf  sfq

    полоса  0    1    2

    Объемный трафик будет обслуживаться дисциплиной 30: , интерактивный — 20: или 10:.

    Конфигурирование:

    # tc qdisc add dev eth0 root handle 1: prio

    ## Эта команда создаст классы 1:1, 1:2, 1:3


    # tc qdisc add dev eth0 parent 1:1 handle 10: sfq

    # tc qdisc add dev eth0 parent 1:2 handle 20: tbf rate 20kbit buffer 1600 limit 3000

    # tc qdisc add dev eth0 parent 1:3 handle 30: sfq

    Теперь посмотрим – что у нас получилось:

    # tc –s

    qdisc ls dev eth0 qdisc sfq 30: quantum 1514b

    Sent 0 bytes 0 pkts (dropped 0, overlimits 0)


    qdisc tbf 20: rate 20Kbit burst 1599b lat 667.6ms

    Sent 0 bytes 0 pkts (dropped 0, overlimits 0)


    qdisc sfq 10: quantum 1514b

    Sent 132 bytes 2 pkts (dropped 0, overlimits 0)


    qdisc prio 1: bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1

    Sent 174 bytes 3 pkts (dropped 0, overlimits 0)

    Как видите, через полосу 0 уже "проскочил" какой-то трафик, пока отрабатывали наши команды!

    Теперь выполним передачу достаточно большого объема данных неким инструментом, который корректным образом устанавливает флаги TOS и проверим еще раз:

    # scp tc ahu@10.0.0.11:./

    ahu@10.0.0.11's password:

    tc 100% |*****************************| 353 KB 00:00

    # tc –s qdisc ls dev eth0

    qdisc sfq 30: quantum 1514b

    Sent 384228 bytes 274 pkts (dropped 0, overlimits 0)


    qdisc tbf 20: rate 20Kbit burst 1599b lat 667.6ms

    Sent 2640 bytes 20 pkts (dropped 0, overlimits 0)


    qdisc sfq 10: quantum 1514b

    Sent 2230 bytes 31 pkts (dropped 0, overlimits 0)


    qdisc prio 1: bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1

    Sent 389140 bytes 326 pkts (dropped 0, overlimits 0)

    На этот раз видно, что весь трафик был отправлен через дисциплину 30:, которая в нашем случае имеет наименьший приоритет. Чтобы убедиться в том, что интерактивный трафик поступает в высокоприоритетные полосы, выполним следующую команду:

    # tc –s qdisc ls dev eth0

    qdisc sfq 30: quantum 1514b

    Sent 384228 bytes 274 pkts (dropped 0, overlimits 0)


    qdisc tbf 20: rate 20Kbit burst 1599b lat 667.6ms

    Sent 2640 bytes 20 pkts (dropped 0, overlimits 0)


    qdisc sfq 10: quantum 1514b

    Sent 14926 bytes 193 pkts (dropped 0, overlimits 0)


    qdisc prio 1: bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1

    Sent 401836 bytes 488 pkts (dropped 0, overlimits 0)

    Как видите, все работает правильно, весь трафик был отправлен в 10: — через самую высокоприоритетную дисциплину.

    9.5.4. Дисциплина CBQ.

    Как уже упоминалось ранее, CBQ — одна из самых сложных дисциплин. Пожалуй я не погрешу против истины, если заявлю, что это самая объемная, самая непонятная и самая запутанная дисциплина организации очередей. Это не потому, что авторы алгоритма некомпетентны, а потому, что идеология этого алгоритма абсолютно не совпадает с идеологией Linux.

    Кроме того, что эта дисциплина является классовой, она так же может выполнять и шейпинг трафика, правда именно эта ее сторона является самым слабым местом. Если вы попробуете ограничить 10 мегабитный канал величиной в 1 мегабит, то окажется, что соединение будет просто простаивать 90% всего времени. Вместо определения объема трафика, CBQ измеряет время в микросекундах между запросами и на основе полученного времени рассчитывается средняя загруженность канала.

    Такой алгоритм работы не всегда дает нужные результаты. Например, что если сетевой интерфейс не может обеспечить полную загрузку канала на всю его возможную ширину, из-за некачественного драйвера? Как тогда правильно определить время простоя?

    Проблема становится еще острее, если вам приходится иметь дело с такими вещами, как PPP через Ethernet или PPTP через TCP/IP. Эффективная пропускная способность в данном случае может быть определена как пропускная способность канала в пространство пользователя, а это величина очень не маленькая.

    Те, кто близко сталкивался с CBQ отмечают, что эта дисциплина не всегда точна, и иногда допускает грубые просчеты при измерении времени.

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

    9.5.4.1. Шейпинг в CBQ.

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

    В процессе работы измеряется эффективное время простоя, как экспоненциальное взвешенное среднее по скользящему окну. Кстати, UNIX рассчитывает величину loadaverage (средняя величина нагрузки) аналогичным способом.

    Расчетное время простоя вычитается из взвешенного среднего, в результате получается величина avgidle. Полностью загруженный канал имеет величину avgidle равную нулю – промежуток времени между пакетами точно совпадает с расчетным. В случае превышения заданного ограничения, величина avgidle становится отрицательной. Если превышение достигает некоторого порога, CBQ приостанавливает передачу.

    С другой стороны, после нескольких часов простоя, величина avgidle может получиться слишком большой и это приведет к тому, что канал "распахнется" на всю ширину. Чтобы этого не происходило, величина avgidle ограничивается числом maxidle.

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

    Рассмотрим параметры дисциплины CBQ, позволяющие настроить ограничение полосы пропускания:

    avpkt

    Усредненный размер одного пакета. Совместно с величиной maxburst (которая измеряется в пакетах) используется для вычисления значения maxidle.

    bandwidth

    Физическая пропускная способность устройства. Необходима для вычисления времени простоя.

    cell

    Время, необходимое на передачу пакета через интерфейс может увеличиваться с определенным шагом. Например, передача пакетов с размерами 800 и 806 байт займет одно и тоже время, а пакетов с размерами 810 байт – немного больше. Данный параметр задает размер шага, с которым увеличивается расчетное время передачи. Чаще всего устанавливается значение '8'. Значение должно быть степенью числа 2.

    maxburst

    Параметр используется для вычисления значения maxidle. Он задает количество усредненных пакетов, которые будут обработаны до того, как значение avgidle станет равным нулю. Параметр maxidle нельзя задать напрямую, только косвенно, с помощью этого параметра.

    minburst

    Как я уже говорил, в случае перегрузки, CBQ должна прекратить передачу данных. Идеальным решением является ожидание в течение расчетного промежутка времени, после этого передать один пакет и снова приостановить передачу. Однако, в Unix существует определенные сложности с измерением интервалов времен, короче 10 мс, потому лучше увеличить промежуток ожидания, после которого можно будет выполнить передачу уже не одного, а несколько пакетов, количество которых определяется параметром minburst . Соответственно, промежуток ожидания между передачей пакетов увеличивается пропорционально значению данного параметра.

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

    minidle

    Отрицательное значение avgidle указывает, что канал перегружен, и нужно прекратить передачу на время, пока avgidle не увеличится достаточно для передачи следующего пакета. Однако, это может вызвать длительные периоды ожидания после интенсивных всплесков трафика. В таких случаях avgidle присваивается значение параметра minidle.

    Величина minidle измеряется в отрицательных микросекундах, следовательно значение "10" говорит о том, что параметр avgidle не может опуститься ниже –10 микросекунд.

    mpu

    Минимальный размер пакета — необходим, поскольку даже "пустой" пакет дополняется до 64 байт для передачи по сети ethernet, и передача такого пакета занимает определенное время. Алгоритм CBQ должен знать минимальный размер, чтобы правильно рассчитать время простоя.

    rate

    Желаемая величина пропускной способности. Для данной дисциплины — это "педаль газа"!

    Внутрення реализация CBQ имеет ряд дополнительных настроек. Например, классы, в очередях которых нет данных, не опрашиваются. Для классов, допустивших перегрузку, понижается значение эффективного приоритета. В принципе все достаточно грамотно, хотя и очень сложно.

    9.5.4.2. Характеристики классов в CBQ.

    Кроме ограничения полосы пропускания, CBQ имеет возможность классифицировать трафик, подобно дисциплине PRIO, и назначать классам приоритеты.

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

    Следующие параметры позволяют управлять процессом выборки данных:

    allot

    Когда производится выбор пакета для передачи, CBQ начинает опрашивать свои подклассы в соответствии с их приоритетами. Когда классу предоставляется возможность передачи, выбирается определенный объем данных. Базовая единица этого объема определяется параметром allot.

    prio

    Приоритет. Дисциплина CBQ может присваивать классам приоритеты. Чем меньше значение — тем выше приоритет. Пока не будет обработан трафик с высшим приоритетом, трафик с меньшим приоритетом не обрабатывается.

    weight

    Вес. Каждому из имеющихся классов предоставляется возможность передать данные. Если у вас есть классы, которые значительно отличаются полосой пропускания, имеет смысл разрешить классам с большой пропускной способностью посылать за раз больше данных, чем классам с небольшой пропускной способностью

    Дисциплина CBQ вычисляет сумму весов всех классов и затем нормирует их полученной величиной, потэому, в качестве весов, можно использовать любые значения: важно отношение этих значений. Обычно используется простое правило: вес = полоса пропускания / 10. Для определения количества данных, посылаемых классом за раз, нормированное значение умножается на величину allot.

    Обратите внимание: все внутренние классы дисциплины должны иметь одинаковый старший номер дескриптора!

    9.5.4.3. Параметры CBQ, управляющие характером заимствования.

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

    Isolated/sharing

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

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

    bounded/borrow

    Эти два параметра определяют, может ли класс занимать пропускающую способность других классов. Параметр bounded запрещает, а borrow разрешает занимать неиспользуемую часть полосы пропускания классов, сконфигурированных с параметром sharing.

    Примером, когда используются классы с параметрами bounded и isolated, может послужить ситуация использования одного канала двумя организациями. В этом случае они действительно будут ограничены заданной полосой пропускания.

    Внутри каждого такого класса могут находиться подклассы с опциями sharing и borrow. В этой ситуации заем будет выполняться в пределах родительского класса.

    9.5.4.4. Пример конфигурирования.

                   1:           корневая дисциплина

                   |

                  1:1           дочерний класс

                 /   \

                /     \

              1:3     1:4       краевые классы

               |       |

              30:     40:       дисциплины

             (sfq)   (sfq)
               

    Рассмотрим реализацию следующего сценария. Необходимо ограничить полосу пропускания веб-трафика до 5 мегабит, а SMTP — до 3 мегабит. Суммарная полоса пропускания не должна превышать 6 мегабит. На сервере стоит 100-мегабитная сетевая карта, классы могут занимать пропускную способность друг у друга.

    # tc qdisc add dev eth0 root handle 1:0 cbq bandwidth 100Mbit \

     avpkt 1000 cell 8

    # tc class add dev eth0 parent 1:0 classid 1:1 cbq bandwidth 100Mbit \

     rate 6Mbit weight 0.6Mbit prio 8 allot 1514 cell 8 maxburst 20 \

     avpkt 1000 bounded

    В этой части устанавливается корневая дисциплина и класс 1:1, пропускная способность которого ограничена величиной в 6 мегабит.

    Как видите, CBQ требует много больше настроек по сравнению с HTB.

    # tc class add dev eth0 parent 1:1 classid 1:3 cbq bandwidth 100Mbit \

     rate 5Mbit weight 0.5Mbit prio 5 allot 1514 cell 8 maxburst 20 \

     avpkt 1000

    # tc class add dev eth0 parent 1:1 classid 1:4 cbq bandwidth 100Mbit \

     rate 3Mbit weight 0.3Mbit prio 5 allot 1514 cell 8 maxburst 20 \

     avpkt 1000

    Здесь создаются два класса, управляющие веб и почтовым трафиками. Обратите внимание на то, как указаны веса классов. Пропускная способность классов не ограничивается, но они подчинены классу 1:1, который имеет ограничение по полосе пропускания. Таким образом, сумма пропускных способностей этих классов не сможет превысить ограничение родительского класса. Старшие номера дескрипторов дочерних классов (classid) наследуют старший номер родительского класса.

    # tc qdisc add dev eth0 parent 1:3 handle 30: sfq

    # tc qdisc add dev eth0 parent 1:4 handle 40: sfq

    При создании, к каждому из классов, по-умолчанию присоединяется дисциплина FIFO, однако, для более равномерного распределения пропускной способности между соединениями, присоединим к каждому из классов дисциплину обработки очереди SFQ.

    # tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \

     sport 80 0xffff flowid 1:3

    # tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip \

     sport 25 0xffff flowid 1:4

    В заключение, трафик классифицируется с помощью фильтров и направляется в нужные классы.

    Обратите внимание: команда tc class add СОЗДАЕТ класс в пределах дисциплины, а tc qdisc add – добавляет дисциплину к классу.

    У вас может возникнуть резонный вопрос: "Что будет с трафиком, который не подпадает под условия установленных фильтров?". В этом случае трафик останется неклассифицированым и будет обработан корневой дисциплиной 1:0, т.е. пройдет без ограничений.

    Если сумма SMTP+web трафиков превысят сконфигурированные 6 мегабит, то вся полоса пропускания будет разделена между классами, в соответствии с их весами. Таким образом WEB-сервер получит 5/8 ширины канала, а SMTP-сервер — 3/8.

    В соответствии с данной конфигурацией можно утверждать, что WEB-сервер всегда будет иметь полосу, как минимум 5/8*6=3.75 мегабита.

    9.5.4.5. Прочие параметры настройки CBQ: split и defmap.

    Как уже говорилось выше, для классификации трафика, полноклассовые дисциплины используют фильтры.

    Но кроме фильтров, CBQ может предложить вам параметры split и defmap. Хотя назначение этих параметров достаточно сложно понять, и к тому же они не являются жизненно необходимыми, тем не менее я постараюсь описать их.

    Так как наиболее часто классификация трафика производится только на основе поля TOS, в заголовке пакета, то предусматривается специальный синтаксис команд. Каждый раз, когда CBQ сталкивается с необходимостью определения — в какую из очередей поставить пакет, она проверяет — является ли этот узел "узлом разбиения" и если это так, то выбирается подочередь с заданным приоритетом, который может быть рассчитан исходя из значения поля TOS.

    Значение приоритета пакета складывается по "И" с параметром defmap и проверяется — есть ли совпадение. Проще говоря — это самый простой способ создания высокоскоростных фильтров, которые работают с незначительным числом приоритетов. С параметром defmap, равным 0xFF будет совпадать любой пакет, 0x00 — ни один. Возможно пример настройки поможет вам полнее понять вышесказанное:

    # tc qdisc add dev eth1 root handle 1: cbq bandwidth 10Mbit allot 1514 \

     cell 8 avpkt 1000 mpu 64

    # tc class add dev eth1 parent 1:0 classid 1:1 cbq bandwidth 10Mbit \

     rate 10Mbit allot 1514 cell 8 weight 1Mbit prio 8 maxburst 20 \

     avpkt 1000

    Самое обычное начало для CBQ. Значения для параметра defmap можно определить из следующей таблицы:

    TC_PRIO.. Число Значение поля TOS
    BESTEFFORT 0 Maximize Reliablity (0x04) (Максимальная надежность)
    FILLER 1 Minimize Cost (0x02) (Минимальная стоимость)
    BULK 2 Maximize Throughput (0x08) (Максимальная пропускная способность)
    INTERACTIVE_BULK 4
    INTERACTIVE 6 Minimize Delay (0x10) (Минимальная задержка)
    CONTROL 7

    Уровень приоритета TC_PRIO.. рассчитывается исходя из значения поля TOS (за дополнительной информацией о значениях приоритета пакета, обращайтесь к разделу pfifo_fast).

    Теперь создадим классы, через которые пойдет интерактивный и объемный трафик:

    # tc class add dev eth1 parent 1:1 classid 1:2 cbq bandwidth 10Mbit \

     rate 1Mbit allot 1514 cell 8 weight 100Kbit prio 3 maxburst 20 \

     avpkt 1000 split 1:0 defmap c0

    # tc class add dev eth1 parent 1:1 classid 1:3 cbq bandwidth 10Mbit \

     rate 8Mbit allot 1514 cell 8 weight 800Kbit prio 7 maxburst 20 \

     avpkt 1000 split 1:0 defmap 3f

    В данном случае "узлом разбиения" назначается дисциплина 1:0, это та точка, где будет делаться выбор. Число 0xC0 в двоичном представлении имеет вид 11000000, а 0x3F — 00111111, таким образом оба класса перекрывают весь диапазон возможных приоритетов. Первому классу будут соответствовать пакеты, приоритеты которых имеют 6 и/или 7 биты в установленном состоянии, что соответствует интерактивному и управляющему трафику. Ко второму классу будут отнесены все остальные пакеты.

    Таблица выбора для узла 1:0 теперь будет иметь следующий вид:

    приоритет класс
    0 1:3
    1 1:3
    2 1:3
    3 1:3
    4 1:3
    5 1:3
    6 1:2
    7 1:2

    Кроме того, можно изменять приоритеты отдельных видов трафика. Для этого используется команда вида: tc class change, например, чтобы повысить приоритет трафика best effort и классифицировать его, как принадлежащий классу 1:2, нужно дать следующую команду:

    # tc class change dev eth1 classid 1:2 cbq defmap 01/01

    В этом случае, таблица выбора будет иметь следующий вид:

    приоритет класс
    0 1:2
    1 1:3
    2 1:3
    3 1:3
    4 1:3
    5 1:3
    6 1:2
    7 1:2

    FIXME: Корректность работы команды tc class change не проверена. Выводы были сделаны исключительно на основе изучения исходных текстов.

    9.5.5. Hierarchical Token Bucket

    Мартин Девера (Martin Devera) aka <devik> справедливо отмечает, что CBQ слишком сложна и слабо оптимизирована для большинства типичных ситуаций. Его подход более точно соответствует конфигурациям, когда необходимо распределить заданную полосу пропускания между различными видами трафика на полосы гарантированной ширины, с возможностью заимствования.

    HTB работает точно так же, как и CBQ, но, в отличие от последней, принцип работы основан не на вычислении времени простоя, а на определении объема трафика, что полностью соответствует названию Token Bucket Filter. Эта дисциплина имеет незначительное число параметров настройки, которые достаточно хорошо описаны на сайте http://luxik.cdi.cz/~devik/qos/htb/.

    Хотя конфигурирование HTB — задача достаточно сложная, тем не менее конфигурации хорошо масштабируются. В случае же с CBQ процесс конфигурирования становится слишком сложным даже в самых простых случаях! HTB3 теперь стала частью ядра (начиная с версий 2.4.20-pre1 и 2.5.31). Однако, вам может потребоваться пропатченная версия утилиты tc: старший номер версии htb в ядре и пользовательских утилит должны совпадать, в противном случае tc откажется работать с htb.

    Если у вас установлено достаточно свежее или пропатченное ядро, вам определенно стоит посмотреть в сторону HTB!

    9.5.5.1. Пример конфигурации.

    Конфигурация практически идентична вышеприведенному примеру:

    # tc qdisc add dev eth0 root handle 1: htb default 30


    # tc class add dev eth0 parent 1: classid 1:1 htb rate 6mbit burst 15k


    # tc class add dev eth0 parent 1:1 classid 1:10 htb rate 5mbit burst 15k

    # tc class add dev eth0 parent 1:1 classid 1:20 htb rate 3mbit ceil 6mbit burst 15k

    # tc class add dev eth0 parent 1:1 classid 1:30 htb rate 1kbit ceil 6mbit burst 15k

    Автор рекомендует устанавливать дисциплину SFQ для этих классов:

    # tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10

    # tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10

    # tc qdisc add dev eth0 parent 1:30 handle 30: sfq perturb 10

    Добавим фильтры, которые будут выполнять классификацию трафика:

    # U32="tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32"

    # $U32 match ip dport 80 0xffff flowid 1:10

    # $U32 match ip sport 25 0xffff flowid 1:20

    В результате получаем ясную и понятную конфигурацию — никаких малопонятных чисел, никаких недокументированных параметров.

    В HTB все выглядит достаточно прозрачно — классы 10: и 20: имеют гарантированную пропускную способность, при наличии свободной части пропускной способности они заимствуют ее в отношении 5:3.

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

    9.6. Классификация пакетов с помощью фильтров.

    Для классификации того или иного пакета, всякий раз вызывается так называемая "цепочка классификации". Эта цепочка состоит из всех фильтров, присоединенных к полноклассовой дисциплине.

    Вернемся к дереву:

                       root 1:

                          |

                        _1:1_

                       /  |  \

                      /   |   \

                     /    |    \

                   10:   11:   12:

                  /   \       /   \

               10:1  10:2   12:1  12:2

    Когда пакет необходимо поставить в очередь, проверяется каждая ветвь в цепочке фильтров. Например, некоторый пакет мог бы быть направлен фильтром 1:1 в класс 12: и далее в 12:2.

    Фильтр, который сразу отправляет пакет в 12:2, мог бы быть сразу присоединен к 1:1, но в этом случае пакет минует дополнительные проверки, которые могли бы быть сделаны в 12:.

    Вы не можете выполнять фильтрацию в обратном порядке, только вниз! Кроме того, все фильтры в HTB должны присоединяться к корню!

    Повторюсь еще раз. Пакеты могут фильтроваться (классифицироваться) только в направлении сверху-вниз.

    9.6.1. Ряд простых примеров фильтрации.

    Для начала продемонстрируем самый обычный случай, который, к счастью, достаточно прост. Допустим, что у нас имеется дисциплина PRIO, с дескриптором 10:, которая содержит три класса и нам нужно весь трафик, отправляемый на 22 порт и с 80 порта, отдать в самую высокоприоритетную полосу, тогда набор фильтров мог бы выглядеть так:

    # tc filter add dev eth0 protocol ip parent 10: prio 1 u32 match \

     ip dport 22 0xffff flowid 10:1

    # tc filter add dev eth0 protocol ip parent 10: prio 1 u32 match \

     ip sport 80 0xffff flowid 10:1

    # tc filter add dev eth0 protocol ip parent 10: prio 2 flowid 10:2

    О чем говорят эти строки? Они говорят: "Присоединить к eth0, к узлу 10:, фильтр u32, с приоритетом 1, который отбирает пакеты, направляемые на порт 22, и передает их в полосу 10:1". Аналогичное высказывание делается относительно пакетов, отправленных с порта 80. И последняя строка говорит о том, что весь неклассифицированный трафик должен отправляться в полосу 10:2.

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

    Отбор пакетов по IP-адресам выполняется аналогичным образом:

    # tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 \

     match ip dst 4.3.2.1/32 flowid 10:1

    # tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 \

     match ip src 1.2.3.4/32 flowid 10:1

    # tc filter add dev eth0 protocol ip parent 10: prio 2 \

     flowid 10:2

    В этой конфигурации весь трафик, идущий на хост 4.3.2.1 и с хоста 1.2.3.4, ставится в очередь с наивысшим приоритетом.

    Допускается смешивать проверку IP-адреса и номера порта:

    # tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 match ip src 4.3.2.1/32 \

     match ip sport 80 0xffff flowid 10:1

    9.6.2. Наиболее употребимые способы фильтрации.

    В большинстве случаев, команды фильтрации начинаются так:

    # tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 ..

    Это так называемый селектор u32, который может выполнять отбор пакетов по любой его части.

    По IP-адресу

    По исходящему адресу: match ip src 1.2.3.0/24, по адресу назначения: match ip dst 4.3.2.0/24. Чтобы отобрать пакеты, отправляемые с/на единственный узел сети нужно указать сетевую маску /32 или вообще опустить ее.

    По номеру порта

    Исходящий порт: match ip sport 80 0xffff, порт назначения: match ip dport 80 0xffff.

    По типу протокола, из семейства IP (tcp, udp, icmp, gre, ipsec)

    Номера протоколов вы найдете у себя, в файле /etc/protocols . Например, отбор ICMP-пакетов (номер протокола icmp – 1) можно выполнить командой match ip protocol 1 0xff.

    По метке пакета

    Пакеты могут маркироваться либо средствами ipchains, либо средствами iptables. Это бывает полезно, например, для наложения ограничений на трафик, который следует с интерфейса eth1 на интерфейс eth0:

    # tc filter add dev eth1 protocol ip parent 1:0 prio 1 handle 6 fw flowid 1:1

    Обратите внимание — этот фильтр не является селектором u32!

    Установить метку можно следующим образом:

    # iptables –A PREROUTING –t mangle –i eth0 –j MARK -–set-mark 6 В

    данном случае число 6 выбрано произвольным образом.

    Если вы не хотите с головой погружаться в синтаксис tc, тогда просто пользуйтесь возможностями iptables и запомните принцип отбора по метке.

    По полю TOS

    Отбор трафика с минимальной задержкой:

    # tc filter add dev ppp0 parent 1:0 protocol ip prio 10 u32 \

     match ip tos 0x10 0xff \

     flowid 1:4

    Дополнительные сведения о фильтрации трафика вы найдете в главе Расширенная фильтрация.

    9.7. Intermediate queueing device.

    Устройство IMQ не является дисциплиной обработки очереди, но тесно с ними связано. В Linux, дисциплины обработки очередей присоединяются к сетевым устройствам и все, что помещается в очередь устройства, попадает сначала в очередь дисциплины обработки очереди. Из-за этого подхода существуют два ограничения:

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

    2. Дисциплина обработки очереди обслуживает трафик только для одного интерфейса, нет никакой возможности задать глобальные ограничения.

    Устройство IMQ пытается решить эти проблемы. С помощью подсистемы фильтрации ОС Linux можно определенные пакеты направлять через этот псевдо-интерфейс, к которому подключаются различные дисциплины обработки очередей. Таким образом, можно управлять полосой пропускания, как входящего, так и общего трафика.

    9.7.1. Пример конфигурирования.

    Первое, что может прийти на ум – попытаться сформировать входящий трафик так, чтобы дать себе наивысший приоритет ;) Конфигурация IMQ очень похожа на конфигурацию любого другого интерфейса:

    tc qdisc add dev imq0 root handle 1: htb default 20


    tc class add dev imq0 parent 1: classid 1:1 htb rate 2mbit burst 15k


    tc class add dev imq0 parent 1:1 classid 1:10 htb rate 1mbit

    tc class add dev imq0 parent 1:1 classid 1:20 htb rate 1mbit


    tc qdisc add dev imq0 parent 1:10 handle 10: pfifo

    tc qdisc add dev imq0 parent 1:20 handle 20: sfq


    tc filter add dev imq0 parent 10:0 protocol ip prio 1 u32 match \

     ip dst 10.0.0.230/32 flowid 1:10

    В этом примере для классификации пакетов используется селектор u32, однако, при работе с imq, могут использоваться и другие селекторы.

    Отбираемый трафик маркируется средствами iptables:

    iptables –t mangle –A PREROUTING –i eth0 –j IMQ –todev 0

    ip link set imq0 up

    Действие IMQ в iptables

    допускается использовать только в цепочках PREROUTING и POSTROUTING, таблицы mangle. Его синтаксис:

    IMQ [ -–todev n ]

    где n – это номер устройства imq.

    Это действие существует и в ip6tables.

    Обратите внимание: трафик попадает на интерфейс не в тот момент, когда переходит к цели IMQ, а после обработки соответствующей цепочки. Точное место входа на устройство imq зависит от типа трафика (входящий/исходящий).

    Для входящего трафика imq регистрируется с приоритетом NF_IP_PRI_MANGLE + 1. Это означает, что пакеты попадают на устройство сразу после прохождения цепочки PREROUTING. Для исходящего трафика, imq использует приоритет NF_IP_PRI_LAST, который гарантирует, что пакеты, уничтоженные пакетным фильтром не будут занимать полосу пропускания устройства.

    Дополнительные сведения и "заплаты" вы найдете на сайте http://luxik.cdi.cz/~patrick/imq/







     

    Главная | В избранное | Наш E-MAIL | Добавить материал | Нашёл ошибку | Наверх