DPDK收发包流程分析(一)

DPDK收发包流程分析 一、 前言 DPDK是intel工程师开发的一款用来快速处理数据包的框架,最初的目的是为了证明传统网络数据包处理性能低不是intel处理器导致的,而是传统数据的处理流程导致,后来随着dpdk的开源及其生态的快速发展,dpdk成为了高性能网络数据处理的优秀框架。本篇文章主要介绍DPDK接收与发送报文的流程,包括CPU与网卡DMA协同工作的整个交互流程、数据包在内存、CPU、网卡之间游走的过程。 阅读详情

一、 前言】

       DPDK是intel工程师开发的一款用来快速处理数据包的框架,最初的目的是为了证明传统网络数据包处理性能低不是intel处理器导致的,而是传统数据的处理流程导致,后来随着dpdk的开源及其生态的快速发展,dpdk成为了高性能网络数据处理的优秀框架。本篇文章主要介绍DPDK接收与发送报文的流程,包括CPU与网卡DMA协同工作的整个交互流程、数据包在内存、CPU、网卡之间游走的过程。

                                                   【二、场景】

       DPDK从2013开始开源,经过前辈们的缝缝补补到现在为止DPDK框架比较成熟、使用比较方便,使得现在开发者在不需要深入了解底层数据包收发原理的情况下也可以做简单的项目开发。但是个人感觉做简单的项目尚且可以应付,如果需要做性能优化等类似的需求时就需要取全面的了解DPDK的收发包机制,因为收发包性能与驱动工作流程、前期初始化配置息息相关。话不多说,下面我们进入正题。

                                            【三、收发包处理流程】

 

  • 数据包接收的大体流程:
  1. 数据包到达网卡
  2. 网卡经过DMA操作将数据包从网卡拷贝到收包队列
  3. DPDK应用从收包队列中取包
  • 数据包发送的大体流程:
  1. DPDK应用将数据包送到发包队列
  2. 网卡经过DMA操作将网卡队列中的数据包拷贝到网卡
  3. 数据包从网卡发出
  • 收发包流程中的关键操作,主要是网卡如何与DPDK应用交互:
  1. 网卡的初始化配置操作有哪些,因为网卡要想正常工作肯定需要进行初始化配置一些属性
  2. 网卡的DMA操作怎么找到DMA 地址,进而将数据包拷贝到系统主存供DPDK读取
  3. 网卡把数据包成功放到队列后如何通知DPDK应用去队列中读取
  4. DPDK从队列中取完数据包后需要做哪些操作通知网卡为下一次收包做准备
  5. DPDK将数据包送到发送队列中需要做哪些预操作
  6. 网卡从发送队列中取包需要做哪些操作

                                        【四、收包软件处理流程】

DPDk在初始化阶段通过igb_alloc_rx_queue_mbufs 负责将描述符,mbuf, dma,接收队列给关联起来,如下图所示。初始化配置这块内容下篇讲

1、模块/硬件介绍

Network interface: 指以太网卡,它工作在OSI的下两层(物理层、数据链路层),工作在物理层的芯片称为PHY,工作在数据链路层的芯片称为MAC控制器,即Media Access Control,即媒体访问控制子层协议.该协议位于OSI七层协议中数据链路层的下半部分,但是目前好多网卡是将MAC和PHY功能做到了一颗芯片中,但是MAC和PHY的机制还是单独存在的,只是对外体现为一颗芯片。MAC控制器的功能主要是数据帧的构建、数据差错检查、传送控制、向网络层提供标准的数据接口等功能;PHY芯片的主要功能是将从PHY来的并行数据转换为穿行流数据,再按照物理层的编码规则把数字信号进行编码,最后再转换为模拟信号把数据发出去。

RX_FIFO: 数据接收缓冲区

TX_FIFO: 数据发送缓冲区

DMA Engine:Direct Memory Access,即直接寄存器访问,是一种告诉的数据传输方式,允许在外部设备和存储器之间直接读写数据,数据的读写不消耗CPU资源,DMA控制器通过一组描述符环形队列与CPU互相操作完成数据包的收发。CPU通过操作DMA寄存器来与DMA控制器进行部分通信与初始化配置,主要寄存器有Base、Size、Tail、Head,head寄存器用于DMA往rx_ring里插入时使用,tail是应用通过写寄存器通知给DMA控制器当前可用的最后一个描述符(head->next 为tail时表示当前rx_ring存满了,再来报文会被记录rx_missed_error)。

Rx_queue: 收包队列结构体:我们主要关注两个环形队列rx_ring、sw_ring

Rx_ring:一个地址连续环形队列,存储的是描述符,描述符中包含将来存放数据包的物理地址、DD标志(下面会介绍DD标志)等,上面图中只画了存放数据包的物理地址,物理地址供网卡DMA模块使用,也称为DMA地址(硬件使用物理地址,当网卡收到数据包后会通过DMA操作将数据包拷贝到物理地址,物理地址是通过虚拟地址转换得到的,下面分析源码时会介绍)

Sw_ring: 存储的是将来存放数据包的虚拟地址,虚拟地址供应用使用(软件应用使用虚拟地址,应用往虚拟地址读写数据包)

DD标志:用于标识一个描述符buf是否可用,无论网卡是工作在轮询方式下还是中断方式,判断数据包接收成功或者是否发送成功都需要检查描述符中的完成状态位(Description Done)DD,该状态位由DMA控制器在完成操作后进行回写

Mbuf:对应于Mbuf内存池中的元素,通过alloc或者free操作内存池获取或者释放mbuf对象,这里需要说的一点是mbuf池创建的时候是连续的,但是rx_ring和sw_ring里指向的数据地址不一定是连续的,下面分析收包流程时会介绍

PCIE总线:采用高速串行通信互联标准,自上而下分为事务传输层、数据链路层、物理层,网卡与CPU之间数据包的传输、CPU对网卡寄存器的MMIO操作都通过PCIE进行传输

DMA寄存器:CPU配置网卡的操作通过操作网卡的寄存器,寄存器主要

2、收包流程

Rx_ring收数据时的状态如下:


DMA控制器收到数据后往head写,当head=tail时表示当前队列为空,head->bext = tail表示当前队列已存满,dpdk启动刚初始化完后如下图所示:


 


可以看出来cpu对tail寄存器的更新并不是在rx_ring描述符中填充完dma地址后立马就执行,而是等dma可用描述符低于一定阈值时才执行写寄存器更新tail


 


具体详细流程如下:

(1)CPU填缓冲地址(mbuf中的data)到收接收侧描述符(在dpdk初始化时就会第一次填充),也就是上图中rx_ring会指向                mbuf池中的 部分mbuf用于接收数据包;另外CPU通过操作网卡的base、size寄存器,将rx_ring环形队列的起始地址和内              存卡大小告诉给DMA控制器,将描述符队列的物理地址写入到寄存器后,dma 通过读这个寄存器就知道了描述符队列的地            址,进而 dma收到报文后,会将报文保存到描述符指向的 mbuf 空间

(2)网卡读取rx_ring队列里接收侧的描述符进而获取系统缓冲区地址

(3)从外部到达网卡的报文数据先存储到网卡本地的RX_FIFO缓冲区

(4)DMA通过PCIE总线将报文数据写到系统的缓冲区地址

(5)网卡回写rx_ring接收侧描述符的更新状态DD标志,置1表示接收完毕

(6)CPU读取描述符sw_ring队列中元素的DD状态,如果为1则表示网卡已经接收完毕,应用可以读取数据包

(7)CPU从sw_ring中读取完数据包后有个“狸猫换太子”的动作,重新从mbuf池中申请一个mbuf替换到sw_ring的该描述符中、             将新分配的mbuf虚拟地址转换为物理地址更新到rx_ring中该条目位置的dma物理地址、更新描述符rx_ring队列里的DD标             志置0,这样网卡就可以持续往rx_ring缓冲区写数据了

(8)CPU判断rx_ring里可用描述符小于配置的阈值时更新tail寄存器,而不是回填一个mbuf到描述符就更新下tail寄存器(因为CPU高频率的操作寄存器是性能的杀手,所以改用此机制)

(9)至此,应用接收数据包完毕

注意:这里有两个非常关键的队列rx_ring、sw_ring,rx_ring描述符里存放的是mbuf里data区的起始物理地址供DMA控制器收到报文后往该地址写入(硬件DMA直接操作物理地址,不需要cpu参与);sw_ring描述符里存放的是mbuf的起始虚拟地址供应用读取数据包

3、代码的实现过程

我们以e1000驱动类型网卡举例,来分析数据包接收相关的软件结构及接口

(1)接收队列的结构如下图,图中标出了两个重要的环形队列(上面已介绍):

                                    

(2)     数据包的软件接收流程如下图

                                                           

(3)分析下eth_igb_recv_pkts接口源码,与第四章的收包内部流程相对应

uint16_t
eth_igb_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
           uint16_t nb_pkts)
{
    struct igb_rx_queue *rxq;
    volatile union e1000_adv_rx_desc *rx_ring;
    volatile union e1000_adv_rx_desc *rxdp;
    struct igb_rx_entry *sw_ring;
    struct igb_rx_entry *rxe;
    struct rte_mbuf *rxm;
    struct rte_mbuf *nmb;
    union e1000_adv_rx_desc rxd;
    uint64_t dma_addr;
    uint32_t staterr;
    uint32_t hlen_type_rss;
    uint16_t pkt_len;
    uint16_t rx_id;
    uint16_t nb_rx;
    uint16_t nb_hold;
    uint64_t pkt_flags;

    nb_rx = 0;
    nb_hold = 0;
    rxq = rx_queue;
    rx_id = rxq->rx_tail;
    rx_ring = rxq->rx_ring;
    sw_ring = rxq->sw_ring;
    while (nb_rx < nb_pkts) {
         /*第一步:从描述符队列中找到被应用最后一次接收的那个文件描述符的位置*/
        rxdp = &rx_ring[rx_id];
        staterr = rxdp->wb.upper.status_error;

         /*第二步:检查DD状态是否为1,为1则说明驱动已经将报文成功放到接收队列,否则直接退出*/
        if (! (staterr & rte_cpu_to_le_32(E1000_RXD_STAT_DD)))
            break;
        rxd = *rxdp;


        PMD_RX_LOG(DEBUG, "port_id=%u queue_id=%u rx_id=%u "
               "staterr=0x%x pkt_len=%u",
               (unsigned) rxq->port_id, (unsigned) rxq->queue_id,
               (unsigned) rx_id, (unsigned) staterr,
               (unsigned) rte_le_to_cpu_16(rxd.wb.upper.length));

         /*第三步:从mbuf池中重新申请一个mbuf,为下面的填充做准备*/

        nmb = rte_mbuf_raw_alloc(rxq->mb_pool);
        if (nmb == NULL) {
            PMD_RX_LOG(DEBUG, "RX mbuf alloc failed port_id=%u "
                   "queue_id=%u", (unsigned) rxq->port_id,
                   (unsigned) rxq->queue_id);
            rte_eth_devices[rxq->port_id].data->rx_mbuf_alloc_failed++;
            break;
        }

        nb_hold++;

        /*第四步:找到了描述符的位置,也就找到了需要取出的mbuf*/
        rxe = &sw_ring[rx_id];
        rx_id++;
        if (rx_id == rxq->nb_rx_desc)
            rx_id = 0;

        /* Prefetch next mbuf while processing current one. */
        rte_igb_prefetch(sw_ring[rx_id].mbuf);

        /*
         * When next RX descriptor is on a cache-line boundary,
         * prefetch the next 4 RX descriptors and the next 8 pointers
         * to mbufs.
         */
        if ((rx_id & 0x3) == 0) {
            rte_igb_prefetch(&rx_ring[rx_id]);
            rte_igb_prefetch(&sw_ring[rx_id]);
        }

        rxm = rxe->mbuf;

        /*第五步:给描述符sw_ring队列重新填写新申请的mbuf*/
        rxe->mbuf = nmb;

        /*第六步:将新申请的mbuf的虚拟地址转换为物理地址,为rx_ring的缓冲区填充做准备*/
        dma_addr =
            rte_cpu_to_le_64(rte_mbuf_data_iova_default(nmb));

        /*第七步:将rx_ring描述符中该条目的DD标志置0,表示允许DMA控制器操作*/
        rxdp->read.hdr_addr = 0;

        /*第八步:重新填充rx_ring描述符中该条目的dma地址*/
        rxdp->read.pkt_addr = dma_addr;

        /*
         * Initialize the returned mbuf.
         * 1) setup generic mbuf fields:
         *    - number of segments,
         *    - next segment,
         *    - packet length,
         *    - RX port identifier.
         * 2) integrate hardware offload data, if any:
         *    - RSS flag & hash,
         *    - IP checksum flag,
         *    - VLAN TCI, if any,
         *    - error flags.
         */

        /*第九步:对获取到的数据包做部分封装,比如:报文类型、长度等*/
        pkt_len = (uint16_t) (rte_le_to_cpu_16(rxd.wb.upper.length) -
                      rxq->crc_len);
        rxm->data_off = RTE_PKTMBUF_HEADROOM;
        rte_packet_prefetch((char *)rxm->buf_addr + rxm->data_off);
        rxm->nb_segs = 1;
        rxm->next = NULL;
        rxm->pkt_len = pkt_len;
        rxm->data_len = pkt_len;
        rxm->port = rxq->port_id;

        rxm->hash.rss = rxd.wb.lower.hi_dword.rss;
        hlen_type_rss = rte_le_to_cpu_32(rxd.wb.lower.lo_dword.data);

        /*
         * The vlan_tci field is only valid when PKT_RX_VLAN is
         * set in the pkt_flags field and must be in CPU byte order.
         */
        if ((staterr & rte_cpu_to_le_32(E1000_RXDEXT_STATERR_LB)) &&
                (rxq->flags & IGB_RXQ_FLAG_LB_BSWAP_VLAN)) {
            rxm->vlan_tci = rte_be_to_cpu_16(rxd.wb.upper.vlan);
        } else {
            rxm->vlan_tci = rte_le_to_cpu_16(rxd.wb.upper.vlan);
        }
        pkt_flags = rx_desc_hlen_type_rss_to_pkt_flags(rxq, hlen_type_rss);
        pkt_flags = pkt_flags | rx_desc_status_to_pkt_flags(staterr);
        pkt_flags = pkt_flags | rx_desc_error_to_pkt_flags(staterr);
        rxm->ol_flags = pkt_flags;
        rxm->packet_type = igb_rxd_pkt_info_to_pkt_type(rxd.wb.lower.
                        lo_dword.hs_rss.pkt_info);

        /*
         * Store the mbuf address into the next entry of the array
         * of returned packets.
         */

        /*第十步:将获取到的报文放入将要返回给用户操作的指针数组中*/
        rx_pkts[nb_rx++] = rxm;
    }
    rxq->rx_tail = rx_id;

    /*
     * If the number of free RX descriptors is greater than the RX free
     * threshold of the queue, advance the Receive Descriptor Tail (RDT)
     * register.
     * Update the RDT with the value of the last processed RX descriptor
     * minus 1, to guarantee that the RDT register is never equal to the
     * RDH register, which creates a "full" ring situtation from the
     * hardware point of view...
     */

     /*第十步:CPU判断rx_ring里可用描述符小于配置的阈值时更新尾部寄存器供DMA控制器参考*/
    nb_hold = (uint16_t) (nb_hold + rxq->nb_rx_hold);
    if (nb_hold > rxq->rx_free_thresh) {
        PMD_RX_LOG(DEBUG, "port_id=%u queue_id=%u rx_tail=%u "
               "nb_hold=%u nb_rx=%u",
               (unsigned) rxq->port_id, (unsigned) rxq->queue_id,
               (unsigned) rx_id, (unsigned) nb_hold,
               (unsigned) nb_rx);
        rx_id = (uint16_t) ((rx_id == 0) ?
                     (rxq->nb_rx_desc - 1) : (rx_id - 1));
        E1000_PCI_REG_WRITE(rxq->rdt_reg_addr, rx_id);
        nb_hold = 0;
    }
    rxq->nb_rx_hold = nb_hold;
    return nb_rx;
}                                          

                                             【五、发包软件处理流程】

发包流程与第四章的收包流程有些区别,DPDk在初始化阶段不会从mbuf池中获取缓冲区插到描述符队列空间里,只有在真正的发送过程中才会从mbuf池中获取mbuf,然后插入到描述符队列空间里。网卡的初始化配置部分下篇讲。

1、模块/硬件介绍

Tx_queue: 发包队列结构体:我们主要关注两个环形队列tx_ring、sw_ring

Tx_ring:一个地址连续环形队列,存储的是描述符,描述符中包含将来存放数据包的物理地址、DD标志(下面会介绍DD标志)等,上面图中只画了存放数据包的物理地址,物理地址供网卡DMA模块使用,也称为DMA地址(硬件使用物理地址,当网卡收到数据包后会通过DMA操作将数据包拷贝到物理地址,物理地址是通过虚拟地址转换得到的,下面分析源码时会介绍)

2、发包流程

Tx_ring发数据时的状态如下:


dpdk初始化完成时tx_ring的队列为空


DMA控制器通过head去判断当前的DD状态,如果为0则可以执行发送动作


 


CPU需要对tx_ring上网卡发送成功的描述符的缓存空间进行释放操作,待应用下次继续写入


(1)CPU读取发送侧描述符tx_ring队列,检查DD标志是否为1,为1则说明发送完毕

(2)针对发送完毕的描述符需要释放该描述符里对应的缓冲区

(3)CPU将准备发送的缓冲区mbuf的虚拟地址填充到描述符sw_ring

(4)CPU通过将准备发送的缓冲区mbuf的虚拟地址转换得到该mbuf里data数据部分的物理地址填充到发送测描述符tx_ring队列           中,并将DD标志清0

(5)DMA控制器读取base寄存器,获取发送侧描述符,根据发送测描述符获取tx_ring队列地址,读取head指针里的元素,判断DD标志释放为0则从描述符中获取数据缓存区地址,通过PCIE总线将数据拷贝到网卡硬件Tx_FIFO缓存中往外发送数据

(6)DMA控制器回写该描述符中队列里DD的标志置1,通知CPU该缓存中数据已成功发送

(7)至此,应用发送数据包完毕

注意:这里有两个非常关键的队列tx_ring、sw_ring,tx_ring描述符里存放的是mbuf里data区的起始物理地址供DMA控制器读取报文(硬件DMA直接操作物理地址,不需要cpu参与);sw_ring描述符里存放的是mbuf的起始虚拟地址供应用写入数据包

3、代码的实现过程

我们以e1000驱动类型网卡举例,来分析数据包发送相关的软件结构及接口

(1)发送队列的结构如下图,图中标出了两个重要的环形队列(上面已介绍):

 (2)数据包的软件发送流程如下图

                                                    

 (3) eth_igb_xmit_pkts接口源码,发包逻辑参考上面小节,这里不做补充了         

                                                   【六 、后续】

到目前位置分析完了数据包在网卡、CPU、主存上游走的流程,可以看到DPDK收发包的流程设计的还是比较震撼的,充分考虑到了高性能收发数据,其中一些处理流程、数据结构的设计经验等值得我们在平时的开发项目中去运用和学习。网卡的初始化配置那块后面再分析。

本篇文章中的网卡的硬件组成部分参考了网上其他网友的思路,本篇文章纯属个人的理解,观点可能存在错误的地方,另外文章中的文字及框架图为个人纯手工写的,可能会存在一些语法不顺等其他问题,欢迎各位朋友针对文中不正确的地方给多多指教。

DPDK-收包完整过程 本篇博客作为自己了解dpdk收包过程的一个记录。在写时发现已经有很多写DPDK收包过程的博客了,但还是决定自己写一遍。DPDK收包分为两个阶段,首先是DMA将数据包从网卡搬运到内存,然后是调用dpdk提供的接口rte_eth_rx_burst去取。但是具体是怎么做的呢?简单大致的过程如图1所示。图1,dpdk收包大致过程本文将按如下顺序进行展开。 阅读详情

相关推荐

dpdk网卡收包分析

一个网络报文从网卡接收到被应用处理,中间主要需要经历两个阶段:阶段一:网卡通过其DMA硬件将收到的报文写入到收包队列中(入队) 阶段二: 应用从收包队列中读取报文(出队) 由于目前正在使用vpp/dpdk 优化waf引擎的工作,所以就看看ixgbe网卡在dpdk框架下是怎么工作的。下面分别介绍一下 收包队列结构 初始化(使能) 收包流程。

lingshengxiyou的博客 619

深入浅出dpdk读书笔记--pcie与包处理(二)----dma

DMA(Direct Memory Access,直接存储器访问)是一种高速的数据传输方式,允许在外部设备和存储器之间直接读写数据。数据既不通过CPU,也不需要CPU干预。整个数据传输操作在DMA控制器的控制下进行。但是这种方式存在多次访存的情况,而且还存在内存一致性问题,基于此intel提出DDIO技术,是对传统DMA技术的一个优化。DDIO允许I/O设备(如支持该技术的网卡)将数据直接写入或读取CPU的最后级缓存(LLC),而非内存。

huoyunfeng13579的专栏 2316

14 DPDK 探索 DPDK收发包流程分析

DPDK是intel工程师开发的一款用来快速处理数据包的框架,最初的目的是为了证明传统网络数据包处理性能低不是intel处理器导致的,而是传统数据的处理流程导致,后来随着dpdk的开源及其生态的快速发展,dpdk成为了高性能网络数据处理的优秀框架。本篇文章主要介绍DPDK接收与发送报文的流程,包括CPU与网卡DMA协同工作的整个交互流程、数据包在内存、CPU、网卡之间游走的过程。CPU 有转移数据、计算、控制程序等很多功能,但其实转移数据(尤其是转移大量数据)是可以不需要 CPU 参与。

qq_39748830的博客 1453

DPDK收发包全景分析

前言:DPDK收发包是基础核心模块,从网卡收到包到驱动把包拷贝到系统内存中,再到系统对这块数据包的内存管理,由于在处理过程中实现了零拷贝,数据包从接收到发送始终只有一份,对这个报文的管理在前面的mempool内存池中有过介绍。这篇主要介绍收发包的过程。 一、收发包分解 收发包过程大致可以分为2个部分 1.收发包的配置和初始化,主要是配置收发队列等。 2.数据包的获取和发送,主要是从队列中获取到数...

weixin_30932215的博客 2803

深入浅出dpdk读书笔记--pcie与包处理(三)---收发包流程

pcie是报文转发的基础,DMA是网卡和CPU交互的具体方式,这两个知识点就像公路和汽车,外在的硬件已经有了,该启动汽车上路了,所以就有了接下来所讲的内容,dpdk数据的收发包流程。

huoyunfeng13579的专栏 1856

suricata中DPDK收发包源码分析2

suricata中分析了整体的DPDK收发包框架代码,今天我们继续来深入了解一下一些细节方面的问题。

每天分享一个编程小知识 716

DPDK 网卡收包流程

Table of Contents 1、Linux网络收发包流程 1.1 网卡与liuux驱动交互 1.2 linux驱动与内核协议栈交互 题外1: 中断处理逻辑 题外2:中断的弊端 2、linux发包流程 2、DPDK 收发包流程 2.1 网卡DMA描述符环形队列 2.2 dpdk 收包流程 1、构造收包队列 2.启动 3.收包 3、 PCIE 带宽调优 1)减少MMIO访问的频度。 (2)提高PCIe传输的效率。 (3)尽量避免Cache Line的部分写。 4、软..

RToax 9260

DPDK 收发包流程

dpdk 收发包流程

fengcai_ke的博客 2332

dpdk:收发包全景分析

前言:DPDK收发包是基础核心模块,从网卡收到包到驱动把包拷贝到系统内存中,再到系统对这块数据包的内存管理,由于在处理过程中实现了零拷贝,数据包从接收到发送始终只有一份,对这个报文的管理在前面的mempool内存池中有过介绍。这篇主要介绍收发包的过程。 目录 1、收发包分解 2、收发包的配置和初始化...

9383

手把手教你排查Abaqus中的Johnson-Cook损伤参数:避免因d3正负号导致的仿真失败

本文详细解析了Abaqus中Johnson-Cook损伤参数d3正负号设置的关键问题,帮助用户避免因参数错误导致的仿真失败和Excessive distortion报错。通过对比不同文献定义、提供实操指南和典型错误排查流程,有效提升非线性分析的准确性和效率。

weixin_33960567的博客 355

模型参考自适应控制(MRAC):让PID参数动态优化

本文深入解析模型参考自适应控制(MRAC)技术,它通过实时调整PID参数,使控制系统能自动适应系统特性变化和外部干扰。文章详细介绍了MRAC的工作原理、数学基础,并提供了用C语言实现的实战代码示例,帮助工程师解决传统PID控制在非线性、时变系统中参数整定繁琐的难题。

tequila的博客 903

dpdk报文收发流程

本篇文章来分析下dpdk是如何接收报文以及发送报文的。 一、报文的接收流程 传统方式接收报文时,当网卡接收到报文后会产生硬件中断,进而报文会通过协议栈,最后到达应用层,这个过程需要内核协议栈的处理。 和传统报文接收不同,当应用层想要接收来自网卡的报文时, 应用层通过while死循环的方式,调用rte_eth_rx_burst接口轮询接收来自网卡的报文,相当于绕...

ApeLife技术博客 6793

Unity物理引擎实战:从刚体重心到碰撞体,打造真实不倒翁交互

刚体(Rigidbody)是Unity物理系统的核心组件,它定义了游戏对象的物理属性,如质量、阻力和碰撞响应。其原理基于牛顿力学,通过物理引擎(如PhysX)实时计算物体的运动状态。在游戏开发中,刚体的价值在于能够模拟真实世界的物理行为,为玩家提供沉浸式的交互体验。碰撞体(Collider)则定义了物体的形状边界,用于检测与其他物体的接触。通过精细调整刚体的重心(Center of Mass)和碰撞体形状,开发者可以模拟出各种有趣的物理现象,例如低重心物体的动态平衡。这在休闲游戏、物理玩具模拟等场景中尤为实

weixin_33976326的博客 355

dpdk多设备收发包测试

**配置设备**:通过 `rte_eth_dev_configure()` 配置每个网卡设备,包括设置接收和发送队列,并调用 `rte_eth_rx_queue_setup()` 和 `rte_eth_tx_queue_setup()` 设置设备的接收和发送队列。- **合并和批量处理**:DPDK 提供了批量发送和接收 API (`rte_eth_rx_burst` 和 `rte_eth_tx_burst`),可以减少每次系统调用的开销,提高性能。

1123

从加权最小二乘(WLS)到IAA:手把手推导DOA估计中的迭代自适应核心公式

本文深入解析了从加权最小二乘(WLS)到迭代自适应算法(IAA)在DOA估计中的数学推导与应用。通过动态调整加权矩阵,IAA在低快拍数、相干源等复杂场景中展现出卓越性能,显著提升角度分辨率和检测概率。文章详细介绍了算法核心步骤、工程优化策略及前沿发展,为雷达探测和无线通信领域提供重要参考。

weixin_30847865的博客 290

NTC热敏电阻选型快速指南

NTC(Negative Temperature Coefficient Thermistor)负温度系数热敏电阻器,是由锰Mn,镍Ni,铜Cu,一氧化碳Co等烧结而成的氧化物。其电阻值随温度的升高而减小,即具有复温度系数,故被称为负温度系数热敏电阻。本文对热敏电阻的应用场景,结构特点和选型参数进行总结。

fydar的博客 1295

dpdk 程序收发包问题排查的一般流程

dpdk 程序收发包问题排查 接口不收包问题排查 1.确认网卡类型与异常接口 2.收集 ethtool -i x/x、ifconfig x/x、ethtool x/x、ethtool -d x/x、ethtool -S x/x 信息 3.确认接口连线是否正常,接口是否 up,接口处于 down 状态不能说明收包存在异常 4.确认对端是否在发流,对端没有发流则不能说明存在异常 5.dmesg 信息中是否有下面类似的信息: dmar: DMAR:[DMA Read] Request device [01

龙瑜的博客 2420

YOLO26涨点改进 | 细节涨点篇 | 源自SCI一区 | YOLO26引入HWD小波下采样模块,而不会显著增加计算开销,(适合小目标分割任务、小目标检测任务)

本文提出了一种基于Haar小波变换的下采样模块HWD,用于改进YOLO26目标检测性能。HWD模块通过小波变换降低特征图分辨率,同时将空间信息编码到通道维度,有效保留了关键信息。相比传统下采样方法,HWD能显著减少信息不确定性,提升小目标检测精度。实验表明,该模块可无缝集成到CNN架构中,不增加计算开销。文章详细介绍了HWD的实现原理、代码结构以及在YOLO26中的集成方法,并提供了两种改进版yaml配置文件。该创新模块已在多种数据集上验证有效,特别适合语义分割和目标检测任务。

Ai缝合怪、助力小伙伴高效发论文 403

DPDK介绍

什么是dpdk DPDK是INTEL公司开发的一款高性能的网络驱动组件,旨在为数据面应用程序提供一个简单方便的,完整的,快速的数据包处理解决方案,主要技术有用户态、轮询取代中断、零拷贝、网卡RSS、访存DirectIO等。 内核协议栈 vs dpdk 内核收包的两种方式 中断模式 网卡收到包提醒CPU发生中断处理包 轮询模式 CPU主动持续检查网卡是否有数据包到来 内核协议栈收包流程 TX/RX rings ● Circular queue ...

growing_up_的博客 3万+

华为OD机试 - 猴子吃桃 - 二分查找(Java 新系统 100分)

每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天优快云在线答疑。

学Java,找哪吒 3850

北斗导航 | 卫星信号捕获跟踪原理解析

卫星信号的捕获与跟踪是导航接收机的"眼睛",其性能直接决定定位精度、动态适应性和抗干扰能力。随着北斗三号全球组网完成,新一代接收机正朝着。两大核心阶段,二者共同构成定位的基础。调制,频谱主瓣宽度达4.092MHz,较传统BPSK调制抗干扰能力提升3dB[38]。的目标持续演进,在自动驾驶、精密农业等领域展现出巨大应用潜力。二维空间中搜索峰值相关能量[4]。卫星导航接收机对信号的处理可分为。北斗三号B1C/B2a信号采用。北斗三号新增的B1C信号采用。

尘世冰封的专栏 775

vpp中dpdk接口注册流程分析

vpp是一个优秀的包处理转发框架,可以采用非常多的接口类型来进行收发包,应用最多的就是dpdk了,因此本篇博客主要探讨被dpdk接管的网卡是如何注册到vpp中的。vpp代码版本是1904.本文代码贴的比较少,只描述了一些函数调用关系,最好可以参照源码阅读。 关于dpdk就不再赘述,简单的理解dpdk就是一个开发组件,提供了网卡驱动,可以接管原先由内核管理的网卡,实现kernel bypass。同时dpdk也提供了一些辅助机制,可以加快网卡报文的收发。而在vpp中,dpdk是作为一个插件来实现的。在编译vp

the_dog_tail_grass的博客 2934

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

上一篇: 几个非常实用性的在线学习Ethical Hacking的网站
下一篇: 动态规划(DP)的原理、实现及应用
废言Pro
博客等级 码龄16年 1093粉丝 142原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值