PCI Passthrough 实战:KVM 虚拟机网卡直通与 VFIO 性能优化指南

发布时间:2026/10/15 12:58:41
PCI Passthrough 实战:KVM 虚拟机网卡直通与 VFIO 性能优化指南 1. 从一个真实需求说起为什么要做PCI Passthrough如果你在虚拟化环境里跑过对网络延迟敏感的业务比如高频数据采集、实时音视频转发、软件定义存储的后端节点你大概率遇到过这样的尴尬虚拟机里的网卡吞吐量死活上不去CPU占用率却高得离谱。我用一台配置还不错的宿主机做过测试默认的virtio网卡在虚拟机里跑满10Gbps流量时宿主机上光中断处理就吃掉了将近四个物理核心而实际业务能拿到的有效带宽只有理论值的六成左右。这个损耗对于普通业务无所谓但对于那些要求微秒级抖动的场景基本等于不可用。PCI PassthroughPCI直通就是解决这类问题的一把利器。它的核心思路非常直接把宿主机上的一块物理PCI设备通常是一张网卡直接分配给某台虚拟机独占使用让虚拟机绕过虚拟化层的软件模拟路径直接操作硬件寄存器、直接收发数据包。这样一来数据通路从“虚拟机→虚拟网卡→宿主机内核→物理网卡”变成了“虚拟机→物理网卡”中间少了两三次内存拷贝和上下文切换延迟和CPU开销都能大幅下降。这篇文章适合谁看如果你已经对KVM的基本操作有概念知道怎么用命令行创建虚拟机、怎么配置桥接网络但还没深入折腾过设备直通那这篇内容正好补上这块。如果你是完全的新手建议先把虚拟机的常规网络模型跑通再来看不然容易在IOMMU、VFIO这些概念上卡住。我会从整体设计思路讲到具体操作再到踩过的坑尽量把每个“为什么”都说清楚。2. 整体设计思路直通不是“分个设备”那么简单2.1 直通与桥接、SR-IOV的本质区别很多人第一次接触直通会把它和桥接网络、SR-IOV混为一谈。我刚开始也这样觉得反正都是让虚拟机上网能有多大差别。实际用下来三者的定位完全不同。桥接网络是最常见的方案虚拟机通过一个虚拟网桥比如Linux bridge接入物理网络。数据包从虚拟机出来先经过虚拟网卡的前端驱动再经过后端驱动进入宿主机内核然后走网桥转发到物理网卡。这条路径上每个数据包都要经历多次内存拷贝和软中断处理。优点是配置简单、迁移方便、一台物理网卡能给多台虚拟机共享。缺点是性能损耗明显尤其是小包场景。SR-IOV是另一种思路它依赖物理网卡本身支持虚拟化功能。一张物理网卡可以虚拟出多个VFVirtual Function每个VF看起来像一张独立的轻量级PCI设备可以分配给不同的虚拟机。VF的数据通路是硬件级别的性能接近直通同时一张物理卡能服务多台虚拟机。但它对硬件有硬性要求不是所有网卡都支持而且VF的数量有限。PCI Passthrough则是把整块物理设备给一台虚拟机独占。性能上它和SR-IOV的VF路径差不多都是硬件级数据通路但它的代价是设备不能被共享一台虚拟机拿走了宿主机和其他虚拟机就用不了。所以直通更适合“一台虚拟机独占一张网卡”的场景比如专门做数据转发的节点。2.2 为什么必须要有IOMMU直通能成立的前提是硬件层面提供了IOMMUInput-Output Memory Management Unit。这个东西你可以理解成“给设备用的内存管理单元”。CPU访问内存时有MMU做地址翻译和权限检查IOMMU就是给PCI设备做同样的事情。为什么需要它因为虚拟机看到的是“假”的物理地址Guest Physical Address而设备实际要访问的是宿主机的物理地址Host Physical Address。没有IOMMU设备直接拿虚拟机的地址去访问内存轻则数据错乱重则写到别的虚拟机或者宿主机的内存区域直接把系统搞崩。IOMMU负责把设备发出的地址请求翻译成正确的宿主机物理地址同时做隔离确保设备只能访问分配给它的那块内存。所以整个直通方案的设计第一步永远是确认并开启IOMMU。Intel平台叫VT-dAMD平台叫AMD-Vi名字不同但作用一样。开启它需要在BIOS里打开对应选项同时内核启动参数里也要加上相应的开关。这一步没做对后面所有操作都是白费。2.3 VFIO用户态设备驱动的关键角色设备从宿主机“交出去”给虚拟机中间需要一个机制来接管。早期有人用pci-stub把设备从宿主机驱动上解绑但pci-stub只是让设备没人管并不能真正支持虚拟机里的完整功能。现在主流方案是VFIOVirtual Function I/O。VFIO做的事情可以这样理解它把物理设备的各种资源MMIO区域、中断、DMA安全地暴露给用户态程序虚拟机监控器QEMU/KVM就是那个用户态程序。VFIO负责保证设备被隔离只有持有对应权限的虚拟机才能操作它。同时它支持中断重映射让设备的中断能正确投递到虚拟机里而不是打到宿主机上。整个数据流大致是这样虚拟机里的驱动操作网卡寄存器这些操作通过VFIO映射的MMIO区域直接落到物理网卡上网卡收到数据包后通过DMA写入内存IOMMU确保写的是虚拟机所属的内存区域网卡产生中断中断经过重映射后被注入到虚拟机虚拟机里的驱动处理中断。整条路径上宿主机内核基本不参与数据搬运这就是性能提升的来源。3. 核心细节解析从硬件到内核的完整链路3.1 硬件与固件层面的准备先说硬件。不是所有主板和CPU都支持IOMMU。Intel这边需要CPU支持VT-d主板芯片组也要支持而且BIOS里得有开关。AMD这边需要CPU支持AMD-Vi同样主板要支持。我遇到过一些消费级主板CPU明明支持但BIOS里就是没有VT-d选项这种就只能换平台。怎么确认最直接的办法是进BIOS找。Intel平台通常叫“VT-d”或者“Intel Virtualization Technology for Directed I/O”AMD平台叫“IOMMU”或者“AMD-Vi”。有些主板把它藏在“Advanced”或者“Chipset”菜单下面需要先把虚拟化总开关打开才能看到。开启之后进系统用命令确认。Intel平台可以看/proc/cpuinfo里有没有vmx标志AMD平台看有没有svm标志。但这两个标志只说明CPU支持虚拟化不代表IOMMU已经启用。更准确的判断是看内核有没有识别到IOMMU单元dmesg | grep -i -e DMAR -e IOMMU如果看到类似“DMAR: IOMMU enabled”或者“AMD-Vi: Interrupt remapping enabled”的输出说明IOMMU已经正常工作。如果什么都没有那就要回头检查BIOS设置和内核启动参数。3.2 内核启动参数的正确配置内核启动参数是很多人容易配错的地方。Intel和AMD平台的参数不一样而且不同发行版的写法也有细微差别。Intel平台需要加intel_iommuon iommuptAMD平台需要加amd_iommuon iommupt这里的iommupt是“passthrough”模式意思是只对需要直通的设备启用IOMMU翻译其他设备走恒等映射减少性能开销。如果不加这个参数所有设备都走完整翻译虽然功能上没问题但会带来额外的性能损失。参数加在哪里主流发行版一般改/etc/default/grub里的GRUB_CMDLINE_LINUX然后更新grub配置。改完必须重启才生效。我见过有人改完不重启就急着往下做结果怎么都不成功白白浪费半天时间。重启后再用dmesg确认一次确保IOMMU真的启用了。这一步是整个方案的地基地基没打好后面全是空中楼阁。3.3 设备隔离与VFIO绑定IOMMU启用后设备是按IOMMU组IOMMU Group来隔离的。同一个组里的设备不能单独分配给不同的虚拟机因为IOMMU的最小隔离单位是组不是单个设备。这一点非常关键很多人卡在这里。为什么会有组的概念因为PCIe设备之间可能存在依赖关系比如一个PCIe桥下面挂了多个设备它们共享某些资源IOMMU没法把它们拆开单独隔离。所以如果一块网卡和别的设备分在同一个组里你要么把整组设备都直通给同一台虚拟机要么就想办法把网卡挪到独立的组里。查看IOMMU组的命令for d in /sys/kernel/iommu_groups/*/devices/*; do n${d#*/iommu_groups/*}; n${n%%/*} printf IOMMU Group %s $n lspci -nns ${d##*/} done理想情况下你要直通的网卡独占一个组。如果它和别的设备混在一起可以考虑换PCIe插槽通常靠近CPU的插槽直连CPU分组更干净。有些主板还支持在BIOS里调整PCIe的ACSAccess Control Services设置开启后能让分组更细但不是所有主板都有这个选项。确认分组没问题后就要把设备从宿主机驱动上解绑绑定到VFIO。有两种做法一种是动态绑定在虚拟机启动前手动操作另一种是静态绑定通过内核参数在启动时就指定。静态绑定更省事推荐用这种方式。先拿到设备的vendor ID和device IDlspci -nn | grep -i ethernet输出里方括号里的就是ID比如[8086:10fb]前面是vendor ID后面是device ID。然后编辑/etc/modprobe.d/vfio.confoptions vfio-pci ids8086:10fb同时要确保设备原来的驱动不会抢先加载。可以在同一个文件里加上softdep ixgbe pre: vfio-pci这里的ixgbe是网卡原来的驱动名不同网卡不一样需要根据实际情况替换。这样做的目的是让vfio-pci在原生驱动之前加载把设备抢过来。改完更新initramfs并重启update-initramfs -u -k all重启后用lspci -k确认设备使用的驱动是vfio-pci而不是原来的驱动。如果还是原来的驱动说明绑定没成功要检查ID是否写对、initramfs是否更新。4. 实操过程把网卡直通给虚拟机4.1 虚拟机XML配置的关键改动假设你用的是libvirt管理虚拟机直通设备需要在虚拟机的XML里声明。先找到设备的PCI地址lspci | grep -i ethernet输出第一列就是地址比如01:00.0。然后编辑虚拟机配置virsh edit 虚拟机名称在devices段里加入hostdev modesubsystem typepci managedyes source address domain0x0000 bus0x01 slot0x00 function0x0/ /source /hostdev这里的managedyes表示让libvirt自动处理设备的解绑和绑定省去手动操作。但前提是设备已经被vfio-pci接管否则libvirt可能会报错。如果网卡有多个function比如同时提供网络和存储功能需要把每个function都加进去。另外如果设备在IOMMU组里和其他设备共存可能还需要把同组的设备一起直通否则虚拟机启动会失败。4.2 中断重映射与MSI-X的配合现代网卡基本都用MSI-X中断这种方式比传统的中断线更高效每个队列可以有独立的中断向量。直通场景下MSI-X中断需要经过IOMMU的中断重映射才能正确投递到虚拟机。如果内核启动参数里没有启用中断重映射虚拟机里的网卡可能只能收到部分中断表现为网络时通时断、吞吐量上不去。确认中断重映射是否启用的方法dmesg | grep -i interrupt remapping看到“enabled”就没问题。如果显示“disabled”需要在启动参数里加上intremapon。不过大多数现代内核默认就是开启的只要IOMMU正常启用中断重映射一般也会跟着启用。还有一个细节虚拟机里的网卡驱动要支持MSI-X。Linux内核的主流网卡驱动都支持但如果你用的是比较老的系统或者特殊的驱动可能需要手动确认。可以在虚拟机里用lspci -vv看设备的Capabilities里有没有MSI-X以及是否处于Enabled状态。4.3 虚拟机内部的网络配置设备直通进去之后虚拟机里会看到一张“真实”的物理网卡而不是virtio那种虚拟设备。这时候网络配置的方式和物理机完全一样可以用DHCP也可以配静态IP。但有一个坑要注意如果你之前用virtio网卡配好了网络直通之后网卡的名称可能会变比如从ens3变成ens5或者enp1s0。因为网卡的MAC地址变了系统的网络配置可能对不上。解决办法是进虚拟机后用ip link看实际网卡名然后更新网络配置文件。另外直通网卡的MAC地址是物理网卡的真实MAC如果你在多台虚拟机之间做网络规划要注意MAC地址不要冲突。有些场景下可能需要修改MAC但物理网卡的MAC能不能改取决于驱动和硬件不是所有网卡都支持。4.4 性能验证与对比测试配好之后一定要做性能验证不然你不知道直通到底有没有生效。最简单的办法是在虚拟机和另一台机器之间跑iperf3对比直通前后的吞吐量和CPU占用。我自己的测试环境里同样一张10G网卡virtio模式下虚拟机跑到6Gbps左右CPU就快满了换成直通之后轻松跑到9.5Gbps而且宿主机CPU占用几乎为零。延迟方面用ping -f打小包virtio模式下平均延迟在200微秒左右直通之后降到80微秒上下。这个差距在高频交易或者实时转发场景里是决定性的。测试的时候要注意两端都要用足够强的硬件不然瓶颈可能不在网卡上。另外测试前确认虚拟机的CPU亲和性设置合理避免因为CPU调度导致数据波动。5. 常见问题与排查技巧实录5.1 虚拟机启动报错“Device is in use”这是最常见的问题通常是因为设备还被宿主机驱动占着。排查步骤用lspci -k确认设备当前使用的驱动。如果是原生驱动而不是vfio-pci说明绑定没成功。检查/etc/modprobe.d/vfio.conf里的ID是否正确注意vendor ID和device ID的顺序不能反。确认initramfs已经更新并且重启过。如果用的是动态绑定确认在启动虚拟机前已经执行了解绑操作。还有一种可能是设备在IOMMU组里和其他设备共享而其他设备还在被宿主机使用。这种情况下要么把同组设备一起直通要么调整硬件布局。5.2 直通后网络不通或时断时续网络不通的原因很多按这个顺序排查虚拟机里ip link能不能看到网卡看不到说明直通没成功回宿主机检查XML配置。网卡是UP状态吗ip link set 网卡名 up手动拉起来试试。有没有拿到IPdhclient 网卡名手动获取试试。能ping通网关吗不通的话检查虚拟机的路由表和宿主机的网络配置。时断时续的话重点查中断重映射和MSI-X参考4.2节的排查方法。我遇到过一次诡异的情况网卡直通后能通但跑大流量几分钟就断。最后发现是网卡的固件版本太老有DMA相关的bug升级固件后解决。所以如果软件层面都排查完了还是有问题不妨看看固件版本。5.3 宿主机无法使用被直通的网卡这是直通的固有特性设备被虚拟机独占后宿主机就看不到了。如果你需要宿主机和虚拟机同时使用网络直通不是正确方案应该考虑SR-IOV或者多网卡方案。有些场景下你可能希望虚拟机不用的时候把网卡还给宿主机。这需要动态解绑和重新绑定操作比较繁琐而且容易出错。我的建议是规划好硬件用途直通的网卡就专门给虚拟机用宿主机用另外的网卡管理。5.4 虚拟机迁移的限制直通设备绑定了具体的物理硬件所以虚拟机没法在线迁移到另一台宿主机除非目标宿主机有完全相同的设备。这是直通方案最大的局限性之一。如果你的业务需要频繁迁移要么接受迁移时断开直通设备要么改用SR-IOV配合支持迁移的方案。libvirt在迁移时会检查直通设备如果目标主机没有对应设备迁移会直接失败。可以在迁移前手动把hostdev从XML里移除迁移后再加回去但这样网络会中断。对于高可用要求高的场景这个方案需要仔细权衡。问题现象可能原因排查命令解决方向虚拟机启动失败提示设备被占用设备未绑定vfio-pcilspci -k检查vfio配置和initramfs网卡在虚拟机里看不到XML配置错误或IOMMU组冲突virsh dumpxml核对PCI地址和同组设备网络时断时续中断重映射未启用dmesg | grep remapping检查内核启动参数吞吐量不达标MSI-X未启用或队列数不足ethtool -l调整队列数和中断亲和迁移失败目标主机无相同设备virsh migrate日志迁移前移除hostdev5.5 几个容易被忽略的实操心得第一直通网卡的中断亲和性可以在虚拟机里调整。默认情况下中断可能都落在同一个vCPU上成为瓶颈。可以在虚拟机里用/proc/interrupts看中断分布然后通过/proc/irq/编号/smp_affinity把不同队列的中断分散到不同vCPU。第二如果网卡支持多队列记得在虚拟机里把队列数调够。默认可能只开了一两个队列发挥不出硬件性能。用ethtool -L 网卡名 combined 数量调整具体上限看驱动和硬件。第三大页内存对直通性能有正面影响。虚拟机内存用大页hugepages而不是普通4K页能减少TLB miss对高吞吐场景有帮助。配置方法是在宿主机预留大页然后在虚拟机XML里指定使用大页。第四直通设备的电源管理要关掉。有些网卡默认开启ASPMActive State Power Management在直通场景下可能导致链路不稳定。可以在宿主机上用setpci关闭ASPM或者在BIOS里直接禁用PCIe电源管理。6. 方案选型与扩展思考6.1 什么场景该选直通什么场景不该直通最适合的场景有几个特征对延迟和吞吐要求高、虚拟机数量少、不需要频繁迁移、硬件资源充足。比如做网络功能虚拟化NFV的转发节点、做存储后端的iSCSI或NVMe-oF目标端、做实时数据采集的边缘节点这些场景下直通的收益非常明显。反过来如果你的场景是跑一堆轻量级虚拟机、需要灵活迁移、硬件资源紧张那直通就不合适。这种情况下virtio或者SR-IOV更合适。virtio胜在通用和灵活SR-IOV胜在性能和共享的平衡。我个人的经验是先跑通virtio确认业务逻辑没问题再评估性能瓶颈在哪里。如果瓶颈确实在网络上而且直通的硬件条件具备再上直通。不要一上来就折腾直通容易在环境准备阶段就耗尽耐心。6.2 从直通到SR-IOV的演进路径如果你发现直通不够用比如一台宿主机上要跑多台需要高性能网络的虚拟机那就要考虑SR-IOV。SR-IOV的配置比直通复杂一些需要在物理网卡上开启VF然后把VF分配给虚拟机。但它的优势是VF可以共享物理网卡的上行带宽而且VF的数量通常比物理网卡多。从直通过渡到SR-IOV硬件上需要网卡支持SR-IOV软件上需要确认驱动支持VF的创建和管理。配置思路和直通类似也是通过VFIO把VF绑定给虚拟机但设备发现和分配的方式不同。如果你已经掌握了直通SR-IOV的学习曲线会平缓很多。6.3 容器场景下的设备直通虽然这篇文章主要讲虚拟机但设备直通在容器场景下也有应用。比如把一张网卡直通给一个容器让容器直接操作硬件。这种场景下通常用DPDK或者类似的用户态驱动框架配合VFIO把设备映射到容器的用户态空间。容器直通和虚拟机直通的原理相通都是通过VFIO把设备交给用户态程序。区别在于容器没有硬件虚拟化层设备的中断和DMA直接由容器内的进程处理。这种方案适合对性能要求极高的网络功能比如用户态的数据包处理。但它的隔离性不如虚拟机配置也更复杂需要根据具体场景权衡。6.4 一些值得关注的细节直通设备的ROM BAR有时候会引起问题。某些网卡的Option ROM在直通后可能导致虚拟机启动卡住可以在XML里加上rom baroff/来禁用ROM映射。这个细节在文档里很少提但实际遇到的时候很让人头疼。另外如果宿主机用的是较新的内核VFIO的稳定性和功能都会更好。老内核可能在中断重映射或者设备隔离上有已知问题。如果条件允许尽量用较新的长期支持版本内核。还有一点直通设备的错误处理要提前规划。如果虚拟机崩溃或者被强制关闭设备可能处于不确定状态需要重新绑定才能恢复。可以写个简单的脚本在虚拟机停止后自动把设备重新绑定到vfio-pci避免下次启动时出问题。我在实际使用中最大的体会是直通这个方案“配起来麻烦用起来省心”。前期在IOMMU、VFIO、分组这些环节可能要折腾几个小时甚至几天但一旦跑通后续的稳定性非常好基本不用再管。所以如果你决定走这条路前期多花点时间把每个环节确认清楚比后面出了问题再回头排查要划算得多。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询