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++;}

按照最大的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);

遍历全局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;}

遍历全局的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;}

最后,再次遍历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);}

为每个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;}

显示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);elsevlib_cli_output (vm, "%s:", areg->arc_name);

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);elsevlib_cli_output (vm, "  %s\n", freg->node_name);}vec_reset_length (feature_regs);areg = areg->next;}

如下显示:

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

接口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;

根据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;}

先根据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);elsevlib_cli_output (vm, "  %v", n->name);}

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);}

如下显示接口features配置:

vpp# show interface features eth0
Feature paths configured on eth0...nsh-eth-output:none configuredarp:linux-cp-arp-phy

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);                 

在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;

在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;

根据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;

调用函数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));

如下增加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);}

分配一个新的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);}

如果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;

分配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;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/86751.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

为什么添加了@EnableDiscoveryClient注解就可以实现服务注册

添加了nacos的maven依赖之后&#xff0c;只需要在启动类上加一个EnableDiscoveryClient注解就可以实现服务注册&#xff0c;这个注解为什么可以实现&#xff1f; EnableDiscoveryClient注解 进去到EnableDiscoveryClient注解之后&#xff0c;只有简单的几行代码&#xff1a; …

【新版】系统架构设计师 - 案例分析 - 信息安全

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 案例分析 - 信息安全安全架构安全模型分类BLP模型Biba模型Chinese Wall模型 信息安全整体架构设计WPDRRC模型各模型安全防范功能 网络安全体系架构设计开放系统互联安全体系结构安全服务与安全机制…

mysql workbench常用操作

1、No database selected Select the default DB to be used by double-clicking its name in the SCHEMAS list in the sidebar 方法一&#xff1a;双击你要使用的库 方法二&#xff1a;USE 数据库名 2、复制表名&#xff0c;字段名 3、保存链接

简单趋势策略研究

交易对象&#xff1a;目前使用各种主力合约进行交易。 交易平台&#xff1a;易盛极星极星产品网 手续费研究:白糖期货手续费和保证金2023年09月更新 - 九期网 本人使用的期货交易公司&#xff1a;中信期货&#xff08;幸亏资金量大&#xff0c;返还高&#xff0c;不然就是给…

vue3+ts 实现移动端分页

current 开始页码 pageSize 结束页码 const sizeref<number>(10) //一页显示十条 const eachCurrentPageref<number>(1) //默认是第一页interface ITdata {current: number,pageSize: number,// xxxx 其他参数... } const selectApplyList ref<…

联想电脑打开exe提示要在Microsoft Store中搜索应用

问题&#xff1a; 你需要为此任务安装应用。 是否要在Microsoft Store中搜索一个&#xff1f; 如图&#xff1a; 出现此情况&#xff0c;仅需要做如下操作&#xff0c;在要打开的exe文件上右键&#xff0c;属性&#xff1a; 如图箭头所示&#xff0c;点击“解除锁定”出现对钩&…

题解:ABC321D - Set Menu

题解&#xff1a;ABC321D - Set Menu 题目 链接&#xff1a;Atcoder。 链接&#xff1a;洛谷。 难度 算法难度&#xff1a;B。 思维难度&#xff1a;C。 调码难度&#xff1a;B。 综合评价&#xff1a;见洛谷链接。 算法 枚举二分查找。 思路 先对b升序排序&#x…

C++提高编程:02 STL入门

这里写目录标题 STL初识1 STL的诞生2 STL基本概念3 STL六大组件4 STL中容器、算法、迭代器5 容器算法迭代器初识5.1 vector存放内置数据类型5.2 Vector存放自定义数据类型5.3 Vector容器嵌套容器 STL初识 1 STL的诞生 长久以来&#xff0c;软件界一直希望建立一种可重复利用的…

<十二>objectARX开发:Arx注册命令类型的含义以及颜色索引对应RGB值

1、注册命令类型 我们经常在acrxEntryPoint.cpp中看到注册命令如下: 那么各个宏定义代表什么意思呢? 主标识:(常用的) ACRX_CMD_MODAL: 在别的命令执行的时候该命令不会在其中执行。ACRX_CMD_TRANSPARENT: 命令可以再其它命令中执行,但在该标志下ads_sssetfirst()不能使…

SELECT * from t_user where user_id = xxx,可以从那几个点去优化这句sql

优化SQL查询可以从以下几个方面入手&#xff1a; 1. 索引优化&#xff1a;通过为查询涉及的列添加合适的索引&#xff0c;可以提高查询的效率。在该SQL语句中&#xff0c; user_id 列被用作查询条件&#xff0c;可以为 user_id 列创建一个索引。 2. 避免使用 SELECT *&#xf…

LeetCode 494.目标和 (动态规划 + 性能优化)二维数组 压缩成 一维数组

494. 目标和 - 力扣&#xff08;LeetCode&#xff09; 给你一个非负整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 或 - &#xff0c;然后串联起所有整数&#xff0c;可以构造一个 表达式 &#xff1a; 例如&#xff0c;nums [2, 1] &#xff0c;可以在 2…

用Redis做数据排名

1.背景 用Redis做数据缓存用的比较多&#xff0c;大家都能熟练使用String和Hash结构去存储数据&#xff0c;今天讲下如何使用ZSet来做数据排名。 假设场景是需要按天存储全国城市的得分数据&#xff0c;可以查询前十名的城市排名。 这个case可以使用传统关系型数据库做…

如何修复wmvcore.dll缺失问题,wmvcore.dll下载修复方法分享

近年来&#xff0c;电脑使用的普及率越来越高&#xff0c;人们在日常生活中离不开电脑。然而&#xff0c;有时候我们可能会遇到一些问题&#xff0c;其中之一就是wmvcore.dll缺失的问题。wmvcore.dll是Windows平台上用于支持Windows Media Player的动态链接库文件&#xff0c;如…

MATLAB算法实战应用案例精讲-【概念篇】用户画像(补充篇)

目录 前言 几个相关概念 算法原理 用户画像是什么? 用户画像种类

SD-MTSP:萤火虫算法(FA)求解单仓库多旅行商问题MATLAB(可更改数据集,旅行商的数量和起点)

一、萤火虫算法&#xff08;FA&#xff09;简介 萤火虫算法(Firefly Algorithm&#xff0c;FA)是Yang等人于2009年提出的一种仿生优化算法。 参考文献&#xff1a;田梦楚, 薄煜明, 陈志敏, et al. 萤火虫算法智能优化粒子滤波[J]. 自动化学报, 2016, 42(001):89-97. 二、单仓…

代码随想录Day42 | 01背包问题| 416. 分割等和子集

01背包问题&#xff08;Acwing&#xff09; 有 N 件物品和一个容量是 V的背包。每件物品只能使用一次。 第 i 件物品的体积是 vi&#xff0c;价值是 wi。 求解将哪些物品装入背包&#xff0c;可使这些物品的总体积不超过背包容量&#xff0c;且总价值最大。 输出最大价值。 输入…

数量关系(刘文超)

解题技巧 代入排除法 数字特性法 整除特性 比例倍数特性&#xff08;找比例&#xff0c;比例不明显时找等式&#xff09; 看不懂式子时&#xff0c;把所有的信息像表格一样列出来 看不懂式子时&#xff0c;把所有的信息像表格一样列出来

【机器学习】期望最大算法(EM算法)解析:Expectation Maximization Algorithm

【机器学习】期望最大算法&#xff08;EM算法&#xff09;&#xff1a;Expectation Maximization Algorithm 文章目录 【机器学习】期望最大算法&#xff08;EM算法&#xff09;&#xff1a;Expectation Maximization Algorithm1. 介绍2. EM算法数学描述3. EM算法流程4. 两个问…

性能测试 —— Tomcat监控与调优:Jconsole监控

JConsole的图形用户界面是一个符合Java管理扩展(JMX)规范的监测工具&#xff0c;JConsole使用Java虚拟机(Java VM)&#xff0c;提供在Java平台上运行的应用程序的性能和资源消耗的信息。在Java平台&#xff0c;标准版(Java SE平台)6&#xff0c;JConsole的已经更新到目前的外观…

Linux查看哪些进程占用的系统 buffer/cache 较高 (hcache,lsof)命令

1、什么是buffer/cache &#xff1f; buffer/cache 其实是作为服务器系统的文件数据缓存使用的&#xff0c;尤其是针对进程对文件存在 read/write 操作的时候&#xff0c;所以当你的服务进程在对文件进行读写的时候&#xff0c;Linux内核为了提高服务的读写速度&#xff0c;则将…