DPDK数据包与内存专题-mempool内存池

前言:DPDK提供了内存池机制,使得内存的管理的使用更加简单安全。在设计大的数据结构时,都可以使用mempool分配内存,同时,mempool也提供了内存的获取和释放等操作接口。对于数据包mempool甚至提供了更加详细的接口-rte_pktmbuf_pool_create(),接下来重点分析通用的内存池相关内容。使用DPDK-17.02版本。

一. mempool的创建

内存池的创建使用的接口是rte_mempool_create()。在仔细分析代码之前,先说明一下mempool的设计思路:在DPDK-17.02版本中(和2.1等先前版本在初始化略有差异),总体来说,mempool的组织是通过3个部分实现的

  • 1.mempool头结构。mempool由名字区分,挂接在struct rte_tailq_elem rte_mempool_tailq全局队列中,可以根据mempool的名字进行查找,使用rte_mempool_lookup()接口即可。这只是个mempool的指示结构,mempool分配的内存区并不在这里面,只是通过物理和虚拟地址指向实际的内存地址。
  • 2.mempool的实际空间。这就是通过内存分配出来的地址连续的空间,用来存储mempool的obj对象。
  • 3.ring队列。ring是个环形无锁队列,关于这个话题,可以参考官方文档来了解。其作用就是存放mempool中的对象指针,提供了方便存取使用mempool的空间的办法。

接下来,就来具体看看mempool的创建和初始化过程。
先注意一下rte_mempool_create的参数中的两个-mp_initobj_init,前者负责初始化mempool中配置的私有参数,如在数据包中加入的我们自己的私有结构;后者负责初始化每个mempool对象。我们然后按照mempool的3个关键部分展开说明。

  • 1.mempool头结构的创建
    在DPDK-17.02中,mempool头结构包含3个部分:struct rte_mempool,cache和mempool private。创建是在rte_mempool_create_empty()中完成的,看这个函数,先进行了对齐的检查
RTE_BUILD_BUG_ON((sizeof(struct rte_mempool) & RTE_CACHE_LINE_MASK) != 0); 

然后从mempool队列中取出头节点,我们创建的mempool结构填充好,就挂接在这个节点上。接下来做一些检查工作和创建flag的设置。

rte_mempool_calc_obj_size()计算了每个obj的大小,这个obj又是由三个部分组成的,objhdr,elt_size,objtlr,即头,数据区,尾。在没有开启RTE_LIBRTE_MEMPOOL_DEBUG调试时,没有尾部分;头部分的结构为:struct rte_mempool_objhdr,通过这个头部,mempool中的obj都是链接到队列中的,所以,提供了遍历obj的方式(尽管很少这么用)。函数返回最后计算对齐后的obj的大小,为后面分配空间提供依据。

然后分配了一个mempool队列条目,为后面挂接在队列做准备。

te = rte_zmalloc("MEMPOOL_TAILQ_ENTRY", sizeof(*te), 0);
    if (te == NULL) {
        RTE_LOG(ERR, MEMPOOL, "Cannot allocate tailq entry!\n");
        goto exit_unlock;
    }

接下来,就是计算整个mempool头结构多大,吐槽这里的命名!

    mempool_size = MEMPOOL_HEADER_SIZE(mp, cache_size);
    mempool_size += private_data_size;
    mempool_size = RTE_ALIGN_CEIL(mempool_size, RTE_MEMPOOL_ALIGN);

mempool_size这个名字太有误导性,这里指的是计算mempool的头结构的大小。而不是内存池实际的大小。在这里可以清晰的看出这个mempool头结构是由三部分组成的。cache计算的是所有核上的cache之和。

然后,分配这个mempool头结构大小的空间,填充mempool结构体,并把mempool头结构中的cache地址分配给mempool。初始化这部分cache.

最后就是挂接mempool结构。TAILQ_INSERT_TAIL(mempool_list, te, next);

  • 2.mempool实际空间的创建和ring的创建

这部分的创建是在函数rte_mempool_populate_default() 中完成的。

首先计算了每个elt的总共的大小

total_elt_sz = mp->header_size + mp->elt_size + mp->trailer_size;

然后计算为这些元素需要分配多大的空间,rte_mempool_xmem_size(n, total_elt_sz, pg_shift);
 

接着rte_memzone_reserve_aligned()分配空间。
终于到关键的一步了,rte_mempool_populate_phys()把元素添加到mempool,实际上就是把申请的空间分给每个元素。

先看到的是这么一段代码:

 
if ((mp->flags & MEMPOOL_F_POOL_CREATED) == 0) {
        ret = rte_mempool_ops_alloc(mp);
        if (ret != 0)
            return ret;
        mp->flags |= MEMPOOL_F_POOL_CREATED;
} 

这就是创建ring的过程咯,其中的函数rte_mempool_ops_alloc()就是实现。那么,对应的ops->alloc()在哪注册的呢?

if ((flags & MEMPOOL_F_SP_PUT) && (flags & MEMPOOL_F_SC_GET))
        rte_mempool_set_ops_byname(mp, "ring_sp_sc", NULL);
    else if (flags & MEMPOOL_F_SP_PUT)
        rte_mempool_set_ops_byname(mp, "ring_sp_mc", NULL);
    else if (flags & MEMPOOL_F_SC_GET)
        rte_mempool_set_ops_byname(mp, "ring_mp_sc", NULL);
    else
        rte_mempool_set_ops_byname(mp, "ring_mp_mc", NULL);

就是根据ring的类型,来注册对应的操作函数,如默认的就是ring_mp_mc,多生产者多消费者模型,其操作函数不难找到:

static const struct rte_mempool_ops ops_mp_mc = {
    .name = "ring_mp_mc",
    .alloc = common_ring_alloc,
    .free = common_ring_free,
    .enqueue = common_ring_mp_enqueue,
    .dequeue = common_ring_mc_dequeue,
    .get_count = common_ring_get_count,
};

接下来,又分配了一个struct rte_mempool_memhdr *memhdr;结构的变量,就是这个变量管理着mempool的实际内存区,它记录着mempool实际地址区的物理地址,虚拟地址,长度等信息。

再然后,就是把每个元素对应到mempool池中了:mempool_add_elem()。在其中,把每个元素都挂在了elt_list中,可以遍历每个元素。最后rte_mempool_ops_enqueue_bulk(mp, &obj, 1);,最终,把元素对应的地址入队,这样,mempool中的每个元素都放入了ring中。

创建完成!!!

二 . mempool的使用

mempool的常见使用是获取元素空间和释放空间。

  • rte_mempool_get可以获得池中的元素,其实就是从ring取出可用元素的地址。
  • rte_mempool_put可以释放元素到池中。
  • rte_mempool_in_use_count查看池中已经使用的元素个数
  • rte_mempool_avail_count 查看池中可以使用的元素个数

三. 后记

mempool是DPDK内存管理的重要组件,这篇重点介绍了 mempool创建使用的过程,对于系统如何做大页映射,统一地址并没有涉及,希望在后面的篇幅中,关注一下大页的映射和共享内存等。再往后,会介绍驱动与收发包等联系较大的内容。

转载于:https://www.cnblogs.com/yhp-smarthome/p/6687175.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
dpdk-chinaasiapacificsummit2016-park-fastuser.pdf是一份关于2016年DPDK中国亚太峰会上关于Park Fast用户需求的文件。DPDK是数据平面开发工具包的简称,该峰会旨在为来自亚太地区的网络与通信技术专家提供一个交流和分享的平台。 这份文件主要涉及Park Fast用户需求,Park Fast是一种基于DPDK的技术解决方案,用于处理大规模数据包转发和网络加速。Park Fast的用户需求是指使用该解决方案的用户对其功能和性能的要求。 文件的内容可能包括以下几个方面: 1. Park Fast的性能需求:用户对Park Fast在大规模数据包转发和网络加速方面的性能要求,例如,需要支持多少并发连接数,希望达到何种网络吞吐量等。 2. Park Fast的功能需求:用户对Park Fast的各项功能的需求,例如,是否需要支持多种协议,是否需要支持虚拟化环境,是否需要支持特定的硬件设备等。 3. 用户特定需求:不同用户可能有不同的需求,例如,一些用户可能需要定制化的功能或者特定的技术支持,这些需求也可能在文件中提及。 4. 性能优化需求:用户可能对Park Fast的性能进行优化的需求,例如,减少延迟、提高数据包处理效率等。 文件的目的是为Park Fast的开发团队和使用团队提供一个清晰的需求指南,以便在开发和使用过程中更好地满足用户的需求。同时,文件也可以作为日后评估Park Fast解决方案的性能和功能是否满足用户要求的参考依据。 总之,dpdk-chinaasiapacificsummit2016-park-fastuser.pdf是一份关于Park Fast用户需求的文件,提供了关于性能、功能和用户特定需求等方面的信息,旨在为Park Fast解决方案的开发和使用提供指导。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值