简介
virtio是当前主流的IO设备半虚拟化解决方案,其主要目标是在虚拟机和各种Hypervisor虚拟设备之间提供一个统一的通信框架和编程接口,减少跨平台所带来的兼容性问题,提升驱动程序开发效率。virtio是一种前后端架构,包括前端驱动和后端设备以及virtio定义的传输协议。通过传输协议,virtio可以应用到不同的虚拟化方案中,如QEMU/KVM、Iguest等,而且也允许实现不同的前后端。
virtio协议
virtio技术的实现描述在virtio标准协议中。virtio协议定义了virtio通信遵循的接口,包含设备类型、设备状态、设备支持的特性以及前后端数据传输的通道(virtqueue)等内容。
virtio协议版本
目前在使用的virtio规范有三个版本:0.95、1.0和1.1,其中,0.95版本是目前广泛在使用的版本,称为传统模式;1.0版本中协议将设备的配置部分做了一些调整,被称为现代模式;1.1版本则主要是新增了packed virtqueue的支持。
virtio协议架构
从总体上来看,virtio协议架构可分为三层:前端驱动、后端设备以及中间的传输层:
前端驱动
前端驱动是虚拟机内部的virtio模拟设备对应的驱动程序,其主要作用是发现virtio设备、接受来自虚拟机内部的请求,并依据virtio协议与virtio设备进行通信。
对于Linux系统,内核已经实现了一系列的virtio前端驱动程序,包括virtio-ballon、virtio-net、virtio-blk和virtio-scsi等;另外,DPDK也实现了用户态版本的virtio设备驱动程序virtio-pmd(主要针对virito网络设备实现),用于进一步提升virito数据通信的性能。
后端设备
后端设备承担的主体功能分为两部分:1、virtio后端设备的模拟;2、依据virtio协议处理来自虚拟机端发送的请求。
在QEMU的实现中,virtio设备是QEMU为虚拟机模拟的PCI设备,遵循PCI-SIG定义的PCI规范,具有配置空间、中断配置等功能;对于virtio设备的请求处理,最早的实现是放在QEMU内部,但随着技术演进,又逐渐出现了vhost、vhost-user以及vDPA等后端加速方案实现。
传输层
传输层位于前端驱动和后端设备之间,用于支持虚拟机与Hypervisor虚拟设备之间的数据通信。virtio传输层使用虚拟队列的方式来传输数据,虚拟队列是由虚拟机virtio前端驱动创建的用于数据传输的共享内存,后端处理程序通过这块共享内存获取前端设备递交的IO请求。
virtio工作机制
virtio使用前后端通信模型,在虚拟机中运行virtio设备的驱动程序,通过virtio虚拟队列和后端的Hypervisor虚拟设备进行数据交互。virtio虚拟队列通过vring进行实现,vring是虚拟机和后端设备之间共享的一段环形缓冲区,如下图:
vring 包含三个部分:描述符表(Descriptor Table)、可用描述符表(Available Ring)和已用描述符表(Used Ring):
- 描述符表:描述符表用于存储一些关联的描述符,每个描述符记录一个对 buffer 的描述;
- 可用描述符表:用于保存前端驱动提供给后端设备且后端设备可以使用的描述符;
- 已用描述符表:用于保存后端处理程序已经处理过并且尚未反馈给前端驱动的描述。
当虚拟机需要发送请求到后端设备的时候就准备好数据,将数据描述放到Available Ring中,写配置通知后端设备;然后,后端设备就能够通过Availabel Ring中读取请求信息,进而从共享内存中读出数据。后端设备完成请求之后,将响应状态存放在Used Ring中,前端驱动也就可以从Used Ring中得到请求完成信息,并获取请求的数据。
相关参考
- 《深入浅出系统虚拟化:原理与实践》
- 《深度探索Linux系统虚拟化:原理与实现》
- 《Linux开源存储全栈详解——从Ceph到容器存储》