Author basilguo@163.com
Date Aug. 09, 2023
Description VPP Feature Arcs.
1. 环境
在介绍VPP的Feature Arcs之前,需要简要介绍下VLIB。如果有不当之处,还请参考官网VLIB文档。
1.1. 版本
$ sudo vppctl # 或者make run
DBGvpp# show version
vpp v23.06-release built by XXX on XXX at 2023-08-02T07:37:51
$ lsb_release -r
Release: 20.04
2. VLIB (Vector Processing Library)
VLIB源码文件位于:${VPP_HOME}/src/{vlib, vlibapi, vlibmemory}
目录。提供向量处理支持,例如图节点调度、可靠性多播、多任务线程轻量级协作,CLI,.dll支持,物理内存和Linux epoll支持。
VPP VLIB提供的处理数据包的方式是构造无环有向图处理方式。所以添加新的feature,就是向图中添加新的node节点,合理的选择节点的添加位置,就能实现想要的功能。
一个路由器或者交换机具备很多L2-L4层的功能,这也是VPP能通过graph nodes提供的。不过已有的nodes可能无法提供你需要的功能,这时候就需要添加新的feature了。
feature arc并没有严格的定义,它就是现有VPP图的一个子图,包含了你需要的节点nodes。由于是有向图,所以就需要定义从哪里开始,到哪里结束。一般这些严格的首尾节点都是定义好了的,例如device-input、interface-output以及error-drop,从名字也能看出来些端倪。
所以实际上添加新的feature arc,就变成了如何确定添加到的位置,以及如何添加。如何添加的问题,其实就是写一个新的Plugin,可以参考VPP 插件分析与开发 ,其中需要:
- 注册插件
- 入口init函数
- 节点注册以及feature挂载位置
- CLI命令行注册(可选,默认开启情况下)
- 在配置文件中的配置(可选,可以参考hicn)
在创建了插件之后,node.c中插件注册了一个node,指定该node名称以及后续node。
VLIB_REGISTER_NODE (sample_node) =
{
.name = "sample",
.vector_size = sizeof (u32),
.format_trace = format_sample_trace,
.type = VLIB_NODE_TYPE_INTERNAL,
.n_errors = ARRAY_LEN(sample_error_strings),
.error_strings = sample_error_strings,
.n_next_nodes = SAMPLE_N_NEXT, // enum中最后一个,表示的该节点后续节点候选项个数
/* edit / add dispositions here */
.next_nodes = { // 后续节点候选项
[SAMPLE_NEXT_INTERFACE_OUTPUT] = "interface-output",
},
};
node.c还指定了该node要处理函数的逻辑,有两种方式来指定,一种是在注册node的时候使用.function = function_name
,一种是使用宏VLIB_NODE_FN (sample_node)
,其中参数sample_node
和VLIB_REGISTER_NODE
宏中参数对应即可。
3. VPP Fearture Arcs
VPP的Feature就是有序的图节点集合(子有向图嘛)。分为两种,一种是需要接口使能,一种是系统使能。就是是否指定使能接口的区别。
Feature arcs中的node是独立的,没有耦合性的,相互之间不知道彼此存在,需要coder去做“next feature node”的指定。
3.1. 添加新的feature arc
VNET_FEATURE_ARC_INIT (ip4_unicast, static) =
{
.arc_name = "ip4-unicast",
.start_nodes = VNET_FEATURES ("ip4-input", "ip4-input-no-checksum"),
.last_in_arc = "ip4-lookup",
.arc_index_ptr = &ip4_main.lookup_main.ucast_feature_arc_index,
};
这里只是个例子,ip4-unicast
已经存在于VPP中了,初始化的内容包括arc名称、起始结束node名字以及arc_index指针。会以链表形式挂接到全局变量extern vnet_feature_main_t feature_main 的next_arc
上。
通过show feature verbose
可以查看该feature arc以及内部的feature。如果需要添加自己的arc,倒是可以查看一下源代码如何添加feature arc。
DBGvpp# show features verbose
...
[15] ip4-unicast:
[ 0]: ip4-rx-urpf-loose
[ 1]: ip4-rx-urpf-strict
[ 2]: svs-ip4
[ 3]: srv6-t-m-gtp4-dt
[ 4]: srv6-t-m-gtp4-d
[ 5]: srv6-as4-rewrite
[ 6]: srv6-ad4-flow-rewrite
[ 7]: srv6-ad4-rewrite
[ 8]: snort-enq
[ 9]: ip4-sv-reassembly-feature
[10]: pnat-input
[11]: plugin_sample
...
3.2. 添加新的feature
VNET_FEATURE_INIT (mactime, static) =
{
.arc_name = "ip4-input", // arc的名称,挂载位置
.node_name = "plugin_sample",
.runs_before = VNET_FEATURES ("ip4-lookup"),
};
主要完成feature挂载的arc名称,node节点名称,以及运行当前feature的之前或者之后的node节点。可以通过show features verbose
查看挂载位置。还可以查看该节点的一些信息。
DBGvpp# show node plugin_sample
node plugin_sample, type internal, state active, index 77
node function variants:
default only
next nodes:
next-index node-index Node Vectors
0 643 ip4-lookup 0
1 698 error-drop 0
known previous nodes:
none
当然在VNET_FEATURE_INIT
的时候,还可以指定.runs_after
,这样也就能确定previous nodes了。不过我这里就不修改不演示了。
3.3. 启用/关闭feature
vnet_feature_enable_disable ("device-input", /* arc name */
"plugin_sample", /* feature name */
sw_if_index, /* Interface sw_if_index */
enable_disable, /* 1 => enable */
0 /* (void *) feature_configuration */,
0 /* feature_configuration_nbytes */);
sw_if_index = 0,那么就会作为系统使能的方式启用、关闭。