1.Mellanox ConnectX-6-dx智能网卡 openvswitch 流表卸载源码分析
2.什么是源码DPDK?DPDK的原理及学习学习路线总结
3.DPDK 无锁环形队列(Ring)详解--段子解法
4.一文了解dpdk uio的驱动实现
5.linux源码解读(三十二):dpdk原理概述(一)
6.一文分析DPDK跟踪库tracepoint源码
Mellanox ConnectX-6-dx智能网卡 openvswitch 流表卸载源码分析
Mellanox ConnectX-6-dx智能网卡凭借其流表卸载功能,能够无缝融入当前服务器ovs的解析部署环境。然而,源码DPU bluefield 2的解析引入促使ovs需要从服务器迁移至DPU,这无疑对上层neutron架构带来了显著的源码改造挑战。
在OFED的解析room源码分析Linux InfiniBand Drivers版本中,openvswitch采用2..2版本,源码配合dpdk的解析.版本,智能网卡的源码流表卸载主要分为两种途径:netdev_offload_dpdk,通过用户态驱动卸载,解析和netdev_offload_tc,源码通过内核态驱动卸载,解析后者依赖于tc-flow内核模块。源码
ovs-dpdk的解析netdev_offload_dpdk采用异步方式,由offload_main线程配合工作队列执行,源码以避免阻塞包转发线程。在rdma-core中,Mellanox网卡的用户态驱动被集成,因为rdma技术要求用户态操作,以绕过内核TCP/IP协议栈,除非使用iWARP。
相比之下,早期的网卡依赖rdma-core封装的用户态驱动,通过ioctl或netlink接口调用内核驱动进行硬件操作。而netdev_offload_tc则通过tc-flow模块实现内核卸载。
ovs revalidator线程在流程中扮演重要角色,它负责更新卸载流表的统计信息,并在必要时异步删除超时流。对于硬件寄存器中的流表统计,revalidator线程会定时查询,确保信息的实时性。
什么是DPDK?DPDK的原理及学习学习路线总结
DPDK,全称为Data Plane Development Kit,是一个旨在提升数据包处理性能的软件库。对于不同角色的内网穿透源码解读用户,它有着多样的应用场景。在多核处理器上,DPDK通过User Space下的应用程序,利用自有的数据面库,避开Linux内核的协议栈,直接处理数据包,从而显著提高数据传输效率。
DPDK的核心原理在于,它针对公有云和NFV等场景,针对通用服务器(COTS)的CPU核心,优化了网络数据包的收发流程。传统网络设备通常采用NP处理器,通过硬件电路高效处理,而DPDK则为CPU密集型系统提供了一种新的解决方案,避免了内核态与用户态切换以及内存拷贝导致的性能瓶颈。
DPDK源码主要包含库、驱动程序、应用程序、配置文件和工具等,涵盖了从基础库到高级功能的方方面面。学习DPDK,可以从理解其PCI原理、测试工具如testpmd和l3fwd,以及实现DNS、高性能网关和半虚拟化加速等实战项目开始。
总的来说,DPDK的学习路线包括理解其基础架构,深入PCI和驱动原理,实践典型应用,以及结合现代技术的优化。获取更详细的资料和教程,可以参考相关链接中的资源。
DPDK 无锁环形队列(Ring)详解--段子解法
在大数据处理需求日益增长的背景下,公司通常通过分布式集群来扩展服务器资源。稳定建站系统源码然而,在多核服务器中,传统的锁机制并不理想。DPDK提供了一种无锁数据结构,即环形队列(Ring),尽管理解起来有些困难,尤其通过文字描述和代码实现。
为便于理解,我尝试以幽默的段子形式来解析DPDK中的环形队列。首先,环形队列在DPDK中常用于队列管理,它具有固定大小,不同于链表的动态性。与链表队列相比,环形队列的优点包括高效性和无锁操作,但同时也存在空间固定和并发访问时可能出现的环形溢出问题。
环形队列的应用场景包括数据传输和多线程协作。在源码中,环形队列由prod_head, prod_tail, cons_head, cons_tail四个指针标识,利用unsigned int的溢出特性,head和tail的范围为0~2^。通过rte_ring_create创建的队列以"name"标识,保证其唯一性。
接下来,我们以单生产者/单消费者模式为例,描述了入队和出队操作。生产者负责更新prod_head和prod_tail,消费者则操作cons_head和cons_tail。生产者入队时,类似于预定房间并添加对象,出队则类似退房并移动指针。在多生产者/多消费者模式中,无锁操作通过CAS指令实现,多个CPU间的定位诱导源码同步依赖于内存屏障。
虽然故事化讲解有助于理解,但源码仍然是理解环形队列的最佳途径。关于多消费者出队,官方文档未详细说明,但源码提供了解答。通过这种直观的解释,DPDK的无锁环形队列概念应该更容易把握了。
一文了解dpdk uio的驱动实现
在系统加载igb_uio驱动后,每当有网卡和igb_uio驱动进行绑定时,就会在/dev目录下创建一个uio设备, 如/dev/uio1。uio设备作为接口层,用于将pci网卡的内存空间和io空间呈现在应用层。通过这种方式,应用层访问uio设备,就等同于访问了网卡。具体操作如下:当有网卡与uio驱动绑定时,被内核加载的igb_uio驱动会将pci网卡的内存空间、网卡的io空间保存在uio目录下(如/sys/class/uio/uio1/maps文件中),同时也会保存到pci设备目录下的uio文件中。这样应用层就可以访问这两个文件中的任意一个文件内保存的地址空间,通过mmap将文件中保存的网卡物理内存映射成虚拟地址,应用层访问这个虚拟地址空间,就相当于访问了pci设备。
整体框架由用户态驱动pmd、运行在内核态的igb_uio驱动,以及linux的uio框架组成。用户态驱动pmd通过轮询的方式直接从网卡收发报文,旁路了内核,避免了内核与应用层之间的数据拷贝,提高性能。内核态驱动igb_uio用于将pci网卡的内存空间、io空间暴露给应用层,供应用层访问,同时处理硬件中断。分时金叉源码linux uio框架提供给igb_uio驱动调用的接口,例如打开uio(uio_open)、关闭uio(uio_release)、从uio读取数据(uio_read)、往uio写入数据(uio_write)。linux uio框架的代码在内核源码drivers/uio/uio.c文件中实现,同时也会调用内核提供的其他API接口。
应用层pmd通过read系统调用来访问/dev/uiox设备,进而调用igb_uio驱动中的接口,igb_uio驱动最终会调用linux uio框架提供的接口。
pmd用户态驱动通过轮询的方式直接从网卡收发报文,绕过了协议栈,但为什么还需要实现uio?在某些情况下,应用层需要了解网卡的状态信息,这就需要网卡硬件中断的支持。dpdk的实现方式是在内核态的igb_uio驱动上实现一部分硬件中断,例如统计硬件中断的次数,然后唤醒应用层注册到epoll中的/dev/uiox中断,进而完成大部分的中断处理过程,比如获取网卡状态等。
对于网卡报文到来时产生的硬件中断是否会到/dev/uiox中断?答案是不会的,因为/dev/uiox中断只是控制中断,网卡报文收发的数据中断不会触发到这里来。dpdk是如何区分数据中断与控制中断的?在pmd驱动中,调用igb_intr_enable接口开启uio中断功能时,可以指定中断掩码,如E_ICR_LSC网卡状态改变中断掩码,E_ICR_RXQ0接收网卡报文中断掩码,E_ICR_TXQ0发送网卡报文中断掩码等。没有指定的掩码不会触发相应的中断。dpdk的用户态pmd驱动只指定了E_ICR_LSC网卡状态改变中断掩码,因此只有网卡状态改变时才会触发epoll事件。所以,当有来自网卡的报文时,产生的硬件中断不会唤醒epoll事件。
igb_uio驱动注册中断处理回调时,会将中断处理函数设置为igbuio_pci_irqhandler,拦截了网卡的中断回调。得益于拦截了网卡的中断回调,linux uio框架会在中断发生时唤醒epoll事件,进而应用层能够读取网卡中断事件或对网卡进行控制操作。拦截硬件中断处理回调仅对网卡控制操作有效,对pmd用户态驱动轮询网卡报文没有影响。
igb_uio驱动初始化时,会进行一系列操作,如激活pci设备、为pci设备预留内存与io空间、为pci网卡设置dma模式、将pci网卡的物理空间和io空间暴露给uio设备,最后注册uio设备并创建uio文件。
igb_uio驱动初始化包括激活pci设备、预留内存与io空间、设置dma模式、暴露pci网卡空间、注册中断并创建uio设备,最终完成与pmd的关系解析。
linux源码解读(三十二):dpdk原理概述(一)
Linux源码解析(三十二):深入理解DPDK原理(一)
几十年来,随着技术的发展,传统操作系统和网络架构在处理某些业务需求时已显得力不从心。为降低修改底层操作系统的高昂成本,人们开始在应用层寻求解决方案,如协程和QUIC等。然而,一个主要问题在于基于内核的网络数据IO,其繁琐的处理流程引发了效率低下和性能损耗。
传统网络开发中,数据收发依赖于内核的receive和send函数,经过一系列步骤:网卡接收数据、硬件中断通知、数据复制到内存、内核线程处理、协议栈层层剥开,最终传递给应用层。这种长链式处理方式带来了一系列问题,如上下文切换和协议栈开销。
为打破这种限制,Linux引入了UIO(用户空间接口设备)机制,允许用户空间直接控制网卡,跳过内核协议栈,从而大大简化了数据处理流程。UIO设备提供文件接口,通过mmap映射内存,允许用户直接操作设备数据,实现绕过内核控制网络I/O的设想。
DPDK(Data Plane Development Kit)正是利用了UIO的优点,如Huge Page大页技术减少TLB miss,内存池优化内存管理,Ring无锁环设计提高并发性能,以及PMD poll-mode驱动避免中断带来的开销。它采用轮询而非中断处理模式,实现零拷贝、低系统调用、减少上下文切换等优势。
DPDK还注重内存分配和CPU亲和性,通过NUMA内存优化减少跨节点访问,提高性能,并利用CPU亲和性避免缓存失效,提升执行效率。学习DPDK,可以深入理解高性能网络编程和虚拟化领域的技术,更多资源可通过相关学习群获取。
深入了解DPDK原理,可以从一系列资源开始,如腾讯云博客、CSDN博客、B站视频和LWN文章,以及Chowdera的DPDK示例和腾讯云的DPDK内存池讲解。
源:cnblogs.com/thesevenths...
一文分析DPDK跟踪库tracepoint源码
在DPDK跟踪库tracepoint的源码分析中,关键流程包括rte_eal_trace_thread_remote_launch以及初始化过程。初始化流程由`eal_trace_init`执行,挂载`tracepoint`,其核心在于`RTE_TRACE_POINT_DEFINE`宏与`RTE_TRACE_POINT_REGISTER`定义的转换。rte_eal_trace_thread_remote_launch函数定义于`lib\librte_eal\include\rte_eal_trace.h`文件,是远程线程操作的函数。
接着观察`__rte_trace_point_emit_header_generic`函数,通过分析其流程可以看出其主要分为两部分:获取内存区域与填充函数指针、arg指针等数据。在调用这个宏时,内存区域将用于存储时间戳及标志位等信息,然后填入由宏提供的数据类型,包括函数指针、arg指针、bits的slave_id和int型rc变量。这些操作在`rte_eal_remote_launch`函数中执行时完成,DPDK的tracepoint功能最终实现。
为了深入理解这些细节,建议参考相关资源,如《全网讲的最好的DPDK,由简到精,系统学习,资深老师带你聊透DPDK 为什么说实现CM的挑战不在硬件而在软件》等材料,并且实际操作学习DPDK的tracepoint实现方法,通过实践深化对源码的理解。
参考资料链接:t.csdn.cn/NhKEJ
关于vpp中dpdk接口注册流程解析
vpp 是一个高效的包处理转发框架,支持多种接口类型,其中应用最广泛的便是 dpdk。dpdk 通过接管网卡驱动实现内核旁路,提供报文收发加速机制。在 vpp 中,dpdk 作为插件实现,通过 make install-ext-deps 构建过程中自动集成 dpdk。
dpdk 初始化在 /src/plugins/dpdk/device/init.c 文件中,dpdk 的 eal 环境通过调用 rte_eal_init 函数实现。dpdk_config 函数负责参数解析,dpdk_config 函数通过宏 VLIB_CONFIG_FUNCTION 注入,vpp 启动时自动调用,将参数传递给 rte_eal_init 进行初始化。
vpp 的接口层分为硬件层和软件层,硬件层通过 device class 描述硬件驱动,软件层通过 interface class 描述链路层。硬件设备用 vnet_hw_interface_t 结构体描述,软件层接口用 vnet_sw_interface_t 描述。接口统一管理在 vnet_interface_main_t 结构体中,该结构体定义了硬件接口和软件接口的数组。
接口初始化在 vnet_interface_init 函数中进行,此函数除了初始化接口参数,还会将 dpdk 设备的 tx_function 赋值给 device class,决定后续的发包执行函数。
dpdk 接口初始化在 dpdk_lib_init 函数中完成,主要步骤包括初始化 dpdk_device_t 结构体,调用 ethernet_register_interface 注册接口,配置网卡参数,并为接口分配收包线程。
dpdk 收包通过 input node dpdk_input_node 实现,dpdk_device_input 函数完成实际的收包操作,通常将报文传递给下一个 node,如 ethernet_input node。
dpdk 发包逻辑相对复杂,dpdk 的发包并未直接在插件中实现专门的 output node,而是通过接口 tx_function 赋值,最终在 vpp 的发送流程中实现。在发送报文时,接口的 output node 和 tx node 会在 vnet_register_interface 注册接口时一同注册,其中 output node 的执行函数是 vnet_interface_output_node,tx node 的函数则由 vnet_device_class_t 定义。
发送流程以 ip4 报文为例,处理完 ip4 报文后,通常下一个节点为 ip4-lookup 进行路由查找。在 interface-output node 中,通过 buffer->sw_if_index[VNET_TX] 的值确定发送接口,并执行对应的 output node。
在 interface output node 的执行函数中,接口的 output node index 通过调用 vnet_per_buffer_interface_output_hw_interface_add_del 函数获得,该函数在 vpp 初始化过程中将接口的 output node 放置在 interface output node 后面,从而在执行函数中获取到接口 output node 的索引。
vpp 的设计遵循分层架构,逻辑清晰,但宏定义的大量使用增加了阅读难度。 版本源码调整了 node 注册方式,通过 VLIB_NODE_FN 宏实现不同优先级的 function 设置,但这一改动也给源码阅读带来不便。接口发送节点通过 vlib_register_node 函数定义,允许不同驱动共享一个函数,方便了接口的动态添加。
vpp 启动过程中的宏定义执行顺序影响代码结构,后续深入阅读源码时会进一步分析。如有需要,可参考相关学习资料、教学视频和交流群资源进行深入学习和交流。