Skip to content

Instantly share code, notes, and snippets.

@vorlon001
Last active October 24, 2026 09:30
Show Gist options
  • Select an option

  • Save vorlon001/cd54b39f64c1547cb02fba1c7db33aef to your computer and use it in GitHub Desktop.

Select an option

Save vorlon001/cd54b39f64c1547cb02fba1c7db33aef to your computer and use it in GitHub Desktop.
OVS DPDK

PART1

Архитектура стенда (ANSI)

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

       |                        ФИЗИЧЕСКИЙ ХОСТ (Linux)                    |
       |                                                                   |
       |  +-------------------------+             +---------------------+  |
       |  |   Виртуальная Машина    |             |  Сетевой Пространство| |
       |  |      (VM Libvirt)       |             |    Имен (Netns)     |  |
       |  |                         |             |                     |  |
       |  |  +-------------------+  |             |  +---------------+  |  |
       |  |  | eth0 (virtio-net) |  |             |  |   tap-ns1     |  |  |
       |  +--+---------+---------+--+             +--+-------+-------+--+  |
       |               | (Shared Memory)                     |             |
       |               v (Hugepages)                         |             |
       |   /var/run/openvswitch/vhost-vm1                    |             |
       |               |                                     |             |
       |               v (vhostuserclient)                   v (internal)  |
       |  +------------+-------------------------------------+----------+  |
       |  |  [vhost-vm1]                                  [tap-ns1]     |  |
       |  |                                                             |  |
       |  |                     Бридж OVS (br-dpdk)                     |  |
       |  |                    (datapath_type=netdev)                   |  |
       |  |                                                             |  |
       |  |  +-------------------------------------------------------+  |  |
       |  |  | [dpdk-p0] (Физический порт сетевой карты под vfio-pci) |  |  |
       |  |  +---------------------------+---------------------------+  |  |
       |  |                              |                              |  |
       |  |                              v (PMD Threads / CPU Cores)    |  |
       |  +------------------------------+------------------------------+  |
       |                                 |                                 |
       |                                 v (DPDK Driver Bypass Kernel)     |
       |                   +---------------------------+                   |
       |                   |  Физическая сетевая карта |                   |
       |                   |  (PCI: 0000:03:00.0)      |                   |
       +-------------------+---------------------------+-------------------+

ШАГ 1: Конфигурация GRUB (Изоляция ядер и Hugepages при загрузке)

Это фундамент. Если не изолировать ядра на уровне загрузчика, планировщик Linux завалит PMD-потоки OVS своими системными прерываниями.

  1. Узнаем NUMA-ноду вашей сетевой карты: Найдите PCI-адрес карты (например, 0000:03:00.0) через lspci | grep Ethernet. Проверьте её NUMA-ноду:
cat /sys/class/net/<имя_интерфейса>/device/numa_node

Допустим, команда вернула 0. Значит, выделяем память и сажаем ВМ на NUMA-ноду 0. 2. Редактируем параметры загрузки:

sudo nano /etc/default/grub

Найдите строку GRUB_CMDLINE_LINUX_DEFAULT и приведите её к следующему виду (выделяем 2 огромные страницы по 1 ГБ, изолируем ядра 2 и 4 под PMD-потоки):

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash default_hugepagesz=1G hugepagesz=1G hugepages=2 isolcpus=2,4 nohz_full=2,4 rcu_nocbs=2,4 iommu=pt intel_iommu=on"

(Если процессор AMD, замените intel_iommu=on на amd_iommu=on).

  1. Применяем конфигурацию и уходим в ребут:
sudo update-grub
sudo reboot
  1. Проверяем статус после перезагрузки:
# Должно выдать 2,4
cat /sys/devices/system/cpu/isolated

# Должно показать Total: 2

cat /proc/meminfo | grep Hugepages_Total

ШАГ 2: Привязка физической сетевой карты к DPDK

Ядро Linux больше не должно управлять этой картой. Переводим её под контроль vfio-pci.

  1. Загружаем модули ядра:
sudo modprobe vfio-pci
echo "vfio-pci" | sudo tee -a /etc/modules
  1. Включаем безопасный режим No-IOMMU (если работаете в виртуалке или тест-стенде без аппаратного IOMMU):
echo 1 | sudo tee /sys/module/vfio/parameters/enable_unsafe_noiommu_mode
  1. Отвязываем карту и отдаем DPDK:
# Устанавливаем тулзы dpdk, если их нет
sudo apt update && sudo apt install -y dpdk

# Привязываем интерфейс по его PCI-адресу

sudo dpdk-devbind.py --bind=vfio-pci 0000:03:00.0

Проверяем: команда dpdk-devbind.py --status должна показать карту в секции "Network devices using DPDK-compatible driver".

ШАГ 3: Установка и настройка OVS-DPDK

  1. Устанавливаем OVS с поддержкой DPDK и переключаем бинарник по умолчанию:
sudo apt install -y openvswitch-switch-dpdk
sudo update-alternatives --set ovs-vswitchd /usr/lib/openvswitch-switch-dpdk/ovs-vswitchd-dpdk
  1. Конфигурируем демоны OVS (Выделение ядер и сокетов памяти):
# Включаем саму поддержку DPDK

sudo ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-init=true

# Выделяем по 1 ГБ памяти из Hugepages конкретно на NUMA-ноду 0 (где сидит карта)

sudo ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-socket-mem="1024,0"

# Привязываем PMD-потоки к изолированным ядрам 2 и 4 (шестнадцатеричная маска 0x14)

sudo ovs-vsctl set Open_vSwitch . other_config:pmd-cpu-mask=0x14

# Перезапускаем сервис для применения настроек

sudo systemctl restart openvswitch-switch
  1. Проверяем успешность инициализации:
sudo ovs-vsctl get Open_vSwitch . dpdk_initialized

Обязано вернуть true. Если вернуло ошибку — смотрите лог /var/log/openvswitch/ovs-vswitchd.log.

ШАГ 4: Создание виртуального коммутатора и портов

  1. Создаем Userspace-бридж типа netdev:
sudo ovs-vsctl add-br br-dpdk -- set bridge br-dpdk datapath_type=netdev
  1. Добавляем привязанную физическую карту в качестве аплинка:
sudo ovs-vsctl add-port br-dpdk dpdk-p0 -- set Interface dpdk-p0 type=dpdk options:dpdk-devargs=0000:03:00.0
  1. Добавляем порт для ВМ (vhostuserclient):
sudo ovs-vsctl add-port br-dpdk vhost-vm1 -- set Interface vhost-vm1 type=dpdkvhostuserclient options:vhost-server-path=/var/run/openvswitch/vhost-vm1
  1. Добавляем внутренний порт для пространства имен (netns):
sudo ovs-vsctl add-port br-dpdk tap-ns1 -- set Interface tap-ns1 type=internal

ШАГ 5: Настройка Сетевого Пространства Имен (Netns)

  1. Создаем netns и перемещаем туда созданный интерфейс:
sudo ip netns add my-ns
sudo ip link set tap-ns1 netns my-ns
  1. Инициализируем интерфейс внутри netns и вешаем IP:
sudo ip netns exec my-ns ip link set tap-ns1 up
sudo ip netns exec my-ns ip addr add 10.0.0.10/24 dev tap-ns1

ШАГ 6: Настройка прав доступа и обход AppArmor (Важнейший фикс)

Если пропустить этот шаг, Libvirt упадет с ошибкой Permission Denied при старте ВМ, так как системы защиты заблокируют QEMU доступ к сокету OVS.

  1. Выставляем права на UNIX-сокет:
sudo chown libvirt-qemu:kvm /var/run/openvswitch/vhost-vm1
sudo chmod 777 /var/run/openvswitch/vhost-vm1
  1. Добавляем исключение в AppArmor для профиля QEMU:
sudo nano /etc/apparmor.d/abstractions/libvirt-qemu

Листаем в самый конец файла и прямо перед закрывающей фигурной скобкой } добавляем строчку:

/var/run/openvswitch/* rw,

Перезапускаем службу AppArmor:

sudo systemctl restart apparmor

ШАГ 7: Настройка XML-конфигурации ВМ в Libvirt

Открываем конфигурацию нужной виртуалки через virsh edit <имя_вм>. Модифицируем три критических блока внутри основного тега :

  1. Память (Строго Shared Memory и Hugepages):xml
<memory unit='KiB'>2097152</memory> <!-- 2 ГБ выделено под ВМ -->
<currentMemory unit='KiB'>2097152</currentMemory>
<memoryBacking>
  <hugepages/>
  <source type='file'/>
  <access mode='shared'/>
</memoryBacking>
  1. Топология CPU и привязка к NUMA-ноде 0:xml
<cpu mode='host-passthrough' check='none'>
  <numa>
    <cell id='0' cpus='0-1' memory='2097152' unit='KiB' memAccess='shared'/>
  </numa>
</cpu>
  1. Добавление интерфейса vhostuser в секцию :xml
  <devices>
  ...
  <interface type='vhostuser'>
    <mac address='52:54:00:12:34:56'/>
    <source type='unix' path='/var/run/openvswitch/vhost-vm1' mode='client'/>
    <model type='virtio'/>
    <driver name='vhost' queues='2'>
      <alloc type='anonymous'/>
    </driver>
  </interface>
  ...
</devices>
  1. Запускаем гостевую ОС:bash
virsh start <имя_вм>

ШАГ 8: Верификация и проверка трафика

  1. Проверяем, что PMD-потоки OVS успешно захватили сокеты интерфейсов:bash
sudo ovs-appctl dpif-netdev/pmd-rxq-show

В выводе вы обязаны увидеть интерфейсы vhost-vm1 и dpdk-p0, распределенные между ядрами 2 и 4. 2. Проверяем целостность бриджа OVS:

sudo ovs-vsctl show

Возле созданных портов не должно быть никаких надписей вроде error или dropped. 3. Тестируем связность: Зайдите в саму ВМ, настройте статический IP 10.0.0.20/24 на сетевом интерфейсе eth0. Из хостовой системы запустите пинг из пространства имен my-ns до виртуальной машины:

sudo ip netns exec my-ns ping 10.0.0.20

Если пинги всё равно не идут, пришлите вывод одной команды: • sudo ovs-ofctl dump-flows br-dpdk (проверим, нет ли дефолтных правил OpenFlow, которые блокируют коммутацию пакетов внутри самого бриджа).

PART 2

Для настройки VXLAN поверх OVS-DPDK в режиме Point-to-Point (между двумя хостами) требуется использовать инкапсуляцию на уровне пользователей (userspace). Трафик, выходящий из виртуальной машины или пространства имен, попадает в Userspace-бридж, упаковывается в VXLAN-туннель потоками PMD и выстреливается напрямую через физический DPDK-порт в сторону соседа. Ниже приведен полный монолитный мануал для настройки Хоста А и Хоста Б.

Архитектура туннеля Point-to-Point (ANSI)

================================== ХОСТ А ==================================
 [ VM / Netns (10.0.0.10) ]
            |
            v
     Бридж [br-int] (Внутренние сетевые порты)
            |
            v
     Бридж [br-phy] (datapath_type=netdev)
    =========================================

    |  Интерфейс VXLAN (type=vxlan)         |
    |  Local IP:  192.168.1.1 (dpdk-p0)     |
    |  Remote IP: 192.168.1.2               |
    =========================================
            |
            v (Инкапсулированный VXLAN трафик, UDP 4789)
     Физический порт [dpdk-p0] (PCI: 0000:03:00.0)
            |
            |================== ФИЗИЧЕСКИЙ L2/L3 СТЫК ==================
            |
     Физический порт [dpdk-p0] (PCI: 0000:03:00.0)
            ^
            | (Декапсуляция VXLAN)
    =========================================

    |  Интерфейс VXLAN (type=vxlan)         |
    |  Local IP:  192.168.1.2 (dpdk-p0)     |
    |  Remote IP: 192.168.1.1               |
    =========================================
     Бридж [br-phy] (datapath_type=netdev)
            ^
            |
     Бридж [br-int] (Внутренние сетевые порты)
            ^
            |
 [ VM / Netns (10.0.0.20) ]
================================== ХОСТ Б ==================================

ШАГ 1: Базовая подготовка GRUB и памяти (Одинаково на обоих хостах)

Для работы VXLAN в OVS-DPDK хостам необходимы изолированные ядра и выделенные Hugepages.

  1. Конфигурация GRUB:
sudo nano /etc/default/grub

Добавьте параметры выделения двух страниц по 1 ГБ и изоляции ядер 2,4 для PMD-потоков:

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash default_hugepagesz=1G hugepagesz=1G hugepages=2 isolcpus=2,4 nohz_full=2,4 rcu_nocbs=2,4 iommu=pt intel_iommu=on"
  1. Применение и перезагрузка:
sudo update-grub && sudo reboot

ШАГ 2: Привязка физических карт к DPDK (Одинаково на обоих хостах)

Физические интерфейсы, через которые хосты связаны друг с другом, отдаются под управление драйвера vfio-pci.

# Загружаем модуль
sudo modprobe vfio-pci

# Разрешаем режим No-IOMMU при необходимости
echo 1 | sudo tee /sys/module/vfio/parameters/enable_unsafe_noiommu_mode

# Привязываем сетевую карту (подставьте ваш PCI-адрес, например 0000:03:00.0)
sudo dpdk-devbind.py --bind=vfio-pci 0000:03:00.0

ШАГ 3: Запуск и инициализация OVS-DPDK (Одинаково на обоих хостах)

# Установка и переключение на версию DPDK
sudo apt update && sudo apt install -y openvswitch-switch-dpdk dpdk
sudo update-alternatives --set ovs-vswitchd /usr/lib/openvswitch-switch-dpdk/ovs-vswitchd-dpdk

# Конфигурация ресурсов OVS
sudo ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-init=true
sudo ovs-vsctl --no-wait set Open_vSwitch . other_config:dpdk-socket-mem="1024,0"
sudo ovs-vsctl set Open_vSwitch . other_config:pmd-cpu-mask=0x14

# Перезапуск службы и верификация (должно быть true)
sudo systemctl restart openvswitch-switch
sudo ovs-vsctl get Open_vSwitch . dpdk_initialized

ШАГ 4: Настройка сетевой топологии на ХОСТЕ А

Нам понадобятся два бриджа:

  1. br-phy — физический бридж (в пространстве netdev/userspace), который держит карту и упаковывает VXLAN.
  2. br-int — сервисный бридж, куда подключаются клиенты (ВМ или контейнеры). bash

1. Создаем физический бридж

sudo ovs-vsctl add-br br-phy -- set bridge br-phy datapath_type=netdev

2. Добавляем в него физический DPDK порт

sudo ovs-vsctl add-port br-phy dpdk-p0 -- set Interface dpdk-p0 type=dpdk options:dpdk-devargs=0000:03:00.0

3. Назначаем IP-адрес для самого OVS-интерфейса br-phy (Tep IP / Транспортный адрес)

sudo ip addr add 192.168.1.1/24 dev br-phy
sudo ip link set br-phy up

4. Создаем внутренний бридж интеграции

sudo ovs-vsctl add-br br-int -- set bridge br-int datapath_type=netdev

# 5. Создаем туннельный VXLAN порт на br-phy, смотрящий на Хост Б (192.168.1.2)
# key=flow позволяет гибко управлять VNI через правила OpenFlow, vni=100 задает жесткий ID туннеля

sudo ovs-vsctl add-port br-int vxlan0 -- set Interface vxlan0 type=vxlan \
    options:remote_ip=192.168.1.2 \
    options:local_ip=192.168.1.1 \
    options:key=100 \
    options:dst_port=4789

ШАГ 5: Настройка сетевой топологии на ХОСТЕ Б

Выполняются зеркальные настройки. Меняются местами параметры local_ip и remote_ip.

# 1. Создаем физический бридж
sudo ovs-vsctl add-br br-phy -- set bridge br-phy datapath_type=netdev

# 2. Добавляем в него физический DPDK порт
sudo ovs-vsctl add-port br-phy dpdk-p0 -- set Interface dpdk-p0 type=dpdk options:dpdk-devargs=0000:03:00.0

# 3. Назначаем IP-адрес для OVS-интерфейса br-phy на Хосте Б
sudo ip addr add 192.168.1.2/24 dev br-phy
sudo ip link set br-phy up

# 4. Создаем внутренний бридж интеграции
sudo ovs-vsctl add-br br-int -- set bridge br-int datapath_type=netdev

# 5. Создаем туннельный VXLAN порт на br-phy, смотрящий на Хост А (192.168.1.1)
sudo ovs-vsctl add-port br-int vxlan0 -- set Interface vxlan0 type=vxlan \
    options:remote_ip=192.168.1.1 \
    options:local_ip=192.168.1.2 \
    options:key=100 \
    options:dst_port=4789

ШАГ 6: Подключение тестовых эндпоинтов (Netns)

Для проверки прокинем по одному Network Namespace в бридж br-int на каждом хосте. На ХОСТЕ А:

sudo ip netns add ns-client
sudo ovs-vsctl add-port br-int tap-client -- set Interface tap-client type=internal
sudo ip link set tap-client netns ns-client
sudo ip netns exec ns-client ip link set tap-client up
sudo ip netns exec ns-client ip addr add 10.0.0.10/24 dev tap-client

На ХОСТЕ Б:

sudo ip netns add ns-client
sudo ovs-vsctl add-port br-int tap-client -- set Interface tap-client type=internal
sudo ip link set tap-client netns ns-client
sudo ip netns exec ns-client ip link set tap-client up
sudo ip netns exec ns-client ip addr add 10.0.0.20/24 dev tap-client

ШАГ 7: Настройка ARP-таблицы внутри OVS (Критически важно для Userspace VXLAN)

Так как инкапсуляция VXLAN происходит в пространстве пользователя (Userspace) силами самого OVS-DPDK, коммутатор должен заранее знать MAC-адрес соседа, соответствующий удаленному туннельному IP (remote_ip). Ядро Linux в этом процессе не участвует, поэтому OVS должен составить свою ARP-таблицу. На ХОСТЕ А (сообщаем OVS MAC-адрес Хоста Б): Выясните MAC-адрес интерфейса br-phy на Хосте Б с помощью ip link show br-phy (например, aa:bb:cc:dd:ee:22).

sudo ovs-appctl tnl/arp/set br-phy 192.168.1.2 aa:bb:cc:dd:ee:22

На ХОСТЕ Б (сообщаем OVS MAC-адрес Хоста А): Выясните MAC-адрес интерфейса br-phy на Хосте А (например, aa:bb:cc:dd:ee:11).

sudo ovs-appctl tnl/arp/set br-phy 192.168.1.1 aa:bb:cc:dd:ee:11

ШАГ 8: Верификация туннеля и прогон трафика

  1. Проверяем статус портов на обоих хостах:
sudo ovs-vsctl show

В выводе бриджа br-int вы должны увидеть порт vxlan0 без ошибок. 2. Проверяем внутреннюю ARP/Туннельную таблицу OVS:

sudo ovs-appctl tnl/arp/show

Запись соседа должна быть в статусе валидной. 3. Запуск пинга сквозь VXLAN туннель: С Хоста А отправляем пакеты из пространства имен до пространства имен на Хосте Б:

sudo ip netns exec ns-client ping 10.0.0.20

Если пинг не проходит, пришлите вывод отладочной команды с любого из хостов: • sudo ovs-appctl dpif/show (покажет, видит ли ядро OVS виртуальные туннельные маршруты для инкапсуляции).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment