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部分 的相关文章

  • Web 客户端和 Expect100Continue

    使用 WebClient C NET 时设置 Expect100Continue 的最佳方法是什么 我有下面的代码 我仍然在标题中看到 100 continue 愚蠢的 apache 仍然抱怨 505 错误 string url http
  • 在结构中使用 typedef 枚举并避免类型混合警告

    我正在使用 C99 我的编译器是 IAR Embedded workbench 但我认为这个问题对于其他一些编译器也有效 我有一个 typedef 枚举 其中包含一些项目 并且我向该新类型的结构添加了一个元素 typedef enum fo
  • Google BQ:运行参数化查询,其中参数变量是 BQ 表目标

    我正在尝试从 Linux 命令行为 BQ 表目标运行 SQL 此 SQL 脚本将用于多个日期 客户端和 BQ 表目标 因此这需要在我的 BQ API 命令行调用中使用参数 标志 parameter 现在 我已经点击此链接来了解参数化查询 h
  • 如何为 Linux 桌面条目文件指定带有相对路径的图标?

    对于我的一个 Linux 应用程序 我有应用程序二进制文件 一个 launcher sh 脚本 针对 LD LIBRARY PATH 和一个 desktop 文件 所有这些都位于同一文件夹中 我想使用图标的相对路径而不是绝对路径 我试过了
  • ASP.NET MVC:这个业务逻辑应该放在哪里?

    我正在开发我的第一个真正的 MVC 应用程序 并尝试遵循一般的 OOP 最佳实践 我正在将控制器中的一些简单业务逻辑重构到我的域模型中 我最近一直在阅读一些内容 很明显我应该将逻辑放在域模型实体类中的某个位置 以避免出现 贫血域模型 反模式
  • 如何使用 ICU 解析汉字数字字符?

    我正在编写一个使用 ICU 来解析由汉字数字字符组成的 Unicode 字符串的函数 并希望返回该字符串的整数值 五 gt 5 三十一 gt 31 五千九百七十二 gt 5972 我将区域设置设置为 Locale getJapan 并使用
  • 用于登录 .NET 的堆栈跟踪

    我编写了一个 logger exceptionfactory 模块 它使用 System Diagnostics StackTrace 从调用方法及其声明类型中获取属性 但我注意到 如果我在 Visual Studio 之外以发布模式运行代
  • python获取上传/下载速度

    我想在我的计算机上监控上传和下载速度 一个名为 conky 的程序已经在 conky conf 中执行了以下操作 Connection quality alignr wireless link qual perc wlan0 downspe
  • 通过 Visual Studio 2017 使用远程调试时 Linux 控制台输出在哪里?

    我的Visual Studio 2017 VS2017 成功连接Linux系统 代码如下 include
  • 转发声明和包含

    在使用库时 无论是我自己的还是外部的 都有很多带有前向声明的类 根据情况 相同的类也包含在内 当我使用某个类时 我需要知道该类使用的某些对象是前向声明的还是 include d 原因是我想知道是否应该包含两个标题还是只包含一个标题 现在我知
  • 如何在整个 ASP .NET MVC 应用程序中需要授权

    我创建的应用程序中 除了启用登录的操作之外的每个操作都应该超出未登录用户的限制 我应该添加 Authorize 每个班级标题前的注释 像这儿 namespace WebApplication2 Controllers Authorize p
  • 控件的命名约定[重复]

    这个问题在这里已经有答案了 Microsoft 在其网站上提供了命名指南 here http msdn microsoft com en us library xzf533w0 VS 71 aspx 我还有 框架设计指南 一书 我找不到有关
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • 如何使用 C# / .Net 将文件列表从 AWS S3 下载到我的设备?

    我希望下载存储在 S3 中的多个图像 但目前如果我只能下载一个就足够了 我有对象路径的信息 当我运行以下代码时 出现此错误 遇到错误 消息 读取对象时 访问被拒绝 我首先做一个亚马逊S3客户端基于我的密钥和访问配置的对象连接到服务器 然后创
  • 为什么编译时浮点计算可能不会得到与运行时计算相同的结果?

    In the speaker mentioned Compile time floating point calculations might not have the same results as runtime calculation
  • 混合 ExecutionContext.SuppressFlow 和任务时 AsyncLocal.Value 出现意外值

    在应用程序中 由于 AsyncLocal 的错误 意外值 我遇到了奇怪的行为 尽管我抑制了执行上下文的流程 但 AsyncLocal Value 属性有时不会在新生成的任务的执行范围内重置 下面我创建了一个最小的可重现示例来演示该问题 pr
  • 是否可以在 .NET Core 中将 gRPC 与 HTTP/1.1 结合使用?

    我有两个网络服务 gRPC 客户端和 gRPC 服务器 服务器是用 NET Core编写的 然而 客户端是托管在 IIS 8 5 上的 NET Framework 4 7 2 Web 应用程序 所以它只支持HTTP 1 1 https le
  • C# - OutOfMemoryException 在 JSON 文件上保存列表

    我正在尝试保存压力图的流数据 基本上我有一个压力矩阵定义为 double pressureMatrix new double e Data GetLength 0 e Data GetLength 1 基本上 我得到了其中之一pressur
  • C++ 中类级 new 删除运算符的线程安全

    我在我的一门课程中重新实现了新 删除运算符 现在我正在使我的代码成为多线程 并想了解这些运算符是否也需要线程安全 我在某处读到 Visual Studio 中默认的 new delete 运算符是线程安全的 但这对于我的类的自定义 new
  • 使用.NET技术录制屏幕视频[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有没有一种方法可以使用 NET 技术来录制屏幕 无论是桌面还是窗口 我的目标是免费的 我喜欢小型 低

随机推荐

  • 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 极其难以理解 不看代码只看原理性文档往往流于表面 只有真正看懂了代