HOOOS

拒绝重启:KVM 虚拟机 SR-IOV 直通极速网络与网卡热插拔实战

0 5 网路架构师 KVMSR-IOV热插拔
Apple

在高性能计算、低延迟网络传输(如金融交易、电信网元 NFV)等场景下,普通的 VirtIO 虚拟网卡即使开启了 vhost-net,也无法满足极致的吞吐和延迟要求。**SR-IOV(Single Root I/O Virtualization)**技术通过将物理网卡虚拟出多个独立的 PCIe 虚拟通道(VF, Virtual Function),直接透传给虚拟机(VM),能提供接近物理硬件的裸金属级网络性能。

然而,传统的 PCI 直通通常需要在虚拟机关机状态下配置。如何在生产环境下不中断业务、不重启虚机,动态地将 SR-IOV 网卡热插、热拔?

下面将从宿主机配置、XML 定义、动态热插拔操作及避坑指南四个维度,给出完整的实战方案。


一、 准备工作:宿主机开启 IOMMU 与创建 VF

在进行热插拔之前,必须确保宿主机内核已启用 IOMMU,且物理网卡已经生成了虚拟函数(VF)。

1. 开启 IOMMU(以 Intel CPU 为例)

编辑宿主机的 Grub 配置文件 /etc/default/grub,在 GRUB_CMDLINE_LINUX 中追加:

intel_iommu=on iommu=pt

更新 Grub 并重启宿主机生效:

# CentOS/RHEL/Fedora
grub2-mkconfig -o /boot/grub2/grub.cfg

# Ubuntu/Debian
update-grub
reboot

重启后验证 IOMMU 是否正常启用:

dmesg | grep -i iommu
# 输出中应包含 "IOMMU enabled" 或 "Adding to iommu group" 相关字样

2. 生成物理网卡的 VF

假设宿主机的 10G/25G 物理网卡接口名为 ens1f0
执行以下命令启用 4 个 VF:

echo 4 > /sys/class/net/ens1f0/device/sriov_numvfs

验证 VF 是否生成成功:

ip link show ens1f0

如果输出中看到 vf 0 MAC 00:00:00:00:00:00... 等多行 VF 信息,说明生成成功。

注意:上述 echo 写入 sysfs 的方式在宿主机重启后会失效。建议将该命令写入 /etc/rc.local,或者通过 Netplan/ifupdown 脚本进行持久化配置。


二、 确定待热插拔的 VF PCI 地址

我们需要通过 lspci 找到刚才生成的 VF 的 PCI 总线地址。

lspci -D | grep -i "Virtual Function"

输出示例:

0000:04:10.0 Ethernet controller: Intel Corporation Ethernet Virtual Function 700 Series (rev 02)
0000:04:10.1 Ethernet controller: Intel Corporation Ethernet Virtual Function 700 Series (rev 02)
0000:04:10.2 Ethernet controller: Intel Corporation Ethernet Virtual Function 700 Series (rev 02)
0000:04:10.3 Ethernet controller: Intel Corporation Ethernet Virtual Function 700 Series (rev 02)

我们选择使用第一个 VF,其 PCI 地址为 0000:04:10.0


三、 配置 XML 模板(避坑关键:用 interface 还是 hostdev?)

在 KVM (libvirt) 中,直通 PCI 设备有两种 XML 定义方式:

  1. <hostdev>:通用 PCI 直通。
  2. <interface type='hostdev'>专为网络设备设计的直通

强烈建议使用第二种 <interface type='hostdev'>
因为通过 <interface> 方式,Libvirt 可以在宿主机侧帮我们集中管理虚拟机的 MAC 地址、VLAN tag 以及 IP 链路状态(Link State)。如果是纯 <hostdev>,虚拟机会随机生成 MAC 地址,甚至在热插拔后由于 MAC 地址变更导致网络不通。

新建一个临时配置文件 sriov-vf.xml

<interface type='hostdev' managed='yes'>
  <!-- 宿主机上该 VF 的物理驱动,通常为 vfio -->
  <driver name='vfio'/>
  <!-- 指定该 VF 对应的物理网卡 PCI 地址 -->
  <source>
    <address type='pci' domain='0x0000' bus='0x04' slot='0x10' function='0x0'/>
  </source>
  <!-- 预先规划好直通给 VM 后的 MAC 地址,防止热插拔后随机漂移 -->
  <mac address='52:54:00:fa:19:bc'/>
  <!-- 如果有 VLAN 需求,可在此定义,没有则删掉下面这一行 -->
  <vlan><tag id='100'/></vlan>
</interface>

四、 零下行动态热插拔操作

假设我们要操作的虚拟机名称(Domain Name)为 prod-web-vm

1. 动态热插(Attach)

在不关闭虚拟机的情况下,执行以下命令将 VF 动态挂载到虚机中:

virsh attach-device prod-web-vm sriov-vf.xml --live --config
  • --live:立即生效(作用于当前运行中的虚机内存)。
  • --config:将配置写入虚机的 XML 配置文件中,确保虚机下一次重启后,该网卡依然存在。

验证热插结果:
登录到虚拟机内部,执行以下命令查看网卡是否已上线:

# 1. 检查 PCI 设备列表中是否出现新网卡
lspci | grep -i ether

# 2. 检查网卡接口
ip link show

此时会发现多出一个类似 eth1enp0s8 的新接口。由于指定了 MAC 地址,该接口会自动获取 IP 启动业务。

2. 动态热拔(Detach)

当需要对宿主机硬件进行维护,或者需要将该 VF 回收给其他虚机时,可以进行动态热拔。

安全避坑第一步:在热拔前,建议在虚拟机内部先将该网卡接口 Down 掉,避免虚拟机内核或业务应用因底层 PCI 设备瞬间消失而产生死锁或报错。
在虚机内部执行:

ip link set dev eth1 down

然后在宿主机上执行热拔命令:

virsh detach-device prod-web-vm sriov-vf.xml --live --config
  • --live:立即从当前运行的虚机中剥离该设备。
  • --config:同步更新虚机的 XML 配置,防止下次启动时再去寻找该 PCI 设备。

在虚拟机内部再次执行 lspciip link,会发现该网卡已无损、平滑地消失。


五、 高可用进阶:SR-IOV 与 VirtIO 的 Active-Backup 双网卡绑定(Bonding)

SR-IOV 直通虽然性能强悍,但带来了一个致命缺陷:无法进行虚拟机热迁移(Live Migration)。因为物理网卡的硬件状态无法在网络中传输。

为了兼顾“平时跑 SR-IOV 享受极速网络”与“维护时支持热迁移”,业界通用的解决方案是在虚机内部配置 Active-Backup 模式的 Bonding

  1. 虚机配置两张网卡:
    • eth0:标准的 VirtIO 网卡(走 OVS/Linux Bridge,支持热迁移)。
    • eth1:直通的 SR-IOV VF 网卡(动态热插拔)。
  2. 在虚机内创建主备 Bond(如使用 bond0 采用 mode 1 主备模式):
    • eth1(SR-IOV)设为主设备(Primary),平时所有业务流量走 SR-IOV,延迟极低。
    • eth0(VirtIO)设为备份设备。
  3. 当需要对宿主机进行维护需要热迁移虚机时:
    • 在宿主机执行 virsh detach-device 动态热拔移除 SR-IOV 网卡。
    • 虚机内核检测到 eth1 消失,流量无缝切换到 eth0(VirtIO),业务不中断。
    • 执行虚拟机热迁移到新宿主机。
    • 在新宿主机上,动态热插新主机的 SR-IOV VF 网卡,流量再次切回主设备。

通过这种“硬直通 + 软虚拟化”的双网卡联动架构,可以在保障 99.99% 高可用的同时,压榨出物理网卡的最后一滴性能。

点评评价

captcha
健康