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的创建及使用。

一、rte_mempool的创建

1 l2fwd_pktmbuf_pool =2     rte_mempool_create("mbuf_pool", NB_MBUF,3                MBUF_SIZE, 32,4                sizeof(struct rte_pktmbuf_pool_private),5                rte_pktmbuf_pool_init, NULL,6                rte_pktmbuf_init, NULL,7                rte_socket_id(), 0);

“mbuf_pool”:创建的rte_mempool的名称。

NB_MBUF:rte_mempool包含的rte_mbuf元素的个数。

MBUF_SIZE:每个rte_mbuf元素的大小。

1 #define RTE_PKTMBUF_HEADROOM    1282 #define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)3 #define NB_MBUF   8192

1 struct rte_pktmbuf_pool_private {2     uint16_t mbuf_data_room_size; /**< Size of data space in each mbuf.*/3 };

rte_mempool由函数rte_mempool_create()负责创建。首先创建rte_ring,再创建rte_mempool,并建立两者之间的关联。

DPDK内存管理-----(二)rte_mempool内存管理_第1张图片

1、rte_ring_create()创建rte_ring无锁队列

1 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);

struct rte_ring的数据结构如下,

 1 struct rte_ring { 2     TAILQ_ENTRY(rte_ring) next;      /**< Next in list. */ 3  4     char name[RTE_RING_NAMESIZE];    /**< Name of the ring. */ 5     int flags;                       /**< Flags supplied at creation. */ 6  7     /** Ring producer status. */ 8     struct prod { 9         uint32_t watermark;      /**< Maximum items before EDQUOT. */10         uint32_t sp_enqueue;     /**< True, if single producer. */11         uint32_t size;           /**< Size of ring. */12         uint32_t mask;           /**< Mask (size-1) of ring. */13         volatile uint32_t head;  /**< Producer head. */14         volatile uint32_t tail;  /**< Producer tail. */15     } prod __rte_cache_aligned;16 17     /** Ring consumer status. */18     struct cons {19         uint32_t sc_dequeue;     /**< True, if single consumer. */20         uint32_t size;           /**< Size of the ring. */21         uint32_t mask;           /**< Mask (size-1) of ring. */22         volatile uint32_t head;  /**< Consumer head. */23         volatile uint32_t tail;  /**< Consumer tail. */24 #ifdef RTE_RING_SPLIT_PROD_CONS25     } cons __rte_cache_aligned;26 #else27     } cons;28 #endif29 30 #ifdef RTE_LIBRTE_RING_DEBUG31     struct rte_ring_debug_stats stats[RTE_MAX_LCORE];32 #endif33 34     void * ring[0] __rte_cache_aligned; /**< Memory space of ring starts here.35                                          * not volatile so need to be careful36                                          * about compiler re-ordering */37 };

c、调用rte_memzone_reserve(),在rte_config.mem_config->free_memseg[]中查 找一个合适的free_memseg(查找规则是free_memseg中剩余内存大于等于需要分配的内存,但是多余的部分是最小的),从该 free_memseg中分配指定大小的内存,然后将分配的内存记录在rte_config.mem_config->memzone[]中。

d、初始化新分配的rte_ring。

 1 r->flags = flags; 2 r->prod.watermark = count; 3 r->prod.sp_enqueue = !!(flags & RING_F_SP_ENQ); 4 r->cons.sc_dequeue = !!(flags & RING_F_SC_DEQ); 5 r->prod.size = r->cons.size = count; 6 r->prod.mask = r->cons.mask = count-1; 7 r->prod.head = r->cons.head = 0; 8 r->prod.tail = r->cons.tail = 0; 9 10 TAILQ_INSERT_TAIL(ring_list, r, next); // 挂到rte_config.mem_config->tailq_head[RTE_TAILQ_RING]队列中

2、创建并初始化rte_mempool

a、计算需要为rte_mempool申请的内存空间。包含:sizeof(struct rte_mempool)、private_data_size,以及n * objsz.total_size。

1 mempool_size = MEMPOOL_HEADER_SIZE(mp, pg_num) + private_data_size;2 if (vaddr == NULL)3     mempool_size += (size_t)objsz.total_size * n;

objsz.total_size = objsz.header_size + objsz.elt_size + objsz.trailer_size; 其中,

objsz.header_size = sizeof(struct rte_mempool *);

objsz.elt_size = MBUF_SIZE;

objsz.trailer_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的私有数据结构。

 1 /* init the mempool structure */ 2 mp = mz->addr; 3 memset(mp, 0, sizeof(*mp)); 4 snprintf(mp->name, sizeof(mp->name), "%s", name); 5 mp->phys_addr = mz->phys_addr; 6 mp->ring = r; 7 mp->size = n; 8 mp->flags = flags; 9 mp->elt_size = objsz.elt_size;10 mp->header_size = objsz.header_size;11 mp->trailer_size = objsz.trailer_size;12 mp->cache_size = cache_size;13 mp->cache_flushthresh = (uint32_t)14     (cache_size * CACHE_FLUSHTHRESH_MULTIPLIER);15 mp->private_data_size = private_data_size;16 17 /* calculate address of the first element for continuous mempool. */18 obj = (char *)mp + MEMPOOL_HEADER_SIZE(mp, pg_num) +19     private_data_size;20 21 /* populate address translation fields. */22 mp->pg_num = pg_num;23 mp->pg_shift = pg_shift;24 mp->pg_mask = RTE_LEN2MASK(mp->pg_shift, typeof(mp->pg_mask));25 26 /* mempool elements allocated together with mempool */27 mp->elt_va_start = (uintptr_t)obj;28 mp->elt_pa[0] = mp->phys_addr +29     (mp->elt_va_start - (uintptr_t)mp);30 31 mp->elt_va_end = mp->elt_va_start;32 33 RTE_EAL_TAILQ_INSERT_TAIL(RTE_TAILQ_MEMPOOL, rte_mempool_list, mp); //挂到rte_config.mem_config->tailq_head[RTE_TAILQ_MEMPOOL]队列中

d、调用mempool_populate(),以及rte_pktmbuf_init()初始化rte_mempool的每个rte_mbuf元素。

3、总结

相关数据结构的关联关系如下图:

DPDK内存管理-----(二)rte_mempool内存管理_第2张图片

二、rte_mempool的调用

未完,待续。。。。

错误之处,欢迎指出。