本篇从vpp 18.01应用开始着手,开始了解vpp框架的使用
要了解vpp框架,需要抓住几点了解vpp:
1. vpp命令行注册,命令行回调开关可打开对应node功能;
2. plugin,feature,function初始化,main函数初始化调用;
3. node注册,报文接收到后回调。
本篇实现一个node抓包功能,并打印出来,plugin编译加载,命令行配置后生效,disable后失效。
1. 注册命令行,plugin及function
#ifndef __included_ck_sample_h__
#define __included_ck_sample_h__
#include <vnet/vnet.h>
#include <vnet/ip/ip.h>
#include <vppinfra/hash.h>
#include <vppinfra/error.h>
#include <vppinfra/elog.h>
typedef struct {
/* API message ID base */
u16 msg_id_base;
/* convenience */
vnet_main_t * vnet_main;
} ck_sample_main_t;
extern ck_sample_main_t ck_sample_main;
extern vlib_node_registration_t ck_sample_node;
#define CK_SAMPLE_PLUGIN_BUILD_VER "1.0"
#endif /* __included_ck_sample_h__ */
#include <vnet/plugin/plugin.h>
#include <pktdump/pktdump.h>
/* vnet_main_t注册*/
ck_sample_main_t ck_sample_main;
/* 命令行开关*/
int ck_sample_enable_disable(u32 sw_if_index, int enable)
{
if (pool_is_free_index (ck_sample_main.vnet_main->interface_main.sw_interfaces,
sw_if_index))
return VNET_API_ERROR_INVALID_SW_IF_INDEX;
vnet_feature_enable_disable("ip4-unicast",
"ck_sample",
sw_if_index, enable, 0, 0);
return 0;
}
static clib_error_t*
ck_sample_enable_disable_command_fn(vlib_main_t* vm,
unformat_input_t *input,
vlib_cli_command_t *cmd)
{
u32 sw_if_index = ~0;
int enable_disable = 1;
while(unformat_check_input(input) != UNFORMAT_END_OF_INPUT) {
/* 命令行关闭*/
if (unformat(input, "disable"))
enable_disable = 0;
/* 接口索引获取*/
else if (unformat(input, "%U",
unformat_vnet_sw_interface,
ck_sample_main.vnet_main, &sw_if_index));
else
break;
}
if (sw_if_index == ~0)
return clib_error_return(0, "Please specify an interface...");
ck_sample_enable_disable(sw_if_index, enable_disable);
return 0;
}
/*命令行注册及函数回调*/
VLIB_CLI_COMMAND (ck_sample_command, static) = {
.path = "pkt dump",
.short_help =
"pkt dump <interface-name> [disable]",
.function = ck_sample_enable_disable_command_fn,
};
/*插件注册*/
VLIB_PLUGIN_REGISTER () = {
.version = CK_SAMPLE_PLUGIN_BUILD_VER,
.description = "Sample of VPP Plugin",
};
static clib_error_t *ck_sample_init(vlib_main_t* vm)
{
ck_sample_main.vnet_main = vnet_get_main();
return 0;
}
/* FUNCTION注册*/
VLIB_INIT_FUNCTION(ck_sample_init);
/*featrure注册*/
VNET_FEATURE_INIT(ck_sample, static) =
{
.arc_name = "ip4-unicast",
.node_name = "ck_sample",
.runs_before = VNET_FEATURES("ip4-lookup"),
};
2. 注册node节点
#include <vlib/vlib.h>
#include <vnet/vnet.h>
#include <vnet/pg/pg.h>
#include <vnet/ethernet/ethernet.h>
#include <vppinfra/error.h>
#include <pktdump/pktdump.h>
typedef enum
{
CK_SAMPLE_NEXT_IP4,
CK_SAMPLE_DROP,
CK_SAMPLE_NEXT_N,
} ck_sample_next_t;
typedef struct
{
u32 next_index;
u32 sw_if_index;
u8 new_src_mac[6];
u8 new_dst_mac[6];
} ck_sample_trace_t;
#define foreach_ck_sample_error \
_(SHOWED, "show packets processed")
typedef enum
{
#define _(sym,str) SAMPLE_ERROR_##sym,
foreach_ck_sample_error
#undef _
SAMPLE_N_ERROR,
} ck_ssample_error_t;
static char *ck_sample_error_strings[] = {
#define _(sym, str) str,
foreach_ck_sample_error
#undef _
};
extern vlib_node_registration_t ck_sample_node;
static u8 *
format_ck_sample_trace (u8 * s, va_list * args)
{
s = format(s, "To Do!\n");
return s;
}
/* node的function处理*/
static uword ck_sample_node_fn(vlib_main_t *vm, vlib_node_runtime_t *node,
vlib_frame_t * frame)
{
u32 n_left_from, *from, *to_next;
ck_sample_next_t next_index;
from = vlib_frame_vector_args(frame);
n_left_from = frame->n_vectors;
next_index = node->cached_next_index;
while(n_left_from > 0){
u32 n_left_to_next;
vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
while(n_left_from > 0 && n_left_to_next > 0){
vlib_buffer_t *b0;
u32 bi0, next0 = 0;
bi0 = to_next[0] = from[0];
from += 1;
to_next += 1;
n_left_to_next -= 1;
n_left_from -= 1;
b0 = vlib_get_buffer(vm, bi0);
void *en0 = vlib_buffer_get_current(b0);
int i = 0;
for (i = 0; i < 20 i++)
{
printf("%02x ", *(u8*)(en0+i));
}
printf("\n");
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);
}
return frame->n_vectors;
}
/* VLIB NODE注册*/
VLIB_REGISTER_NODE (ck_sample_node) = {
.name = "ck_sample",
.function = ck_sample_node_fn,
.vector_size = sizeof(u32),
.format_trace = format_ck_sample_trace,
.type = VLIB_NODE_TYPE_INTERNAL,
.n_errors = ARRAY_LEN(ck_sample_error_strings),
.error_strings = ck_sample_error_strings,
.n_next_nodes = CK_SAMPLE_NEXT_N,
.next_nodes = {
[CK_SAMPLE_NEXT_IP4] = "ip4-lookup",
[CK_SAMPLE_DROP] = "error-drop",
},
};