本文主要介绍 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 内存块中,最前面存储 structrte_mempool 数据结构,后面紧接着是 rte_pktmbuf_pool_private 数据,再后面就是N个 rte_mbuf 内存块。

每个 rte_mbuf 内存中,最前面同样存储的是 structrte_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 virtualaddress. */

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 数组,每个 unione1000_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(structigb_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

DPDK内存管理 ----- (四) rte_mbuf相关推荐

  1. dpdk内存管理分析

    dpdk内存管理分析 文章目录 dpdk内存管理分析 1.1 简述 1.2 `rte_config_init`分析 1.3 `eal_hugepage_info_init`的分析 1.4 `rte_e ...

  2. DPDK 内存管理---malloc_heap和malloc_elem

    博文是基于dpdk20.5代码阅读所写,如理解有错误或不当之处,烦请指正,不甚感激.也可以私信我一起探讨. 两种数据结构体介绍 Malloc 库内部使用了两种数据结构类型(可以参考dpdk官方文档3. ...

  3. dpdk内存管理——内存初始化

    *说明:本系列博文源代码均来自dpdk17.02* 1.1内存初始化 1.1.1 hugepage技术 hugepage(2M/1G..)相对于普通的page(4K)来说有几个特点: (1) huge ...

  4. dpdk内存管理之rte_eal_hugepage_init()函数分析

    dpdk版本:dpdk-stable-16.11.11 今天我们来看一下rte_eal_hugepage_init() 函数都干了哪些事. 1.计算大页总数 在调用rte_eal_hugepage_i ...

  5. DPDK内存管理总结

    1.前言 本文基于DPDK-17.05.2分析总结, DPDK通过使用hugetlbfs,减少CPU TLB表的Miss次数,提高性能. 2.Hugetlbfs初始化 DPDK的内存初始化工作,主要是 ...

  6. dpdk 内存管理 原理剖析

    dpdk 的内存管理层次结构 物理巨页的管理 虚拟地址空间的管理 heap管理(变长buffer) mempool管理(定长buffer) 物理巨页的管理 dpdk中通过 数组 hugepg_tbl[ ...

  7. DPDK内存管理二:初始化

    DPDK 内存的初始化主要在rte_eal_init()函数中进行: eal_hugepage_info_init() /* 获取系统中hugepage种类以及数量信息到internal_config ...

  8. iPad/iPhone内存管理四之viewDidUnload/dealloc详细解说

    在进行内存管理时,我们必须要知道这两者的区别时什么. viewDidUnload是在程序接到内存警告的时候调用的,在这时候,我们可以把我们不需要的东西去掉或者让他等于nil. dealloc是在计数等 ...

  9. 内存管理(四)——虚拟内存

    前言 上一篇介绍完了内存分页,接下来就是内存管理的重头戏--虚拟内存了. 在正式介绍虚拟内存之前,先简单地介绍一下相关技术的发展过程.虽然我们的物理内存相较于过去已经变大了很多,但是程序所要占用的内存 ...

最新文章

  1. Nginx —— configure的命令参数(nginx编译选项)
  2. 银河麒麟4安装MySQL8_2020-03-24 linux 安装mysql8.0
  3. python:读取excel数据
  4. CI框架--加载静态内容
  5. mysql binlog DDL_mysql一个事务中有DDL语句的binlog情况
  6. java 实现WebService 以及不同的调用方式
  7. 51Nod-1011 最大公约数GCD【欧几里得算法】
  8. 阿里巴巴正式开源全球化OpenMessaging和ApsaraCache项目
  9. vue css下载字体并引入使用
  10. 2021年中国手游行业发展现状及未来发展趋势分析[图]
  11. 互联网大数据面试题集锦
  12. 我用二手书,在这里换了一大箱好书
  13. 大型团队合作的八条法则
  14. 区块链游戏- Solcery(Summoner 召唤者)
  15. linux startx无效_startx命令_Linux startx 命令用法详解:用来启动X Window
  16. 根据某一列拆分Excel为多个表格
  17. 用Rest assured作API自动化集成测试
  18. uni-app使用Hbuilder X如何安卓APP打包、发布、运行
  19. odoo15全面解决财务应收应付全面管理方案(含银企直联)(1)
  20. 马克思主义基本原理概论-练习题带答案

热门文章

  1. python发微信工资条_使用python自动发放员工工资条到个人邮箱
  2. Python筛选某列满足条件的值(isin用法)
  3. 最新的三星android版本号,三星率先公布Android 12/13升级机型名单,可惜S9/Note9被抛弃...
  4. 数学基础差怎么补救,怎么学数学最快最有效的方法
  5. 接口加密(TokenSpringCloud项目中进行token认证)
  6. 8086汇编(5、进位加法)
  7. 微信小程序map组件点聚合初次使用的坑
  8. 主流车品牌魅力指数榜别克、东风日产、一汽丰田列前三;亚航推出东盟超级应用平台 | 美通企业日报...
  9. FPGA零基础学习:数字通信中的电压标准
  10. AliOSS上传图片