Bios配置确认
首先要确定主板和CPU都支持虚拟化技术,在BIOS将VT-d、VT-x设置成enable。
以Intel为例,需要将下面两项设置为enable:
代码语言:javascript复制VT: Intel Virtualization Technology
VT-x:
VT-d: Intel VT for Directed I/O
Onboard VGA:
操作系统配置
确认内核⽀持iommu
cat /proc/cmdline | grep iommu 如果没有输出, 则需要修改kernel启动参数 对于intel cpu 1. 编辑 /etc/default/grub ⽂件, 在 GRUB_CMDLINE_LINUX ⾏后⾯添加: intel_iommu=on
[root@ostack-NMCS-001-021 ~]# cat /etc/default/grub GRUB_TIMEOUT=5 GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)" GRUB_DEFAULT=saved GRUB_DISABLE_SUBMENU=true GRUB_TERMINAL_OUTPUT="console" GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet intel_iommu=on" GRUB_DISABLE_RECOVERY="true" |
---|
如果没有 GRUB_CMDLINE_LINUX , 则使⽤ GRUB_CMDLINE_LINUX_DEFAULT
2、更新grub,并重启设备:
代码语言:javascript复制grub2-mkconfig -o /boot/grub2/grub.cfg
shutdown -r now
[root@ostack-NMCS-001-021 ~]# grub2-mkconfig -o /boot/grub2/grub.cfg Generating grub configuration file ... Found linux image: /boot/vmlinuz-3.10.0-1062.el7.x86_64 Found initrd image: /boot/initramfs-3.10.0-1062.el7.x86_64.img Found linux image: /boot/vmlinuz-0-rescue-9a0f67791cd74cddad3d7044def06753 Found initrd image: /boot/initramfs-0-rescue-9a0f67791cd74cddad3d7044def06753.img done |
---|
注:如果是uefi启动模式,则需要:
代码语言:javascript复制grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
重启以后如下确认是否正常:
代码语言:javascript复制#使用下面命令
dmesg | grep -i iommu
#如果输出类似下面的内容,说明正确
虚拟化支持确认
代码语言:javascript复制egrep -c '(vmx|svm)' /proc/cpuinfo
如果输入非0,则说明支持
配置vfio,检查当前显卡设备信息
[root@ostack-NMCS-001-021 ~]# lspci -nn | grep NVID 02:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP102 [GeForce GTX 1080 Ti] [10de:1b06] (rev a1) 02:00.1 Audio device [0403]: NVIDIA Corporation GP102 HDMI Audio Controller [10de:10ef] (rev a1) 03:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP102 [GeForce GTX 1080 Ti] [10de:1b06] (rev a1) 03:00.1 Audio device [0403]: NVIDIA Corporation GP102 HDMI Audio Controller [10de:10ef] (rev a1) |
---|
可以看到,其实我的这台设备上有两个个vga设备(就是我们服务器上的1080),这两个pci设备一共有2个硬件:VGA、Audio
确认驱动 由于我们的物理服务器操作系统,并没有安装NVIDIA显卡驱动,所以我们会发现如下信息。其中USB设备使用了xhci_hcd驱动,这个驱动是服务器自带的。
[root@ostack-NMCS-001-021 ~]# lspci -vv -s 02:00.0 | grep driver Kernel driver in use: nouveau [root@ostack-NMCS-001-021 ~]# lspci -vv -s 02:00.1 | grep driver Kernel driver in use: snd_hda_intel [root@ostack-NMCS-001-021 ~]# lspci -vv -s 03:00.0 | grep driver Kernel driver in use: nouveau [root@ostack-NMCS-001-021 ~]# lspci -vv -s 03:00.1 | grep driver Kernel driver in use: snd_hda_intel |
---|
如果我们安装了NVIDIA驱动的话, 可能会获得如下输出:
代码语言:javascript复制lspci -vv -s 06:00.0 | grep driver
Kernel driver in use: nvidia
lspci -vv -s 06:00.1 | grep driver
Kernel driver in use: snd_hda_intel
lspci -vv -s 06:00.2 | grep driver
Kernel driver in use: xhci_hcd
lspci -vv -s 06:00.3 | grep driver
配置vfio
因为我们想要把VGA设备透传到虚拟机中,首先我们需要将设备从物理机上分离(可能分离的 说法并不准确,暂且这么认为),实现的方法是将设备使用的默认驱动禁用,然后将设备加入到vfio模块,让设备使用vfio驱动。
在上面,我们已经查到了,理论上 ,由于我们并没有装NVIDIA驱动,我们只需要将xhci_hcd禁用即可,但是为了以防万一,我们可以将其他nvidia驱动也加到禁止名单。
这里我们将GPU带的4个设备的驱动都配置成vfio的一个原因是:默认情况下,统一pci端口的不同设备,会被分配到同一个iommu组,同一组的设备,只能同时被分配到一个虚拟机使用。假设,我们只讲VGA设备分离,其他三个不分离的话,会导致创建虚拟机的时候报错如下错误:Please ensure all devices within the iommu_group are bound to their vfio bus driver.。如果出现该问题,请检查每个设备的使用的驱动是否已经是vfio。
禁用默认驱动 为了保证设备不被宿主机使用,我们建议将上面查到的两个驱动禁用,编辑/etc/modprobe.d/blacklist.conf,添加如下配置(似乎并不需要此步骤):
代码语言:javascript复制blacklist nouveau
options nouveau modeset=0
blacklist xhci_hcd
blacklist nvidia
blacklist snd_hda_intel
#下面是网上看到的,有可能不需要
blacklist nvidiafb
配置系统加载模块
配置加载vfio-pci模块,编辑/etc/modules-load.d/openstack-gpu.conf,添加如下内容:
#注意vfio_pci的写法,一旦写错,创建带GPU的虚拟机的时候,可能会无法直通到虚拟机或者非常慢,虚拟机一直处于puased状态。
代码语言:javascript复制vfio_pci
#下面的内容也是参考网上的配置,有可能不需要
pci_stub
vfio
vfio_iommu_type1
kvm
kvm_intel
配置vfio加载的设备
配置使用vfio驱动的设备(这里的设备就是上面我们查到的设备的)编辑/etc/modprobe.d/vfio.conf,添加如下配置:
代码语言:javascript复制# GTX 2080Ti and its audio controller
options vfio-pci ids=10de:1e04,10de:10f7,10de:1ad6,10de:1ad7
重新生成内核并重启
重新生成内核文件之前,我们先备份已有的:
mv /boot/initramfs-$(uname -r).img /boot/initramfs-$(uname -r)-nouveau.img
重新生成:
dracut /boot/initramfs-$(uname -r).img $(uname -r)
重启设备:
shutdown -r now
查看启动信息,确认vfio模块是否加载
dmesg | grep -i vfio
[root@ostack-nmcs-001-026 ~]# dmesg | grep -i vfio [ 5.365031] VFIO - User Level meta-driver version: 0.3 [ 5.377591] vfio_pci: add [10de:1e07[ffff:ffff]] class 0x000000/00000000 [ 5.377810] vfio_pci: add [10de:10f7[ffff:ffff]] class 0x000000/00000000 [ 5.377899] vfio_pci: add [10de:1ad6[ffff:ffff]] class 0x000000/00000000 [ 5.378107] vfio_pci: add [10de:1ad7[ffff:ffff]] class 0x000000/00000000 |
---|
重启以后,我们查看设备使用的驱动,都显示vfio说明正确
[root@ostack-NMCS-001-021 ~]# lspci -vv -s 02:00.0| grep driver Kernel driver in use: vfio-pci [root@ostack-NMCS-001-021 ~]# lspci -vv -s 02:00.1| grep driver Kernel driver in use: vfio-pci |
---|
注:如果有设备的驱动不是vfio,可能会导致报错:Please ensure all devices within the iommu_group are bound to their vfio bus driver.
注:有时候,我们可能会遇到正常操作以后,USB设备依然使用xhci_hcd驱动的情况。而当我们尝试用[modprobe -r xhci_hcd]去卸载该驱动模块的时候,会报错如下错误: modprobe: FATAL: Module xhci_hcd is builtin。 这时候,我们有两种方法去解决: 1、可以如下操作手动分离,并绑定vfio驱动。 2、从新编译内核,让xhci_pci模块oaded而不built-in。
我们介绍第一种解决方法:
代码语言:javascript复制#分离xhci_hcd驱动,分离后
[lspci -vv -s 0000:1a:00.2 | grep driver]命令将没有输出
echo -n “0000:1a:00.2” > /sys/bus/pci/drivers/xhci_hcd/unbind
代码语言:javascript复制#绑定vfio驱动,绑定后
[lspci -vv -s 0000:1a:00.2 | grep driver]命令将正常输出vfio
echo -n “0000:1a:00.2” > /sys/bus/pci/drivers/vfio-pci/bind
#但重启以后,会自动恢复 如果是多个设备,可以如下执行:
代码语言:javascript复制for p in $(lspci -nn | grep -i ‘nvi’| grep -i ‘usb’ | awk '{print KaTeX parse error: Expected 'EOF', got '}' at position 2: 1}̲' );do echo -n …p" > /sys/bus/pci/drivers/xhci_hcd/unbind;echo “$p” > /sys/bus/pci/drivers/vfio-pci/bind ;done
openstack配置
控制节点配置
主要配置2个块,filter_scheduler和pci
代码语言:javascript复制[filter_scheduler]
available_filters = nova.scheduler.filters.all_filters
#主要在末尾添加:PciPassthroughFilter
代码语言:javascript复制enabled_filters = RetryFilter,AvailabilityZoneFilter,ComputeFilter,ComputeCapabilitiesFilter,RamFilter,CoreFilter,ImagePropertiesFilter,ServerGroupAntiAffinityFilter,ServerGroupAffinityFilter,PciPassthroughFilter
[pci]
#alias
是能够直通设备的信息,多个设备多条记录,我们希望GPU上的4个设备都直通到虚拟机,所以将4个设备信息都写上 #这里还要注意的是device_type,可用的有:type-PCI,type-PF,type-VF,要根据实际情况来:
代码语言:javascript复制##2080的写法
alias = {"name":"nv2080vga","product_id":"1e04","vendor_id":"10de","device_type":"type-PCI"}
alias = {"name":"nv2080aud","product_id":"10f7","vendor_id":"10de","device_type":"type-PCI"}
alias = {"name":"nv2080usb","product_id":"1ad6","vendor_id":"10de","device_type":"type-PCI"}
alias = {"name":"nv2080bus","product_id":"1ad7","vendor_id":"10de","device_type":"type-PCI"}
##T4的写法:
alias = {"name":"nvT43D","product_id":"1eb8","vendor_id":"10de","device_type":"type-PF"}
#1080写法
alias = {"name":"nv1080vga","product_id":"1b06","vendor_id":"10de","device_type":"type-PCI"}
alias = {"name":"nv1080aud","product_id":"10ef","vendor_id":"10de","device_type":"type-PCI"}
配置完成以后,重启nova 相关服务(nova-api和nova-scheduler):
代码语言:javascript复制systemctl restart openstack-nova-api.service openstack-nova-scheduler.service
配置计算节点
计算节点,主要配置pci部分
代码语言:javascript复制[pci]
#alias可以配置多条,对应多个设备
alias = {"name":"nv2080vga","product_id":"1e04","vendor_id":"10de","device_type":"type-PCI"}
alias = {"name":"nv2080aud","product_id":"10f7","vendor_id":"10de","device_type":"type-PCI"}
alias = {"name":"nv2080usb","product_id":"1ad6","vendor_id":"10de","device_type":"type-PCI"}
alias = {"name":"nv2080bus","product_id":"1ad7","vendor_id":"10de","device_type":"type-PCI"}
#passthrough_whitelist配置该计算节点可用于直通的设备
passthrough_whitelist = [{ "vendor_id": "10de", "product_id": "1e04" },
{ "vendor_id": "10de", "product_id": "10f7" },
{ "vendor_id": "10de", "product_id": "1ad6" },
{ "vendor_id": "10de", "product_id": "1ad7" }]
重启计算服务:
代码语言:javascript复制systemctl restart openstack-nova-compute
创建带有显卡直通信息的flavor
代码语言:javascript复制openstack flavor create --public --ram 2048 --disk 20 --vcpus 2 m1.large
代码语言:javascript复制openstack flavor set m1.large --property pci_passthrough:alias='nv2080vga:2,nv2080aud:2,nv2080usb:2,nv2080bus:2'
pci_passthrough:alias是固定格式,标识用alias方筛选pci设备 nv2080vga:2标识2块名为 nv2080vga的设备,多个设备英文逗号隔开
以上步骤可以dashboard上操作 隐藏虚拟机的hypervisor id 因为NIVIDIA显卡的驱动会检测是否跑在虚拟机里,如果在虚拟机里驱动就会出错,所以我们需要对显卡驱动隐藏hypervisor id。在OpenStack的Pile版本中的Glance 镜像引入了img_hide_hypervisor_id=true的property,所以可以对镜像执行如下的命令隐藏hupervisor id:
openstack image set [IMG-UUID] --property img_hide_hypervisor_id=true 1 通过此镜像安装的instance就会隐藏hypervisor id。
可以通过下边的命令查看hypervisor id是否隐藏:
cpuid | grep hypervisor_id hypervisor_id = "KVMKVMKVM " hypervisor_id = "KVMKVMKVM " 1 2 3 上边的显示结果说明没有隐藏,下边的显示结果说明已经隐藏:
cpuid | grep hypervisor_id hypervisor_id = " @ @ " hypervisor_id = " @ @ " 1 2 3 创建实例 这时候,我们使用上面的flavor和image来创建虚拟机就可以了
创建GPU报错:(Please ensure all devices within the iommu_group are bound to their vfio bus driver.)
首先查看GPU所有设备信息:
lspci -nn | grep NV
例如输出:
41:00.0 VGA compatible controller [0300]: NVIDIA Corporation TU102 [GeForce RTX 2080 Ti Rev. A] [10de:1e07] (rev a1) 41:00.1 Audio device [0403]: NVIDIA Corporation TU102 High Definition Audio Controller [10de:10f7] (rev a1) 41:00.2 USB controller [0c03]: NVIDIA Corporation TU102 USB 3.1 Host Controller [10de:1ad6] (rev a1) 41:00.3 Serial bus controller [0c80]: NVIDIA Corporation TU102 USB Type-C UCSI Controller [10de:1ad7] (rev a1) |
---|
然后通过查看此设备的驱动信息:
[root@ostack-NMCS-001-026 ~]# lspci -vv -s 41:00.2 | grep driver Kernel driver in use: xhci_hcd |
---|
查看此设备的驱动信息不对,解绑驱动:
echo -n "0000:41:00.2" > /sys/bus/pci/drivers/xhci_hcd/unbind |
---|
然后绑定openstack支持的驱动:
echo -n "0000:41:00.2" > /sys/bus/pci/drivers/vfio-pci/bind |
---|
如果有多个这个USB设备,需要每一个进行解绑并进行绑定。
参考这个文档:
使用 GPU 在直通中启动虚拟机时出现问题 - 红帽客户门户 (redhat.com)