vai系统设计(virtio设备和驱动概述)
vai系统设计(virtio设备和驱动概述)设备状态字段是设备和驱动程序用于执行其初始化的位序列。我们可以将其想象为控制台上的交通信号灯,设置每个零件并清除指示其状态的每个位。现在,我们将为每个部分提供更多详细信息,以及设备和驱动程序如何开始使用它们进行通信。virtio设备是公开virtio接口以供软件管理和交换信息的设备。可以使用PCI,内存映射I/O(仅将设备暴露在内存区域中)和S/390通道I/O暴露给仿真环境。通信的一部分需要委托给这些,例如设备发现。它的主要任务是将信号从虚拟环境之外的格式(VM,容器等)转换为需要通过virtio数据层交换的格式,反之亦然。该信号可以是真实的(例如,来自NIC的电或光),也可以是虚拟的(例如,主机从网络数据包中获得的表示)。virtio接口包含以下必填部分(virtio1.1 spec):
打包的virtqueue(补充了拆分的virtqueue)已在virtio 1.1规范中合并,并已在模拟设备(qemu,virtio_net,dpdk)和物理设备中成功实现。
我们将从对virtio设备,驱动程序及其数据层交互的概述开始。然后,我们将继续解释拆分式virtqueue环布局的详细信息。接下来是打包的virtqueue与拆分式virtqueue方法相比所带来的优点的概述。
Virtio设备和驱动程序概述
本节简要介绍了virtio设备,virtio驱动程序,可以使用的不同体系结构和不同组件的示例。
Virtio设备virtio设备是公开virtio接口以供软件管理和交换信息的设备。可以使用PCI,内存映射I/O(仅将设备暴露在内存区域中)和S/390通道I/O暴露给仿真环境。通信的一部分需要委托给这些,例如设备发现。
它的主要任务是将信号从虚拟环境之外的格式(VM,容器等)转换为需要通过virtio数据层交换的格式,反之亦然。该信号可以是真实的(例如,来自NIC的电或光),也可以是虚拟的(例如,主机从网络数据包中获得的表示)。
virtio接口包含以下必填部分(virtio1.1 spec):
- 设备状态字段
- 功能位
- 通知事项
- 一种或多种virtqueues
现在,我们将为每个部分提供更多详细信息,以及设备和驱动程序如何开始使用它们进行通信。
设备状态字段设备状态字段是设备和驱动程序用于执行其初始化的位序列。我们可以将其想象为控制台上的交通信号灯,设置每个零件并清除指示其状态的每个位。
guest或驱动程序在设备状态字段中设置ACKNOWLEDGE(0x1)位表示已确认该设备,DRIVER(0x2)表示正在进行的初始化。此后,它将使用功能位开始功能协商(稍后会详细介绍),DRIVER_OK(0x4)和FEATURES_OK(0x8)设置为确认功能,以便可以开始通信。如果设备要指示致命故障,则可以将DEVICE_NEEDS_RESET(0x40)置1,驱动程序也可以对FAILED(0x80)进行设置。
该设备使用特定于传输的方法(例如PCI扫描或知道MMIO的地址)传达这些位的位置。
功能位设备的功能位用于传达其支持的功能,并与驱动程序就将使用哪些功能达成一致。这些可以是设备通用的或特定于设备的。作为第一种情况的示例,一位可以确认设备是否支持SR-IOV或可以使用哪种存储模式。第二种情况的一个例子是它可以执行的不同卸载,例如校验和或分散聚集(如果设备是网络接口)。
在上一节中介绍的设备初始化之后,前者读取设备提供的功能位,然后将其可以处理的子集发送回去。如果他们同意,驱动程序将分配并告知设备虚拟状态以及所需的所有其他配置。
通知设备和驱动程序必须使用通知来通知他们有信息可以进行通信。尽管在标准中指定了它们的语义,但是它们的实现是特定于传输的,例如PCI中断或写入特定的内存位置。设备和驱动程序需要公开至少一种通知方法。我们将在以后的部分中对此进行扩展。
一种或多种virtqueues:通讯工具一个virtqueue只是host使用的guest缓冲队列(读取或写入它们,然后返回给guest)。当前实现的virtqueue内存布局是一个圆环,因此通常称为virtring或vring。
Virtio驱动程序virtio驱动程序是虚拟环境中的软件部分,它使用virtio规范的相关部分与virtio设备进行通讯。
一般来说,其virtio控制层任务是:
- 寻找设备
- 在guest中分配共享内存以进行通信
使用Virtio设备中的协议启动它。
设备和驱动程序的交互在本节中,我们将在三种不同的体系结构中定位每个virtio网络元素(设备,驱动程序以及通信方式),以提供一个共同的框架来开始解释virtio数据层并展示其适应性。我们已经在过去的文章中介绍了这些元素,因此,如果您是virtio-net系列读者,则可以跳过本节。另一方面,如果您还没有阅读它们,则可以将它们用作参考,以更好地理解这一部分。
在virtio-networking和vhost-net介绍中,我们展示了qemu创建模拟网络设备并将其提供给guest virtio-net驱动程序的环境。在这种环境中,驱动程序通知将从对guest公开的任何方法(通常是PCI)路由到KVM中断,从而中断guest的处理器并将控制权返回给host(vmexit)。同样,设备通知是host可以发送到KVM设备的特殊ioctl(vCPU IRQ)。QEMU可以使用共享内存访问virtqueue信息。
注意,virtio环共享内存概念的含义:驱动程序和设备访问的内存在RAM中是同一页,它们不是遵循协议进行同步的两个不同区域。
图1:Qemu仿真设备组件图
由于通知现在需要从guest(KVM)传输到QEMU,然后到内核以后者转发网络帧,因此我们可以在内核中生成一个线程,该线程可以访问guest的共享内存映射,然后让它处理virtio数据层。
在这种情况下,QEMU使用virtio数据层启动设备,然后将virtio设备状态转发到vhost-net,将数据层委托给它。在这种情况下,KVM将使用事件文件描述符(eventfd)来传达设备中断,并公开另一个事件文件描述符以接收CPU中断。guest不需要知道此更改,它将像以前的情况一样进行操作。
另外,为了提高性能,我们创建了一个内核内部的virtio-net设备(称为vhost-net),将数据层直接卸载到发生数据包转发的内核:
图2:Virtio-net组件图
稍后,我们将virtio设备从内核移到了host中的用户空间进程,该主机可以运行像DPDK这样的数据包转发框架。设置所有这些的协议称为virtio-user。
图3:Virtio用户组件图
它甚至允许guest在guest的用户区中运行virtio驱动程序,而不是内核!在这种情况下,virtio名称会驱动正在管理内存和virtqueue的进程,而不是在guest虚拟机中运行的内核代码。
图4:Virtio-user和guest虚拟机中的userland驱动程序
最后,我们可以使用适当的硬件直接进行virtio设备直通。如果NIC支持virtio数据层,我们可以使用适当的硬件(IOMMU设备,能够在客户机和设备的内存地址之间进行转换)和软件(例如,VFIO linux驱动程序)将其直接暴露给客户机,以使主机能够直接将PCI设备的控制权交给guest)。该设备将典型的硬件信号用于通知基础结构,例如PCI和CPU中断(IRQ)。
如果硬件NIC希望采用这种方式,则最简单的方法是在vDPA之上构建其驱动程序。
图5:Virtio硬件直通组件图