В блог

Настройка Open vSwitch для KVM через libvirt

Настройка Open vSwitch для KVM через libvirt

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

Для этого можно использовать Open vSwitch (OVS). Он позволяет объединять виртуальные и физические интерфейсы в одном мосту, назначать портам VLAN и передавать тегированный трафик на внешний коммутатор. При этом libvirt продолжает управлять виртуальными машинами и автоматически подключает их сетевые интерфейсы к OVS

Разберём настройку на примере одного моста kvmnetwork⁠, виртуальной машины demo-vm и физического интерфейса eth1⁠. Сначала подключим машину к мосту, затем обеспечим выход во внешнюю сеть и настроим VLAN 20

Подготовка хоста и ВМ

Для примера потребуется Linux-сервер с установленными Open vSwitch, QEMU/KVM и libvirt. Виртуальная машина должна существовать в системном подключении qemu:///system⁠, а физический интерфейс eth1 не должен использоваться для управления сервером или входить в другой мост

Сам OVS не заменяет libvirt. Он отвечает за передачу Ethernet-кадров между портами, тогда как libvirt создаёт сетевые интерфейсы виртуальных машин и подключает их к выбранному мосту

Для обычной сети без дополнительных требований можно использовать и Linux bridge. Open vSwitch имеет смысл выбрать, если вы уже используете его в инфраструктуре или хотите управлять виртуальными сетями, VLAN и правилами коммутации средствами OVS

Начнём с проверки текущей конфигурации

sudo ovs-vsctl show
sudo virsh --connect qemu:///system list --all
ip -br address show dev eth1
ip route show dev eth1
ip -6 route show dev eth1

Первая команда покажет существующие мосты и порты OVS. Во второй найдите demo-vm и убедитесь, что виртуальная машина доступна через libvirt

Остальные команды нужны для проверки eth1⁠. На интерфейсе, который мы собираемся добавить в мост, не должно быть IP-адресов и маршрутов, необходимых самому серверу. Если NetworkManager или другой сетевой менеджер автоматически настраивает этот интерфейс, сначала измените его конфигурацию

Создание моста Open vSwitch

В Open vSwitch виртуальные машины подключаются к мосту через отдельные порты. Пока у моста нет физического интерфейса, обмен данными возможен только между подключёнными к нему устройствами

Создадим мост kvmnetwork

sudo ovs-vsctl add-br kvmnetwork
sudo ip link set dev kvmnetwork up
sudo ovs-vsctl show

В выводе ovs-vsctl show должен появиться новый мост. OVS также создаст одноимённый внутренний интерфейс, который при необходимости можно использовать для подключения сетевого стека хоста. В нашем примере IP-адрес ему назначать не требуется

Мост готов к подключению виртуальных машин, но сам по себе не предоставляет DHCP, NAT или маршрутизацию. Если двум гостям назначить адреса одной подсети, они смогут обмениваться данными напрямую, однако доступа во внешнюю сеть пока не будет

Для проверки внутри изолированного стенда можно использовать, например, 192.0.2.10/24 и 192.0.2.11/24⁠. Эти адреса предназначены для документационных примеров, поэтому в реальной сети используйте подходящую подсеть

Подключение KVM через libvirt

Чтобы libvirt подключал виртуальную машину к OVS при каждом запуске, нужно изменить определение её сетевого интерфейса в XML

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

sudo virsh --connect qemu:///system dumpxml --inactive demo-vm > demo-vm.before-ovs.xml

Теперь штатно выключим виртуальную машину

sudo virsh --connect qemu:///system shutdown demo-vm
sudo virsh --connect qemu:///system domstate demo-vm

shutdown только отправляет запрос на завершение работы гостевой ОС. Прежде чем редактировать и запускать машину, дождитесь состояния shut off⁠. Если она не выключается, проверьте состояние гостя через консоль

Откройте XML-конфигурацию

sudo virsh --connect qemu:///system edit demo-vm

Найдите нужный <interface> внутри <devices>⁠. Для подключения к OVS у него должны быть указаны тип bridge⁠, имя моста и тип виртуального порта openvswitch

<interface type='bridge'>
  <source bridge='kvmnetwork'/>
  <virtualport type='openvswitch'/>
  <model type='virtio'/>
</interface>

Здесь source определяет мост, к которому подключается машина. А элемент virtualport сообщает libvirt, что это мост Open vSwitch, а не обычный Linux bridge

В существующем интерфейсе обязательно сохраните MAC-адрес, PCI-адрес и другие необходимые параметры. Модель сетевого адаптера без причины тоже менять не следует. В примере указан virtio⁠, но если гостевая система использует другой адаптер, сохраните его

Такой способ подключения описан в документации Open vSwitch для libvirt

После сохранения XML запустите виртуальную машину

sudo virsh --connect qemu:///system start demo-vm
sudo virsh --connect qemu:///system domiflist demo-vm
sudo ovs-vsctl show

Libvirt создаст TAP-интерфейс виртуальной машины и зарегистрирует его как порт OVS. В выводе domiflist он может называться vnet0⁠, vnet1 или иначе. Имя назначается при запуске и может измениться в дальнейшем

Добавлять TAP-интерфейс в мост вручную не нужно. Libvirt сделает это самостоятельно на основании XML-конфигурации

Если до переноса машина использовала стандартную NAT-сеть libvirt, прежние DHCP и шлюз больше не будут доступны через изменённый интерфейс. Настройте IP-адрес гостя для новой сети и подключите вторую машину аналогичным образом

Теперь можно проверить связь между гостями, находящимися в одной подсети. Пока физический интерфейс не подключён, трафик останется внутри хоста

Подключение к физической сети

Чтобы виртуальные машины могли обмениваться данными с устройствами за пределами хоста, добавим в kvmnetwork физический интерфейс eth1

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

sudo ovs-vsctl add-port kvmnetwork eth1
sudo ip link set dev eth1 up

После добавления eth1 виртуальные машины получают возможность отправлять кадры во внешнюю сеть через тот же мост

Для работы по IP адреса гостей должны соответствовать подключённому сетевому сегменту. Их можно получить от внешнего DHCP-сервера или назначить вручную вместе с нужным шлюзом и DNS

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

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

Для этого настроим VLAN на портах OVS

Настройка VLAN для гостя

Предположим, что demo-vm должна находиться в VLAN 20⁠. Гостевой системе при этом не нужно самостоятельно добавлять тег к Ethernet-кадрам. Эту работу выполнит Open vSwitch

Схема будет состоять из двух типов портов. Виртуальная машина подключается через access-порт VLAN 20⁠, а физический интерфейс eth1 используется как trunk и передаёт кадры с тегом 20 на внешний коммутатор

Trunk на физическом порту

Сначала разрешим VLAN 20 на порту eth1

sudo ovs-vsctl set Port eth1 vlan_mode=trunk trunks=20

Теперь OVS будет передавать через этот порт тегированный трафик VLAN 20⁠. Внешний коммутатор должен быть настроен соответствующим образом – его порт тоже должен принимать и отправлять VLAN 20 с тегом

Команда задаёт новый список разрешённых VLAN. Если через eth1 должны проходить другие сегменты, включите их в trunks вместе с VLAN 20

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

Если на внешнем коммутаторе используется native VLAN с передачей кадров без тега, схема будет отличаться. Для такого подключения потребуется соответствующий режим native-tagged или native-untagged в OVS, а не обычный trunk из нашего примера

Назначение VLAN через libvirt

Теперь укажем VLAN в конфигурации libvirt

Выключите demo-vm⁠, дождитесь завершения работы и снова откройте XML через virsh edit⁠. В сетевой интерфейс добавьте элемент <vlan>⁠, сохранив остальные настройки

<interface type='bridge'>
  <source bridge='kvmnetwork'/>
  <virtualport type='openvswitch'/>
  <vlan>
    <tag id='20'/>
  </vlan>
  <model type='virtio'/>
</interface>

После сохранения запустите машину

sudo virsh --connect qemu:///system start demo-vm

При запуске libvirt передаст настройки VLAN в Open vSwitch. Для порта виртуальной машины будет назначен тег 20⁠, а OVS начнёт обрабатывать его как access-порт соответствующего сегмента

Когда гость отправляет кадр без VLAN-тега, OVS относит его к VLAN 20⁠. При передаче через eth1 на trunk-порту к кадру добавляется тег 802.1Q. В обратном направлении OVS принимает тегированный кадр, определяет нужный сегмент и удаляет тег перед передачей гостю

Таким образом, внутри виртуальной машины остаётся обычный сетевой интерфейс. Создавать eth0.20 или другой VLAN-интерфейс в гостевой ОС не требуется

В документации XML libvirt этот механизм называется guest-transparent VLAN tagging

Назначьте гостю IP-адрес из подсети VLAN 20 или получите его через DHCP. Если необходим доступ к другим подсетям, в этом VLAN должен быть доступен маршрутизатор

Остальные машины можно подключить к VLAN 20 по той же схеме. Для разделения виртуальных машин используйте другие VLAN ID, предварительно разрешив соответствующие VLAN на физическом trunk-порту

Проверка портов и соединений

После изменения конфигурации стоит отдельно проверить состояние портов OVS и доступность сети из виртуальной машины

Начнём с параметров VLAN

sudo ovs-vsctl --columns=name,vlan_mode,tag,trunks list Port

У порта виртуальной машины в поле tag должно быть значение 20⁠. У физического eth1 ожидаются vlan_mode=trunk и список trunks⁠, содержащий VLAN 20

Учтите, что пустой список trunks в OVS означает разрешение всех VLAN, а не их запрет. Поэтому при необходимости ограничить физический порт конкретными сегментами список следует задавать явно

Посмотрим, корректно ли OVS создал сетевые интерфейсы

sudo ovs-vsctl --columns=name,type,ofport,error list Interface
ip -br link show dev eth1

У рабочего интерфейса ofport обычно содержит положительное число. Если указано -1⁠, проверьте поле error⁠, где OVS может сообщить причину проблемы

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

Описание полей OVS доступно в схеме базы данных Open vSwitch

Теперь проверьте сетевую конфигурацию внутри Linux-гостя

ip -br address
ip route

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

Когда связь между гостями есть, а шлюз недоступен, в первую очередь сравните VLAN ID на виртуальном порту, физическом интерфейсе OVS и внешнем коммутаторе. Несовпадение тегов или неправильный режим native VLAN могут приводить к тому, что кадры уходят в один сегмент, а возвращаются из другого или отбрасываются

Такие ситуации разобраны в FAQ Open vSwitch по VLAN

Если соединение по IP работает, но доменные имена не разрешаются, проверьте DNS внутри гостевой ОС. При проблемах только с крупными пакетами сравните MTU на всех участках сети

Для диагностики можно использовать ping или подключение к доступному сетевому сервису. При этом отсутствие ICMP-ответа ещё не означает, что сеть не работает – ICMP может блокироваться firewall

Если виртуальная машина вообще не запускается после изменения XML, начните с ошибки virsh start⁠, затем проверьте журналы libvirt и Open vSwitch. Обычно этого достаточно, чтобы определить, связана ли проблема с XML, отсутствующим мостом или ошибкой создания TAP-порта

Сохранение настроек и откат

Open vSwitch хранит конфигурацию мостов и портов в собственной базе данных. Изменения, внесённые через ovs-vsctl⁠, сохраняются в ней и обычно восстанавливаются при следующем запуске OVS

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

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

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

Если нужно отменить перенос виртуальной машины, сначала штатно выключите её и дождитесь состояния shut off

Затем восстановите исходный XML

sudo virsh --connect qemu:///system define demo-vm.before-ovs.xml
sudo virsh --connect qemu:///system start demo-vm

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

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

sudo ovs-vsctl del-port kvmnetwork eth1
sudo ovs-vsctl del-br kvmnetwork

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

В результате вся конфигурация сети остаётся разделена между двумя компонентами. Libvirt управляет подключением виртуальных машин, а Open vSwitch определяет, к каким VLAN относятся их порты и как трафик передаётся через физические интерфейсы. Это позволяет изменять сетевую схему без настройки VLAN внутри каждой гостевой системы

Настроим сеть для ваших виртуальных машин

Подключим виртуальные машины к сети, настроим Open vSwitch и разделение по VLAN. Учтём существующую схему и доступ к управлению сервером

Обсудить настройку DevOps и техническая поддержка