Глава 3. Построение сетей KVM при помощи libvirt

В этой главе мы намерены рассмотреть такие вопросы:

  • Мост Linux

  • Open vSwitch

  • Настройка сетевой среды пересылки NAT

  • Настройка сетевой среды с мостом

  • Настройка сквозной сетевой среды PCIe

  • Манипулирование интерфесами сетевой среды

Введение

В libvirt мы можем определять различные типы сетевых сред для наших гостевых KVM при помощи уже известного нам синтаксиса определений XML и инструментов пространства пользователя virsh и virt-install. В этой главе мы намерены развернуть три типа сетевых сред, изучить соответствующий сетевой формат XML и рассмотреть примеры того как определять виртуальные интерфейсы для своих экземпляров KVM и как ими манипулировать.

Чтобы иметь возможность подключать виртуальные машины к ОС своего хоста или друг к другу, мы собираемся воспользоваться имеющимся мостом Linux и демонами Open vSwitch (OVS), инструментами пространства пользователя и модулями ядра. Обе технологии построения программного моста великолепны при создании Software-defined Networking (SDN, программно определяемой сетевой среды) различной сложности неким согласованным и простым в обращении образом. И мост Linux, и OVS, оба действуют как мост/ коммутатор, к которым могут подключаться имеющиеся у наших гостевых KVM виртуальные интерфейсы.

Имея это в виду, давайте начнём узнавать подробности программных мостов в Linux.

Мост Linux

Мост Linux является неким программно определяемым устройством 2 уровня, который предоставляет необходимую функциональность какого- то физического устройства моста. Он способен переправлять кадры между гостевыми KVM, ОС своего хоста и виртуальными машинами, запущенными на прочих серверах или в иных сетевых средах. Мост Linux состоит из двух компонентов - инструмента администрирования пространства пользователя, который мы намерены применять в данном рецепте и какого- то модуля ядра, который и выполняет всю работу по соединению воедино множества сегментов Ethernet. Каждый создаваемый нами программный мост может иметь некое число подключённых к нему портов, где и происходит переадресация сетевого обмена в обоих направлениях. При создании экземпляров KVM мы можем подключать их виртуальные интерфейсы, которые ассоциированы с таким мостом, что аналогично вставке какого- то сетевого кабеля от некой NIC сервера в устройство моста/ коммутатора. Выступая в роли устройства 2 уровня, имеющийся мост Linux работает с MAC адресами и выполняет сопровождение некоторой структуры ядра по отслеживанию портов и ассоциированных MAC адресов в виде некоей таблицы Content Addressable Memory (CAM, ассоциативной памяти).

В данном рецепте мы намерены создать некий новый мост Linux и воспользоваться утилитой brctl для манипуляций с ним.

Приготовление

В данном рецепте нам потребуется следующее:

  • Современное ядро Linux с включёнными возможностями 802.1d Ethernet.

    Для проверки того скомпилировано ли ваше ядро с такой функциональностью или выставлены ли модули ядра, исполните такие команды:

    
    root@kvm:~# cat /boot/config-`uname -r` | grep -i bridg
    # PC-card bridges
    CONFIG_BRIDGE_NETFILTER=y
    CONFIG_NF_TABLES_BRIDGE=m
    CONFIG_BRIDGE_NF_EBTABLES=m
    CONFIG_BRIDGE_EBT_BROUTE=m
    CONFIG_BRIDGE_EBT_T_FILTER=m
    CONFIG_BRIDGE_EBT_T_NAT=m
    CONFIG_BRIDGE_EBT_802_3=m
    CONFIG_BRIDGE_EBT_AMONG=m
    CONFIG_BRIDGE_EBT_ARP=m
    CONFIG_BRIDGE_EBT_IP=m
    CONFIG_BRIDGE_EBT_IP6=m
    CONFIG_BRIDGE_EBT_LIMIT=m
    CONFIG_BRIDGE_EBT_MARK=m
    CONFIG_BRIDGE_EBT_PKTTYPE=m
    CONFIG_BRIDGE_EBT_STP=m
    CONFIG_BRIDGE_EBT_VLAN=m
    CONFIG_BRIDGE_EBT_ARPREPLY=m
    CONFIG_BRIDGE_EBT_DNAT=m
    CONFIG_BRIDGE_EBT_MARK_T=m
    CONFIG_BRIDGE_EBT_REDIRECT=m
    CONFIG_BRIDGE_EBT_SNAT=m
    CONFIG_BRIDGE_EBT_LOG=m
    # CONFIG_BRIDGE_EBT_ULOG is not set
    CONFIG_BRIDGE_EBT_NFLOG=m
    CONFIG_BRIDGE=m
    CONFIG_BRIDGE_IGMP_SNOOPING=y
    CONFIG_BRIDGE_VLAN_FILTERING=y
    CONFIG_SSB_B43_PCI_BRIDGE=y
    CONFIG_DVB_DDBRIDGE=m
    CONFIG_EDAC_SBRIDGE=m
    # VME Bridge Drivers
    root@kvm:~#
    		
  • Собственно модуль ядра bridge.

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

    
    root@kvm:~# lsmod | grep bridge
    bridge 110925 0
    stp 12976 2 garp,bridge
    llc 14552 3 stp,garp,bridge
    root@kvm:~#
    root@kvm:~# modinfo bridge
    filename: /lib/modules/3.13.0-107-generic/kernel/net/bridge/bridge.ko
    alias: rtnl-link-bridge
    version: 2.3
    license: GPL
    srcversion: 49D4B615F0B11CA696D8623
    depends: stp,llc
    intree: Y
    vermagic: 3.13.0-107-generic SMP mod_unload modversions
    signer: Magrathea: Glacier signing key
    sig_key: E1:07:B2:8D:F0:77:39:2F:D6:2D:FD:D7:92:BF:3B:1D:BD:57:0C:D8
    sig_hashalgo: sha512
    root@kvm:~#
    		
  • Пакет bridge-utils, который предоставляет необходимые инструменты для создания моста Linux и манипуляции им.

  • Возможность создания новых гостей KVM при помощи libvirt или соответствующих утилит QEMU или некого имеющегося экземпляра KVM из наших предыдущих глав.

Как это сделать...

Чтобы создавать, перечислять и манипулировать новым мостом, выполните следующие шаги:

  1. Установите необходимый пакет моста Linux, если его ещё нет:

    
    root@kvm:~# apt install bridge-utils
     	   
  2. Постройте новый экземпляр KVM при помощи сырого образа из нашего рецепта Главы 1 Установка пользовательской ОС в образ при помощи debootstrap если вы не читаете эту книгу от корки до корки:

    
    root@kvm:~# virt-install --name kvm1 --ram 1024 --disk path=/tmp/debian.img,format=raw --graphics vnc,listen=146.20.141.158 --noautoconsole --hvm --import
    
    Starting install...
    Creating domain... | 0 B 00:00
    Domain creation completed. You can restart your domain by running:
     virsh --connect qemu:///system start kvm1
    root@kvm:~#
     	   
  3. Перечислите все доступные устройства мостов:

    
    root@kvm:~# brctl show
    bridge name      bridge id             STP enabled     interfaces
    virbr0           8000.fe5400559bd6     yes             vnet0
    root@kvm:~#
     	   
  4. Выключите свой виртуальный мост, удалите его и убедитесь в его удалении:

    
    root@kvm:~# ifconfig virbr0 down
    root@kvm:~# brctl delbr virbr0
    root@kvm:~# brctl show
    bridge name bridge id STP enabled interfaces
    root@kvm:~#
     	   
  5. Создайте некий новый мост и поднимите его:

    
    root@kvm:~# brctl addbr virbr0
    root@kvm:~# brctl show
    bridge name     bridge id            STP enabled interfaces
    virbr0          8000.000000000000    no
    root@kvm:~# ifconfig virbr0 up
    root@kvm:~#
     	   
  6. Назначьте мосту некий IP адрес:

    
    root@kvm:~# ip addr add 192.168.122.1 dev virbr0
    root@kvm:~# ip addr show virbr0
    39: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
     link/ether 32:7d:3f:80:d7:c6 brd ff:ff:ff:ff:ff:ff
     inet 192.168.122.1/32 scope global virbr0
     valid_lft forever preferred_lft forever
     inet6 fe80::307d:3fff:fe80:d7c6/64 scope link
     valid_lft forever preferred_lft forever
    root@kvm:~#
     	   
  7. Перечислите все сетевые интерфейсы ОС своего хоста:

    
    root@kvm:~# ip a s | grep vnet
    38: vnet0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 500
    root@kvm:~#
     	   
  8. Добавьте имеющийся виртуальный интерфейс vnet0 в свой мост:

    
    root@kvm:~# brctl addif virbr0 vnet0
    root@kvm:~# brctl show virbr0
    bridge name     bridge id             STP enabled     interfaces
    virbr0          8000.fe5400559bd6     no              vnet0
    root@kvm:~#
     	   
  9. Включите в своём мосте Spanning Tree Protocol (STP, протокол связующего дерева):

    
    root@kvm:~# brctl stp virbr0 on
    root@kvm:~# brctl showstp virbr0
    virbr0
     bridge id 8000.fe5400559bd6
     designated root 8000.fe5400559bd6
     root port 0 path cost 0
     max age 20.00 bridge max age 20.00
     hello time 2.00 bridge hello time 2.00
     forward delay 15.00 bridge forward delay 15.00
     ageing time 300.00
     hello timer 0.26 tcn timer 0.00
     topology change timer 0.00 gc timer 90.89
     flags
    
    
    vnet0 (1)
     port id 8001 state forwarding
     designated root 8000.fe5400559bd6 path cost 100
     designated bridge 8000.fe5400559bd6 message age timer 0.00
     designated port 8001 forward delay timer 0.00
     designated cost 0 hold timer 0.00
     flags
    
    root@kvm:~#
     	   
  10. Из экземпляра KVM поднимите интерфейс, запросите IP- адрес и проверьте подключение к ОС его хоста:

    
    root@debian:~# ifconfig eth0 up
    root@debian:~# dhclient eth0
    root@debian:~# ip a s eth0
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
     link/ether 52:54:00:55:9b:d6 brd ff:ff:ff:ff:ff:ff
     inet 192.168.122.92/24 brd 192.168.122.255 scope global eth0
     valid_lft forever preferred_lft forever
     inet6 fe80::5054:ff:fe55:9bd6/64 scope link
     valid_lft forever preferred_lft forever
    root@debian:~#
    root@debian:~# ping 192.168.122.1 -c 3
    PING 192.168.122.1 (192.168.122.1) 56(84) bytes of data.
    64 bytes from 192.168.122.1: icmp_seq=1 ttl=64 time=0.276 ms
    64 bytes from 192.168.122.1: icmp_seq=2 ttl=64 time=0.226 ms
    64 bytes from 192.168.122.1: icmp_seq=3 ttl=64 time=0.259 ms
    
    --- 192.168.122.1 ping statistics ---
    3 packets transmitted, 3 received, 0% packet loss, time 1999ms
    rtt min/avg/max/mdev = 0.226/0.253/0.276/0.027 ms
    root@debian:~#
     	   

Как это работает...

После того как мы впервые установили свой демон libvirt несколько моментов произошло в автоматическом режиме:

  • Был создан некий новый мост Linux с теми названием и IP адресом, которые определены в файле настройки /etc/libvirt/qemu/networks/default.xml

  • Была запущена служба dnsmasq с какой- то конфигурацией, определённой в файле /var/lib/libvirt/dnsmasq/default.conf

Давайте изучим установленные по умолчанию настройки моста libvirt:


root@kvm:~# cat /etc/libvirt/qemu/networks/default.xml
<network>
 <name>default</name>
 <bridge name="virbr0"/>
 <forward/>
 <ip address="192.168.122.1" netmask="255.255.255.0">
   <dhcp>
     <range start="192.168.122.2" end="192.168.122.254"/>
   </dhcp>
 </ip>
</network>
root@kvm:~#
		

Именно эту сетевую среду по умолчанию создал для нас libvirt, определив соответствующие название моста, адрес IP и тот диапазон IP, который используется запущенным сервером DHCP. Позднее в этой главе мы намерены обсудить более подробно сетевую среду libvirt; тем не менее мы показали её здесь чтобы помочь вам понять откуда появились все наши адреса IP и само название моста.

Мы можем обнаружить, что в ОС нашего хоста исполняется некий сервер DHCP и просмотреть его файл настройки с помощью такой команды:


root@kvm:~# pgrep -lfa dnsmasq
38983 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf
root@kvm:~# cat /var/lib/libvirt/dnsmasq/default.conf
##WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
##OVERWRITTEN AND LOST. Changes to this configuration should be made using:
## virsh net-edit default
## or other application using the libvirt API.
##
## dnsmasq conf file created by libvirt
strict-order
user=libvirt-dnsmasq
pid-file=/var/run/libvirt/network/default.pid
except-interface=lo
bind-dynamic
interface=virbr0
dhcp-range=192.168.122.2,192.168.122.254
dhcp-no-override
dhcp-leasefile=/var/lib/libvirt/dnsmasq/default.leases
dhcp-lease-max=253
dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile
addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts
root@kvm:~#
		

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

Имея всё это в виду, давайте пройдём по всем выполненным нами ранее шагам.

На шаге 1 мы установили инструментарий пространства пользователя brctl, который мы будем применять для создания, настройки и инспектирования конфигурации своего моста Linux в своём ядре Linux.

На шаге 2 мы предоставили некий новый экземпляр KVM при помощи некого индивидуального сырого образа, содержащего необходимую гостевую ОС. Это шаг не требуется если вы выполняли все рецепты в наших предыдущих главах.

На шаге 3 мы вызвали свою утилиту bridge для перечисления всех доступных устройств моста. Из полученного вывода мы можем обнаружить что в настоящий момент у нас имеется один мост с названием virbr0, который был автоматически создан libvirt. Отметим, что в колонке интерфейса мы можем видеть интерфейс vnet0. Именно эта виртуальная NIC выставляется в ОС нащего хоста при запуске нами соответствующего экземпляра KVM. Это означает, что наша виртуальная машина подключена к мосту своего хоста.

На шаге 4 мы вначале отключаем имеющийся мост для его удаления, а затем снова применяем команду brctl для унчтожения этого моста и проверки того что он более не присутствует в ОС нашего хоста.

На шаге 5 мы повторно создаём необходимый мост и опять поднимаем его. Мы делаем это чтобы показать шаги, необходимые при создании какого- то нового моста.

На шаге 6 мы повторно назначаем тот же самый IP адрес своему мосту и просматриваем его.

На шагах 7 и 8 мы перечисляем все виртуальные интерфейсы в ОС своего хоста. Поскольку у нас имеется в настоящий момент только одна гостевая KVM, которая исполняется в нашем сервере, мы видим всего один виртуальный интерфейс, то есть vnet0. Затем мы переходим к добавлению/ подключению своего виртуального NIC к созданному мосту.

На шаге 9 мы включаем STP в своём мосте. STP является неким протоколом 2 уровня, который помогает нам предотвращать зацикливания в сетевой среде в случае когда у нас имеются избыточные сетевые пути. Это в особенности полезно при сетевых топологиях более крупного масштаба и более сложных, когда множество мостов соединяются друг с другом.

Наконец, на шаге 10 мы подключаемся к своей гостевой KVM при помощи консоли, перечисляем настройки её сетевых интерфейсов и убеждаемся что мы способны выполнить пинг к имеющемуся в ОС её хоста мосту. Для этого нам требуется поднять этот сетевой интерфейс внутри своего гостя с помощью ifconfig eth0 up, затем получить некий IP адрес при помощи команды dhclient eth0 от того сервера dnsmasq, который запущен на нашем хосте.

Также ознакомьтесь...

Существует ещё ряд полезных команд, которые могут применяться для имеющегося моста Linux.

Мы уже знаем что некий мост выполняет переадресацию кадров на основе тех MAC адресов, которые содержатся внутри него. Для изучения имеющейся таблицы MAC адресов, известных нашему мосту, исполните такую команду:


root@kvm:~# brctl showmacs virbr0
port no  mac addr               is local?      ageing timer
  1      52:54:00:55:9b:d6      no             268.02
  1      fe:54:00:55:9b:d6      yes            0.00
root@kvm:~#
		

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


root@kvm:~# virsh console kvm1
Connected to domain kvm1
Escape character is ^]

root@debian:~# ip a s eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
 link/ether 52:54:00:55:9b:d6 brd ff:ff:ff:ff:ff:ff
 inet6 fe80::5054:ff:fe55:9bd6/64 scope link
 valid_lft forever preferred_lft forever
root@debian:~#
		

Второй MAC адрес является адресом самого нашего моста и его MAC адрес имеющегося виртуального интерфейса, относящегося к имеющейся виртуальной машине, который выставляется ОС его хоста. Чтобы убедиться в этом исполните такую команду:


root@kvm:~# ifconfig | grep "fe:54:00:55:9b:d6"
virbr0 Link encap:Ethernet HWaddr fe:54:00:55:9b:d6
vnet0  Link encap:Ethernet HWaddr fe:54:00:55:9b:d6
root@kvm:~#
		

Когда наш мост видит некий кадр в одном из своих портов, он записывает значение времени, затем после того как на протяжении установленного промежутка времени он не наблюдает тот же самый MAC адрес снова, он удалит эту запись из своей таблицы CAM. Мы можем устанавливать в секундах этот временной предел до того как истечёт срок действия записи MAC адреса выполняя такую команду:


root@kvm:~# brctl setageing virbr0 600
root@kvm:~#
		

Команда brctl хорошо документирована; чтобы перечислить все доступные субкоманды, запустите её без параметров:


root@kvm:~# brctl
Usage: brctl [commands]
commands:
        addbr <bridge> add bridge
        delbr <bridge> delete bridge
        addif <bridge> <device> add interface to bridge
        delif <bridge> <device> delete interface from bridge
        hairpin <bridge> <port> {on|off} turn hairpin on/off
        setageing <bridge> <time> set ageing time
        setbridgeprio <bridge> <prio> set bridge priority
        setfd <bridge> <time> set bridge forward delay
        sethello <bridge> <time> set hello time
        setmaxage <bridge> <time> set max message age
        setpathcost <bridge> <port> <cost> set path cost
        setportprio <bridge> <port> <prio> set port priority
        show [ <bridge> ] show a list of bridges
        showmacs <bridge> show a list of mac addrs
        showstp <bridge> show bridge stp info
        stp <bridge> {on|off} turn stp on/off
root@kvm:~#
		

Большинство дистрибутивов Linux пакуют в свой состав обсуждаемую утилиту brctl и именно её мы и применяем в данном рецепте. Однако, чтобы воспользоваться самой последней версией или если пакет не доступен в вашем дистрибутиве, мы можем построить эту утилиту из исходного кда клонировав её проект с git, а затем выполнив настройку и скомпилировав её:


root@kvm:~# cd /usr/src/
root@kvm:/usr/src# apt-get update && apt-get install build-essential automake pkg-config git
root@kvm:/usr/src# git clone git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/bridge-utils.git
Cloning into 'bridge-utils'...
remote: Counting objects: 654, done.
remote: Total 654 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (654/654), 131.72 KiB | 198.00 KiB/s, done.
Resolving deltas: 100% (425/425), done.
Checking connectivity... done.
root@kvm:/usr/src# cd bridge-utils/
root@kvm:/usr/src/bridge-utils# autoconf
root@kvm:/usr/src/bridge-utils# ./configure && make && make install
root@kvm:/usr/src/bridge-utils# brctl --version
bridge-utils, 1.5
root@kvm:/usr/src/bridge-utils#
		

В своём предыдущем выводе мы можем наблюдать что вначале мы клонировали имеющийся для проекта bridge-utils репозиторий git, а потом скомпилировали полученный исходный код.

В хосте RedHat/CentOS этот процесс аналогичный:


[root@centos ~]# cd /usr/src/
[root@centos src]#
[root@centos src]# yum groupinstall "Development tools"
[root@centos src]# git clone git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/bridge-utils.git
Cloning into 'bridge-utils'...
remote: Counting objects: 654, done.
remote: Total 654 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (654/654), 131.72 KiB | 198.00 KiB/s, done.
Resolving deltas: 100% (425/425), done.
Checking connectivity... done.
[root@centos src]# cd bridge-utils
[root@centos bridge-utils]# autoconf
[root@centos bridge-utils]# ./configure && make && make install
[root@centos bridge-utils]# brctl --version
bridge-utils, 1.5
[root@centos bridge-utils]#
		

Open vSwitch

OVS является другим программно определяемым устройством моста/ коммутатора, который может применяться для создания различных виртуальных сетевых топологий и подключать к ним экземпляры KVM. OVS может использоваться вместо моста Linux и предоставляет расширенный набор свойств, включающих в свой состав политики маршрутизации, ACL (Access Control Lists, списки контролья доступа) политики QoS (Quality of Service, качества обслуживания), отслеживание сетевого обмена, управление потоком, выставление тегов VLAN, туннелирование GRE и многое другое.

В данном рецепте мы намереваемся установить, настроить и применить мост OVS для подключения некоего экземпляра KVM к ОС его хоста аналогично тому как мы это делали в своём предыдущем рецепте с помощью моста Linux.

Приготовление

Для работы с этим рецептом нам понадобятся гарантии следующего:

  • Мост Linux удалён, в случае его наличия, а OVS установлен

  • У нас имеется запущенным по крайней мере один экземпляр KVM

Как это сделать...

Для создания некого нового моста OVS и подключения имеющегося виртуального интерфейса некой гостевой KVM следуйте таким шагам:

  1. Если он имеется, удалите существующий мост Linux:

    
    root@kvm:~# brctl show
    bridge name      bridge id             STP enabled      interfaces
    virbr0           8000.fe5400559bd6     yes              vnet0
    root@kvm:~# ifconfig virbr0 down
    root@kvm:~# brctl delbr virbr0
    root@kvm:~# brctl show
    bridge name bridge id STP enabled interfaces
    root@kvm:~#
     	   
    [Совет]Совет

    В некоторых дистрибутивах Linux помогает выгрузка соответствующего модуля ядра для моста KVM перед использованием OVS. Чтобы сделать это выполните root@kvm:/usr/src# modprobe -r bridge.

  2. Установите необходимый пакет OVS в Ubuntu:

    
    root@kvm:~# apt-get install openvswitch-switch
    ...
    Setting up openvswitch-common (2.0.2-0ubuntu0.14.04.3) ...
    Setting up openvswitch-switch (2.0.2-0ubuntu0.14.04.3) ...
    openvswitch-switch start/running
    ...
    root@kvm:~#
     	   
  3. Убедитесь что соответствующие процессы OVS исполняются:

    
    root@kvm:~# pgrep -lfa switch
    22255 ovsdb-server /etc/openvswitch/conf.db -vconsole:emer -vsyslog:err -vfile:info --remote=punix:/var/run/openvswitch/db.sock --private-key=db:Open_vSwitch,SSL,private_key --certificate=db:Open_vSwitch,SSL,certificate --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert --no-chdir --log-file=/var/log/openvswitch/ovsdb-server.log --pidfile=/var/run/openvswitch/ovsdb-server.pid --detach --monitor
    22264 ovs-vswitchd: monitoring pid 22265 (healthy)
    22265 ovs-vswitchd unix:/var/run/openvswitch/db.sock -vconsole:emer -vsyslog:err -vfile:info --mlockall --no-chdir --log-file=/var/log/openvswitch/ovs-vswitchd.log --pidfile=/var/run/openvswitch/ovs-vswitchd.pid --detach --monitor
    root@kvm:~#
     	   
  4. Проверьте загрузку необходимого модуля ядра OVS:

    
    root@kvm:~# lsmod | grep switch
    openvswitch       70989   0
    gre               13796   1 openvswitch
    vxlan             37611   1 openvswitch
    libcrc32c         12644   1 openvswitch
    root@kvm:~#
     	   
  5. Перечислите все доступные коммутаторы OVS:

    
    root@kvm:~# ovs-vsctl show
    e5164e3e-7897-4717-b766-eae1918077b0
     ovs_version: "2.0.2"
    root@kvm:~#
     	   
  6. Создайте некий новый коммутатор OVS:

    
    root@kvm:~# ovs-vsctl add-br virbr1
    root@kvm:~# ovs-vsctl show
    e5164e3e-7897-4717-b766-eae1918077b0
     Bridge "virbr1"
       Port "virbr1"
         Interface "virbr1"
           type: internal
     ovs_version: "2.0.2"
    root@kvm:~#
     	   
  7. Добавьте имеющийся интерфейс исполняемого экземпляра KVM в созданный коммутатор OVS:

    
    root@kvm:~# ovs-vsctl add-port virbr1 vnet0
    root@kvm:~# ovs-vsctl show
    e5164e3e-7897-4717-b766-eae1918077b0
     Bridge "virbr1"
       Port "virbr1"
         Interface "virbr1"
           type: internal
       Port "vnet0"
         Interface "vnet0"
     ovs_version: "2.0.2"
    root@kvm:~#
     	   
  8. Настройте IP адрес самого коммутатора OVS:

    
    root@kvm:~# ip addr add 192.168.122.1/24 dev virbr1
    root@kvm:~# ip addr show virbr1
    41: virbr1: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
     link/ether b2:52:e0:73:89:4e brd ff:ff:ff:ff:ff:ff
     inet 192.168.122.1/24 scope global virbr1
     valid_lft forever preferred_lft forever
     inet6 fe80::b0a8:c2ff:fed4:bb3f/64 scope link
     valid_lft forever preferred_lft forever
    root@kvm:~#
     	   
  9. Настройте некий IP адрес внутри своей гостевой KVM и проверьте связь с ОС её хоста (если ваш образ не имеет настроенного доступа к консоли, подключитесь к нему при помощи VNC:

    
    root@debian:~# ifconfig eth0 up && ip addr add 192.168.122.210/24 dev eth0
    root@debian:~# ip addr show eth0
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
     link/ether 52:54:00:55:9b:d6 brd ff:ff:ff:ff:ff:ff
     inet 192.168.122.210/24 scope global eth0
     valid_lft forever preferred_lft forever
     inet6 fe80::5054:ff:fe55:9bd6/64 scope link
     valid_lft forever preferred_lft forever
    root@debian:~# ping 192.168.122.1
    PING 192.168.122.1 (192.168.122.1) 56(84) bytes of data.
    64 bytes from 192.168.122.1: icmp_seq=1 ttl=64 time=0.711 ms
    64 bytes from 192.168.122.1: icmp_seq=2 ttl=64 time=0.394 ms
    64 bytes from 192.168.122.1: icmp_seq=3 ttl=64 time=0.243 ms
    ^C
    --- 192.168.122.1 ping statistics ---
    3 packets transmitted, 3 received, 0% packet loss, time 2001ms
    rtt min/avg/max/mdev = 0.243/0.449/0.711/0.195 ms
    root@debian:~#
     	   

Как это работает...

Для упрощения нашей установки и во избежание конфликтов будет благоразумно вначале удалить имеющийся мост Linux, прежде чем создавать некий новый OVS. На 1 шаге мы удаляем имеющийся мост и опционально выгружаем его модуль ядра.

На шаге 2 мы устанавливаем пакет OVS, который также запускает основной необходимый демон OVS ovs-vswitchd, который отвечает за создание необходимых мостов/ коммутаторов и их изменение в ОС данного хоста.

На шаге 4 мы проверяем что модуль ядра OVS загружен, а на шаге 5 мы перечисляем все доступные коммутаторы OVS в данном хосте.

На шагах 6 и 7 мы создаём некий новый коммутатор OVS и добавляем имеющийся виртуальный интерфейс KVM в этот коммутатор.

Тот процесс сервера ovsdb, который также был запущен после установки основного пакета, и который мы видели на шаге 3, является неким механизмом базы данных, который применяет RPC (Remote Procedure Calls) JSON для взаимодействия со своим основным демоном OVS. Данный процесс сервера ovsdb запоминает информацию, например, относительно потоков, портов и QoS своего коммутатора, чтобы упоминуть хотя бы некоторую из возможной. Вы можете опрашивать эту базу данных исполняя такую команду:


root@kvm:~# ovsdb-client list-dbs
Open_vSwitch
root@kvm:~# ovsdb-client list-tables
Table
-------------------------
Port
Manager
Bridge
Interface
SSL
IPFIX
Open_vSwitch
Queue
NetFlow
Mirror
QoS
Controller
Flow_Table
sFlow
Flow_Sample_Collector_Set
root@kvm:~# ovsdb-client dump Open_vSwitch
...
Port table
_uuid bond_downdelay bond_fake_iface bond_mode bond_updelay external_ids fake_bridge interfaces lacp mac name other_config qos statistics status tag trunks vlan_mode
------------------------------------ -------------- --------------- --------- ------------ ------------ ----------- -------------------------------------- ---- --- -------- ------------ --- ---------- ------ --- ------ ---------
9b4b743d-66b2-4779-9dd8-404b3aa55e18 0 false [] 0 {} false [e7ed4e2b-a73c-46c7-adeb-a203be56587c] [] [] "virbr1" {} [] {} {} [] [] []
f2a033aa-9072-4be3-808e-6e0fce67ce7b 0 false [] 0 {} false [86a10eed-698f-4ccc-b3b7-dd20c13e3ee3] [] [] "vnet0" {} [] {} {} [] [] []
...
root@kvm:~#
		

Отметим, что в нашем предыдущем выводе теперь отображены эти новые коммутатор virbr1 и порт vnet0 когда мы опрашиваем имеющуюся базу данных OVS.

На шагах 8 и 9 мы назначаем IP адреса созданному коммутатору OVS и имеющейся гостевой KVM и проверяем что мы способны достигать полученный мост хоста изнутри своей виртуальной машины.

Также ознакомьтесь...

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

Для удаления имеющегося виртуального интерфейса KVM из соответствующего коммутатора OVS выполните такую команду:


root@kvm:~# ovs-vsctl del-port virbr1 vnet0
root@kvm:~#
		

Чтобы полностью удалить имеющийся коммутатор OVS исполните такую команду:


root@kvm:~# ovs-vsctl del-br virbr1 && ovs-vsctl show
e5164e3e-7897-4717-b766-eae1918077b0
 ovs_version: "2.0.2"
root@kvm:~#
		
[Замечание]Замечание

Для получения дополнительных сведений относительно OVS посетите, пожалуйста веб сайт проекта.

Настройка переадресации NAT сетевой среды

После своего запуска, libvirt создаёт некую сетевую среду по умолчанию в своём файле настроек /etc/libvirt/qemu/networks/default.xml. При построении какой- то новой KVM без определения каких бы то ни было новых сетевых параметров, она будет использовать такие настройки по умолчанию для взаимодействия с ОС своего хоста и прочими гостями, а также с сетевыми средами. Устанавливаемая по умолчанию сетевая среда libvirt применяет метод NAT (Network Address Translation, трансляции сетевых адресов). NAT предоставляет соответствие одного IP адреса другому, изменяя имеющийся IP адрес в самом заголовке данной IP дейтаграммы пакета. Это в особенности полезно когда наш хост предоставляет один IP адрес, позволяющий множеству гостей в одном и том же хосте применять этот адрес для установления исходящих соединений. Адреса таких виртуальных машин по существу транслируются чтобы проявляться как IP адрес этой машины хоста.

Сетевая среда переадресации по умолчанию определяет и настраивает некий мост Linux для подключения к нему имеющихся гостей. В данном рецепте мы собираемся создать некую новую сеть NAT и подключить к ней свою гостевую KVM.

Приготовление

В данном рецепте нам понадобится следующее:

  • Некий хост Linux с установленным libvirt и его запущенным демоном.

  • Установленные в ОС рассматриваемого хоста пакеты iptables и iproute2. Если вы устанавливали libvirt из некого пакета, имеются шансы что эти iptables и iproute2 уже установлены, как зависимости самого пакета libvirt. Если же вы строили libvirt из исходного кода, вам может потребоваться установить их вручную.

  • Исполняемые экземпляры KVM.

Как это сделать...

Для настройки некоей новой сетевой среды NAT и подключения к ней какого- то экземпляра KVM выполните следующее:

  1. Перечислите все доступные сети:

    
    root@kvm:~# virsh net-list --all
     Name       State    Autostart     Persistent
    ----------------------------------------------------------
     default    active    yes          yes
    
    root@kvm:~#
     	   
  2. Выдайте дамп имеющихся установок вашей сети по умолчанию:

    
    root@kvm:~# virsh net-dumpxml default
    <network connections='1'>
     <name>default</name>
     <uuid>2ab5d22c-5928-4304-920e-bc43b8731bcf</uuid>
     <forward mode='nat'>
       <nat>
         <port start='1024' end='65535'/>
       </nat>
     </forward>
     <bridge name='virbr0' stp='on' delay='0'/>
     <ip address='192.168.122.1' netmask='255.255.255.0'>
       <dhcp>
         <range start='192.168.122.2' end='192.168.122.254'/>
       </dhcp>
     </ip>
    </network>
    
    root@kvm:~#
     	   
  3. Сравните это с файлом определения XML для сети по умолчанию:

    
    root@kvm:~# cat /etc/libvirt/qemu/networks/default.xml
    <network>
     <name>default</name>
     <bridge name="virbr0"/>
     <forward/>
     <ip address="192.168.122.1" netmask="255.255.255.0">
       <dhcp>
         <range start="192.168.122.2" end="192.168.122.254"/>
       </dhcp>
     </ip>
    </network>
    root@kvm:~#
     	   
  4. Перечислите все запущенные в вашем хосте экземпляры:

    
    root@kvm:~# virsh list --all
     Id    Name    State
    ----------------------------------------------------
     3    kvm1     running
    
    root@kvm:~#
     	   
  5. Убедитесь что ваши экземпляры KVM подключены к установленному по умолчанию мосту Linux:

    
    root@kvm:~# brctl show
    bridge name    bridge id           STP enabled    interfaces
    virbr0         8000.fe5400559bd6   yes            vnet0
    root@kvm:~#
     	   
  6. Создайте некое новое определение сети NAT:

    
    root@kvm:~# cat nat_net.xml
    <network>
     <name>nat_net</name>
     <bridge name="virbr1"/>
     <forward/>
     <ip address="10.10.10.1" netmask="255.255.255.0">
       <dhcp>
         <range start="10.10.10.2" end="10.10.10.254"/>
       </dhcp>
     </ip>
    </network>
    root@kvm:~#
     	   
  7. Определите эту новую сетевую среду:

    
    root@kvm:~# virsh net-define nat_net.xml
    Network nat_net defined from nat_net.xml
    
    root@kvm:~# virsh net-list --all
     Name       State      Autostart    Persistent
    ----------------------------------------------------------
     default    active     yes          yes
     nat_net    inactive   no           yes
    
    root@kvm:~#
     	   
  8. Запустите эту новую сетевую среду и установите её автоматический старт:

    
    root@kvm:~# virsh net-start nat_net
    Network nat_net started
    
    root@kvm:~# virsh net-autostart nat_net
    Network nat_net marked as autostarted
    
    root@kvm:~# virsh net-list
     Name      State     Autostart    Persistent
    ----------------------------------------------------------
     default   active    yes          yes
     nat_net   active    yes          yes
    
    root@kvm:~#
     	   
  9. Получите дополнительные сведения относительно этой новой сети:

    
    root@kvm:~# virsh net-info nat_net
    Name: nat_net
    UUID: fba2ca2b-8ca7-4dbb-beee-14799ee04bc3
    Active: yes
    Persistent: yes
    Autostart: yes
    Bridge: virbr1
    
    root@kvm:~#
     	   
  10. Измените соответствующее определение своего экземпляра kvm1 и измените название сетевой среды его источника:

    
    root@kvm:~# virsh edit kvm1
    ...
     <interface type='network'>
       ...
       <source network='nat_net'/>
       ...
     </interface>
    ...
    
    Domain kvm1 XML configuration edited.
    
    root@kvm:~#
     	   
  11. Перезупустите эту гостевую KVM:

    
    root@kvm:~# virsh destroy kvm1
    Domain kvm1 destroyed
    
    root@kvm:~# virsh start kvm1
    Domain kvm1 started
    
    root@kvm:~#
     	   
  12. Перечислите все программно определённые мосты своего хоста:

    
    root@kvm:~# brctl show
    bridge name     bridge id         STP enabled interfaces
    virbr0          8000.000000000000 yes
    virbr1          8000.525400ba8e2c yes         virbr1-nic
                                                  vnet0
    root@kvm:~#
     	   
  13. Подключитесь к своим экземплярам KVM и проверьте установленные IP адреса их нтерфейсов eth0 и убедитесь в наличии подключения к мосту их хоста (если ваш образ не настроен для доступа через консоль, воспользуйтесь вместо него каким- то клиентом VNC):

    
    root@kvm:~# virsh console kvm1
    Connected to domain kvm1
    Escape character is ^]
    
    Debian GNU/Linux 8 debian ttyS0
    
    debian login: root
    Password:
    ...
    root@debian:~# ip a s eth0 | grep inet
     inet 10.10.10.92/24 brd 10.10.10.255 scope global eth0
     inet6 fe80::5054:ff:fe55:9bd6/64 scope link
    root@debian:~# ifconfig eth0 up && dhclient eth0
    root@debian:~# ping 10.10.10.1 -c 3
    PING 10.10.10.1 (10.10.10.1) 56(84) bytes of data.
    64 bytes from 10.10.10.1: icmp_seq=1 ttl=64 time=0.313 ms
    64 bytes from 10.10.10.1: icmp_seq=2 ttl=64 time=0.136 ms
    64 bytes from 10.10.10.1: icmp_seq=3 ttl=64 time=0.253 ms
    
    --- 10.10.10.1 ping statistics ---
    3 packets transmitted, 3 received, 0% packet loss, time 2000ms
    rtt min/avg/max/mdev = 0.136/0.234/0.313/0.073 ms
    root@debian:~#
     	   
  14. В ОС своего хоста опросите какие службы DHCP запущены:

    
    root@kvm:~# pgrep -lfa dnsmasq
    38983 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf
    40098 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/nat_net.conf
    root@kvm:~#
     	   
  15. Проверьте установленный IP для интерфейса своего нового моста:

    
    root@kvm:~# ip a s virbr1
    43: virbr1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
     link/ether 52:54:00:ba:8e:2c brd ff:ff:ff:ff:ff:ff
     inet 10.10.10.1/24 brd 10.10.10.255 scope global virbr1
       valid_lft forever preferred_lft forever
    root@kvm:~#
     	   
  16. Выведите список правил iptables для имеющейся таблицы NAT:

    
    root@kvm:~# iptables -L -n -t nat
    Chain PREROUTING (policy ACCEPT)
    target prot opt source destination
    
    Chain INPUT (policy ACCEPT)
    target prot opt source destination
    
    Chain OUTPUT (policy ACCEPT)
    target prot opt source destination
    
    Chain POSTROUTING (policy ACCEPT)
    target prot opt source destination
    RETURN all -- 10.10.10.0/24 224.0.0.0/24
    RETURN all -- 10.10.10.0/24 255.255.255.255
    MASQUERADE tcp -- 10.10.10.0/24 !10.10.10.0/24 masq ports: 1024-65535
    MASQUERADE udp -- 10.10.10.0/24 !10.10.10.0/24 masq ports: 1024-65535
    MASQUERADE all -- 10.10.10.0/24 !10.10.10.0/24
    RETURN all -- 192.168.122.0/24 224.0.0.0/24
    RETURN all -- 192.168.122.0/24 255.255.255.255
    MASQUERADE tcp -- 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535
    MASQUERADE udp -- 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535
    MASQUERADE all -- 192.168.122.0/24 !192.168.122.0/24
    RETURN all -- 192.168.122.0/24 224.0.0.0/24
    RETURN all -- 192.168.122.0/24 255.255.255.255
    MASQUERADE tcp -- 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535
    MASQUERADE udp -- 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535
    MASQUERADE all -- 192.168.122.0/24 !192.168.122.0/24
    root@kvm:~#
     	   

Как это работает...

Мы начали на шаге 1 с перечисления всех доступных сетевых сред в ОС своего хоста. Как мы можем видеть из получаемого вывода своей команды virsh, имеется запущенной только одна сетевая среда, установленная по умолчанию.

На шаге 2 мы изучаем имеющиеся настройки в этой установленной по умолчанию сетевой среды. Его определение XML использует следующие атрибуты:

  • Атрибут <network> является корневым элементом, указывающим libvirt что мы определяем некую сетевую среду.

  • Элемент <name> определяет само название этой сете вой среды и требует его уникальности.

  • Атрибут <uuid> предоставляет некий глобальный уникальный идентификатор для нашей виртуальной сетевой среды и, если он опущен, он выработается автоматически.

  • Элемент <forward> и его атрибут режима определяют ту сеть, с которой соединяется весь стек сети хоста при помощи NAT. Если этот элемент опущен, libvirt создаст некую изолированную сеть.

  • Субэлемент <nat> далее определяет соответствующий диапазон <port>, который будет применяться когда данный хост выполняет NAT.

  • Элемент <bridge> определяет создаваемый мост, его название и параметры STP.

  • Атрибут <ip> определяет необходимый диапазон IP для существующего сервера DHCP под назначение адресов всем гостевым ВМ.

На шаге 3 мы просматриваем файл настроек для установленной сети по умолчанию относительно перечисленного. Обратите внимание, что некоторые атрибуты пропущены. Libvirt автоматически вырабатывает определённые атрибуты и назначает значения по умолчанию так где это необходимо.

На шагах 4 и 5 мы проверяем что у нас имеется запущенный экземпляр, подключённый к установленному по умолчанию мосту Linux.

На шаге 6 мы создаём некое новое определение сетевой среды при помощи сети по умолчанию в качестве шаблона. Мы изменяем её название и определяем новый диапазон IP.

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

После получения на шаге 9 дополнительной информации относительно вновь созданной сетевой среды мы продолжаем на шаге 10 изменять имеющееся определение XML соответствующей гостевой KVM. Чтобы сделать эту ВМ частью нашей новой сети всё что требуется, это обновить её элемент <source network>.

После перезапуска этой гостевой KVM на шаге 11 мы продолжаем на шаге 12 выводом списка всех доступных программно определяемых мостов в ОС своего хоста. Обратите внимание, что теперь у нас существует два моста, причём новый мост имеет подключёнными к нему виртуальные интерфейсы vnet0 с виртуальных машин.

Затем мы подключаемся к запущенной гостевой KVM и убеждаемся что её сетевой интерфейс eth0 получил некий IP адрес от своего сервера DHCP запущенного в этом хосте и что этот IP является частью того диапазона адресов, который мы настроили ранее. Мы также проверяем соединение при помощи команды ping.

Вернувшись в ОС своего хоста, на шагах 14 и 15 мы проверяем что службы DHCP запущены. Относительно вывода команды pgrep, обратите внимание что теперь у нас имеются два запущенных процесса dnsmasq: по одному для каждой из определённых сетей.

Переадресация NAT достигается установкой правил iptables, который мы можем видеть на шаге 18. Всякий раз когда мы определяем и запускаем некую новую сеть NAT, libvirt создаёт все необходимые правила в iptables. Из полученного на шаге 18 вывода мы можем видеть наличие двух наборов правил NAT, по одному для каждой запущенной сети NAT.

Настройка сетевой среды через мосты

Полностью снарядив себя мостами мы можем подключать свои гостевые KVM напрямую к сетевой среде своего хоста без использования NAT. Однако такая установка требует некоего IP адреса, который является частью подсети самого хоста, причём для каждой виртуальной машины. Если у вас нет возможности выделять настолько много IP адресов, рассмотрите применение сети NAT, как это описано в выданном ранее рецепте Настройка переадресации NAT сетевой среды. При таком режиме построения сетевой среды ваши виртуальнве машины всё ещё используют для связи имеющийся мост ОС своего хоста; однако этот мост поглощает все физические интерфейсы, которые вы намерены применять для своих гостей.

Приготовление

В этом рецепте нам потребуется следующее:

  • Некий сервер с по крайней мере двумя физическими интерфейсами

  • Возможность предоставлять и запускать экземпляры KVM с помощью libvirt

  • Запущенный экземпляр KVM

Как это сделать...

Для определения некоторой новой сетевой среды с мостом и подключения к ней гостей выполните следующие шаги:

  1. Отключите тот интерфейс, который мы намерены использовать для моста:

    
    root@kvm:~# ifdown eth1
    root@kvm:~#
     	   
  2. Измените файл сетевых настроек в своём хосте и замените его блок eth1 следующим, если ваш хост это ОС с Debian/ Ubuntu:

    
    root@kvm:~# vim /etc/network/interfaces
    ...
     auto virbr2
     iface virbr2 inet static
         address 192.168.1.2
         netmask 255.255.255.0
         network 192.168.1.0
         broadcast 192.168.1.255
         gateway 192.168.1.1
         bridge_ports eth1
         bridge_stp on
         bridge_maxwait 0
    ...
    root@kvm:~#
     	   
  3. Если вы применяете дистрибутивы RedHat/CentOS, вместо этого замените следующие два файла:

    
    oot@kvm:~# cat /etc/sysconfig/ifcfg-eth1
    DEVICE=eth1
    NAME=eth1
    NM_CONTROLLED=yes
    ONBOOT=yes
    TYPE=Ethernet
    BRIDGE=virbr2
    root@kvm:~# cat /etc/sysconfig/ifcfg-bridge_net
    DEVICE=virbr2
    NAME=virbr2
    NM_CONTROLLED=yes
    ONBOOT=yes
    TYPE=Bridge
    STP=on
    IPADDR=192.168.1.2
    NETMASK=255.255.255.0
    GATEWAY=192.168.1.1
    root@kvm:~#
     	   
  4. Поднимите свой новый интерфейс:

    
    root@kvm:~# ifup virbr2
    root@kvm:~#
     	   
  5. Отключите отправку пакетов в iptables, которые появляются из ваших гостевых ВМ:

    
    root@kvm:~# sysctl -w net.bridge.bridge-nf-call-iptables=0
    net.bridge.bridge-nf-call-iptables = 0
    root@kvm:~# sysctl -w net.bridge.bridge-nf-call-iptables=0
    net.bridge.bridge-nf-call-iptables = 0
    root@kvm:~# sysctl -w net.bridge.bridge-nf-call-arptables=0
    net.bridge.bridge-nf-call-arptables = 0
    root@kvm:~#
     	   
  6. Перечислите все мосты в своём хосте:

    
    root@kvm:~# # brctl show
     bridge name     bridge id            STP enabled     interfaces
     virbr0          8000.000000000000    yes
     virbr2          8000.000a0ac60210    yes             eth1
    root@kvm:~#
     	   
  7. Измените определение XML для своего экземпляра KVM:

    
    root@kvm:~# virsh edit kvm1
    ...
     <interface type='bridge'>
       <source bridge='virbr2'/>
     </interface>
    ...
    
    Domain kvm1 XML configuration edited.
    
    root@kvm:~#
     	   
  8. Перезапустите этот экземпляр KVM:

    
    root@kvm:~# virsh destroy kvm1
    Domain kvm1 destroyed
    
    root@kvm:~# virsh start kvm1
    Domain kvm1 started
    
    root@kvm:~#
     	   

Как это работает...

Для настройки сетевой среды с мостом на шагах 1 и 2 мы вначале выключаем некий физический интерфейс (в данном примере eth1), чтобы поглотить его (сделать его некоторой частью того нового моста, который мы намерены создать). Затем мы создаём некую сетевую конфигурацию, определяем новый необходимый мост и тот физический интерфейс, который мы намерены сделать частью этого моста. Это на самом деле устанавливает соответствие той подсети что мы настраиваем в данном физическом интерфейсе данному мосту. Если ваш сервер имеет только один сетевой интерфейс, вы всё ещё можете поглотить его. Однако вам потребуется некий дополнительный способ подключения к этому серверу, так как после того как вы отключите свой основной интерфейс, вы потеряете связь и устранение неисправностей может стать невозможным через какое- то подключение SSH.

После того как этот новый мост настроен, мы запускаем его на шаге 3.

На шаге 4 мы указываем своему ядру не применять правила iptable ни к какому обмену, появляющемуся у наших виртуальных гостей подключаемых к этому мосту Linux, поскольку мы не применяем никаких правил NAT.

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

На шаге 6 мы изменяем имеющееся определение XML своего экземпляра kvm1, в котором мы задаём необходимый тип сетевой среды который мы желаем применять; для данного рецепта это сеть с мостом (bridge). Если вы вспомните рецепт Настройка переадресации NAT сетевой среды, мы использовали тип сети (network) вместо сети с мостом и мы определяли некое название сети libvirt вместо самого названия моста.

Наконец, после перезапуска своего экземпляра KVM на шаге 7, наша гостевая ОС должна теперь иметь возможность достигать прочие экземпляры, которые являются частью той же самой подсети без использования NAT.

Настройка проброса PCI сетевой среды

Обсуждаемый нами гипервизор KVM поддерживает прямое подключение устройств PCI из ОС своего хоста в его виртуальные машины. Мы можем применять эту функциональность для подключения сетевого интерфейса напрямую в имеющуюся гостевую ОС без необходимости применения NAT или программно определяемого моста.

В данном рецепте мы намерены подключить некую NIC (Network Interface Card), которая поддерживает SR-IOV (Single Root I/O Virtualization, виртуализацию ввода/ вывода с единым корнем) из своего хоста в соответствующего гостя KVM. SR-IOV представляет собой спецификацию, которая позволяет устройству PCIe (Peripheral Component Interconnect Express) выступать в виде множества физических устройств {Прим. пер.: виртуальных функций}, которые могут совместно применяться многими виртуальными машинами в одном и том же хосте, выполняя проброс на уровне самого супервизора, тем самым достигая естественной сетевой скорости. Поставщики облачных решений, такие как Amazon AWS выставляют эту функциональность для своих вычислительных экземпляров EC2 через вызовы API.

Приготовление

Для полного исполнения данного рецепта нам потребуется следующее:

  • Некий физический хост с NIC, которая поддерживает SR-IOV

  • Коммутатор с возможностями 802.1Qbh, подключаемый к этому физическому серверу

  • ЦПУ с расширениями либо Intel VT-d, либо AMD IOMMU

  • Хост Linux с установленным libvirt готовый к предоставлению экземпляров KVM

Как это сделать...

Для настройки сетевой среды со сквозным PCIe проделайте следующие шаги:

  1. Выведите список всех устройств ОС своего хоста:

    
    root@kvm:~# virsh nodedev-list --tree
    computer
     |
     +- net_lo_00_00_00_00_00_00
     +- net_ovs_system_0a_c6_62_34_19_b4
     +- net_virbr1_nic_52_54_00_ba_8e_2c
     +- net_vnet0_fe_54_00_55_9b_d6
     ...
     |
     +- pci_0000_00_03_0
     | |
     | +- pci_0000_03_00_0
     | | |
     | | +- net_eth0_58_20_b1_00_b8_61
     | |
     | +- pci_0000_03_00_1
     | |
     | +- net_eth1_58_20_b1_00_b8_61
     |
     ...
     root@kvm:~#
     	   
  2. Перечислите все адаптеры PCI Ethernet:

    
    root@kvm:~# lspci | grep Ethernet
    03:00.0 Ethernet controller: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection (rev 01)
    03:00.1 Ethernet controller: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection (rev 01)
    root@kvm:~#
     	   
  3. Получите дополнительные сведения относительно той NIC, которую использует устройство eth1:

    
    root@kvm:~# virsh nodedev-dumpxml pci_0000_03_00_1
    <device>
     <name>pci_0000_03_00_1</name>
     <path>/sys/devices/pci0000:00/0000:00:03.0/0000:03:00.1</path>
     <parent>pci_0000_00_03_0</parent>
     <driver>
       <name>ixgbe</name>
     </driver>
     <capability type='pci'>
       <domain>0</domain>
       <bus>3</bus>
       <slot>0</slot>
       <function>1</function>
       <product id='0x10fb'>82599ES 10-Gigabit SFI/SFP+ Network Connection</product>
       <vendor id='0x8086'>Intel Corporation</vendor>
     </capability>
    </device>
    
    root@kvm:~#
     	   
  4. Преобразуйте домен, шину, слот и значения функций в шестнадцатеричные числа:

    
    root@kvm:~# printf %x 0
    0
    root@kvm:~# printf %x 3
    3
    root@kvm:~# printf %x 0
    0
    root@kvm:~# printf %x 1
    1
    root@kvm:~#
     	   
  5. Создайте некий новый файл определения сетевой среды libvirt:

    
    root@kvm:~# cat passthrough_net.xml
    <network>
     <name>passthrough_net</name>
     <forward mode='hostdev' managed='yes'>
       <pf dev='eth1'/>
     </forward>
    </network>
    root@kvm:~#
     	   
  6. Определите, запустите и включите автоматический старт своей новой сетевой среды libvirt:

    
    root@kvm:~# virsh net-define passthrough_net.xml
    Network passthrough_net defined from passthrough_net.xml
    
    root@kvm:~# virsh net-start passthrough_net
    Network passthrough_nett started
    
    root@kvm:~# virsh net-autostart passthrough_net
    Network passthrough_net marked as autostarted
    
    root@kvm:~# virsh net-list
     Name               State      Autostart    Persistent
    ----------------------------------------------------------
     default            active    yes           yes
     passthrough_net    active    yes           yes
    
    root@kvm:~#
     	   
  7. Измените XML определение своей гостевой KVM:

    
    root@kvm:~# virsh edit kvm1
    ...
     <devices>
     ...
     <interface type='hostdev' managed='yes'>
       <source>
         <address type='pci' domain='0x0' bus='0x00' slot='0x07' function='0x0'/>
       </source>
       <virtualport type='802.1Qbh' />
     </interface>
     <interface type='network'>
       <source network='passthrough_net'>
     </interface>
     ...
     </devices>
    ...
    
    Domain kvm1 XML configuration edited.
    
    root@kvm:~#
     	   
  8. Перезапустите этот экземпляр KVM:

    
    root@kvm:~# virsh destroy kvm1
    Domain kvm1 destroyed
    
    root@kvm:~# virsh start kvm1
    Domain kvm1 started
    
    root@kvm:~#
     	   
  9. Выведите перечень VF (Virtual Functions), предоставляемых NIC SR-IOV:

    
    root@kvm:~# virsh net-dumpxml passthrough_net
    <network connections='1'>
       <name>passthrough_net</name>
       <uuid>a4233231-d353-a112-3422-3451ac78623a</uuid>
       <forward mode='hostdev' managed='yes'>
         <pf dev='eth1'/>
         <address type='pci' domain='0x0000' bus='0x02' slot='0x10' function='0x1'/>
         <address type='pci' domain='0x0000' bus='0x02' slot='0x10' function='0x3'/>
         <address type='pci' domain='0x0000' bus='0x02' slot='0x10' function='0x5'/>
         <address type='pci' domain='0x0000' bus='0x02' slot='0x10' function='0x7'/>
         <address type='pci' domain='0x0000' bus='0x02' slot='0x11' function='0x1'/>
         <address type='pci' domain='0x0000' bus='0x02' slot='0x11' function='0x3'/>
         <address type='pci' domain='0x0000' bus='0x02' slot='0x11' function='0x5'/>
       </forward>
    </network>
    root@kvm:~#
     	   

Как это работает...

Чтобы напрямую подключать NIC PCIe от ОС своего хоста в его гостевые ВМ нам вначале необходимо получить некую информацию об аппаратных средствах этого устройства, такую как домен, шина, слот и идентификаторы функций. На шаге 1 мы собираем информацию обо всех доступных устройствах в сервере своего хоста. Нас интересуют сетевой интерфейс, применяемый для eth1; более того мы выписываем из полученного вывода уникальную идентификацию PCI - в данном случае pci_0000_03_00_1.

Чтобы убедится что это на самом деле NIC, который мы бы хотели выставить своему гостю, мы перечисляем все устройства PCI на шаге 2. Из этого вывода мы можем обнаружить, что идентификатор его PCI тот же самый, 03:00.1.

Применяя PCI ID с шага 1 на шаге 3 мы продолжим собирать дополнительную информацию относительно NIC. Обратите внимание, что 0000_03_00_1 ID разбивается далее на идентификатор домена, идентификатор шины, идентификатор слота и идентификатор функции, как это показано в соответствующих атрибутах XML. Мы намерены воспользоваться ими на шаге 7; однако вначале нам необходимо преобразовать их в шестнадцатеричные числа, что мы и делаем на шаге 4.

На шагах 5 и 6 мы определяем некую новую сетевую среду libvirt для своих гостей и включаем автоматический сатр в случае перезапуска сервера своего хоста. Если вы выполняли прочие рецепты из этой главы, вы уже должны быть знакомы с большинством атрибутов в таком файле XML определений для той сети, которую мы только что создали. Режим hostdev определённый в атрибуте <forward> является именно тем, что инструктирует libvirt что наша новая сетевая среда намерена применять проброс PCI. Соответствующий параметр managed=yes, как это определено в нашем атрибуте <forward> сообщает libvirt вначале отключить это устройство PCI от хоста перед передачей его соответствующему гостю и повторно подключать его в этот хост после останова такого гостя. Наконец, субэлемент <pf> определяет тот физический интерфейс, который будет виртуализован и представлен соответствующему гостю.

[Замечание]Замечание

Для получения дополнительных сведений относительно доступных атрибутов XML, обращайтесь, пожалуйста, к http://libvirt.org/formatdomain.html.

На щаге 7 мы изменяем определение XML своего экземпляра KVM, определяя тот ID PCI, который мы получили на шаге 3 и определяем некий интерфейс, который будет применять новую сквозную сетевую среду PCIe, которую мы создали на шагах 5 и 6.

На шаге 8 мы перезапускаем свой экземпляр KVM и наконец проверяем что наше физическое устройство PCI NIC теперь является частью новой сквозной сетевой среды, определённой нами ранее. Обратите внимание на наличие множества устройств с типом PCI. Это происходит потому, что данное проброшенное устройство PCIe, которое мы будем применять, поддерживает SR-IOV. Все гостевые KVM, которые будут пользоваться этой сетевой средой теперь будут способны напрямую применять NIC своего хоста назначая одно из перечисленных виртуальных устройств PCie.

Манипулирование сетевыми интерфейсами

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

В данном рецепте мы намерены определить некий новый мост Linux, создать его и наконец удалить его с помощью virsh. Если вы вспомните наши более ранние рецепты, мы можем манипулировать имеющимся мостом Linux через такие утилиты как brctl. Для libvirt, однако, у нас имеется некий способ контроля этого программным путём через написание соответствующего файла определения и использование соответствующих компоновок API, которые мы рассмотрим в Главе 7, Применение Python для построения экземпляров KVM и управления ими.

Приготовление

Для данного рецепта нам потребуются:

  • Установленный в нашем хосте пакет libvirt

  • Некий хост Linux с установленным модулем ядра для моста

Как это сделать...

Для создания нового интерфейса моста при помощи libvirt выполните такие команды:

  1. Создайте некий новый файл настройки интерфейса моста:

    
    root@kvm:~# cat test_bridge.xml
    <interface type='bridge' name='test_bridge'>
     <start mode="onboot"/>
       <protocol family='ipv4'>
     <ip address='192.168.1.100' prefix='24'/>
     </protocol>
     <bridge>
       <interface type='ethernet' name='vnet0'>
         <mac address='fe:54:00:55:9b:d6'/>
       </interface>
     </bridge>
    </interface>
    root@kvm:~#
     	   
  2. Перечислите все известные libvirt интерфейсы:

    
    root@kvm:~# virsh iface-list --all
     Name            State       MAC Address
    ---------------------------------------------------
     bond0           active      58:20:b1:00:b8:61
     bond0.129       active      bc:76:4e:20:10:6b
     bond0.229       active      bc:76:4e:20:17:7e
     eth0            active      58:20:b1:00:b8:61
     eth1            active      58:20:b1:00:b8:61
     lo              active      00:00:00:00:00:00
     test_bridge     inactive
    
    root@kvm:~#
     	   
  3. Запустите полученный новый интерфейс моста:

    
    root@kvm:~# virsh iface-start test_bridge
    Interface test_bridge started
    
    root@kvm:~# virsh iface-list --all | grep test_bridge
     test_bridge    active    4a:1e:48:e1:e7:de
    root@kvm:~#
     	   
  4. Перечислите все устройства моста в этом хосте:

    
    root@kvm:~# brctl show
    bridge name       bridge id           STP enabled   interfaces
    test_bridge       8000.000000000000   no
    virbr0            8000.000000000000   yes
    virbr1            8000.525400ba8e2c   yes           virbr1-nic
                                                        vnet0
    root@kvm:~#
     	   
  5. Проверьте все активные сетевые настройки своего нового моста:

    
    root@kvm:~# ip a s test_bridge
    46: test_bridge: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
     link/ether 4a:1e:48:e1:e7:de brd ff:ff:ff:ff:ff:ff
     inet 192.168.1.100/24 brd 192.168.1.255 scope global test_bridge
     valid_lft forever preferred_lft forever
     inet6 fe80::481e:48ff:fee1:e7de/64 scope link
     valid_lft forever preferred_lft forever
    root@kvm:~#
     	   
  6. Определите этот новый интерфейс:

    
    root@kvm:~# virsh iface-define test_bridge.xml
    Interface test_bridge defined from test_bridge.xml
    
    root@kvm:~#
     	   
  7. Получите значение MAC адреса моста:

    
    root@kvm:~# virsh iface-mac test_bridge
    4a:1e:48:e1:e7:de
    
    root@kvm:~#
     	   
  8. Получите название созданного моста предоставив его MAC адрес:

    
    root@kvm:~# virsh iface-name 4a:1e:48:e1:e7:de
    test_bridge
    
    root@kvm:~#
     	   
  9. Удалите созданный интерфейс следующим образом:

    
    root@kvm:~# virsh iface-destroy test_bridge
    Interface test_bridge destroyed
    
    root@kvm:~# virsh iface-list --all | grep test_bridge
     test_bridge inactive
    root@kvm:~# virsh iface-undefine test_bridge
    Interface test_bridge undefined
    
    root@kvm:~# virsh iface-list --all | grep test_bridge
    root@kvm:~#
     	   

Как это работает...

На шаге 1 мы записываем необходимое определение XML для своего нового сетевого интерфейса. Мы определяем мост по значению типа, некого IP адреса для его интерфейса и необязательного какого- то MAC адреса.

На шагах 2 и 3 мы определяем этот новый мост и выводим его в списке. Определение такого интерфейса не делает автоматически его активным, поэтому на шаге 4 мы активируем его.

Как показано на шаге 5, активация этого моста создаёт его реальный интерфейс в этом хосте.

На шаге 6 мы убеждаемся что назначенные адреса IP и MAC действительно те, которые мы определили на шаге 1.

На шагах 7 и 8 мы получаем и название и MAC адрес при помощи утилиты virsh, а, наконец, на шаге 9 мы удаляем созданный интерфейс bridge.