E.2. 修正到 IOMMU 组
IOMMU 组被定义为可从 IOMMU 的角度来隔离的最小设备集合。实现隔离的第一步是进行粒度。如果 IOMMU 无法将设备区分到单独的 IOVA 空间,它们不会被隔离。例如,如果多个设备试图别名到同一 IOVA 空间,IOMMU 将无法区分它们。这就是为什么典型的 x86 PC 将将所有传统-PCI 设备分组到一起,它们的所有别名都别名化到同一请求者 ID( PCIe-to-PCI 网桥)。旧的 KVM 设备分配允许用户单独分配这些传统-PCI 设备,但配置会失败,因为 IOMMU 无法区分设备。因为 VFIO 受 IOMMU 组管理,它可防止任何违反了此最基本的粒度的配置。
下一步是确定该设备的事务是否实际到达 IOMMU。PCIe 规范允许在互连结构内重新路由事务。PCIe downstream 端口可以从一个下游设备重新路由到另一个事务。PCIe 交换机的下游端口可以互连,以允许从一个端口重新路由到另一个端口。即使在多功能端点设备内,一个功能的事务可以直接传送到另一个功能。这些从一个设备到另一个设备的进程被称为 peer-to-peer 事务,可以销毁在单独的 IOVA 空间中运行的设备的隔离。例如,如果分配给客户机虚拟机的网卡,DMA 将操作尝试写入到其自身 IOVA 空间内的虚拟地址。但是在物理空间中,同一地址属于主机拥有的对等磁盘控制器。由于 IOVA 到设备的物理转换仅在 IOMMU 执行,尝试优化该事务的数据路径的任何互连都会错误地将 DMA 写入操作重定向到磁盘控制器,然后再进入转换的 IOMMU。
为解决这个问题,PCI Express 规范包括支持 PCIe Access Control Services(ACS),它提供对这些重定向的可见性和控制力。这是将设备相互隔离的重要组件,通常在互连和多功能端点中缺失。在设备的每个级别上没有 ACS 支持到 IOMMU,则必须假定可以重定向。因此,这将打破 PCI 拓扑中缺少 ACS 支持的所有设备的隔离。PCI 环境中的 IOMMU 组将这一隔离取到一起,将设备组合在一起,这些设备能够无法转换的对等点对手。
总之,IOMMU 组代表 IOMMU 可见且与其他组隔离的最小设备集合。VFIO 使用这些信息为用户空间强制实施安全设备的所有权。除网桥、根端口和交换机外(所有互连结构示例),IOMMU 组中的所有设备必须绑定到 VFIO 设备驱动程序或已知的安全 stub 驱动程序。对于 PCI,这些驱动程序是 vfio-pci 和 pci-stub。仅允许 pci-stub,因为主机不知道主机不会通过这个驱动程序与设备交互[2].如果发生错误表示组在使用 VFIO 时是不可行的,这表示该组中的所有设备都需要绑定到适当的主机驱动程序。使用 virsh nodedev-dumpxml 探索 IOMMU 组的组成和 virsh nodedev-detach 将设备绑定到 VFIO 兼容驱动程序,将有助于解决这些问题。
[2]
一个例外是旧的 KVM 设备分配,在绑定到 pci-stub 驱动程序时通常与设备交互。Red Hat Enterprise Linux 7 不包括旧的 KVM 设备分配,避免这种交互和潜在的冲突。因此,不建议在同一 IOMMU 组中使用 VFIO 和旧的 KVM 设备分配。