从内核4.10, 支持 virtual gpu 的代码开始汇入主线程。这部分代码主要由两部分组成:

首先, mediated 设备框架(mdev),基本上,这部分代码使得内核驱动开始用vfio框架跟接口来支持虚拟pci设备。nvidia 以及intel都采用了这种所谓的mdev机制,将宿主机中的物理GPU分割成多个虚拟设备,以便供多个虚拟机同时使用。

第二个, intel 的i915驱动也是采用了mdev初始化支持,当然仍然有很多工作需要去做,例如不能直接登录虚拟机的显示画面,所以必须通过客户机中安装x11vnc或者类似的vnc工具,也有一些稳定性的问题需要解决。

如果你还是想尝尝鲜的话,下面是详细的步骤,当然不要在生产环境中测试,也做做好系统崩溃的准备, :-)

 

宿主机:生成虚拟设备

确保你的系统内核要大于4.10, 如何是intel的集成显卡的话,确定要至少是broadwell或者更新。在内核配置文件中打开vfio跟mdev(所有的CONFIG_VFIO_*选项), 如果是intel设备,再打开 CONFIG_DRM_I915_GVT 和 CONFIG_DRM_I915_GVT_KVMGT 。如果你想加入一些测试功能的话,也可以打开CONFIG_SAMPLE_VFIO_MDEV_MTTY,生成一些mtty的测试驱动。

 

启动新编译的内核,加载所有的模块:vfio-pci,vfio-mdev, 可选的mtty。 当然你也不能忘了i915以及kvmgt,不过他们可能已经在启动过程中默认加载了。

进入目录  /sys/class/mdev_bus directory

kraxel@broadwell ~# cd /sys/class/mdev_bus
kraxel@broadwell .../class/mdev_bus# ls -l
total 0
lrwxrwxrwx. 1 root root 0 17. Jan 10:51 0000:00:02.0 -> ../../devices/pci0000:00/0000:00:02.0
lrwxrwxrwx. 1 root root 0 17. Jan 11:57 mtty -> ../../devices/virtual/mtty/mtty

你会看到每一个被mdev支持的驱动都在那有一个目录。 下一步进入 $device/mdev_supported_types, 检查以下你可以生成什么样的虚拟GPU设备

kraxel@broadwell .../class/mdev_bus# cd 0000:00:02.0/mdev_supported_types
kraxel@broadwell .../0000:00:02.0/mdev_supported_types# ls -l
total 0
drwxr-xr-x. 3 root root 0 17. Jan 11:59 i915-GVTg_V4_1
drwxr-xr-x. 3 root root 0 17. Jan 11:57 i915-GVTg_V4_2
drwxr-xr-x. 3 root root 0 17. Jan 11:59 i915-GVTg_V4_4

你可以发现,intel可以支持三种不同的设备类型,三种设备有不同的显存大小,以及可以被生成的数量。让我们继续看一下description 和 available_instance

kraxel@broadwell .../0000:00:02.0/mdev_supported_types# cd i915-GVTg_V4_2
kraxel@broadwell .../mdev_supported_types/i915-GVTg_V4_2# cat description 
low_gm_size: 64MB
high_gm_size: 192MB
fence: 4
kraxel@broadwell .../mdev_supported_types/i915-GVTg_V4_2# cat available_instance 
2

现在你可以通过在“write”文件中写入UUID来生成相应的虚拟设备:

kraxel@broadwell .../mdev_supported_types/i915-GVTg_V4_2# uuid=$(uuidgen)
kraxel@broadwell .../mdev_supported_types/i915-GVTg_V4_2# echo $uuid
f321853c-c584-4a6b-b99a-3eee22a3919c
kraxel@broadwell .../mdev_supported_types/i915-GVTg_V4_2# sudo sh -c "echo $uuid > create"

新生成的vgpu设备将会在宿主机GPU下作为一个子目录出现:

kraxel@broadwell .../mdev_supported_types/i915-GVTg_V4_2# cd ../../$uuid
kraxel@broadwell .../0000:00:02.0/f321853c-c584-4a6b-b99a-3eee22a3919c# ls -l
total 0
lrwxrwxrwx. 1 root root    0 17. Jan 12:31 driver -> ../../../../bus/mdev/drivers/vfio_mdev
lrwxrwxrwx. 1 root root    0 17. Jan 12:35 iommu_group -> ../../../../kernel/iommu_groups/10
lrwxrwxrwx. 1 root root    0 17. Jan 12:35 mdev_type -> ../mdev_supported_types/i915-GVTg_V4_2
drwxr-xr-x. 2 root root    0 17. Jan 12:35 power
--w-------. 1 root root 4096 17. Jan 12:35 remove
lrwxrwxrwx. 1 root root    0 17. Jan 12:31 subsystem -> ../../../../bus/mdev
-rw-r--r--. 1 root root 4096 17. Jan 12:35 uevent

你可以看到设备被放置在IOMMU的第10组,我们会在下面使用这个值。

 

宿主机:设置虚拟机

最终我们希望虚拟机设置就像添加一个libvirt xml 文件那样简单。 因为mdev设备并没有一个PCI 地址,因此我们不能简单的透传,我们需要一个sysfs设备路径来传递给QEMU, libvirt现在还不支持这个功能, 所以这一步稍微有些复杂,我们需要在libvirt里做一些手动设置。

首先,我们必须确定QEMU 具有权限访问 “/dev”。 默认情况下libvirt通过用户控制组限定了这个访问,我们需要关闭它。 到文件“/etc/libvirt/qemu.conf”里,屏蔽掉“cgroup_controllers”那一栏就好,还有记得删掉“devices”。 完成后记得重启libvirtd

其次,我们也要允许QEMU可以访问IOMMU group10. 可通过下面的命令实现:

kraxel@broadwell ~# chmod 666 /dev/vfio/10

第三:更新libvirt xml文件:

<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
  [ ... ]
  <currentMemory unit='KiB'>1048576</currentMemory>
  <memoryBacking>
    <locked/>
  </memoryBacking>
  [ ... ]
  <qemu:commandline>
    <qemu:arg value='-device'/>
    <qemu:arg value='vfio-pci,addr=05.0,sysfsdev=/sys/class/mdev_bus/0000:00:02.0/f321853c-c584-4a6b-b99a-3eee22a3919c'/>
  </qemu:commandline>
</domain>

我们可以使用一个比较特殊的namespace来传递额外的命令行,毕竟libvirt还不支持传递 sysfs路径(当前libvirt已经可以了)。同时我们也必须显式的锁主客户机内存

 

虚拟机内部设置

最好在添加vgpu之间先准备一个可以运行的虚拟机。添加一个串口,这样我们也可以在图形界面坏掉的时候仍然可以跟虚机通讯。 将i915加入blacklist,至少在你知道你的设置可以工作后再手动加载它。 同时 启动进入runlevel3 文本界面而不是通常的runlevel5 图形界面,然后手动启动xorg服务器

intel推荐客户机需要使用4.8以后的内核,同时确保xorg server 使用 modesetting驱动, 我的基于intel驱动的测试并没有成功。 配置文件如下:

root@guest ~# cat /etc/X11/xorg.conf.d/intel.conf 
Section "Device"
        Identifier  "Card0"
#       Driver      "intel"
        Driver      "modesetting"
        BusID       "PCI:0:5:0"
EndSection

然后使用x11vnc,xterm, 以及mwm来启动xorg server,脚本如下:

#!/bin/sh
# debug
echo "# $0: DISPLAY=$DISPLAY"
# start server
if test "$DISPLAY" != ":4"; then
        echo "# $0: starting Xorg server"
        exec startx $0 -- /usr/bin/Xorg :4
        exit 1
fi
echo "# $0: starting session"
# configure session
xrdb $HOME/.Xdefaults
# start clients
x11vnc -rfbport 5904 &amp;
xterm &amp;
exec mwm

这个session 使用了 4号显示,所以你可以在宿主机里用以下命令访问:

kraxel@broadwell ~# vncviewer $guest_ip:4

 

原文

https://www.kraxel.org/blog/2017/01/virtual-gpu-support-landing-upstream/