Содержание

Настройка хоста OpenNebula с PCI Passtrough GPU на Ubuntu 22.04 LTS Server

Для того чтобы вкоючить поддержку PCI Passtrough есть специальная страничка от разработчиков OpenNebula, но там почему-то этот вопрос рассматривается несколько поверхностно. В данной статье будет реально рабочий вариант настройки KVM-хоста с комментариями и пояснениями.

1 Начальная настройка подчиненного хоста

1.1 Добавление репозитория OpenNebula

Т.к. начиная с Ubuntu 22.04 (а может и раньше) APT начал предупреждать что, добавление GPG-ключей в общее хранилище это не правильно и в скором времени данный метод хранения будет исключен, то ниже представленн более правильный, на мой взгляд, метод добавления репозитория OpenNebula:

1
2
3
wget https://downloads.opennebula.io/repo/repo2.key -O /etc/apt/trusted.gpg.d/opennebula.asc
echo "deb https://downloads.opennebula.io/repo/6.6/Ubuntu/22.04/ stable opennebula" > /etc/apt/sources.list.d/opennebula.list
apt-get update

1.2 Установка OpenNebula KVM node

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

1
2
apt-get -y install opennebula-node-kvm
systemctl restart libvirtd

Чтобы не возникало вопросов с доступом к хранилищам, так же необходимо добавить правило для AppArmor:

1
echo "/var/lib/one/datastores/** rwk," >> /etc/apparmor.d/abstractions/libvirt-qemu

1.3 Настройка сетевых параметров

Данный пример подразумевает, что используется самый простой способ - работа сети виртуальных машин через мост.

Сначала необходимо создать сам bridge-интерфейс, для этого файл /etc/netplan/00-installer-config.yaml нужно привести примерно к следующему ниже виду, где настройки IP самого хоста нужно изменить в соответствии с вашей локальной сетью, а так же может отличаться имя сетевого адаптера:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
ethernets:
    enp2s0:
    dhcp4: no
    dhcp6: no
bridges:
    br0:
    dhcp4: no
    dhcp6: no
    addresses:
    - 192.168.0.100/24
    gateway4: 192.168.0.1
    nameservers:
        addresses:
        - 192.168.0.1
        search:
        - mynetwork.ru
    interfaces:
    - enp2s0
version: 2

После чего можно попробовать применить новые настройки с помощью netplan try или, если вы точно уверены что все настройки верны, то можно сразу netplan apply

Далее необходимо удалить стандартную сеть KVM:

1
2
virsh net-destroy default
virsh net-undefine default

И создать новую для работы через bridge-интерфейс. Для этого необходимо создать файл host-bridge.xml следующего содержания:

1
2
3
4
5
<network>
  <name>host-bridge</name>
  <forward mode="bridge"/>
  <bridge name="br0"/>
</network>

После чего определить новую сеть, запустить ее и сделать чтобы она также автоматически запускалась при загрузке хоста:

1
2
3
virsh net-define host-bridge.xml
virsh net-start host-bridge
virsh net-autostart host-bridge

Чтобы управляющая нода могла взаимодействовать с новым хостом, нужно добавить её публичный коюч SSH на подчиненную ноду. Производитель рекомендует делать это так:

1
2
3
sudo -u oneadmin bash
ssh-copy-id [пользователь]@[адрес_ноды]
scp -p /var/lib/one/.ssh/known_hosts [адрес_ноды]:/var/lib/one/.ssh/

2 Настройка PCI Passtrough

Для того чтобы включить поддержки IOMMU необходимо добавить опции ядра в файле /etc/default/grub:

Для Intel:

1
GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=on iommu=pt pcie_acs_override=downstream kvm.ignore_msrs=1"

Для AMD:

1
GRUB_CMDLINE_LINUX_DEFAULT="amd_iommu=on iommu=pt pcie_acs_override=downstream kvm.ignore_msrs=1"

Затем, включить загрузку соответствующих модулей в файле /etc/modules:

1
2
3
4
5
# PCI Passtrough
vfio
vfio_iommu_type1
vfio_pci
vfio_virqfd

И выпонить следующую комманду:

1
echo "options vfio_iommu_type1 allow_unsafe_interrupts=1" > /etc/modprobe.d/iommu_unsafe_interrupts.conf

Теперь нужно сделать так чтобы для GPU, который мы будем пробрасывать не загружался системный драйвер. Наже приведен пример файла /etc/modprobe.d/blacklist.conf, содержимое которого конечно избыточно, но за то на все случаи жизни:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
blacklist amdgpu
blacklist radeon
blacklist nvidia
blacklist nvidiafb
blacklist snd_hda_intel
blacklist nouveau
blacklist lbm-nouveau
options nouveau modeset=0
alias nouveau off
alias lbm-nouveau off

После этого обновляем initramfs, выполнив:

1
update-initramfs -u

После чего нужно перезагрузить систему и убедиться, что все получилось

Теперь, при выполнении комманды lspci -nnk, мы должны увидеть, что к видеокарте не привязано никакого драйвера.

Чтобы убедиться, что IOMMU работает, можно выполнить комманду:

1
dmesg | grep -e DMAR -e IOMMU

Так же признаком работы IOMMU будет наличие групп для устройств. Проверить это можно выполнив комманду find /sys/kernel/iommu_groups/ -type l. После чего мы увидим нечто подобное:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
/sys/kernel/iommu_groups/7/devices/0000:00:1d.0
/sys/kernel/iommu_groups/5/devices/0000:00:17.0
/sys/kernel/iommu_groups/3/devices/0000:00:14.2
/sys/kernel/iommu_groups/3/devices/0000:00:14.0
/sys/kernel/iommu_groups/1/devices/0000:00:01.0
/sys/kernel/iommu_groups/1/devices/0000:01:00.0
/sys/kernel/iommu_groups/1/devices/0000:01:00.1
/sys/kernel/iommu_groups/8/devices/0000:00:1f.0
/sys/kernel/iommu_groups/8/devices/0000:00:1f.5
/sys/kernel/iommu_groups/8/devices/0000:00:1f.3
/sys/kernel/iommu_groups/8/devices/0000:00:1f.4
/sys/kernel/iommu_groups/6/devices/0000:00:1c.0
/sys/kernel/iommu_groups/4/devices/0000:00:16.0
/sys/kernel/iommu_groups/2/devices/0000:00:02.0
/sys/kernel/iommu_groups/0/devices/0000:00:00.0
/sys/kernel/iommu_groups/9/devices/0000:03:00.0

Для устройств работающих через IOMMU нужно создать файл настроек, например /etc/modprobe.d/local.conf, в котором будет примерно следующее содеримое (в данном случае это GeForce GTX 1050 Ti):

1
options vfio-pci ids=10de:1c82

Если устройств несколько, то они перечисляются через запятую:

1
options vfio-pci ids=10de:1c82,10de:0fb9

Далее мы создадим скрипт, который будет запускаться как сервис systemd, чтобы осуществить привязку драйвера vfio-pci к интересующим нас устройствам и смену владельца этих устройств на oneadmin:oneadmin, т.к. именно от имени этого пользователя запускаются вируальные машины KVM и если этого не сделать, то мы получим ошибку “Permission denied” при запуске ВМ.

Сначала создадим файл настроек /etc/default/vfio-bind содержащий перечень устройств разделенных пробелом, которые нужно привязать:

1
DEVICES="0000:01:00.0 0000:01:00.1"
Совет
Обратите внимание на формат идентификаторов устройств. Чтобы увидеть его в таком виде лучше использовать комманду lspci -D

Теперь создадим сам скрипт /usr/local/bin/vfio-bind:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#!/bin/bash
modprobe vfio-pci
IFS=' '
read -ra DEV <<< "$@"
for dev in "${DEV[@]}"; do
        vendor=$(cat /sys/bus/pci/devices/$dev/vendor)
        device=$(cat /sys/bus/pci/devices/$dev/device)
        if [ -e /sys/bus/pci/devices/\$dev/driver ]; then
                echo $dev > /sys/bus/pci/devices/$dev/driver/unbind
        fi
        echo $vendor $device > /sys/bus/pci/drivers/vfio-pci/new_id
done
find /dev/vfio -regex ".*/[0-9]*" -type c -exec chown oneadmin:oneadmin {} \;

И создадим сервис /etc/systemd/system/vfio-bind.service:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[Unit]
Description=Binds devices to vfio-pci
After=syslog.target

[Service]
EnvironmentFile=-/etc/default/vfio-bind
Type=oneshot
RemainAfterExit=yes
ExecStart=-/usr/local/bin/vfio-bind $DEVICES

[Install]
WantedBy=multi-user.target

После чего его нужно включить и запустить:

1
2
systemctl enable vfio-bind.service
systemctl start vfio-bind.service

Чтобы убедиться, что скрипт работает, посмотрим резултат вывода комманды ls -l /dev/vfio/. Результат должен быть примерно такой:

1
2
crw------- 1 oneadmin oneadmin 241,   0 Mar 17 12:57 1
crw-rw-rw- 1 root     root      10, 196 Mar 17 12:57 vfio

И вывод комманды lspci -nnk (для GPU GeFroce GTX 1050Ti):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
...
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP107 [GeForce GTX 1050 Ti] [10de:1c82] (rev a1)
	Subsystem: Gigabyte Technology Co., Ltd GP107 [GeForce GTX 1050 Ti] [1458:3764]
	Kernel driver in use: vfio-pci
	Kernel modules: nvidiafb, nouveau
01:00.1 Audio device [0403]: NVIDIA Corporation GP107GL High Definition Audio Controller [10de:0fb9] (rev a1)
	Subsystem: Gigabyte Technology Co., Ltd GP107GL High Definition Audio Controller [1458:3764]
	Kernel driver in use: vfio-pci
	Kernel modules: snd_hda_intel
...

По умолчанию функция “PCI passtrough” отключена в OpenNebula. Чтобы ее включить нужно модифицировать файл /var/lib/one/remotes/etc/im/kvm-probes.d/pci.conf (для KVM) на управляющей ноде OpenNebula. В нем содержатся комментарии, из которых понятно что именно нужно изменить, но я все таки приведу пример как это сделано у меня для всех GPU NVidia:

1
2
3
4
5
:filter: '10de:*'
:short_address: []
:device_name: []
:nvidia_vendors:
  - '10de'

Чтобы проверить что всё работает в самой OpenNebula, нужно обновить конфигурацию шаблона ВМ, перейдя в раздел “Input/Output” и добавив нужное устройство. После создания ВМ из этого шаблона, в случае успеха, там дожно появиться наше устройство. В примере данной статьи это должна быть GPU NVidia GTX 1050 Ti. Остается только установить небходимые драйверы устройств внутри виртуальной машины и можно считать процесс настройки завершенным.