Virtio
是一套 I/O 半虚拟化的程序,是对半虚拟化 Hypervisor
中的一组通用 I/O 设备
(如网络设备
、块设备
等)的抽象,为各种 I/O 设备
的虚拟化提供了通用的、标准化的前端接口,增加了各个虚拟化平台的代码复用。
驱动抽象
virtio
为半虚拟化提供了一系列通用设备仿真的接口,它可以抽象为两部分:
Front-end drivers
:通过 半虚拟化
在客户机操作系统中修改 Guest OS
代码实现driver
Back-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-end
Hypervisor(实现在Qemu上)中的处理程序模块
上图,列出五个前端驱动程序:
virtio-blk
(如磁盘)
virtio-net
网络设备
virtio-pci
PCI模拟
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>