virtio代码分析(一)-qemu部分

2023-11-06

virtio内容众多,代码分布于qemu,linux,dpdk等中,而且分为frontend和backend,可以运行于userspace也可以运行于kernelspace,极其难以理解,不看代码只看原理性文档往往流于表面,只有真正看懂了代码才能理解virtio。

以qemu和linux中的virtio-net举例分析代码,这儿只分析qemu部分virtio代码,在qemu中创建一个virtio-net设备,tap作为backend,有2个queue,那么qemu中tx和rx各2个,再加1个controll queue就得创建5个queue了

-netdev tap,id=hostnet0,queues=2
-device virtio-net-pci,host_mtu=1450,mq=on,vectors=5,netdev=hostnet0,id=net0,mac=fa:16:3e:d8:fe:81,bus=pci.0,addr=0x3

我们先看数据结构NetClientState,重点关注peer和incoming_queue

struct NetClientState {
    NetClientInfo *info;
    int link_down;
    QTAILQ_ENTRY(NetClientState) next;
    NetClientState *peer;
    NetQueue *incoming_queue;
    char *model;
    char *name;
    char info_str[256];
    unsigned receive_disabled : 1;
    NetClientDestructor *destructor;
    unsigned int queue_index;
    unsigned rxfilter_notify_enabled:1;
    int vring_enable;
    int vnet_hdr_len;
    bool is_netdev;
    QTAILQ_HEAD(, NetFilterState) filters;
};

先看qemu中的参数-netdev,创建了2个TAPState,每个TAPState包含一个NetClientState,函数qemu_net_client_setup参数peer为空,所以创建的ncs中peer为空。

net_tap_fd_init
  └─qemu_new_net_client
      └─qemu_net_client_setup//这个函数参数peer为NULL

再看qemu的参数-device中有netdev=hostnet0,而-netdev中有id=hostnet0,根据name找到了刚才tap创建的2个NetClientState和queue个数为2

typedef struct NICPeers {
    NetClientState *ncs[MAX_QUEUE_NUM];
    int32_t queues;
} NICPeers;
typedef struct NICConf {
    MACAddr macaddr;
    NICPeers peers;
    int32_t bootindex;
} NICConf;
#define DEFINE_NIC_PROPERTIES(_state, _conf)                            \
    DEFINE_PROP_MACADDR("mac",   _state, _conf.macaddr),                \
    DEFINE_PROP_NETDEV("netdev", _state, _conf.peers)
static Property virtio_net_properties[] = {
DEFINE_NIC_PROPERTIES(VirtIONet, nic_conf),
}
set_netdev
  └─qemu_find_net_clients_excep

根据queue个数生成2个NetClientState,现在有2个NetClientState,成对peer互相指向对方

virtio_net_device_realize
  └─qemu_new_nic
      └─qemu_net_client_setup//和tap init相比,peer不为NULL,是tap的NetClientState

qemu对virtio-net-pci的初始化

virtio_device_realize
  ├─virtio_net_pci_realize
  ├─virtio_bus_device_plugged
  |   ├─virtio_pci_device_plugged//初始化virtio-pci设备
  |   └─vdev->dma_as = &address_space_memory;//分配dma_as
  └─memory_listener_register
      └─virtio_memory_listener_commit
          └─virtio_init_region_cache

virtio_net_device_realize
  ├─virtio_init
  ├─virtio_net_add_queue
  |   └─virtio_add_queue//rx和tx的handle_output分别是virtio_net_handle_rx和virtio_net_handle_tx_bh
  ├─qemu_bh_new//生成一个qemu bh virtio_net_tx_bh
  └─virtio_add_queue//控制qemu是virtio_net_handle_ctrl

guest把分配的vring地址传递给qemu

virtio_pci_common_write
  └─virtio_queue_set_rings
      └─virtio_init_region_cache
          └─address_space_cache_init//这个函数等qemu内存虚拟化时一块分析

给kvm注册一个eventfd,等guest kick时,kvm通知qemu进程

virtio_pci_common_write
  └─virtio_pci_start_ioeventfd
      └─virtio_bus_start_ioeventfd
          └─virtio_device_start_ioeventfd_impl
              ├─virtio_bus_set_host_notifier
              |   └─virtio_pci_ioeventfd_assign
              |       └─memory_region_add_eventfd
              └─event_notifier_set_handler(virtio_queue_host_notifier_read)

guest里的virtio-net通知tx或者rx写mmio,带着vector号,kvm通知qemu

virtio_pci_notify_write
  └─virtio_queue_notify
      ├─handle_output
      └─event_notifier_set
virtio_queue_host_notifier_read
  └─virtio_queue_notify_vq
      └─handle_output

不管是发送还是接收,都是guest设置好vring中的address,是guest的physical address,需要qemu调用address_space_map转换成自己的virtual address。

收发包的原理就是tap收到发往guest,从guest收到发往tap,tap和virtio-net-pci peer互相指,从自己NetClientState的peer找到对端的NetClientState,然后找到NetClientState中的incoming_queue,incoming_queue中deliver调用receive函数。

qemu读tap,然后调用virtio_net_receive,如果virtio_net_receive不能receive,等guest kick时再用virtio_net_handle_rx收包。

tap_send
  └─qemu_send_packet_async
      └─qemu_send_packet_async_with_flags
          └─qemu_net_queue_send
              └─调用到virtio-net的virtio_net_receive

学习地址: Dpdk/网络协议栈/vpp/OvS/DDos/NFV/虚拟化/高性能专家-学习视频教程-腾讯课堂
更多DPDK相关学习资料有需要的可以自行报名学习,免费订阅,久学习,或点击这里加qun免费
领取,关注我持续更新哦! ! 

guest kick时接收,virtio_net_handle_rx is handle_outpu,rxvq是VRING_DESC_F_WRITE,DMA_DIRECTION_FROM_DEVICE,站在guest角度看问题,从qemu到guest内存

virtio_net_handle_rx
  └─qemu_flush_queued_packets
      └─qemu_flush_or_purge_queued_packets
          └─qemu_net_queue_flush
              └─qemu_net_queue_deliver
                  └─qemu_deliver_packet_iov
                      └─nc_sendv_compat
                          └─virtio_net_receive

virtio_net_receive_rcu
  ├─virtio_net_process_rss选择接收的queue
  |   └─virtqueue_pop
  |       └─virtqueue_split_pop
  |           └─virtqueue_map_desc
  |               └─dma_memory_map
  |                   └─address_space_map
  ├─virtqueue_fill
  ├─virtqueue_flush
  └─virtio_notify

guest kick时发送virtio_net_handle_tx_bh is handle_output

#guest kick时发送virtio_net_handle_tx_bh is handle_output
virtio_net_handle_tx_bh
  └─virtio_net_tx_bh
      ├─virtio_net_flush_tx
      |   ├─virtqueue_pop
      |   |   └─virtqueue_split_pop
      |   |       └─virtqueue_map_desc
      |   |           └─dma_memory_map
      |   |               └─address_space_map
      |   ├─qemu_sendv_packet_async
      |   |   └─qemu_net_queue_send_iov
      |   |       └─qemu_net_queue_deliver_iov
      |   |           └─qemu_deliver_packet_iov
      |   |               └─调用到了对端的peer_receive就是tap_receive
      |   |                  └─tap_write_packet
      |   └─qemu_net_queue_flush
      |       └─qemu_net_queue_deliver
      └─bh的回调函数virtio_net_tx_complete
          ├─virtqueue_push
          |    ├─virtqueue_fill
          |    └─virtqueue_flush
          |        └─vring_used_idx_set
          └─virtio_notify

记录dirty page用于live migration

virtqueue_fill
  ├─virtqueue_unmap_sg
  |   └─dma_memory_unmap
  |       └─address_space_unmap
  |           └─invalidate_and_set_dirty
  └─virtqueue_split_fill
      └─vring_used_write
          └─address_space_write_cached
              ├─flatview_write_continue
              |   └─invalidate_and_set_dirty
              └─address_space_cache_invalidate
  • virtio-net tx时如何选择queue号的?

tx时virtnet_select_queue cpu和queue有一个对应关系,是virtnet_set_affinity分配好的,或者用内核的xps确定queue号。

  • rx时又如何选择queue呢?

virtio_net_process_rss选择接收的queue。rx时看virtio-net-pci用什么中断模块,如果用msix可能每个queue有自己的vector号,中断来了直接定位queue,如果共享只能遍历所有queue了。

  • 那么vhost-net/vhost-user/vhost-vdpa时有时怎么处理NetClientState的?

和原来一样没有什么变化

  • qemu做virtio写元数据时如何和guest保证cache coherence?

一个host cpu写,另一个guest host已经读到cache中,怎么搞?

address_space_cache_invalidate

  • qemu做virtio写virtio vring里buf时如果更新dirty page的?

invalidate_and_set_dirty

等补充内容

vIOMMU时virtio地址怎么转换的?

原文链接https://zhuanlan.zhihu.com/p/308062561

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

virtio代码分析(一)-qemu部分 的相关文章

  • 停止服务时单元陷入故障状态(状态=143)[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 这是我的问题 我有 CentOS 和 java 进程在上面运行 Java进程是通过启动 停止脚本来操作的 它也创建了 java 实例的 p
  • 使用 getopt_long (C++) 如何为两个需要参数编写长选项和短选项?

    include
  • 如何查找boost运行时版本

    我正在编写一个使用 boost 的 C 库 在这个库中 我想包含有关用于编译我的库的二进制版本的 boost 版本的信息 我可以使用宏BOOST VERSION这很好 我还想确定哪个是 boost 的运行时版本 以便我可以与用于编译我的库的
  • 实体框架 - 循环更新属性

    我正在尝试找到一种方法来循环 EF 对象的属性并更新这些属性的值 更具体地说 我有 50 个字段 其中最多填充 50 个下拉列表 所有 50 个可能都需要填充 也可能不需要填充 为了解决这个问题 我有一个中继器 最多可以创建 50 个 DD
  • 如何使用movntdqa避免缓存污染?

    我正在尝试编写一个 memcpy 函数 该函数不会将源内存加载到 CPU 缓存中 目的是避免缓存污染 下面的 memcpy 函数可以工作 但会像标准 memcpy 一样污染缓存 我正在使用带有 Visual C 2008 Express 的
  • 无法使用 Unity 函数在 Visual Studio Code 中获得完整的 Intellisense

    好吧 我知道这个问题已经被问过并回答过很多次了 但我花了大约 3 天的时间试图解决这个问题 但到目前为止我所做的一切都没有奏效 我基本上在 Visual Studio Code 中有部分智能感知 也就是说 它似乎只识别 Unity 类和变量
  • 将 try_emplace 与 shared_ptr 一起使用

    所以我有一个std unordered map
  • C# - 如何将 IntPtr 缓冲区数据保存到文件(最快的方法)?

    我使用此代码将非托管代码中的 IntPtr 缓冲区中的字节保存到文件中 这是一个简单的回调函数 private void callback IntPtr buffer int length byte bytes new byte lengt
  • 无法更新 .mdf 数据库,因为该数据库是只读的(Windows 应用程序)

    我使用 C 创建了一个数据库 Windows 应用程序 我的应用程序在 Windows XP 上成功运行 但在 Vista 或 Windows 7 系统上无法正确执行 我的应用程序显示类似以下内容的消息 无法更新 mdf 数据库 因为该数据
  • WIX 自动生成 GUID *?

    假设我生成产品 ID 为 的 WIX XML 文件 另外 对于每个组件 GUID 我都使用
  • NHibernate 中具有不同类型答案的问题

    我正在尝试找到一个问卷问题的简洁解决方案 假设我有一个Questionnaire类有一个集合Answers e g public class Questionnaire public virtual ISet
  • 让 WIX 在项目中包含引用

    我对 WiX 和设置自定义安装程序完全陌生 所以我对问题的主题表示歉意 我有一个内部业务应用程序 日记 它构建并运行良好 因此我按照教程 官方文档添加 WiX 项目并引用日记的 csproj 然后构建并运行这个最基本版本的 WiX 安装程序
  • 如何使用 Caliburn.Micro MVVM 将焦点设置到控件

    我有一个表单 我想在发生某些用户操作时将焦点设置到文本框 我知道 MVVM 的处理方式是绑定到 VM 属性 但是 TextBox 没有允许这种情况发生的属性 从虚拟机设置焦点的最佳方法是什么 我创建了一个 IResult 实现 可以很好地实
  • 读取所有进程内存以查找字符串变量c#的地址

    我有 2 个用 C 编写的程序 第一个名为 ScanMe 的程序包含一个包含值 FINDMEEEEEEE 的字符串变量 以及一个值为 1546 22915487 的双精度变量 另一个名为 MemoryScan 的程序读取第一个程序的所有内存
  • 什么是多重重继承?

    我将以下称为 多重重新继承 直接继承一个类一次 并通过继承其一个或多个后代来间接继承一次或多次 通过继承一个类的两个或多个后代来间接继承一个类两次或多次 我想知道它是否存在以及如何明确访问嵌入的子对象 1 Professional C 2n
  • lambda 表达式是多线程的吗?

    lambda 表达式是多线程的吗 假设当你将数学公式编写为 lambda 方法时 当你将其传递给另一个方法时 它会是多线程的吗 不是100 清楚你问的是什么 您是否想问 lambda 是否自然地在不同的线程上运行 如果是这样 则它们只是 S
  • 父窗体中的居中消息框[重复]

    这个问题在这里已经有答案了 有没有一种简单的方法可以在 net 2 0中将MessageBox居中于父窗体中 我在 C 中确实需要这个并发现中心消息框 C http bytes com topic c sharp answers 26712
  • jquery ajax“发布”调用

    我是 jQuery 和 Ajax 的新手 并且在 发布 方面遇到问题 我正在使用 jQuery Ajax post 调用将数据保存到数据库 当我尝试保存数据时 它将 null 传递给我的 C 方法 jQuery 看起来像这样 functio
  • 为什么C#不支持多重继承? [复制]

    这个问题在这里已经有答案了 可能的重复 C 应该包含多重继承吗 https stackoverflow com questions 191691 should c include multiple inheritance 为什么C 不支持多
  • 你将如何开始自动化我的工作? - 第2部分

    后续这个问题 https stackoverflow com questions 2796128 how would you start automating my job 在经历了第一波进货 9 小时的复制 粘贴 后 我现在相信我已经满足

随机推荐

  • Java学习之:异常及其处理方式

    文章目录 1 所有异常都继承 Throwable 类 2 分类 3 为什么要处理异常 4 异常处理格式 5 完整异常信息的取得 5 1 常见的异常 6 throws throw 关键字 6 1 throws 用在定义方法上 6 1 1 用在
  • R中重命名数据框列名小技巧

    R中重命名数据框列名 文章目录 前言 一 基础包names函数和索引 二 使用dplyr rename函数 前言 R语言中两种修改数据框列名的小方法 创建名为df的数据框 一 基础包names函数和索引 将第二列名score修改为popul
  • 深入理解Android之Gradle

    转自 http blog csdn net innost article details 48228651 深入理解Android之Gradle 格式更加精美的PDF版请到 https pan baidu com s 1boG2cLD下载
  • SQL语句中的循环

    SQL语句中的循环 SQL语句中的循环类似于foreach循环 可以循环遍历某个表并进行新增 修改和删除的操作 SQL语句中的循环 使用SQL的游标来实现 上示例 declare ID int 声明变量 名称 类型 begin 开始 pri
  • setFocus不能生效的问题

    focusInEvent只有在对象显示出来的情况下设定setFocus才可以触发 这一点help手册里有说明 转一篇文章如下 http blog csdn net alex201030273437 article details 81937
  • CSV简单了解

    1 CSV介绍 CSV全称是Comma Separate Values 这种文件格式可以作为不同程序之间的数据交互的格式 csv就是一种纯文本文件 如 txt doc等 即是一组字符序列 字符之间已英文字符的逗号或制表符 Tab 分隔 语法
  • Python数据结构-----leetcode232.用栈实现队列

    目录 前言 方法讲解 示例 代码实现 232 用栈实现队列 前言 我们都知道队列的特征是先进先出 就跟排队一样先到先得 而栈的特征是后进后出 那这里我们怎么去通过两个栈来实现一个队列的功能呢 这一期我们一起来学习吧 方法讲解 这里需要准备好
  • 订单业务中的重要问题:超卖问题的解决方案

    订单业务中的重要问题 超卖问题的解决方案 我在做过的一些项目中都涉及到了订单的业务 如果你的项目中有关于订单的业务模块 那肯定说明你的项目中有卖商品的功能 所以有买卖场景就面临一个很常见的一个问题 那就是超卖问题 下面我就整理一下我在做项目
  • MyBatis与JDBC连接数据库所使用的url之间的差异

    1 在JDBC连接里是这样的 连接无误 2 在Mybatis里配置要这样 3 主要区别 说明 JDBC 方式连接 MySQL 不需要对 进行转义 而在Mybatis里要求一定要对 转义 4 如果是在properties文件里 不用转义的 在
  • IP静态路由实验报告

    一 将192 168 1 0 24划分为4个网段 192 168 1 0 26 192 168 1 64 26 192 168 1 128 26 192 168 1 192 26 1 取192 168 1 0 26继续划分 为主干道添加IP
  • Spring 加载、解析applicationContext.xml 流程

    概要 Spring 框架使用了BeanFactory 进行加载 xml 和生成 bean 实例 下面我们分析下Spring加载xml文件的过程 spring 版本是最新的 4 3 9 release 版本 示例 XmlBeanFactory
  • java 转换tif图片为jpg,解决转换后颜色异常问题

    java 转换tif图片为jpg 解决转换后颜色异常问题 说明 正常情况下 tif转换jpg图片会出现颜色失真 丢失部分颜色 原因是两种图片的色彩模式不同 jpg默认使用的是RGB色彩模式 TIF默认使用的是CMYK色彩模式 RGB的色域比
  • 有关“ModuleNotFoundError: No module named ‘flask._compat’”错误的解决过程

    在进行flask安装后 运行程序的过程中出现了 ModuleNotFoundError No module named flask compat 的错误 在查询了多个网站后给出了不同的答案 其报错原因是flask版本过高导致无法识别该语法
  • 仿京东 项目笔记2(注册登录)

    这里写目录标题 1 注册页面 1 1 注册 登录页面 接口请求 1 2 Vue开发中Element UI的样式穿透 1 2 1 v deep的使用 1 2 2 elementUI Dialog内容区域显示滚动条 1 3 注册页面 步骤条和表
  • 服务器i5 和e系列,e5和i5有什么区别

    两个系列的处理器主要在设计规格和面向范围方面存在区别 设计规格上 前者核心数更多 多线程能力更强 但睿频能力相对较弱 后者核心数较少 多线程能力不如前者 但睿频能力更强 面向范围上 前者主要面向服务器 嵌入式等企业设备 后者主要面向消费级硬
  • (LeetCode)全排列

    目录 题目要求 题目理解以及思路分析 代码分部讲解 第一部分 第二部分 题目要求 给定一个不含重复数字的数组 nums 返回其 所有可能的全排列 你可以 按任意顺序 返回答案 示例 1 输入 nums 1 2 3 输出 1 2 3 1 3
  • 规则引擎Drools使用 第十一篇 Drools 的高级语法之LHS增强

    前面我们已经知道了在规则体中的LHS部分是介于when和then之间的部分 主要用于模式匹配 只有匹配结果为true时 才会触发RHS部分的执行 下面我们会针对LHS部分学习几个新的用法 目录 复合值限制in not in 条件元素eval
  • 升压电路(BOOST)与降压电路(BUCK)

    一 电路中产生电流的条件是 1 电路里必须有电源供电 2 电路必须形成闭合回路 降压元器件 升降压电路构成的核心元器件 1 电感 储存能量 电感是无法突变的 工作状态是线性的 2 二极管 3 mos管 首先先分清楚mos是N mos还是P
  • Qt全局宏和变量

    1 Qt 全局宏定义 Qt版本号 QT VERSION major lt lt 16 minor lt lt 8 patch 检测版本号 QT VERSION CHECK major minor patch major lt lt 16 m
  • virtio代码分析(一)-qemu部分

    virtio内容众多 代码分布于qemu linux dpdk等中 而且分为frontend和backend 可以运行于userspace也可以运行于kernelspace 极其难以理解 不看代码只看原理性文档往往流于表面 只有真正看懂了代