virtio-net前端-virtqueue

news2024/12/23 14:22:18

文章目录

  • 1.概述
  • 2.数据结构
  • 3. 流程分析
    • 3.1 virtio总线创建
    • 3.3virtio-net
    • 3.3.1virtio-net初始化![在这里插入图片描述](https://img-blog.csdnimg.cn/7246c1705ac24f88b75fad63f8941ca5.png)
      • 3.3.2 virtio-net驱动发送
      • 3.3.3 Qemu virtio-net设备接收
  • 4.virtqueue
    • 4.1数据结构
    • 4.2发送
    • 4.3接收

1.概述

在这里插入图片描述
guest中的virtio驱动框架
在这里插入图片描述
核心模块为virtio和virtqueue,其他高层的驱动都是基于核心模块之上构建的;virtio-net,是一个virtio设备,又是一个PCI设备
每一个virtio设备都有一个对应的virtio PCI代理设备
以virtio-net驱动为例,由于virtioPCI设备的存在,PCI进行扫描的时候会扫描到该设备,并且会调用想要的驱动probe函数

2.数据结构

内核创建总线用于挂载设备,总线负责设备与驱动的匹配。Linux内核创建了一个virtio bus
在这里插入图片描述
virtio设备和virtio驱动,通过virtio_device_id来匹配,而这个都是在virtio规范中定义好的;
virtio_device结构中有一个struct virtio_config_ops,函数集由驱动来进行指定,用于操作具体的设备;
这里描述的virtio-net驱动,既是一个virtio设备,也是一个pci设备,在内核中通过结构体struct virtio_pci_device来组织:在这里插入图片描述
该结构体中维护了几个IO区域:
Common, ISR, Device, Notify,用于获取virtio设备的各种信息,这个也是由virtio规范决定的;
通常来说一个virtio设备,由以下几个部分组成:

  • Device status field
  • Feature bits
  • Notifications
  • Device Configuration space
  • One or more virtqueues
    从结构体看,它用于充当pci设备和virtio设备的纽带,后续也会在probe函数中针对不同的部分进行对应的初始化;
    以总线的匹配视角来看就是这样子的:
    在这里插入图片描述

3. 流程分析

3.1 virtio总线创建

在这里插入图片描述
bus_register注册virtio总线,总线负责匹配,在匹配成功后调用通用的virtio_dev_probe函数;在这里插入图片描述
virtio-net设备通过挂在pci总线上,系统在PCI子系统初始化时会去枚举所有的设备,并将枚举的设备注册进系统;
系统在匹配上之后,调用设备的驱动; 在这里插入图片描述
PCI设备根据Vendor ID来匹配驱动;
virtio规范中规定基于PCI的virtio设备,Vendor ID号为:0x1AF4,因此最终调用的驱动入口为virtio_pci_probe;在这里插入图片描述
在probe函数中分配struct virtio_pci_device结构,前文中也提到过它负责将virtio设备和pci设备绑定到一起,最终会在两个设备驱动的probe函数中完成整体结构的初始化,也就是virtio_pci_probe完成一部分,实际的virtio设备驱动中完成一部分;
virtio_pci_modern_probe:该函数的内容就与virtio规范紧密相关了,简单来说,virtio设备都会按照规范填充common、device、isr、notification等功能部分,而virtio_pci_modern_probe函数通过virtio_pci_find_capability去获取对应的能力,并且通过map_capability完成IO空间的映射;
virtio_pci_probe中还设置了virtio_pci_config_ops操作函数集,并传递给virtio驱动,在驱动中调用这些回调函数来操作virtio设备;
register_virtio_device:向系统注册virtio设备,从而也就触发了virtio总线的匹配操作,最终调用virtio_dev_probe函数;
virtio_dev_probe函数中按照virtio规范分阶段设置不同的状态、获取virtio设备的feature等,并最终调用实际设备的驱动程序了;
总结:
virtio_pci_config_ops是vritio配置函数集合,它的成员函数通常是代理virtioPCI代理设备的IO操作,如读写vritioPCI代理设备的PIO和MMIO,vritio设备可以通过该结构体中的各个回调函数来驱动设备

3.3virtio-net

virtio-net数据发送流程
在这里插入图片描述

3.3.1virtio-net初始化在这里插入图片描述

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驱动;

4.virtqueue

Virtqueue 是整个virtio方案的灵魂所在,是virtio驱动和virtio设备的通信方式,每个virtio设备有一个或多个virtioqueue。每个virtqueu包含三个部分,descriptor table、available ring和used ring。descriptor table中每一项用来描述一段缓冲区,包含缓冲区的物理地址GPA和长度,descriptor table的项数标识vritqueue的大学。available ring中每一项的值表示当前可用descriptor table中的indx,有虚拟机内部virtio驱动设置,有QEMU测定virtio设备读取。used ring中每一项的值表示也就使用过的descriptor table中的indx,由vritio设备设置,virtio驱动读取。

4.1数据结构

在这里插入图片描述
通常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一致;

4.2发送

在这里插入图片描述
当驱动需要把数据发送给设备时,流程如上图所示:
①A表示分配一个Buffer并添加到Virtqueue中,①B表示从Used队列中获取一个Buffer,这两种中选择一种方式;
②表示将Data拷贝到Buffer中,用于传送;
③表示更新Avail队列中的描述符索引值,注意,驱动中需要执行memory barrier操作,确保Device能看到正确的值;
④与⑤表示Driver通知Device来取数据;
⑥表示Device从Avail队列中获取到描述符索引值;
⑦表示将描述符索引对应的地址中的数据取出来;
⑧表示Device更新Used队列中的描述符索引;
⑨与⑩表示Device通知Driver数据已经取完了;

4.3接收

在这里插入图片描述
当驱动从设备接收数据时,流程如上图所示:
①表示Device从Avail队列中获取可用描述符索引值;
②表示将数据拷贝至描述符索引对应的地址上;
③表示更新Used队列中的描述符索引值;
④与⑤表示Device通知Driver来取数据;
⑥表示Driver从Used队列中获取已用描述符索引值;
⑦表示将描述符索引对应地址中的数据取出来;
⑧表示将Avail队列中的描述符索引值进行更新;
⑨与⑩表示Driver通知Device有新的可用描述符;

参考:https://www.cnblogs.com/LoyenWang/category/1828942.html

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

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

相关文章

模糊测试Fuzzing基础知识学习笔记

概念 模糊测试(Fuzzing),是一种通过向目标系统提供非预期的输入并监视异常结果来发现软件漏洞的方法。在模糊测试中,用随机坏数据(也称做 fuzz)攻击一个程序,然后观察哪里遭到了破坏。 模糊测试…

6.Mysql自连接

针对相同的表进行的连接被称为“自连接”(self join) 那么为什么要把相同的一张表连接起来呢?一开始还是挺难理解的。把它想象成连接两张不同的表,这样容易理解一些。事实上,自连接还是有很多用处的 1. 在同一张表内进…

模板初识与STL简介

初识模板 引言函数模板定义实例化隐式实例化显式实例化 类模板定义实例化 STL简介STL六大组件 总结 引言 模板是泛型编程的基础 在之前我们介绍过函数重载,可以定义许多函数名相同参数列表不同的重载函数,来实现不同类型的相似操作。调用重载函数时会根…

chatgpt赋能python:归一化在PyTorch中的运用

归一化在PyTorch中的运用 PyTorch是一种广泛使用的深度学习框架,它可以用于训练和预测各种类型的神经网络。在深度学习中,归一化是提高模型性能的一种常用技术。归一化是指将输入数据进行标准化或规范化处理,以确保数据的统一性和一致性。在…

golang硬核技术(二)go程序从启动到运行到底经历了啥

前言 go相对其他语言,对并发的支持更友好。这使得他的设计和其他程序迥然不同。让我们来看看它都是如何初始化程序的,从程序加载到运行到底经历的什么。 我们继续之前的版本1.18.4 汇编入口 首先我们编译一个hello world 程序。 package main impor…

python--连接oracle数据库

python--连接oracle数据库 前言一、安装cx_Oracle二、导入库三、数据库操作实例3.1 连接3.2数据库查询3.3数据库插入3.4 实例从某网站上面爬取彩票号码 四、异常4.1、运行时,出现连接数据库失败:DatabaseError:DPI-1047解决连接失败问题1、查看Oracle的版本号2、进入…

辅助驾驶功能开发-功能规范篇(21)-1-XP行泊一体方案功能规范

XPilot Safety 主动安全系统 一、前向碰撞预防(Forward Collision Prevention) - 产品定义 基于车辆前向视觉模块和前毫米波雷达的感知能力,对车辆前方扇形区域内的车辆和VRU(弱势道路使用者) 有可能与本车的运行路线发生碰撞,进行预警、碰撞伤害降低或碰撞避免的一系列…

QT 简易视频播放器版本1.1

设计Qt界面实现播放、暂停、停止、下一集、上一集、快进、后退、倍速播放、进度调节,音量调节、视频播放列表等功能 先上演示效果: ui界面设计 videoplayer.h #ifndef VIDEOPLAYER_H #define VIDEOPLAYER_H#pragma execution_character_set("utf-…

深入了解Promise机制并使用JS实现一个Promise(一)

前言 关于为什么会有Promise以及Promise的一些用法和基本机制可以参考之前的文章JS中的异步与Promise使用整体来说,Promise可以帮助我们很好的解决异步的问题,号称是异步的终极解决方案。在浏览器中Promise是使用C实现的,今天就使用js来实现…

JSP原理以及基本语法

1、JSP原理 什么是JSP? Java Server Pages:Java服务器页面,和Servlet一样是动态Web技术! 和HTML的区别? HTML是静态页面。在JSP页面中可以嵌入Java代码,为用户提供动态的数据。 JSP 和 Servlet 的关系…

枚举一个进程中的所有线程

在 Win32 开发中,如果需要获取程序运行过程中的一些较为底层的信息,你可能需要使用到 Tool Helper 库。但我愿意称之它为 Win32 中的 “害群之马”。何解? Tool Helper 库在 16 位 Windows 时代就已经存在了,这个库主要用来提供一…

今天给我的Ubuntu服务器挂在了一个4T的硬盘却只能识别到2T,原来是因为这!涨知识了

前言 今天买的4T机械硬盘到了,准备给我的服务器加装上,用来作为Nextcloud的存储硬盘。把硬盘安装好后就迫不及待的进行挂载,挂载的操作倒是挺顺利的,但是无论怎么操作Ubuntu系统识别到的大小居然都是2T,最后没办法&am…

chatgpt赋能python:开方在Python中的用法

开方在Python中的用法 开方是数学中常见的一种运算,用于求一个数的平方根。在Python中,开方运算可以通过使用math模块中的sqrt函数来实现。本文将介绍开方运算的概念、Python中的应用以及一些常见问题的解决方法。 开方的概念 开方是指,对…

chatgpt赋能python:在Python中运行程序的方法介绍

在Python中运行程序的方法介绍 Python是一种广泛使用的编程语言,也是人工智能和数据科学领域的首选。在这篇SEO文章中,我们将介绍Python中运行程序的几种方法。 1. 在Python环境中运行程序 Python环境是一个Python解释器及其标准库的集合。为了在Pyth…

Redis7【⑥ Redis复制(replica)】

Redis复制 Redis 复制(Replication)是 Redis 的一项核心功能,用于将一个 Redis 数据库的所有数据复制到另一个 Redis 实例上。Redis 复制可以提高系统的可用性、可靠性和扩展性,使得在发生故障时可以快速地恢复数据。 Redis 复制…

【TiDB v7.1.0】资源管控调研及评测

作者: angryart 原文来源: https://tidb.net/blog/ad24240a 多租户是什么 有语云,食在广州,玩在杭州,死在柳州,广东人除了天上飞的飞机不吃,地上走的坦克不吃,其它的什么都吃&am…

Mybatis面试题--MyBatis一级缓存,二级缓存

Mybatis的一级、二级缓存用过吗? 一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当Session进行flush或close之后,该Session中的所有Cache就将清空,默认打开一级缓存 二级缓存 是基于n…

Python将多维列表「拉伸」为一维列表的10种方式

来源:投稿 作者:Fairy 编辑:学姐 在Python编程中,列表是一种常用的数据类型。当我们遇到了一个嵌套列表,如果想将它扁平化为一维列表,就可以使用下面10种方法之一来实现这个需求。 1. 使用两层循环遍历 l…

【记录】实践场景

Apache Doris 在京东搜索实时 OLAP 探索与实践 https://doris.apache.org/zh-CN/blog/JD_OLAP/ 通过对比开源的几款实时OLAP引擎,我们发现doris和clickhouse能够满足我们的需求,但是clickhouse的并发度太低是个潜在的风险,而且clickhouse的数…

已将该虚拟机配置为使用 64 位客户机操作系统。但是,无法执行 64 位操作。

错误提示: 一般只有下面几种方法 百度经验解决方法 http://jingyan.baidu.com/article/90bc8fc859b481f653640cac.html http://jingyan.baidu.com/article/25648fc1bfd4a29190fd0067.html 2.第二种方法 检测问题所在: 下载LeoMoon CPU-V 检查一下CP…