概述

virtio的关键技术是virtqueue机制,其提供了一套统一的用于virito前端和后端的通信机制。对于每个virtqueue包含三个部分:

  • Descriptor Area:用于描述数据buffer;
  • Driver Area:驱动需要传递给设备的额外数据;
  • Device Area:设备需要传递给驱动的额外数据。

最新的virtio协议版本定义有两种virtqueue格式:Split Virtqueue和Packed Virtqueue,下面针对这两种格式,我们分别进行描述。

Split Virtqueue

在virtio协议1.0版本及之前,Split Virtqueue是唯一支持的virtqueue格式。Split Virtqueue格式将virtqueue分成了三个部分,对于每个部分只能由驱动或者设备写入,而不支持同时可写。virtqueue的核心数据结构是vring,这是virtio前端驱动和后端Hypervisor虚拟设备之间传输数据的载体。

vring数据结构

vring数据结构示意图如下:

vring主要由三个部分组成:描述符表(Descriptor Table)、可用描述符表(Avaliable Ring)和已用描述符表(Used Ring)。virtio协议规定,vring结构关联的内存由客户机中的前端驱动负责分配和回收。Linux内核virtio前端驱动定义的vring数据结构如下:

struct vring {unsigned int num;   /* vring的队列深度,表示一个VRing有多少个buffer */struct vring_desc *desc;    /* 指向Descriptor Table */struct vring_avail *avail;  /* 指向Avaliable Ring */struct vring_used *used;    /* 指向Used Ring */
};

描述符表

描述符表用于保存一系列描述符,每一个描述符都被用来描述客户机内的一块内存区域。对于这块内存区域,如果存放的是前端驱动写给设备的数据,称这个描述符为out类型的;如果存放的是前端驱动从设备读取的数据,称这个描述符为in类型的。描述符数据结构定义如下:

struct vring_desc {__virtio64 addr;   __virtio32 len;     __virtio16 flags;  __virtio16 next;
};

描述符通过以下字段指定内存区域的各个属性:

字段 作用
addr 表示内存区域在客户机物理地址空间中的起始地址
len 该字段的意义取决于该内存区域的读写属性。如果该区域是只写的,数据传递方向只能从后端设备到前端驱动,此时len表示设备最多可以向该内存块写入的数据长度。反之,如果该区域是只读的,此时len表示后端设备必须读取的来自前端驱动的数据量。
flags 用于标识描述符自身的特性,一共有三种可选值。VRING_DESC_F_WRITE表示当前内存区域是只写的,即该内存区域只能被后端设备用来向前端驱动传递数据。VRING_DESC_F_NEXT表明该描述符的next字段是否有效。VRING_DESC_F_INDIRECT表明该描述符是否指向一个间接描述符表。
next 驱动和设备的一次数据交互往往会涉及多个不连续的内存区域。通常的做法是将描述符组织成描述符链表的形式来表示所有的内存区域。next字段便是用来指向下一个描述符。通过flag字段中的值VRING_DESC_F_NEXT,就可以间接地确定该描述符是否为描述符链表的最后一个。

可用描述符表

可用描述符表用于保存前端驱动提供给后端设备且后端设备可以使用的描述符。可用描述符表由一个flags字段、idx索引字段以及一个以数组形式实现的环组成。可用描述符表数据结构定义如下:

struct vring_avail {__virtio16 flags;__virtio16 idx;__virtio16 ring[];
};

各个字段作用描述如下:

字段 作用
flags 标志位,表示可用描述符表的一些属性,包括是否需要设备在使用了可用描述符表中的表项后发送中断给驱动。
idx 用于索引ring数组中下一个可用的位置
ring 用于存放描述符链表中作为链表头的描述符在描述符表中的索引

已用描述符表

已用描述符表用于保存后端已经处理并且尚未反馈给驱动的描述。与可用描述符表不同的是,已用描述符表中数组ring的每个元素不仅包含后端设备已经处理的描述符链表的头部描述符在描述符表中的索引,而且由于后端设备可能会向前端驱动写回数据或需要告知驱动写操作的状态,还需要包括一个len字段来记录设备写回数据的长度。已用描述符区域数据结构定义如下:

struct vring_used {__virtio16 flags;__virtio16 idx;struct vring_used_elem ring[];
};

各个字段作用描述如下:

字段 作用
flags 标志位,表示已用描述符表的一些属性,包括是否需要驱动在回收了已用描述符表中的表项后发送通知给设备
idx 用于索引ring数组中下一个已用元素的位置
ring 存储已用元素的数组,每个已用元素包括描述符索引和数据长度

IO请求组织方式

一个IO请求通常需要使用多个Descriptor描述,描述的信息一般包括一个请求、一个或多个数据页以及提供给后端设备填写处理结果的响应Buffer。通过flags中的VRING_DESC_F_INDIRECT字段是否设置,一个IO请求可以选择Chained Descriptor或者Indirector Descriptor方式进行组织。

Chained Descriptor

Chained Descriptor通过next字段将多个描述符串接成描述符链表的形式来描述一个IO请求:

Indirect Descriptor

Indirect Descriptor方式下,IO请求使用的描述符指向的是一个包含多个描述符的间接描述符表,并由间接描述表中的描述符描述所有的内存区域。对于一个IO请求,在包含的描述符数量较多的情况下,可以优化后端设备对描述信息的访问:设备可以一次性读取整个间接描述表中所有描述符,避免沿着next字段逐个读取。

使用Split Virtqueue的通信流程

设备使用virtqueue主要包括两部分过程:驱动通过描述符列表和可用描述符表提供数据缓冲区给设备用,和设备使用描述符后再通过已用描述符表归还给驱动。

前端驱动写入

客户机操作系统通过驱动提供数据缓冲区给设备使用,具体包括以下步骤:

  1. 把数据缓冲区的地址、长度等信息赋值到空闲的描述符中;
  2. 把该描述符指针添加到该虚拟队列的可用环表的头部;
  3. 更新该可用环表中的头部指针;
  4. 写入该虚拟队列编号到Queue Notify寄存器以通知设备。

后端设备使用

每次后端设备取用可用描述符时,需要知道剩余可用描述符在数组ring中的起始位置。后端设备会维护一个变量last_avail_idx,用来标记这个位置。当切换到主机中时,后端设备将检查last_avail_idx和idx的值,数组ring中位于last_avail_idx和idx-1之间的部分就是可供后端设备使用的区域。

设备使用数据缓冲区后(基于不同种类的设备可能是读取或者写入,或是部分读取或者部分写入),将用过的缓冲区描述符填充已用环表,并通过中断通知驱动。具体的过程如下:

  1. 把使用过的数据缓冲区描述符的头指针添加到该虚拟队列的已用环表的头部;
  2. 更新该已用环表中的头部指针;
  3. 根据是否开启MSI-X中断,用不同的中断方式通知驱动

前端驱动回收

当设备驱动回收已用的设备描述符时,需要知道剩余已用标识符在数组ring中的起始位置,前端驱动会维护一个变量last_used_idx,用来标记这个位置。当切换到虚拟机中时,前端驱动将检查last_used_idx和idx的值,数组ring中位于last_used_idx和idx-1之间的部分便是可供前端驱动回收的区域。

Packed Virtqueue

待续。。。

相关参考

  • 《深入浅出DPDK》
  • 《深入浅出系统虚拟化:原理与实践》
  • 《深度探索Linux系统虚拟化:原理与实现》

virtio技术(3)virtqueue机制相关推荐

  1. virtio技术(1)简介

    概述 virtio是当前主流的IO设备半虚拟化解决方案,其主要目标是在虚拟机和各种Hypervisor虚拟设备之间提供一个统一的通信框架和编程接口,减少跨平台所带来的兼容性问题,提升驱动程序开发效率. ...

  2. 从FTP模块学习先进的诊断技术(Erlang Trace机制)

    从FTP模块学习先进的诊断技术(Erlang Trace机制) 我们开发好了一个软件的时候,通常是经过严格测试的,才分发给用户使用, 但是即使这样也不能保证用户的环境和我们的相同, 我们的软件还是会失 ...

  3. 软件加密技术和注册机制加密基础(转)

    软件加密技术和注册机制加密基础 本文是一篇软件加密技术的基础性文章,简要介绍了软件加密的一些基本常识和一些加密产品,适用于国内软件开发商或者个人共享软件开发者阅读参考. 1.加密技术概述 一个密码系统 ...

  4. virtio系列-packed virtqueue

    virtio packed virtqueue spilt virtqueue因其简约的设计而备受欢迎,但是它有一个基本的问题:avail, used ring 是分离的,cpu cache miss ...

  5. 区块链技术之共识机制

    "共识机制"一词通常通俗地用于指代"股权证明"."工作证明"或"权威证明"协议.然而,这些只是防止女巫攻击的共识机制的组 ...

  6. 性能优化——Android热修复技术,类加载机制详解

    一.背景 热修复技术慢慢的成为Android开发必不可少的技术,也是成为一名高级程序员必不可少的技能之一.那么什么是热修复技术呢? 当app上线之后,发现了一个严重的bug,需要紧急修复,按照以往的惯 ...

  7. 华为BFD技术 技术背景+工作机制+应用场景

    技术背景 故障检测需求及主要方法:为了减少设备故障对业务的影响,提高网络的可用性,设备 需要能够尽快检测到与相邻设备间的通信故障,以便能够及时采取措施,从而保证业务 继续进行. BFD:Bidirec ...

  8. 主流的分布式存储技术及其实现机制

    分布式存储技术主要包括四类: (1)集群存储技术.集群存储系统是指架构在一个可扩充服务器集群中的文件系统,用户不需要考虑文件是存储在集群中的什么位置,仅仅需要使用统一的界面就可以访问文件资源.当负载增 ...

  9. java spi技术,Java SPI机制

    Java组件一个更为人熟知的名词"服务",与流行的微服务有所区别. 以往加载JDBC驱动使用如下方式:Class.forName() Java 1.6引入SPI机制,使用Drive ...

最新文章

  1. Ionic启动时提示:The Angular CLI requires a minimum Node.js version of eithor v10.13 or v12.0
  2. 散列函数的应用及其安全性
  3. 关于java.net.URLEncoder.encode编码问题
  4. 深入浅出的webpack构建工具---PostCss(五)
  5. 电热水器工作过程 c语言,热水器工作流程图
  6. opencv jpg作为png背景_基于OpenCV与tensorflow实现实时手势识别
  7. centos7配置静态ip地址
  8. 蓝桥杯训练 2n皇后问题
  9. 物联网项目设计 (七) 基于RT-thread的MQTT协议物联网辉光钟
  10. Zynga公布2021年第二季度财务业绩
  11. 微软的teredo服务器,win10系统通过teredo连接ipv6的操作方法
  12. php返回结果,后端继续执行
  13. 在自己电脑上用excel重新绘制荧光定量溶解曲线
  14. 服务器装系统进pe界面就死机了,电脑可以进入PE系统,但重装就是重启,装不了系统是什么原因?...
  15. 青海师范大学计算机专业分数线,青海师范大学2018年各省及各专业录取分数线及最低录投档线【理科 文科】...
  16. MYSQL关闭安全模式
  17. 【约瑟夫环】Java实现:100个人开始从1开始报数,每当报数到3,报数3的人离开,求最后留下来人的位置。
  18. 扎好篱笆桩:三大运营商守住网络安全“命门”
  19. 2021年中国私募基金市场日益壮大,私募基金管理规模达到19.78万亿元[图]
  20. c语言贪吃蛇打包到桌面,C语言实现桌面贪吃蛇小游戏

热门文章

  1. 实时音视频直播新玩法中的混音技术
  2. 我的世界服务器光影文件夹,我的世界光影包放在哪个文件夹(光影包文档保存位置)...
  3. 胜意差旅管理 | 从OA变革到费控系统的企业报销体验
  4. Python实现Decision Tree
  5. pscp linux,windows下 pscp 安装及使用
  6. python实验猜数游戏
  7. Centos安装 Node.js v12.16.1 和 v16.14
  8. 深度学习模型分析人类复杂疾病的准确性
  9. 如何用word制作英语答题卡_考研英语答题卡模板(word打印版).doc
  10. IBM的PBC ——通透的绩效管理文化