DPDK-vpp 一次mbuf地址被踩的定位思路
上个月解决了一个mbuf地址异常导致程序coredump的问题,问题定位前后花了将近一个月的时间,期间也是一点定位思路都没有,写这篇文章希望有同样问题的提供一种解决思路。
问题背景
在业务转发流程中vpp 发包模块mtu 9000字节,多mbuf单链表串联场景下,其中一个mbuf的next地址是非法地址,从而导致程序coredump异常。
异常调用栈分析
分析过程发现发包mubuf数组中tx_pkts[-1]的next是非法地址导致程序异常。通过vlib_buf的next_buffer反推下一个mbuf和当前mbuf->next地址不一致,确定next地址被修改。此问题在测试环境上大概率复现,并且地址中间2字节被清0.
Mar 30 16:48 coredump.hdp_wk_0.24145
(gdb) bt
#0 ixgbe_xmit_pkts (tx_queue=0x7ffadfe00480, tx_pkts=0x7fb46fb4bbf8, nb_pkts=474)at drivers/net/ixgbe/ixgbe_rxtx.c:860
#1 0x00007fb4d0d71161 in rte_eth_tx_burst (nb_pkts=<optimized out>, tx_pkts=<optimized out>, queue_id=1, port_id=<optimized out>)at install-hdp-native/dpdk/include/rte_ethdev.h:2791
#2 tx_burst_vector_internal (flag=0, tx_vector=<optimized out>, xd=0x7fb4701f2840, vm=<optimized out>)at build-data/../vnet/vnet/devices/dpdk/device.c:488
#3 dpdk_interface_tx (vm=<optimized out>, node=<optimized out>, f=<optimized out>)at build-data/../vnet/vnet/devices/dpdk/device.c:1799
#4 0x00007fb5265502aa in dispatch_node (vm=0x7fb46a883b08, node=0x7fb46fe799d8, type=<optimized out>, dispatch_state=<optimized out>, frame=<optimized out>, last_time_stamp=3244754031693250) at build-data/../vlib/vlib/main.c:1002
#5 0x00007fb526550495 in dispatch_pending_node (vm=vm@entry=0x7fb46a883b08, p=0x7fb46ef35d68, last_time_stamp=<optimized out>)at build-data/../vlib/vlib/main.c:1130
#6 0x00007fb526573239 in vlib_worker_thread_internal (vm=0x7fb46a883b08) at build-data/../vlib/vlib/threads.c:1450
#7 vlib_worker_thread_fn (arg=<optimized out>) at build-data/../vlib/vlib/threads.c:1495
#8 0x00007fb4979f1c80 in clib_calljmp () at build-data/../hdpinfra/hdpinfra/longjmp.S:110
#9 0x00007fb388174bc0 in ?? ()
#10 0x00000000005200e7 in eal_thread_loop (arg=<optimized out>)at lib/librte_eal/linuxapp/eal/eal_thread.c:186
#11 0x0000000000000000 in ?? ()
(gdb)
最开始在分析业务配置时,通过测试口述只是一个简单的ipsec业务场景,所以我们也把重点放在ipsec业务流程上去。通过加一些调式手段分析了一周也没有发现任何疑点。期间也阅读了vpp mempool申请,释放、ring队列等等代码(使用的是比较老的版本,mbuf pool池还是dpdk上申请和管理的,这点和最新vpp源码有差异)。dpdk中配置中有config/common_base文件中有一些debug开关可以打开如下:
#
# Compile librte_mbuf
#
CONFIG_RTE_LIBRTE_MBUF=y
CONFIG_RTE_LIBRTE_MBUF_DEBUG=y #由n修改为y
CONFIG_RTE_MBUF_DEFAULT_MEMPOOL_OPS="ring_mp_mc"
CONFIG_RTE_MBUF_REFCNT_ATOMIC=y
CONFIG_RTE_PKTMBUF_HEADROOM=128#
# Compile librte_mempool
#
CONFIG_RTE_LIBRTE_MEMPOOL=y
CONFIG_RTE_MEMPOOL_CACHE_MAX_SIZE=4096
CONFIG_RTE_LIBRTE_MEMPOOL_DEBUG=y #由n修改为y
CONFIG_RTE_LIBRTE_MEMPOOL_ADDR_DEBUG=y
上述开关打开后,异常调用栈总是报错在从mempool中的ring队列取mbuf时或者从mempool cache中取mbuf时,mbuf地址是非法的。
后续也做了下面一个调试:
1、关闭mempool中的cache; 相当于每次都是从mempool的ring队列中取mbuf。
2、mempool get和put时候,增加对ring队列上mbuf地址有效性检查。
3、在vpp node节点处理调度时,增加对ring队列mbuf地址有效性检查。
4、在mempool创建后,确定ring队列上地址时有效的。
5、将vpp修改成只有一个单线程,只有一个main核情况,-------这个比较关键。
修改dpdk的patch如下。
/*vpp相关修改*/
diff --git a/hdp/vlib/vlib/main.c b/hdp/vlib/vlib/main.c
index 8da914c..86d4b7f 100755
--- a/hdp/vlib/vlib/main.c
+++ b/hdp/vlib/vlib/main.c
@@ -996,7 +996,14 @@ dispatch_node (vlib_main_t * vm,b->pre_data[log_index] = node->node_index;}}
- n = node->function (vm, node, frame);
+ {+ extern void common_ring_check_mbuf(struct rte_mempool *mp);
+ struct rte_mempool *mp = vm->buffer_main->pktmbuf_pools[0];
+ common_ring_check_mbuf(mp);
+ n = node->function (vm, node, frame);
+ common_ring_check_mbuf(mp);
+
+ }}elsen = node->function (vm, node, frame);
/*dpdk相关修改*/
diff --git a/sdk/dpdk-19.11/config/common_base b/sdk/dpdk-19.11/config/common_base
index d2ae57b..ad5062a 100644
--- a/sdk/dpdk-19.11/config/common_base
+++ b/sdk/dpdk-19.11/config/common_base
@@ -816,7 +816,7 @@ CONFIG_RTE_LIBRTE_STACK=yCONFIG_RTE_LIBRTE_MEMPOOL=yCONFIG_RTE_MEMPOOL_CACHE_MAX_SIZE=4096CONFIG_RTE_LIBRTE_MEMPOOL_DEBUG=y
-CONFIG_RTE_LIBRTE_MEMPOOL_ADDR_DEBUG=y
+CONFIG_RTE_LIBRTE_MEMPOOL_ADDR_DEBUG=n## Compile Mempool drivers
diff --git a/sdk/dpdk-19.11/drivers/mempool/ring/rte_mempool_ring.c b/sdk/dpdk-19.11/drivers/mempool/ring/rte_mempool_ring.c
index e78a568..0bcab86 100644
--- a/sdk/dpdk-19.11/drivers/mempool/ring/rte_mempool_ring.c
+++ b/sdk/dpdk-19.11/drivers/mempool/ring/rte_mempool_ring.c
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: BSD-3-Clause
+ /* SPDX-License-Identifier: BSD-3-Clause* Copyright(c) 2010-2016 Intel Corporation*/@@ -9,12 +9,64 @@#include <rte_ring.h>#include <rte_mempool.h>+unsigned int start_check = 0;
+
+void common_ring_check_mbuf(struct rte_mempool *mp)
+{+ struct rte_ring *r = (struct rte_ring *)mp->pool_data;
+ void** ring = (void**)&r[1];
+ unsigned index;
+ const unsigned size = r->size;
+ unsigned mbuf_num = (r->prod.tail) - (r->cons.head);
+ unsigned idx = (r->cons.head)&(r->mask);
+
+ if ((start_check == 0) || (mbuf_num == 0))
+ {+ return;
+ }
+
+ if ((idx + mbuf_num) < size)
+ {+ for (index = 0; index < mbuf_num; index++,idx++)
+ {+ if (rte_mempool_from_obj(ring[idx]) != mp)
+ {+ rte_panic("MEMPOOL: bad mbuf:%p\n",ring[idx]);
+ }
+ }
+ }
+ else
+ {+ for (index = 0; idx < size; index++, idx++)
+ {+ if (rte_mempool_from_obj(ring[idx]) != mp)
+ {+ rte_panic("MEMPOOL: bad mbuf:%p\n",ring[idx]);
+ }
+ }
+
+ for (idx = 0; index < mbuf_num; index++, idx++)
+ {+ if (rte_mempool_from_obj(ring[idx]) != mp)
+ {+ rte_panic("MEMPOOL: bad mbuf:%p\n",ring[idx]);
+ }
+ }
+ }
+}
+static intcommon_ring_mp_enqueue(struct rte_mempool *mp, void * const *obj_table,unsigned n){- return rte_ring_mp_enqueue_bulk(mp->pool_data,
+
+
+ common_ring_check_mbuf(mp);
+ int ret = rte_ring_mp_enqueue_bulk(mp->pool_data,obj_table, n, NULL) == 0 ? -ENOBUFS : 0;
+
+ common_ring_check_mbuf(mp);
+ return ret;}static int
@@ -74,12 +126,15 @@ common_ring_mc_ensure_legality(struct rte_mempool *mp,static intcommon_ring_mc_dequeue(struct rte_mempool *mp, void **obj_table, unsigned n){+ common_ring_check_mbuf(mp);int ret = rte_ring_mc_dequeue_bulk(mp->pool_data, obj_table, n, NULL);ret = ret == 0 ? -ENOBUFS : 0;
-
+ if (0 == ret) {ret = common_ring_mc_ensure_legality(mp, obj_table, n);}
+ common_ring_check_mbuf(mp);
+return ret;}
问题稳定复现:
上述修改后,我们确认每次调度完bfd报文处理后,出现mbuf地址异常,后续的bfd处理node代码进行分析,发现问题存在原因。
获取udp地址不对,
对上面代码中udp_header->checksum=0xefef,查询挂的地址中间2字节被修改成0xefef。到这里我们基本确认问题点。
但是疑问的为什么会修改到ring队列存储地址上?
经过计算确实偏移到了ring的地址上,报文长度是96字节,因为没有进行字节序转换,所以便宜量时0x6000,计算如下:
(gdb) p &ring[idx] #异常mbuf的地址。
$8 = (void **) 0x7ffadf831af8。
问题回顾
1、没有详细分析测试的配置,从问题结论来看,只有流量触发bfd相关流程,才会出现此问题。我们可以从简化配置入手分析问题会少走很多弯路。
2、在第二周~~“在vpp node节点处理调度时,增加对ring队列mbuf地址有效性检查~~ ”已经加了这个检测问题,但是当时环境还是多核,误认为是其他是其他node导致。所以在解决此问题最好配置成单线程模式。
3、了解底层数据内存分布结构–vlib_buffer ret_mbuf ring mempool等加速问题定位效率。
DPDK-vpp 一次mbuf地址被踩的定位思路相关推荐
- 基于DPDK+VPP实现高性能防火墙
0. 数据平面和用户态协议栈 传统基于linux netfilter实现防火墙,虽然方便,但是性能很差.于是pfring/netmap/dpdk等机制,都要bypass掉内核协议栈. 多年来,各大操作 ...
- 如何在庞大的ip地址库中快速定位到对应的ip地址所对应的归属地?
通过ip地址查看 ip地址的归属地,这个功能实现起来并不复杂,它是通过维护一个很大的ip地址库来实现的,比如查找 202..133.3 该ip地址库,那便会在对应的ip地址库中找到 一个区间 如 [2 ...
- FD.io VPP 20.09版本正式发布:往期VPP文章回顾+下载地址+相关链接
目录 下载RPM/DEB包 往期文章回顾与推荐 FD.io是一些项目和库的集合,基于DPDK并逐渐演化,支持在通用硬件平台上部署灵活可变的业务.FD.io为软件定义基础设施的开发者提供了一个通用平台, ...
- DPDK 20.11 Dynamic mbuf
目录 背景 解决方法 申请外部结构 增大mbuf的空间 多种布局 Dynamic mbuf 原理 使用/API 更大的额外空间的需求怎么办? 参考 背景 需要metadata的场景 通用的metada ...
- 微信头像失效_微信头像地址失效踩坑记附带方案
微信头像失效问题说明? 最近工作遇到一个微信头像失效的问题,情况是这样的,我们一个h5页面在微信授权后打开,会存储微信相关昵称和头像信息,不过,我们没有保存图片到自己的服务器,而是仅仅存储微信头像地址 ...
- 微信头像失效_微信头像地址失效踩坑记附带解决方案
微信头像失效问题说明? 最近工作遇到一个微信头像失效的问题,情况是这样的,我们一个h5页面在微信授权后打开,会存储微信相关昵称和头像信息,不过,我们没有保存图片到自己的服务器,而是仅仅存储微信头像地址 ...
- 栈区数据被飞踩问题定位手段
1.栈溢出或者栈数据被踩时,继续运行就会出现segmentation fault.可以尝试着接管SIGSEGV信号,在信号处理函数中保存一些出现异常时候的信息. 2.基于栈溢出场景,栈空间被破坏,也就 ...
- Jenkins 插件 地址证书报错问题解决思路
问题提示摘要: SunCertPathBuilderException: unable to find valid certification path to requested target ... ...
- vue使用高德地图搜索地址添加标记marker,定位,拖拽选址功能
目录 JSAPI 的加载 使用 JSAPI Loader (推荐) 实现效果: 需求:点击输入框弹窗地图弹窗,输入框输入地址模糊搜索列表结果,点击列表添加相应得marker标记,并且添加标记拖拽选址功 ...
最新文章
- Microsoft patterns practices Enterprise Library released
- 【OpenCV 4开发详解】轮廓发现与绘制
- pandas使用sort_values函数和groupby函数获取每个分组数值最小的前N行数据(n rows with smallest column value in each group)
- 开源!mathAI 手写拍照自动能解高数题,还不快试试?
- 以太坊是什么 - 以太坊开发入门指南
- 分区创建 linux_在 Intel NUC 上安装 Linux
- Web 开发中 20 个很有用的 CSS 库
- Android 如何使用juv-rtmp-client.jar向Red5服务器发布实时视频数据
- Java 并发编程 基础
- link 和 style 元素在 HTML 文档中的位置
- 如何格式化电脑_电脑硬盘不小心格式化如何恢复【恢复方法】
- java完全自学手册 pdf_fortran教程下载
- genymotion-安卓模拟器-IMEI修改方法
- Zemax 快捷键及使用技巧(持续更新中)
- 视频图像处理-01背景差分法
- Python最优化算法学习笔记(Gurobi)
- Python 利用 turtle画出樱花树
- 省市县地址联动插件distpicker 代码及示例
- Arduino ESP8266 使用LittleFS存储配置文件实践
- android-配置文件AndroidManifest.xml详解