GVT-G – это технология, позволяющая виртуализировать встроенную в процессоры Intel Core видеокарту. Можно создать несколько таких виртуальных видеокарт и раздать виртуальным машинам. Каждая виртуальная машина будет иметь доступ к настоящему аппаратному 3d-ускорителю. Пока работает только под KVM и XEN. Есть возможность выводить картинку с этой виртуальной видеокарты на реальную. Но у нас же сервер. Нам не для игр. Поэтому ограничимся доступом по Remote Desktop.
1. Берем комп с процессором Intel Core поколения 5 или новее. В BIOS выставляем максимально возможный размер видеопамяти.
2. Ставим ubuntu 18.04. Мой любимый debian не подойдет, поскольку у него в ядре выключен CONFIG_DRM_I915_GVT_KVMGT. Можно пересобрать ядро самостоятельно, но нам же надо быстро.
3. Обновляем
# apt update # apt dist-upgrade -y
4. Ставим libvirt
# apt install libvirt-daemon-system
5. Добавляем в /etc/default/grub:
GRUB_CMDLINE_LINUX="i915.enable_gvt=1 kvm.ignore_msrs=1 intel_iommu=on i915.enable_guc=0"
Не забываем обновить конфиг:
# update-grub
Перезагружаемся и после перезагрузки убеждаемся, что у нас получилось:
# ls /sys/bus/pci/devices/0000:00:02.0/mdev_supported_types/ i915-GVTg_V5_2 i915-GVTg_V5_4 i915-GVTg_V5_8
В каждом из этих каталогов есть файл available_instances, в котором указано, сколько виртуальных видеокарт можно создать одновременно. В файле description написано, какие параметры будут у этих видеокарт.
6. Придумываем UUID и создаем виртуальную видеокарту.
# echo "df7aee77-abed-4c3c-b6b0-3e38db57f13d" > "/sys/bus/pci/devices/0000:00:02.0/mdev_supported_types/i915-GVTg_V5_4/create"
Эту процедуру придется повторять руками после каждой загрузки или прибить гвоздями куда-нибудь в /etc/rc.local.
7. Создаем виртуалку примерно такого вида:
<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
<name>win1</name>
<uuid>d68571d2-3dd1-4aa2-a780-36160afff657</uuid>
<memory unit='KiB'>3145728</memory>
<currentMemory unit='KiB'>3145728</currentMemory>
<vcpu placement='static'>2</vcpu>
<os>
<type arch='x86_64' machine='pc-q35-2.11'>hvm</type>
<bootmenu enable='yes' timeout='3000'/>
</os>
<features>
<acpi/>
<apic/>
<hyperv>
<relaxed state='on'/>
<vapic state='on'/>
<spinlocks state='on' retries='8191'/>
<vpindex state='on'/>
<synic state='on'/>
<stimer state='on'/>
</hyperv>
<vmport state='off'/>
<ioapic driver='kvm'/>
</features>
<cpu mode='host-passthrough' check='partial'>
<topology sockets='1' cores='2' threads='1'/>
<cache mode='passthrough'/>
</cpu>
<clock offset='localtime'>
<timer name='rtc' tickpolicy='catchup'/>
<timer name='pit' tickpolicy='delay'/>
<timer name='hpet' present='no'/>
<timer name='hypervclock' present='yes'/>
</clock>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<emulator>/usr/bin/kvm</emulator>
<disk type='block' device='disk'>
<driver name='qemu' type='raw' discard='unmap'/>
<source dev='/virt/raw/win1/raw'/>
<target dev='sda' bus='scsi'/>
<boot order='1'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<source file='/virt/iso/win10-64.iso'/>
<target dev='sdb' bus='sata'/>
<readonly/>
<address type='drive' controller='0' bus='0' target='0' unit='1'/>
</disk>
<controller type='scsi' index='0' model='lsisas1068'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</controller>
<controller type='usb' index='0' model='qemu-xhci'>
<address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
</controller>
<controller type='sata' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/>
</controller>
<controller type='pci' index='0' model='pcie-root'/>
<controller type='pci' index='1' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='1' port='0x8'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/>
</controller>
<controller type='pci' index='2' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='2' port='0x9'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<interface type='bridge'>
<mac address='54:52:00:e7:2f:2a'/>
<source bridge='br-int'/>
<model type='e1000'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<serial type='pty'>
<target type='isa-serial' port='0'>
<model name='isa-serial'/>
</target>
</serial>
<console type='pty'>
<target type='serial' port='0'/>
</console>
<input type='tablet' bus='usb'>
<address type='usb' bus='0' port='1'/>
</input>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='vnc' port='-1' autoport='yes'>
<listen type='address'/>
</graphics>
<memballoon model='none'/>
</devices>
</domain>
Ключевое тут – чипсет pc-q35-2.11.
8. Запускаем виртуалку, подключаемся по VNC и ставим Windows 10. Настраиваем сеть, разрешаем Remote Desktop. Подключаемся по Remote Desktop, скачиваем драйвера для видеокарты. Выключаем виртуалку.
9. Добавляем новое устройство vfio-pci c uuid нашей виртуальной видеокарты.
...
</graphics>
<hostdev mode='subsystem' type='mdev' managed='no' model='vfio-pci'>
<source>
<address uuid='df7aee77-abed-4c3c-b6b0-3e38db57f13d'/>
</source>
<address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>
</hostdev>
<memballoon model='none'/>
...
10. Загружаем виртуалку, подключаемся по Remote Desktop и устанавливаем драйвер для видеокарты. На этом пункте уже можно остановиться, 3D на виртуальной машине уже есть. Но…
11. …поскольку примерно с п.9 подключаться по VNC бессмысленно (всегда будет только черный экран), можно убрать из xml вот этот блок:
<graphics type='vnc' port='-1' autoport='yes'>
<listen type='address'/>
</graphics>
и добавить дополнительный аргумент в командную строку qemu:
...
</devices>
<qemu:commandline>
<qemu:arg value='-nographic'/>
</qemu:commandline>
</domain>
Вот теперь точно всё.