使用libvirt和qemu将pci pass through设备添加到虚拟机上

本文详细介绍如何使用libvirt和qemu实现PCI设备透传至虚拟机的过程,并解决透传过程中遇到的常见问题,如No IOMMU found及SELinux限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

透传的优势

guest使用透传设备可以获得设备近乎原生的性能,

PCI pass-throught设备给动态迁移带来的问题, dest host可能没有同样的硬件.

就算可以模拟一个设备,但是原始设备的内部状态不能获得.

VT-d support

In order to assign devices in KVM, you’ll need a system which supports VT-d. This has nothing to do with the VT-x support of your CPU, VT-d needs to be supported by both your chipset on your motherboard and by your CPU.

If you are in doubt whether your motherboard or CPU supports VT-d or not, the Xen VT-d wikipage has some pointers of VT-d enabled chipsets, motherboards and CPUs: http://wiki.xensource.com/xenwiki/VTdHowTo

If your hardware doesn’t have an IOMMU (“Intel VT-d” support in case of Intel – “AMD I/O Virtualization Technology” support in case of AMD), you’ll not be able to assign devices in KVM. Some work towards allowing this were done, but the code never made it into KVM, due to various issues with the code. At the moment it doesn’t seem like device assignment without hardware support, will ever be integrated into KVM.

Assignment of graphics cards are not officially supported at the moment, but there has been some success passing through a secondary Radeon HD 5850 as a VM’s secondary display.

资料:http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM

在host选择PCI pass through设备

reboot and verify that your system has IOMMU support

AMD Machine

1
2
3
4
5
6
dmesg | grep AMD-Vi
  ...
  AMD-Vi: Enabling IOMMU at 0000:00:00.2 cap 0x40
  AMD-Vi: Lazy IO/TLB flushing enabled
  AMD-Vi: Initialized for Passthrough Mode
  ...

Intel Machine

1
2
3
4
5
dmesg | grep -e DMAR -e IOMMU
...
DMAR:DRHD base: 0x000000feb03000 flags: 0x0
IOMMU feb03000: ver 1:0 cap c9008020e30260 ecap 1000
...

If you get no output you’ll need to fix this before moving on. Check if your hardware supports VT-d and check that it has been enabled in BIOS.

NOTE: If you still get an error “No IOMMU found.” Check dmesg for errors suggesting your BIOS is broken. Another possible reason: CONFIG_DMAR_DEFAULT_ON is not set. In that case, pass “intel_iommu=on” as kernel parameter to enable it. AMD uses different kernel parameter than Intel, on AMD you need to pass “iommu=pt iommu=1”.

请看附录:No IOMMU found 解决

选择要使用的透传设备

1
2
3
4
5
6
# lspci -nn
00:00.0 Host bridge [0600]: Intel Corporation 2nd Generation Core Processor Family DRAM Controller [8086:0100] (rev 09)
......
00:1b.0 Audio device [0403]: Intel Corporation 6 Series/C200 Series Chipset Family High Definition Audio Controller [8086:1c20] (rev 04)
.....
00:1f.3 SMBus [0c05]: Intel Corporation 6 Series/C200 Series Chipset Family SMBus Controller [8086:1c22] (rev 04)

友情提示:使用透传设备时,拿USB控制器作实验,可能鼠标键盘不能使用.请谨慎.

将设备从宿主机上解除绑定

使用echo命令,将设备从host机器上解除绑定,将来用于guest机器. For example:

1
2
3
echo "8086 1c20" > /sys/bus/pci/drivers/pci-stub/new_id
echo 0000:00:1b.0 > /sys/bus/pci/devices/0000:00:1b.0/driver/unbind
echo 0000:00:1b.0 > /sys/bus/pci/drivers/pci-stub/bind

关闭虚拟机

关闭虚拟机,修改配置文件.

使用libvirt进行pci pass through

修改虚拟机配置文件

1
2
3
4
5
6
7
<devices> …
     <hostdev mode='subsystem' type='pci' managed='yes'>
       <source>
          <address domain='0x000' bus='0x00′ slot='0x1b' function='0x0' />
       </source>
    </hostdev>
</devices>

在修改完虚拟机配置文件后,运行虚拟机.

使用qemu进行pci pass through

使用qemu进行pci pass through也是一样的简单的.我们需要一个已经创建好操作系统的虚拟机.

在qemu命令行运行以下命令以启动虚拟机

1
2
3
4
5
/usr/bin/qemu-kvm -name vdisk - enable -kvm -m 512 -smp 2 \
-hda /mnt/nfs/vdisk .img \
-monitor stdio \
-vnc 0.0.0.0:0 \
-device pci-assign,host=00:1b.0

这样就将设备挂载到虚拟机上了.

  • 参数-device pci-assign,host=00:1b.0说的是使用一个pci设备,并提供一个设备的地址.
  • 参数-monitor stdio是使用一个标准的控制台输出.在命令行中进行输入命令,等等迁移的时候也在这里输入命令.

附录1:No IOMMU found 解决

启动虚拟机的时候出现了iommu的问题.以供大家参考

1.查看错误日志说明

在配置好XML文件后,启动虚拟机,遇到一个问题.

error: Failed to start domain vdisk
error: Unable to read from monitor: Connection reset by peer

查看虚拟机日志( cat /var/log/libvirt/qemu/vdisk.log )信息.

char device redirected to /dev/pts/3
No IOMMU found. Unable to assign device "hostdev0"
qemu-system-x86_64: -device pci-assign,configfd=20,host=00:1b.0,id=hostdev0,bus=pci.0,addr=0x4: Device 'pci-assign' could not be initialized
2013-07-08 06:41:23.256+0000: shutting down

上网查阅资料,说是要在BIOS上设置虚拟化,然后在引导程序里也要设置iommu.可以查看一下自己的电脑信息是否开启了.

2.查看信息gurb的引导信息

1
2
# cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-3.9.6-200.fc18.x86_64 root=/dev/mapper/fedora-home ro rd.lvm.lv=fedora/swap rd.md=0 rd.dm=0 rd.lvm.lv=fedora/home rd.luks=0 vconsole.keymap=us rhgb quiet LANG=en_US.UTF-8

可以发现,我的还未开启intel_iommu=on选项.所以接下来我们来激活它.

3.激活intel_iommu=on

Activate Intel VT-d in the kernel

Activate Intel VT-d in the kernel by appending the intel_iommu=on parameter to the kernel line of the kernel line in the/boot/grub/grub.conf file. The example below is a modified grub.conf file with Intel VT-d activated.

对于intel的cpu和amd的cpu,在grub配置上是不同的,具体的配置请参考文章:http://pve.proxmox.com/wiki/Pci_passthrough

4.更新grub

在编辑完grub文件后,需要更新

1
2
grub2-mkconfig   # fedora arch centos
update-grub            # ubuntu debian

5.重启电脑,使其生效

1
2
# cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-3.9.6-200.fc18.x86_64 root=/dev/mapper/fedora-home ro rd.lvm.lv=fedora/swap rd.md=0 rd.dm=0 rd.lvm.lv=fedora/home rd.luks=0 vconsole.keymap=us rhgb quiet intel_iommu=on LANG=en_US.UTF-8

发现开机已经启动了inte _iommu=on了.再次启动虚拟机已经就不会出现这个bug了.

附录2 PCI pass through 失败要关闭SELinux

我用的是Fedora 18 ,将SELinux给disalbed了,但是发现PCI pass through出先问题.上网看到文章PCI passthrough fails in qemu-kvm unless selinux is disabled 说,要将selinux设置成permissive模式,于是这个问题解决了.

参考资料

声明:未经允许禁止转载 东东东 陈煜东的博客 文章,谢谢。如经授权,转载请注明: 转载自东东东 陈煜东的博客

本文链接地址: 使用libvirt和qemu将pci pass through设备添加到虚拟机上 – https://www.chenyudong.com/archives/add-pci-pass-through-device-to-guest-vm-with-libvirt-and-qemu.html

<think>我们正在使用libvirt 6.9.1.1版本,需要将PCI设备绑定到NUMA节点。在libvirt中,这通常通过虚拟机的XML配置中的`<numatune>``<memory>`设置以及设备的位置(通过`<iommu>`或`<address>`)来实现。但是,对于PCI设备,我们需要确保设备与正确的NUMA节点关联,尤其是在多NUMA系统中,以避免跨节点访问导致性能下降。 步骤: 1. 确定PCI设备的NUMA节点 2. 在虚拟机XML配置中设置NUMA节点绑定 3. 配置虚拟机的内存绑定到相同的NUMA节点(可选,但推荐) 详细步骤: 步骤1:确定PCI设备的NUMA节点 使用`lspci``lstopo`等工具确定PCI设备所在的NUMA节点。 例如,使用以下命令查看PCI设备(比如设备地址为0000:61:00.0)的NUMA节点: ```bash lspci -s 61:00.0 -v | grep NUMA ``` 或者使用: ```bash cat /sys/bus/pci/devices/0000:61:00.0/numa_node ``` 注意:如果返回-1,表示设备不属于任何NUMA节点(可能是主板设备),或者系统不支持。否则,返回的是NUMA节点编号(从0开始)。 步骤2:配置虚拟机的NUMA节点绑定 在虚拟机的XML配置中,使用`<numatune>``<memory>`元素来设置内存的NUMA绑定。同时,对于PCI设备,我们通常不需要在设备上直接指定NUMA节点,因为设备的位置已经由物理硬件决定。但是,我们可以通过将虚拟机的CPU内存绑定到与PCI设备相同的NUMA节点来优化性能。 示例XML配置: ```xml <domain type='kvm'> ... <cpu mode='host-passthrough' check='none'> <numa> <cell id='0' cpus='0-7' memory='512000' unit='KiB'/> <cell id='1' cpus='8-15' memory='512000' unit='KiB'/> </numa> </cpu> <numatune> <memory mode='strict' nodeset='1'/> </numatune> ... <devices> <hostdev mode='subsystem' type='pci' managed='yes'> <source> <address domain='0x0000' bus='0x61' slot='0x00' function='0x0'/> </source> </hosthostdev> </devices> </domain> ``` 在上面的例子中,我们将虚拟机的内存绑定到NUMA节点1(通过`<numatune>`),并且假设我们的PCI设备(0000:61:00.0)位于NUMA节点1。同时,我们在`<cpu>`元素中定义了NUMA拓扑,将虚拟CPU0-7分配给节点0,8-15分配给节点1,并且每个节点分配512MB内存。 注意:如果虚拟机需要访问多个NUMA节点,可以在`<numatune>`的`nodeset`中指定多个节点,如`nodeset='0,1'`,并使用`interleave`模式等。但是,为了获得最佳性能,通常建议将设备、内存vCPU绑定到同一个NUMA节点。 步骤3:验证绑定 启动虚拟机后,可以在虚拟机内部使用诸如`numactl -H`的命令来查看内存分配情况,并确保设备中断处理在正确的CPU上(通过检查`/proc/interrupts`)。 另外,在宿主机上,可以使用以下命令检查虚拟机的内存绑定: ```bash virsh numatune <vm_name> ``` 以及使用以下命令查看虚拟机的vCPU与物理CPU的绑定(即CPU亲性): ```bash virsh vcpuinfo <vm_name> ``` 注意:在libvirt 6.9.1.1中,还支持更精细的调整,例如通过`<iothreads>``<emulatorpin>`将I/O线程模拟器线程绑定到特定的CPU上。 高级配置:如果希望将整个虚拟机(包括模拟器)绑定到特定的NUMA节点,可以使用`<vcpu>``<cputune>`来设置CPU亲性,并将模拟器线程绑定到与PCI设备相同的NUMA节点上的CPU。 示例: ```xml <cputune> <vcpupin vcpu='0' cpuset='8'/> <vcpupin vcpu='1' cpuset='9'/> ... <emulatorpin cpuset='8-15'/> </cputune> ``` 这里将vCPU0绑定到物理CPU8,vCPU1绑定到物理CPU9,模拟器线程绑定到8-15(这些物理CPU属于NUMA节点1)。 相关问题: 1. 如何检查PCI设备的NUMA节点归属? 2. 在libvirt中如何配置多个NUMA节点的内存绑定? 3. 如何验证虚拟机内的内存分配是否符合NUMA绑定? 4. 在配置NUMA绑定时,如何避免内存分配失败? 5. 如何将虚拟机的I/O线程绑定到特定的CPU核心? 6. 在跨NUMA节点使用PCI设备时,性能影响有多大? 7. 如何配置libvirt使用巨页(Huge Pages)并绑定到NUMA节点?</think>### Libvirt 6.9.1.1 PCI设备绑定NUMA节点配置指南 #### 🔧 核心配置步骤 1. **定位PCI设备与NUMA节点关系** ```bash # 查看PCI设备拓扑 $ lspci -nn | grep -i "设备名" # 如 NVIDIA/Intel 0000:61:00.0 VGA [0300]: NVIDIA Corporation GA102 [GeForce RTX 3090] [10de:2204] # 获取NUMA节点信息 $ cat /sys/bus/pci/devices/0000\:61\:00.0/numa_node 1 # 输出为NUMA节点ID ``` 2. **编辑虚拟机XML配置** ```xml <domain type='kvm'> <cpu mode='host-passthrough' check='none'> <numa> <cell id='0' cpus='0-7' memory='2097152' unit='KiB'/> <cell id='1' cpus='8-15' memory='2097152' unit='KiB'/> </numa> </cpu> <numatune> <memory mode='strict' nodeset='1'/> <!-- 绑定到节点1 --> </numatune> <devices> <hostdev mode='subsystem' type='pci' managed='yes'> <source> <address domain='0x0000' bus='0x61' slot='0x00' function='0x0'/> </source> <!-- NUMA绑定声明 --> <address type='pci' domain='0x0000' bus='0x00' slot='0x10' function='0x0'/> </hostdev> </devices> </domain> ``` 3. **关键参数说明** - `<numatune>`: 定义内存绑定策略 - `strict`: 严格限制内存分配在指定节点 - `preferred`: 优先但非强制 - `<cell>`: NUMA节点定义 - `id`: 节点ID (需与物理节点一致) - `cpus`: 绑定的CPU核心 - `memory`: 分配内存大小 (单位KiB/MiB/GiB) - PCI设备地址格式: `domain:bus:slot.function` #### ⚙️ 高级优化配置 1. **CPU与内存协同绑定** ```xml <cputune> <vcpupin vcpu='0' cpuset='8'/> <!-- vCPU0绑定物理CPU8 --> <vcpupin vcpu='1' cpuset='9'/> <!-- vCPU1绑定物理CPU9 --> <emulatorpin cpuset='8-15'/> <!-- QEMU进程绑定 --> </cputune> ``` 2. **巨页内存优化** ```xml <memoryBacking> <hugepages> <page size='1048576' unit='KiB' nodeset='1'/> <!-- 1GiB巨页 --> </hugepages> </memoryBacking> ``` 3. **IOThreads绑定** ```xml <iothreads>4</iothreads> <!-- 启用4个IO线程 --> <iothreadids> <iothread id='1' thread_pool_min='2' thread_pool_max='4'/> </iothreadids> ``` #### ✅ 验证配置 1. **虚拟机内部验证** ```bash $ numactl -H available: 1 nodes (1) # 应只看到绑定的节点 node 1 cpus: 0 1 2 3 node 1 size: 8192 MB ``` 2. **宿主机性能监控** ```bash # 查看QEMU进程绑定 $ ps -eLo pid,tid,psr,args | grep qemu | grep -v grep 12345 12346 8 qemu-system-x86_64 ... # PSR列显示CPU核心 # NUMA内存分配统计 $ numastat -p <qemu_pid> Per-node process memory usage (in MBs) PID Node 0 Node 1 Total ------- ------ ------ ----- 12345 0.0 8192.0 8192.0 ``` #### ⚠️ 常见问题处理 1. **PCI设备未出现在预期节点** - 解决方案:检查ACPI表 ```bash $ dmesg | grep -i acpi | grep -i numa ACPI: SRAT: Node 0 PXM 0 [mem 0x00000000-0x3fffffff] ACPI: SRAT: Node 1 PXM 1 [mem 0x40000000-0x7fffffff] ``` 2. **内存分配失败错误** ```log error: internal error: process exited while connecting to monitor: cannot set up guest memory 'pc.ram': Cannot allocate memory ``` - 修复:验证节点内存容量 ```bash $ virsh freecell --all # 查看NUMA节点可用内存 ``` 3. **性能未达预期** - 使用`perf`分析延迟: ```bash $ perf stat -e numa_migrations,local_loads,local_stores virsh start <vm> ``` #### 📌 最佳实践建议 1. **拓扑一致性原则** PCI设备、vCPU、内存分配应遵循物理拓扑: $$ \text{物理NUMA节点} \leftrightarrow \text{虚拟NUMA节点} \leftrightarrow \text{PCI设备位置} $$ 2. **中断亲性设置** 对于高性能场景,手动分配设备中断: ```bash $ echo "8-15" > /proc/irq/<irq_num>/smp_affinity_list ``` 3. **冷热页面优化** 在Linux客户机中启用自动NUMA平衡: ```bash $ echo 1 > /proc/sys/kernel/numa_balancing ``` --- ### 相关问题 1. 如何验证PCI设备的NUMA节点归属是否正确?[^1] 2. Libvirt 6.9.1.1中跨NUMA节点访问的性能影响如何量化? 3. 配置NUMA绑定后虚拟机启动失败的可能原因有哪些? 4. 如何为SR-IOV VF设备配置NUMA亲性? 5. Libvirt的NUMA绑定与cgroup v2如何协同工作?[^2] 6. Windows虚拟机是否支持NUMA设备绑定? 7. 在Kubernetes中如何通过libvirt实现NUMA感知的PCI设备分配? [^1]: 需结合ACPI SRAT表物理拓扑验证 [^2]: 需检查cpuset控制器集成状态
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值