前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >VPP feature arc机制

VPP feature arc机制

作者头像
dpdk-vpp源码解读
发布2023-03-07 17:23:57
1.8K0
发布2023-03-07 17:23:57
举报
文章被收录于专栏:DPDK VPP源码分析DPDK VPP源码分析

最近项目中需要增加一个feature arc类用于挂接在自定义的收包节点上,完成类似ip4-output feature arc功能。但是每次使能后都会出现异常,最后发现是feature arc类结束节点没有进行初始化导致问题。下来我们就来研究一下vpp的feature机制。

简介

VPP内部业务逻辑是通过一系列的node连接来实现的,这些node通常在初始化时就已经定义,比如二层以太处理ethernet-input,三层ip4-input等,通过初始化定义,将node连接成一个有序的向量图,来实现VPP的业务功能,如下图所示:

而早期的VPP本身的node框架比较固定,各个node之间逻辑连接已经固定了。为此新版本增加了feature机制,每个feature是一个node,用户可以启用/停止某个或某些feature。用户也可以自己写插件,把自定义node(自己的业务逻辑)加入到指定位置。 VPP中,将不同的feature按照类型分成了不同的组,每组feature称之为一个arc。arc中的feature按照代码指定的顺序串接起来。arc结构中,记录这组feature中的起始node和结束node。系统初始化时,会完成初步的排序,但并没有应用到对应的接口中。

feature arc及feature注册

下面以ip4-unicast为例来介绍基本的流程:

代码位置:vnet\ipIp4_forward.c feature arc及feature的main函数启动前的注册宏

1、feature arc注册

VNET_FEATURE_ARC_INIT将注册feature arc,主要初始化feature类的名称、起始及结束node名字及记录arc索引的指针地址。会 以链表形式挂接到全局变量extern vnet_feature_main_t feature_main 的next_arc上。

代码语言:javascript
复制
/* Built-in ip4 unicast rx feature path definition */
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,
};
2、feature注册

VNET_FEATURE_INIT完成feature的注册,主要初始化arc名称,node节点名称,及运行当前feature node的前面或后面的feature node。

代码语言:javascript
复制
VNET_FEATURE_INIT (ip4_policer_classify, static) =
{
  .arc_name = "ip4-unicast",
  .node_name = "ip4-policer-classify",
  .runs_before = VNET_FEATURES ("ipsec4-input-feature"),
};
VNET_FEATURE_INIT (ip4_lookup, static) =
{
  .arc_name = "ip4-unicast",
  .node_name = "ip4-lookup",
  .runs_before = 0,    /* not before any other features */
};

需要注意是feature的顺序是初始化的时候已经固定固定好的。 ip4-unicast以ip4-lookup结束,虽然在feature arc 初始化时已经指定,但是在feature 初始化时必须设置一下,否则会引起转发异常(debug版本直接coredump,release版本可能转发节点异常)。

feature初始化及使能

1、feature初始化 feature初始化流程必须是在node节点注册的后面,是由VLIB_INIT_FUNCTION (vnet_feature_init)宏注册到初始化函数中,在mian loop前被调用。主要是完成feature相关资源的申请及初始化,遍历vnet_feature_main_t feature_main链表生成feature arc及生成feature资源顺序关系图。

2、以ip4-unicast为例,vnet_feature_arc_init函数实现流程。

代码语言:javascript
复制
typedef struct
  /** feature arc configuration list 
   *main函数启动前VNET_FEATURE_ARC_INIT宏中注册的feature arc 链表形式保存下来*/
  vnet_feature_arc_registration_t *next_arc;
  /*创建<key:arc_name, vlaue:feature_arc指针及在next_arc链表中的节点地址>的hash表*/
  uword **arc_index_by_name;

  /** feature path configuration lists 
   *main函数启动前 VNET_FEATURE_INIT宏将feature注册到这个链表中*/
  vnet_feature_registration_t *next_feature;
  /*next_feature_by_arc[arc_index] 将同一类的feature以链表形式串到一起*/
  vnet_feature_registration_t **next_feature_by_arc;
  /*vector结构:二维,一维是feature arc的索引,二维是hash头
   next_feature_by_name[arc_index] :  <key:feature结构中node 名称;
   value:  vnet_feature_registration_t 的指针。 */
  uword **next_feature_by_name;

  /** feature arc类对应一个 vnet_feature_config_main_t。
   *feature_config_mains[arc_index]:保存feature类的配置属性*/
  vnet_feature_config_main_t *feature_config_mains;

  /** Save partial order results for show command 
   *feature_nodes[x], X:feature arc 的索引
    保存feature 节点,保存节点node的名称,顺序存储*/
  char ***feature_nodes;

  /** bitmap of interfaces which have driver rx features configured */
  uword **sw_if_index_has_features;

  /** feature reference counts by interface 
  *feature_count_by_sw_if_index[arc_index][sw_if_index]:下面feature的计数*/
  i16 **feature_count_by_sw_if_index;

  /** Feature arc index for device-input */
  u8 device_input_feature_arc_index;

  /** convenience */
  vlib_main_t *vlib_main;
  vnet_main_t *vnet_main;
} vnet_feature_main_t;

关键结构体如下:

1、vnet_feature_config_main_t 该结构是所有feature相关的配置主结构体,每个arc有一个对应的该结构体。在为接口开启feature时,会创建对应的接口体,并按照接口索引设置config_index_by_sw_if_index这个vec向量,保存配置的索引。 2、vnet_config_main_t feature配置主结构体,其中config_pool是配置结构的内存池,不同的接口如果设置了不同的feature就会申请不同的vnet_config_t。vnet_feature_init启动中完成对feature的排序、feature和node节点索引之间的关系。 3、vnet_config_t feature的配置结构体,里面保存了多个feature,当接口使能一个feature时,会在对应的feature中增加多个vnet_config_feature_t。该结构体中还在config_string中保存了feature之间的node关系。 4、vnet_config_feature_t config中的具体的feature,当为接口配置feature时,将会为该配置最终生成此转发数据结构,用于生成转发顺序图

3、使能去使能流程feature

代码语言:javascript
复制
#dhcp报文探测报文处理节点去使能
  vnet_feature_enable_disable ("ip4-unicast",
                   "ip4-dhcp-client-detect",
                   c->sw_if_index, 0 /* disable */ , 0, 0);

feature使能去使能函数处理逻辑如下:

4、最终生成转发节点获取next0结构图

结构体vnet_feature_config_main_t中变量config_index_by_sw_if_index是vector结构,通过接口索引获取config_index(也就是在config_string_heap堆的偏移量)。

下面函数就是在转发获取next0,实际上就是从config_String中获取。

代码语言:javascript
复制
always_inline void *
vnet_get_config_data (vnet_config_main_t * cm,
              u32 * config_index, u32 * next_index, u32 n_data_bytes)
{
  u32 i, n, *d;
  /*获取当前config索引*/
  i = *config_index;

  d = heap_elt_at_index (cm->config_string_heap, i);  /*字节对齐操作*/

  n = round_pow2 (n_data_bytes, sizeof (d[0])) / sizeof (d[0]);

  /* Last 32 bits are next index. */
  *next_index = d[n];

  /* Advance config index to next config. 更新到下一个node节点对应的config索引*/
  *config_index = (i + n + 1);

  /* Return config data to user for this feature. 返回当前节点配置数据起始指针*/
  return (void *) d;
}

相关命令行

1、show feature [verbose]

可以查询arc的索引及当前arc类型所有feature的排序顺序

代码语言:javascript
复制
show features verbose
[] ip4-unicast:  #ipv4单播 arc索引是16
  []: ip4-rx-urpf-loose
  []: ip4-rx-urpf-strict
  []: svs-ip4
 ....
  []: ip4-vxlan-bypass
  []: ip4-lookup  #ip4-lookup目前在最后,

这里只是ip4-unicast单播的feature挂接顺序,如果未使能的话,并不会挂接在ip4-input的下面。vpp是动态挂feature的。

2、show node ip4-input

查询当前node节点下feature的信息,node类型、node的状态及索引等。

代码语言:javascript
复制
vpp# show node ip4-input
#node 类型,状态 及索引
node ip4-input, type internal, state active, index 567
  node function variants:
    Name             Priority  Active
    default                 0        
    icl                    -1        
    skx                    -1        
    hsw                    50    yes 

  next nodes:#当前node已经挂接的孩子node节点情况:
    next-index  node-index               Node               Vectors
         0          649               error-drop                  
                                  error-punt                  
                                  ip4-options                 
                                  ip4-lookup                  
                            ip4-mfib-forward-lookup           
                                ip4-icmp-error                
                              ip4-full-reassembly             
                                ip4-not-enabled               
  known previous nodes:#当前节点的父节点
    vmxnet3-input ()                  rdma-input ()                    pppoe-input ()  

这里也可以通过show vlib graph ip4-input来查询node 图。

3、 show interface feat

查询指定接口下所有arc的使能情况:

代码语言:javascript
复制
show interface feat GigabitEthernet13//
ip4-unicast:
  ip4-sv-reassembly-feature
  nat44-in2out

上面是接口使能nat44功能,会同时使能ip报文重组功能,用于解决分片报文nat五元组查询问题。

4、set interface feature
代码语言:javascript
复制
#指定接口使能某arc类下feature功能。
set interface feature <intfc> <feature_name> arc <arc_name> [disable]

注意,arc类下必须已经注册当前feature,否则会失败。

定义自己的feature arc

1、自定义arc类及自定义业务feature。
代码语言:javascript
复制
#1、注册arc类internal_rx_output_v4
VNET_FEATURE_ARC_INIT (internal_rx_output_v4, static) =
{
    .arc_name = "internal_rx_output_v4",
    .start_nodes = VNET_FEATURES ("internal-rx"),
    .last_in_arc = "interface-output",
    .arc_index_ptr = &internal_main.outputv4_feature_arc_index,
};
#2、注册arc类最后一个节点 ,这个必须设置。
VNET_FEATURE_INIT (internal_rx_ip4_interface_output, static) =
{
    .arc_name = "internal_rx_output_v4",
    .node_name = "interface-output",   
    .runs_before = ,    /* not before any other features */
};
#3、将自己新增ip4_test_output的node节点挂接到arc类中
VNET_FEATURE_INIT (ip4_test_output, static) = {
    .arc_name = "internal_rx_output_v4",
    .node_name = "ip4_test_output",
    .runs_before = VNET_FEATURES ("interface-output"),
};
2、新增node节点internal-rx-input作为feature arc的起始node

在internat-rx-input节点增加自己的业务处理逻辑,然后判断接口是否使能feature,如果使能调用函数vnet_feature_arc_start设置vlib_buffer_t结构中feature_arc_index及当前current_config_index索引。

代码语言:javascript
复制
u32 arc_index = internal_main.outputv4_feature_arc_index;
if (vnet_have_features (arc_index, sw_if_index))
{
     /**/
     vnet_feature_arc_start (arc_index, sw_if_index, &next, b);
}
else
{
   next = interface_output_index;
}
3、arc中中间node节点获取next

调用函数vnet_feature_next从config_string中读取当前node的子节点的slot num 赋值next0,报文最终送到子节点处理。

代码语言:javascript
复制
vnet_feature_next (u32 * next0, vlib_buffer_t * b0)

总结

本文简单描述了vpp的feature机制的注册、初始化及函数调用,并介绍了如何注册

和使用自己的feature arc类。通过VPP的feature机制,可以在不改变VPP现有框架

下,灵活地增加/删除业务功能。

巨人的肩膀

1、vpp feature机制介绍 https://www.sdnlab.com/24055.html 2、vppfeature arc说明 https://www.yuque.com/taohuaban/fc6dp0/ix0fkg

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-03-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DPDK VPP源码分析 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
  • feature arc及feature注册
    • 1、feature arc注册
      • 2、feature注册
      • feature初始化及使能
      • 相关命令行
        • 1、show feature [verbose]
          • 2、show node ip4-input
            • 3、 show interface feat
              • 4、set interface feature
              • 定义自己的feature arc
                • 1、自定义arc类及自定义业务feature。
                  • 2、新增node节点internal-rx-input作为feature arc的起始node
                    • 3、arc中中间node节点获取next
                    • 总结
                    • 巨人的肩膀
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档