15 使用 virsh
配置虚拟机 #
您也可以在命令行上使用 virsh
来配置虚拟机 (VM),以此替代虚拟机管理器。使用 virsh
可以控制 VM 的状态、编辑 VM 的配置,甚至将 VM 迁移到另一台主机。下列章节介绍如何使用 virsh
来管理 VM。
15.1 编辑 VM 配置 #
VM 配置储存在 /etc/libvirt/qemu/
中的某个 XML 文件内,其内容如下所示:
<domain type='kvm'> <name>sles15</name> <uuid>ab953e2f-9d16-4955-bb43-1178230ee625</uuid> <memory unit='KiB'>2097152</memory> <currentMemory unit='KiB'>2097152</currentMemory> <vcpu placement='static'>2</vcpu> <os> <type arch='x86_64' machine='pc-q35-2.0'>hvm</type> </os> <features>...</features> <cpu mode='custom' match='exact' check='partial'> <model fallback='allow'>Skylake-Client-IBRS</model> </cpu> <clock>...</clock> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>destroy</on_crash> <pm> <suspend-to-mem enabled='no'/> <suspend-to-disk enabled='no'/> </pm> <devices> <emulator>/usr/bin/qemu-system-x86_64</emulator> <disk type='file' device='disk'>...</disk> </devices> ... </domain>
如果您要编辑 VM Guest 的配置,请检查它是否处于脱机状态:
>
sudo
virsh list --inactive
如果您的 VM Guest 在此列表中,则表明您可以放心地编辑其配置:
>
sudo
virsh edit NAME_OF_VM_GUEST
在保存更改之前,virsh
会根据 RelaxNG 纲要验证您的输入。
15.2 更改计算机类型 #
使用 virt-install
工具安装时,VM Guest 的计算机类型默认为 pc-q35。计算机类型储存在 VM Guest 配置文件中的 type
元素内:
<type arch='x86_64' machine='pc-q35-2.3'>hvm</type>
下面的过程示范了如何将此值更改为 q35
计算机类型。值 q35
表示一种 Intel* 芯片组,其中包括 PCIe,最多支持 12 个 USB 端口,并支持 SATA 和 IOMMU。
检查您的 VM Guest 是否处于非活动状态:
>
sudo
virsh list --inactive
Id Name State ---------------------------------------------------- - sles15 shut off编辑此 VM Guest 的配置:
>
sudo
virsh edit sles15
请将
machine
属性的值替换为pc-q35-2.0
:<type arch='x86_64' machine='pc-q35-2.0'>hvm</type>
重启动 VM Guest:
>
sudo
virsh start sles15
检查计算机类型是否已更改。登录到 VM Guest 并运行以下命令:
>
sudo
dmidecode | grep Product
Product Name: Standard PC (Q35 + ICH9, 2009)
每当升级主机系统上的 QEMU 版本时(例如,将 VM 主机服务器升级到新服务包时),请将 VM Guest 的计算机类型升级到最新的可用版本。要进行检查,请在 VM 主机服务器上使用 qemu-system-x86_64 -M help
命令。
默认计算机类型(例如 pc-i440fx
)会定期更新。如果您的 VM Guest 仍在 pc-i440fx-1.X
计算机类型上运行,我们强烈建议更新到 pc-i440fx-2.X
。这样就可以利用计算机定义中最近的更新和更正,并确保将来可以更好地兼容。
15.3 配置超级管理程序功能 #
libvirt
可自动启用一组默认的超级管理程序功能(这些功能在大多数情况下已够用),同时还允许按需启用和禁用功能。例如,Xen 不支持默认启用 PCI 直通。必须使用直通
设置来启用此功能。可以使用 virsh
来配置超级管理程序功能。查看 VM Guest 配置文件中的 <features>
元素,并根据需要调整各项功能。仍以 Xen 直通为例:
>
sudo
virsh edit sle15sp1 <features> <xen> <passthrough/> </xen> </features>
保存更改并重启动 VM Guest。
有关详细信息,请参见 https://libvirt.org/formatdomain.html#elementsFeatures 上 libvirt 的《Domain XML format》(域 XML 格式)手册中的“Hypervisor features”(超级管理程序功能)一节。
15.4 配置 CPU #
可以使用 virsh
来配置提供给 VM Guest 的虚拟 CPU 的许多属性。可以更改分配给 VM Guest 的当前和最大 CPU 数量,以及 CPU 型号及其功能集。以下小节介绍如何更改 VM Guest 的常用 CPU 设置。
15.4.1 配置 CPU 数量 #
分配的 CPU 数量储存在 /etc/libvirt/qemu/
下 VM Guest XML 配置文件中的 vcpu
元素内:
<vcpu placement='static'>1</vcpu>
在此示例中,只为 VM Guest 分配了一个 CPU。下面的过程说明如何更改分配给 VM Guest 的 CPU 数量:
检查您的 VM Guest 是否处于非活动状态:
>
sudo
virsh list --inactive
Id Name State ---------------------------------------------------- - sles15 shut off编辑现有 VM Guest 的配置:
>
sudo
virsh edit sles15
更改分配的 CPU 数量:
<vcpu placement='static'>2</vcpu>
重启动 VM Guest:
>
sudo
virsh start sles15
检查 VM 中的 CPU 数量是否已更改。
>
sudo
virsh vcpuinfo sled15
VCPU: 0 CPU: N/A State: N/A CPU time N/A CPU Affinity: yy VCPU: 1 CPU: N/A State: N/A CPU time N/A CPU Affinity: yy
还可以在 VM Guest 正在运行时更改 CPU 数量。可以热插接 CPU,只要不超过 VM Guest 启动时配置的最大数量即可。同样,可以热拔除 CPU,只要不达到下限 1 即可。以下示例演示如何将活动 CPU 计数从 2 个更改为预定义的最大计数 4 个。
检查当前的在线 vcpu 计数:
>
sudo
virsh vcpucount sles15 | grep live
maximum live 4 current live 2将当前或活动的 CPU 数量更改为 4 个:
>
sudo
virsh setvcpus sles15 --count 4 --live
检查当前的在线 vcpu 计数现在是否为 4 个:
>
sudo
virsh vcpucount sles15 | grep live
maximum live 4 current live 4
在 KVM 中可以定义 CPU 数量超过 255 个的 VM Guest,但需要完成额外的配置才能启动和运行 VM Guest。需要微调 ioapic
功能,并且需要将 IOMMU 设备添加到 VM Guest。下面是适用于 288 个 CPU 的示例配置。
<domain> <vcpu placement='static'>288</vcpu> <features> <ioapic driver='qemu'/> </features> <devices> <iommu model='intel'> <driver intremap='on' eim='on'/> </iommu> </devices> </domain>
15.4.2 配置 CPU 型号 #
向 VM Guest 公开的 CPU 型号往往会影响该 VM Guest 中运行的工作负载。默认 CPU 型号派生自一种名为 host-model
的 CPU 模式。
<cpu mode='host-model'/>
使用 CPU 模式 host-model
启动 VM Guest 时,libvirt
会将其主机 CPU 型号复制到 VM Guest 定义中。可以在 virsh capabilities
的输出中观察复制到 VM Guest 定义的主机 CPU 型号和功能。
另一种有趣的 CPU 模式是 host-passthrough
。
<cpu mode='host-passthrough'/>
使用 CPU 模式 host-passthrough
启动 VM Guest 时,将为该 VM Guest 提供与 VM 主机服务器 CPU 完全相同的 CPU。当 libvirt
的简化 host-model
CPU 不能提供 VM Guest 工作负载所需的 CPU 功能时,该型号可能很有用。在某些情况下也需要 host-passthrough
CPU 模式,例如,在运行内存超过 4TB 的 VM Guest 时。host-passthrough
CPU 模式存在迁移能力下降的劣势。采用 host-passthrough
CPU 模式的 VM Guest 只能迁移到具有相同硬件的 VM 主机服务器。
使用 host-passthrough
CPU 模式时,仍可以禁用不需要的功能。以下配置将为 VM Guest 提供与主机 CPU 完全相同的 CPU,但会禁用 vmx
功能。
<cpu mode='host-passthrough'> <feature policy='disable' name='vmx'/> </cpu>
custom
CPU 模式是另一种常用模式,用于定义可在群集中不同主机之间迁移的规范化 CPU。例如,在主机包含 Nehalem、IvyBridge 和 SandyBridge CPU 的群集中,可以使用包含 Nehalem CPU 型号的 custom
CPU 模式来配置 VM Guest。
<cpu mode='custom' match='exact'> <model fallback='allow'>Nehalem</model> <feature policy='require' name='vme'/> <feature policy='require' name='ds'/> <feature policy='require' name='acpi'/> <feature policy='require' name='ss'/> <feature policy='require' name='ht'/> <feature policy='require' name='tm'/> <feature policy='require' name='pbe'/> <feature policy='require' name='dtes64'/> <feature policy='require' name='monitor'/> <feature policy='require' name='ds_cpl'/> <feature policy='require' name='vmx'/> <feature policy='require' name='est'/> <feature policy='require' name='tm2'/> <feature policy='require' name='xtpr'/> <feature policy='require' name='pdcm'/> <feature policy='require' name='dca'/> <feature policy='require' name='rdtscp'/> <feature policy='require' name='invtsc'/> </cpu>
有关 libvirt
的 CPU 型号和拓扑选项的详细信息,请参见 https://libvirt.org/formatdomain.html#cpu-model-and-topology 上的 CPU 型号和拓扑文档。
15.6 配置内存分配 #
您还可以使用 virsh
来配置分配给 VM Guest 的内存量。该配置储存在 memory
元素中,它定义了引导时为 VM Guest 分配的最大内存。可选的 currentMemory
元素定义分配给 VM Guest 的实际内存。currentMemory
可以小于 memory
,这样,就可以在 VM Guest 正在运行时增加(或扩大)内存。如果省略 currentMemory
,则其默认值与 memory
元素的值相同。
可以通过编辑 VM Guest 配置来调整内存设置,但请注意,更改只会在下次引导后生效。以下步骤说明如何将 VM Guest 更改为使用 4G 内存引导,但随后可以扩展到 8G:
打开 VM Guest 的 XML 配置:
>
sudo
virsh edit sles15
搜索
memory
元素并设置为 8G:... <memory unit='KiB'>8388608</memory> ...
如果
currentMemory
元素不存在,请将其添加到memory
元素下面,或将其值更改为 4G:[...] <memory unit='KiB'>8388608</memory> <currentMemory unit='KiB'>4194304</currentMemory> [...]
当 VM Guest 正在运行时,可以使用 setmem
子命令更改内存分配。以下示例显示如何将内存分配增加到 8G:
检查 VM Guest 的现有内存设置:
>
sudo
virsh dominfo sles15 | grep memory
Max memory: 8388608 KiB Used memory: 4194608 KiB将使用的内存更改为 8G:
>
sudo
virsh setmem sles15 8388608
检查已更新的内存设置:
>
sudo
virsh dominfo sles15 | grep memory
Max memory: 8388608 KiB Used memory: 8388608 KiB
内存要求为 4TB 或更高的 VM Guest 目前必须使用 host-passthrough
CPU 型号。
15.7 添加 PCI 设备 #
要使用 virsh
将 PCI 设备指派到 VM Guest,请执行以下步骤:
标识要指派到 VM Guest 的主机 PCI 设备。在下面的示例中,我们要将一块 DEC 网卡指派到 Guest:
>
sudo
lspci -nn
[...] 03:07.0 Ethernet controller [0200]: Digital Equipment Corporation DECchip \ 21140 [FasterNet] [1011:0009] (rev 22) [...]请记下设备 ID(在本例中为
03:07.0
)。使用
virsh nodedev-dumpxml ID
收集有关设备的详细信息。要获取 ID,请将设备 ID (03:07.0
) 中的冒号和句点替换为下划线。使用 “pci_0000_” 作为结果的前缀:pci_0000_03_07_0
.>
sudo
virsh nodedev-dumpxml pci_0000_03_07_0
<device> <name>pci_0000_03_07_0</name> <path>/sys/devices/pci0000:00/0000:00:14.4/0000:03:07.0</path> <parent>pci_0000_00_14_4</parent> <driver> <name>tulip</name> </driver> <capability type='pci'> <domain>0</domain> <bus>3</bus> <slot>7</slot> <function>0</function> <product id='0x0009'>DECchip 21140 [FasterNet]</product> <vendor id='0x1011'>Digital Equipment Corporation</vendor> <numa node='0'/> </capability> </device>记下域、总线和功能的值(请查看上面以粗体列显的 XML 代码)。
从主机系统上分离设备,然后将其挂接到 VM Guest:
>
sudo
virsh nodedev-detach pci_0000_03_07_0
Device pci_0000_03_07_0 detached提示:多功能 PCI 设备使用不支持 FLR(功能级重设置)或 PM(电源管理)重设置的多功能 PCI 设备时,需要从 VM 主机服务器分离其所有功能。出于安全原因,整个设备都必须重设置。如果 VM 主机服务器或其他 VM Guest 仍在使用设备的某个功能,
libvirt
将拒绝指派该设备。将域、总线、插槽和功能值从十进制转换为十六进制。在本示例中,域 = 0,总线 = 3,插槽 = 7,功能 = 0。确保按正确顺序插入值:
>
printf "<address domain='0x%x' bus='0x%x' slot='0x%x' function='0x%x'/>\n" 0 3 7 0
这会返回以下结果:
<address domain='0x0' bus='0x3' slot='0x7' function='0x0'/>
在您的域上运行
virsh edit
,并使用上一步的结果在<devices>
部分添加以下设备项:<hostdev mode='subsystem' type='pci' managed='yes'> <source> <address domain='0x0' bus='0x03' slot='0x07' function='0x0'/> </source> </hostdev>
提示:受管
模式与不受管
模式的比较libvirt
可识别 PCI 设备的两种处理模式:受管
或不受管
。在受管模式下,libvirt
将处理从现有驱动程序取消绑定设备(如果需要)、重设置设备、在启动域之前将设备绑定到vfio-pci
等事项的所有细节。对于受管设备,当终止域或者从域中去除设备时,libvirt
会将设备从vfio-pci
取消绑定,然后将其重新绑定到原始驱动程序。如果设备不受管,则用户必须确保在将设备指派到域之前以及在设备不再由域使用之后,所有这些设备管理方面的操作都已完成。在上面的示例中,
managed='yes'
选项表示设备是受管的。要将设备切换为不受管模式,请在上面的列表中设置managed='no'
。如果这样做,需使用virsh nodedev-detach
和virsh nodedev-reattach
命令处理相关的驱动程序。在启动 VM Guest 之前,需运行virsh nodedev-detach pci_0000_03_07_0
以从主机分离设备。如果 VM Guest 未运行,您可以运行virsh nodedev-reattach pci_0000_03_07_0
,使设备可供主机使用。关闭 VM Guest,并禁用 SELinux(如果它正在主机上运行)。
>
sudo
setsebool -P virt_use_sysfs 1
启动 VM Guest 以使指派的 PCI 设备可用:
>
sudo
virsh start sles15
在包含 SLES11 SP4 KVM Guest 的新型 QEMU 计算机(pc-i440fx-2.0 或更高版本)上,默认不会在 Guest 中装载 acpiphp
模块。必须装载此模块才能启用磁盘和网络设备热插拔功能。要手动装载该模块,请使用 modprobe acpiphp
命令。也可以通过在 /etc/modprobe.conf.local
文件中添加 install acpiphp /bin/true
来自动装载该模块。
使用 QEMU Q35 计算机类型的 KVM Guest 采用 PCI 拓扑,其中包含一个 pcie-root
控制器和七个 pcie-root-port
控制器。pcie-root
控制器不支持热插拔。每个 pcie-root-port
控制器支持热插拔一个 PCIe 设备。PCI 控制器无法热插拔,因此,如果要热插拔的 PCIe 设备超过七个,请相应地做好规划并添加更多 pcie-root-port
控制器。可以添加一个 pcie-to-pci-bridge
控制器来支持热插拔旧式 PCI 设备。有关不同 QEMU 计算机类型的 PCI 拓扑的详细信息,请参见 https://libvirt.org/pci-hotplug.html。
15.7.1 IBM Z 的 PCI 直通 #
为了支持 IBM Z,QEMU 扩展了 PCI 表示形式,现在它允许配置额外的属性。<zpci/>
libvirt
规范中添加了两个额外的属性:uid
和 fid
。uid
表示用户定义的标识符,fid
表示 PCI 功能标识符。这些属性是可选的,如果不指定,系统将使用不冲突的值自动生成这些属性。
要在域规范中包含 zPCI 属性,请使用以下示例定义:
<controller type='pci' index='0' model='pci-root'/> <controller type='pci' index='1' model='pci-bridge'> <model name='pci-bridge'/> <target chassisNr='1'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'> <zpci uid='0x0001' fid='0x00000000'/> </address> </controller> <interface type='bridge'> <source bridge='virbr0'/> <model type='virtio'/> <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0'> <zpci uid='0x0007' fid='0x00000003'/> </address> </interface>
15.8 添加 USB 设备 #
要使用 virsh
将 USB 设备指派到 VM Guest,请执行以下步骤:
标识要指派到 VM Guest 的主机 USB 设备:
>
sudo
lsusb
[...] Bus 001 Device 003: ID 0557:2221 ATEN International Co., Ltd Winbond Hermon [...]记下供应商 ID 和产品 ID。在本示例中,供应商 ID 为
0557
,产品 ID 为2221
。在您的域上运行
virsh edit
,并使用上一步获得的值在<devices>
部分添加以下设备项:<hostdev mode='subsystem' type='usb'> <source startupPolicy='optional'> <vendor id='0557'/> <product id='2221'/> </source> </hostdev>
提示:供应商/产品或设备地址如果不使用
<vendor/>
和<product/>
ID 定义主机设备,您可以根据第 15.7 节 “添加 PCI 设备”中所述的适用于主机 PCI 设备的操作使用<address/>
元素。关闭 VM Guest,并禁用 SELinux(如果它正在主机上运行):
>
sudo
setsebool -P virt_use_sysfs 1
启动 VM Guest 以使指派的 PCI 设备可用:
>
sudo
virsh start sles15
15.9 添加 SR-IOV 设备 #
支持单根 I/O 虚拟化 (SR-IOV) 的 PCIe 设备能够复制其资源,因此它们看上去像是多个设备。可将其中的每个“伪设备”指派到 VM Guest。
SR-IOV 是外围部件互连专业组 (PCI-SIG) 联盟制定的行业规范。其中介绍了物理功能 (PF) 和虚拟功能 (VF)。PF 是用于管理和配置设备的完整 PCIe 功能。PF 还可以移动数据。VF 在配置和管理方面的作用有所欠缺 — 它们只能移动数据,提供的配置功能有限。由于 VF 不包括所有的 PCIe 功能,主机操作系统或超级管理程序必须支持 SR-IOV 才能访问和初始化 VF。理论上 VF 的最大数量为每台设备 256 个(因此,对于双端口以太网卡,最大数量为 512 个)。在实际环境中,此最大数量要少得多,因为每个 VF 都会消耗资源。
15.9.1 要求 #
要使用 SR-IOV,必须符合以下要求:
支持 SR-IOV 的网卡(从 SUSE Linux Enterprise Server 15 开始,只有网卡支持 SR-IOV)
支持硬件虚拟化的 AMD64/Intel 64 主机(AMD-V 或 Intel VT-x),有关详细信息,请参见第 7.1.1 节 “KVM 硬件要求”
支持设备指派的芯片组(AMD-Vi 或 Intel VT-d)
libvirt
0.9.10 或更高版本主机系统上必须装载并配置 SR-IOV 驱动程序
符合重要:VFIO 和 SR-IOV 的要求中所列要求的主机配置
要指派到 VM Guest 的 VF 的 PCI 地址列表
可以通过运行 lspci
从设备的 PCI 描述符中获取有关该设备是否支持 SR-IOV 的信息。支持 SR-IOV 的设备会报告类似如下的功能:
Capabilities: [160 v1] Single Root I/O Virtualization (SR-IOV)
您必须已按照第 15.9.2 节 “装载和配置 SR-IOV 主机驱动程序”中所述配置 VM 主机服务器,才可在最初设置 VM Guest 时向其添加 SR-IOV 设备。
15.9.2 装载和配置 SR-IOV 主机驱动程序 #
要访问和初始化 VF,需在主机系统上装载一个支持 SR-IOV 的驱动程序。
在装载驱动程序之前,请运行
lspci
来确保可正常检测到网卡。下面的示例显示了双端口 Intel 82576NS 网卡的lspci
输出:>
sudo
/sbin/lspci | grep 82576
01:00.0 Ethernet controller: Intel Corporation 82576NS Gigabit Network Connection (rev 01) 01:00.1 Ethernet controller: Intel Corporation 82576NS Gigabit Network Connection (rev 01) 04:00.0 Ethernet controller: Intel Corporation 82576NS Gigabit Network Connection (rev 01) 04:00.1 Ethernet controller: Intel Corporation 82576NS Gigabit Network Connection (rev 01)如果未检测到网卡,可能是因为未在 BIOS/EFI 中启用硬件虚拟化支持。要检查是否已启用硬件虚拟化支持,请查看主机 BIOS 中的设置。
运行
lsmod
来检查是否已装载 SR-IOV 驱动程序。在下面的示例中,用于检查是否装载了 Intel 82576NS 网卡的 igb 驱动程序的命令返回了一条结果。这表示已装载该驱动程序。如果该命令未返回任何结果,则表示未装载该驱动程序。>
sudo
/sbin/lsmod | egrep "^igb "
igb 185649 0如果已装载驱动程序,请跳过以下步骤。如果尚未装载 SR-IOV 驱动程序,需要先去除非 SR-IOV 驱动程序,然后再装载新驱动程序。使用
rmmod
卸载驱动程序。下面的示例会卸载 Intel 82576NS 网卡的非 SR-IOV 驱动程序:>
sudo
/sbin/rmmod igbvf
随后使用
modprobe
命令装载 SR-IOV 驱动程序 — 必须指定 VF 参数 (max_vfs
):>
sudo
/sbin/modprobe igb max_vfs=8
或者,您也可以通过 SYSFS 装载驱动程序:
通过列出以太网设备确定物理 NIC 的 PCI ID:
>
sudo
lspci | grep Eth
06:00.0 Ethernet controller: Emulex Corporation OneConnect NIC (Skyhawk) (rev 10) 06:00.1 Ethernet controller: Emulex Corporation OneConnect NIC (Skyhawk) (rev 10)要启用 VF,请向
sriov_numvfs
参数回送需要装载的 VF 数量:>
sudo
echo 1 > /sys/bus/pci/devices/0000:06:00.1/sriov_numvfs
校验是否已装载 VF NIC:
>
sudo
lspci | grep Eth
06:00.0 Ethernet controller: Emulex Corporation OneConnect NIC (Skyhawk) (rev 10) 06:00.1 Ethernet controller: Emulex Corporation OneConnect NIC (Skyhawk) (rev 10) 06:08.0 Ethernet controller: Emulex Corporation OneConnect NIC (Skyhawk) (rev 10)获取可用 VF 的最大数量:
>
sudo
lspci -vvv -s 06:00.1 | grep 'Initial VFs'
Initial VFs: 32, Total VFs: 32, Number of VFs: 0, Function Dependency Link: 01创建
/etc/systemd/system/before.service
文件,用于在引导时通过 SYSFS 装载 VF:[Unit] Before= [Service] Type=oneshot RemainAfterExit=true ExecStart=/bin/bash -c "echo 1 > /sys/bus/pci/devices/0000:06:00.1/sriov_numvfs" # beware, executable is run directly, not through a shell, check the man pages # systemd.service and systemd.unit for full syntax [Install] # target in which to start the service WantedBy=multi-user.target #WantedBy=graphical.target
在启动 VM 之前,需要创建指向
/etc/init.d/after.local
脚本(用于分离 NIC)的另一个服务文件 (after-local.service
)。否则 VM 将无法启动:[Unit] Description=/etc/init.d/after.local Compatibility After=libvirtd.service Requires=libvirtd.service [Service] Type=oneshot ExecStart=/etc/init.d/after.local RemainAfterExit=true [Install] WantedBy=multi-user.target
将此文件复制到
/etc/systemd/system
。#! /bin/sh # ... virsh nodedev-detach pci_0000_06_08_0
将它另存为
/etc/init.d/after.local
。重引导计算机,然后根据本过程的第一步所述,重新运行
lspci
命令检查是否已装载 SR-IOV 驱动程序。如果已成功装载 SR-IOV 驱动程序,您应该会看到额外的 VF 行:01:00.0 Ethernet controller: Intel Corporation 82576NS Gigabit Network Connection (rev 01) 01:00.1 Ethernet controller: Intel Corporation 82576NS Gigabit Network Connection (rev 01) 01:10.0 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01) 01:10.1 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01) 01:10.2 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01) [...] 04:00.0 Ethernet controller: Intel Corporation 82576NS Gigabit Network Connection (rev 01) 04:00.1 Ethernet controller: Intel Corporation 82576NS Gigabit Network Connection (rev 01) 04:10.0 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01) 04:10.1 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01) 04:10.2 Ethernet controller: Intel Corporation 82576 Virtual Function (rev 01) [...]
15.9.3 将 VF 网络设备添加到 VM Guest #
在 VM 主机服务器上正确设置 SR-IOV 硬件后,便可将 VF 添加到 VM Guest。为此,您需要先收集一些数据。
下面的过程使用的是示例数据。请务必将其替换为您设置中的相应数据。
使用
virsh nodedev-list
命令获取您要指派的 VF 的 PCI 地址及其对应的 PF。第 15.9.2 节 “装载和配置 SR-IOV 主机驱动程序”中所示的lspci
输出中的数字值(例如01:00.0
或04:00.1
)已经过转换:添加了前缀“pci_0000_”并将冒号和句点替换为下划线。因此,lspci
列出的 PCI ID“04:00.0”会被 virsh 列为“pci_0000_04_00_0”。下面的示例列出了 Intel 82576NS 网卡的第二个端口的 PCI ID:>
sudo
virsh nodedev-list | grep 0000_04_
pci_0000_04_00_0 pci_0000_04_00_1 pci_0000_04_10_0 pci_0000_04_10_1 pci_0000_04_10_2 pci_0000_04_10_3 pci_0000_04_10_4 pci_0000_04_10_5 pci_0000_04_10_6 pci_0000_04_10_7 pci_0000_04_11_0 pci_0000_04_11_1 pci_0000_04_11_2 pci_0000_04_11_3 pci_0000_04_11_4 pci_0000_04_11_5前两个项表示 PF,其他项表示 VF。
对您要添加的 VF 的 PCI ID 运行以下
virsh nodedev-dumpxml
命令:>
sudo
virsh nodedev-dumpxml pci_0000_04_10_0
<device> <name>pci_0000_04_10_0</name> <parent>pci_0000_00_02_0</parent> <capability type='pci'> <domain>0</domain> <bus>4</bus> <slot>16</slot> <function>0</function> <product id='0x10ca'>82576 Virtual Function</product> <vendor id='0x8086'>Intel Corporation</vendor> <capability type='phys_function'> <address domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> </capability> </capability> </device>下一步需要以下数据:
<domain>0</domain>
<bus>4</bus>
<slot>16</slot>
<function>0</function>
创建一个临时 XML 文件(例如
/tmp/vf-interface.xml
),其中包含将 VF 网络设备添加到现有 VM Guest 所需的数据。该文件至少需包含如下所示的内容:<interface type='hostdev'>1 <source> <address type='pci' domain='0' bus='11' slot='16' function='0'2/>2 </source> </interface>
如果设备已挂接到主机,则无法将它挂接到 VM Guest。要使该设备可供 Guest 使用,请先将它从主机分离:
>
sudo
virsh nodedev-detach pci_0000_04_10_0
将 VF 接口添加到现有 VM Guest:
>
sudo
virsh attach-device GUEST /tmp/vf-interface.xml --OPTION
需将 GUEST 替换为 VM Guest 的域名、ID 或 UUID。--OPTION 可为下列其中一项:
--persistent
此选项始终将设备添加到域的永久性 XML 中。此外,如果域正在运行,则会热插入设备。
--config
此选项只影响永久性 XML,即使域正在运行也是如此。设备在下次引导后才会显示在 VM Guest 中。
--live
此选项只影响运行中的域。如果域处于非活动状态,则操作将会失败。设备不会永久保留在 XML 中,因此其下次引导后在 VM Guest 中将不可用。
--current
此选项影响域的当前状态。如果域处于非活动状态,设备将添加到永久性 XML 中,因此其下次引导后仍可用。如果域处于活动状态,则会热插入设备,但不会将其添加到永久性 XML 中。
要分离 VF 接口,请使用
virsh detach-device
命令,该命令也接受上面所列的选项。
15.9.4 动态分配池中的 VF #
如果您按照第 15.9.3 节 “将 VF 网络设备添加到 VM Guest”中所述以静态方式在 VM Guest 的配置中定义了 VF 的 PCI 地址,此类 Guest 将很难迁移到另一台主机。该主机必须在 PCI 总线上的相同位置具有相同的硬件,否则每次启动之前都必须修改 VM Guest 配置。
另一种方法是使用一个包含 SR-IOV 设备所有 VF 的设备池创建 libvirt
网络。之后,VM Guest 将引用此网络,每次 VM Guest 启动时,系统都会向它动态分配单个 VF。当 VM Guest 停止时,该 VF 将返回到池中,可供其他 Guest 使用。
15.9.4.1 在 VM 主机服务器上使用 VF 池定义网络 #
下面的网络定义示例为 SR-IOV 设备创建了一个包含所有 VF 的池,该设备的物理功能 (PF) 位于主机中的网络接口 eth0
上:
<network> <name>passthrough</name> <forward mode='hostdev' managed='yes'> <pf dev='eth0'/> </forward> </network>
要在主机上使用此网络,请将上述代码保存到文件(例如 /tmp/passthrough.xml
)中,然后执行以下命令。请记得将 eth0
替换为 SR-IOV 设备的 PF 的实际网络接口名称:
>
sudo
virsh net-define /tmp/passthrough.xml
>
sudo
virsh net-autostart passthrough
>
sudo
virsh net-start passthrough
15.9.4.2 将 VM Guest 配置为使用池中的 VF #
下面的 VM Guest 设备接口定义示例使用第 15.9.4.1 节 “在 VM 主机服务器上使用 VF 池定义网络”中为 SR-IOV 设备创建的池中的某个 VF。Guest 首次启动时,libvirt
会自动派生与该 PF 关联的所有 VF 的列表。
<interface type='network'> <source network='passthrough'> </interface>
在第一个使用以 VF 池定义的网络的 VM Guest 启动后,校验关联的 VF 列表。为此,请在主机上运行 virsh net-dumpxml passthrough
。
<network connections='1'> <name>passthrough</name> <uuid>a6a26429-d483-d4ed-3465-4436ac786437</uuid> <forward mode='hostdev' managed='yes'> <pf dev='eth0'/> <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>
15.10 列出挂接的设备 #
尽管 virsh
中没有任何机制可列出 VM 主机服务器中已挂接到其 VM Guest 的所有设备,但您可以通过运行以下命令列出已挂接到特定 VM Guest 的所有设备:
virsh dumpxml VMGUEST_NAME | xpath -e /domain/devices/hostdev
例如:
>
sudo
virsh dumpxml sles12 | -e xpath /domain/devices/hostdev Found 2 nodes: -- NODE -- <hostdev mode="subsystem" type="pci" managed="yes"> <driver name="xen" /> <source> <address domain="0x0000" bus="0x0a" slot="0x10" function="0x1" /> </source> <address type="pci" domain="0x0000" bus="0x00" slot="0x0a" function="0x0" /> </hostdev> -- NODE -- <hostdev mode="subsystem" type="pci" managed="yes"> <driver name="xen" /> <source> <address domain="0x0000" bus="0x0a" slot="0x10" function="0x2" /> </source> <address type="pci" domain="0x0000" bus="0x00" slot="0x0b" function="0x0" /> </hostdev>
<interface type='hostdev'>
挂接的 SR-IOV 设备
对于通过 <interface type='hostdev'>
挂接到 VM 主机服务器的 SR-IOV 设备,需要使用不同的 XPath 查询:
virsh dumpxml VMGUEST_NAME | xpath -e /domain/devices/interface/@type
15.11 配置储存设备 #
储存设备在 disk
元素中定义。一般的 disk
元素支持多个属性。下面是两个最重要的属性:
type
属性描述虚拟磁盘设备的来源。有效值为file
、block
、dir
、network
或volume
。device
属性指示如何向 VM Guest 操作系统公开磁盘。例如,可能的值可能包括floppy
、disk
、cdrom
等。
下面是最重要的子元素:
driver
包含驱动程序和总线。VM Guest 使用驱动程序和总线来操作新磁盘设备。target
元素包含新磁盘显示在 VM Guest 中时所用的设备名称。它还包含可选的总线属性,该属性定义用于操作新磁盘的总线的类型。
下面的过程说明如何将储存设备添加到 VM Guest:
编辑现有 VM Guest 的配置:
>
sudo
virsh edit sles15
在
disk
元素内部,连同属性type
和device
一起添加disk
元素:<disk type='file' device='disk'>
指定
driver
元素并使用默认值:<driver name='qemu' type='qcow2'/>
创建一个磁盘映像,用作新虚拟磁盘设备的来源:
>
sudo
qemu-img create -f qcow2 /var/lib/libvirt/images/sles15.qcow2 32G
添加磁盘来源的路径:
<source file='/var/lib/libvirt/images/sles15.qcow2'/>
定义 VM Guest 中的目标设备名以及用于操作磁盘的总线:
<target dev='vda' bus='virtio'/>
重启动您的 VM:
>
sudo
virsh start sles15
现在,新储存设备在 VM Guest 操作系统中应该可供使用。
15.12 配置控制器设备 #
一般情况下,libvirt
会根据 VM Guest 使用的虚拟设备类型自动管理控制器。如果 VM Guest 包含 PCI 和 SCSI 设备,libvirt 将自动创建并管理 PCI 和 SCSI 控制器。libvirt
还可为特定于超级管理程序的控制器(例如 KVM VM Guest 的 virtio-serial
控制器,或 Xen VM Guest 的 xenbus
控制器)建模。尽管默认控制器及其配置在一般情况下都可满足需求,但在某些用例中,需要手动调整控制器或其属性。例如,virtio-serial 控制器可能需要更多端口,或者 xenbus 控制器可能需要更多内存或更多虚拟中断。
Xenbus 控制器的独特之处在于,它充当着所有 Xen 半虚拟设备的控制器。如果 VM Guest 包含许多磁盘和/或网络设备,则控制器可能需要更多内存。Xen 的 max_grant_frames
属性设置要将多少授权帧或共享内存块分配给每个 VM Guest 的 xenbus
控制器。
默认值 32 在大多数情况下已够用,但包含大量 I/O 设备的 VM Guest 以及 I/O 密集型工作负载可能会由于授权帧耗尽而发生性能问题。可以使用 xen-diag
来检查 dom0 与 VM Guest 的当前和最大 max_grant_frames
值。VM Guest 必须正在运行:
>
sudo
virsh list Id Name State -------------------------------- 0 Domain-0 running 3 sle15sp1 running>
sudo
xen-diag gnttab_query_size 0 domid=0: nr_frames=1, max_nr_frames=256>
sudo
xen-diag gnttab_query_size 3 domid=3: nr_frames=3, max_nr_frames=32
sle15sp1
Guest 仅使用了 32 个帧中的 3 个。如果您发现了性能问题并且有日志项指出帧数不足,请使用 virsh
增大该值。查看 Guest 配置文件中的 <controller type='xenbus'>
行,并添加 maxGrantFrames
控制元素:
>
sudo
virsh edit sle15sp1 <controller type='xenbus' index='0' maxGrantFrames='40'/>
保存更改并重启动 Guest。现在,xen-diag 命令应该会显示您的更改:
>
sudo
xen-diag gnttab_query_size 3 domid=3: nr_frames=3, max_nr_frames=40
与 maxGrantFrames 类似,xenbus 控制器也支持 maxEventChannels
。事件通道类似于半虚拟中断,它们与授权帧共同构成半虚拟驱动程序的数据传输机制。它们还用于处理器间的中断。包含大量 vCPU 和/或许多半虚拟设备的 VM Guest 可能需要增大最大默认值 1023。可以像更改 maxGrantFrames 那样更改 maxEventChannels:
>
sudo
virsh edit sle15sp1 <controller type='xenbus' index='0' maxGrantFrames='128' maxEventChannels='2047'/>
有关详细信息,请参见 https://libvirt.org/formatdomain.html#elementsControllers 上 libvirt 的《Domain XML format》(域 XML 格式)手册中的“Controllers”(控制器)一节。
15.13 配置视频设备 #
使用虚拟机管理器时,只能定义视频设备型号。只能在 XML 配置中更改分配的 VRAM 量或 2D/3D 加速。
15.13.1 更改分配的 VRAM 量 #
编辑现有 VM Guest 的配置:
>
sudo
virsh edit sles15
更改分配的 VRAM 大小:
<video> <model type='vga' vram='65535' heads='1'> ... </model> </video>
通过查看虚拟机管理器中的数量来检查 VM 中的 VRAM 量是否已更改。
15.13.2 更改 2D/3D 加速状态 #
编辑现有 VM Guest 的配置:
>
sudo
virsh edit sles15
要启用/禁用 2D/3D 加速,请相应地更改
accel3d
和accel2d
的值:<video> <model> <acceleration accel3d='yes' accel2d='no'> </model> </video>
只有 virtio
和 vbox
视频设备支持 2D/3D 加速。无法在其他视频设备上启用此功能。
15.14 配置网络设备 #
本节介绍如何使用 virsh
配置虚拟网络设备的特定方面。
https://libvirt.org/formatdomain.html#elementsDriverBackendOptions 中提供了有关 libvirt
网络接口规范的更多细节。
15.14.1 使用多队列 virtio-net 提升网络性能 #
多队列 virtio-net 功能允许 VM Guest 的虚拟 CPU 并行传输包,因此可以提升网络性能。有关更多一般信息,请参见第 33.3.3 节 “使用多队列 virtio-net 提升网络性能”。
要为特定的 VM Guest 启用多队列 virtio-net,请遵照第 15.1 节 “编辑 VM 配置”中所述编辑其 XML 配置,并按如下所示修改其网络接口:
<interface type='network'> [...] <model type='virtio'/> <driver name='vhost' queues='NUMBER_OF_QUEUES'/> </interface>
15.15 使用 macvtap 共享 VM 主机服务器网络接口 #
使用 Macvtap 可将 VM Guest 虚拟接口直接挂接到主机网络接口。基于 macvtap 的接口扩展了 VM 主机服务器网络接口,它在相同以太网段上有自己的 MAC 地址。通常,使用此功能是为了使 VM Guest 和 VM 主机服务器都直接显示在 VM 主机服务器连接的交换机上。
Macvtap 不能与已连接到 Linux 网桥的网络接口搭配使用。在尝试创建 macvtap 接口之前,请去除网桥中的接口。
使用 macvtap 时,一个 VM Guest 可与其他多个 VM Guest 通讯,并可与网络上的其他外部主机通讯。但是,该 VM Guest 无法与用于运行它的 VM 主机服务器通讯。这是规定的 macvtap 行为,原因与 VM 主机服务器物理以太网挂接到 macvtap 网桥的方式有关。从 VM Guest 进入该网桥并转发到物理接口的流量无法回弹到 VM 主机服务器的 IP 堆栈。同样,来自 VM 主机服务器 IP 堆栈并发送到物理接口的流量无法回弹到 macvtap 网桥以转发到 VM Guest。
libvirt 通过指定接口类型 direct
支持基于 macvtap 的虚拟网络接口。例如:
<interface type='direct'> <mac address='aa:bb:cc:dd:ee:ff'/> <source dev='eth0' mode='bridge'/> <model type='virtio'/> </interface>
可以使用 mode
属性控制 macvtap 设备的操作模式。下面的列表显示了该属性的可能的值以及每个值的说明:
vepa
:将所有 VM Guest 包都发送到外部网桥。如果包的目标是某个 VM Guest,而该 VM Guest 所在的 VM 主机服务器与包的来源服务器相同,那么这些包将由支持 VEPA 的网桥(现今的网桥通常都不支持 VEPA)发回到该 VM 主机服务器。bridge
:将其目标与来源为同一 VM 主机服务器的包直接递送到目标 macvtap 设备。来源和目标设备需处于bridge
模式才能直接递送。如果其中一个设备处于vepa
模式,则需要使用支持 VEPA 的网桥。private
:将所有包都发送到外部网桥;仅当通过外部路由器或网关发送所有包,并且设备会将其发回到 VM 主机服务器时,才将所有包递送到同一 VM 主机服务器上的目标 VM Guest。如果来源或目标设备处于 private 模式,将遵循此过程。passthrough
:可为网络接口提供更强大的能力的一种特殊模式。将所有包转发到接口,并允许 virtio VM Guest 更改 MAC 地址或设置混杂模式,以桥接该接口或在该接口上创建 VLAN 接口。请注意,在passthrough
模式下,网络接口不可共享。将某个接口指派到 VM Guest 会使其与 VM 主机服务器断开连接。出于此原因,在passthrough
模式下常常会将 SR-IOV 虚拟功能指派到 VM Guest。
15.16 禁用内存气球设备 #
内存气球已成为 KVM 的默认选项。设备将显式添加到 VM Guest,因此您无需在 VM Guest 的 XML 配置中添加此元素。但是,如果您出于任何原因想要在 VM Guest 中禁用内存气球,需按如下所示设置 model='none'
:
<devices> <memballoon model='none'/> </device>
15.17 配置多个监视器(双头) #
libvirt
支持使用双头配置在多个监视器上显示 VM Guest 的视频输出。
Xen 超级管理程序不支持双头配置。
当虚拟机正在运行时,校验 xf86-video-qxl 软件包是否已安装在 VM Guest 中:
>
rpm -q xf86-video-qxl关闭 VM Guest,并按照第 15.1 节 “编辑 VM 配置”中所述开始编辑其 XML 配置。
校验虚拟显卡的型号是否为“qxl”:
<video> <model type='qxl' ... />
将显卡型号规格中的
heads
参数从默认值1
增大为2
,例如:<video> <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='2' primary='yes'/> <alias name='video0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </video>
将虚拟机配置为使用 Spice 显示器而不是 VNC:
<graphics type='spice' port='5916' autoport='yes' listen='0.0.0.0'> <listen type='address' address='0.0.0.0'/> </graphics>
启动虚拟机并使用
virt-viewer
连接到其显示器,例如:>
virt-viewer --connect qemu+ssh://USER@VM_HOST/system在 VM 列表中,选择您已修改了其配置的 VM,并单击
确认。在 VM Guest 中装载图形子系统 (Xorg) 后,选择
› › 打开一个新窗口,其中会显示第二个监视器的输出。
15.18 将 IBM Z 上的加密适配器直通到 KVM Guest #
15.18.1 简介 #
IBM Z 计算机附带加密硬件以及一些实用的功能,例如生成随机数、生成数字签名或加密。KVM 允许将这些加密适配器作为直通设备专门用于 Guest。这意味着,超级管理程序无法观察 Guest 与设备之间的通讯。
15.18.2 本章内容 #
本章介绍如何将 IBM Z 主机上的加密适配器和域专用于 KVM Guest。该过程包括以下基本步骤:
对主机上的默认驱动程序屏蔽加密适配器和域。
装载
vfio-ap
驱动程序。将加密适配器和域指派到
vfio-ap
驱动程序。将 Guest 配置为使用加密适配器。
15.18.3 要求 #
QEMU/
libvirt
虚拟化环境需已正确安装且正常运行。用于运行内核的
vfio_ap
和vfio_mdev
模块需在主机操作系统上可用。
15.18.4 将加密适配器专用于 KVM 主机 #
校验
vfio_ap
和vfio_mdev
内核模块是否已装载到主机上:>
lsmod | grep vfio_如有任何一个模块未列出,请手动装载,例如:
>
sudo
modprobe vfio_mdev在主机上创建一个新的 MDEV 设备,并校验是否已添加该设备:
uuid=$(uuidgen) $ echo ${uuid} | sudo tee /sys/devices/vfio_ap/matrix/mdev_supported_types/vfio_ap-passthrough/create dmesg | tail [...] [272197.818811] iommu: Adding device 24f952b3-03d1-4df2-9967-0d5f7d63d5f2 to group 0 [272197.818815] vfio_mdev 24f952b3-03d1-4df2-9967-0d5f7d63d5f2: MDEV: group_id = 0
识别主机逻辑分区中您要专用于 KVM Guest 的设备:
>
ls -l /sys/bus/ap/devices/ [...] lrwxrwxrwx 1 root root 0 Nov 23 03:29 00.0016 -> ../../../devices/ap/card00/00.0016/ lrwxrwxrwx 1 root root 0 Nov 23 03:29 card00 -> ../../../devices/ap/card00/在此示例中,该设备是卡
0
队列16
。为了与硬件管理控制台 (HMC) 配置相匹配,需要将十六进制数16
转换为十进制数22
。使用以下命令对
zcrypt
屏蔽适配器:>
lszcrypt CARD.DOMAIN TYPE MODE STATUS REQUEST_CNT ------------------------------------------------- 00 CEX5C CCA-Coproc online 5 00.0016 CEX5C CCA-Coproc online 5屏蔽适配器:
>
cat /sys/bus/ap/apmask 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff echo -0x0 | sudo tee /sys/bus/ap/apmask 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff屏蔽域:
>
cat /sys/bus/ap/aqmask 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff echo -0x0 | sudo tee /sys/bus/ap/aqmask 0xfffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffff将适配器 0 和域 16(十进制数 22)指派到
vfio-ap
:>
sudo
echo +0x0 > /sys/devices/vfio_ap/matrix/${uuid}/assign_adapter>
echo +0x16 | sudo tee /sys/devices/vfio_ap/matrix/${uuid}/assign_domain>
echo +0x16 | sudo tee /sys/devices/vfio_ap/matrix/${uuid}/assign_control_domain校验配置的矩阵:
>
cat /sys/devices/vfio_ap/matrix/${uuid}/matrix 00.0016创建一个新 VM(参见第 10 章 “Guest 安装”)并等待它初始化,或使用现有的 VM。对于这两种情况,请确保 VM 已关闭。
将 VM 的配置更改为使用 MDEV 设备:
>
sudo
virsh edit VM_NAME [...] <hostdev mode='subsystem' type='mdev' model='vfio-ap'> <source> <address uuid='24f952b3-03d1-4df2-9967-0d5f7d63d5f2'/> </source> </hostdev> [...]重启动 VM:
>
sudo
virsh reboot VM_NAME登录到 Guest 并校验该适配器是否存在:
>
lszcrypt CARD.DOMAIN TYPE MODE STATUS REQUEST_CNT ------------------------------------------------- 00 CEX5C CCA-Coproc online 1 00.0016 CEX5C CCA-Coproc online 1
15.18.5 更多资料 #
第 6 章 “安装虚拟化组件”中详细介绍了虚拟化组件的安装。
https://www.kernel.org/doc/Documentation/s390/vfio-ap.txt 中详细介绍了
vfio_ap
体系结构。https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1787405 中提供了一般概述和详细过程。
https://www.kernel.org/doc/html/latest/driver-api/vfio-mediated-device.html 中详细介绍了 VFIO 调解设备 (MDEV) 的体系结构。