写一个简单的VPP插件

目录

注册插件

注册node

Node处理packet主函数

注册开关CLI

文件位置

运行测试

源码在此

总结分析


通过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. 如果要多线程处理该怎么做

 

  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值