上个月解决了一个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地址被踩的定位思路相关推荐

  1. 基于DPDK+VPP实现高性能防火墙

    0. 数据平面和用户态协议栈 传统基于linux netfilter实现防火墙,虽然方便,但是性能很差.于是pfring/netmap/dpdk等机制,都要bypass掉内核协议栈. 多年来,各大操作 ...

  2. 如何在庞大的ip地址库中快速定位到对应的ip地址所对应的归属地?

    通过ip地址查看 ip地址的归属地,这个功能实现起来并不复杂,它是通过维护一个很大的ip地址库来实现的,比如查找 202..133.3 该ip地址库,那便会在对应的ip地址库中找到 一个区间 如 [2 ...

  3. FD.io VPP 20.09版本正式发布:往期VPP文章回顾+下载地址+相关链接

    目录 下载RPM/DEB包 往期文章回顾与推荐 FD.io是一些项目和库的集合,基于DPDK并逐渐演化,支持在通用硬件平台上部署灵活可变的业务.FD.io为软件定义基础设施的开发者提供了一个通用平台, ...

  4. DPDK 20.11 Dynamic mbuf

    目录 背景 解决方法 申请外部结构 增大mbuf的空间 多种布局 Dynamic mbuf 原理 使用/API 更大的额外空间的需求怎么办? 参考 背景 需要metadata的场景 通用的metada ...

  5. 微信头像失效_微信头像地址失效踩坑记附带方案

    微信头像失效问题说明? 最近工作遇到一个微信头像失效的问题,情况是这样的,我们一个h5页面在微信授权后打开,会存储微信相关昵称和头像信息,不过,我们没有保存图片到自己的服务器,而是仅仅存储微信头像地址 ...

  6. 微信头像失效_微信头像地址失效踩坑记附带解决方案

    微信头像失效问题说明? 最近工作遇到一个微信头像失效的问题,情况是这样的,我们一个h5页面在微信授权后打开,会存储微信相关昵称和头像信息,不过,我们没有保存图片到自己的服务器,而是仅仅存储微信头像地址 ...

  7. 栈区数据被飞踩问题定位手段

    1.栈溢出或者栈数据被踩时,继续运行就会出现segmentation fault.可以尝试着接管SIGSEGV信号,在信号处理函数中保存一些出现异常时候的信息. 2.基于栈溢出场景,栈空间被破坏,也就 ...

  8. Jenkins 插件 地址证书报错问题解决思路

    问题提示摘要: SunCertPathBuilderException: unable to find valid certification path to requested target ... ...

  9. vue使用高德地图搜索地址添加标记marker,定位,拖拽选址功能

    目录 JSAPI 的加载 使用 JSAPI Loader (推荐) 实现效果: 需求:点击输入框弹窗地图弹窗,输入框输入地址模糊搜索列表结果,点击列表添加相应得marker标记,并且添加标记拖拽选址功 ...

最新文章

  1. Microsoft patterns practices Enterprise Library released
  2. 【OpenCV 4开发详解】轮廓发现与绘制
  3. pandas使用sort_values函数和groupby函数获取每个分组数值最小的前N行数据(n rows with smallest column value in each group)
  4. 开源!mathAI 手写拍照自动能解高数题,还不快试试?
  5. 以太坊是什么 - 以太坊开发入门指南
  6. 分区创建 linux_在 Intel NUC 上安装 Linux
  7. Web 开发中 20 个很有用的 CSS 库
  8. Android 如何使用juv-rtmp-client.jar向Red5服务器发布实时视频数据
  9. Java 并发编程 基础
  10. link 和 style 元素在 HTML 文档中的位置
  11. 如何格式化电脑_电脑硬盘不小心格式化如何恢复【恢复方法】
  12. java完全自学手册 pdf_fortran教程下载
  13. genymotion-安卓模拟器-IMEI修改方法
  14. Zemax 快捷键及使用技巧(持续更新中)
  15. 视频图像处理-01背景差分法
  16. Python最优化算法学习笔记(Gurobi)
  17. Python 利用 turtle画出樱花树
  18. 省市县地址联动插件distpicker 代码及示例
  19. Arduino ESP8266 使用LittleFS存储配置文件实践
  20. android-配置文件AndroidManifest.xml详解

热门文章

  1. 期末冲刺作文素材合集 | 奉献
  2. ds6k5b计算机联锁系统简介,ds6k5b计算机联锁系统维护手册.ppt
  3. Visual Studio相关电子资料、软件汇总:
  4. 戏谑五大互联网巨头“打工人”气质
  5. 被MD5加密坑了?雅虎大规模泄密是个咋样的悲剧
  6. 跳转到文字转语音设置界面
  7. scratch接苹果 电子学会图形化编程scratch等级考试三级真题和答案解析2021-3
  8. 【并发编程专题(一)】
  9. 长春治疗耳鸣专科医院哪些最好
  10. 耳鸣的治疗方法是什么