Virtio是一套 I/O 半虚拟化的程序,是对半虚拟化Hypervisor中的一组通用I/O 设备(如网络设备、块设备等)的抽象,为各种I/O 设备的虚拟化提供了通用的、标准化的前端接口,增加了各个虚拟化平台的代码复用。
驱动抽象
virtio 为半虚拟化提供了一系列通用设备仿真的接口,它可以抽象为两部分:
Front-end drivers:通过半虚拟化在客户机操作系统中修改Guest OS代码实现driverBack-end Drivers:Hyptervisor提供设备仿真的后端驱动,实现前端接口

Virtio 架构
除了 Front-end drivers 和 Back-end Drivers 之外,Virtio 还定义了两层来支持虚拟机与 Hypervisor 进行通讯,Virtio 四层如下:
Front-end层guest 中各种驱动程序模块virtio层是虚拟队列(virtual queue)接口,它是前端驱动程序和后端驱动程序通信的桥梁。驱动程序可以根据需要使用零个或多个队列。例如:virtio-net网络驱动程序使用两个虚拟队列(一个用于接收,一个用于发送)virtio-blk块驱动程序只使用一个队列
virtio-ring层是virtio层的具体实现,它实现了两个环形缓冲区,分别用于保存前端驱动程序和后端处理程序执行的信息。virtio-ring实现了virtio的具体通信机制和数据流程虚拟队列(virtual queue)是虚拟的,它实际上被实现为一个环(rings),用于遍历guest-to-hypervisor过渡。它也可以以其他方式实现,只要guest和hypervisor以相同的方式实现即可virtio的核心机制就是通过共享内存在前端驱动与后端实现间进行数据传输,共享内存区域被称作vring
Back-endHypervisor(实现在Qemu上)中的处理程序模块

上图,列出五个前端驱动程序:
virtio-blk(如磁盘)virtio-net网络设备virtio-pciPCI模拟virtio-balloon(用于动态管理客户内存使用)virtio-console控制台
每个前端驱动程序在hypervisor中都有一个对应的后端驱动程序。
层次结构概念

virtio_driver表示客户机中的前端驱动。与驱动相匹配的设备被封装在virtio_device(在客户机中表示设备),其中有成员config指向virtio_config_ops结构(其中定义了配置virtio设备的操作)virtqueue中有成员vdev指向virtio_device(也就是指向它所服务的某一设备virtio_device)- 每个
virtio_queue中有个类型为virtqueue_ops的对象,其中定义了与hypervisor交互的虚拟队列操作
vring 组成
vring 由三部分构成:
Descriptor Table:描述内存buffer,主要包括addr/len等信息Available Ring:用于驱动通知设备有新的可用的描述符。比如,通知后端设备,有一个待发送的报文描述符Used Ring:用于通知驱动设备侧已用的描述符。比如,后端设备收到一个报文,需要将报文数据放入可用的描述符,并更新Used Ring,同时通知前端驱动
Virtio缓冲
客户机驱动(前端)与hypervisor(后端)通过缓冲区进行通信。对于一次I/O,客户机提供一个或多个缓冲区表示请求。
Virtio Drivers 示例
Front-end drivers在Linux内核源码的./drivers子目录- 网络驱动
./driver/net/virtio_net.c - 块驱动
./driver/block/virtio_blk.c ./driver/virtio子目录下提供了 virtio 接口的实现(virtio设备、驱动、virtqueue和环形缓冲区)
- 网络驱动
其他
virtio-fs是红帽在2018年12月10号在kata社区提出的一种在guest之间共享文件系统的方案。
一般 Linux 系统都内置 virtio 驱动,但 windows系统 需要单独安装 virtio 驱动。检测 Linux 是否包含 virtio 驱动命令:
$ find /lib/modules/3.10.0-1160.*/ -name "virtio*"将网卡类型设置为 virtio
<interface ...>
<model type='virtio' />
...
</interface>将磁盘类型设置为 virtio
<disk ...>
<target dev='hda' bus='virtio' />
<address type='pci' />
...
</disk>