一文分析Linux虚拟化KVM-Qemu之virtqueue

news2024/9/23 11:13:21

说明:

  1. KVM版本:5.9.1
  2. QEMU版本:5.0.0
  3. 工具:Source Insight 3.5, Visio

1. 概述

  • 前边系列将Virtio Device和Virtio Driver都已经讲完,本文将分析virtqueue;
  • virtqueue用于前后端之间的数据交换,一看到这种数据队列,首先想到的就是ring-buffer,实际的实现会是怎么样的呢?

2. 数据结构

先看一下核心的数据结构:

  • 通常Virtio设备操作Virtqueue时,都是通过struct virtqueue结构体,这个可以理解成对外的一个接口,而Virtqueue机制的实现依赖于struct vring_virtqueue结构体;
  • Virtqueue有三个核心的数据结构,由struct vring负责组织:
  • struct vring_desc:描述符表,每一项描述符指向一片内存,内存类型可以分为out类型和in类型,分别代表输出和输入,而内存的管理都由驱动来负责。该结构体中的next字段,可用于将多个描述符构成一个描述符链,而flag字段用于描述属性,比如只读只写等;
  • struct vring_avail:可用描述符区域,用于记录设备可用的描述符ID,它的主体是数组ring,实际就是一个环形缓冲区;
  • struct vring_used:已用描述符区域,用于记录设备已经处理完的描述符ID,同样,它的ring数组也是环形缓冲区,与struct vring_avail不同的是,它还记录了设备写回的数据长度;

这么看,当然是有点不太直观,所以,下图来了:

  • 简单来说,驱动会分配好内存(scatterlist),并通过virtqueue_add添加到描述表中,这样描述符表中的条目就都能对应到具体的物理地址了,其实可以把它理解成一个资源池子;
  • 驱动可以将可用的资源更新到struct vring_avail中,也就是将可用的描述符ID添加到ring数组中,熟悉环形缓冲区的同学应该清楚它的机制,通过维护头尾两个指针来进行管理,Driver负责更新头指针(idx),Device负责更新尾指针(Qemu中的Device负责维护一个last_avail_idx),头尾指针,你追我赶,生生不息;
  • 当设备使用完了后,将已用的描述符ID更新到struct vring_used中,vring_virtqueue自身维护了last_used_idx,机制与struct vring_avail一致;

 资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈

3. 流程分析

3.1 发送

 

当驱动需要把数据发送给设备时,流程如上图所示:

  1. ①A表示分配一个Buffer并添加到Virtqueue中,①B表示从Used队列中获取一个Buffer,这两种中选择一种方式;
  2. ②表示将Data拷贝到Buffer中,用于传送;
  3. ③表示更新Avail队列中的描述符索引值,注意,驱动中需要执行memory barrier操作,确保Device能看到正确的值;
  4. ④与⑤表示Driver通知Device来取数据;
  5. ⑥表示Device从Avail队列中获取到描述符索引值;
  6. ⑦表示将描述符索引对应的地址中的数据取出来;
  7. ⑧表示Device更新Used队列中的描述符索引;
  8. ⑨与⑩表示Device通知Driver数据已经取完了;

3.2 接收

 

当驱动从设备接收数据时,流程如上图所示:

  1. ①表示Device从Avail队列中获取可用描述符索引值;
  2. ②表示将数据拷贝至描述符索引对应的地址上;
  3. ③表示更新Used队列中的描述符索引值;
  4. ④与⑤表示Device通知Driver来取数据;
  5. ⑥表示Driver从Used队列中获取已用描述符索引值;
  6. ⑦表示将描述符索引对应地址中的数据取出来;
  7. ⑧表示将Avail队列中的描述符索引值进行更新;
  8. ⑨与⑩表示Driver通知Device有新的可用描述符;

3.3 代码分析

代码的分析将围绕下边这个图来展开(Virtio-Net),偷个懒,只分析单向数据发送了:

 

3.3.1 virtqueue创建

  • 之前的系列文章分析过virtio设备和驱动,Virtio-Net是PCI网卡设备驱动,分别会在virtnet-probe和virtio_pci_probe中完成所有的初始化;
  • virtnet_probe函数入口中,通过init_vqs完成Virtqueue的初始化,这个逐级调用关系如图所示,最终会调用到vring_create_virtqueue来创建Virtqueue;
  • 这个创建的过程中,有些细节是忽略的,比如通过PCI去读取设备的配置空间,获取创建Virtqueue所需要的信息等;
  • 最终就是围绕vring_virtqueue数据结构的初始化展开,其中vring数据结构的内存分配也都是在驱动中完成,整个结构体都由驱动来管理与维护;

3.3.2 virtio-net驱动发送

  • 网络数据的传输在驱动中通过start_xmit函数来实现;
  • xmit_skb函数中,sg_init_table初始化sg列表,sg_set_buf将sg指向特定的buffer,skb_to_sgvec将socket buffer中的数据填充sg;
  • 通过virtqueue_add_outbuf将sg添加到Virtqueue中,并更新Avail队列中描述符的索引值;
  • virtqueue_notify通知Device,可以过来取数据了;

3.3.3 Qemu virtio-net设备接收

  • Guest驱动写寄存器操作时,陷入到KVM中,最终Qemu会捕获到进行处理,入口函数为kvm_handle_io;
  • Qemu中会针对IO内存区域设置读写的操作函数,当Guest进行IO操作时,最终触发操作函数的调用,针对Virtio-Net,由于它是PCI设备,操作函数为virtio_pci_config_write;
  • virtio_pci_config_write函数中,对Guest的写操作进行判断并处理,比如在VIRTIO_PCI_QUEUE_NOTIFY时,调用virtio_queue_notify,用于处理Guest驱动的通知,并最终回调handle_output函数;
  • 针对Virtio-Net设备,发送的回调函数为virtio_net_handle_tx_bh,并在virtio_net_flush_tx中完成操作;
  • 通用的操作模型:通过virtqueue_pop从Avail队列中获取地址,将数据进行处理,通过virtqueue_push将处理完后的描述符索引更新到Used队列中,通过virtio_notify通知Guest驱动;

Virtqueue这种设计思想比较巧妙,不仅用在virtio中,在AMP系统中处理器之间的通信也能看到它的身影。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/377189.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[4.10]-AutoSAR零基础学习-Secure Debug(SHE+)(一)

目录 1 内部调试保护概述 2 UCB confirmation AURIXTM 设备提供多个安全保护层,以限制调试器访问整个微控制器。 保护层的配置基于用户配置块 UCB,存在于DFlash上(DF_UCB)。UCB 包含保护设置参数和其他可由用户配置的参数。 DF_…

使用Python对excel中的数据进行处理

一、读取excel中的数据首先引入pandas库,没有的话使用控制台安装 —— pip install pandas 。import pandas as pd #引入pandas库,别名为pd#read_excel用于读取excel中的数据,这里只列举常用的两个参数(文件所在路径&#xff…

华为OD机试模拟题 用 C++ 实现 - 连续子串(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 最多获得的短信条数(2023.Q1)) 文章目录 最近更新的博客使用说明连续子串题目输入输出示例一输入输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD …

SQL Server开启CDC的完整操作过程

这里写自定义目录标题写在前面SQL Server开启CDC1. 将指定库的实例先开启CDC2. 开启需要开启CDC的表3. 关闭CDC功能更详细信息参照官网写在前面 鉴于老旧数据的结构和项目都在sqlserver上存储,且迁移成本巨大,当下要为sqlserver的存储过程减负。要将一部…

深入理解Spring MVC下

上一篇博客从理论概念上来梳理Spring MVC相关知识,此篇博客将通过spring官网提供showcase代码为例子,详细介绍showcase代码中包含的各个例子是如何实现的。官网的showcase代码包含的主要例子包括,Demo地址:Mapping Requests&#…

2023王道考研数据结构笔记第一章绪论

第一章 绪论 1.1 数据结构的基本概念 1.数据:数据是信息的载体,是描述客观事物属性的数、字符以及所有能输入到计算机中并被程序识别和处理的符号的集合。 2.数据元素:数据元素是数据的基本单位,通常作为一个整体进行考虑和处理…

【LeetCode】2363. 合并相似的物品

2363. 合并相似的物品 题目描述 给你两个二维整数数组 items1 和 items2 ,表示两个物品集合。每个数组 items 有以下特质: items[i] [valuei, weighti] 其中 valuei 表示第 i 件物品的 价值 ,weighti 表示第 i 件物品的 重量 。items 中每…

cpp之STL

STL原理 STL ⼀共提供六⼤组件,包括容器,算法,迭代器,仿函数,适配器和空间配置器,彼此可以组合套⽤。容器通过配置器取得数据存储空间,算法通过迭代器存取容器内容,仿函数可以协助算…

电子科技大学软件工程期末复习笔记(九):项目管理

目录 前言 重点一览 软件项目管理的四大要素 团队组织方式 虚拟团队 软件范围 项目计划 P-CMM的5个级别 本章小结 前言 本复习笔记基于王玉林老师的课堂PPT与复习大纲,供自己期末复习与学弟学妹参考用。 重点一览 本节是软件工程复习笔记的最后一篇&…

Hive---Zeppelin安装教程

Zeppelin安装教程 安装zeppelin必须基于Hadoop和Hive上 文章目录Zeppelin安装教程简介安装步骤1.上传zeppelin压缩包2.解压并更名3.修改配置文件编辑zeppelin-site.xml---将配置文件的ip地址和端口号进行修改编辑 zeppelin-env.sh---添加JDK和Hadoop环境拷贝hive文件切换目录拷…

数据结构与算法(六):图结构

图是一种比线性表和树更复杂的数据结构,在图中,结点之间的关系是任意的,任意两个数据元素之间都可能相关。图是一种多对多的数据结构。 一、基本概念 图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成&#x…

嵌入式小白的进阶之路

学习嵌入式采用的是2021年华清远见嵌入式课程 安装虚拟机 : 懒人版 目标:快速上手 问题一: 在Linux虚拟环境中运行一个c语言程序步骤 1、激活虚拟环境:source venv/bin/activate 2、进入Hello文件夹:cd Hello 3、新…

【Python学习笔记】第二十节 Python 网络编程

Python 网络编程简单来说,网络是用物理链路将各个孤立的工作站或主机相连在一起,组成数据链路,从而达到资源共享和通信的目的。所谓的网络编程就是,让在不同的电脑上的软件能够进行数据传递,即进程之间的通信Python 提…

超级品牌符号怎么设计?大咖有方法

怎么设计超级LOGO图标?有方法! LOGO设计大趋势:卡通化、拟人化 抽象符号已经泛滥 但卡通形象也已经泛滥 趣讲大白话:设计容易出名难 【安志强趣讲信息科技89期】 ******************************* 别以为设计一个卡通就牛X闪闪 比…

解析iptables原里及设置规则

文章目录一、前言二、iptables简介三、iptables原理四、iptables设置规则五、 Linux 常用实例六、注意事项1、命令书写规则2、谨慎使用的动作 DROP3、永久生效一、前言 其实在IT行业里了,不仅是专职的运维人员需要了解 iptables,开发、测试等人员在了解…

IIS .Net Core 413错误和Request body too large解决办法

错误描述图片比较大时&#xff0c;在前端上传就报413错误。根本到不了后端。在网上看到这个文章比较有用。https://blog.csdn.net/wstever/article/details/1288707421、修改网站Web.config配置文件加入下面这段配置<?xmlversion"1.0" encoding"utf-8"…

Python 中 openpyxl 模块封装,读写 Excel 文件中自动化测试用例数据

只有测试数据和错误提示信息不同&#xff0c;其他代码都是一样的&#xff0c;不这样不易修改数据和维护&#xff0c;会有两点痛点 1.代码冗余极其严重, 程序可读性不佳 2.程序拓展性很差 往往我们在自动化测试汇总&#xff0c;会将数据放在 Excel 文件、CSV文件、数据库 Py…

JVM 堆内存模型

方法区和永久代的关系 方法区与 Java 堆一样&#xff0c;是各个线程共享的内存区域&#xff0c;它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然 Java 虚拟机规范把方法区描述为堆的一个逻辑部分&#xff0c;但是它却有一个别名叫做 N…

如何整理自己的前端面试题库

compose 题目描述:实现一个 compose 函数 // 用法如下: function fn1(x) {return x 1; } function fn2(x) {return x 2; } function fn3(x) {return x 3; } function fn4(x) {return x 4; } const a compose(fn1, fn2, fn3, fn4); console.log(a(1)); // 1432111实现代码…

基于Java+SpringBoot+Vue前后端分离书店购书系统设计与实现

博主介绍&#xff1a;✌全网粉丝3W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战✌ 博主作品&#xff1a;《微服务实战》专栏是本人的实战经验总结&#xff0c;《Spring家族及…