QoS в Linux знущаємось над трафіком

У попередній статті я розповідав про фільтр 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. Інший спосіб обійти цю проблему - перенаправляти трафік на інший інтерфейс.

Давайте розглянемо найпростіший приклад застосування дій. Напевно, багато хто з ним уже стикався. Йтиметься про обмеження смуги пропускання для окремих типів трафіку за допомогою так званого полісера. Полісер працює за алгоритмом поточного відра (прочитати цей алгоритм можна на вікіпедії або у Таненбаума).

Найбільший інтерес для нас представляють два останні рядки (якщо вам незрозумілі й інші рядки, прочитайте LARTC і про фільтр U32).

  • action police - вказує на те, що трафік, що підпадає під фільтр, буде оброблятися полісером. Далі йдуть параметри полісеру.
  • rate 2Mbit burst 200K - задаємо смугу пропускання в 2 мегабіти в секунду. Burst 200K - це один з параметрів, потрібний для правильної роботи полісера. Є й інші параметри, але ми їх не розглядатимемо.
  • exceed-conform drop – визначає дію над пакетами, які «переливаються через край відра», у разі вони відкидаються. Пакети ж, які влазять у смугу 2 мегабіти пропускаються.

Запустимо, наприклад, iperf на обох машинах і виміряємо швидкість. Якщо все правильно зроблено, то швидкість від 192.168.10.3 до 192.168.10.5 має бути в районі двох мегабіт(це у випадку, якщо крім тестових даних між вузлами нічого не передається). У статистиці можна побачити, скільки даних пройшло через фільтр, скільки разів він спрацював, скільки пакетів було пропущено та відкинуто тощо.

Подібним чином використовуються інші дії. Для кожної дії можна викликати невелику довідку щодо параметрів. Наприклад, для того ж таки полісера це можна зробити командою:

Щоб дізнатися підказку до інших дій, просто вкажіть їхню назву замість «police».

Короткий перелік дій
Об'єднання дій у ланцюжок

Дії можуть застосовуватися як поодинці, так і спільно, утворюючи ланцюжки. Все це схоже на конвеєрну обробку даних у консолі, коли виведення однієї програми подається на введення іншої. З діями так само. Наприклад, спробуємо змінити якесь поле в заголовку пакета. Після цього нам необхідно буде перерахувати та оновити контрольну суму. Для цього дії pedit та csum будуть об'єднані в ланцюжок. Для наочності віддзеркалюємо результуючі пакети на інтерфейс ifb0 і подивимося їх tcpdump-ом.

Перевіримо, як все працює за допомогою аналізу статистики, а також запустивши tcpdump на інтерфейсі ifb0:

Ось у принципі і все, що я хотів розповісти про застосування дій.