VPP FIB路径链表环路检查

对于路径链表中的三种路径类型:

FIB_PATH_TYPE_RECURSIVE
FIB_PATH_TYPE_ATTACHED_NEXT_HOP
FIB_PATH_TYPE_ATTACHED

在添加新的路径时需要进行路径环路检查。函数fib_path_list_recursive_loop_detect会被反复调用。

static void
fib_entry_recursive_loop_detect_i (fib_node_index_t path_list_index)
{   fib_node_index_t *entries = NULL;fib_path_list_recursive_loop_detect(path_list_index, &entries);vec_free(entries);
}

FIB路径链表环路检查

函数fib_path_list_recursive_loop_detect根据path_list_index获取FIB路径链表,遍历路径向量(fpl_paths)中的每个路径。

int 
fib_path_list_recursive_loop_detect (fib_node_index_t path_list_index, fib_node_index_t **entry_indicies)
{   fib_node_index_t *path_index;int is_looped, list_looped;fib_path_list_t *path_list;list_looped = 0;path_list = fib_path_list_get(path_list_index);

函数fib_path_recursive_loop_detect对路径(path_index)进行检查,是否和copy_ptr中的路径有环路。对于第一个路径,copy_ptr为空,无环路。函数被再次调用的时候,entry_indicies不为空。

copy_ptr向量保存已经进行过环路检查的FIB表项(参见FIB表项环路检查一节)。list_looped表示FIB路径列表中的环路数量。

    vec_foreach (path_index, path_list->fpl_paths){fib_node_index_t *copy, **copy_ptr;/* we need a copy of the nodes visited so that when we add entries* we explore on the nth path and a looped is detected, those entries* are not again searched for n+1 path and so finding a loop that does not exist.*/copy = vec_dup(*entry_indicies);copy_ptr = ©is_looped  = fib_path_recursive_loop_detect(*path_index, copy_ptr);list_looped += is_looped;vec_free(copy);}

根据list_looped的值,路径链表设置环路标志(FIB_PATH_LIST_FLAG_LOOPED)。

    FIB_PATH_LIST_DBG(path_list, "loop-detect: eval:%d", list_looped);if (list_looped) {path_list->fpl_flags |= FIB_PATH_LIST_FLAG_LOOPED;} else {path_list->fpl_flags &= ~FIB_PATH_LIST_FLAG_LOOPED;}return (list_looped);

FIB路径环路检查

以上为FIB路径链表的环路检查函数。以下为FIB路径的环路检查。首先排除DROP动作的路径,其不需要解析(resolve),也不会有环路。

int 
fib_path_recursive_loop_detect (fib_node_index_t path_index, fib_node_index_t **entry_indicies)
{fib_path_t *path = fib_path_get(path_index);/* the forced drop path is never looped, cos it is never resolved. */if (fib_path_is_permanent_drop(path))return (0);

对于RECURSIVE递归类型的FIB路径,遍历参数entry_indicies中所有的表项索引,如果存在和要检查的递归路径所依赖的FIB(fp_via_fib)相同的情况,表明存在环路。

此FIB递归路径本身是RECURSIVE类型,并且要通过FIB路径链表中的某个FIB路径去解析(RESOVLE),添加到路径链表将导致环路。

    switch (path->fp_type){case FIB_PATH_TYPE_RECURSIVE:{fib_node_index_t *entry_index, *entries = *entry_indicies;int looped = 0;vec_foreach(entry_index, entries) {if (*entry_index == path->fp_via_fib) {/* the entry that is about to link to this path-list (or one of this path-list's children) * is the same entry that this recursive path resolves through. this is a cycle. abort the walk. */looped = 1;break;}}

如果发现环路,将FIB路径的DPO设置为DPO_DROP类型的DPO,避免转发流量,设置路径的运行标志FIB_PATH_OPER_FLAG_RECURSIVE_LOOP。

    if (looped) {FIB_PATH_DBG(path, "recursive loop formed");path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RECURSIVE_LOOP;dpo_copy(&path->fp_dpo, drop_dpo_get(path->fp_nh_proto));

如果以上没有发现环路,递归检查FIB路径依赖的FIB表项。fp_via_fib是否和路径链表path-list中的已有表项(entry_indicies)有环路。根据结果为FIB路径设置或者清除标志位FIB_PATH_OPER_FLAG_RECURSIVE_LOOP。

    } else {/* no loop here yet. keep forward walking the graph. */if (fib_entry_recursive_loop_detect(path->fp_via_fib, entry_indicies)) {FIB_PATH_DBG(path, "recursive loop formed");path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RECURSIVE_LOOP;} else {FIB_PATH_DBG(path, "recursive loop cleared");path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RECURSIVE_LOOP;}}break;}

对于直连类型的FIB路径,如果DPO是邻居类型,检查邻居是否有环路,设置相应的标志位。

    case FIB_PATH_TYPE_ATTACHED_NEXT_HOP:case FIB_PATH_TYPE_ATTACHED:if (dpo_is_adj(&path->fp_dpo) && adj_recursive_loop_detect(path->fp_dpo.dpoi_index, entry_indicies)) {FIB_PATH_DBG(path, "recursive loop formed");path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RECURSIVE_LOOP;} else {FIB_PATH_DBG(path, "recursive loop cleared");path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RECURSIVE_LOOP;}break;

以下这些FIB路径类型不可能形成环路。

    case FIB_PATH_TYPE_SPECIAL:case FIB_PATH_TYPE_DEAG:case FIB_PATH_TYPE_DVR:case FIB_PATH_TYPE_RECEIVE:case FIB_PATH_TYPE_INTF_RX:case FIB_PATH_TYPE_UDP_ENCAP:case FIB_PATH_TYPE_EXCLUSIVE:case FIB_PATH_TYPE_BIER_FMASK:case FIB_PATH_TYPE_BIER_TABLE:case FIB_PATH_TYPE_BIER_IMP:/* these path types cannot be part of a loop, since they are the leaves of the graph. */break;}return (fib_path_is_looped(path_index));

FIB表项环路检查

如果FIB表项没有链接在任何FIB路径链表(fe_parent有效)中,不需要进行环路检查。

int     
fib_entry_recursive_loop_detect (fib_node_index_t entry_index, fib_node_index_t **entry_indicies)
{       fib_entry_t *fib_entry;int was_looped, is_looped;fib_entry = fib_entry_get(entry_index);

这里更新entry_indicies。再次调用开始时的fib_path_list_recursive_loop_detect函数,检查路径链表fe_parent中的路径是否与entries有环路。

    if (FIB_NODE_INDEX_INVALID != fib_entry->fe_parent){   fib_node_index_t *entries = *entry_indicies;vec_add1(entries, entry_index);was_looped = fib_path_list_is_looped(fib_entry->fe_parent);is_looped = fib_path_list_recursive_loop_detect(fib_entry->fe_parent, &entries);*entry_indicies = entries;

如果FIB路径链表fe_parent的环路状态发生变化,重新评估所有表项的转发属性,设置load-balance。

      if (!!was_looped != !!is_looped) {/* re-evaluate all the entry's forwarding. NOTE: this is an inplace modify */fib_entry_delegate_type_t fdt;fib_entry_delegate_t *fed;FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed,{fib_entry_src_mk_lb(fib_entry, fib_entry_get_best_source(entry_index),fib_entry_delegate_type_to_chain_type(fdt), &fed->fd_dpo);});}

FIB表项没有链接到FIB路径链表。

    } else {/* the entry is currently not linked to a path-list. this happens* when it is this entry that is re-linking path-lists and has thus broken the loop*/is_looped = 0;}return (is_looped);

DROP路径

如果路径fib_path_t,配置了FIB_PATH_CFG_FLAG_DROP标志,应该类似于Linux中的黑洞路由。或者设置了运行标志FIB_PATH_OPER_FLAG_DROP,返回真,认为此路径为permanent_drop。

static int
fib_path_is_permanent_drop (fib_path_t *path)
{return ((path->fp_cfg_flags & FIB_PATH_CFG_FLAG_DROP) ||(path->fp_oper_flags & FIB_PATH_OPER_FLAG_DROP));
}

FIB路径环路标识

检查路径结构的操作标志(fp_oper_flags),如果设置了FIB_PATH_OPER_FLAG_RECURSIVE_LOOP,表明路径有环路。

int
fib_path_is_looped (fib_node_index_t path_index)
{fib_path_t *path;path = fib_path_get(path_index);return (path->fp_oper_flags & FIB_PATH_OPER_FLAG_RECURSIVE_LOOP);
}

邻居环路

以下类型的DPO都属于邻居类型。

int dpo_is_adj (const dpo_id_t *dpo)
{    return ((dpo->dpoi_type == DPO_ADJACENCY) ||(dpo->dpoi_type == DPO_ADJACENCY_INCOMPLETE) ||(dpo->dpoi_type == DPO_ADJACENCY_GLEAN) ||(dpo->dpoi_type == DPO_ADJACENCY_MCAST) ||(dpo->dpoi_type == DPO_ADJACENCY_MCAST_MIDCHAIN) ||(dpo->dpoi_type == DPO_ADJACENCY_MIDCHAIN));
}   

对于除去MIDCHAIN和MCAST_MIDCHAIN之外,其它的IP_LOOKUP_NEXT_*节点都是终止图节点,没有成环的可能性。MIDCHAIN类型通常为隧道接口使用,添加外层IP头部数据使用,存在环路的可能性。

int adj_recursive_loop_detect (adj_index_t ai, fib_node_index_t **entry_indicies)
{                                      ip_adjacency_t * adj = adj_get(ai);switch (adj->lookup_next_index) {    case IP_LOOKUP_NEXT_REWRITE:case IP_LOOKUP_NEXT_ARP:case IP_LOOKUP_NEXT_GLEAN:case IP_LOOKUP_NEXT_MCAST:case IP_LOOKUP_NEXT_BCAST:case IP_LOOKUP_NEXT_DROP:case IP_LOOKUP_NEXT_PUNT:case IP_LOOKUP_NEXT_LOCAL:case IP_LOOKUP_NEXT_ICMP_ERROR:case IP_LOOKUP_N_NEXT:/* these adjacency types are terminal graph nodes, so there's no* possibility of a loop down here. */break;

对于MIDCHAIN类型,进行检查。

    case IP_LOOKUP_NEXT_MIDCHAIN:case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:return (adj_ndr_midchain_recursive_loop_detect(ai, entry_indicies));}return (0);

如果MIDCHAIN邻居adj解析所需要的FIB表项(fei索引),与entry_indicies向量中的某个表项索引相等,表明存在路由环路,设置ADJ_FLAG_MIDCHAIN_LOOPED标志。

int adj_ndr_midchain_recursive_loop_detect (adj_index_t ai, fib_node_index_t **entry_indicies)
{   fib_node_index_t *entry_index, *entries;ip_adjacency_t * adj = adj_get(ai);entries = *entry_indicies;vec_foreach(entry_index, entries) {if (*entry_index == adj->sub_type.midchain.fei) {/* The entry this midchain links to is already in the set of visited entries, this is a loop */adj->ia_flags |= ADJ_FLAG_MIDCHAIN_LOOPED;return (1);}}adj->ia_flags &= ~ADJ_FLAG_MIDCHAIN_LOOPED;return (0);

路由环路示例

如下三条recursive类型的路由形成环路。

ip route add 5.5.5.5/32 via 6.6.6.6
ip route add 6.6.6.6/32 via 7.7.7.7
ip route add 7.7.7.7/32 via 5.5.5.5

对应以下三个FIB表项。

vpp# show fib entry
FIB Entries:
7@5.5.5.5/32unicast-ip4-chain[@0]: dpo-load-balance: [proto:ip4 index:10 buckets:1 uRPF:8 to:[0:0]][0] [@0]: dpo-drop ip4
8@6.6.6.6/32unicast-ip4-chain[@0]: dpo-load-balance: [proto:ip4 index:9 buckets:1 uRPF:10 to:[0:0]][0] [@0]: dpo-drop ip4
9@7.7.7.7/32unicast-ip4-chain[@0]: dpo-load-balance: [proto:ip4 index:11 buckets:1 uRPF:9 to:[0:0]][0] [@0]: dpo-drop ip4

以下路由链表:13,14,15都设置了loop标志。并且,其中的路径都设置了recursive-loop标志,对应于fib_path_t结构中成员fp_cfg_flags中标志位FIB_PATH_OPER_ATTRIBUTE_RECURSIVE_LOOP。

vpp# show fib path-lists 
FIB Path Lists
path-list:[13] locks:2 flags:shared,looped, uPRF-list:8 len:0 itfs:[]path:[13] pl-index:13 ip4 weight=1 pref=0 recursive:  oper-flags:recursive-loop,via 6.6.6.6 in fib:0 via-fib:8 via-dpo:[dpo-drop:0]
path-list:[14] locks:2 flags:shared,looped, uPRF-list:10 len:0 itfs:[]path:[14] pl-index:14 ip4 weight=1 pref=0 recursive:  oper-flags:recursive-loop,via 7.7.7.7 in fib:0 via-fib:9 via-dpo:[dpo-drop:0]
path-list:[15] locks:2 flags:shared,looped, uPRF-list:9 len:0 itfs:[]path:[15] pl-index:15 ip4 weight=1 pref=0 recursive:  oper-flags:recursive-loop,via 5.5.5.5 in fib:0 via-fib:7 via-dpo:[dpo-drop:0]

命令show logging查看在加入最后一条路由之后的日志。在函数fib_path_recursive_loop_detect中打印了形成环路的FIB路径(path)的详细信息,在函数fib_path_list_recursive_loop_detect中打印了形成环路的路径链表(path-list)的详细信息。

日志“loop-detect: eval:1”表明环路的数量为1.

fib/path       [path:[15] pl-index:15 ip4 weight=1 pref=0 recursive: via 5.5.5.5 in fib:0 via-fib:7 via-dpo:[dpo-load-balance:10]]: recursive loop formed
fib/path-list  [path-list:[15] locks:2 flags:shared, uPRF-list:7 len:0 itfs:[]path:[15] pl-index:15 ip4 weight=1 pref=0 recursive:  oper-flags:recursive-loop,via 5.5.5.5 in fib:0 via-fib:7 via-dpo:[dpo-drop:0]
]:loop-detect: eval:1
fib/path       [path:[14] pl-index:14 ip4 weight=1 pref=0 recursive: via 7.7.7.7 in fib:0 via-fib:9 via-dpo:[dpo-load-balance:11]]: recursive loop formed
fib/path-list  [path-list:[14] locks:2 flags:shared, uPRF-list:8 len:0 itfs:[]path:[14] pl-index:14 ip4 weight=1 pref=0 recursive:  oper-flags:recursive-loop,via 7.7.7.7 in fib:0 via-fib:9 via-dpo:[dpo-load-balance:11]
]:loop-detect: eval:1
fib/path       [path:[13] pl-index:13 ip4 weight=1 pref=0 recursive: via 6.6.6.6 in fib:0 via-fib:8 via-dpo:[dpo-load-balance:9]]: recursive loop formed
fib/path-list  [path-list:[13] locks:2 flags:shared, uPRF-list:9 len:0 itfs:[]path:[13] pl-index:13 ip4 weight=1 pref=0 recursive:  oper-flags:recursive-loop,via 6.6.6.6 in fib:0 via-fib:8 via-dpo:[dpo-load-balance:9]
]:loop-detect: eval:1
fib/path       [path:[15] pl-index:15 ip4 weight=1 pref=0 recursive:  oper-flags:recursive-loop,via 5.5.5.5 in fib:0 via-fib:7 via-dpo:[dpo-drop:0]]: recursive loop formed
fib/path-list  [path-list:[15] locks:2 flags:shared,looped, uPRF-list:7 len:0 itfs:[]path:[15] pl-index:15 ip4 weight=1 pref=0 recursive:  oper-flags:recursive-loop,via 5.5.5.5 in fib:0 via-fib:7 via-dpo:[dpo-drop:0]
]:loop-detect: eval:1

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

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

相关文章

MySQL-数据库设计规范

1、范式 1.1、概述 在关系型数据库中,关于数据表设计的基本原则、规则就称为范式常见六种范式,按照范式级别由低到高如下所示: 第一范式第二范式第三范式巴斯范式第四范式第五范式 1.2、键和相关属性 范式的定义会用法主键和候选键&…

llllllllll

llllllllllllllll

gulp 构建Node.js 应用

安装 ## 安装 gulp 命令行工具 npm install --global gulp-cli## 安装 gulp,作为开发时依赖项 npm install --save-dev gulp为什么要用Gulp ? 在前端开发中,Gulp是一个node.js 的自动化构建工具,它通过流和代码优于配置的策略来简化任务编…

类的继承和方法重载

想象一下,有一个相亲想爱的一家人家族树。在这个家族树中,有一个祖先(父类),它拥有一些基本的特征和行为,比如家族的传统、姓氏、某些共同的技能或知识。 现在,这个祖先有多个后代(…

vivado 设计连接性

设计连接性 IP集成商提供设计师协助,帮助您完成连接过程 设计。图3显示了MHS的一个示例,图4显示了设计帮助 可在IP集成商中获得 地址映射 在XPS中,无论主机访问从机IP,每个从机都有相同的地址。IP integrator为基于master的寻址提…

【C++课程学习】:命名空间的理解(图文详解)

🎁个人主页:我们的五年 🔍系列专栏:C课程学习 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录 📷1.命名冲突 📷2.重定义 📷3.命名空间 🍺命名空间可…

Leetcode刷题笔记3

18. 四数之和 18. 四数之和 - 力扣(LeetCode) 给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应&…

解决Element组件el-switch在Vue中值的绑定与回显问题

概要 Switch 开关表示两种相互对立的状态间的切换,多用于触发「开/关」。可当一个布尔值进行使用。 问题描述与解决 引入Element组件的switch到Vue中,可以读取switch的值,但如果放在页面中,不能回显上去。 如上图,无论值是"否"还是“是”。都不能正确渲染到页…

Make New 函数 ---golang

make 和 new 函数的使用区别 共同点: make 函数和new 函数都是用来申请内存地址的。不同点 1、new函数的使用相对来比较少,用于对一般的数据类型,做数据类型申请 如: string, int,且申请的为 指针类型。…

vue-officef实现pdf文件在线预览

一、参考网址 https://www.cnblogs.com/guozhiqiang/p/17957288 1、引入依赖 npm install vue-office/pdf vue-demi2、编写组件 <template><vue-office-pdf :src"pdf"/> </template> <script> // import pdf from vue-pdf import VueOffice…

基于长短期记忆网络 LSTM 的送餐时间预测

前言 系列专栏:【深度学习&#xff1a;算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域&#xff0c;讨论了各种复杂的深度神经网络思想&#xff0c;如卷积神经网络、循环神经网络、生成对…

Linux Kernel入门到精通系列讲解(RV-U-boot 篇) 4.2 RISC-V从零移植自己的Uboot

1. 概述 上一章节我们已经成功从OpenSBI跳转到Uboot,并且已经把默认的qemu-riscv64_smode_defconfig移植成功了,本章节我们将会重新规划memory 分区,方便后续创建更多的设备,并且从零开始移植一个属于Naruto Pi的uboot。 2. 重建分区表 2.1 当前QEMU已创建Memory 地址大小…

实战13:lstm bp 机器学习随机森林粮食产量预测-完整代码数据

直接看视频: lstm bp 机器学习随机森林粮食产量预测-完整代码数据_哔哩哔哩_bilibili 看数据: 代码: from sklearn.linear_model import LinearRegression from sklearn import preprocessing import random from sklearn.model_selection import train_test_split from…

postgresql|数据库|闪回插件e-maj的部署和使用

前言&#xff1a; E-Maj 是 PostgreSQL 数据库的一个扩展插件&#xff0c;它的全称为 "Elementary Majordomo"。这个扩展的主要功能是为数据库中的表集提供细粒度的写入日志记录和时间旅行能力。这意味着使用 E-Maj 的用户可以在数据库的特定子集上实现事务的回滚&a…

C++笔记之Unix时间戳、UTC、TSN、系统时间戳、时区转换、local时间笔记

C++笔记之Unix时间戳、UTC、TSN、系统时间戳、时区转换、local时间笔记 ——2024-05-26 夜 code review! 参考博文 C++笔记之获取当前本地时间以及utc时间

Linux定时计划

定时计划 一、计划任务种类 突发性&#xff1a;临时决定只执行一次的任务 at&#xff1a;处理执行一次任务就结束定时性&#xff1a;每隔一定时间需要重复执行此命令 crontab&#xff1a;指定任务&#xff0c;按照设定的周期一直循环执行二、作用 定时任务可以用于自动备份…

TCP/IP协议(一)

一.报文和协议 协议有什么作用&#xff1f;协议定义通信实体间所交换报文的格式和次序&#xff0c;以及在报文发送和/或接收或者其他事件方面所采取的行动(响应)。 什么是报文&#xff1f;指在网络中传输的数据单元&#xff0c;网络通讯的基本单位。&#xff08;HTTP报文、TCP报…

链式二叉树的前,中,后序遍历 AND 结点个数及高度等 文末附带全部代码

目录 前言1. 前序遍历2. 中序遍历3. 后续遍历4. 二叉树结点的个数5. 二叉树叶子结点个数6. 二叉树的高度7. 二叉树第K层结点的个数8. 二叉树查找值为x的结点全部代码总结 正文开始 前言 本文旨在介绍二叉树的链式存储中一些函数的实现 博客主页: 酷酷学!!! 更多文章, 期待关…

高德地图地图 JS API 2.0 基本使用

1. 按 NPM 方式安装使用 Loader npm i amap/amap-jsapi-loader --save2. 新建 MapContainer.vue 文件 在项目中新建 MapContainer.vue 文件&#xff0c;用作地图组件。 3.创建地图容器 在 MapContainer.vue 地图组件中创建 div 标签作为地图容器 &#xff0c;并设置地图容器…

01主动安全系统

“安全”一直是车主对车辆考核的重要指标。车辆安全可以分为从主动安全和被动安全两个方面进行分类。今天就来说说汽车主动安全系统的那些事儿。 01.什么是主动安全系统&#xff1f; 主动安全是指尽量自如地操纵控制汽车的安全系统措施。无论是直线上的制动与加速还是左右打方…