目录
通过VPP自带的例子和网上一些例子的参考,写了一个最简单的插件练习,插件功能:把hook到的包打印一下IP头。
注册插件
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;
}
VLIB_INIT_FUNCTION(ck_sample_init);
注册node
//node初始化信息,生成一堆该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",
},
};
//将node注册在ip4-unicat的arc中,指定ip-lookup之前Hook到数据包
VNET_FEATURE_INIT(ck_sample, static) =
{
.arc_name = "ip4-unicast",
.node_name = "ck_sample",
.runs_before = VNET_FEATURES("ip4-lookup"),
};
Node处理packet主函数
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);
//获取到IP header
void *en0 = vlib_buffer_get_current(b0);
int i = 0;
//打印前20 bytes, 即ip header
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;
}
注册开关CLI
指定interface的开关
VLIB_CLI_COMMAND (ck_sample_command, static) = {
.path = "ck sample",
.short_help =
"ck sample <interface-name> [disable]",
.function = ck_sample_enable_disable_command_fn,
};
开关实现
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;
//打开or关闭该sw_if_index接口到ck_sample node的开关
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", //通过interface找到sw_if_index
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;
}
文件位置
[ckun@localhost plugins]$ ll ck_sample/
total 16
-rwxrw-r-- 1 ckun ckun 2037 Dec 6 11:04 ck_sample.c
-rwxr--r-- 1 ckun ckun 519 Dec 5 17:16 ck_sample.h
-rwxrw-r-- 1 ckun ckun 2970 Dec 5 10:45 ck_sample_node.c
-rwxrw-r-- 1 ckun ckun 147 Dec 5 10:48 CMakeLists.txt
[ckun@localhost plugins]$ pwd
/home/ckun/vpp/src/plugins
运行测试
编译make wipe, make build, make run
DBGvpp# show int address
GigabitEthernet1/0/0 (dn):
GigabitEthernet1/0/1 (up):
L3 66.6.6.6/24
local0 (dn):
DBGvpp#
DBGvpp# ck sample GigabitEthernet1/0/1 //打开开关
从另一台linux机器(66.6.6.1) ping过来
[ckun@localhost ~]$ ping 66.6.6.6
PING 66.6.6.6 (66.6.6.6) 56(84) bytes of data.
64 bytes from 66.6.6.6: icmp_seq=1 ttl=64 time=1.47 ms
64 bytes from 66.6.6.6: icmp_seq=2 ttl=64 time=0.675 ms
64 bytes from 66.6.6.6: icmp_seq=3 ttl=64 time=0.900 ms
64 bytes from 66.6.6.6: icmp_seq=4 ttl=64 time=1.18 ms
64 bytes from 66.6.6.6: icmp_seq=5 ttl=64 time=0.858 ms
64 bytes from 66.6.6.6: icmp_seq=6 ttl=64 time=0.590 ms
64 bytes from 66.6.6.6: icmp_seq=7 ttl=64 time=1.00 ms
命令行输出
DBGvpp# 45 00 00 54 61 8f 40 00 40 01 49 07 42 06 06 01 42 06 06 06
45 00 00 54 65 51 40 00 40 01 45 45 42 06 06 01 42 06 06 06
45 00 00 54 65 91 40 00 40 01 45 05 42 06 06 01 42 06 06 06
45 00 00 54 67 d3 40 00 40 01 42 c3 42 06 06 01 42 06 06 06
45 00 00 54 69 80 40 00 40 01 41 16 42 06 06 01 42 06 06 06
45 00 00 54 6b 22 40 00 40 01 3f 74 42 06 06 01 42 06 06 06
45 00 00 54 6c 5d 40 00 40 01 3e 39 42 06 06 01 42 06 06 06
这些Ping包已成功被该插件的Node给获取到。
源码在此
https://download.csdn.net/download/jacicson1987/10832046
总结分析
照葫芦画瓢都比较简单,但是深入理解却却是不易。
几个概念mark一下,将在后续学习中逐渐理解
1. feature arc 是怎么分组的, 各个node和不同arc的关系是什么?
2. 数据包node之间的流程是怎样,包是基于怎样的数据结构在node之间传输
3. 如果要多线程处理该怎么做