Настройка qos в linux

Обновлено: 05.07.2024

Разделение, ограничение и управление трафиком - актуальная и сложная задача,
которую обычно возлагают на дорогостоящее специальное сетевое оборудование. Но
решить ее можно и с помощью подсистемы Linux-ядра Traffic Control, не
уступающей по возможностям Cisco IOS.

Допустим, существует офис некой компании X, и в нем числится около ста
сотрудников, каждый из которых может выходить в интернет через шлюз. Скорость
внешнего канала составляет 100 Мбит. Системный администратор справился с
настройкой шлюза в силу своих способностей – что и посчитал достаточным для
правильного функционирования сети. К чему это привело? К увольнению
недальновидного (или ленивого) админа.

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

Краткий сценарий

Решение проблемы: разделение канала между сотрудниками с ограничением
скорости! Сеть будет функционировать на "5+", если каждый сотрудник получит в
распоряжение отдельный канал, скорость которого будет составлять 1 Мбит. Тогда
отдельно взятый интернет-пользователь не сможет занять больше причитающейся ему
доли и отобрать часть канала у других. С точки зрения компании, это еще и
отличный способ экономии (после разделения канала оказывается, что его суммарная
пропускная способность даже излишне высока) и ведения статистики по трафику для
отдельно взятого сотрудника.

Обычно для разделения канала с ограничением скорости используются возможности
операционной системы IOS, на которой функционирует сетевое оборудование Cisco
(дешевые решения от других производителей, таких, как Dlink, Trendnet и Netgear,
вообще не обладают такой возможностью). Однако особой необходимости тратить
баснословные суммы на аппаратные шлюзы от Cisco нет. Ядро Linux уже более пяти
лет как содержит в себе код сложной и весьма функциональной подсистемы
управления трафиком Traffic Control, которая по некоторым параметрам даже
обходит IOS.

Подсистема Traffic Control

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

Подсистема управления трафиком Linux позволяет делать следующее:

  • Shaping. Шейпинг - ограничение трафика, задержка пакетов с
    целью создания желаемой скорости передачи. Может использоваться не только для
    "сужения" исходящего канала, но и для сглаживания бросков во время пиковых
    нагрузок.
  • Scheduling. Планирование – упорядочивание типов трафика в
    канале. Позволяет избегать задержек для критичных типов трафика (QoS).
  • Policing. Политика входящего трафика. Позволяет ограничить
    входящий трафик путем уничтожения превысивших лимит пакетов. Помогает бороться
    с DDoS.

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

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

  • Дисциплина обработки пакетов (qdisc) - очередь пакетов и
    закрепленный за ней алгоритм обработки.
  • Класс (class) - логический контейнер, который может
    содержать несколько подклассов или дисциплину.
  • Фильтр (filter) - механизм классификации трафика.

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

Linux действует таким же образом. Но формат представления очереди и алгоритм
ее обработки, в совокупности называемые дисциплиной обработки пакетов, в нем
заменяемы! По умолчанию используется дисциплина pfifo_fast, реализующая очередь
FIFO. Пользуясь утилитой tc, администратор может заменить ее на другую
дисциплину, которая будет переупорядочивать пакеты (планирование), задерживать
их на определенное время (шейпинг) или выполнять другие действия.

Дисциплины классов

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

Чтобы управлять тем, дисциплиной какого класса будет обработан определенный
тип трафика, классовые дисциплины позволяют подключать к себе фильтры. Это дает
возможность "завернуть" определенный трафик в один из ее подклассов. Фильтры
используют классификаторы для идентификации пакетов нужного типа и как бы
говорят ядру: "Этот вид трафика должен обрабатываться с помощью дисциплины вот
этого класса". Существует несколько разных классификаторов. Самыми популярными
являются u32 и fw. Первый позволяет выделять пакеты по исходящим адресам и
адресам назначения, портам, парам "хост:порт", типам протокола и типу сервиса.
Второй классифицирует пакеты путем чтения маркировок, записанных брандмауэром
iptables/netfilter (цель MARK).

За каждым сетевым интерфейсом должны быть закреплены две особые дисциплины:
корневая дисциплина (root qdisc) и входящая дисциплина (ingress qdisc). В первую
помещается весь исходящий трафик (по умолчанию используется дисциплина
pfifo_fast). Во вторую - входящий.

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

Утилита tc

Для конфигурирования подсистемы управления трафиком предназначена утилита tc
из пакета iproute2. Она принимает набор команд в качестве аргументов, с помощью
которых можно создавать классы, привязывать к ним дисциплины и добавлять
фильтры. Синтаксис ее похож на синтаксис команды ipfw из операционной системы
FreeBSD, так что знакомые с ним быстро освоятся.

Для примера рассмотрим простейший вариант использования:

Эта команда устанавливает ограничение для всего исходящего трафика в 256
Кбит/с. Разберем подробнее все аргументы tc:

  • qdisc add - добавляем новую дисциплину (для удаления используй del).
  • dev eth0 - указываем устройство, к которому будет привязана дисциплина.
  • root - наша дисциплина корневая (будет обрабатываться весь трафик).
  • tbf - имя дисциплины.
  • rate 256kbit latency 50ms burst 1540 - параметры, специфичные для данной
    дисциплины: rate - ограничение скорости, latency - максимальный "возраст"
    пакета в очереди, burst - размер буфера.

Проще говоря, команда подключает дисциплину tbf в качестве корневой на
интерфейсе eth0 и задает ей несколько параметров. Token Bucket Filter (TBF) -
это бесклассовая дисциплина, которая передает поступающие пакеты с заданной
скоростью.

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

Формат указания скорости в утилите tc

mbps = 1024 kbps = 1024 * 1024 bps => Байт/с
mbit = 1024 kbit => Кбит/с
mb = 1024 kb = 1024 * 1024 b => Байт

Заменить стандартную корневую дисциплину на любую бесклассовую совсем
несложно, но на таком коне далеко не уедешь. Для создания разветвленной системы
управления трафиком нужны классовые дисциплины, классы, фильтры и целое дерево
дисциплин. Чтобы настроить все это, может понадобиться не один десяток команд.
Мы рассмотрим несколько вводных примеров, перед тем как перейти к обсуждению
дисциплины HTB.

Пример дерева дисциплин

Подключим дисциплину prio в качестве корневой и назначим ей имя (дескриптор)
"1:0":

Результат этой команды: дисциплина prio, подключенная в качестве корня, и три
класса (1:1, 1:2 и 1:3) внутри нее, к каждому из которых подключена дисциплина
FIFO.

Мы вольны заменить любую из дисциплин, подключенных к классам, чем и
воспользуемся для подключения дисциплины sfq с дескриптором "10:0" к классу
"1:1":

Это обеспечит справедливое разделение канала между интерактивными
приложениями (они имеют наивысший приоритет). Чтобы остальные приложения, такие
как менеджеры закачек и torrent-клиенты (которые обычно шлют пакеты с меньшим
приоритетом в поле TOS), не мешали интерактивным, ограничим для них скорость:

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

Теперь сделаем так, чтобы весь SSH-трафик имел наивысший приоритет. Для этого
закрепим за корневой дисциплиной prio фильтр, который будет перенаправлять
пакеты с портом назначения 22 в дисциплину класса "1:1".

Рассмотрим подробнее механизм подключения фильтров.

  • filter add - Добавляем фильтр.
  • dev eth0 - Указываем устройство.
  • parent 1:0 - Дескриптор родителя.
  • protocol ip - Протокол, с которым будет работать фильтр.
  • prio 1 - Присваиваем классифицированному трафику приоритет 1 (наивысший).
  • u32 - Используемый классификатор.
  • match ip dport 22 0xffff - Параметры классификатора. В данном случае
    указание отбирать пакеты с портом назначения 22.
  • flowid 1:1 - Отфильтрованные пакеты должны иметь класс "1:1" и
    обрабатываться с помощью его дисциплины.

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

Классовая дисциплина HTB

Еще в первый релиз системы Traffic Control была включена классовая
дисциплина CBQ (Class-Based Queue), предназначенная для реализации сложных
систем управления и ограничения трафика. CBQ завоевала большую популярность
благодаря своей гибкости, но была очень сложна, запутана и обладала рядом
ограничений (тут и необходимость заранее указывать максимальную пропускную
способность канала, и неэффективный алгоритм шейпинга).

Поэтому в скором времени появилась более эффективная и простая в
использовании альтернатива под названием HTB (Hierarchical Token
Bucket). Классовая дисциплина HTB предназначена для разделения полосы
пропускания между различными видами трафика, каждому из которых может быть
предоставлена полоса гарантированной ширины. Она не обладает гибкостью CBQ, но
гораздо более проста в настройке и лишена ее недостатков. Именно на HTB сегодня
принято строить сложные и эффективные системы ограничения трафика.

Рассмотрим применение HTB на примере, представленном в начале статьи, но
более усложненном. Допустим, у нас есть шлюз на Linux, интерфейс eth1 которого
смотрит наружу, а eth0 - во внутреннюю сеть. Ширина канала - 100 Мбит. Задача:
разделить канал между сотрудниками компании так, чтобы директор и сотрудники
IT-отдела могли выходить в интернет без скоростных ограничений, маркетологи
получили ограничение в 2 Мбит/c каждый, менеджеры - 1 Мбит/c, секретари - 512
Кбит/c, а все остальные - 256 Кбит/c.

Есть два варианта решения. Первый: составить огромную таблицу IP-адресов и
создать специальные правила ограничений для каждого адреса (с точки зрения
системы HTB это будет выглядеть как огромный набор классов и фильтров, по одному
на каждый адрес). Второй: разбить всех потребителей канала на мета-группы,
каждую из которых выделить в отдельную подсеть (директор и IT-отдел -
172.16.1.0, маркетологи - 172.16.2.0, менеджеры - 172.16.3.0, секретари -
172.16.4.0, остальные - 172.16.5.0). Для каждой подсети назначить суммарное для
всех ее членов ограничение со справедливым разделением канала.

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

Для начала создадим работоспособную систему, основанную только на втором
варианте решения задачи. Подключим дисциплину HTB в качестве корневой:

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

Создадим в нем пять подклассов для пяти наших подсетей. Директору и IT-отделу
выделим 30-мегабитный канал с возможностью его расширения (заимствования) вплоть
до 100 Мбит в случаях, когда остальные каналы не заняты:

Для маркетологов выделим 20-мегабитный канал:

Менеджерам – 10 Мбит/с:

Секретарям – 5 Мбит/с:

И – 40 Мбит/с на всех остальных:

По умолчанию к вновь созданным классам подключены дисциплины, реализующие
очередь FIFO. Это нам не подходит. Чтобы канал равномерно распределялся между
всеми участниками подсети, мы должны подключить к ним дисциплину sfq:

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

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

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

Для примера, установим ограничение в 256 Кбит/с для пользователя,
находящегося в подсети "все остальные". Сначала добавим к "классу-подсети" новый
"класс-пользователь":

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

В предыдущей статье я рассказывал про фильтр U32. В этой статье речь пойдёт о так называемых tc actions — действиях, которые можно производить над трафиком. Например, можно построить файерволл без использования iptables/netfilter, или изменять отдельные байты в пакетах, перенаправлять/зеркалировать трафик на другие интерфейсы. Осваивать это будем на примерах. Продолжение под катом.

Что же это за tc actions такие?

Traffic Control Action (далее просто «действия») — это расширение фильтров в подсистеме управления трафиком. Расширения эти нужны для самых разнообразных нужд — от простейшего отбрасывания пакетов до изменений самого трафика. Действие прикрепляется к отдельному фильтру, и таким образом манипуляции производятся только над выбранным трафиком, что добавляет гибкости. Кроме того, можно строить целые цепочки действий через пайпы (подобно конвейерной обработке данных в консоли), комбинируя их. Манипуляции могут производиться как над входящим трафиком, так и над исходящим.

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

Естественно, в ядро должны быть включены соответствующие модули. Находятся они в ветке Networking support — Networking options — QoS and/or fair queueing. Вам необходимы включенные опции Actions и модули с действиями, которые будете использовать. В дистрибутивных ядрах, обычно, всё уже включено.

Простейший пример использования действий

Для упрощения построения фильтров, мы будем отбирать трафик для манипуляций с помощью меток. Этот способ подходит лишь для исходящего трафика. Почему так? Давайте посмотрим на эту картинку, на которой изображён путь пакета по сетевому стеку Linux. Как можно заметить, дисциплина и классификация входящих пакетов выполняется гораздо раньше, чем любые хуки netfiter, и поэтому нам просто негде пометить пакет раньше. В этом случае, для классификации имеет смысл строить фильтры по другим критериям, например, используя U32. Другой способ обойти данную проблему — перенаправлять трафик на другой интерфейс.

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

Допустим, мы хотим ограничить скорость входящего трафика протокола tcp c ip-адреса 192.168.10.3 на адрес 192.168.10.5. Можно сделать это следующим образом:

  • action police — указывает на то, что подпадающий под фильтр трафик будет обрабатываться полисером. Далее идут параметры полисера.
  • rate 2Mbit burst 200K — задаём полосу пропускания в 2 мегабита в секунду. «burst 200K» — это один из параметров, нужный для правильной работы полисера. Есть и другие параметры, но мы их не будем рассматривать.
  • exceed-conform drop — определяет действие над пакетами, которые «переливаются через край ведра», в данном случае они отбрасываются. Пакеты же, которые влезают в полосу 2 мегабита пропускаются.

Запустим, например iperf на обоих машинах и измерим скорость. Если всё правильно сделано, то скорость от 192.168.10.3 до 192.168.10.5 должна быть в районе двух мегабит (это в случае, если кроме тестовых данных между узлами ничего не передаётся). В статистике можно увидеть, сколько данных прошло через фильтр, сколько раз он сработал, сколько пакетов было пропущено и отброшено и т.п.

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

Для того, чтобы узнать подсказку к другим действиям, просто укажите их название вместо «police».

Краткий перечень действий
  • police — как и говорилось ранее, реализует функции полисера для ограничения скоростей.
  • gact — generic action — позволяет пропускать, отбрасывать, переклассифицировать пакеты и т.п. С помощью этого действия можно реализовать подобие файерволла.
  • mirred — с помощью этого расширения можно зеркалировать или перенаправлять пакеты на другие сетевые интерфейсы. Широкое применение получило совместно с IFB-интерфейсами для сглаживания (шейпинга) входящего трафика.
  • ipt — iptables target — даёт применять к пакетам действия iptables, например, маркирование. В этом случае, если фильтр прикреплён к ingress-дисциплине, то это примерно соответствует действиям в цепочке mangle-prerouting.
  • nat — stateless nat — реализует преобразование сетевых адресов без учёта состояний. Т.е. просто меняет в заголовке один ip-адрес на другой.
  • pedit — packet edit — с его помощью можно изменять в пакетах отдельные биты и байты. Пример его применения будет позже.
  • skbedit — позволяет изменять поля структуры sk_buf, в которой хранится пакет. Применяется для изменения приоритета, в основном.
  • csum — check sum update — пересчитывает контрольные суммы и обновляет их значения в заголовках пакетов. Обычно используется совместно с pedit.
Объединение действий в цепочку

Действия могут применяться как по одиночке, так и совместно, образуя цепочки. Всё это похоже на конвейерную обработку данных в консоли, когда вывод одной программы подаётся на ввод другой. С действиями точно так же. Например, попробуем изменить какое-нибудь поле в заголовке пакета. После этого нам необходимо будет пересчитать и обновить контрольную сумму. Для этого действия pedit и csum будут объединены в цепочку. Для наглядности, отзеркалируем результирующие пакеты на интерфейс ifb0 и посмотрим их tcpdump-ом.

Команда выглядит довольно устрашающе. Начало нам знакомо — добавляем фильтр для того, чтобы отобрать нужные нам пакеты по адресам источника и назначения, протоколу и номеру порта (protocol tcp, ip src 10.10.20.119, ip dst 10.10.20.254, tcp dport 10500). Но вместо классифицирования мы меняем содержимое пакета (параметр «action pedit») — одинарное слово по смещению 22 байта от начала ip-пакета. Если поглядеть на формат заголовков, то это поле соответствует номеру порта получателя в tcp. Мы перезаписываем его, устанавливая равным 11500 («munge offset 22 u16 set 11500»). Но после того, как мы поменяли поле, контрольная сумма заголовка изменится. Чтобы её пересчитать, пакеты перенаправляются действию csum с помощью параметра «pipe». Csum пересчитывает контрольную сумму заголовка tcp и направляет пакеты действию «mirred» так же с помощью параметра «pipe». В результате работы действия «mirred» на интерфейс ifb0 приходят копии пакетов, которые были отправлены.

Проверим, как всё работает с помощью анализа статистики, а так же запустив tcpdump на интерфейсе ifb0:

Вот в принципе и всё, что я хотел рассказать по поводу применения действий.

Этой заметкой начинается цикл статей на русском языке о QoS в Linux с актуальностью на момент времени 2014Q2. Базовой user space утилитой для управления трафиком является tc(traffic control), документация к которой устарела и содержит неточности. Различные HOWTO в большинстве своём датируются началом 2000-ых годов. Единственным достоверным источником о том как оно работает являются исходники ядра. Предполагается, что читатель владеет такими понятиями как классификация, маркировка, планирование(scheduling).

В качестве linux-дистрибутива будет использоваться Ubuntu 14.04(ядро 3.13.0-24-generic, но в один момент будет заменено на 3.14.1-031401-generic)

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

pfifo_fast

Ввиду ряда исторических особенностей, связанных с тем, что IP precedence, TOS bits и DSCP используют один и тот же байт, маппинг TOS->internal priority, на сегодняшний день, выглядет как минимум странно, кроме того, после commit 4a2b9c3(2011 год), в документации(man 8 tc-prio(git)), содержащей таблицу маппинга TOS field в internal priority(и, соответственно, номер очереди) теперь есть ошибка, а именно в строке:

В самом деле для TOS=0x2(00000010) значение linux priority(internal priority) будет 0(Best Effort) и, в соответствии с priomap, номер очереди(band) 1, а не 2.
Для того, чтобы получить реальную картину по маппингам, выполним следующий код в пространстве ядра(kernel space):

На выходе получаем таблицу:

Допустим, имеется два потока, один с DSCP=46 (класс обслуживания EF) и второй с DSCP=36 (AF42). В соответствии с этой таблицей, для DSCP=46 linux priority(P)=4, что соответствует band=1(4ый элемент в priomap, нумерация элементов с 0), для DSCP=36 P=6 и band=0, т.е. в случае с pfifo_fast, трафик с DSCP=AF42 будет иметь абсолютный приоритет по сравнению с потоком DSCP=EF. В реальной жизни специально так никто не настраивает QoS.

К сожаленью, использовать ESXi или veth-интерфейсы между netns для полноценной демонстрации QoS не получится(потому что скорость на виртуальных картах vmware и linux veth не ограничена(упирается в CPU)), поэтому придётся воспользоваться реальным паткордом и двумя сетевыми картами:

Linux QoS pfifo_fast scheme

Если у вас сетевая карточка поддерживает задание размера аппаратного tx-буфера(чтобы проверить, нужно выполнить ethtool -g eth2), то для изучения QoS в ядре Linux лучше минимизировать его размер(ethtool -G eth2 tx 3).

Смотрим в терминал 2, убеждаемся, что на сервер приходит трафик со скоростью

95Мбит/с. Запускаем пинги:

Для просмотра статистики используется опция -s:

В этом эксперименте размер очереди на отправку пропорционален размеру окна tcp. Как видно из этой статистики, tcp-поток занимает в буфере в каждый момент времени примерно 30 пакетов. Запустим ещё 3 iperf-а(чтобы выйти за установленный лимит txqueuelen=100) с таким же значением TOS и убедимся, что буфер начнёт переполняться и пойдут дропы:

backlog будет изменяться от

80 до 100 пакетов(в этом можно убедиться, несколько раз выполнив указанную команду)

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

Если локальное приложение не умеет устанавливать internal priority или TOS, то локальную приоритезацию трафика можно осуществить с помощью iptables:

Такое правило установит skb->priority=6 для исходящего icmp-трафика. В соответствии с priomap, band будет равен 0 для такого трафика и он станет самым приоритетным.

Дисциплина mq

В начале заметки был вывод tc qdisc show, в котором видно, что к устройству eth0 применена дисциплина mq. Это классовая дисциплина, в которой каждый класс привязан к аппаратной tx-очереди. Однако в выводе tc нет внутренней структуры, это связано с особенностью, поведение которой изменено в commit 95dc192. Ядро 3.13 не включает в себя этот коммит, поэтому заменим его на 3.14.1(можно скомпилировать или взять готовое здесь). Если у вас для экспериментов нет сетевой карты с поддержкой multiqueue, то можно воспользоваться vmware ESXi с сетевой картой vmxnet3(количество очередей будет равно числу vCPU) или другим продуктом с поддержкой vmxnet3.

После замены ядра вывод tc становится следующим:

Здесь мы видем, что на каждую аппартную очередь прикрепрелена дисциплина pfifo_fast. Чтобы заменить дисциплину для конкретной очереди(ассоциированной с фиксированным номером класса):

Чтобы заменить mq целиком на какую-нибудь другую дисциплину(например, pfifo_fast) нужно выполнить:

Чтоб вернуть обратно нужно удалить корневую дисциплину(после чего к интерфейсу применится дисциплина по умолчанию):

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

Дерево HTB строится ещё проще:

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

Для интерфейса локальной сети menlo адрес задан статически, так что там кроме файла options ещё нужен файл ipv4address:

2. Дальше настраиваете ip-forwarding и nat masquarading. За первый отвечает строчка

в файле /etc/net/sysctl.conf , в то время как другое делается добавлением строки masquerade out-iface comcast в файл /etc/net/ifaces/default/fw/iptables/nat/POSTROUTING :

3. Далее я настраивал распознавание и маркирование пакетов, которым надо было обеспечить гарантированную ширину пропускания канала. Для меня это были два телефонных адаптера, которые не искажают звук только если им предоставлены 10 килобит в секунду. Эти адаптеры стоят в локальной сети и dhcp сервер по их мак-адресам даёт им статические адреса. Эти адреса я и использовал в качестве критерия для маркировки. Маркировка обеспечивается следующим образом:

Мысль для себя на будущее: наверно можно было маркировать по мак-адресу, и тем самым избежать необходимости настраивать статические адреса выдаваемые dhcpd.

4. Ну а теперь остаётся самое настроить qos htb для идущего наружу интерфейса comcast.

Теперь телефонам будет предоставляться 80 килобит в секунду как только они того потребуют, а если они недоиспользуют эти 80kbit, всё оставшееся будет предоставляться другим соединениям.

P.S Большое спасибо Денису Овсиенко за то, что объяснил, как правильно организовать иерархию фильтров, чтобы эта конструкция заработала.

Потихоньку настраиваю QoS на роутере. Более менее разобрался в принципах остались нюансы. Скрипт такой:

Вопросы остались как выявить skype трафик, чтобы добавить его в приоритетный список? Еще есть RDP, вроде все просто порт 3389, но на многих серверах он настроен на других портах, может как-то можно по содержимому пакетов через u32 match выявить? Подскажите.



Сейчас подумал, кроме RDP аналогичный вопрос по VNC и Radmin

Настройка QoS на офисном роутере особо не даёт эффекта, т.к. фактически полноценно вы можете управлять лишь исходящим трафиком, а на входящий(к вам) лишь косвенное влияние, в основном на tcp-трафик. А обычно в офисах входящий превышает исходящий.

То, что Вы хотите должен делать провайдер(т.е. продавать вам X мбит/с, но внутри это трубы делать приоритезацию). Между прочим, есть провайдеры, которые это делают. Потестите различных, если в вашем офисе есть выбор.

Вопросы остались как выявить skype трафик, чтобы добавить его в приоритетный список? Еще есть RDP, вроде все просто порт 3389, но на многих серверах он настроен на других портах, может как-то можно по содержимому пакетов через u32 match выявить? Подскажите.

Для linux-а нет открытых/бесплатных решений, позволяющих эффективно матчить skype и делать прочую L7-классификацию. На сегодняшний день на рынке есть только платные(и весьма дорогостоящие решения) типа Cisco SCE.

Ога, L7 или того же OpenDPI в природе не существует.


для не циско фанов:

Проще говоря, оба проекты мёртвые. А DPI это штука такая, требующих постоянных обновлений, как антивирусы и антиспамы.

Вы его пробовали? Реально, оно почти ничего не умеет и производительность УГ

Есть обзор и тесты?


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

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


Ну SCE это не самая крутая с точки зрения dpi система. Вот всякие процера, аллот, ф5 это ближе.

Ни в коем разе не пытался это утверждать. Просто привёл как пример промышленной DPI-системы.

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

Это нормально работает для tcp, при небольшом и среднем количестве потоков. Если кто-то балуется udp, то тут как повезёт, зависит от агрессивности вышестоящего протокола.


О! у меня как раз с UDP (IPTV) проблемы на высоких скоростях канала. Я новую тему создал - QoS для IPTV на скоростном канале

Может подскажите, что можно докрутить до ума, чтобы спасти IPTV?

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

А с RDP да, выявить кажется можно. Или использовать отдельный ip, алиас, для RDP, Radmin, VNC

Сам искал поиском как приоретизировать трафик скайпа и наткнулся на эту тему. Решил задачу следующим образом:
Скайп, собака, не имеет статически определенного порта по которому он коммуникачит с другими клиентами. Но в настройках ему можно указать порт. По сему, единственный выход - сказать всем клиентам установить определенный порт. Тогда маркируем трафик следующим правилом:
$TC filter add dev $IF_INT parent 1: protocol ip prio 19 u32 match ip sport 19000 0xffff flowid 1:3
В итоге все пакеты маркируются и отправляются в определенный подкласс HTB где и устанавливаем ему приоритет выше остального трафика. Может способ и костыльный, но работает.

Добрый день. Настраиваю шейпер и приоритезацию трафика. Создал классы по ограничению скорости канала для каждого клиента, а также подклассы с приоритетами. По моим соображениям скрипт должен гарантировать скорость 4950kbit каждому клиенту (за исключением VoIP), а если канал никем не занят, выдавать 35000kbit. По факту максимальная скорость всегда выдается 4950kbit, даже если в канале больше никого нет. ЧЯДНТ?

Читайте также: