Привет, Хабр! Мы уже разбирали OVN в связке с OpenStack и трассировку пакетов. А сегодня предлагаем почитать перевод документации про Quality of Service (QoS) в Neutron: что это, какие правила поддерживаются, как настроить и как работать с политиками.

Навигация по тексту

QoS (Quality of Service, управление качеством обслуживания) — механизм, который позволяет управлять определенными сетевыми параметрами: пропускной способностью, задержкой, джиттером. Это нужно для выполнения SLA между провайдером приложения и конечными пользователями.

Сетевые устройства — коммутаторы и маршрутизаторы — могут классифицировать и маркировать трафик, а также применять к нему политики приоритизации, ограничения скорости (policing) и сглаживания (shaping). Это особенно важно для чувствительных к задержкам приложений, таких как VoIP и видеостриминг.

В OpenStack QoS реализован как отдельный сервисный плагин. Он слабо связан с остальным кодом Neutron и подключается через ml2 extension driver.

Поддерживаемые типы правил QoS

Актуальный список типов правил определён в VALID_RULE_TYPES в constants.py:

  • bandwidth_limit — ограничение пропускной способности для сетей, портов или плавающих IP.

  • packet_rate_limit — ограничение частоты пакетов для определенных типов трафика.

  • dscp_marking — маркировка трафика значением DSCP.

  • minimum_bandwidth — гарантия минимальной полосы пропускания.

  • minimum_packet_rate — гарантия минимальной частоты пакетов.

Каждый QoS-драйвер указывает, какие типы правил он поддерживает, через свойство supported_rules. QoS driver manager пересчитывает этот список динамически.

Поддержка правил по бэкендам и направлениям трафика (с точки зрения ВМ):

Правило

Open vSwitch

SR-IOV

OVN

Bandwidth limit

Egress / Ingress

Egress ¹

Egress / Ingress

Packet rate limit

Egress / Ingress

Minimum bandwidth

Egress / Ingress ²

Egress / Ingress ²

Egress / Ingress ²

Minimum packet rate

DSCP marking

Egress

Egress

¹ Параметр max burst не поддерживается утилитой ip.
² Placement-based enforcement работает в обоих направлениях, но поддержка dataplane зависит от бэкенда.

Для правила minimum bandwidth по бекендам и направлениям:

Тип принуждения

Open vSwitch

SR-IOV

OVN

Dataplane

Egress ³

Egress ¹

Egress ⁴

Placement

Egress/Ingress ²

Egress/Ingress ²

Egress/Ingress ⁴

¹ Начиная с Newton.
² Начиная с Stein.
³ Только для сетей без туннелирования (VLAN и flat).
⁴ Начиная с Zed.

SR-IOV агент не поддерживает dataplane enforcement для портов с direct-physical vnic_type, однако начиная с Yoga Placement enforcement для этого типа работает.

Для minimum packet rate поддержка через Placement появилась в Yoga (только для Open vSwitch, направление any/Egress/Ingress). Dataplane enforcement не реализован ни для одного из бэкендов.

Для ml2-плагина список поддерживаемых типов правил — это пересечение правил, поддерживаемых всеми активными mechanism driver'ами. Правило QoS всегда привязано к политике QoS. При создании или обновлении правила:

  • если политика не привязана ни к одному порту или сети — проверяется поддержка правила хотя бы одним активным mechanism driver;

  • если политика привязана — проверяется поддержка драйверами, управляющими конкретными портами.

Допустимые значения DSCP

Допустимые значения DSCP — чётные числа от 0 до 56, исключая 2–6, 42 и 50–54. Полный список:

0, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 44, 46, 48, 56

QoS в L3-сервисах

QoS-политики применимы к плавающим IP-адресам (Floating IP) и к маршрутизаторам — в последнем случае политика действует на gateway-порт.

ML2/OVS

Поддерживаются только правила ограничения полосы:

Floating IP bandwidth limit — лимит применяется к каждому Floating IP независимо.
Gateway IP bandwidth limit — лимит действует на gateway-порт в namespace маршрутизатора (или SNAT namespace для DVR edge router). Ограничение применяется ко всему трафику через gateway IP; на Floating IP-трафик не распространяется.

ML2/OVN

Поддерживаются и rate limit, и DSCP. Оба типа политик применяются через QoS metering rules.

Floating IP — трафик матчится по gateway-порту и адресу Floating IP; порт может быть централизованным или распределенным.
Gateway port — трафик матчится по gateway chassis port.

Если к порту и к Floating IP/маршрутизатору одновременно привязаны политики, приоритеты работают так:

  • Rate limit: применяется минимальное из всех значений.

  • DSCP: маркировка Floating IP/маршрутизатора применяется на исходящий пакет.

Если политики привязаны и к маршрутизатору, и к Floating IP — приоритет всегда у политики Floating IP.

L3-сервисы, реализующие QoS-расширения

L3 router — ограничение полосы реализовано через Linux TC.

OVN L3 — через OVN QoS metering rules.

Поддержка bandwidth limiting: оба L3-сервиса поддерживают Egress и Ingress для Floating IP и Gateway IP.

DSCP marking поддерживается только в OVN L3 (только Egress) для Floating IP и Gateway IP.

Настройка

Предполагается стандартная архитектура, описанная в Networking architecture.

На контроллерных нодах

Добавить qos в service_plugins в /etc/neutron/neutron.conf:

service_plugins = router,metering,qos

Опционально — задать notification_drivers в секции [qos] (по умолчанию message_queue).

Для поддержки QoS на Floating IP (qos-fip) в service_plugins должны быть и router, и qos:

service_plugins = router,qos

В /etc/neutron/plugins/ml2/ml2_conf.ini добавить qos в extension_drivers:

extension_drivers = port_security,qos

В конфигурационном файле агента (/etc/neutron/plugins/ml2/<agent_name>_agent.ini) добавить qos в extensions:

[agent]
extensions = qos

На сетевых и вычислительных нодах

Аналогично добавить qos в extensions агента.

Опционально для Open vSwitch — включить qos_meter_bandwidth:


[ovs]
qos_meter_bandwidth = True

Для QoS на Floating IP добавить fip_qos в /etc/neutron/l3_agent.ini. Если включён DVR — для всех L3-агентов:

[agent]
extensions = fip_qos

Начиная с Stein поддержка bandwidth limit распространяется на Floating IP, привязанный к neutron-порту или к port forwarding.

Для QoS на gateway IP добавить gateway_ip_qos (для агентов типа dvr_snat или legacy):

[agent]
extensions = gateway_ip_qos

Совместно с fip_qos это ограничивает все L3 IP с привязанными QoS-политиками:

[agent]
extensions = fip_qos, gateway_ip_qos

Ограничение полосы не работает на OVS-портах типа internal. В качестве workaround для gateway-портов маршрутизатора — включить ovs_use_veth:

[DEFAULT]
ovs_use_veth = True

QoS сейчас работает только с ml2 (поддерживаемые драйверы — SR-IOV и Open vSwitch).

DSCP-маркировка внешнего заголовка для overlay-сетей

При использовании overlay-сетей (например, VxLAN) DSCP-маркировка применяется только к внутреннему заголовку. При инкапсуляции метка не копируется во внешний заголовок автоматически.

Чтобы задать значение DSCP для внешнего заголовка:

[agent]
dscp = 8

Чтобы скопировать DSCP из внутреннего заголовка во внешний:

[agent]
dscp_inherit = true

Если dscp_inherit = true, значение из параметра dscp игнорируется.

Настройка policy.yaml для доверенных проектов

Если пользователям проектов разрешено самостоятельно управлять QoS-политиками, нужно скорректировать /etc/neutron/policy.yaml:

"get_policy": "rule:regular_user"

"create_policy": "rule:regular_user"

"update_policy": "rule:regular_user"

"delete_policy": "rule:regular_user"

"get_rule_type": "rule:regular_user"

Для каждого типа правил — аналогичный набор записей (get/create/update/delete). Пример для bandwidth limit:

"get_policy_bandwidth_limit_rule": "rule:regular_user"

"create_policy_bandwidth_limit_rule": "rule:regular_user"

"delete_policy_bandwidth_limit_rule": "rule:regular_user"

"update_policy_bandwidth_limit_rule": "rule:regular_user"

То же — для dscp_marking_rule, minimum_bandwidth_rule, minimum_packet_rate_rule.

Пользовательский сценарий

По умолчанию QoS-политики создают только администраторы. Если проекты настроены как доверенные — пользователи могут создавать политики самостоятельно.

Создание политики и правила ограничения полосы

Важно про burst. Правильно подобранное значение burst критично для корректной работы bandwidth limit в агенте Open vSwitch. Слишком маленький burst будет дросселировать трафик даже при правильно заданном лимите; слишком большой — пропускать пакеты сверх лимита. Для TCP-трафика рекомендуется задавать burst на уровне 80% от значения лимита: например, при лимите 1000 кбит/с — burst 800 кбит. Если не задавать burst явно, он по умолчанию составит 80% от лимита.

Привязка политики к порту

$ openstack port list

$ openstack port set --qos-policy bw-limiter <port-id>

Отвязать политику:

$ openstack port unset --qos-policy <port-id>

Порт можно создать сразу с привязанной политикой:

$ openstack port create --qos-policy bw-limiter --network private port1

Привязка политики к сети

При привязке политики к сети все compute-порты в этой сети наследуют её по умолчанию — если только к конкретному порту не привязана своя политика. Внутренние порты (DHCP, маршрутизатор) под сетевую политику не попадают.

$ openstack network set --qos-policy bw-limiter private

Привязка политики к Floating IP

$ openstack floating ip set --qos-policy bw-limiter <floating-ip-id>

Отвязать:

$ openstack floating ip set --no-qos-policy <floating-ip-id>

# или

$ openstack floating ip unset --qos-policy <floating-ip-id>

Floating IP можно создать сразу с политикой:

$ openstack floating ip create --qos-policy bw-limiter public

Правила QoS, привязанные к Floating IP, активируются только после его ассоциации с портом. Политика применяется именно к Floating IP, а не к порту — qos_policy_id порта при этом не меняется.

Агент L3 для Floating IP поддерживает только правила bandwidth_limit. Другие типы (например, DSCP) игнорируются.

Каждый проект может иметь одну политику QoS по умолчанию. Если она задана, все новые сети проекта автоматически получают её — если при создании не указана другая политика.

$ openstack network qos policy create --default bw-limiter
$ openstack network qos policy set --no-default bw-limiter

Ограничение частоты пакетов

$ openstack network qos policy create pps-limiter

$ openstack network qos rule create --max-kpps 1000 --max-burst-kpps 100 \
    --ingress --type packet-rate-limit pps-limiter

$ openstack network qos rule create --max-kpps 1000 --max-burst-kpps 100 \
    --egress --type packet-rate-limit pps-limiter

Единица измерения — тысяч пакетов в секунду (kpps).

Применить к порту:

$ openstack port set --qos-policy pps-limiter <port-id>

Packet rate limit поддерживается только ml2 ovs driver. Используется meter action в ovs kernel datapath (ядро >= 4.15) или userspace ovs dpdk datapath.

Административное принуждение

Если политика не является общей (shared), проект не сможет отвязать её от порта или сети, если она была привязана администратором. Если политика общая — проект вправе самостоятельно привязывать и отвязывать её от своих объектов.

Изменение правил в runtime

Правила можно менять на лету — изменения применятся ко всем привязанным портам:

$ openstack network qos rule set --max-kbps 2000 --max-burst-kbits 1600 \

    --ingress bw-limiter 92ceb52f-170f-49d0-9528-976e2fee2d6f

$ openstack network qos rule show \

    bw-limiter 92ceb52f-170f-49d0-9528-976e2fee2d6f

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

| Field          | Value                                |

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

| direction      | ingress                              |

| id             | 92ceb52f-170f-49d0-9528-976e2fee2d6f |

| max_burst_kbps | 1600                                 |

| max_kbps       | 2000                                 |

| name           | None                                 |

| project_id     |                                      |

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

DSCP-маркировка

$ openstack network qos policy create dscp-marking
+------------+--------------------------------------+
| Field      | Value                                |
+------------+--------------------------------------+
| description|                                      |
| id         | d1f90c76-fbe8-4d6f-bb87-a9aea997ed1e |
| is_default | False                                |
| name       | dscp-marking                         |
| project_id | 4db7c1ed114a4a7fb0f077148155c500     |
| rules      | []                                   |
| shared     | False                                |
+------------+--------------------------------------+

$ openstack network qos rule create --type dscp-marking --dscp-mark 26 \
    dscp-marking
+-----------+--------------------------------------+
| Field     | Value                                |
+-----------+--------------------------------------+
| dscp_mark | 26                                   |
| id        | 115e4f70-8034-4176-8fe9-2c47f8878a7d |
| name      | None                                 |
| project_id|                                      |
+-----------+--------------------------------------+

$ openstack network qos rule set --dscp-mark 22 \
    dscp-marking 115e4f70-8034-4176-8fe9-2c47f8878a7d

$ openstack network qos rule list dscp-marking
+--------------------------------------+-----------+
| ID                                   | DSCP Mark |
+--------------------------------------+-----------+
| 115e4f70-8034-4176-8fe9-2c47f8878a7d | 22        |
+--------------------------------------+-----------+

$ openstack network qos rule show \
    dscp-marking 115e4f70-8034-4176-8fe9-2c47f8878a7d
+-----------+--------------------------------------+
| Field     | Value                                |
+-----------+--------------------------------------+
| dscp_mark | 22                                   |
| id        | 115e4f70-8034-4176-8fe9-2c47f8878a7d |
| name      | None                                 |
| project_id|                                      |
+-----------+--------------------------------------+

$ openstack network qos rule delete \
    dscp-marking 115e4f70-8034-4176-8fe9-2c47f8878a7d

Комбинирование правил в одной политике

В одной политике можно совмещать несколько правил — при условии, что тип или направление каждого из них различаются. Например, два правила bandwidth-limit (egress и ingress) и одно minimum-bandwidth:

$ openstack network qos rule create --type bandwidth-limit \

    --max-kbps 50000 --max-burst-kbits 50000 --egress bandwidth-control

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

| Field          | Value                                |

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

| direction      | egress                               |

| id             | 0db48906-a762-4d32-8694-3f65214c34a6 |

| max_burst_kbps | 50000                                |

| max_kbps       | 50000                                |

| name           | None                                 |

| project_id     |                                      |

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

$ openstack network qos rule create --type bandwidth-limit \

    --max-kbps 10000 --max-burst-kbits 10000 --ingress bandwidth-control

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

| Field          | Value                                |

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

| direction      | ingress                              |

| id             | faabef24-e23a-4fdf-8e92-f8cb66998834 |

| max_burst_kbps | 10000                                |

| max_kbps       | 10000                                |

| name           | None                                 |

| project_id     |                                      |

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

$ openstack network qos rule create --type minimum-bandwidth \

    --min-kbps 1000 --egress bandwidth-control

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

| Field     | Value                                |

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

| direction | egress                               |

| id        | da858b32-44bc-43c9-b92b-cf6e2fa836ab |

| min_kbps  | 1000                                 |

| name      | None                                 |

| project_id|                                      |

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

$ openstack network qos policy show bandwidth-control

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

| Field           | Value                                |

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

| description     |                                      |

| id              | 8491547e-add1-4c6c-a50e-42121237256c |

| is_default      | False                                |

| name            | bandwidth-control                    |

| project_id      | 7cc5a84e415d48e69d2b06aa67b317d8     |

| revision_number | 4                                    |

| rules           | [{u'max_kbps': 50000,                |

|                 |   u'direction': u'egress',           |

|                 |   u'type': u'bandwidth_limit',       |

|                 |   u'id': u'0db48906-a762-4d32-8694-3f65214c34a6',|

|                 |   u'max_burst_kbps': 50000,          |

|                 |   u'qos_policy_id': u'8491547e-add1-4c6c-a50e-42121237256c'},|

|                 |  {u'max_kbps': 10000,                |

|                 |   u'direction': u'ingress',          |

|                 |   u'type': u'bandwidth_limit',       |

|                 |   u'id': u'faabef24-e23a-4fdf-8e92-f8cb66998834',|

|                 |   u'max_burst_kbps': 10000,          |

|                 |   u'qos_policy_id': u'8491547e-add1-4c6c-a50e-42121237256c'},|

|                 |  {u'direction': u'egress',           |

|                 |   u'min_kbps': 1000,                 |

|                 |   u'type': u'minimum_bandwidth',     |

|                 |   u'id': u'da858b32-44bc-43c9-b92b-cf6e2fa836ab',|

|                 |   u'qos_policy_id': u'8491547e-add1-4c6c-a50e-42121237256c'}]|

| shared          | False                                |

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

Политика с правилом minimum bandwidth обеспечивает best-effort соблюдение минимальной полосы — полная гарантия пока не реализована, поскольку QoS не интегрирован с планировщиком Compute.