DPDK之eventdev_pipeline源码解析

news2024/11/16 6:41:06

DPDK之eventdev_pipeline源码解析

  • 引言
  • 1 实现原理
    • 1.1 数据接收
    • 1.2 数据发送
    • 1.3 事件调度
    • 1.4 struct rte_event
  • 2 核心API
  • 3 源码解析
    • 3.1 generic实现
    • 3.2 tx enq实现

引言

DPDK Eventdev库是DPDK基于事件驱动的编程模型。其中eventdev_pipeline实现了对该模型的应用例子。

1 实现原理

在这里插入图片描述
整个eventdev有两个关键的概念,即event queue与event port。event queue是存放事件的队列,当网卡或CPU产生一个事件最终会放到事件队列中待消费者取出来执行;此外,DPDK Eventdev架构不能直接对event queue进行enqueue或dequeue操作,只能通过event port放入事件和获取事件,然后eventdev内部实现从event port关联(或者说link)的event queue进行dequeue操作(即link确定了port可以取哪些queue的事件)。一般地,Queue与业务处理阶段有关;Port与处理核对应。

假设我们做基于UDP的一个网络回复程序:那么我们可以将业务处理阶段划分为如下几步:

  1. 读取以太网数据;
  2. 解析数据包;
  3. 根据请求内容,确定返回内容;
  4. 封装返回数据包;
  5. 发送以太网数据。

注1 : 当网络设备具备RTE_EVENT_ETH_RX_ADAPTER_CAP_INTERNAL_PORT能力,由网络硬件实现接受数据,CPU只需要通过rte_event_eth_rx_adapter_queue_add设置好接收到数据包需放入的工作队列ID;
注2 : 当网络设备具备RTE_EVENT_ETH_TX_ADAPTER_CAP_INTERNAL_PORT能力,由网络硬件实现发送数据的功能,CPU只需要设置struct rte_mbuf的dst_addr和hash.txadapter.txq两个字段即可

1.1 数据接收

当硬件不具备RTE_EVENT_ETH_RX_ADAPTER_CAP_INTERNAL_PORT能力的时候,由CPU调度:

  • 首先,通过rte_event_eth_rx_adapter_queue_add关联相应网卡号对应的接收队列收到数据后放入的工作队列ID;
  • 然后,通过rte_event_eth_rx_adapter_service_id_get获取rx_adapter_id的rxadptr_service_id;
  • 继续,通过rte_event_eth_rx_adapter_start启动rx_adapter_id;
  • 最后,通过rte_service_run_iter_on_app_lcore不断在数据接收核上调度rxadptr_service_id接收数据。

注:本质上,rx adapter内部会创建一个event port,接收到数据后会通过该port发送到第一步指定的业务队列

1.2 数据发送

当硬件不具备RTE_EVENT_ETH_TX_ADAPTER_CAP_INTERNAL_PORT能力的时候,由CPU调度:

  • 首先,通过rte_event_eth_tx_adapter_queue_add关联相应网卡号对应的发送队列;
  • 然后,通过rte_event_eth_tx_adapter_event_port_get获取tx_adapter_id的event port号tx_port_id;
  • 继续,通过rte_event_port_link将tx_port_id与业务创建的代表发送数据阶段的event queue关联起来;
  • 继续,通过rte_event_eth_tx_adapter_service_id_get获取tx_adapter_id的txadptr_service_id;
  • 继续,通过rte_event_eth_tx_adapter_start启动tx_adapter_id;
  • 最后,通过rte_service_run_iter_on_app_lcore不断在数据发送核上调度txadptr_service_id发送event queue中的数据。

注:本质上,tx adapter内部也会创建一个event port,通过该port去获取event queue中的数据

1.3 事件调度

DPDK Eventdev库从编程模型(或者说概念架构上)有event queue,但是底层实现中queue只是一个事件分发配置或者说策略(例如driver/event/sw中的实现)。它的事件是存储在event port对应的数据结构中,那么就需要由CPU或者硬件去实现将一个event port中的事件根据策略搬移到对应的event port中。

当硬件不具备RTE_EVENT_DEV_CAP_DISTRIBUTED_SCHED能力的时候,由CPU调度:

  • 首先,通过rte_event_dev_service_id_get获取event_dev_id的evdev_service_id;
  • 然后,通过rte_service_run_iter_on_app_lcore不断在调度核上调度evdev_service_id实现事件分发。

Eventdev库定义了三种事件调度的策略,即有序调度、原子调度和并行调度:

  • RTE_SCHED_TYPE_ORDERED
    有序调度允许同一个queue中、flow_id相同的事件,可以被多个port通过dequeue获取并处理;但在enqueue下个相同queue时,会维持之前的事件顺序;对该事件显示调用enqueue执行RTE_EVENT_OP_RELEASE可提前释放该事件在flow中的保序工作。
  • RTE_SCHED_TYPE_ATOMIC
    原子调度允许同一个queue中、flow_id相同的事件,只能被单个port通过dequeue获取;直到对该port再次调用dequeue,或对该事件显示调用enqueue执行RTE_EVENT_OP_RELEASE释放流上下文。
  • RTE_SCHED_TYPE_PARALLEL
    并行调度按照优先级、负载均衡策略去调度,由应用程序去保序。

注:RTE_SCHED_TYPE_ORDERED与RTE_SCHED_TYPE_ATOMIC的区别:前者是可以被多个port在多核上并行执行的,一般应用场景是先用ORDERED并行处理、同时保证有序,最后用ATOMIC串行处理需要有序依次处理的部分。

1.4 struct rte_event

rte_event结构体记录着eventdev框架中流通的事件信息。

WORD0 核心成员如下:

  • flow_id :与事件分派保序有关;
  • queue_id :指定enqueue到哪个队列;
  • sched_type :调度类型/策略;
  • op :事件enqueue操作类型,可以是RTE_EVENT_OP_NEW、RTE_EVENT_OP_FORWARD和RTE_EVENT_OP_RELEASE;

注:RTE_EVENT_OP_RELEASE除了会将当前事件从保序上下文中释放,还会释放mbuf/vec字段。

WORD1 核心成员如下:

  • mbuf :事件中附带的单个收发数据包;
  • vec :事件中附带的单个或多个收发数据包;

注:当调用rte_event_eth_rx_adapter_queue_add时,设置struct rte_event_eth_rx_adapter_queue_conf.rx_queue_flags参数带有RTE_EVENT_ETH_RX_ADAPTER_QUEUE_EVENT_VECTOR标志,那么WORD1就是vec;否则就是mbuf。

2 核心API

  • rte_event_dev_count / rte_event_dev_info_get / rte_event_dev_configure
    rte_event_dev_count用于获取事件设备数量;rte_event_dev_info_get用于获取事件设备信息;rte_event_dev_configure用于配置配置事件设备。
  • rte_event_queue_setup / rte_event_port_setup / rte_event_port_link
    rte_event_queue_setup 用于配置事件队列;rte_event_port_setup用于配置事件端口;rte_event_port_link用于将端口关联到队列;
  • rte_event_dev_service_id_get / rte_event_eth_rx_adapter_service_id_get / rte_event_eth_tx_adapter_service_id_get
    获取事件设备 / 接收适配器 / 发送适配器的服务ID
  • rte_event_dev_start / rte_event_dev_stop / rte_event_dev_close
    启动/停止/关闭事件设备;
  • rte_event_eth_rx_adapter_create / rte_event_eth_tx_adapter_create
    创建接收/发送适配器;
  • rte_event_eth_rx_adapter_queue_add / rte_event_eth_tx_adapter_queue_add
    将网卡设备端口的接收/发送队列配置到接收/发送适配器;
  • rte_event_eth_rx_adapter_event_port_get / rte_event_eth_tx_adapter_event_port_get
    获取软件实现的发送/接收数据的事件端口号;前者一般在应用层不常用;
  • rte_event_eth_rx_adapter_start / rte_event_eth_rx_adapter_stop
    用于启动/停止接收数据适配器;
  • rte_event_eth_tx_adapter_start / rte_event_eth_tx_adapter_stop
    用于启动/停止发送数据适配器;
  • rte_service_component_register / rte_service_component_runstate_set
    rte_service_component_register用于注册事件服务;rte_service_component_runstate_set用于设置服务组件状态为运行或停止状态;一般事件设备和适配器内部实现隐式调用了这两个接口。
  • rte_service_runstate_set / rte_service_set_runstate_mapped_check
    rte_service_runstate_set将服务应用状态设置为启动或停止;rte_service_set_runstate_mapped_check启动服务状态检测功能;两者会在启动相关句柄之前调用。
  • rte_service_run_iter_on_app_lcore
    当硬件不支持的情况下,用于在特定核上运行服务,例如收发数据服务、调度服务;
  • rte_event_dequeue_burst / rte_event_enqueue_burst / rte_event_eth_tx_adapter_enqueue
    rte_event_dequeue_burst从特定事件端口获取事件;rte_event_enqueue_burst将事件通过特定端口发送出去;rte_event_eth_tx_adapter_enqueue将事件通过指定的端口发送到硬件实现的发送端口绑定的队列上去。

3 源码解析

eventdev_pipeline将事件相关操作封装在fdata->cap变量中,这个结构体主要函数指针字段如下:

  • check_opt :用于运行前对事件设备和适配器的相关能力检测;
  • evdev_setup : 用于创建事件设备、事件端口、事件队列以及将队列与端口绑定;
  • adptr_setup :用于网络设备端口的初始化、然后根据网络设备创建收发数据的事件适配器;
  • scheduler :当硬件没有相关能力的时候,由软件去调度相关的服务(例如事件调度、收发数据);
  • worker :用于获取事件并处理,完毕后投送到下各队列。

本实例程序提供两套fdata->cap的实现机制,一套我们称为generic实现、一套称为tx enq实现。

3.1 generic实现

只要有一个网卡设备不具备RTE_EVENT_ETH_TX_ADAPTER_CAP_INTERNAL_PORT能力,那么就需要采用generic实现,该实现发送数据由上述的软件方式实现

3.2 tx enq实现

当所有的网卡具备RTE_EVENT_ETH_TX_ADAPTER_CAP_INTERNAL_PORT能力,那么采用tx enq实现。该实现发送数据采用硬件实现。
tx enq的worker实现分为原子和非原子调度。原子调度是每个网络设备对应一个事件队列,各个网络设备不共享事件队列,每次递增struct rte_event.sub_event_type;非原子调度是每个网络设备对应cdata.num_stages + 1个事件队列,各个网络设备不共享事件队列,每次调度递增struct rte_event.queue_id。
当设备不具备接收数据能力的时候,它与generic实现一样采用软件实现,同时它与generic实现不同的是:tx enq实现是每个网络设备(或者说端口)创建一个对应的接收适配器并与之关联。
另外,tx enq实现中没有发现调用scheduler回调的地方。

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

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

相关文章

linux内核模块符号导出

一、内核模块符号导出简介 驱动程序编译生成的 ko 文件是相互独立的,即模块之间变量或者函数在正常情况下无法进行互相访问。而一些复杂的驱动模块需要分层进行设计,这时候就需要用到内核模块符号导出。   内核符号导出指的是在内核模块中导出相应的函…

[MAUI]深入了解.NET MAUI Blazor与Vue的混合开发

文章目录 Vue在混合开发中的特点创建MAUI项目创建Vue应用使用element-ui组件库JavaScript和原生代码的交互传递根组件参数从设备调用Javascript代码从Vue页面调用原生代码 读取设备信息项目地址 .NET MAUI结合Vue的混合开发可以使用更加熟悉的Vue的语法代替Blazor语法&#xff…

Cypress安装使用

node.js 安装使用Cypress总是会看见node.js,那就先看看node.js是什么。JavaScript以前运行需要在浏览器中(浏览器内置解释器),通过node.js框架内置v8引擎(也就是可以执行js脚本所需的工具),这样…

金翅擘海|人大女王金融硕士庞雪雨:行学之道,在自律、在勤勉、在止于至善

庞雪雨 中国人民大学-加拿大女王大学金融硕士2022-2023级行业高管班 光大保德信资产管理有限公司董事总经理 当我进入到人大校园的那一刻,映入眼帘的是明德楼,由此我想到了《大学》,大学开篇中讲到,大学之道,在明明德&…

如何理解Linux字符设备驱动?

我们学习编程的时候,一般都会从hello程序开始。同样的,学习Linux驱动,我们也是从最简单的hello驱动学起。 一、驱动层和应用层 看一下STM32裸机开发与嵌入式Linux开发的一些区别: 嵌入式Linux的开发方式与STM32裸机开发的方式有…

【数值分析】1 - 误差及有关概念

文章目录 一、误差的背景介绍1.1 误差的来源与分类1.2 误差的传播与积累1.3 例题1.3.1 公式一1.3.2 公式二1.3.3 总结 二、误差与有效数字2.1 绝对误差与绝对误差限2.2 相对误差和相对误差限 三、有效数字3.1 有效数字的定义和标准浮点式3.1.1 例题 3.2 有效数字与相对误差的关…

【一文清晰】单元测试到底是什么?应该怎么做?

我是java程序员出身,后来因为工作原因转到到了测试开发岗位。测试开发工作很多年后,现在是一名自由职业者 1、什么是单元测试 2、该怎么做单元测试 一、什么是单元测试? 单元测试(unit testing),是指对软件…

4款文件恢复工具推荐,恢复数据就靠它们!

“想问问大家在使用电脑时有什么好的文件恢复工具推荐吗?最近好像有点粗心,经常误删文件,非常需要一个有用的恢复工具,希望大家给些意见!” 在日常工作或学习中,由于各种原因造成的文件丢失是很正常的情况。…

什么是模拟芯片,模拟芯片都有哪些测试指标?

模拟芯片又称处理模拟信号的集成电路 模拟集成电路主要是指由电容、电阻、晶体管等组成的模拟电路集成在一起用来处理模拟信号的集成电路。有许多的模拟集成电路,如运算放大器、模拟乘法器、锁相环、电源管理芯片等。 模拟集成电路的主要构成电路有:放…

打造属于自己的vue图标库

hfex-icon图标库 Install npm i -D hfex-icon主要提供2种使用方式 方式一 通过svg图标资源,借助unplugin-icons库将svg图标文件生成vue组件,然后通过vue组件的引入方式在vue中使用 unplugin-icons 兼容vue2和vue3 在vue.config.js的plugins中配置…

“轻松实现文件夹批量重命名:使用顺序编号批量改名“

你是否曾经需要大量修改文件夹名称?或者需要为文件夹添加有序编号以便于管理?下面就教你一个简单的方法,轻松实现文件夹批量重命名,使用顺序编号批量改名。 首先我们要进入文件批量改名高手主页面,并在板块栏里选择“文…

java springboot VUE粮食经销系统开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot VUE 粮食经销系统是一套完善的完整信息管理类型系统,结合springboot框架和VUE完成本系统,对理解JSP java编程开发语言有帮助系统采用springboot框架(MVC模式开发) ,系统具有完整的源代码和数…

kafka、zookeeper、flink测试环境、docker

1、kafka环境单点 根据官网版本说明(3.6.0)发布,zookeeper依旧在使用状态,预期在4.0.0大版本的时候彻底抛弃zookeeper使用KRaft(Apache Kafka)官方并给出了zk迁移KR的文档 2、使用docker启动单点kafka 1、首先将kafka启动命令,存储为.servi…

LLC 三相移相PWM产生原理分析

LLC 三相移相PWM产生原理分析 void MX_PWM_Stop(void) {//----------------------使用停止函数后会导致移相角度为60度---------------------------------------------------------------- #if 1 //------Tim1 PWM定时器初始化------------------ HAL_TIM_OC_Stop(&htim1…

最新Google play开发者账号注册要求、单位账号邓白氏编码问题及身份验证解决思路!

随着Google play商店的蓬勃发展,越来越多的开发者在上面上传应用,但部分开发者为了获得更多的收益,试图通过多种方式绕过谷歌限制,无视谷歌规则。 为了维持Google play的生态环境,谷歌采取了多种方式和方法去应对这些…

决策树oo

决策树学习的算法通常是一个递归地选择最优特征(选择方法的不同,对应着不同的算法),并根据该特征对训练数据进行分割,使得各个子数据集有一个最好的分类的过程。这一过程对应着对特征空间的划分,也对应着决策树的构建 步骤&#…

git切换远程仓库源步骤

git切换远程仓库源步骤: 第一步:git remote -v 查看当前远程仓库源: 第二步:git remote rm origin删除远程仓库源; 第三步:git remote add origin http://newURL.git 添加新的远程仓库源地址&#xff1b…

Operator 开发实践 四 (WebHook)

1. WebHook介绍 我们知道访问Kubernetes API有好几种方式,比如使用kubectl命令、使用client-go之类的开发库、直接通过REST请求等。不管是一个使用kubectl的真人用户,还是一个Service Account,都可以通过API访问认证,这个过程官网…

AI机器视觉多场景应用迸发检测活力,引领食品及包装行业新发展

随着食品安全意识的广泛传播,人们对食品质量和安全的要求越来越高,众多食品包装厂商加速产线数智化转型,迫切需要高效、准确且智能化的检测技术。 在现代食品及包装行业的自动化生产中,涉及到各种各样的识别、检测、测量等环节&a…

LabVIEW中管理大型数据

LabVIEW中管理大数据 LabVIEW的最大优势之一是自动内存管理。这种内存管理允许用户轻松创建字符串、数组和集群,而无需C/C用户经常担心。但是,这种内存管理设计为绝对安全,因此数据被非常频繁地复制。这通常不会造成任何问题,但是…