vpp buffer 泄露问题定位思路

2023-03-07 17:14:55 浏览数 (1)

前面我们简单了解了buffer相关初始化及内存分布情况,这篇文章来讲一下我目前遇到过buffer相关的一些问题及定位手段。没有阅读过前面2节内容的,需要先熟悉一下,链接如下:

vlib ----buffer pool 内存初始化(1)

vlib ----buffer pool 内存初始化(2)

buffer泄露问题确认:

我们可以通过下面的命令行来查询buffer使用情况:

代码语言:javascript复制
DBGvpp# show buffers
Pool Name            Index NUMA  Size  Data Size  Total  Avail  Cached   Used
default-numa-0         0     0   2496     2048   430185 424425    919    4841

当Used使用数量持续增加而不减少时,可能就存在buffer泄露了。

在vpp老的版本中可能需要查询dpdk buffer情况(老版本buffer还是由dpdk来申请)

代码语言:javascript复制
DBGvpp# show dpdk buffer
name="vpp pool 0"  available =     694 allocated =  429491 total =  430185

注意:在新版本中上面命令行是无效的。

buffer泄露问题如何定位:

其实vpp源码中提供了一种方法,就是跟踪报文所走的node节点。默认是关闭的,需要自己打开。 宏定义在文件srcvlibbuffer.h中。

代码语言:javascript复制
#define VLIB_BUFFER_TRACE_TRAJECTORY 0
#if VLIB_BUFFER_TRACE_TRAJECTORY > 0
extern void (*vlib_buffer_trace_trajectory_cb) (vlib_buffer_t * b, u32 index);
extern void (*vlib_buffer_trace_trajectory_init_cb) (vlib_buffer_t * b);
extern void vlib_buffer_trace_trajectory_init (vlib_buffer_t * b);
#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b) 
  vlib_buffer_trace_trajectory_init (b);
#else
#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b)
#endif /* VLIB_BUFFER_TRACE_TRAJECTORY */

node节点的信息存储在私有字段2中,指针:trajectory_trace,文件srcvnetbuffer.h

代码语言:javascript复制
typedef struct
{
  .......
  union
  {
    struct
    {
#if VLIB_BUFFER_TRACE_TRAJECTORY > 0
      /* buffer trajectory tracing */
      u16 *trajectory_trace;
#endif
    };
 ..........
  };
} vnet_buffer_opaque2_t;

在代码中没有找到能打印trajectory_trace的地方,可能只能借助gdb了吧。 但是使用中可能存在问题,我们可以看一下vlib_buffer_copy函数中是一段代码如下:

代码语言:javascript复制
clib_memcpy_fast (d->opaque2, s->opaque2, sizeof (s->opaque2));

默认情况下是是一个buffer对应一个trajectory_trace内存,在copy或者clone函数都是直接复制的,就会导致转发过程中判断异常。目前没有找到好的方法修改,我们借鉴其的方法利用buffer结构中pre-data字段来存储node索引。下面是我修改后的patch文件。

代码语言:javascript复制
diff --git a/src/vlib/buffer.h b/src/vlib/buffer.h
index 42e3cdf98..472d3c27f 100755
--- a/src/vlib/buffer.h
    b/src/vlib/buffer.h
@@ -487,6  487,8 @@ extern void (*vlib_buffer_trace_trajectory_init_cb) (vlib_buffer_t * b);
 extern void vlib_buffer_trace_trajectory_init (vlib_buffer_t * b);
 #define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b) 
   vlib_buffer_trace_trajectory_init (b);
 #elif CLIB_DEBUG > 0
 #define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b) ((b)->pre_data[0] = 0)
 #else
 #define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b)
 #endif /* VLIB_BUFFER_TRACE_TRAJECTORY */
diff --git a/src/vlib/main.c b/src/vlib/main.c
old mode 100644
new mode 100755
index 90ce53de5..c6e738eaf
--- a/src/vlib/main.c
    b/src/vlib/main.c
@@ -1198,6  1198,26 @@ dispatch_node (vlib_main_t * vm,
        dispatch_pcap_trace (vm, node, frame);
       n = node->function (vm, node, frame);
     }
   #if CLIB_DEBUG > 0
   else if ((CLIB_DEBUG > 0) &&  frame)
   {
         int i;
         u32 *from;
         from = vlib_frame_vector_args (frame);
         for (i = 0; i < frame->n_vectors; i  )
         {
             vlib_buffer_t *b = vlib_get_buffer (vm, from[i]);
             b->pre_data[0]  ;
             if (b->pre_data[0] < 32)
             {
                 b->pre_data[b->pre_data[0]] = (u8)node->node_index;
             }
         }
         if (PREDICT_FALSE (vm->dispatch_pcap_enable))
             dispatch_pcap_trace (vm, node, frame);
         n = node->function (vm, node, frame);
   }
   #endif
   else
     {
       if (PREDICT_FALSE (vm->dispatch_pcap_enable))

如果存在buffer泄露,我们可以大致根据在buffer池中找到buffer索引,多查询几个索引的node路径,能大致确认是那个接口处理存在的问题。再去详细阅读代码。

总结:

本文只是详细介绍了定位buffer泄露问题的思路,当然具体问题还需要具体分析。通过一些手段来缩小排查范围。如果大家由更好的思路或者方法,欢迎交流。

0 人点赞