libvirt USB 设备直通虚拟机:在线热插拔,不硬编码 domain XML

九月 01, 2026 [虚拟化与容器] #libvirt #qemu #usb

libvirt USB 设备直通虚拟机:在线热插拔,不硬编码 domain XML

背景

需要把一台 Android 手机(Pixel/Nexus,USB 连接模式为 "charging + debug",即 adb 调试)直通到本机 libvirt 虚拟机(debian13 / ubuntu26.04,均未运行)里使用。

Bus 001 Device 027: ID 18d1:4ee7 Google Inc. Nexus/Pixel Device (charging + debug)

问题来了:直通方式一旦硬编码进 domain XML(virsh edit 里的 <hostdev>),下次换手机(vendor/product 变化)就不生效,且 USB 设备不在场时 VM 启动会直接失败。有没有在线、灵活的方案?

方案:热插拔 + vendor/product 匹配,不写 domain XML

核心两点:

  1. 设备 XML 与虚拟机定义完全分离,只对运行中的 VM 生效(不 --persistent 就不落盘);
  2. 按 vendor/product 匹配,而不是 bus/device 地址——设备号(027)每次拔插都会变,vendor/product 才是稳定标识。

设备 XML 模板:

<!-- usb-device.xml -->
<hostdev mode='subsystem' type='usb' managed='yes'>
  <source>
    <vendor id='0x18d1'/>
    <product id='0x4ee7'/>
  </source>
</hostdev>

操作命令:

virsh attach-device debian13 usb-device.xml   # 热插上
virsh detach-device debian13 usb-device.xml   # 热拔下

为什么不推荐硬编码 hostdev

对比硬编码 domain XML在线 attach-device
VM 启动时设备不在场启动失败(hostdev 缺失阻止域启动)无影响,随时补插
换设备要改 domain XML(可能需关机)改设备 XML,在线生效
VM 重启后自动生效需重新 attach

硬编码方案唯一的好处是 VM 重启后自动挂载,代价是设备缺失时起不来、换设备要改定义——对「设备是可选的外设」场景不划算。

拔线之后会怎样(实测,推翻想当然)

实测环境:QEMU 10.0.8 + libvirt 11.3.0(Debian 13)。结论:物理拔线不会通知客户机。

所以正确姿势:拔线/换线后手动 detach-device 清理,不然客户机一直挂着僵尸设备:

virsh detach-device debian13 usb-device.xml   # 物理拔线后仍需显式 detach

再插回来:同样没有自动重挂——每次拔插、VM 重启后都要手动 attach-device。建议封装成一条链:

virsh start <vm> && virsh attach-device <vm> usb-device.xml

前置:普通用户操作 virsh

非 root 用户连 system libvirtd 需要授权。Debian 自带 polkit 规则 /usr/share/polkit-1/rules.d/60-libvirt.rules:libvirt 组成员免密放行 org.libvirt.unix.manage。所以只需:

sudo usermod -aG libvirt peter   # 加入 libvirt 组

总结

  1. 在线方案 = attach-device(设备 XML 独立)+ vendor/product 匹配,换设备、拔插都不动虚拟机定义;
  2. 硬编码 hostdev 的坑:设备不在场 VM 启动失败、换设备要改定义;
  3. 物理拔线不会通知客户机(实测):客户机挂着僵尸设备,需显式 detach-device 才触发客户机 udev REMOVE;
  4. 热插拔不持久,拔插、重启后都要手动 attach——脚本化一条链即可。