【原创】Linux虚拟化KVM-Qemu分析(九)之virtio设备
背景
Read the fucking source code!
--By 鲁迅A picture is worth a thousand words.
--By 高尔基
说明:
- KVM版本:5.9.1
- QEMU版本:5.0.0
- 工具:Source Insight 3.5, Visio
- 文章同步在博客园:
https://www.cnblogs.com/LoyenWang/
新的一年, 大家牛起来!
祝小姐姐们:
落雁沉鱼 兰质蕙心 明眸皓齿 螓首蛾眉 天生丽质 天香国色 杏脸桃腮 煦色韶光 涎玉沫珠 宜嗔宜喜 远山芙蓉 艳色绝世 余霞成绮 阿娇金屋 逞娇呈美 国色天香 花颜月貌 绝色佳人 暗香盈袖 闭月羞花 倾国倾城 温婉娴淑 千娇百媚 仪态万千...
祝男的:
新年好。
1. 概述
先来张图:
- 图中罗列了四个关键模块:
Virtio Device
、Virtio Driver
、Virtqueue
、Notification(eventfd/irqfd)
; Virtio Driver
:前端部分,处理用户请求,并将I/O请求转移到后端;Virtio Device
:后端部分,由Qemu来实现,接收前端的I/O请求,并通过物理设备进行I/O操作;Virtqueue
:中间层部分,用于数据的传输;Notification
:交互方式,用于异步事件的通知;
想在一篇文章中写完这四个模块,有点too yong too simple
,所以,看起来又是一个系列文章了。
本文先从Qemu侧的virtio device入手,我会选择从一个实际的设备来阐述,没错,还是上篇文章中提到的网络设备。
2. 流程分析
在Qemu的网卡虚拟化时,通常会创建一个虚拟网卡前端和虚拟网卡后端,如下图:
- 在虚拟机创建的时候指定参数:
-netdev tap, id = tap0, -device virtio-net-pci, netdev=tap0
; - 创建一个
Tap
网卡后端设备; - 创建一个
Virtio-Net
网卡前端设备; - 网卡前端设备和后端设备进行交互,最终与Host的驱动完成数据的收发;
全文围绕着Tap
设备的创建和Virtio-Net
设备的创建展开。
入口流程如下:
- Qemu的代码阅读起来还是比较费劲的,各种盘根错节,里边充斥着面向对象的思想,先给自己挖个坑,后续会专题研究的,
this is for you, you have my words.
; - 图中与本文相关的有三个模块:1)模块初始化;2)网络设备初始化;3)设备初始化;
- Qemu中设备模拟通过
type_init
先编译进系统,在module_call_init
时进行回调,比如图中的xxx_register_types
,在这些函数中都是根据TypeInfo
类型信息来创建具体的实现信息; net_init_client
用来创建网络设备,比如Tap
设备;device_init_func
根据Qemu命令的传入参数创建虚拟设备,比如Virtio-Net
;
- Qemu中设备模拟通过
下边进入细节,the devil is in the details
。
3. tap创建
从上文中,我们知道,Tap
与Virtio-Net
属于前后端的关系,最终是通过结构体分别指向对方,如下图:
NetClientState
是网卡模拟的核心结构,表示网络设备中的几个端点,两个端点通过peer
指向对方;
创建Tap设备的主要工作就是创建一个NetClientState
结构,并添加到net_clients
链表中:
函数的调用细节如下图:
- 处理流程只关注了核心的处理流程,整个过程有很多关于传入参数的处理,选择性忽略了;
net_tap_init
:与Host的tun
驱动进行交互,其实质就是打开该设备文件,并进行相应的配置等;net_tap_fd_init
:根据net_tap_info
结构,创建NetClientState
,并进行相关设置,这里边net_tap_info
结构体中的接收函数指针用于实际的数据传输处理;tap_read_poll
用于将fd添加到Qemu的AioContext中,用于异步响应,当有数据来临时,捕获事件并进行处理;
以上就是Tap后端的创建过程,下文将针对前端创建了。
4. virtio-net创建
这是一个复杂的流程。
4.1 数据结构
Qemu中用C语言实现了面向对象的模型,用于对设备进行抽象,精妙!
针对Virtio-Net设备,结构体及拓扑组织关系如下图:
DeviceState
作为所有设备的父类,其中派生了VirtIODevice
和PCIDevice
,而本文研究的Virtio-Net
派生自VirtIODevice
;- Qemu中会虚拟一个PCI总线,同时创建
virtio-net-pci
,virtio-balloon-pci
,virtio-scsi-pci
等PCI代理设备,这些代理设备挂载在PCI总线上,同时会创建Virtio总线,用于挂载最终的设备,比如VirtIONet
; - PCI代理设备就是一个纽带;
4.2 流程分析
与设备创建相关的三个函数,可以从device_init_func
入口跟踪得知:
- 当Qemu命令通过
-device
传入参数时,device_init_func
会根据参数去查找设备,并最终调用到该设备对应的类初始化函数、对象初始化函数、以及realize函数; - 所以,我们的分析就是这三个入口;
4.2.1 class_init
- 在网卡虚拟化过程中,参数只需要指定PCI代理设备即可,也就是
-device virtio-net-pci, netdev=tap0
,从而会调用到virtio_net_pci_class_init
函数; - 由于实现了类的继承关系,在子类初始化之前,需要先调用父类的实现,图中也表明了继承关系以及调用函数顺序;
- C语言实现继承,也就是将父对象放置在自己结构体的开始位置,图中的颜色能看出来;
4.2.2 instance_init
类初始化结束后,开始对象的创建:
- 针对
Virtio-Net-PCI
的实例化比较简单,作为代理,负责将它的后继对象初始化,也就是本文的前端设备Virtio-Net
;
4.2.3 realize
realize
的调用,比较绕,简单来说,它的类继承关系中存在多个realize
的函数指针,最终会从父类开始执行,一直调用到子类,而这些函数指针的初始化在什么时候做的呢?没错,就是在class_init类初始化的时候,进行了赋值,细节不表,结论可靠;- 最终的调用关系就如图了;
到目前为止,我们似乎都还没有看到Virtio-Net
设备的相关操作,不用着急,已经很接近真相了:
virtio_net_pci_realize
函数,会触发virtio_device_realize
的调用,该函数是一个通用的virtio设备实现函数,所有的virtio设备都会调用,而我们的前端设备Virtio-Net
也是virtio设备;virtio_net_device_realize
就到了我们的主角了,它进行了virtio通用的设置(后续在数据通信中再分析),还创建了一个NetClientState
端点,与Tap
设备对应,分别指向了对方,惺惺相惜,各自安好;virtio_bus_device_plugged
表示设备插入总线时的处理,完成的工作就是按照PCI总线规划,配置各类信息,以便与Guest OS中的virtio驱动交互,后续的文章再分析了;
本文基本捋清了虚拟网卡前端设备和后端设备的创建过程,完成的工作只是绑定了彼此,数据交互以及通知机制,留给后续吧。
参考
《 Virtual I/O Device (VIRTIO) Version 1.1》
https://www.redhat.com/en/blog/virtio-devices-and-drivers-overview-headjack-and-phone
欢迎关注个人公众号,不定期更新技术文章。
【原创】Linux虚拟化KVM-Qemu分析(九)之virtio设备的更多相关文章
- KVM/QEMU/qemu-kvm/libvirt 概念全解
目录 目录 前言 KVM QEMU KVM 与 QEMU qemu-kvm Libvirt Libvirt 在 OpenStack 中的应用 前言 如果是刚开始接触虚拟机技术的话, 对上述的概念肯定会 ...
- 【原创】Linux虚拟化KVM-Qemu分析(三)之KVM源码(1)
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: KVM版本:5.9 ...
- 【原创】Linux虚拟化KVM-Qemu分析(一)
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: KVM版本:5.9 ...
- 【原创】Linux虚拟化KVM-Qemu分析(四)之CPU虚拟化(2)
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: KVM版本:5.9 ...
- 【原创】Linux虚拟化KVM-Qemu分析(五)之内存虚拟化
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: KVM版本:5.9 ...
- 【原创】Linux虚拟化KVM-Qemu分析(八)之virtio初探
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: KVM版本:5.9 ...
- Linux虚拟化技术KVM、QEMU与libvirt的关系(转)
说明:个人理解,KVM是内核虚拟化技术,而内核是不能使用在界面上使用的,那么此时QEMU提供了用户级别的使用界面,相互辅助.当然,单独使用QEMU也是可以实现一整套虚拟机,不过QEMU+KVM基本是标 ...
- 【原创】Linux虚拟化KVM-Qemu分析(十)之virtio驱动
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: KVM版本:5.9 ...
- 【原创】Linux虚拟化KVM-Qemu分析(十一)之virtqueue
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: KVM版本:5.9 ...
随机推荐
- C# datagridview设置标题为汉语
正常情况下,在给datagridview绑定数据源之后,显示的是SQL语句中的栏位,如下 我们想让标题显示汉语,可以有一下两种方法 1.在SQL中设置列别名 SELECT TITLE AS '报警标题 ...
- 判断最长回文串——暴力、延展、Manacher
1. 暴力 时间复杂度O(n^3). 2. 延展 以某一字符为中心,设置left, right两个变量同时向外扩,判断他们指向字符是否相同.注意分奇偶讨论.时间复杂度O(n^2). 3. Manach ...
- Cisco之show基础命令
#show version:显示版本信息等 #show running-config:显示当前(活动,并不一定保存)的配置 #show interfaces fastEthernet 0/1:进入接 ...
- 4. Tomcat调优
1, 调内存 JVM 2, 调网络处理框架 普通io/nio,netty https://segmentfault.com/a/1190000008873688 https://ww ...
- 页面渲染html的过程
浏览器渲染页面的一般过程: 1.浏览器解析html源码,然后创建一个 DOM树.并行请求 css/image/js在DOM树中,每一个HTML标签都有一个对应的节点,并且每一个文本也都会有一个对应的文 ...
- CODEVS 2542单词__fail树
2542 单词 2013年省队选拔赛天津市队选拔赛 时间限制: 2 s 空间限制: 256000 KB 题目等级 : 大师 Master 题目描述 Description 小张最近在忙毕 ...
- Excel 如何使用 函数 实现传说中的 多条件中位数 (MEDIANIFS)?
数据科学交流群,群号:189158789,欢迎各位对数据科学感兴趣的小伙伴的加入! 实际上Excel中根本没有MEDIANIFS,但我们可以通过一些方式进行实现: 比如如下图的需求,需要求这一列中,1 ...
- Jumpserver-堡垒机
Jumpserver-堡垒机 1.基于Docker搭建Jumpserver堡垒机 1.1 下载镜像 1.2 运行镜像 1.2.1 官网步骤-Docker快速启动 1.3 浏览器访问 2.Jumpser ...
- Nginx,Nginx 搭建图片服务器
Nginx Nginx 概述 反向代理 工作流程 优点 1:保护了真实的web服务器,保证了web服务器的资源安全 2:节约了有限的IP地址资源 3:减少WEB服务器压力,提高响应速度 4:其他优点 ...
- java正则表示判断。是否以某个关键字结尾的
String defaultPageSqlId = ".*ByPaging$"; System.out.println("dsdsdsdByPaging".ma ...