Cisco VPP插件开发

Cisco VPP插件开发,有需要的朋友可以参考一下。


还在初学阶段,如果有误,希望多批评指正。


在VPP中,插件可以在程序启动的时候加载,一般我们会往里面加入node,实现一些功能。


首先介绍怎么直接重定义硬件接口RX到我们的node


vnet_hw_interface_rx_redirect_to_node(vnet_main,hw_if_index, my_graph_node.index /* redirect to my_graph_node */);


这个接口主要是将指定的接口重定向到我们自己实现的node上。


具体的实现我们可以看sample-plugin,或者看以下简单的例子:


这是注册node的代码,里面主要是function、name和next_nodes


//注册node
VLIB_REGISTER_NODE(my_node) = {
    .function = my_node_fn, //node功能函数
    .name = "zzx-test", //node名字,唯一
    .vector_size = 4, 
    .format_trace = format_my_trace, //show trace显示
    .type = VLIB_NODE_TYPE_INTERNAL, //node类型
    .n_errors = ARRAY_LEN(my_error_strings),
    .error_strings = my_error_strings,
    .n_next_nodes = MY_N_NEXT,
    .next_nodes = {
        [MY_ETHERNET_INPUT] = "ethernet-input", //下一级node名字
    },
};node功能如下,这里是拿到数据包,执行功能,设置下一级的node三个主要功能static uint64_t my_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
{
uint32_t *from = vlib_frame_vector_args(frame);
uint32_t n_left_from = frame->n_vectors;
my_next_t next_index = node->cached_next_index;
uint32_t pkts_showed = 0;
while(n_left_from > 0) {
uint32_t *to_next;
uint32_t n_left_to_next;
vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
//n_left_from表示vector拿到多少个数据包
//n_left_to_next表示上次缓存的下一级node剩下的vector位置
//所以循环表示的是当前node还能拿到多少个包,下一级能接收多少包,以少的为准。有0的话就停止执行
while(n_left_from > 0 && n_left_to_next > 0) {
uint32_t next0 = MY_ETHERNET_INPUT;
uint32_t bi0 = from[0];
to_next[0] = bi0;
from += 1;
to_next += 1;
n_left_from -= 1;
n_left_to_next -= 1;
//拿到数据包
vlib_buffer_t *b0 = vlib_get_buffer(vm, bi0);
//当前node的主要功能是输出数据包内容到终端
void *en0 = vlib_buffer_get_current(b0);
show_packet(en0);
//将数据包入队给下一级node
pkts_showed += 1;
vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0);
}
vlib_put_next_frame(vm, node, next_index, n_left_to_next);
}
//增加计数器,主要是加在show err命令了,vpp本身的node也是加在那里了
vlib_node_increment_counter(vm, my_node.index, MY_ERROR_SHOW, pkts_showed);
return frame->n_vectors;
}
以上是node.c的基本展示。

下面介绍下插件注册时需要的一些函数


首先是注册初始化函数


//我们没有什么特别的功能,所以初始化没有做任何事情
static clib_error_t *my_init(vlib_main_t *vm)
{
return 0;
}
//此处是我们将初始化函数加载到vpp里面,以供程序运行的时候初始化
VLIB_INIT_FUNCTION(my_init);接下来是必备函数,vpp在加载插件会调用这个函数,传递给我们一些必须的数据//vm里面记录了我们需要的大部分东西,好多接口里面都会调用
//vnet_main是我们连接其他node或者网络相关的数据
//这里因为运行的比较早,DPDK硬件初始化还没开始。
//所以我们在连接硬件接口RX的时候,这里不能做,这里最好就是获取一些基本的数据
clib_error_t *vlib_plugin_register(vlib_main_t *vm, vnet_plugin_handoff_t *h,
int32_t from_early_init)
{
my_main_t *mm = &my_main;
mm->vlib_main = vm;
mm->vnet_main = h->vnet_main;
mm->ethernet_main = h->ethernet_main;
return NULL;
}因为如上说到硬件还没初始化,所以我们不能在这里直接去重定向硬件RX,但是其他地方也没有合适的接口被调用,所以我们考虑采用命令行去配置需要重定向的接口,命令行的支持如下://命令行注册,path表示的是命令,function是执行函数
VLIB_CLI_COMMAND(show_packet_command, static) = {
.path = "show packet",
.short_help = "show packet [disable]",
.function = my_command_enable_disable_fn,
};未完待续。。。

资料来源:https://fd.io/

猜你喜欢

转载自blog.csdn.net/zqt520/article/details/60154465