简介
vpp官方文档中有buffer mdata相关介绍,公众号也进行了简单的翻译:vpp Buffer Metadata,本文主要介绍一下源码中mdata插件的使用(主要用来跟踪buffer mdata的变化)。代码比较简单,但是实现框架值得我们来详细了解一下。
官方链接:https://fd.io/docs/vpp/master/gettingstarted/developers/metadata.html 。 最近在vpp交流群中有群友遇到buffer重复释放的问题,我觉得也可以借助此框架来检测buffer使用不当问题,应该可以确认到那个node节点的故障。曾经遇到过一次dpdk mbuf ring队列地址被踩的问题,思路和这个框架差不多。https://blog.csdn.net/sjin_1314/article/details/106090582?spm=1001.2014.3001.5501
1、开启/关闭buffer mdata tracking
buffer metadata tracking [on][off]
2、查询buffer mdata的变化 buffer mdata 主要是跟踪当前节点在调用node->function函数前后vlib_buffer_t结构中前128字节的中数据是否存在变化。
learning_vpp# show buffer metadata
ip4-icmp-echo-request: flags
vnet_buffer_t: sw_if_index[0] #表示当前节点src接口发生了变化。
vnet_buffer2_t: no changes
arp-reply: current_data current_length current_config_index punt_reason
vnet_buffer_t: sw_if_index[1]
vnet_buffer2_t: no changes
arp-input: current_config_index punt_reason
vnet_buffer_t: feature_arc_index
vnet_buffer2_t: no changes
ip4-glean: error
vnet_buffer_t: no changes
vnet_buffer2_t: no changes
ip6-input: current_config_index punt_reason
vnet_buffer_t: feature_arc_index ip.adj_index[0] l2.feature_bitmap map.mtu map_t.map_domain_index cop.current_config_index lisp.overlay_afi tcp.connection_index snat.flags
vnet_buffer2_t: no changes
vpp底层基础库文件callback_data.h中提供callback函数初始化、添加、删除、查询等一系列的操作函数。 下面以buffer mdata使能为例介绍。
#1、使用clib_callback_data_typedef来定义callback集合的结构体
clib_callback_data_typedef (vlib_node_runtime_perf_callback_set_t,
vlib_node_runtime_perf_callback_data_t);
#2、perf callbacks定义在viib_main_t结构中
typedef struct vlib_main_t
{
vlib_node_runtime_perf_callback_set_t vlib_node_runtime_perf_callbacks;
}
3、声明callback 回调函数
typedef void (*vlib_node_runtime_perf_callback_fp_t)
(struct vlib_node_runtime_perf_callback_data_t * data,
vlib_node_runtime_perf_callback_args_t * args);
vlib_node_runtime_perf_callbacks 变量定义在vlib_main_t结构中,说明每个worker核都存储一份了,在使能的时候,需要每个worker线程都需要使能。
相关结构体之间关系如下图所示:
callback函数应该是提供了一种线程安全接口,在vlib_node_runtime_perf_callback_set_t 结构体中有三个指针 curr、(volatile) next,spare 及互斥锁来实现线程安全接口。不过当前buffer mdata本身就是线程安全的。
int
mdata_enable_disable (mdata_main_t * mmp, int enable_disable)
{
int rv = 0;
vlib_thread_main_t *thread_main = vlib_get_thread_main ();
int i;
/*多核模式下需要申请modify_lock互斥锁资源*/
if (mmp->modify_lock == 0 && thread_main->n_vlib_mains > 1)
{
clib_spinlock_init (&mmp->modify_lock);
}
/*首次时,需要申请资源*/
if (vec_len (mmp->before_per_thread) == 0)
{
mdata_none.node_index = ~0;
vec_validate (mmp->before_per_thread, vlib_get_n_threads () - 1);
}
/*重置节点函数*/
vec_reset_length (mmp->modifies);
/*每个线程都需要使能mdata trace callback函数*/
for (i = 0; i < vlib_get_n_threads (); i++)
{
vlib_main_t *ovm = vlib_get_main_by_index (i);
if (ovm == 0)
continue;
clib_callback_data_enable_disable (
&ovm->vlib_node_runtime_perf_callbacks, mdata_trace_callback,
enable_disable);
}
return rv;
}
以dispatch_node vpp调度函数为例,介绍perf callback执行框架,大概逻辑就是三步: 1、执行node节点函数前,保存buffer mdata元数据 2、执行node函数处理 3、执行node函数处理后,对比前后buffer mdata元数据的变化。
static_always_inline u64
dispatch_node (xxxxx)
{
/*1.执行调度前,保存buffer mdata元数据*/
vlib_node_runtime_perf_counter (vm, node, frame, 0, last_time_stamp,
VLIB_NODE_RUNTIME_PERF_BEFORE);
/*2、node 函数处理*/
n = node->function (vm, node, frame);
/*3、执行函数处理后,执行buffer mdata元数据对比,是否存在变化*/
vlib_node_runtime_perf_counter (vm, node, frame, n, t,
VLIB_NODE_RUNTIME_PERF_AFTER);
}
个人觉得可以利用此框架实现一些check动作,比如在开头说明dpdk mbuf ring队列地址被踩的问题时,就是在node-》function函数前后检查ring队列中mbuf地址是否存在异常。
mdata功能一共就三个文件api,.c,.h文件,功能相对比较简单。这里就不介绍了,感兴趣的自己阅读一下代码。下面主要说一下结构体:
说明: before_per_thread[thread_index][vec_header]:二级指针,一级以线程id,二级是vector结构头指针。用来保存node节点在调用node函数前存储buffer mdata元数据。 modifies[node_index]:记录元数据变化,0:表示没有变化,1:表示有变化。
本文简单的介绍一下vpp mdata插件的功能及perf callback的框架,个人觉得此框架还是能做很多东西的,比如存储报文经过那些node节点以及buffer泄露检查动作,可以做成动态使能。
本文分享自 DPDK VPP源码分析 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!