前面我们简单了解了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泄露问题的思路,当然具体问题还需要具体分析。通过一些手段来缩小排查范围。如果大家由更好的思路或者方法,欢迎交流。