当前位置: 首页 > 工具软件 > mempool > 使用案例 >

dpdk-19.11 中 rte_mempool_create 与 rte_pktmbuf_pool_create 的区别

齐建安
2023-12-01

前言

dpdk-16.04 中,使用 rte_mempool_create 与 rte_pktmbuf_pool_create 都可以创建出支持多生产者与多消费者的 pktmbuf pool。

rte_mempool_create 创建 pktmbuf pool 示例代码如下:

pool = rte_mempool_create("MBUF_POOL", nb_mbuf_per_pool, MBUF_SIZE, MBUF_CACHE_SIZE,
			sizeof(struct rte_pktmbuf_pool_private),
			rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL,
			rte_socket_id(), 0);

rte_pktmbuf_pool_create 创建 pktmbuf pool 示例代码如下:

test_params->mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL",
			nb_mbuf_per_pool, MBUF_CACHE_SIZE, 0,
			RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());

rte_pktmbuf_pool_create 只能创建多生产者与多消费者的 pktmbuf pool,使用 rte_mempool_create 却可以创建诸如单生产者与单消费者的 pktmbuf pool。

尽管低版本有这样的行为,在高版本这两个接口却会有不同的行为。当 dpdk 程序从低版本向高版本迁移时,混用这两个接口在一些场景会有潜在的问题,且从编码角度不容易发现, 本文将描述一个相关的问题案例。

mempool_ops 抽象

dpdk 高版本对 mempool 进一步抽象,引入了 rte_mempool_ops 来实例化不同功能的 mempool 操作方法。在新的实现中,每一个 mempool 都要被绑定到一个 rte_mempool_ops 函数表上,这个函数表可以由用户指定,也可以隐藏在 mempool 创建的过程中。

rte_mempool_create_empty

使用 rte_mempool_create_empty 可以创建一个 rte_mempool_ops 为空的内存池,此后用户可以调用 rte_mempool_set_ops_byname 来绑定到一个自定义的 rte_mempool_ops 上。

rte_mempool_create VS rte_pktmbuf_pool_create 接口

rte_mempool_create 与 rte_pktmbuf_pool_create 并没有提供设定 rte_mempool_ops 的参数,这两个接口创建的 mempool 其 rte_mempool_ops 函数表在内部逻辑中绑定。

rte_mempool_create 中设置 rte_mempool_ops 函数表的代码如下:

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

它根据传入的 flags 参数来设定基于 dpdk ring 的不同 rte_mempool_ops 类型,根据生产者与消费者数目的组合分为四种。

rte_pktmbuf_pool_create 接口是对 rte_pktmbuf_pool_create_by_ops 函数的封装,它指定 ops_name 为空,在 rte_pktmbuf_pool_create_by_ops 函数中,通过调用 rte_mbuf_best_mempool_ops 函数确定绑定的 rte_mempool_ops,相关代码如下:

if (mp_ops_name == NULL)
		mp_ops_name = rte_mbuf_best_mempool_ops();
	ret = rte_mempool_set_ops_byname(mp, mp_ops_name, NULL);

rte_mbuf_best_mempool_ops 函数按如下顺序获取最优的 rte_mempool_ops 名称,找到一个则立刻返回。

  1. 查找名为 mbuf_user_pool_ops 的 memzone 中保存的 rte_mempool_ops 名称,当此 memzone 不存在则返回程序调用 rte_eal_init 时通过 --mbuf-pool-ops-name 参数指定的名称,未指定则返回空
  2. 查找名为 mbuf_platform_pool_ops 的 memzone 中保存的 rte_mempool_ops 名称
  3. 返回缺省的名称——ring_mp_mc

显然当设定了 mbuf_user_pool_ops 与 mbuf_platform_pool_ops 时, rte_pktmbuf_pool_create 与 rte_mempool_create 的行为就不一致,这时就可能产生异常的行为。

下面我将以一个实例来描述下这种异常行为的具体表现。

dpdk 使用 dpaa 网卡

nxp dpaa 网卡挂在 dpaa 总线上,dpaa_bus 的 rte_dpaa_bus_probe 函数中有如下代码:

rte_mbuf_set_platform_mempool_ops(DPAA_MEMPOOL_OPS_NAME);

此处代码将 platform_mempool_ops 设置为 dpaa,当 dpdk 程序使用 dpaa 网卡时,调用 rte_pktmbuf_pool_create 缺省绑定的 rte_mempool_ops 为 dpaa 类型,而调用 rte_mempool_create 却只能绑定基于 ring 的 rte_mempol_ops。

dpaa 驱动收发包队列使用的 mempool 需要绑定到 dpaa rte_mempool_ops,此时如果使用 rte_mempool_create 创建 mempool 在驱动运行时就会触发段错误。

问题的关键在于 dpaa rte_mempool_ops 中实现的 alloc 函数需要执行如下代码初始化内部结构:

  rte_memcpy(bp_info, (void *)&rte_dpaa_bpid_info[bpid],
		   sizeof(struct dpaa_bp_info));
	mp->pool_data = (void *)bp_info;

此 mp 的 pool_data 字段保存 dpaa_bp_info 结构的地址,驱动内部会使用 mp 来获取到这个结构地址访问。当未使用 dpaa rte_mempool_ops 创建时,mempool 的 pool_data 字段并不指向一个 dpaa_bp_info 结构,就会触发异常。

在 dpdk 源码中检索 mp->pool_data 赋值的位置,得到如下信息:

*** drivers/mempool/bucket/rte_mempool_bucket.c:
bucket_alloc[531]              mp->pool_data = bd;
*** drivers/mempool/dpaa/dpaa_mempool.c:
dpaa_mbuf_create_pool[119]     mp->pool_data = (void *)bp_info;
*** drivers/mempool/dpaa2/dpaa2_hw_mempool.c:
rte_hw_mbuf_create_pool[130]   mp->pool_data = (void *)bp_info;
*** drivers/mempool/ring/rte_mempool_ring.c:
ring_alloc[103]                mp->pool_data = r;
*** drivers/mempool/stack/rte_mempool_stack.c:
__stack_alloc[27]              mp->pool_data = s;

可以看到,不同的 rte_mempool_ops 实现类型,其 pool_data 指向的数据结构是不同的,rte_mempool_create 创建的 mempool 基于 ring,它创建的 mempool 的 pool_data 字段指向一个 rte_ring 结构,而非 dpaa_bp_info 结构。

其它类似行为

搜索 rte_mbuf_set_platform_mempool_ops,有如下结果:

./drivers/net/octeontx/octeontx_ethdev.c:1325:  rte_mbuf_set_platform_mempool_ops("octeontx_fpavf");
./drivers/mempool/octeontx2/otx2_mempool.c:313:         rte_mbuf_set_platform_mempool_ops("octeontx2_npa");
./drivers/bus/fslmc/portal/dpaa2_hw_dpbp.c:98:          rte_mbuf_set_platform_mempool_ops(DPAA2_MEMPOOL_OPS_NAME);
./drivers/bus/dpaa/dpaa_bus.c:694:      rte_mbuf_set_platform_mempool_ops(DPAA_MEMPOOL_OPS_NAME);

使用了这些总线、网卡驱动时都可能产生类似的问题。

总结

当 dpdk 程序从低版本向高版本迁移时,低版本的一些行为在表面上与高版本相同,但是实际却存在区别,导致适配后运行程序出现异常。要能够识别这些问题需要对低版本与高版本的行为都了如指掌,需要持续地研究。

 类似资料: