• VPP ARC和feature初始化


    遍历feature_main主结构的next_arc单向链表,按照顺序为每个ARC注册结构分配索引(feature_arc_index),如果注册ARC的时候为成员arc_index_ptr附了值,将ARC索引写入此值。

    将arc_name作为key,areg注册结构为value,写入arc_index_by_name的哈希中,方便之后查找。计算ARC中开始节点的数量,递增ARC索引,遍历下一个ARC注册结构。

    vnet_feature_init (vlib_main_t * vm)
    {
      vnet_feature_main_t *fm = &feature_main;
      vnet_feature_registration_t *freg;
      vnet_feature_arc_registration_t *areg;
      vnet_feature_constraint_registration_t *creg;
      u32 arc_index = 0;
    
      fm->arc_index_by_name = hash_create_string (0, sizeof (uword));
      areg = fm->next_arc;
      while (areg) {
          char *s;
          int i = 0;
          areg->feature_arc_index = arc_index;
          if (areg->arc_index_ptr)
            *areg->arc_index_ptr = arc_index;
          hash_set_mem (fm->arc_index_by_name, areg->arc_name, pointer_to_uword (areg));
    
          while ((s = areg->start_nodes[i]))
            i++;
          areg->n_start_nodes = i;
          areg = areg->next;
          arc_index++;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    按照最大的ARC索引值,分配以下的向量。

      vec_validate (fm->next_feature_by_arc, arc_index - 1);
      vec_validate (fm->feature_nodes, arc_index - 1);
      vec_validate (fm->feature_config_mains, arc_index - 1);
      vec_validate (fm->next_feature_by_name, arc_index - 1);
      vec_validate (fm->sw_if_index_has_features, arc_index - 1);
      vec_validate (fm->feature_count_by_sw_if_index, arc_index - 1);
      vec_validate (fm->next_constraint_by_arc, arc_index - 1);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    遍历全局features单向链表next_feature,根据feature中的ARC名称,在哈希arc_index_by_name中找到ARC注册结构,进而找到ARC的feature链表头next_feature_by_arc[arc_index],为索引arc_index的ARC创建feature链表。

    遍历结束之后,为每个ARC创建了feature链表next_feature_by_arc[arc_index]。

      freg = fm->next_feature;
      while (freg) {
          vnet_feature_registration_t *next;
          uword *p = hash_get_mem (fm->arc_index_by_name, freg->arc_name);
          if (p == 0) {
            clib_warning ("Unknown feature arc '%s'", freg->arc_name);
            os_exit (1);
          }
          areg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
          arc_index = areg->feature_arc_index;
    
          next = freg->next;
          freg->next_in_arc = fm->next_feature_by_arc[arc_index];
          fm->next_feature_by_arc[arc_index] = freg;
    
          freg = next;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    遍历全局的next_constraint链表,最终为每个ARC创建单独的constraint链表,链表头部为next_constraint_by_arc[arc_index],最后添加的位于链表的头部。

      /* Move bulk constraints to the constraint by arc lists */
      creg = fm->next_constraint;
      while (creg) {
          vnet_feature_constraint_registration_t *next;
          uword *p = hash_get_mem (fm->arc_index_by_name, creg->arc_name);
          if (p == 0) {
            clib_warning ("Unknown feature arc '%s'", creg->arc_name);
            os_exit (1);
          }
          areg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
          arc_index = areg->feature_arc_index;
    
          next = creg->next;
          creg->next_in_arc = fm->next_constraint_by_arc[arc_index];
          fm->next_constraint_by_arc[arc_index] = creg;
          creg = next;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    最后,再次遍历next_arc链表,对于每个ARC集合,检测其中的features是否满足定义的次序,如果last_in_arc不等于排序之后的最后一个feature,表明发生错误。

      areg = fm->next_arc;
      while (areg)
      {
          vnet_feature_config_main_t *cm;
          vnet_config_main_t *vcm;
          char **features_in_order, *last_feature;
    
          arc_index = areg->feature_arc_index;
          cm = &fm->feature_config_mains[arc_index];
          vcm = &cm->config_main;
          if ((error = vnet_feature_arc_init (vm, vcm, areg->start_nodes, areg->n_start_nodes,
              areg->last_in_arc, fm->next_feature_by_arc[arc_index],
              fm->next_constraint_by_arc[arc_index], &fm->feature_nodes[arc_index]))) {
            os_exit (1);
          }
          features_in_order = fm->feature_nodes[arc_index];
    
          /* If specified, verify that the last node in the arc is actually last */
          if (areg->last_in_arc && vec_len (features_in_order) > 0)
          {
            last_feature = features_in_order[vec_len (features_in_order) - 1];
            if (strncmp (areg->last_in_arc, last_feature, strlen (areg->last_in_arc)))
              clib_warning("WARNING: %s arc: last node is %s, but expected %s!",
                 areg->arc_name, last_feature, areg->last_in_arc);
          }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    为每个ARC的所有feature初始化next_feature_by_name[arc_index]哈希结构,之后可通过feature名称找到feature注册结构。

          fm->next_feature_by_name[arc_index] = hash_create_string (0, sizeof (uword));
          freg = fm->next_feature_by_arc[arc_index];
    
          while (freg) {
            hash_set_mem (fm->next_feature_by_name[arc_index], freg->node_name, pointer_to_uword (freg));
            freg = freg->next_in_arc;
          }
          areg = areg->next;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    显示ARC

    命令:show features [verbose] 用于显示VPP系统中的注册的ARCs以及每个ARC包含的features集合。所有的信息都保存在全局结构feature_main中,其成员next_arc为保存了ARC注册信息的单向链表,以下函数遍历此链表。

    static clib_error_t *
    show_features_command_fn (vlib_main_t * vm,
                  unformat_input_t * input, vlib_cli_command_t * cmd)
    {
      vnet_feature_main_t *fm = &feature_main;
      vnet_feature_arc_registration_t *areg;
      vnet_feature_registration_t *freg;
      vnet_feature_registration_t *feature_regs = 0;
    
      areg = fm->next_arc;
      while (areg) {
        if (verbose)
          vlib_cli_output (vm, "[%2d] %s:", areg->feature_arc_index, areg->arc_name);
        else
          vlib_cli_output (vm, "%s:", areg->arc_name);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    ARC中的features链表保存在feature_main的成员next_feature_by_arc中,单向链表,next_in_arc指向下一个feature注册结构。遍历过程中将所有的feature注册结构保存到feature_regs向量中,按照feature索引值由小到大进行排序之后,输出feature索引和名称信息。

        freg = fm->next_feature_by_arc[areg->feature_arc_index];
        while (freg) {
          vec_add1 (feature_regs, freg[0]);
          freg = freg->next_in_arc;
        }
        vec_sort_with_function (feature_regs, feature_cmp);
    
        vec_foreach (freg, feature_regs) {
          if (verbose)
            vlib_cli_output (vm, "  [%2d]: %s\n", freg->feature_index, freg->node_name);
          else
            vlib_cli_output (vm, "  %s\n", freg->node_name);
        }
        vec_reset_length (feature_regs);
        areg = areg->next;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    如下显示:

    vpp# show features verbose
    Available feature paths
    [ 0] nsh-eth-output:
      [ 0]: interface-output
      [ 1]: error-drop
    [ 1] arp:
      [ 0]: vrrp4-arp-input
      [ 1]: linux-cp-arp-phy
      [ 2]: linux-cp-arp-host
      [ 3]: arping-input
      [ 4]: arp-reply
      [ 5]: arp-proxy
      [ 6]: arp-disabled
      [ 7]: error-drop
    [ 2] nsh-output:
      [ 0]: error-drop
    [ 3] mpls-input:
      [ 0]: vlan-mpls-qos-record
      [ 1]: mpls-qos-record
      [ 2]: mpls-not-enabled
      [ 3]: mpls-lookup
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    接口feature配置

    函数vnet_interface_features_show显示在指定接口上激活的feature集合,这里也是由遍历feature_main结构的成员next_arc开头的单链表开始。

    void
    vnet_interface_features_show (vlib_main_t * vm, u32 sw_if_index, int verbose)
    {
      vnet_feature_main_t *fm = &feature_main;
      vnet_feature_config_main_t *cm = fm->feature_config_mains;
      vnet_feature_arc_registration_t *areg;
      vnet_config_main_t *vcm;
      vnet_config_t *cfg;
      vnet_config_feature_t *feat;
      vlib_node_t *n;
    
      vlib_cli_output (vm, "Feature paths configured on %U...",
               format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index);
    
      areg = fm->next_arc;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    根据ARC索引找到对应的配置结构vcm,如果接口sw_if_index完全没有激活此ARC,显示"none configured"。否则,检查此接口在此ARC上激活了哪些features。

      while (areg) {
          feature_arc = areg->feature_arc_index;
          vcm = &(cm[feature_arc].config_main);
    
          vlib_cli_output (vm, "\n%s:", areg->arc_name);
          areg = areg->next;
    
          if (!vnet_have_features (feature_arc, sw_if_index)) {
            vlib_cli_output (vm, "  none configured");
            continue;
          }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    先根据sw_if_index接口索引在向量config_index_by_sw_if_index中找到ARC配置索引(current_config_index),再根据配置索引在向量config_pool_index_by_user_index中找到pool索引,最终,在config_pool中取得相应配置cfg。

    遍历cfg结构向量成员features,根据其中的节点索引node_index,找到feature的节点结构。打印输出feature索引和节点名称。

          current_config_index =
        vec_elt (cm[feature_arc].config_index_by_sw_if_index, sw_if_index);
          cfg_index =
        vec_elt (vcm->config_pool_index_by_user_index, current_config_index);
          cfg = pool_elt_at_index (vcm->config_pool, cfg_index);
    
          for (i = 0; i < vec_len (cfg->features); i++) {
            feat = cfg->features + i;
            node_index = feat->node_index;
            n = vlib_get_node (vm, node_index);
            if (verbose)
              vlib_cli_output (vm, "  [%2d] %v", feat->feature_index, n->name);
            else
              vlib_cli_output (vm, "  %v", n->name);
          }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    ARC的最后一个节点索引保存在end_node_indices_by_user_index的current_config_index索引位置,vlib_get_node根据最后节点索引找到节点结构,打印其名称。

          if (verbose) {
            n = vlib_get_node (vm, vcm->end_node_indices_by_user_index[current_config_index]);
            vlib_cli_output (vm, "  [end] %v", n->name);
          }
    
    • 1
    • 2
    • 3
    • 4

    如下显示接口features配置:

    vpp# show interface features eth0
    Feature paths configured on eth0...
    
    nsh-eth-output:
      none configured
    
    arp:
      linux-cp-arp-phy
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    feature开启关闭

    feature开启关闭操作需要指定ARC和Feature的名称,以及要开启的接口索引。如下函数,根据ARC和Feature名称找到ARC索引和feature索引。

    int
    vnet_feature_enable_disable (const char *arc_name, const char *node_name,
                     u32 sw_if_index, int enable_disable,     
                     void *feature_config, u32 n_feature_config_bytes)
    {  
      u32 feature_index;
      u8 arc_index;
       
      arc_index = vnet_get_feature_arc_index (arc_name); 
       
      if (arc_index == (u8) ~ 0)
        return VNET_API_ERROR_INVALID_VALUE;
       
      feature_index = vnet_get_feature_index (arc_index, node_name);
       
      return vnet_feature_enable_disable_with_index (arc_index, feature_index,
                             sw_if_index, enable_disable,             
                             feature_config, n_feature_config_bytes);                 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在feature_main结构中,根据ARC名称,在哈希arc_index_by_name找到ARC的注册结构,其中保存着ARC的索引feature_arc_index。

    vnet_get_feature_arc_index (const char *s)
    {
      vnet_feature_main_t *fm = &feature_main;
      vnet_feature_arc_registration_t *reg;
      uword *p;
    
      p = hash_get_mem (fm->arc_index_by_name, s);
      if (p == 0)
        return ~0;
    
      reg = uword_to_pointer (p[0], vnet_feature_arc_registration_t *);
      return reg->feature_arc_index;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在feature_main主结构中,根据ARC索引,和feature名称,在哈希next_feature_by_name[arc]中找到feature的注册结构,其中保存着feature的索引feature_index。

    vnet_get_feature_index (u8 arc, const char *s)
    {
      vnet_feature_main_t *fm = &feature_main;
      vnet_feature_registration_t *reg;
      uword *p;
    
      if (s == 0) return ~0;
    
      p = hash_get_mem (fm->next_feature_by_name[arc], s);
      if (p == 0)
        return ~0;
    
      reg = uword_to_pointer (p[0], vnet_feature_registration_t *);
      return reg->feature_index;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    根据ARC索引找到对应配置结构cm,再根据接口索引sw_if_index在config_index_by_sw_if_index找到配置池索引ci,检查一下接口当前开启的feature数量,如果为零,并且当前为disable操作,直接返回,不需要disable了。

    vnet_feature_enable_disable_with_index (u8 arc_index, u32 feature_index,
                        u32 sw_if_index, int enable_disable,
                        void *feature_config, u32 n_feature_config_bytes)
    {
      vnet_feature_main_t *fm = &feature_main;
      vnet_feature_config_main_t *cm;
    
      cm = &fm->feature_config_mains[arc_index];
      vec_validate_init_empty (cm->config_index_by_sw_if_index, sw_if_index, ~0);
      ci = cm->config_index_by_sw_if_index[sw_if_index];
    
      vec_validate (fm->feature_count_by_sw_if_index[arc_index], sw_if_index);
      feature_count = fm->feature_count_by_sw_if_index[arc_index][sw_if_index];
    
      if (!enable_disable && feature_count < 1)
        return 0;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    调用函数vnet_config_add_feature/vnet_config_del_feature添加或者删除feature。将返回的配置池索引ci保存到接口对应的config_index_by_sw_if_index中。递增接口的feature数量。

    ARC对应的向量sw_if_index_has_features[arc_index]中保存接口是否开启有feature。

      ci = (enable_disable
        ? vnet_config_add_feature
        : vnet_config_del_feature)
        (vlib_get_main (), &cm->config_main, ci, feature_index, feature_config, n_feature_config_bytes);
      if (ci == ~0)
          return 0;
      cm->config_index_by_sw_if_index[sw_if_index] = ci;
    
      /* update feature count */
      enable_disable = (enable_disable > 0);
      feature_count += enable_disable ? 1 : -1;
      ASSERT (feature_count >= 0);
    
      fm->sw_if_index_has_features[arc_index] =
        clib_bitmap_set (fm->sw_if_index_has_features[arc_index], sw_if_index, (feature_count > 0));
      fm->feature_count_by_sw_if_index[arc_index][sw_if_index] = feature_count;
    
      vnet_feature_reg_invoke (sw_if_index, arc_index, (feature_count > 0));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    如下增加feature函数,如果config_string_heap_index为有效值,据此获得之前添加的vnet_config_t结构old(这里将p进行了减一操作,之后会再次看着这个值进行了加一保存),将其中的features复制一份。

    vnet_config_add_feature (vlib_main_t * vm,
         vnet_config_main_t * cm, u32 config_string_heap_index,
         u32 feature_index, void *feature_config, u32 n_feature_config_bytes)
    {
      vnet_config_t *old, *new;
      vnet_config_feature_t *new_features, *f;
      u32 n_feature_config_u32s, end_node_index;
      u32 node_index = vec_elt (cm->node_index_by_feature_index, feature_index);
    
      if (config_string_heap_index == ~0) {
          old = 0;
          new_features = 0;
          end_node_index = cm->default_end_node_index;
      } else {
          u32 *p = vnet_get_config_heap (cm, config_string_heap_index);
          old = pool_elt_at_index (cm->config_pool, p[-1]);
          new_features = old->features;
          end_node_index = cm->end_node_indices_by_user_index[config_string_heap_index];
          if (new_features)
            new_features = duplicate_feature_vector (new_features);
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    分配一个新的feature结构vnet_config_feature_t,将要添加的feature索引和节点索引赋值到新feature结构中。如果指定了配置字节,保存到新feature结构中。

      vec_add2 (new_features, f, 1);
      f->feature_index = feature_index;
      f->node_index = node_index;
    
      if (n_feature_config_bytes) {
          n_feature_config_u32s = round_pow2 (n_feature_config_bytes, sizeof (f->feature_config[0])) / sizeof (f->feature_config[0]);
          vec_validate (f->feature_config, n_feature_config_u32s - 1);
          clib_memcpy_fast (f->feature_config, feature_config, n_feature_config_bytes);
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    如果new_features向量元素大于1,进行排序。释放旧的vnet_config结构。函数find_config_with_features分配一个新的vnet_config结构new。

      /* Sort (prioritize) features. */
      if (vec_len (new_features) > 1)
        vec_sort_with_function (new_features, feature_cmp);
    
      if (old)
        remove_reference (cm, old);
    
      new = find_config_with_features (vm, cm, new_features, end_node_index);
      new->reference_count += 1;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    分配config_pool_index_by_user_index索引,将配置池索引进行保存。返回配置池索引值(进行了加一操作)。

      /* User gets pointer to config string first element
       * (which defines the pool index this config string comes from).
       */
      vec_validate (cm->config_pool_index_by_user_index,
            new->config_string_heap_index + 1);
      cm->config_pool_index_by_user_index[new->config_string_heap_index + 1]
        = new - cm->config_pool;
      return new->config_string_heap_index + 1;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    CentOS8中文乱码问题
    表单v-for动态添加的校验,即动态数据项表单验证
    【RocketMQ】消息的拉取总结
    Git常见的面试题
    【FPGA零基础学习之旅#13】串口发送模块设计与验证
    Windows10下Git2.37.1安装及配置完整版
    承装修试电力设施许可证怎么办理?承装修试电力设施许可证办理应该注意哪些?
    领英高效开发客户方法(建议收藏)
    beforeRouteEnter、created、mounted的思考和总结
    【校招VIP】去年招770人,今年竟然只招50人??24届秋招真的好难。。。
  • 原文地址:https://blog.csdn.net/sinat_20184565/article/details/133253111