天天看点

DPDK内存管理三:用户接口

DPDK以两种方式对外提供内存管理方法,一个是rte_mempool,主要用于网卡数据包的收发;一个是rte_malloc,主要为应用程序提供内存使用接口。

struct rte_mempool 内存池结构体

/**
 * The RTE mempool structure.
 */
struct rte_mempool {
    /*
     * Note: this field kept the RTE_MEMZONE_NAMESIZE size due to ABI
     * compatibility requirements, it could be changed to
     * RTE_MEMPOOL_NAMESIZE next time the ABI changes
     */
    char name[RTE_MEMZONE_NAMESIZE]; /**< Name of mempool. */
    union {
        void *pool_data;         /**< Ring or pool to store objects. */
        uint64_t pool_id;        /**< External mempool identifier. */
    };
    void *pool_config;               /**< optional args for ops alloc. */
    const struct rte_memzone *mz;    /**< Memzone where pool is alloc'd. */
    int flags;                       /**< Flags of the mempool. */
    int socket_id;                   /**< Socket id passed at create. */
    uint32_t size;                   /**< Max size of the mempool. */
    uint32_t cache_size;
    /**< Size of per-lcore default local cache. */

    uint32_t elt_size;               /**< Size of an element. */
    uint32_t header_size;            /**< Size of header (before elt). */
    uint32_t trailer_size;           /**< Size of trailer (after elt). */

    unsigned private_data_size;      /**< Size of private data. */
    /**
     * Index into rte_mempool_ops_table array of mempool ops
     * structs, which contain callback function pointers.
     * We're using an index here rather than pointers to the callbacks
     * to facilitate any secondary processes that may want to use
     * this mempool.
     */
    int32_t ops_index;

    struct rte_mempool_cache *local_cache; /**< Per-lcore local cache */

    uint32_t populated_size;         /**< Number of populated objects. */
    struct rte_mempool_objhdr_list elt_list; /**< List of objects in pool */
    uint32_t nb_mem_chunks;          /**< Number of memory chunks */
    struct rte_mempool_memhdr_list mem_list; /**< List of memory chunks */

#ifdef RTE_LIBRTE_MEMPOOL_DEBUG
    /** Per-lcore statistics. */
    struct rte_mempool_debug_stats stats[RTE_MAX_LCORE];
#endif
}  __rte_cache_aligned;
           

rte_mempool由函数rte_mempool_create_empty()负责创建。

/* create the mbuf pool */
    l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", NB_MBUF,
        MEMPOOL_CACHE_SIZE, , RTE_MBUF_DEFAULT_BUF_SIZE,
        rte_socket_id());
           

这里rte_pktmbuf_pool_create()函数调用了rte_mempool_create_empty()函数创建一个empty mempool

mbuf_pool:rte_mempool的名称

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

MBUF_SIZE:每个rte_mbuf元素的大小

rte_mbuf: 表示一个数据包

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

DPDK内存管理三:用户接口

Mbuf由缓冲池rte_mempool管理,rte_mempool在初始化时一次申请多个mbuf,申请的mbuf个数和长度都由用户指定。宏MBUF_SIZE是例子程序中使用的mbuf长度:

用下面函数向rte_mempool申请一个mbuf:

struct rte_mbuf *rte_pktmbuf_alloc(struct rte_mempool *mp);
           

拷贝操作:

dpdk接收报文并把报文上送上层应用的过程中,报文传输是“零拷贝”,即不需要拷贝报文内容,只需要传送mbuf地址。然而在一个报文上送给多个应用时,仍然需要对报文做拷贝并送给不同的应用。Librte_mbuf采用“复制rte_mbuf,共享data数据域”的方式实现报文的拷贝函数rte_pktmbuf_clone(),函数原型如下:

struct rte_mbuf *rte_pktmbuf_clone(struct rte_mbuf *md, struct rte_mempool *mp)
           

rte_pktmbuf_clone()函数首先申请一个新的rte_mbuf,我们称这个mbuf为indirect buffer,用mi表示,参数md称为direct buffer。函数将md的各结构体成员(引用计数refcnt除外)一一复制给mi,同时将md的引用计数refcnt增1。此时,mi->pkt.data指向md的data数据域。

rte_malloc():

rte_malloc()为程序运行过程中分配内存,模拟从堆中动态分配内存空间

DPDK内存管理三:用户接口

rte_malloc_socket():

指定从哪个socket上分配内存空间,默认是指定SOCKET_ID_ANY,即,程序在哪个socket上运行,就从哪个socket上分配内存。如果指定的socket上没有合适的内存空间,就再从其它socket上分配。

malloc_heap_alloc():

从rte_config.mem_config->malloc_heaps[]数组中找到指定socket对应的堆(使用struct malloc_heap描述堆),即,从这个堆中分配空间。如果该堆是第一次使用,还没有被初始化过,则调用malloc_heap_init()初始化;首先,调用find_suitable_element()在堆中查找是否有合适内存可以分配,如果没有,则调用malloc_heap_add_memzone()在rte_config.mem_config->memzone[]中给堆分配一块内存。最后,调用malloc_elem_alloc()在堆中,将需要分配的内存划分出去。

继续阅读