DPDK内存管理-----(四)rte_mbuf

本文主要介绍rte_mbuf与rte_mempool数据结构之间的组织关系、以及网卡接收到的数据是如何存储在rte_mbuf中的。

一、rte_mbuf、rte_mempool及网卡收到的数据包在内存中的组织结构

      

调用rte_mempool_create()函数创建rte_mempool的时候,指定申请多少个rte_mbuff及每个rte_mbuf中elt_size的大小。elt_size是为网卡接收的数据包预先分配的内存的大小,该内存块就是rte_mbuf->pkt.data的实际存储区域。具体如上图所示。

在申请的rte_mempool内存块中,最前面存储struct rte_mempool数据结构,后面紧接着是rte_pktmbuf_pool_private数据,再后面就是N个rte_mbuf内存块。

每个rte_mbuf内存中,最前面同样存储的是struct rte_mbuf数据结果,后面是RTE_PKTMBUF_HEADROOM,最后面就是实际网卡接收到的数据,如下:

   struct rte_mbuf *m = _m;
    uint32_t buf_len = mp->elt_size - sizeof(struct rte_mbuf);

    RTE_MBUF_ASSERT(mp->elt_size >= sizeof(struct rte_mbuf));

    memset(m, 0, mp->elt_size);

    /* start of buffer is just after mbuf structure */
    m->buf_addr = (char *)m + sizeof(struct rte_mbuf);
    m->buf_physaddr = rte_mempool_virt2phy(mp, m) +
            sizeof(struct rte_mbuf);
    m->buf_len = (uint16_t)buf_len;

    /* keep some headroom between start of buffer and data */
    m->pkt.data = (char*) m->buf_addr + RTE_MIN(RTE_PKTMBUF_HEADROOM, m->buf_len);

    /* init some constant fields */
    m->type = RTE_MBUF_PKT;
    m->pool = mp;
    m->pkt.nb_segs = 1;
    m->pkt.in_port = 0xff;

二、网卡接收的数据是如何存储到rte_mbuf中的?

以e1000网卡为例,在网卡初始化的时候,调用eth_igb_rx_init()初始化网卡的收包队列。每个收包队列数据结果如下:

/**
 * Structure associated with each RX queue.
 */
struct igb_rx_queue {
    struct rte_mempool  *mb_pool;   /**< mbuf pool to populate RX ring. */
    volatile union e1000_adv_rx_desc *rx_ring; /**< RX ring virtual address. */
    uint64_t            rx_ring_phys_addr; /**< RX ring DMA address. */
    volatile uint32_t   *rdt_reg_addr; /**< RDT register address. */
    volatile uint32_t   *rdh_reg_addr; /**< RDH register address. */
    struct igb_rx_entry *sw_ring;   /**< address of RX software ring. */
    struct rte_mbuf *pkt_first_seg; /**< First segment of current packet. */
    struct rte_mbuf *pkt_last_seg;  /**< Last segment of current packet. */
    uint16_t            nb_rx_desc; /**< number of RX descriptors. */
    uint16_t            rx_tail;    /**< current value of RDT register. */
    uint16_t            nb_rx_hold; /**< number of held free RX desc. */
    uint16_t            rx_free_thresh; /**< max free RX desc to hold. */
    uint16_t            queue_id;   /**< RX queue index. */
    uint16_t            reg_idx;    /**< RX queue register index. */
    uint8_t             port_id;    /**< Device port identifier. */
    uint8_t             pthresh;    /**< Prefetch threshold register. */
    uint8_t             hthresh;    /**< Host threshold register. */
    uint8_t             wthresh;    /**< Write-back threshold register. */
    uint8_t             crc_len;    /**< 0 if CRC stripped, 4 otherwise. */
    uint8_t             drop_en;  /**< If not 0, set SRRCTL.Drop_En. */
};

我们只关注其中两个成员变量,rx_ring和sw_ring。rx_ring记录的是union e1000_adv_rx_desc数组,每个union e1000_adv_rx_desc中指定了网卡接收数据的DMA地址,网卡收到数据后,直接往该地址写数据。sw_ring数组记录的是每个具体的rte_mbuf地址,每个rte_mbuf的rte_mbuff->buf_phyaddr + RTE_PKTMBUF_HEADROOM映射后的DMA地址就存储在rx_ring队列的union e1000_adv_rx_desc数据结构中。rte_mbuff->buf_phyaddr + RTE_PKTMBUF_HEADROOM指向的就是rte_mbuf->pkt.data的地址。此时,rte_mbuf、rte_mbuf->pkt.data,已经网卡的收包队列就关联起来了。具体如下:

static int
igb_alloc_rx_queue_mbufs(struct igb_rx_queue *rxq)
{
    struct igb_rx_entry *rxe = rxq->sw_ring;
    uint64_t dma_addr;
    unsigned i;

    /* Initialize software ring entries. */
    for (i = 0; i < rxq->nb_rx_desc; i++) {
        volatile union e1000_adv_rx_desc *rxd;
        struct rte_mbuf *mbuf = rte_rxmbuf_alloc(rxq->mb_pool);

        if (mbuf == NULL) {
            PMD_INIT_LOG(ERR, "RX mbuf alloc failed "
                "queue_id=%hu\n", rxq->queue_id);
            return (-ENOMEM);
        }
        dma_addr =
            rte_cpu_to_le_64(RTE_MBUF_DATA_DMA_ADDR_DEFAULT(mbuf));
        rxd = &rxq->rx_ring[i];
        rxd->read.hdr_addr = dma_addr;
        rxd->read.pkt_addr = dma_addr;
        rxe[i].mbuf = mbuf;
    }

    return 0;
}

网卡收到数据后,向rx_ring指定的DMA地址上写数据,其实,就是往每个rte_mbuf->pkt.data写数据。应用程序在调用rte_eth_rx_burst()收包时,以e1000网卡为例,最后调用的是eth_igb_recv_pkts(),就是从每个收包队列中,从sw_ring数组中将rte_mbuf取出来,然后重启申请新的rte_mbuf替换到rx_ring中,重新关联rte_mbuf、union e1000_adv_rx_desc、sw_ring以及rte_mbuf->pkt.data的DMA地址。如下简图所示。

    

错误之处,欢迎指出。

转载请标明转自http://www.cnblogs.com/MerlinJ/p/4284706.html

时间: 2024-10-12 22:15:41

DPDK内存管理-----(四)rte_mbuf的相关文章

[转]dpdk内存管理

转自 dpdk内存管理 --初始化(hugepage)    https://www.cnblogs.com/MerlinJ/p/4074391.html dpdk内存管理--rte_mempool内存管理  https://www.cnblogs.com/MerlinJ/p/4081986.html dpdk内存管理-- rte_malloc内存管理   https://www.cnblogs.com/MerlinJ/p/4092432.html 原文地址:https://www.cnblog

DPDK内存管理-----(二)rte_mempool内存管理

DPDK以两种方式对外提供内存管理方法,一个是rte_mempool,主要用于网卡数据包的收发:一个是rte_malloc,主要为应用程序提供内存使用接口.本文讨论rte_mempool.rte_mempool由函数rte_mempool_create()负责创建,从rte_config.mem_config->free_memseg[]中取出合适大小的内存,放到rte_config.mem_config->memzone[]中. 本文中,以l2fwd为例,说明rte_mempool的创建及使

DPDK内存管理(1)

1 前言 DPDK将利用hugepage预留的物理内存统一的组织管理起来,然后以库的方式对外提供使用的接口.下图展示了DPDK中内存有关的模块的相互关系. rte_eal            是统一的组织管理者(当然rte_eal不只是做内存的工作) rte_malloc       对外提供分配释放内存的API,分配的内存都是rte_eal中管理的内存 rte_ring          提供无锁队列,他之间使用了rte_eal管理的内存 rte_mempool  利用rte_eal中的内存

DPDK内存管理(1)(转)

1 前言 DPDK将利用hugepage预留的物理内存统一的组织管理起来,然后以库的方式对外提供使用的接口.下图展示了DPDK中内存有关的模块的相互关系. rte_eal            是统一的组织管理者(当然rte_eal不只是做内存的工作) rte_malloc       对外提供分配释放内存的API,分配的内存都是rte_eal中管理的内存 rte_ring          提供无锁队列,他之间使用了rte_eal管理的内存 rte_mempool  利用rte_eal中的内存

DPDK内存管理-----(一)初始化

1 前言 DPDK通过使用hugetlbfs,减少CPU TLB表的Miss次数,提高性能. 2 初始化 DPDK的内存初始化工作,主要是将hugetlbfs的配置的大内存页,根据其映射的物理地址是否连续.属于哪个Socket等,有效的组织起来,为后续管理提供便利. 2.1 eal_hugepage_info_init() eal_hugepage_info_init()主要是获取配置好的Hugetlbfs的相关信息,并将其保存在struct internal_config数据结构中. 主要工作

DPDK内存管理-----(三)rte_malloc内存管理

rte_malloc()为程序运行过程中分配内存,模拟从堆中动态分配内存空间. 1 void * 2 rte_malloc(const char *type, size_t size, unsigned align) 3 { 4 return rte_malloc_socket(type, size, align, SOCKET_ID_ANY); 5 } rte_malloc()函数调用关系如下图: rte_malloc_socket():指定从哪个socket上分配内存空间,默认是指定SOCK

CUP对内存管理精华总(vector机制)

CPU对内存管理一: 内存:电容 操作系统:管理内存 CPU:处理数据. PC的CPU位数决定安装的操作系统位数,大了,浪费,小了无法安装操作系统 未来移动方向CPU与操作系统的最佳组合是Inter和微软 → 软件的沉淀 CPU对内存管理二: 内存4G用切割32位的方法划分为页表 页表和物理内存对应 优点:物理内存的保护和节省内存 一般认识的缺陷:可用内存4G,实际为少1M,一级页表 CPU对内存管理三: vector原理: 使用的内存,在页表中预留填写-1 -1提交后填写物理内存地址 使用完后

【OC语法快览】四、基础内存管理

Basic Memory Management                                                           基础内存管理 If you're writing an application for Mac OS X, you have the option to enable garbage collection. In general, this means that you don't have to think about memory

cocos2dx 3.1从零学习(四)——内存管理(错误案例分析)

本篇内容文字比较较多,但是这些都是建立在前面三章写代码特别是传值的时候崩溃的基础上的.可能表达的跟正确的机制有出入,还请指正. 如果有不理解的可以联系我,大家可以讨论一下,共同学习. 首先明确一个事实,retain和release是一一对应的,跟new和delete一样. 1.引用计数retain release 这里请参考一下引用计数的书籍,肯定说的比我讲的详细. 简单一点理解就是,对new的指针加一个计数器,每引用一次这块内存,计数就加1.在析构的时候减1,如果等于0的时候就delete这个