本文首发于个人公众号 Linux云计算网络(id: cloud_dev),专一于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」便可领取,欢迎你们关注,二维码文末能够扫。前端
virtio 是一种 I/O 半虚拟化解决方案,是一套通用 I/O 设备虚拟化的程序,是对半虚拟化 Hypervisor 中的一组通用 I/O 设备的抽象。提供了一套上层应用与各 Hypervisor 虚拟化设备(KVM,Xen,VMware等)之间的通讯框架和编程接口,减小跨平台所带来的兼容性问题,大大提升驱动程序开发效率。编程
在彻底虚拟化的解决方案中,guest VM 要使用底层 host 资源,须要 Hypervisor 来截获全部的请求指令,而后模拟出这些指令的行为,这样势必会带来不少性能上的开销。半虚拟化经过底层硬件辅助的方式,将部分不必虚拟化的指令经过硬件来完成,Hypervisor 只负责完成部分指令的虚拟化,要作到这点,须要 guest 来配合,guest 完成不一样设备的前端驱动程序,Hypervisor 配合 guest 完成相应的后端驱动程序,这样二者之间经过某种交互机制就能够实现高效的虚拟化过程。后端
因为不一样 guest 前端设备其工做逻辑大同小异(如块设备、网络设备、PCI设备、balloon驱动等),单独为每一个设备定义一套接口实属没有必要,并且还要考虑扩平台的兼容性问题,另外,不一样后端 Hypervisor 的实现方式也大同小异(如KVM、Xen等),这个时候,就须要一套通用框架和标准接口(协议)来完成二者之间的交互过程,virtio 就是这样一套标准,它极大地解决了这些不通用的问题。数组
从整体上看,virtio 能够分为四层,包括前端 guest 中各类驱动程序模块,后端 Hypervisor (实如今Qemu上)上的处理程序模块,中间用于先后端通讯的 virtio 层和 virtio-ring 层,virtio 这一层实现的是虚拟队列接口,算是先后端通讯的桥梁,而 virtio-ring 则是该桥梁的具体实现,它实现了两个环形缓冲区,分别用于保存前端驱动程序和后端处理程序执行的信息。网络
严格来讲,virtio 和 virtio-ring 能够看作是一层,virtio-ring 实现了 virtio 的具体通讯机制和数据流程。或者这么理解可能更好,virtio 层属于控制层,负责先后端之间的通知机制(kick,notify)和控制流程,而 virtio-vring 则负责具体数据流转发。架构
vring 主要经过两个环形缓冲区来完成数据流的转发,以下图所示。框架
vring 包含三个部分,描述符数组 desc,可用的 available ring 和使用过的 used ring。函数
desc 用于存储一些关联的描述符,每一个描述符记录一个对 buffer 的描述,available ring 则用于 guest 端表示当前有哪些描述符是可用的,而 used ring 则表示 host 端哪些描述符已经被使用。工具
Virtio 使用 virtqueue 来实现 I/O 机制,每一个 virtqueue 就是一个承载大量数据的队列,具体使用多少个队列取决于需求,例如,virtio 网络驱动程序(virtio-net)使用两个队列(一个用于接受,另外一个用于发送),而 virtio 块驱动程序(virtio-blk)仅使用一个队列。性能
具体的,假设 guest 要向 host 发送数据,首先,guest 经过函数 virtqueue_add_buf 将存有数据的 buffer 添加到 virtqueue 中,而后调用 virtqueue_kick 函数,virtqueue_kick 调用 virtqueue_notify 函数,经过写入寄存器的方式来通知到 host。host 调用 virtqueue_get_buf 来获取 virtqueue 中收到的数据。
存放数据的 buffer 是一种分散-汇集的数组,由 desc 结构来承载,以下是一种经常使用的 desc 的结构:
当 guest 向 virtqueue 中写数据时,其实是向 desc 结构指向的 buffer 中填充数据,完了会更新 available ring,而后再通知 host。
当 host 收到接收数据的通知时,首先从 desc 指向的 buffer 中找到 available ring 中添加的 buffer,映射内存,同时更新 used ring,并通知 guest 接收数据完毕。
virtio 是 guest 与 host 之间通讯的润滑剂,提供了一套通用框架和标准接口或协议来完成二者之间的交互过程,极大地解决了各类驱动程序和不一样虚拟化解决方案之间的适配问题。
virtio 抽象了一套 vring 接口来完成 guest 和 host 之间的数据收发过程,结构新颖,接口清晰。
个人公众号 「Linux云计算网络」(id: cloud_dev) ,号内有 10T 书籍和视频资源,后台回复 「1024」 便可领取,分享的内容包括但不限于 Linux、网络、云计算虚拟化、容器Docker、OpenStack、Kubernetes、工具、SDN、OVS、DPDK、Go、Python、C/C++编程技术等内容,欢迎你们关注。