简单分析Linux虚拟化KVM-Qemu之vhost-net

news2024/11/15 9:09:51

说明:

  1. KVM版本:5.9.1

  2. QEMU版本:5.0.0

  3. 工具:Source Insight 3.5, Visio

1. 概述

让我们先来看看问题的引入,在之前的virtio系列文章中,网络虚拟化的框架如下图所示:

  • Qemu中的virtio-net设备数据包收发,通过用户态访问tap设备完成的;

  • 收发过程涉及Guest OS,KVM,Qemu中的virtio-net设备,Host中的网络协议栈等的交互,路径长并且涉及的切换多,带来了性能的损耗;

  • vhost-net的引入,就是将vitio-net后端设备的数据处理模块下沉到Kernel中,从而提高整体的效率;

vhost-net的框架图如下:

  • 从图中可以看出,Guest的网络数据交互直接可以通过vhost-net内核模块进行处理,而不再需要从内核态切换回用户态的Qemu进程中进行处理;

  • 之前的文章分析过virtio设备与驱动,针对数据传遵循virtio协议,因此vhost-net中需要去实现virtqueue的相关机制;

本文将分析vhost-net的原理,只说重点,进入主题。

2. 数据结构

vhost-net内核模块的层次结构如下图:

  • struct vhost_net:用于描述Vhost-Net设备。它包含几个关键字段:1)struct vhost_dev,通用的vhost设备,可以类比struct device结构体内嵌在其他特定设备的结构体中;2)struct vhost_net_virtqueue,实际上对struct vhost_virtqueue进行了封装,用于网络包的数据传输;3)struct vhost_poll,用于socket的poll,以便在数据包接收与发送时进行任务调度;

  • struct vhost_dev:描述通用的vhost设备,可内嵌在基于vhost机制的其他设备结构体中,比如struct vhost_net,struct vhost_scsi等。关键字段如下:1)vqs指针,指向已经分配好的struct vhost_virtqueue,对应数据传输;2)work_list,任务链表,用于放置需要在vhost_worker内核线程上执行的任务;3)worker,用于指向创建的内核线程,执行任务列表中的任务;

  • struct vhost_virtqueue:用于描述设备对应的virtqueue,这部分内容可以参考之前virtqueue机制分析,本质上是将Qemu中virtqueue处理机制下沉到了Kernel中。关键字段如下:1)struct vhost_poll,用于poll eventfd对应的文件,当不满足处理请求时会添加到eventfd对应的等待队列中,而一旦被唤醒,该结构体中的struct vhost_work(执行函数被初始化为handle_tx_kick,以发送为例)将被放置到内核线程中去执行;

结构体的核心围绕着数据和通知机制,其中数据在vhost_virtqueue中体现,而通知主要是通过vhost_poll来实现,具体的细节下文将进一步描述。

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

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

3. 流程分析

3.1 初始化

vhost-net为内核模块,注册为misc设备,Qemu通过系统调用接口与内核交互,Qemu中的初始化如下图:

  • Qemu中tap设备初始化在net_init_tap中完成,其中net_init_tap_one打开vhost-net设备文件,用于与内核的vhost-net交互;

  • vhost_set_backend_type:设置vhost的后端类型,以及vhost的操作函数集。目前有两种vhost后端,一种是在内核态实现的virtio后端,一种是在用户态中实现的virtio后端;

  • kernel_ops:vhost的内核操作函数集,都是一些回调函数的实现,最终会通过vhost_kernel_call-->ioctl-->vhost-net.ko路径,进行配置;

ioctl系统调用,与驱动交互简单来说可以分为三大类,下边分别介绍几个关键的设置:

  1. vhost net设置

  2. VHOST_SET_OWNER:底层会为调用者创建一个内核线程,对应到前文中数据结构中的vhost_worker,同时在vhost_dev结构体中还会保存调用者线程的内存空间数据结构;

  3. VHOST_NET_SET_BACKEND:设置vhost-net的后端设备,比如Qemu往内核态传递的tap设备对应的fd,从而让vhost-net直接与tap设备进行通信;

  4. vhost dev设置从Guest OS中的虚拟地址到最终的Host上的物理地址映射关系如上图所示,如果在Guest OS中要将数据发送出去,实际上只需要将Qemu中关于Guest OS的物理地址布局信息传递下去,此外再结合VHOST_SET_OWNER时传递的内存空间信息,就可以根据映射关系找到Guest OS中的数据对应到Host之上的物理地址,完成最后搬运即可;

  5. VHOST_SET_MEM_TABLE:将Qemu中的虚拟机物理地址布局信息传递给内核,为了解释清楚这个问题,可以回顾一下之前内存虚拟化中的一张图:

  6. vhost vring设置

  7. VHOST_SET_VRING_KICK:设置vhost-net模块前端virtio驱动发送通知时触发的eventfd,通知机制,最终触发handle_kick函数的执行;

  8. VHOST_SET_VRING_CALL:设置vhost-net后端到虚拟机virtio前端的中断通知,参考之前文章中的irqfd机制;

  9. 此外关于vring的设备还包括vring的大小,地址信息等;

上述的这些设置的流程路径如下,只画出了关键路径:

  • 当Guest OS中的virtio-net驱动完成初始化后,会通过vp_set_status来设置状态,以通知后端驱动已经ready,此时会触发VM的退出并进入KVM进行异常处理,最终路由给Qemu;

  • Qemu中的vcpu线程监测异常,当检测到KVM_EXIT_MMIO时,去回调注册该IO区域的读写函数,比如virtio_pci_common_write函数,在该函数中逐级往下最终调用到vhost_net_start函数;

  • 在vhost_net_start中最终去通过kernel_ops函数集去设置底层并交互;

初始化完成后,接下来让我们看看数据的发送与接收,为了能将整个流程表达清楚,我会将完整的图拆分成几个步骤来讲述。

3.2 数据发送

1)

发送前的框图如下:

  • Guest OS中的virtio-net驱动中维护两个virtqueue,分别用于发送和接收;

  • 图中的datagram表示的是需要发送的数据;

  • KVM模块提供了ioeventfd和irqfd用于通知机制;

  • vhost-net模块中创建好了vhost_worker内核线程,用于处理任务;

2)

  • 当数据包准备好之后,通过往kick fd上触发信号,从而唤醒vhost_worker内核线程来调用handle_tx_kick进行数据的发送;

  • 当Tap/Tun不具备发送条件时,vhost_worker会poll在socket上,等待Tap/Tun的唤醒,一旦被唤醒后可以调用handle_tx_net发送;

  • 最终的handle_tx完成具体的发送;

3)

  • vhost_get_vq_desc函数在vritqueue中查找可用的buffer,并将信息存储到iov中,以便更好的访问;

  • sock->ops->sendmsg()函数,实际调用的是tun_sendmsg函数,在该函数中分配了skb结构体,并将iov[]中的信息传递过来,最终如图中所示完成数据的拷贝和发送,通过NIC发送出去;

4)

  • 数据发送完毕后,通过irqfd机制通知vcpu;

3.3 数据接收

数据的接收是发送的逆过程,流程一致:

1)

  • 初始化部分与发送过程一致;

  • Tap/Tun驱动从NIC接收到数据包,准备发送给vhost-net;

2)

  • vhost-net中的vhost_worker线程也poll在两个fd之上,与发送端类似;

  • kick fd上触发信号时最终调用handle_rx_kick函数,Tap/Tun对应的socket上触发信号时,调用handle_rx_net函数;

  • 最终通过handle_rx来完成实际的接收;

3)

  • 接收过程中,vhost_get_vq_desc获取virtqueue中的可用buffer,并将信息存储到iov[]中;

  • sock->ops->recvmsg()函数实际指向tun_recvmsg函数,在该函数中最终完成数据的传递;

4)

  • 数据接收完成后,通过irqfd机制通过vcpu,从而在Guest OS中进行处理;

 

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

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

相关文章

WebRTC-NACK、Pacer和拥塞控制和FEC

NACK机制发送端实现NACK的三个重点流程:发送RTP报文,实时存储报文到packet_history_队列处理接收到的RTCP NACK报文把nack包里的序号放到nack_sequence_numbers丢包队列重发NACK反馈的RTP报文重发报文这里有三点需要注意:1)会判断…

Allegro如何查看PCB上器件的库路径操作指导

Allegro如何查看PCB上器件的库路径操作指导 在做PCB设计的时候,有时需要检查PCB上器件使用的库的路径是否正确,Allegro支持快速将PCB上所有器件的库路径都列出来 如下图 如何显示这个报表,具体操作如下 点击Tools点击Report

蓝桥杯-求和问题

蓝桥杯-求和问题1、问题描述2、解法一:暴力解法(两层循环)3、解法二:结合律(一层循环解决)1、问题描述 给定 n 个整数 a1,a2,...,ana_1,a_2,...,a_na1​,a2​,...,an​,求它们两两相乘再相加的和,即: Sa1.a2a1.a3...a…

Presto 在美图的实践

导读:本文的主题是Presto高性能引擎在美图的实践,首先将介绍美图在处理ad-hoc场景下为何选择Presto,其次我们如何通过外部组件对Presto高可用与稳定性的增强。然后介绍在美图业务中如何做到合理与高效的利用集群资源,最后如何利用…

项目管理的主要内容包括哪些?盘点好用的项目管理系统软件

阅读本文您将了解:1、项目管理的主要内容包括哪些2、好用的项目管理软件 项目管理是为了实施一个特定目标,所实施的一系列针对项目要素的管理过程,包括过程、手段以及技术等。 通过项目管理,我们能够提前安排和控制项目的时间、…

深度解析:我如何用300并发把数据库压挂了

问:为什么300的并发能把支持最大连接数4000数据库压死? 买了一台数据库,最大连接数的参数是 4000,看起来很棒!但是 cpu 和内存并不咋好!是 2c4g的超低配制。但是想着反正业务量也不大,不如先扛…

【vulhub漏洞复现】CVE-2018-2894 Weblogic任意文件上传漏洞

一、漏洞详情影响版本weblogic 10.3.6.0、weblogic 12.1.3.0、weblogic 12.2.1.2、weblogic 12.2.1.3WebLogic是美国Oracle公司出品的一个application server,确切的说是一个基于JAVAEE架构的中间件,WebLogic是用于开发、集成、部署和管理大型分布式Web应…

Oracle Primavera P6 登录提示错误“该用户已经登录“(SQLite)

目录 引言 解决思路 使用工具 处理办法 引言 在使用Oracle Primavera P6 非正常退出后,Professional再次登录或出现异常,体现为“该用户已经登录。请使用另一个用户名” 以上为近期一个朋友请教的问题,为了给后续出现同样问题朋友给予解…

有限元中四面体的一些积分公式

文章目录有限元中四面体的相关积分公式有限元中四面体的相关积分公式 在 xyzxyzxyz 坐标系中通过四个点 (xi,yi,zi),(xj,yj,zj),(xm,ym,zm),(xp,yp,zp)(x_i, y_i, z_i), (x_j, y_j, z_j), (x_m, y_m, z_m), (x_p, y_p, z_p)(xi​,yi​,zi​),(xj​,yj​,zj​),(xm​,ym​,zm​…

解决PyCharm下OpenCV没有自动补全、函数提示的问题!

Content找到Python环境下的OpenCV安装目录中的“cv2.pyd”文件复制cv2.pyd文件到site-packages文件夹中重启PyCharm,cv2就可以正常使用了最近使用PyCharm编写一段需要使用Opencv库的代码,却发现cv2没有自动补全和函数提示了。博主自己找到以下解决办法&a…

ThreadLocal使用

1、简介ThreadLocal类用来提供线程内部的局部变量,不同的线程之间不会相互干扰这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量在线程的生命周期内起作用,可以减少同一个线程…

CentOS系统编译安装PHP-5.6.27版本

一、手动安装编译工具: yum install -y gcc gcc-c 二、添加用户和用户组: groupadd web useradd -M -s /sbin/nologin -g web php 三、yum安装依赖: yum -y install libmcrypt libmcrypt-devel mcrypt mhash libxml2-devel libpng-devel l…

适应多场景的云桌面metaScreenshare1.0 sdk

概述 metaRTC新推出云桌面metaScreenshare1.0 sdk版本,基于metaIPC1.0搭建,基于mqtt通信,同时支持windows/linux/android操作系统远程桌面控制,支持Nvidia和Intel的GPU编码,适应多种业务场景,可方便集成到…

ElasticSearch 学习笔记总结(四)

文章目录一、ES继承 Spring Data 框架二、SpringData 功能集成三、ES SpringData 文档搜索四、ES 优化 硬件选择五、ES 优化 分片策略六、ES 优化 路由选择七、ES 优化 写入速度优化七、ES 优化 内存设置八、ES 优化 重要配置一、ES继承 Spring Data 框架 Spring Data 是一个用…

【案例教程】拉格朗日粒子扩散模式FLEXPART

拉格朗日粒子扩散模式FLEXPART通过计算点、线、面或体积源释放的大量粒子的轨迹,来描述示踪物在大气中长距离、中尺度的传输、扩散、干湿沉降和辐射衰减等过程。该模式既可以通过时间的前向运算来模拟示踪物由源区向周围的扩散,也可以通过后向运算来确定…

CKKS自举笔记(CKKS Bootstrapping)

文章目录CKKS Bootstrapping流程流程的框架如何做同态取模操作直接泰勒展开(naive idea)采用二倍角公式来拟合(欧密2018)如何做同态编码或解码CKKS的编码和解码基础知识(明文下面怎么做)同态的旋转、共轭&a…

Linux 进程:进程控制

目录一、进程创建1.fork2.vfork二、进程终止三、进程等待四、进程替换1.理解程序替换2.子进程在程序替换中的作用Linux的进程控制分为四部分: 进程创建进程终止进程等待进程替换 一、进程创建 常见的创建进程的函数有两个: pid_t fork(void)pid_t vf…

一篇文章帮助你初步了解CDN内容分发网络

文章目录CDN内容分发网络CDN内容分发网络的工作原理CDN的作用CDN如何实现内容的加速CDN内容分发网络 CDN(Content Delivery Network)内容分发网络。CDN 是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过…

手撕CSDN博文:学用curl命令获取博文页面源码,学不会爬虫先手剥CSDN博文阅读点赞收藏和评论数量

学用curl命令获取博文页面源码,学不会爬虫先手剥CSDN博文阅读点赞收藏和评论数量。 (本文获得CSDN质量评分【xx】)【学习的细节是欢悦的历程】Python 官网:https://www.python.org/ Free:大咖免费“圣经”教程《 python 完全自学教程》&…

客户服务软件推荐榜:28款!

在这个竞争激烈的时代,做到服务对企业的存亡有着深刻的意义。改善客户服务,做好客户服务工作,是关键,因为客户服务团队代表着企业的形象,面孔,客户有可能 不大会记得企业的某个东西,但是他们将会…