AIGC标识 InfiniBand 专题【左扬精讲】—— InfiniBand 路由引擎:算法原理、选型对照与 OpenSM 配置验证

InfiniBand 专题【左扬精讲】—— InfiniBand 路由引擎:算法原理、选型对照与 OpenSM 配置验证

路径算出来和路径走得通,是两件事。本系列第八篇讲子网初始化时,路径计算那一步只留下了一个名字——SM 会为每一对源和目的节点算出"最佳路径",然后写进每台交换机的线性转发表(LFT)。但"最佳"这个词由什么定义、算出来的表凭什么不会把整片网络锁死、换一个拓扑要不要换算法,那一篇没有展开。这个决定性的一环,由一个独立的软件组件负责:路由引擎(Routing Engine)。

本篇是 InfiniBand 专题【左扬精讲】 系列的 第 11 篇,主题是子网管理器常用路由引擎的原理、选型对照与 OpenSM 上的配置验证。全文按"为什么有多个引擎 → 每个引擎解决什么问题 → 用哪个 → 怎么配 → 怎么验证"的顺序展开,先讲清楚课程点名的五个引擎——minhop / updn / ftree / torus-2QoS / dfp——再落到 opensm.conf 里两个真实参数 routing_engine 与 root_guid_file 上,最后给出一份可照抄的验证清单。

开篇必读:课程口语转写里的四组高频误听,本文全部按真实标识符纠正

本篇素材来自一段英伟达英文课程的口语转写,转写引擎对专有名词的还原率很低。以下四组对照是全文可复现性的前提——照着转写稿敲命令一定敲不通:

  • "taurus" / "torres" → torus-2QoS(环面拓扑,Torus)。转写把 torus 反复听成西班牙语人名 torres。
  • "dragonfly plus" / "dfp" → dfp。Dragonfly+ 在 MLNX SM 的 routing_engine 参数里就是取字 dfp;三级及以上树形岛用 dfp2。
  • "root good file" / "root gou IDE list" → root_guid_file(配置项名)与 -a / --root_guid_file(命令行选项名)。GUID 被听成了 good / gou IDE。
  • "open SM dash c" → opensm -c,"open SM dot comt" → opensm.conf,"ib switches" → ibswitches。

另外一处需要单独纠正:转写稿说 "up down and fat tree should be used in fat tree topologies",这与 OpenSM 官方文档相反。OpenSM 手册对 UPDN 的定位是——当子网不是纯胖树(not a pure Fat Tree)、且可能因环导致死锁时,才应该选它。胖树本身没有环,正是死锁免疫的拓扑;UPDN 的价值恰恰在于给有环的非胖树拓扑兜底。详见第二节对照表。

本篇核心术语:
Routing Engine 路由引擎 / Min Hop 最短跳数 / Up-Down 升降 / Fat Tree 胖树
Torus 环面 / 2D Torus 二维环面 / 3D Torus 三维环面 / DOR 维序路由
Dragonfly+ 蜻蜓增强拓扑 / Group 组 / Island 岛 / Spine 脊交换机 / Leaf 叶交换机
Rank 秩 / Rank 0 根交换机 / Root Node 根节点 / Uplink 上行 / Downlink 下行
Credit Loop 信用环 / Credit-Based Flow Control 基于信用的流控 / Deadlock 死锁
Virtual Lane 虚拟通道 / VL Increment VL 递增 / SL Service Level 服务级别
Adaptive Routing 自适应路由 / Min Hop + 1 非最短一跳 / Congestion 拥塞
LFT Linear Forwarding Table 线性转发表 / FDB 转发数据库
OpenSM 子网管理器守护进程 / opensm.conf 配置文件

本篇核心命令与配置项:
opensm -c 生成配置 / opensm -R 指定路由引擎 / opensm -a 指定根 GUID 文件
routing_engine 路由引擎配置项 / root_guid_file 根 GUID 文件配置项 / qos QoS 开关
ibswitches 列出交换机 / ibroute 读交换机转发表 / ibstat 读本机端口

本篇权威依据:
opensm(8) man page —— -R/--routing_engine 支持的全部引擎名、-a/--root_guid_file 语义、UPDN 三阶段算法原文、torus-2QoS 激活方式
opensm doc/current-routing.txt —— UPDN 自动探测根节点与 rank 排序的算法描述、纯胖树判定条件
opensm opensm/osm_ucast_mgr.c —— osm_ucast_mgr_process 输出 "%s tables configured on all switches" 的源码位置
NVIDIA MLNX SM 文档 —— dfp / dfp2 路由引擎与 AR_ALGORITHM 取值 LAG / TREE / DF_PLUS
IBTA InfiniBand Architecture Specification Volume 1 Release 1.3.4 —— 信用环与 VL 依赖图

InfiniBandRouting EngineMin HopUp/DownFat TreeTorus-2QoSDragonfly+Credit LoopDeadlockAdaptive RoutingVirtual Laneopensm.confroot_guid_fileopensm

★ 学完这一篇你能掌握什么(渐进式路径:1→2→3→4 不可跳跃)

  • 第 1 步 · 分清引擎的命名逻辑(第一节、第二节)
      • What:minhop 与 updn 不绑定特定拓扑;ftree / torus-2QoS / dfp 是按目标拓扑命名,用错拓扑会导致路由失败
      • How:能说出 OpenSM 支持的全部引擎标识符,以及未指定 routing_engine 时默认启用哪一个
      • Why:理解 "为什么在没有咨询 fabric 架构师前不应改动 routing_engine"——改动会重写每一台交换机的转发表,属于全网级变更
  • 第 2 步 · 掌握 Up/Down 的算法与规则(第三节、第四节、第五节)
      • What:三阶段 = 找根节点 → BFS 赋 rank → BFS 生成转发表;核心规则是丢弃任何"先降后升"的路径
      • How:能对着任意拓扑图判断一条路径是否合法,以及为什么合法路径不会形成信用环
      • Why:理解 "为什么 Up/Down 与 Min Hop 走的都是最短路,差别只在多一条剪枝规则"——这正是它能防死锁而 Min Hop 不能的原因
  • 第 3 步 · 理解 Fat Tree 与 Dragonfly+ 的差异化设计(第六节、第七节)
      • What:Fat Tree 利用端口序位对称让各叶交换机选不同出口;Dragonfly+ 通过 Min Hop + 1 绕开拥塞,且 VL 在"降后升"处递增
      • How:能解释为什么"所有叶交换机默认选同一出口"会拥塞,以及负载均衡版本如何修正
      • Why:理解 "为什么两种引擎防信用环的思路完全不同"——Fat Tree 沿用 Up/Down 的剪枝规则,Dragonfly+ 则用 VL 递增
  • 第 4 步 · 会配会验(第八节、第九节、第十节)
      • What:opensm -c 生成配置;root_guid_file 填根交换机 GUID(每行一个);routing_engine updn 切换引擎
      • How:能在 opensm.log 里找到 updn tables configured on all switches 这行作为成功判据,并识别失败时的回退链
      • Why:理解 "为什么没配 root_guid_file 时 UPDN 会退回 Min Hop"——自动探测根节点是统计方法,可能一个根都找不到

★ 阅读前提 & 本篇不涉及的内容

  • 前置知识:本系列第一篇《InfiniBand 架构简介:从五层模型到子网管理》中的 Fabric vs. Subnet、GUID / LID / GID 三层地址;本系列第八篇《子网初始化:拓扑发现、LID 分配、路径计算与子网激活》中的 LFT 表结构、线性转发表编程与子网激活;本系列第九篇《SM 监控与拓扑变化:选举、故障切换、扫描与重收敛》中的 Light Sweep / Heavy Sweep 与 failover。本篇不重复解释这些内容
  • 信息来源:本篇出现的全部引擎标识符(minhop / updn / dnup / file / ftree / lash / dor / torus-2QoS / nue / dfsssp / sssp / dfp / dfp2)、配置项名(routing_engine / root_guid_file / qos)、命令行选项(-R / -a / -c / -F)与日志字符串,均引自文末「参考资料」列出的 opensm(8) man page、opensm/doc/current-routing.txt、opensm/opensm/osm_ucast_mgr.c 与 NVIDIA MLNX SM 官方文档
  • 本篇不涉及:QP / RC / UD 传输层细节、组播转发表 MFT 的生成树算法、QoS 策略文件的编写语法、信用环的缓冲级数推导、交换机固件侧的转发表硬件结构

一、路由引擎的定位:它是 SM 路径计算的实现者

What — 这一节要钉死一个概念

课程开场就把这件事说得很直接:路由引擎是子网管理器用来计算最佳路径的方式(routing engines are the way paths are chosen through the physical topology from source to destination)。这句话里有三个关键词,每一个都对应一个具体的设计问题:

  1. "through the physical topology"——路径是在物理拓扑上选出来的。这意味着路由引擎的输出必然受物理连线方式约束,它不能凭空造出一条不存在的路径。
  2. "from source to destination"——路径是逐对算的。N 个节点要算 N × (N-1) 条(或有向 N × N)路径,这是 SM 初始化阶段最重的一项计算。
  3. "each routing engine uses its own algorithm, according to the existing topology"——每个引擎各有算法,且算法要适配既有拓扑。这是本篇全篇的题眼:算法与拓扑是配对关系,不是自由选择关系。

把三条合起来,路由引擎在整个子网里的位置就很清楚了——它是"拓扑"与"转发表"之间唯一的翻译器。拓扑是一张无向的图,转发表是一张按目的 LID 索引的出口端口表,中间必须有人把图变成表,路由引擎就是这个人。

路由引擎在 SM 初始化流水线中的位置

阶段 0  物理层:光纤与端口连线
============================================================
    host-01     host-02        host-11    host-12    host-13
        |           |              |          |          |
    leaf-A      leaf-A         leaf-C     leaf-C     leaf-D
        |           |              |          |          |
        +-----------+              +----------+----------+
                    |                          |
                spine-SW-A ---------------- spine-SW-B


阶段 1  拓扑发现:SM 通过 SMP 扫出上图的节点与链路
============================================================
    物理拓扑 = 一张无向图:只有节点与边,没有方向,没有优先级


阶段 2  LID 分配:交换机 + HCA 被分配了 LID
============================================================
    host-01(LID 10)  ...  host-15(LID 20)


阶段 3  路径计算:<==== 本篇的主题
============================================================
    路由引擎完成,输出是"每一对 LID 该怎么走"
                                |
                                v
    结果写进每台交换机的 LFT(线性转发表)


阶段 4  子网激活与数据面
============================================================
    包按 LFT 转发,数据面不再做任何路径决策。

    数据面没有算法。正确性在初始化那一刻就被"固化"进硬件表项,
    每个数据包只是查表。表错了,网络就错了,
    ibstat / ibnetdiscover 这类工具看不出任何异常。
设计视角 — 为什么"数据面不做路径决策"是一个刻意的选择

把上图拆开看,路由引擎的输出是一张已经算完、已经写死、逐条固化到每台交换机硬件里的表。数据面收到一个包时,只做一件事:用目的 LID 索引,查出出口端口号,转出去。它不判断拥塞、不重新评估路径、不看链路状态、也不知道这张表是谁算的。

这个设计的收益是转发延迟可预测。数据面的每一步都是定长操作——索引、查表、转发。交换机不需要为每个包做图搜索,也不需要维护任何逐包状态。这正是 InfiniBand 能做到确定性低延迟的前提:一个包在 fabric 里走过的每一跳,代价是确定的,不随流量负载波动。

代价则是:所有路径风险都被前置到了初始化那一刻。如果路由引擎算错——比如在有环拓扑上用了不防死锁的算法——那么错表会被写进每一台交换机,此后每一个包都会沿着这条错误路径走。运维侧能观测到的现象是"链路是 up 的、端口是 ACTIVE 的、ibstat 一切正常,但流量就是不通"。这类故障最难排查,根因就在这一步。

因此"改 routing_engine"从来不是一条普通配置变更。它触发的是全网每一台交换机的转发表重算、重编程、重激活。在本系列第九篇的框架下,这就是一次完整的 Heavy Sweep:拓扑发现、路径计算、节点编程、子网激活全部重来。课程因此明确警告,在没有先咨询 fabric 架构师之前改动路由算法,对 fabric 可能具有破坏性影响——这不是保守措辞,而是上述机制的直接推论。

还有一个容易被忽略的推论:路由引擎的选择必须在 fabric 建设期确定,而不是在出故障后临时切换。因为每种引擎对拓扑有硬性前提(下一节展开),临场能选得越少,就越需要在设计期把拓扑与引擎配对这件事想清楚。

本节关键记忆:1 个定位 + 1 个事实 + 1 条红线

  • 1 个定位:路由引擎 = 拓扑图到转发表的翻译器,是 SM 路径计算的唯一实现者
  • 1 个事实:数据面只查表,不做路径决策——正确性完全由初始化时固化的表项决定
  • 1 条红线:改动 routing_engine = 全网转发表重算,属于破坏性变更,课程明确要求先咨询 fabric 架构师

二、命名规则:哪些引擎绑定拓扑,哪些不绑定

What — 课程给出的命名规律,以及一处必须纠正的转写错误

课程说:这些引擎的名字通常取自它们所针对的拓扑(the names given to these engines refer to the name of the topology they were designed for)。这个命名规律是非常实用的自解释机制——看到一个引擎名,就知道它默认服务什么拓扑。课程随即点名了 fat tree、torus、dragonfly plus 三个按拓扑命名的引擎。

课程同时把 minhop 和 updn 归到另一类:Min Hop 不绑定特定拓扑,而 Up/Down 与 Fat Tree 应在胖树拓扑上使用。

这里必须纠正一处转写错误。课程口语说 "up down and fat tree should be used in fat tree topologies",但 OpenSM 官方手册对 UPDN 的定位与之相反,原文是:当子网不是纯胖树(is not a pure Fat Tree)、且可能因环导致死锁时,应选 UPDN。两者为什么相反,见下表第 2 行的说明。

引擎标识符中文名是否绑定拓扑OpenSM 官方定位
minhop 最短跳数 否,通用 基于到每个节点的最小跳数,并对路径长度做优化;未指定引擎时的默认引擎
updn 升 / 降 否,通用 同样基于最小跳数,但受 rank 规则约束;应选用于非纯胖树、且可能因环死锁的子网
ftree 胖树 是,胖树 为无拥塞的"移位"(shift)通信模式优化;应选用于对称或近似对称的胖树,各类型均可(非恒定 K、非满员、任意 CBB 比)
torus-2QoS 环面双 QoS 是,2D/3D 环面 基于 DOR,为 2D/3D 环面拓扑特化;提供两级 QoS,可在不引入死锁、不改变故障前已授予路径 SL 值的前提下绕开多链路或单交换机故障
dfp / dfp2 Dragonfly+ 是,Dragonfly+ Dragonfly+ 拓扑专用;dfp2 去掉了岛内两级胖树的限制,支持任意层数的树形岛

读表提醒:第 2 行的加红是本篇最容易踩坑的地方。

"胖树拓扑就用 Up/Down"是一个听起来完全合理、实际上会导致选型错误的说法。正确的关系是:纯胖树本身无环,不会因环死锁,所以不需要 Up/Down 那套剪枝规则;真正需要 Up/Down 的,恰恰是那些不规则、有环、可能死锁的拓扑。胖树场景要用 Up/Down 也不是不行(它会正常工作),但那是用了一个更重的工具去做一件不需要做的事,而在真正的非胖树场景下用 Min Hop 才是危险的。

关于自适应路由的适用性,课程与厂商文档的对照

课程给出一条明确约束:Up/Down 与 Fat Tree 可以在开启或关闭自适应路由的情况下运行,而 Dragonfly+ 需要自适应路由(while updn and ftree routing engines can run with or without adaptive routing enabled, dragonfly plus requires adaptive)。

这条约束在 MLNX SM 文档里能找到对应物:自适应路由管理器有一个 AR_ALGORITHM 选项,取值为 LAG / TREE / DF_PLUS,其中 TREE 的文档明确要求必须与 updn 或 ftree 路由引擎搭配运行,而 DF_PLUS 是专为 Dragonfly+ 拓扑设计的算法。课程那句"Dragonfly+ 需要自适应"的实质是:DF+ 的出口分散能力是由 AR 管理器提供的,不是由路由引擎单独提供的——这一点第九节会展开。

另有一条来自 MLNX SM 文档、且与选型直接相关的约束值得记下:当自适应路由配置为 DF_PLUS 算法时,SM 侧的 QoS 配置不被支持,即 opensm.conf 中的 qos 选项应设为 FALSE。文档同时给出了用不同 SL 分离流量的替代做法(例如 max_op_vls 设为 3 得到 4 个操作型 VL,用 VL0 与 VL2 分别承载两类应用)。

本节关键记忆:2 类命名 + 1 条改引擎红线

  • 2 类命名:minhop / updn = 通用(不绑拓扑);ftree / torus-2QoS / dfp = 绑定拓扑(按目标拓扑命名)
  • 1 条红线:未经 fabric 架构师确认,不要改动 routing_engine——可能对 fabric 造成破坏性影响
  • 1 个易错点:UPDN 是给"非纯胖树"用的,不是给胖树用的;这与课程口语转写的表述相反,以 OpenSM 手册为准

三、Min Hop:两阶段生成转发表,以及它为何防不住信用环

What — 课程对 Min Hop 的完整描述只有三句,但信息密度很高

  1. 默认引擎。课程明说:如果未指定任何路由算法,Min Hop 算法被默认调用(the minhop algorithm is invoked by default if no routing algorithm is specified)。这与 OpenSM 手册 "instead of Min Hop algorithm (default)" 完全一致。
  2. 优化目标。课程明说:Min Hop 可用于不同拓扑,其依据是到每个节点的最小跳数,在该基础上优化路径长度(minhop can be used for different topologies and is based on the minimum number of hops to each node where the path length is optimized)。这句话几乎是 OpenSM 手册 "based on the minimum hops to each node where the path length is optimized" 的逐字复现。
  3. 两阶段。课程把 Min Hop 拆成两个阶段:其一,在每台交换机上计算 Min Hop 表;其二,为每台交换机生成出口端口的 LFT(线性转发表)。

这三句合起来已经完整定义了 Min Hop 的行为契约。注意第 1 条与第 2 条之间有一个容易被忽略的推论:既然它是默认引擎,那么"fabric 一旦建好、没配 routing_engine"这个状态,就等价于"整个 fabric 一直在跑一个不防死锁的算法"。

Min Hop 的两个阶段

阶段一:计算每台交换机的 Min Hop 表
---------------------------------------------------
每个节点 s(CA 或交换机)分别做一次 BFS:
以 s 为起点,在物理拓扑图上广度优先展开
记录"从 s 到每个目的节点的最短跳数"

  s = host-11        s = host-13
  hop:  0 1 2 3      hop:  0 1 2 3
  node: H11 L-C S-B L-D H13     node: H13 L-D S-B L-C H11

阶段二:生成每台交换机的 LFT(线性转发表)
---------------------------------------------------
对每台交换机 X:遍历 LFT[X] 的每一行(LID 目的)
  1. 从"阶段一"的结果里取出经 X 转发的最短路径
  2. 把该路径在 X 上的出方向端口号写入 LFT[X][目的 LID]

  LFT[leaf-C][dest = H13 的 LID] = <连到 spine-B 的那个端口号>
  LFT[spine-B][dest = H13 的 LID] = <连到 leaf-D 的那个端口号>
  LFT[leaf-D][dest = H13 的 LID] = <连到 host-13 的那个端口号>

隐含一个重要前提
---------------------------------------------------
两台交换机的出口端口必须能"对上"。
若拓扑里有环,从 host-11 到 host-13 与从 host-13 到 host-11
的最短路就可能分别穿过对方"来时的那条边",
于是有机会互相把对方的包又送回来 —— 这就是信用环。

Min Hop 的根本缺陷,课程是直接点名的,不是推测

课程原文:Min Hop 路由引擎的问题在于它不阻止信用环,正如本单元前面已经看到的那样;信用环虽然罕见,但一旦发生,就能让网络陷入停顿(the problem with the minhop routing engine is that it doesn't prevent credit loops as we saw earlier in this unit, though rare, when credit loops happen, they can bring the network to a halt)。

这句话里有三个层次的信息,需要分开理解:

  • "doesn't prevent"——是"不阻止",不是"必然造成"。Min Hop 算出的路径有可能凑巧不构成环,也可能构成环。算法本身不提供任何保证。这与"算法保证了不会成环"是本质区别。
  • "though rare"——罕见,但这是课程对发生概率的定性描述,不是量化指标。本系列规范要求不为无实测依据的��率给出数字,因此这里不写任何发生率。
  • "bring the network to a halt"——后果是全局停摆,不是局部丢包。信用环一旦闭合,环上每个交换机都在等对端把信用还回来,而对端的包正卡在环的另一端,这是一个互相等待的死结,不是拥塞意义上的变慢。

把这三点与第一节的"数据面只查表"合起来,就能得到一个完整解释:Min Hop 不提供死锁免疫保证 → 算出的表可能构成环 → 表被固化进每一台交换机 → 数据面照表转发 → 环上的信用互相等待 → 整片网络停顿。整条链路上没有任何一个环节能拦住它,这就是为什么这不是"性能问题"而是"可用性问题"。

机制视角 — 为什么"最短跳数"这个优化目标本身就无法排除信用环

先看信用环成立的物理条件。InfiniBand 链路层是基于信用的流控:发送侧为每个虚拟通道维护一组发送缓冲,只有当它收到对端授予的信用时才能发包。当 A 交换机已把信用全授予 B,B 又把信用全授予 C,C 再把信用全授予 A 时,就形成了信用依赖环。此时环上任意一个节点想发包,都要等环上其他节点先消费掉缓冲释放信用,而那些包又都在等自己前面的人——死锁形成。

关键在于:信用依赖环是"端口—缓冲"层面的事实,与路径长度无关。只要 A 发往 C 的包经由 B 转发,且 A 与 B、B 与 C 之间的缓冲分配形成环状的等待关系,环就成立了。这条路径是 1 跳还是 5 跳,对死锁没有任何区别。

再看 Min Hop 的优化目标与死锁免疫之间的关系。Min Hop 的目标函数是"跳数最少"。最短跳数是一条纯局部目标:对每对源宿,独立地找跳数最少的走法。它不对"多对源宿的路径合起来会不会成环"做任何全局约束。而在有环的拓扑里,逐对独立取最短路,恰恰是最容易让不同流量的路径互相咬合成环的方式——因为每条路径单独看都"最优",合起来却可能构成闭合回路。

所以准确的说法是:Min Hop 不是"会导致信用环",而是"对信用环不做任何排除"。在纯胖树这种无环拓扑上,Min Hop 算出的所有最短路合起来天然不可能成环(因为图本身就是树,树里不存在环),所以它在那里是安全的。危险恰恰出现在"拓扑有环"这个前提上。这就把问题转化成一个选型问题:我的拓扑有没有环?有环就必须换成能防死锁的引擎。

这一节的推论直接决定了第二节那张表怎么用。判断 Min Hop 是否可接受,只需要问一个问题:我的子网拓扑是无环的吗?如果是一个严格意义上的树(每对节点间只有一条路径),Min Hop 安全;如果存在任何环路,就必须用 UPDN 或其他死锁免疫引擎。这个判据比"是不是胖树"更精确,因为非对称的胖树也可能有环,而某些不是胖树的多层结构反而无环。

本节关键记忆:3 句定义 + 1 个缺陷 + 1 个判据

  • 3 句定义:默认引擎(未配 routing_engine 时启用)/ 目标是最小跳数并优化路径长度 / 分两阶段:先算 Min Hop 表,再生成 LFT 出口端口
  • 1 个缺陷:不阻止信用环;罕见但一旦发生可致整网停顿
  • 1 个判据:拓扑无环 → Min Hop 可用;有环 → 必须换死锁免疫引擎

四、Up/Down 的三阶段:找根、赋秩、生成转发表

What — 课程给出的五个步骤,以及每一步在 OpenSM 里对应什么

课程明说:Up/Down 算法最重要的特点是,它被设计用来阻止子网中的环导致死锁(most importantly, and unlike minhop, the up down algorithm is designed to prevent deadlocks from occurring in loops of the subnet)。与 Min Hop 一样,Up/Down 走的也是两端点之间的最短可用路径。差别在于它多了一套 rank 体系与一条剪枝规则。

课程把算法拆成五个步骤。这五步在 OpenSM 文档里有精确对应的表述,下面把课程口述与 OpenSM 文档的三个阶段并排列出,便于核对:

课程五步骤 ↔ OpenSM 官方三阶段 对照

  1. 课程步骤 1:从根交换机开始编排全网,根交换机称为 rank 0
      → OpenSM 阶段 1:自动探测根节点(auto-detect root nodes)
  2. 课程步骤 2:找出所有距根一跳的交换机,标记 rank 1
      → OpenSM 阶段 2:rank 排序过程(ranking process),用 BFS 递增赋秩
  3. 课程步骤 3:发现距根两跳的交换机,标记 rank 2,重复直到所有交换机都被赋予距离
      → 仍属 OpenSM 阶段 2,是同一个 BFS 过程的延续
  4. 课程步骤 4:找出任意两端点之间的所有可能最短路径
      → OpenSM 阶段 3:设置 Min Hop 表,从每个节点跑 BFS,按 rank 规则与 GUID 更新途经交换机的 FDB
  5. 课程步骤 5:丢弃任何包含"从 rank n 交换机到 rank n+1 交换机,再回到 rank n"这一跳的路径
      → 仍属 OpenSM 阶段 3,是 BFS 过程中施加的剪枝规则

为什么 OpenSM 文档只说三个阶段,课程却说五个步骤?

因为课程是从"交换机距离根多远"这个直觉视角逐步叙述的,而 OpenSM 文档是按代码里的实际执行边界划分的。课程的步骤 2 与步骤 3(找一跳远的、找两跳远的)在实现里就是同一个 BFS 循环的相邻两轮,所以文档合并成"阶段 2";课程的步骤 4 与步骤 5(找最短路、丢弃违规路径)在实现里也是同一个 BFS 过程中的两个动作。

两个说法都对,只是切面不同。理解算法时按课程的五个步骤走最直观;排查 OpenSM 日志与源码时按文档的三个阶段定位更准确。

阶段一:找根节点(root nodes)

无环拓扑中,"距离所有节点都最远的那层交换机"就是根。
OpenSM 的自动探测方法是统计法:
      对每台交换机,以"从它到各 CA 的跳数"为列,
      统计出现次数,画成直方图;
      如果某一列明显高于其他列,该交换机被标为根节点。

统计法 = 可能失败。OpenSM 文档写得很直白:
      "Since the algorithm is statistical, it may not find any root nodes."
若用户也没提供 GUID 文件,则退回 Min Hop。

所以 root_guid_file 这个参数不是"可选优化",是"确定性保障"。


阶段二:BFS 赋秩(ranking process)

  所有根交换机      rank = 0
  从 rank 0 出发做 BFS:
      距根 1 跳的交换机     rank = 1
      距根 2 跳的交换机     rank = 2
      距根 3 跳的交换机     rank = 3
      ... 直到每台交换机都被赋予一个 rank

rank 的语义:一个整数,标注这台交换机"离根有多远"。

阶段二的产物(示例:三层结构)
------------------------------------------------------
      rank 0           rank 1            rank 2
   +----------+    +----------+     +----------+
   | spine-1  |    |  leaf-1  |     |  host-1  |
   | spine-2  |    |  leaf-2  |     |  host-2  |
   +----------+    |  leaf-3  |     |  host-3  |
                   |  leaf-4  |     +----------+
                   +----------+


阶段三:生成转发表(min hop table setting)

每个节点(CA 或交换机)各跑一次 BFS。
路径中每经过一台交换机,就按 rank 规则更新该交换机的 FDB 表项。

关键:更新 FDB 时施加剪枝规则(见第五节)
  有剪枝 = 这就是 Up/Down
  无剪枝 = 这就是 Min Hop

根 GUID 文件的两个实用细节,OpenSM 文档有明文

细节一:文件格式与容错。文档规定:一个合法的 GUID 文件每行指定一个 GUID,格式不合法的行会被丢弃(a valid guid file specifies one guid in each line. Lines with an invalid format will be discarded)。这意味着写错格式不会让 SM 报错停机,而是让那一行被静默忽略——结果是那个根节点没被识别,可能进一步导致自动探测接管、甚至整个 UPDN 失败。排查时必须逐行核对 GUID 的位数与前导零。

细节二:可以填 CA 的 GUID。文档说明:用户应当指定根交换机的 GUID,但也可以指定 CA 的 GUID;如果指定的是 CA,OpenSM 会使用把该 CA 接入子网的那台交换机的 GUID 作为根节点(it is also possible to specify CA guids; OpenSM will use the guid of the switch (if it exists) that connects the CA to the subnet as a root node)。这是一个很实用的容错设计:如果运维手头只有主机的 GUID 而拿不到交换机 GUID,算法依然可用。

再补一条与 Fat Tree 相关的约束:如果不提供根 GUID 文件,拓扑必须是一个纯胖树且满足一组具体条件——OpenSM 文档列出了树秩必须在 2 到 8 之间(含端点)、同秩交换机的上行/下行端口组数量需满足对称性要求、所有 CA 必须处于同一树秩等等。不满足这些条件时,UPDN 同样会走到"找不到根节点"这条路径上。

本节关键记忆:3 阶段 + 1 个统计法风险 + 2 个文件细节

  • 3 阶段:找根(统计直方图,可能失败)→ BFS 赋秩(根为 rank 0,逐跳递增)→ 按 rank 规则跑 BFS 生成 FDB
  • 1 个统计法风险:自动探测可能一个根都找不到;此时若未提供 GUID 文件,OpenSM 退回 Min Hop
  • 2 个文件细节:每行一个 GUID,格式错误行被静默丢弃 / 允许填 CA GUID,会自动转成其接入交换机 GUID

五、Up/Down 的剪枝规则:为什么"先降后升"的路径被丢弃

What — 课程给出的唯一一条硬规则

课程把规则说得很简洁:Up/Down 算法找出任意一对端点之间的所有可能最短路径之后,丢弃任何包含"从 rank n 交换机跳到 rank n+1 交换机、然后再跳回 rank n"这一跳的路径。换句话说,它丢弃任何先"向下远离根"、然后再"向上朝向根"的路径(it discards any path that goes down away from the roots and then up toward the roots)。

把这条规则翻译成"方向"语言:向上 = rank 递增(靠近根),向下 = rank 递减(远离根)。于是规则可以表述为——路径中不允许出现"向下、然后向上"的转折。

课程原例:switch A 到 host 15 / host 16
---------------------------------------------------
拓扑:三层结构,A 是中间的交换机

            +--------+
            | spine  |  rank 0
            +--------+
             /      \
            /        \
     -------+  +--------+
     sw-A   |  | sw-B   |     rank 1
     -------+  +--------+
     |    |       |    |
     |    |       |    |
     -----+  +------+   rank 2
    host15|  |host16|
     -----+  +------+


     sw-A -> host 15:  合法
-----------------------------------------------------
      sw-A  --向上-->  spine  --向下-->  host 15
       rank1           rank0            rank2

      方向序列:   up  然后  down
      判定:       只有一次转折,且是"先上后下",不含"下后上"
      结论:       VALID


     sw-A -> host 16:  非法
-----------------------------------------------------
      sw-A  --向下-->  sw-B  --向上-->  spine  --向下-->  host 16
       rank1         rank1*     rank0            rank2

      方向序列:   down  然后  up  然后  down
                   ^^^^^^^^^^^^^
                   这一段就是被丢弃的那一跳:
                   "从 rank n 到 rank n+1,再回到 rank n"
      判定:       存在"下后上"转折
      结论:       FORBIDDEN

注意:非法路径的中转跳数更少(2 跳 vs 3 跳中转),
      但 Up/Down 宁可绕远也不走它。
      死锁免疫的代价就是路径不再总是全局最短。
结构视角 — 为什么"禁止下后上"这一条规则就足以切断全部信用环

先看被允许的路径形状有哪些。把方向序列里不允许出现"down 转 up"这个条件施加上去,剩下的合法形状只有三种:

  • 纯向上:up up up ... up——一直靠近根,直到抵达根。适用于源和目的分处根的两侧。
  • 纯向下:down down down ... down——一直远离根。适用于源在上、目的在下。
  • 先上后下:up ... up 然后 down ... down——单次转折,且转折点是最高 rank。适用于源和目的在同一子树下。

再证明这三种形状不可能构成环。观察每种形状的 rank 序列:纯向上是单调递增,纯向下是单调递减,先上后下是先单调递增到峰值、再单调递减。三者有一个共同性质——沿路径走,rank 先升后降,峰值只出现一次,且任何一条边只可能被"顺着 rank 递增方向"或"顺着 rank 递减方向"经过,不会两个方向都经过。

这就给出了死锁免疫的严格论证。信用环的本质是:存在一组流,构成一个"每个节点都在等对端释放信用"的闭合等待关系。这种闭合关系必须建立在"某条边被双向使用"之上——A 发给 B 的包经由某条边,同时 B 发给 A 的包也经由同一条边,信用才能绕成圈。而 rank 的单调性保证了任何一条边只承载单一方向的流,等待关系因此无法闭合,信用环在结构上不可能形成。

这就是 Up/Down 与 Min Hop 的全部差别。两者跑的都是最短路 BFS,看的是同一张图。Min Hop 缺少的只是这条剪枝规则:它会把"先下后上"的路径也算进候选,于是在有环拓扑里,逐对独立取最短路的结果可能让不同流量的路径互相咬合。加上剪枝之后,允许的路径形状被限制在一个无环依赖的集合内,死锁免疫成为结构性保证,而不是概率。

但要如实指出这个保证的代价:路径不再总是全局最短。第五节的例子里,从 A 到 host 16 的非法路径中转跳数更少,Up/Down 选择绕远。在无环拓扑上这个代价不会出现(因为唯一的路径本来就是合法的);代价只在有环拓扑上显现——而这正是你选用 Up/Down 的原因。用"路径可能稍长"换"整网不停摆",这个交换在任何有死锁风险的 fabric 上都是划算的。

本节关键记忆:1 条规则 + 3 种合法形状 + 1 个代价

  • 1 条规则:丢弃任何"先降后升"的路径(从 rank n 到 rank n+1 再回 rank n)
  • 3 种合法形状:纯向上 / 纯向下 / 先上后下(峰值唯一)——三者 rank 序列都先升后降,故任何边只被单向使用
  • 1 个代价:路径可能不是全局最短;但这个代价仅在有环拓扑上出现——而那正是选用 Up/Down 的前提

六、Up/Down 如何切断信用环:双层胖树实例

What — 课程用一个更贴近生产的双层结构演示规则生效的结果

第五节的三层例子说明规则本身;本节用只有 spine 与 leaf 两层的胖树,演示规则如何成对地作用于双向流量。因为在两层结构里,"向上"必然是 leaf→spine,"向下"必然是 spine→leaf,方向判定最直观,信用环的成环条件也最容易看清。

双层胖树:四条路径的合法性与成环可能性

         spine-A (rank 0)              spine-B (rank 0)
        /            \                /            \
       /              \              /              \
  leaf-1 (rank 1)  leaf-2 (rank 1)   leaf-3 (rank 1)  leaf-4 (rank 1)
   |       |          |       |         |       |        |       |
  H10     H11        H12     H13       H14     H15      H16     H17


四条被考察的路径
===============================================================

路径 1:host 11 -> host 12        合法
---------------------------------------------------------------
        H11 -> leaf-1 -> spine-A -> leaf-2 -> H12
              up         (peak)     down
        方向:up  然后  down
        判定:VALID     "只上后下",即从叶交换机向上到脊交换机,
                        再从脊交换机向下到叶交换机

路径 2:host 12 -> host 11        合法
---------------------------------------------------------------
        H12 -> leaf-2 -> spine-A -> leaf-1 -> H11
              up         (peak)     down
        方向:up  然后  down
        判定:VALID

> 路径 1 与路径 2 互为逆行且都合法,这一点至关重要:
       它们使用同一条物理链路,但方向相反(一条 up 一条 down),
       信用流向也相反,因此不构成信用环。


路径 3:host 10 -> host 13        非法
---------------------------------------------------------------
        H10 -> leaf-1 -> spine-A -> leaf-3 -> spine-B -> leaf-4 -> H13
              up         (peak)     down      up        down
                                    ^^^^^^^^^
                                    出现了 down -> up
        判定:FORBIDDEN   "下后上"
        风险:若允许此路径,spine-B 收到 leaf-3 送来的包后再
              送回 spine-A 侧,spine-A 与 leaf-3 之间的信用
              互相等待,构成潜在信用环。


路径 4:host 13 -> host 10        非法
---------------------------------------------------------------
        H13 -> leaf-4 -> spine-B -> spine-A -> leaf-1 -> H10
              up        (peak)     down     up
                                     ^^^^^
        判定:FORBIDDEN
        理由同上。


结论
===============================================================
      spine 的流量(路径 3、4:H10  H13)被整类禁止。
      课程说明:这类路径被识别为潜在的信用环,
      因此不允许被写入交换机转发表。

直接后果:host 10 与 host 13 之间没有流量可达。
      这不是故障,这是 Up/Down 的设计结果。

必须如实指出这个设计后果:host 10 到 host 13 之间不通

课程明确陈述了这个后果:结果是 host 10 与 host 13 之间无法路由任何流量(the consequence is that no traffic can be routed between nodes 10 and 13),而理由是:如果发生信用环,可能让整个 fabric 陷入死锁。

这个结论非常重要,因为它揭示了 Up/Down 的一个常被忽略的前提:它的可达性依赖于"跨 spine 流量是否必须存在"。在标准胖树里,任意两台叶交换机之间本来就有多条等价的最短路——H10 到 H13 既可以走 spine-A 也可以走 spine-B。Up/Down 的规则把"经不同 spine"这一类路径禁掉了,于是这类流量就彻底没有合法路径了。

那为什么标准胖树还普遍部署 Up/Down?因为课程第五节已经说明:当拓扑是纯胖树(无环)时,从 H10 到 H13 的最短路只有一条——它必然是"上到某一个 spine、再下到目标 leaf",也就是"先上后下"的合法形状。纯胖树里根本不存在"下后再上"的路径,因为图里没有环。路径 3 之所以非法,前提正是拓扑允许 spine-A 与 spine-B 之间存在某种替代走法(例如两台 spine 之间互连,或有第三条上行路径),那已经是非纯胖树的结构了。

因此使用 Up/Down 前必须做一次拓扑核查:如果你的拓扑是严格的无环树,Up/Down 与 Min Hop 等价、都能用;如果拓扑有环,则要确认被禁止的那类流量在业务上确实不需要,否则会出现"某些主机之间不通"的现象——而这在故障排查中极容易被误判为链路故障或配置错误。

设计要点 — 逆行对称性:为什么路径 1 与 2 都合法才是关键

初看之下,"两条路径都合法"似乎理所当然——它们互为逆行。但把上一节的 rank 单调性论证用在这里,会得到一个更强的结论:

在双层胖树中,leaf→spine 永远是"向上"(rank 递增),spine→leaf 永远是"向下"(rank 递减),这个方向判定与流量方向无关,只与链路的物理层级有关。

因此 H11→H12 与 H12→H11 虽然走同一条物理链路,但在 rank 语义下,H11 侧的出口是"上行",H12 侧的出口也是"上行"——两条路径各自都只是"上、然后下"的单次转折形状,都不含下后上。同时,因为两条路径在每条链路上都是相反方向通过的,信用在同一条链路上也是反向流动的,无法构成互相等待的闭合环。

这解释了为什么 Up/Down 在双层胖树上既安全又高效:它没有牺牲可达性(同 spine 的流量全通),也没有牺牲无死锁性(同一条链路上的双向流量信用方向相反)。真正的代价只出现在"需要绕行到第二个 spine"的场景——而那已经意味着拓扑不是纯胖树。

本节关键记忆:4 条路径 + 1 个直接后果 + 1 个使用前提

  • 4 条路径:H11↔H12 合法(同 spine,逆行但都只上后下)/ H10↔H13 非法(跨 spine,含下后上)
  • 1 个直接后果:被禁止的那对节点之间完全无流量可达——这是设计结果,不是故障
  • 1 个使用前提:纯胖树下 Up/Down 与 Min Hop 等价;有环拓扑下必须确认被禁流量在业务上不需要
  • 1 个误判提醒:ibstat 一切正常但部分主机不通,先怀疑路由引擎可达性,再怀疑链路

七、Fat Tree:端口序位对称性带来的出口负载均衡

What — Fat Tree 引擎与 Up/Down 的关系,以及它多出来的那一件事

课程对 Fat Tree 的定位是:它在节点序位(node ordering)已知且固定的对称拓扑上优化流量吞吐,应当在对称或近似对称的各类胖树子网中选择它(it optimizes the traffic throughputs in fully symmetrical topologies where the node ordering is known and fixed according to a design topology. It should be chosen if a subnet is a symmetrical or almost symmetrical fat tree of various types)。

课程紧接着指出了它与 Up/Down 的继承关系:Fat Tree 路由引擎沿用与 Up/Down 算法相同的做法来避免信用环(fat tree routing engine follows the same approach used by the up down algorithm to avoid credit loops)。

所以 Fat Tree = Up/Down 的剪枝规则 + 一项额外能力。额外的那一项,就是本节的核心:利用端口序位的对称性做出口负载均衡。

机制视角 — 端口序位这个"额外信息"是从哪里来的,为什么它值钱

先说清楚什么是端口序位。在对称胖树中,每台叶交换机用同一个端口编号连向每一台脊交换机(each of the leaf switches is connected with the same port index to each of the spine switches)。课程的例子是:每台叶交换机都通过端口 1 连到左侧的 spine 交换机 A,通过端口 2 连到右侧的 spine 交换机 B。

这个信息为什么值钱?因为它是一个纯粹由物理布线约定提供的一致性保证。算法在计算路径时,知道"从 leaf-1 出去到 spine-A 和从 leaf-2 出去到 spine-A,用的是它们各自编号相同的那个端口"。而 Min Hop 与 Up/Down不知道这件事——它们只知道"叶 k 连到脊 j 有一条链路",不知道这条链路在各台叶交换机上编号是否一致。

有了这个一致性保证,就能定义一个强得多的均衡判据。课程给出两种行为的对比:

  • 默认行为:所有叶交换机用同一个出口端口去往同一个目的 LID。课程举例——所有叶交换机都使用出口端口 1 去往目的 LID 12。如果有多条流的目的都是 LID 12,所有叶交换机都会把流量转发给 spine 交换机 A,这会导致拥塞(which can lead to congestion)。
  • 更好的策略:给每台叶交换机选不同的出口端口。课程指出——因此经由不同的脊交换机路由,从而实现流量负载均衡(choose a different exit port for each of the leaf switches, therefore routing via a different spine switch that would lead to traffic load balancing)。

把两种行为的后果并列,差别就非常直观。默认行为下,目的 LID 12 的全部入口流量压在 spine-A 一条路径上,spine-A 成为热点,spine-B 完全空闲,而每条叶->spine 链路的利用率也只有一半。改成按叶交换机分散出口之后,流量被摊到两台脊上,两条路径都满载。

关键在于:这两种行为产出的路径跳数完全相同。从 leaf-2 经 spine-A 到 LID 12 和从 leaf-2 经 spine-B 到 LID 12,中转跳数都是 1 跳 spine,总跳数一样。换句话说,负载均衡在这个场景下是一个"免费"的改进——不牺牲任何路径长度,只是把等价路径重新分配。这也解释了为什么 OpenSM 文档说 Fat Tree 是为"无拥塞的移位(shift)通信模式"优化的:移位通信的特征正是"大量节点同时向同一个目的发数据",默认的单出口行为在这种模式下会立刻退化。

最后必须说清楚这个能力的前提条件。端口序位对称性不是自动成立的——它要求管理员按一致的约定完成物理布线。OpenSM 文档对 Fat Tree 的适用条件给出了一组明确要求,包括:树秩在 2 到 8 之间、同秩交换机的上行与下行端口组数量需满足对称性、同秩交换机每个端口组内的端口数需一致、以及所有 CA 必须处于同一树秩。若未提供根 GUID 文件,这些条件是 UPDN/Fat Tree 能正常工作的硬前提;不满足时算法可能探测不到根,进而回退。

Fat Tree 的出口选择:默认行为 vs 负载均衡行为

前提,端口序位约定:每台 leaf 用 port1 接 spine-A,port2 接 spine-B

           port1        port1        port1        port1
  leaf-1 --------+  leaf-2 --------+  leaf-3 --------+  leaf-4
           port2        port2        port2        port2
                  \         |         |         /
                   +--------+--------+--------+
                            |        |
                       +--------+   +--------+
                       |spine-A |   |spine-B |
                       +--------+   +--------+
                            |        |
                            +--------+
                                 |
                           dest LID 12
                              (host 12)


默认行为(所有 leaf 选同一出口)
============================================================
  leaf-1  --port1-->  spine-A  -->  LID 12
  leaf-2  --port1-->  spine-A  -->  LID 12
  leaf-3  --port1-->  spine-A  -->  LID 12
  leaf-4  --port1-->  spine-A  -->  LID 12

结果:spine-A 承载 100% 流量   [|||||||X|X|X|X|X|X|X]
      spine-B 承载   0% 流量   [|         ]
      每条 leaf->spine 链路利用率约 50%

课程结论:which can lead to congestion


负载均衡(每台 leaf 选不同出口)
============================================================
  leaf-1  --port1-->  spine-A  -->  LID 12
  leaf-2  --port2-->  spine-B  -->  LID 12
  leaf-3  --port1-->  spine-A  -->  LID 12
  leaf-4  --port2-->  spine-B  -->  LID 12

结果:spine-A 承载 50% 流量    [||||X|X|X|         ]
      spine-B 承载 50% 流量    [|         |||X|X|X]
      两条 spine 路径都被利用

课程结论:routing via a different spine switch
            that would lead to traffic load balancing

两种行为的路径跳数完全相同。
      负载均衡在此不付出任何路径长度代价。

两条与 Fat Tree 相关的 OpenSM 约束,配置时容易踩

约束一:Fat Tree 不支持 LMC > 0。OpenSM 文档在 Fat Tree 一节末尾写明:注意 Fat Tree 路由不支持 LMC > 0;如果指定了 LMC,将改用默认路由算法(Note: LMC > 0 is not supported by fat-tree routing. If this is specified, the default routing algorithm is invoked instead)。这意味着在配了多路径主机(LMC 大于 0)的子网里选 ftree,实际生效的会是 Min Hop——而这个回退在日志里的表现与"引擎正常工作"完全不同,必须主动核对。

约束二:Fat Tree 的计算节点列表可显式指定。文档说明:用 -u / --cn_guid_file 提供计算节点列表;如果不提供,所有 CA 都被视为计算节点。文档进一步指出:使用 cn_guid_file 允许非 CN 节点处于胖树的不同层级;在这种情况下,不保证 Fat Tree 会在两个非 CN 节点之间路由。要解决该问题,可以用 -G / --io_guid_file 指定这些节点列表,它们将被允许反向使用交换机有限次数(由 -H / --max_reverse_hops 指定)。

关于 max_reverse_hops,OpenSM 文档的警告必须原样传达:文档指出,使用 max_reverse_hops 会创建"逆流方式"(counter-stream way)的路由,此选项绝不应被用于连接彼此间有高带宽流量的节点,只应用于为高可用等目的提供连通性;并且反向路由理论上可能引起信用环。文档在此处加了一句 Use these options with extreme care!。这是全套 OpenSM 文档里少数几处直接点名"可能引起信用环"的地方,与本篇第五、六节的主题直接呼应。

本节关键记忆:1 个继承 + 1 个额外能力 + 2 条约束

  • 1 个继承:ftree 沿用 Up/Down 的剪枝规则防信用环,因此同样具备死锁免疫
  • 1 个额外能力:利用端口序位对称性做出口负载均衡——默认所有叶交换机选同一出口会拥塞,分散出口可摊到各脊,且跳数不变
  • 2 条约束:LMC > 0 时 ftree 不生效,会退回默认算法 / max_reverse_hops 理论上可引起信用环,文档要求极端谨慎

八、Torus-2QoS:面向 2D/3D 环面的无死锁路由

What — 这是转写稿里错得最厉害的一个引擎名

转写稿反复出现 "taurus" 与 "torres",正确名称是 Torus(环面),OpenSM 中的引擎标识符为 torus-2QoS。课程对这个引擎的定位是:它是为大规模 2D/3D 环面 fabric 设计的路由算法,具有处理环面固有绕线特性的独特能力(torus is a routing algorithm designed for large scale 2D/3D torus fabrics. This algorithm has the unique capability of being able to handle the loop wiring nature of a torus)。

"loop wiring"(绕线特性)是理解 Torus 的关键:普通胖树的连线构成树、无环;而环面拓扑里,同一个维度上的首尾两台交换机要直接相连,物理上就形成了环。第五节的结论在这里立刻适用——有环就必须用死锁免疫引擎。Torus-2QoS 就是为这种拓扑准备的。

设计视角 — 为什么环面拓扑必须换算法,以及 Torus-2QoS 提供的三重能力

先确认环面为什么有环。在一维环面里,节点 0、1、2、…、N-1 首尾相连,节点 N-1 与节点 0 之间有一条链路。在三维环面里,每个坐标维度上都各有一个这样的闭合环。这些环是拓扑定义的一部分,不是布线的错误。换言之,环面拓扑的环是"设计出来的必然",不是"接错了"的结果。

这直接排除�� Min Hop。按第三节的判据:拓扑有环 → 必须换死锁免疫引擎。而且环面有环的维度不止一个,二维环面有两个、三维环面有三个,可能成环的方向组合比单环拓扑多得多。

再说明"QoS"这两个字为什么出现在引擎名里。课程解释了 QoS 在这里的意义:QoS 很重要,因为它允许不同流量类型或服务级别拥有各自专用的网络资源,这些资源不会干扰来自其他服务级别的流量(quality of service is important as it allows different traffic types or service levels their own dedicated network resources that won't interfere with traffic from other service levels)。"2QoS" 的含义就是"两个 QoS 级别"——对应 OpenSM 文档里那句 "supporting two quality of service (QoS) levels"。

最后把课程列出的能力清单与 OpenSM 官方描述对齐。课程给了四条,官方文档给了一句更凝练的总结:

  • 能力一:支持信用环免疫(无死锁路由)。课程:"it supports credit loops, free routing"(原文如此,指无信用环的自由路由);官方文档:"provides deadlock-free routing"。这是 Torus-2QoS 存在的基本理由。
  • 能力二:两级 QoS。课程:"two levels of quality of service";官方文档同义。
  • 能力三:绕开故障且不改变已授予的 SL 值。课程原话:能绕开单个交换机故障和/或多条链路故障,而不会引入信用环,也不会改变数据包已被授予的 SL 值(without introducing credit loops or changing a packet's SL value)。官方文档表述为 "able to route around multiple failed fabric links or a single failed fabric switch without introducing deadlocks, and without changing path SL values granted before the failure"。
  • 能力四:自愈与可扩展性。课程进一步说明:路由被组织成可以自愈并绕开多根线缆故障乃至整台交换机故障的形式;这种重路由由子网管理器自动完成,独立于在其上运行的应用;并且运行时间很短,随 fabric 规模增大具有良好的扩展性。

能力三里的"不改变 SL 值"值得单独强调,因为它是一个容易被忽略的强约束。SL(Service Level,服务级别)参与 QoS 调度与 VL 仲裁。如果故障绕行改变了包的 SL 值,那么故障前后同一条流的调度行为就不一致——原本属于高优先级的流量可能在绕行后落到低优先级队列上。Torus-2QoS 承诺不改变它,说明绕行是在保持 QoS 语义的前提下完成的,而不是简单地重算一条最短路。

能力四里"由 SM 自动完成、独立于应用"这一句,与本系列第九篇的框架是同一件事的两种说法:故障检测与重路由由 SM 的扫描与重收敛机制驱动,不需要应用层感知。但第九篇讲的重收敛会重算转发表,而本篇讲的是 Torus-2QoS 承诺绕行后 SL 不变——把两篇合起来读可以看出:"绕开故障"的能力来自路由引擎的算法设计,而"触发重算"的能力来自 SM 的监控机制,两者协作才形成完整的容错路径。

最后给出激活方式,这是配置时唯一需要的正确姿势。OpenSM 文档明确写出:用 -R torus-2QoS -Q 或 -R torus-2QoS,no_fallback -Q 来激活 torus-2QoS 算法。注意这里必须有 -Q(等价于配置文件中的 qos TRUE),因为该算法依赖 QoS 能力。而 no_fallback 的作用是禁止在所有配置引擎都失败时回退到 Min Hop——在环面拓扑上这个回退是危险的,因为它会重新引入不防死锁的引擎。

两个与 Torus-2QoS 配套的 OpenSM 配置事实

其一:它需要自己的配置文件。OpenSM 文档说明:--torus_config 选项定义 torus-2QoS 路由引擎所需额外配置信息的文件名,默认名为 /etc/opensm/torus-2QoS.conf。该文件用于配置环面各维度的 radix(节点数)等拓扑参数。

其二:它有独立的 man page。OpenSM 文档在 Torus-2QoS 一节末尾注明 see torus-2QoS(8) for full documentation。配置环面 fabric 时应查该页,而不是仅依赖 opensm(8) 的概览。

把这两条与第二节的红线合起来看:课程说"未经咨询不要改动路由引擎",而 Torus-2QoS 是需要额外拓扑配置文件、且必须开启 QoS 的引擎,是全套引擎里配置最复杂的一个。这正是那条红线存在的原因——它是唯一一个"配错了会静默退回到不防死锁引擎"的场景。

本节关键记忆:1 个名称纠正 + 4 项能力 + 1 条激活命令

  • 1 个名称纠正:taurus / torres → Torus,标识符是 torus-2QoS
  • 4 项能力:无死锁路由 / 两级 QoS / 绕开多链路或单交换机故障且不改变已授予 SL / 自动自愈且运行时间短、可扩展
  • 1 条激活命令:opensm -R torus-2QoS -Q——-Q 不能省;配套 /etc/opensm/torus-2QoS.conf

九、Dragonfly+:Min Hop + 1 与自适应路由的耦合

What — Dragonfly+ 与前面所有引擎的根本差异:它主动选择"非最短路"

课程开门见山:为了在不同流量模式下获得最大吞吐,Dragonfly+ 路由引擎(DFP)需要非最短多路径路由(to achieve maximal throughput for different traffic patterns, dragonfly plus routing engine or dfp requires non minimal multipath routing)。

接下来是本引擎的核心机制,课程给了一个精确的定义:非最短路径引入 Min Hop + 1 路由;非最短跳路径的选择由交换机管理器基于出口队列负载、增强自适应路由特性来完成(a non minimal path introduces minhop plus one routes. Non minimal hop path selection is done by the switch manager based on the egress Q load enhancing the adaptive routing feature. That is, the sending switch decides whether to choose a minhop or minhop plus one based on how busy the ports are)。

把这段话拆成三层,每一层都很重要:

  1. Min Hop + 1 = 比最短路多一跳。这是路径长度的定义。
  2. 选择权在发送交换机手里(the sending switch decides)——不是 SM 预先把两条路径都写进表里,而是交换机在运行时决定走哪条。这是本引擎与前三节的根本架构差异。
  3. 判据是端口忙闲程度(based on how busy the ports are)——这就是自适应路由要解决的问题。
Dragonfly+:group 之间的 Min Hop 与 Min Hop + 1

Dragonfly+ 的组(group)结构:组内两级胖树,组间全连接

           +-- group A --+          +-- group B --+          +-- group C --+
           |             |          |             |          |             |
      +------+      +------+    +------+      +------+    +------+      +------+
      |leaf  |      |leaf  |    |leaf  |      |leaf  |    |leaf  |      |leaf  |
      +------+      +------+    +------+      +------+    +------+      +------+
             \          /               \          /               \          /
              \        /                 \        /                 \        /
               +------+                   +------+                   +------+
               |spine |                   |spine |                   |spine |
               +------+                   +------+                   +------+
           group B
                      (绿色路径,课程原文用绿色表示)
          中转跳数:最短

路径二:绕经中间组(Min Hop + 1)
---------------------------------------------------------------
          group A  --->  group C  --->  group B
                      (橙色路径,课程原文用橙色表示)
          中转跳数:比最短路多 1 跳


决策发生在发送交换机上
===============================================================
          情形 1:直连链路空闲
              group A 的发送交换机 --> 选择直连
              => Min Hop

          情形 2:直连链路拥塞
              group A 的发送交换机 --> 改经 group C
              => Min Hop + 1   (多付一跳,换掉拥塞)

课程原话:
          "the sending switch can forward the traffic via group c
           as indicated by the orange path. this introduces an extra
           hop to the path, thus referred to as minhop plus one."
架构视角 — 为什么 Dragonfly+ 把决策从 SM 下放到了交换机

先回顾前三节引擎的决策模式。Min Hop、Up/Down、Fat Tree 的共同点是:路径在 SM 初始化阶段被完整算完,固化进每台交换机的 LFT,数据面只查表。第一节已经说明这个设计的收益是延迟可预测,代价是对拥塞完全无能为力——表里那条唯一的最短路,就算拥塞到丢包,交换机也不会改道。

Dragonfly+ 换了一个位置放决策。课程明确说选择由发送交换机在运行时做出,依据是出口有多忙。这意味着路径不再由 SM 一次性确定,而是由每一跳的交换机根据当时的实际情况确定。这是自适应路由(Adaptive Routing)的本质。

为什么 Min Hop + 1 在拓扑上是可行的。看第九节的图:group A 到 group B 有直连,但 Dragonfly+ 的组间连接是全连接的——A 也能经 C 走到 B。这种"多组可互达"的结构,正是拓扑为绕行预留的空间。相比之下,标准胖树里 leaf 之间只能经 spine 绕行,而 Up/Down 又恰恰禁止了"经另一个 spine 绕行"这类路径(第五、六节)。换句话说,在标准胖树上,绕行能力与死锁免疫是有冲突的;Dragonfly+ 的拓扑通过组间全连,让绕行路径自然存在,从而把这个冲突解开了。

但这带来一个必须正视的新问题:如果允许绕行,会不会产生第五节那种"下后上"路径?会。所以 Dragonfly+ 必须用另一套机制来处理死锁——它没有沿用 Up/Down 的剪枝规则,而是用 VL 递增。这正是第十节的内容。两种机制殊途同归,目标是同一个:在允许绕行的前提下,仍然不形成信用环。

最后说清楚这个设计的收益与代价,这也是课程把它定性为"最大吞吐"的原因。收益是拥塞自适应:拥塞出现时业务不必等重收敛,几毫秒内就能改道。代价是延迟不再完全确定——同一条流的不同包可能走不同长度的路径,路径本身带上了排队时延的不确定性。对于追求确定性低延迟的存储类流量,这个代价需要用 QoS 把流量分离后再评估(而 MLNX 文档又明确指出 DF_PLUS 算法下 SM 侧 QoS 配置不被支持,需要用 SL 分离流量的替代做法)。

配置 Dragonfly+ 的三个 OpenSM / MLNX SM 事实

其一:引擎标识符与版本差异。MLNX SM 文档给出:标准的组内两级胖树岛用 routing_engine dfp;若岛内是三级或更多层级的树形拓扑,则需用 routing_engine dfp2,它去掉了组内两级胖树的限制。dfp2 自 MLNX SM 5.8.x(对应 MLNX_OFED 5.2.x / UFM 6.6.x)起提供。文档同时说明:为定义 Dragonfly+ 各岛的根,需要在 SM 配置文件中提供根 GUID 文件,用法与 ar_updn / ar_ftree 引擎类似;该根 GUID 文件应包含描述所有 Dragonfly+ 岛之根的交换机 GUID 或端口组。

其二:QoS 必须关闭。MLNX SM 文档明确:当自适应路由配置为 DF_PLUS 算法时,SM 的 QoS 配置不被支持,opensm.conf 中的 qos 选项应设为 FALSE。文档给出的替代方案是用不同 SL 分离应用流量(例如把 max_op_vls 设为 3 得到 4 个操作型 VL,用 VL0 与 VL2 分别承载不同应用;SL0 承载存储、SL1 承载 MPI 与 IPoIB)。

其三:AR 算法取值与路由引擎要配套。MLNX SM 文档的 AR_ALGORITHM 取值表里,DF_PLUS 标注为"专为 Dragonfly+ 拓扑设计的算法",而 TREE 明确要求必须与 updn 或 ftree 路由引擎搭配运行。这正是课程那句"Up/Down 与 Fat Tree 可以在开启或关闭自适应路由的情况下运行,而 Dragonfly+ 需要自适应路由"在厂商文档里的落点。

本节关键记忆:1 个定义 + 1 次下放 + 3 条配置事实

  • 1 个定义:Min Hop + 1 = 比最短路多一跳,由发送交换机根据出口忙闲在运行时选择
  • 1 次下放:决策从 SM 下放到交换机——这是与 Min Hop / Up/Down / Fat Tree 的根本架构差异
  • 3 条配置事实:dfp(两级胖树岛)/ dfp2(多层树岛,需根 GUID 文件)/ AR_ALGORITHM DF_PLUS 时 qos 必须设 FALSE

十、Dragonfly+ 的 VL 递增:把信用环转掉而不是绕开

What — 两种截然不同的死锁免疫思路

第六节已经建立过一个对照:Up/Down 的思路是"剪枝"——把可能成环的路径从源头禁掉;Dragonfly+ 显然不能这么做,因为它的核心能力就是允许绕行。课程随即给出了它的替代方案:Dragonfly+ 使用虚拟通道递增来避免信用环(dragonfly plus uses virtual lane increment to avoid credit loops)。

课程对触发条件的表述很精确:当一个包从"向下"方向被转发到"向上"方向时,包内携带的虚拟通道值被递增,信用环因此被消除(when a packet is forwarded from a down to up direction, the virtual lane value carried in the packet is incremented, and the credit loop is eliminated)。

课程还给出了一个具体的数量结论:防止信用环,两个虚拟通道就足够了(two virtual lanes are enough for preventing credit loops)。

注意这个触发条件与 Up/Down 的剪枝条件是同一个转折点——第五节禁止的是"下后上",这里递增 VL 的也正是"下后上"这一步。区别在于应对方式:Up/Down 是禁止这个转折发生,Dragonfly+ 是允许它发生但给这一次转折换一条通道。

机制视角 — 为什么"改一个 VL 号"就能切断信用环

先回顾信用为什么会导致死锁,这是本节推理的基础。课程引用的前序知识是:基于信用的流控机制是按虚拟通道运作的;缓冲被分配、接收到的信用也是按虚拟通道授予的(the credit based flow control mechanism operates per virtual lane. buffers are allocated and receive credits that are granted per virtual lane)。

这句话里藏着一个至关重要的推论:信用是"分通道独立计算"的。交换机 A 授予交换机 B 的信用,是记在某个特定 VL 上的;A 为 VL0 分配��缓冲与为 VL1 分配的缓冲是两个独立的池子。A 向 B 发出的包用哪个 VL,就在消耗哪个池子的信用。

那么,信用环要成立,需要什么?需要存在一组流,构成在同一 VL 上的闭合等待关系:包在 A→B 段用 VL0 消耗 A 给 B 的 VL0 信用,而 B→C 段也用 VL0 消耗 B 给 C 的 VL0 信用,如此首尾相接绕回原点。只要环上所有段用的是同一个 VL,这个等待关系就能闭合。

VL 递增的破解之道就在这里。课程说:包在"下后上"转折处把 VL 值递增。这意味着环上等待关系被打断了。展开来说:A→B 段用 VL0,B→C 段也用 VL0(都是"下"),但 C→D→…→A 那一段因为经过了转折点,用的是 VL1。于是 A 等 B 释放的是 VL0 的信用,而包实际卡在环的另一端等的是 VL1 的信用——两个池子互不相干,等待关系无法闭合,死锁不成立。

为什么"两个虚拟通道就够",现在可以给出解释了。因为需要打破的只有一个转折点:一次递增就足以让环上的路径离开原通道。第二次转折(如果存在)会把 VL 递增回 0,但此时路径已经不可能再构成同 VL 的闭合环——因为沿路径看,VL 序列形如 0, 0, 0, 1, 1, 1, 0, 0,任一条边只被单向经过时,闭合环所需的"全段同 VL"条件已经不成立。所以两轮(VL0 / VL1)就构成了一个足够的状态空间。

把这套机制与 Up/Down 对照,两种思路的优劣就很清楚了:

  • Up/Down:剪枝。优点是只用一个通道、零额外开销、也不需要交换机在运行时判断;缺点是绕行能力被牺牲,部分节点对之间可能完全无路可走(第六节)。
  • Dragonfly+:VL 递增。优点是既保留绕行能力又免疫死锁;缺点是需要额外的 VL 资源,且 VL 数量直接影响可用的 QoS 级别数量——这正是 MLNX 文档要求 AR_ALGORITHM DF_PLUS 场景下关闭 SM QoS 的根本原因:两个 VL 已经被死锁免疫占用了,留给 QoS 区分的通道就少了。

最后必须指出这条机制对硬件与配置���硬要求:VL 必须在链路上真的被区分传输。信用按 VL 独立分配的前提,是交换机与 HCA 的每条物理链路上真的存在多个并行的虚拟通道。因此 Dragonfly+ 拓扑对链路与端口的 VL 能力有前提要求,这也解释了为什么它对自适应路由是强依赖的——交换机必须能在运行时决定并修改发包的 VL。

Dragonfly+ 用 VL 递增避免信用环:两个实例

前置(课程原文):credit based flow control operates per virtual lane
                     buffers allocated and credits granted per virtual lane
                     => 信用按 VL 分池独立计算


实例一:有直连,路径不变
============================================================
host-11 -> leaf -> spine(源组) -> [直连] -> spine(目的组) -> leaf -> host-13
                                                 |
                                                 路径上没有"下后上"转折
                                                 => VL 值全程不变

沿路径的 VL 序列:      VL0  VL0  VL0  VL0  VL0  VL0  VL0


实例二:经中间组,在转折处递增
============================================================
host-10 -> leaf -> spine(源组) -> ... -> spine(中间组) -> ... -> spine(目的组) -> leaf -> host-14
                                                   |
                                                   |  课程原文:crossing between the
                                                   |  intermediate group and the
                                                   |  destination group
                                                   v
                                                   到达中间组时 VL 递增

沿路径的 VL 序列:      VL0  VL0  VL0  |  VL1  VL1  VL1

为什么死锁不可能:
----------------------------------------------------------------
若存在闭合等待环,环上所有段必须耗用同一个 VL 的信用。
上面这条路径在进入中间组时已从 VL0 切到 VL1,
绕环回到起点时消耗的是 VL1 的信用池,
而起点在等的却是 VL0 的信用 —— 两个池子独立,
等待关系无法闭合。


两条 VL 为什么够用?
============================================================
课程原文:two virtual lanes are enough for preventing credit loops

要打断的只有"下后上"这一个转折点。
           递增一次即让环上路径离开原通道,
           两轮(VL0 / VL1)已构成足够的状态空间。


与 Up/Down 的路线对比
============================================================
Up/Down      : 发现"下后上"路径  ->  禁止它进入转发表
Dragonfly+   : 允许"下后上"路径  ->  在该处把 VL 递增

同一个转折点,两种处置:
             一个消除路径        一个消除通道复用
             代价:绕行能力      代价:占用 VL 资源(挤占 QoS 级别)

本节关键记忆:1 个前提 + 1 个机制 + 1 个数量 + 1 组对比

  • 1 个前提:信用按 VL 独立分配与授予——这正是 VL 递增能生效的物理基础
  • 1 个机制:包在"下后上"转折处 VL 值递增,使环上等待关系无法在同一 VL 内闭合
  • 1 个数量:两个虚拟通道足以防止信用环
  • 1 组对比:Up/Down 剪掉路径(无绕行能力) vs Dragonfly+ 换掉通道(保留绕行但占用 VL)

十一、OpenSM 引擎全清单与选型对照

What — 把本篇的内容放回 OpenSM 的完整引擎清单里定位

课程只点名了五个引擎,但 opensm(8) 手册列出的支持列表更长:minhop, updn, dnup, file, ftree, lash, dor, torus-2QoS, nue, dfsssp, sssp。此外 MLNX SM 文档补充了 dfp / dfp2(Dragonfly+)以及后续版本的其他引擎。

把两处合并,得到下表。本表是本篇最有实用价值的产出——选型时照着"我的拓扑是什么形状"这一列往下找即可。

引擎拓扑假设核心算法死锁免疫何时选它
minhop 无环(树) 最小跳数 + 路径长度优化 否 默认引擎;纯树拓扑;未做特殊配置时的实际生效引擎
updn 任意有环拓扑 最短路 + rank 剪枝(禁"下后上") 是(剪枝) 非纯胖树、可能因环死锁的子网;本篇配置示例选它
dnup 部分 CA 比部分交换机更靠近根 类似 UPDN 是 存在"不等深"接入的胖树变体
ftree 对称或近似对称胖树 UPDN 剪枝 + 端口序位出口均衡 是 胖树且布线序位一致;LMC > 0 时不生效
torus-2QoS 2D/3D 环面 DOR 维序路由 + 两级 QoS 是 大规模环面 fabric;必须加 -Q,需 torus-2QoS.conf
dfp / dfp2 Dragonfly+ Min Hop + 1 + 出口队列负载自适应 是(VL 递增) Dragonfly+ 拓扑;需自适应路由,qos 设 FALSE
dor 超立方体 / mesh 基于 Min Hop,但除冗余链路外不做端口均衡 是 按超立方体或 mesh 方式布线的网络
lash LASH 层次化分配 分层分配通道 — 大规模网络的层次化分配策略
sssp 无拓扑限制 全局均衡每链路路由数 — 追求链路利用率均衡
dfsssp 无拓扑限制 以 SSSP 为基,用 VL(SL) 实现死锁免疫 是(VL) 优化链路利用率且需死锁免疫
nue 任意或故障拓扑 直接在通道依赖图上路由,100% 死锁免疫 是 拓扑不规则或已故障;可用任意数量 VL
file 由外部表决定 从路由表文件加载 取决于表内容 需要人工指定路径

四条必须知道的清单级事实

其一:引擎可以串联,且有兜底规则。OpenSM 手册说明:可以指定多个路由引擎,用逗号分隔,前面的失败后会按顺序尝试后面的;如果所有配置的引擎都失败,OpenSM 总是会尝试用 Min Hop 路由,除非在引擎列表中包含 no_fallback。这条规则解释了为什么"配了引擎但日志显示 minhop"是合法结果——它意味着你配的引擎失败了。

其二:兜底到 Min Hop 对有环拓扑是危险的。把上一条与第三节合起来:在有环拓扑上,"回退到 Min Hop"等于"回退到不防死锁的引擎"。环面与 Dragonfly+ 的文档因此都专门提示用 no_fallback 或 ,no_fallback 关闭兜底。

其三:nue 是清单里最"通用"的一个。OpenSM 手册对它的定位是:一个 100% 适用且死锁免疫的路由,可用于任意或故障的网络拓扑与任意数量的虚拟通道(包括完全没有 VL 的情况)。文档同时给出一条重要的理论限制:它有时必须使用绕行,因此不能真正算作"最短路径"路由,因为用有限数量的虚拟通道对任意网络拓扑实现死锁免疫的最短路径路由是不可能的。这句话解释了第五节那个现象的本质——"既最短又绝对无死锁"在有环拓扑上是做不到的。

其四:清单里有两个引擎用 VL 而不是用剪枝来实现死锁免疫。dfsssp 与 nue 属于这一类,而 dfp / dfp2(Dragonfly+)也是。第十节讲的就是这个思路。识别"哪些引擎用剪枝、哪些用 VL"是有用的判据:用剪枝的(updn / ftree)不占 VL 资源但牺牲绕行;用 VL 的保留绕行但占用 QoS 通道。

选型视角 — 三个问题定死一个引擎,不要从"哪个性能好"开始

把前面十节的信息压缩成一个可执行的决策过程。选型的正确顺序是从约束出发,不是从性能出发。

问题一:我的物理拓扑是什么形状?这是第一道门,也是唯一不能妥协的一道。严格的无环树(标准对称胖树)→ minhop 即可,或 updn(等价但不必要)。有环但不规则 → updn。明确是对称胖树且布线序位一致 → ftree。环面 → torus-2QoS。Dragonfly+ → dfp / dfp2。拓扑已经因故障变得不规则 → nue。这一步的输出唯一确定,通常没有选择余地。

问题二:这个选择能不能被正确执行?这是第二道门,也是最容易被跳过、代价最大的一道。胖树选 ftree 要先确认 LMC 是否为 0;torus-2QoS 要确认 -Q 与配置文件已就位;dfp 要确认自适应路由已配好且 qos 已设为 FALSE;updn 要确认根 GUID 文件已备好。如果第二步没做到,结果不是报错,而是静默回退到 Min Hop——对一个有环拓扑来说,这是把安全的选择换成了不安全的选择,而且日志里只有一行 minhop 可以提示。

问题三:牺牲什么?这一步决定方案是否真的可接受。剪枝类引擎的代价是绕行能力(第六节的 host 10 与 host 13 不通);VL 类引擎的代价是占用 VL 通道、压缩 QoS 级别数(第十节)。能明确说出"我牺牲了什么"的选型方案才是完整的;说不出代价的,通常是还没算清楚。

把三步连起来,本篇的核心命题就落到了实处:路由引擎的选择不是一个性能优化决策,而是一个拓扑适配决策。第一节说过"算法与拓扑是配对关系",第十一节把这句话落成了一张可查的表。而第二节那条红线——改动 routing_engine 前先咨询 fabric 架构师——现在有了更充分的理由:它不是流程上的谨慎,而是因为第二步的"静默回退"风险真实存在,且从业务现象上几乎无法察觉。


十二、配置实战:把 fabric 切到 Up/Down

What — 课程收尾的配置演示,四个动作

课程说:到这里我们已经覆盖了拓扑与路由引擎的大量内容。一旦拓扑选定、路由引擎决定下来,下一步就是配置路由引擎并验证其成功执行(once the topology is chosen and the routing engine is decided, the next step is to configure the routing engine and verify its successful execution)。示例中配置的是 Up/Down 引擎。

课程随后给出四个动作,本节逐条落到真实参数与命令上。

12.1 动作一:找到配置文件与它的默认位置

课程说:所有子网管理参数,包括路由引擎,都在 OpenSM 配置文件里配置;当 OpenSM 被安装时,默认位置如下所示;这个文件在 OpenSM 首次运行时会以默认设置被创建;如果文件不存在,用 opensm -c 命令加上文件位置来创建它。

OpenSM 手册把这些事实写得更精确,可以直接照着核对:

  • 配置文件名由 -F / --config <file_name> 指定;不指定时使用 /etc/opensm/opensm.conf(如果它存在)。
  • 创建配置文件的选项是 -c / --create-config <file_name>,即课程口语中的 "opensm dash c"。
  • OpenSM 使用的一批默认文件集中在 /etc/opensm/ 目录下,包括 opensm.conf、ib-node-name-map、partitions.conf、qos-policy.conf、prefix-routes.conf、per-module-logging.conf、torus-2QoS.conf。
动作一:确认或生成配置文件

查看默认配置文件是否存在
---------------------------------------------------------------
# ls -l /etc/opensm/opensm.conf

文件不存在时,用 -c 生成一份带默认值的配置
---------------------------------------------------------------
# opensm -c /etc/opensm/opensm.conf

-c 的完整选项名是 --create-config <file_name>
加载指定配置文件的选项是 -F / --config <file_name>
不指定 -F 时,OpenSM 使用 /etc/opensm/opensm.conf(若存在)

12.2 动作二:确定根交换机并准备根 GUID 文件

课程这一段讲得非常细,因为这是实操中最容易出错的一步。课程说:Up/Down 以构成 fabric 根部或顶层的交换机列表开始;Up/Down 有自动发现根交换机的选项,但强烈建议管理员提供根 GUID 列表(up down has an option to auto discover the root switches, yet it is strongly recommended that the administrator provide the root GUID list)。

课程接着给出识别根节点的方法:首先,有必要识别 fabric 中的脊交换机,它们被视为拓扑的根;可以使用 ibswitches 命令来做这件事,脊交换机的 GUID 是必需的(one can use the ib switches command for this purpose. The guids of the spine switches are required for this)。

课程还用了一个具体的命名习惯作例子:在这个例子里,fabric 中的命名约定暗示了交换机的层级——ibsp07 与 ibsp08,其中 SP 代表 spine。这是一个很实用的工程习惯:交换机命名里带上层级信息,能让识别根节点这一步几乎不费力。

课程继续:其次,你需要用脊交换机的 GUID 填充根 GUID 配置文件;根 GUID 文件是一个每行一个 GUID 的简单文本文件(you need to populate the root guid file with the GUIDs of the spine switches. The root guid file is a simple text file with a guid per line)。

根 GUID 文件的三个实战要点(前半来自课程,后半来自 OpenSM 手册)

其一:命令行为 ibswitches,不是"ib switches"。口语转写把工具名拆成了两个词。ibswitches 的功能是遍历 IB 子网拓扑(或使用已保存的拓扑文件)并提取交换机节点。

其二:每行一个 GUID,格式不合法的行会被静默丢弃。OpenSM 手册原文:"A valid guid file specifies one guid in each line. Lines with an invalid format will be discarded."这意味着格式错误不会导致启动失败,只会让那台交换机不被识别为根——然后 UPDN 可能探测失败,然后静默回退到 Min Hop。整条失败链路上没有任何一步会大声报错。

其三:允许填 CA 的 GUID。OpenSM 手册说明,如果填的是 CA 的 GUID,OpenSM 会使用把该 CA 接入子网的那台交换机的 GUID作为根节点。这是排障时的有力工具——如果某台脊交换机的 GUID 拿不到,填一台接在它上面的主机的 GUID 通常等效。

动作二:识别根交换机并生成根 GUID 文件

第一步:列出 fabric 中的所有交换机,取出脊交换机的 GUID
-----------------------------------------------------------
# ibswitches

第二步:筛出脊交换机
   本例中的命名约定:交换机名里带层级
   ibsp07    

12.3 动作三:让 OpenSM 使用这个根 GUID 文件

课程说:下一步是配置 OpenSM 使用根 GUID 文件。打开 opensm.conf,找到 root_guid_file 参数并填上文件名(open the opensm.conf file, find the root guid file parameter and add the file's name)。

这一步就是把路径写进配置文件,语义与第三节讲的"根 GUID 文件每行一个 GUID"是两件事:文件里存 GUID,配置文件里存这个文件的路径。

12.4 动作四:切换路由引擎并重启服务

课程说:接下来,配置 OpenSM 执行 Up/Down 路由引擎;这个参数同样在 OpenSM 配置文件里配置。找到 routing_engine 参数并改为 updn。必须重启 OpenSM 服务,新设置才会被加载(the open sm service must be restarted for the new settings to be loaded)。

把四个动作合起来,得到本节的核心配置文件:

动作三 + 动作四:opensm.conf 的两处改动

找到这两行,改成下面这样
-----------------------------------------------------------
routing_engine  updn
root_guid_file  /etc/opensm/root_guid.conf

使配置生效
-----------------------------------------------------------
# systemctl restart opensm

等价形式(opensm(8))
-----------------------------------------------------------
# opensm -R updn -a /etc/opensm/root_guid.conf

-R 接受逗号分隔的多个引擎,按顺序尝试;
   若全部失败且未包含 no_fallback,OpenSM 会回退到 Min Hop。

涉及的三个文件
-----------------------------------------------------------
/etc/opensm/opensm.conf    

用命令行改配置的另一条路径:opensm -f / opensm -c

前面已经确认:-c / --create-config 用于生成配置文件。而生成一份配置后再修改、或直接用 -F 加载它,是与"编辑文件 + 重启"等价的路径。两条路都能达到目的,区别只在于配置是否入库:走命令行参数只在本次启动生效,走配置文件 + 重启才是持久的。课程推荐的是后者,因为它可复核——配置文件里那两行是可以被 review 的。

本节关键记忆:4 个动作 + 2 个参数 + 1 个必须重启

  • 动作 1:opensm -c <路径> 生成配置;默认位置 /etc/opensm/opensm.conf
  • 动作 2:ibswitches 识别脊交换机 → 根 GUID 文件每行一个 GUID
  • 动作 3:配置 root_guid_file <路径>
  • 动作 4:配置 routing_engine updn → 必须重启 OpenSM 服务
  • 命令行等价:opensm -R updn -a <root_guid_file>

十三、验证与排障:读 opensm.log 与 ibroute

What — 判断"路由引擎是否成功执行"的判据,全部来自 OpenSM 源码与手册

课程说:为验证 OpenSM 已成功执行 Up/Down 路由引擎,在 opensm.log 文件中查找 updn tables configured on all switches 这一行。课程同时给出失败时的日志与兜底行为(下一段展开)。

这一行日志的来源是可以定位到源码的。OpenSM 的 opensm/osm_ucast_mgr.c 中,osm_ucast_mgr_process 函数的末尾有如下形式的日志调用:

opensm/osm_ucast_mgr.c —— osm_ucast_mgr_process 末尾的日志语句

    OSM_LOG(p_mgr->p_log, OSM_LOG_INFO,
                   "%s tables configured on all switches\n",
                   osm_routing_engine_type_str(p_osm->routing_engine_used));

"实际生效的引擎名"填进格式串,再打印固定后缀。
日志行的前半段 == routing_engine_used 实际取到的值。


可观察输出(前半段即实际生效引擎)
-----------------------------------------------------------
updn tables configured on all switches     

三条日志的完整因果链——这是本节最有价值的产出

把课程给的失败日志与 OpenSM 源码中 osm_ucast_mgr_process 的回退逻辑合起来,可以还原出一条完整的失败链。排障时按这个顺序读日志,能直接定位到断在哪一环:

  1. 第一环(根节点探测失败)。日志出现 disabling UPDN algorithm, no root nodes were found。含义是 __osm_updn_call 这一步没能得到任何根节点。两类可能原因:(a)没提供根 GUID 文件,且自动探测(统计直方图)是失败的;(b)提供了文件,但内容没被正确读到——每行一个 GUID 的格式不对、路径写错、文件权限不足,都会落到这一环。
  2. 第二环(矩阵构建失败)。在有完整日志的现场可以看到紧随其后的一行 ucast_mgr_route: ... cannot build lid matrices.,它说明 UPDN 的 LID 矩阵构建失败。含义是"引擎确定要算,但算不出来"。
  3. 第三环(回退发生)。由于配置里没有 no_fallback,osm_ucast_mgr_process 会走兜底分支,调用 Min Hop 重新构建矩阵与转发表,并把 routing_engine_used 置为 Min Hop。最终打印的那行日志就会是 minhop tables configured on all switches。

为什么这条链在实践中特别有价值。因为第三环的最终日志 minhop tables configured on all switches 看起来完全像一次正常启动——没有 ERROR,没有 WARN,只有一行 INFO。如果不逐字核对引擎名,运维会认为"配置生效了、服务起来了",而实际上 fabric 正在跑一个不防死锁的算法。这正是第二节那条红线在实操层面的具体代价。

补充一条来自 OpenSM 手册的整体成功判据。手册指出,两个日志文件都应包含 SUBNET UP 这条消息,表示 OpenSM 能够正确建立子网。SUBNET UP 是子网激活成功的标志(对应本系列第八篇的最后一个阶段),它与路由引擎成功是两件事:引擎失败回退到 Min Hop,子网照样能激活、SUBNET UP 照样出现、流量照样能跑——只是跑在没有死锁免疫保证的算法上。

13.2 用 ibroute 核对转发表:验证结果而不只是验证日志

日志验证的是"SM 认为它算成功了",它不验证"表里的路径对不对"。要验证后者,需要把表读出来看——这就是 ibroute 的用途:它查询交换机的转发表。

把 ibroute 的输出与本篇的算法规则对照,可以做三类核对:

  • 核对一(Up/Down 剪枝是否生效)。按第五节的规则,表中不应出现"先降后升"的路径组合。具体表现是:在标准双层胖树上,跨 spine 的节点对之间不应存在完整路径(第六节的 host 10 与 host 13)。如果发现这类路径存在,说明实际生效的不是 UPDN。
  • 核对二(Fat Tree 出口是否分散)。按第七节,默认行为是所有叶交换机对同一目的 LID 使用同一出口端口,会拥塞;负载均衡行为则不同。核对方法是看不同叶交换机到同一目的 LID 的表项是否指向了不同的脊。
  • 核对三(Dragonfly+ 的绕行路径是否就位)。按第九节,Min Hop + 1 路径必须已经存在于表中——因为决策发生在发送交换机,它需要表里同时有两条候选路径可选。如果表里只有最短路,说明自适应路由的出口分散没有正确配置。

把日志核对与表项核对配合使用,才是完整的验证

日志回答"哪个引擎生效了",ibroute 回答"这个引擎的规则落地了吗"。两者缺一不可:日志正确但表项不对,说明 SM 内部出了问题;表项符合预期但日志不对,说明你看的是上一轮的旧表(别忘了本系列第九篇讲的 Heavy Sweep 会重算并重写整张表)。

操作顺序建议:先在 opensm.log 里确认引擎名(updn tables configured on all switches),再用 ibroute 读表核对规则。顺序反了会浪费时间——如果引擎已经回退到 Min Hop,那么无论表项看起来多么"合理",它都不是你配的那个引擎的产物。

13.3 完整验证清单

把本篇全部可验证项整理成一份可勾选的清单。这份清单不包含任何性能数字——本篇所有结论都来自算法规则与 OpenSM 的确定性行为,不涉及需要实测才能确定��量。

验证视角 — 把"配置是否生效"拆成六个互不重叠的检查项

检查项一:配置文件里两行是否正确。routing_engine 的值是 updn(不是 up-down、不是 updn_v2),root_guid_file 的路径指向真实存在的文件。这一步排除拼写错误与路径错误——而这两者是最高频也最容易被后续日志掩盖的错误。

检查项二:根 GUID 文件的每一行是否合法。每行一个 GUID,十六进制,前导零位数要一致。关键在于"格式不合法的行会被静默丢弃"这个特性——它不会报错,只会让那台交换机不被识别为根,然后走向探测失败与回退。用编辑器逐行目视核对位数,是最直接的办法。

检查项三:服务是否真的重启了。课程明确指出必须重启 OpenSM 服务才加载新设置。这一步对应本系列第九篇的领域:修改配置后如果没有重启,SM 不会主动重载。用 systemctl status opensm 确认进程启动时间晚于配置文件修改时间,是一个可以自动化检查的判据。

检查项四:日志里的引擎名是否匹配。在 opensm.log 中查找 updn tables configured on all switches。必须逐字确认前半段的引擎名,不能只看"有这行日志"。若出现 disabling UPDN algorithm, no root nodes were found,则回到检查项二。

检查项五:是否有 SUBNET UP。它表示 OpenSM 能够正确建立子网。但要与检查项四分开看——引擎回退到 Min Hop 时子网照样能激活,所以 SUBNET UP 通过不代表引擎配置成功。这两个检查项不可互相替代。

检查项六:转发表里的规则是否落地。用 ibroute 读表,按 13.2 节的三类核对逐一检查。这一步是前五项的最终验证,也是唯一能确认"你想要的算法行为真的在数据面上生效"的一步。

最后把六项之间的关系点明。它们是六个独立的失败点,每个失败点都有各自独特的可观测信号,且失败信号都出现在不同的位置——配置错误在文件里、格式错误在文件里、重启缺失在进程时间戳里、根探测失败在日志里、引擎不匹配在日志里、规则未落地在转发表里。把六个位置都查一遍,才算完成了验证;只查日志会漏掉前三个检查项覆盖的情况。

本节关键记忆:1 个成功判据 + 3 环失败链 + 1 个易误判点

  • 1 个成功判据:/var/log/opensm.log 中出现 updn tables configured on all switches,必须逐字核对引擎名
  • 3 环失败链:no root nodes were found → cannot build lid matrices → 静默回退 minhop
  • 1 个易误判点:SUBNET UP 只说明子网建立成功,引擎回退时它照样出现,不能替代引擎名核对
  • 1 个补充手段:ibroute 读转发表,验证算法规则是否真的落地

十四、FAQ 高频问答(20 组)

本节围绕路由引擎的 20 个高频易错点展开,覆盖命名与选型、五种引擎的算法原理、OpenSM 配置与验证三类。题目中的引擎标识符、配置项名、命令行选项与日志字符串,均引自文末「参考资料」列出的 opensm(8)、opensm/doc/current-routing.txt、opensm/opensm/osm_ucast_mgr.c 与 NVIDIA MLNX SM 官方文档。

  1. Q1. 课程口语里的 "taurus" / "torres" 到底是什么引擎?

    Torus(环面),OpenSM 中的标识符是 torus-2QoS。语音转写把 torus 反复误听成了西班牙语人名 torres。OpenSM 手册的引擎列表中写的是 torus-2QoS,配置项值必须用这个写法。

  2. Q2. 课程说 "up down and fat tree should be used in fat tree topologies",这句话对吗?

    与 OpenSM 官方文档相反,应以手册为准。手册对 UPDN 的定位是:当子网不是纯胖树(not a pure Fat Tree)、且可能因环导致死锁时,应选它。纯胖树本身无环,不需要 UPDN 的剪枝规则;UPDN 是给有环的非胖树拓扑兜底的。

  3. Q3. 不配置 routing_engine 时,OpenSM 用哪个引擎?

    Min Hop。课程明说"未指定任何路由算法时默认调用 Min Hop",OpenSM 手册写作 "instead of Min Hop algorithm (default)"。推论:fabric 一旦建好没配这个参数,就等于一直在跑不防死锁的算法。

  4. Q4. Min Hop 为什么防不住信用环?

    因为它的目标函数里没有这一项。Min Hop 对每对源宿独立地取最小跳数,不对"多对源宿的路径合起来会不会成环"施加任何全局约束。课程的原话是 "doesn't prevent credit loops"——是不阻止,不是必然造成。在无环拓扑上它天然安全(树里不存在环),危险只在有环时出现。

  5. Q5. Min Hop 明明不防死锁,为什么还是默认引擎?

    因为它在最常见的情形下确实是安全的。最常见的拓扑是无环的树(对称胖树),此时任何逐对最短路合起来都不可能成环。Min Hop 的缺陷只有在拓扑有环时才暴露——这也是为什么判断 Min Hop 是否可接受,只需问一句"我的拓扑有没有环"。

  6. Q6. Up/Down 的核心规则用一句话怎么说?

    丢弃任何"先降后升"的路径。课程原文:任何包含"从 rank n 交换机到 rank n+1 交换机,然后再回到 rank n"这一跳的路径被丢弃。剩下的合法形状只有三种:纯向上、纯向下、先上后下——三者 rank 序列都先升后降,故任何一条边只被单向使用,信用环在结构上无法形成。

  7. Q7. 课程说 Up/Down 有五个步骤,OpenSM 文档说三个阶段,哪个对?

    都对,切面不同。课程的步骤 2、3(找一跳远的、找两跳远的)在实现里是同一个 BFS 循环的相邻两轮,所以文档合并为"阶段 2 rank 排序";课程的步骤 4、5(找最短路、丢弃违规路径)也是同一个 BFS 过程中的两个动作。理解算法按课程五步走最直观,定位源码按文档三阶段更准确。

  8. Q8. root_guid_file 是可选优化吗?

    不是。课程说 Up/Down 有自动发现根交换机的选项,但强烈建议管理员提供根 GUID 列表。原因是自动探测是统计方法——OpenSM 文档直言 "Since the algorithm is statistical, it may not find any root nodes"。root_guid_file 是确定性保障,不是性能调优项。

  9. Q9. 根 GUID 文件写错格式会发生什么?

    那一行被静默丢弃,不报错。OpenSM 手册:"Lines with an invalid format will be discarded."后果是那台交换机不被识别为根 → 可能探测不到根 → 日志出现 disabling UPDN algorithm, no root nodes were found → 静默回退 Min Hop。整条链路上没有一步会大声报错。

  10. Q10. 拿不到脊交换机的 GUID 怎么办?

    可以填 CA 的 GUID。OpenSM 手册说明:如果指定的是 CA 的 GUID,OpenSM 会使用把该 CA 接入子网的那台交换机的 GUID 作为根节点("if it exists")。这是排障时的有力替代方案。

  11. Q11. Up/Down 生效后,host 10 和 host 13 之间不通,这是故障吗?

    不是故障,是 Up/Down 的设计结果。课程明说"结果是 host 10 与 host 13 之间无法路由任何流量",理由是避免信用环让整个 fabric 死锁。但要注意前提:这类路径在纯胖树上本来就不存在(无环),只在你有替代走法的非纯胖树结构上才会出现。所以"某些主机不通"应先怀疑路由引擎可达性,而不是链路。

  12. Q12. Fat Tree 与 Up/Down 是什么关系?

    Fat Tree 沿用 Up/Down 的剪枝规则防信用环,并额外增加了出口负载均衡能力。课程原话:"fat tree routing engine follows the same approach used by the up down algorithm to avoid credit loops"。所以两者同样具备死锁免疫,差异在吞吐优化而非安全性。

  13. Q13. "端口序位"(port index)指什么?它为什么值钱?

    指每台叶交换机用相同端口编号连向每台脊交换机。它值钱是因为这是纯粹由物理布线约定提供的一致性保证——Min Hop 与 Up/Down 不知道它,只有 Fat Tree 利用它来判定"不同叶交换机能否选到不同的脊"。课程例子:每台 leaf 都用 port1 连 spine-A、port2 连 spine-B。

  14. Q14. Fat Tree 的默认行为会造成什么后果?

    所有叶交换机用同一出口端口去往同一目的 LID,全部流量压到一台脊上,造成拥塞。课程举例:"所有叶交换机都使用出口端口 1 去往目的 LID 12"→"所有叶交换机都会把流量转发给 spine 交换机 A"→"which can lead to congestion"。更好的策略是给每台叶交换机选不同出口,把流量摊到各脊上。

  15. Q15. 出口负载均衡会不会牺牲路径长度?

    不会,在这个场景下是免费的。从 leaf-2 经 spine-A 到目的 LID 与经 spine-B 到同一目的 LID,中转跳数完全相同。负载均衡只是把等价路径重新分配,不改变总跳数。这也解释了 OpenSM 文档说 Fat Tree 为"无拥塞的移位(shift)通信模式"优化——移位通信的特征正是大量节点同时向同一目的发数据,默认单出口行为会立刻退化。

  16. Q16. 配了 ftree 但 LMC 大于 0,会发生什么?

    Fat Tree 路由不生效,OpenSM 改用默认算法(即 Min Hop)。手册原文:"Note: LMC > 0 is not supported by fat-tree routing. If this is specified, the default routing algorithm is invoked instead."这是一个静默回退,日志里只会看到 minhop。在多路径主机子网里选 ftree 前必须确认这一点。

  17. Q17. torus-2QoS 怎么激活?为什么 -Q 不能省?

    用 opensm -R torus-2QoS -Q 或 -R torus-2QoS,no_fallback -Q。手册明确写出的就是这两种形式。-Q 不能省,因为该算法依赖 QoS 能力(它提供两级 QoS),等价于配置文件中的 qos TRUE。它还需要自己的配置文件,默认 /etc/opensm/torus-2QoS.conf,详细文档见 torus-2QoS(8)。

  18. Q18. dfp 和 dfp2 有什么区别?

    dfp 用于组内两级胖树岛;dfp2 去掉了这个限制,支持任意层数的树形岛。MLNX SM 文档:若拓扑中存在三级或更多层级的胖树岛,必须用 routing_engine dfp2,并在配置文件中提供根 GUID 文件(应包含描述所有 Dragonfly+ 岛之根的交换机 GUID 或端口组)。dfp2 自 MLNX SM 5.8.x(对应 MLNX_OFED 5.2.x / UFM 6.6.x)起提供。

  19. Q19. Dragonfly+ 是怎么避免信用环的?为什么两个 VL 就够?

    用 VL 递增,不是用剪枝。信用按 VL 独立分配与授予,当包从"向下"方向被转发到"向上"方向时,包内携带的 VL 值被递增——于是环上等待关系被打断在两个独立的信用池之间。两个 VL 够用,是因为需要打破的只有"下后上"这一个转折点,递增一次就足以让环上路径离开原通道。

  20. Q20. 怎么确认路由引擎真的生效了?

    在 /var/log/opensm.log 中查找 updn tables configured on all switches,并逐字确认引擎名。这行日志由 opensm/osm_ucast_mgr.c 的 osm_ucast_mgr_process 输出,格式为 "%s tables configured on all switches\n",填入的是实际生效的引擎名。失败链是:no root nodes were found → cannot build lid matrices → 静默回退 minhop。注意 SUBNET UP 不能替代这项核对——回退时子网照样激活。

FAQ 总纲(口诀式速记)

  • 1 个默认:minhop 未指定时启用;2 个缺陷:不阻止信用环、罕见但可致整网停顿
  • 1 条 UPDN 规则:禁"下后上" → 剩 3 种合法形状(纯上 / 纯下 / 先上后下)→ rank 单调 → 边只单向使用 → 环无法形成
  • 1 个反直觉点:UPDN 是给"非纯胖树"用的,不是给胖树用的
  • 3 阶段:找根(统计法,可能失败)→ BFS 赋秩(根为 0)→ 按 rank 规则 BFS 生成 FDB
  • 1 个根文件细节:每行一个 GUID,格式错误行被静默丢弃;可填 CA GUID,会自动转成接入交换机 GUID
  • 1 组 ftree 要点:沿用 UPDN 剪枝 + 端口序位出口均衡;LMC > 0 时不生效
  • 1 个 Torus 名称纠正:taurus / torres → torus-2QoS,激活必须带 -Q
  • 1 个 DFP 要点:dfp(两级胖树岛)/ dfp2(多层树岛,需根 GUID 文件)
  • 1 个 DFP 架构差异:Min Hop + 1,由发送交换机按出口忙闲在运行时决定
  • 1 个 DFP 死锁免疫:下后上处 VL 递增,两个 VL 足够;AR_ALGORITHM DF_PLUS 时 qos 必须设 FALSE
  • 1 条兜底规则:-R 支持逗号分隔多引擎;全失败时回退 Min Hop,除非含 no_fallback
  • 2 条易误判:minhop tables configured... 看起来像正常启动 / SUBNET UP 不代表引擎配置成功
  • 1 条红线:未经 fabric 架构师确认,不要改动 routing_engine——静默回退风险真实存在且业务上几乎无法察觉

十五、Roadmap 后续预告

本篇是 InfiniBand 专题的第十一篇。它的位置是:本系列第一篇《InfiniBand 架构简介:从五层模型到子网管理》讲清了分层、报文结构与三层地址,本系列第八篇《子网初始化:拓扑发现、LID 分配、路径计算与子网激活》讲清了 fabric 怎么从线缆变成能传数据的子网,本系列第九篇《SM 监控与拓扑变化:选举、故障切换、扫描与重收敛》讲清了子网建立之后如何持续运行与故障重收敛,本篇补上了"路径计算这一步内部到底发生了什么"这个环节。这四篇合起来覆盖了"物理连接 → 拓扑发现 → 路径计算 → 子网激活 → 持续监控与重收敛"的完整链路。

接下来的方向,按由路由引擎向它依赖的底层机制深入的顺序包括:

  • 链路层信用流控的完整机制:本篇第六、十节反复用到"信用按虚拟通道分配与授予"这个前提,但没有展开信用本身怎么计算、缓冲怎么划分、信用环在缓冲级别上如何精确成立。这是理解本篇全部死锁讨论的物理基础。
  • 组播转发表 MFT 与组播路由:本篇全部讨论的是单播 LFT(属性 0x0019)。组播用 MFT(0x001B)与 MLID,走的是生成树而非最短路径,死锁免疫的论证方式与单播完全不同。
  • QoS 策略的配置与验证:本篇第十节指出 VL 递增会占用 QoS 通道,Dragonfly+ 场景下 SM 侧 QoS 不被支持、需改用 SL 分离流量。这些替代方案怎么写、怎么验证生效,需要配合 smpquery 读表回读,是本篇留下的直接后续。
  • 自适应路由管理器的完整配置:本篇第九、十节讲了 AR_ALGORITHM 的三个取值与它和路由引擎的配套关系,但没有展开管理器本身的配置文件结构、端口组的生成规则、ageing 与散列策略。
  • SHIELD 机制:MLNX SM 文档提到 dfp2 支持 SHIELD,这是一套独立于路由引擎的链路级保护机制,与本篇讲的三"绕开故障"是不同层次的方案。
  • 拓扑变化后的路径重算耗时测量:本系列第九篇与本篇都强调改路由或故障会触发全网重算,但没有给出这个重算在实际规模下的耗时数据——这是一个必须实测、不能推测的工程指标。
  • 组播与单播路由引擎的差异:本篇的 nue 引擎文档特别提到"也配置组播表",说明路由引擎不只是管单播,但本篇未展开。
  • 软 RoCE 与硬件 InfiniBand 在路由计算上的差异:rxe / Soft-RoCE 没有真实的 SM 与转发表硬件,很多路径计算与信用流控机制在软实现中并不存在或被简化,排查时不能把两者行为直接类比。

如果你在实践中遇到具体问题——例如改了 routing_engine updn 但日志里仍是 minhop tables configured on all switches、ibswitches 输出里找不到预期的脊交换机、部分主机之间在链路正常的情况下互相不通——欢迎在评论区留言,我会挑出共性问题单独扩展一篇专题。


posted @ 2026-10-05 21:46  左扬  阅读(2)  评论(0)    收藏  举报