DPDK内存管理-mempool、mbuf
来源:互联网 发布:泰拉瑞亚mac存档位置 编辑:程序博客网 时间:2024/06/05 07:59
1. init
DPDK通过使用hugetlbfs,减少CPU TLB表的Miss次数,提高性能。
DPDK的内存初始化工作,主要是将hugetlbfs的配置的大内存页,根据其映射的物理地址是否连续、属于哪个Socket等,有效的组织起来,为后续管理提供便利。
1. eal_hugepage_info_init
eal_hugepage_info_init()主要是获取配置好的Hugetlbfs的相关信息,并将其保存在struct internal_config数据结构中。主要工作如下:
- 读取/sys/kernel/mm/hugepages目录下的各个子目录,通过判断目录名称中包含”hugepages-“字符串,获取hugetlbfs的相关子目录,并获取hugetlbfs配置的内存页大小。
- 通过读取/proc/mounts信息,找到hugetlbfs的挂载点。
- 通过读取/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages,获取配置的hugepages个数。
- 以打开文件的方式,打开挂载点目录,为其FD设置互斥锁。上述所有获取的信息,都保存在internal_config.hugepage_info[MAX_HUGEPAGES_SIZE]中,hugepage_info数据结构如下:
struct hugepage_info { size_t hugepage_sz; /**< size of a hugepage */ const char *hugedir; /**< dir wherehugetlbfs is mounted */ uint32_t num_pages[RTE_MAX_NUMA_NODES]; /**< number of hugepages of that size oneach socket */ int lock_descriptor; /**< file descriptorfor hugepage dir */};赋值如下:hpi->hugepage_sz = 2M;hpi->hugedir = /mnt/huge;hpi->num_pages[0] = 64; // 由于此时还不知道哪些内存页分处在哪个socket上,故都先放在socket-0上。hpi->lock_descriptor = open(hpi->hugedir, O_RONLY); // 在读取hugetlbfs配置的时候,需要锁住整个目录。当所有hugepage都mmap(将一个文件或者其它对象映射进内存)完成后,会解锁。
2. rte_eal_config_create
rte_eal_config_create()主要是初始化rte_config.mem_config。
如果是以root用户运行dpdk程序的话,rte_config.mem_config = /var/run/.rte_config文件mmap的首地址,指向/var/run/.rte_config文件mmap的一段 sizeof(struct rte_mem_config) 大小的内存。
3. rte_eal_hugepage_init
rte_eal_hugepage_init()主要是在/mnt/huge目录下创建hugetlbfs配置的内存页数(在本文中就是64)的rtemap_xx文件,并为每个rtemap_xx文件做mmap映射,保证mmap后的虚拟地址与实际的物理地址是一样的。
4. rte_eal_memdevice_init
rte_eal_memdevice_init()初始化rte_config.mem_config->nchannel和rte_config.mem_config->nrank。
rte_config.mem_config->nchannel = 启动参数中“-n”指定的值,不能为0,不能大于4。
rte_config.mem_config->nrank = 启动参数中“-r”指定的值。不能为0,不能大于16。
5. rte_eal_memzone_init
rte_eal_memzone_init()主要负责初始化rte_config.mem_config->free_memseg[]及rte_config.mem_config->memzone[]。
其中,rte_config.mem_config->free_memseg[]记录空闲的rte_config.mem_config->memseg[]。
2. rte_mempool
DPDK 以两种方式对外提供内存管理方法:
- rte_mempool,主要用于网卡数据包的收发;
- rte_malloc,主要为应用程序提供内存使用接口。
rte_mempool 由函数 rte_mempool_create() 负责创建,从 rte_config.mem_config->free_memseg[] 中取出合适大小的内存,放到 rte_config.mem_config->memzone[] 中。
以 l2fwd 为例,说明 rte_mempool 的创建及使用:
l2fwd_pktmbuf_pool =rte_mempool_create("mbuf_pool", NB_MBUF,MBUF_SIZE, 32,sizeof(structrte_pktmbuf_pool_private),rte_pktmbuf_pool_init, NULL,rte_pktmbuf_init, NULL,rte_socket_id(), 0);// “mbuf_pool”:创建的rte_mempool的名称。// NB_MBUF:rte_mempool包含的rte_mbuf元素的个数。// MBUF_SIZE:每个rte_mbuf元素的大小。#defineRTE_PKTMBUF_HEADROOM 128#defineMBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)#defineNB_MBUF 8192struct rte_pktmbuf_pool_private { uint16_t mbuf_data_room_size; /**< Size of data space in each mbuf.*/};
rte_mempool 由函数 rte_mempool_create() 负责创建。首先创建 rte_ring,再创建 rte_mempool,并建立两者之间的关联。
1.rte_ring_create()创建rte_ring无锁队列
r = rte_ring_create(rg_name, rte_align32pow2(n+1), socket_id, rg_flags);
具体步骤如下:
a、需要保证创建的队列数可以被2整除,即,count = rte_align32pow2(n + 1);
b、计算需要为count个队列分配的内存空间,即,ring_size = count * sizeof(void *) + sizeof(struct rte_ring);
c、调用 rte_memzone_reserve(),在 rte_config.mem_config->free_memseg[] 中查找一个合适的 free_memseg(查找规则是 free_memseg 中剩余内存大于等于需要分配的内存,但是多余的部分是最小的),从该 free_memseg 中分配指定大小的内存,然后将分配的内存记录在 rte_config.mem_config->memzone[] 中。
d、初始化新分配的rte_ring。
2、创建并初始化rte_mempool
a、计算需要为rte_mempool申请的内存空间。包含:sizeof(struct rte_mempool)、private_data_size,以及n * objsz.total_size。
b、调用rte_memzone_reserve(),在rte_config.mem_config->free_memseg[]中查找一个合适的free_memseg,在该free_memseg中分配mempool_size大小的内存,然后将新分配的内存记录到rte_config.mem_config->memzone[]中。
c、初始化新创建的rte_mempool,并调用rte_pktmbuf_pool_init()初始化rte_mempool的私有数据结构。
d、调用mempool_populate(),以及rte_pktmbuf_init()初始化rte_mempool的每个rte_mbuf元素。
3. rte_mbuf
1. 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;
2.网卡接收的数据是如何存储到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 intigb_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地址。如下简图所示。
- DPDK内存管理-mempool、mbuf
- dpdk mbuf
- 图解dpdk mempool 对象
- DPDK-Mbuf 结构学习MBUF LIBRARY
- dpdk内存管理
- DPDK mbuf 与 sk_buff转换
- [RTT例程练习] 3.3 静态内存管理,内存池mempool
- DPDK内存管理 ----- (四) rte_mbuf
- dpdk中文-mbuf的基本操作
- dpdk学习之mbuf结构体
- [DPDK编程手册]5Mempool库
- DPDK-Ring 结构学习MEMPOOL LIBRARY
- 内存池(MemPool)
- DPDK内存管理-----(一)初始化
- DPDK内存管理 -----(一)初始化
- DPDK内存管理 -----(二)rte_mempool
- DPDK内存管理 -----(三)rte_malloc
- DPDK内存管理-----(四)rte_mbuf
- 六、工程结构 (一)应用分层
- selenium自动化测试资源整理(含所有版本chrome、chromedriver、firefox下载链接)
- leetcode 312. Burst Balloons 按照length做DP + 很值得学习
- (回顾)水池数目 &&最少步数
- python数组的使用
- DPDK内存管理-mempool、mbuf
- 【收藏篇】32篇技术博文汇总(九月总结)
- Android APK反编译
- 数据服务业务是未来趋势,荣之联刚刚发布的大数据平台DataZoo有啥亮点?
- BZOJ 1008 [HNOI2008]越狱
- 关于 Ubuntu Linux 16.04的 root 权限及桌面登录问题
- 使用神经网络识别手写数字--原理部分
- 金融科技&大数据产品推荐:91征信——用互联网改变征信
- 金融科技&大数据产品推荐:享宇金服-智能金融云