InfiniBand 专题【左扬精讲】—— InfiniBand 子网初始化:拓扑发现、LID 分配、路径计算与子网激活
InfiniBand 专题【左扬精讲】—— InfiniBand 子网初始化:拓扑发现、LID 分配、路径计算与子网激活
线插好了,网线插上了,网卡亮了——然后呢?这是每个第一次接触 InfiniBand 的人都会问的问题。以太网的直觉是 "插上就能用",而在 InfiniBand 里,插上只是开始。
从一堆交换机和 HCA 变成一个可以传数据的子网,中间要经过一整套由 子网管理器(SM)主导的初始化流程:发现拓扑 → 分配 LID → 计算路径 → 配置节点与端口 → 激活子网。这五个阶段任何一步没走完,数据包都发不出去。
本篇是 InfiniBand 专题【左扬精讲】系列的第 8 篇,承接第一篇的 Fabric / Subnet 概念与 SM / SMA 角色,按 严格的递进顺序 把这套初始化流程从头到尾拆开讲透:先把 Fabric 与 Subnet 的边界 钉死,再讲清 SM 究竟在做什么,然后按 SM 自己的动作顺序 逐个阶段展开 —— 包括拓扑发现用的 SMP 报文与两种寻址方式、LID 的三条分配规则、Min Hop 最小跳数算法与端口均衡计数、端口的四个配置参数、SL-to-VL 映射与 VL 仲裁,最后落到激活阶段的 物理状态 × 逻辑状态 二维状态机,以及运维手里的 ibstat / ibswitches / ibroute 三件套。
本篇的核心命题只有一句:InfiniBand 的 "管理先行" 不是设计缺陷,而是把以太网里分散在多个协议、多个设备的控制面逻辑,收敛成了一个有明确阶段顺序的单一过程。理解了这个过程,"为什么我的端口一直停在 Initializing" 这类问题就有了确定的排查路径。
本篇核心术语:
Fabric 织物 / Subnet 子网 / Subnet Manager (SM) 子网管理器 / Subnet Manager Agent (SMA) 子网管理代理
MAD Management Datagram 管理数据报 / SMP Subnet Management Packet 子网管理包
Directed Route 定向路由 / LID Routed LID 路由 / Get / Get Response
LID Local Identifier 本地标识符 / GUID Global Unique Identifier / Node Description 节点描述
Min Hop 最小跳数 / LFT Linear Forwarding Table 单播线性转发表 / MFT Multicast Forwarding Table 组播转发表
LMC LID Mask Count / ECMP 等价多路径
Service Level (SL) 服务等级 / Virtual Lane (VL) 虚拟通道 / VL Arbitration 虚拟通道仲裁 / QoS 服务质量
MTU Maximum Transfer Unit / Width 宽度 / Speed 速率
Physical State 物理状态 / Logical State 逻辑状态 / Polling / Training / LinkUp
Down / Init / Armed / Active / VCRC 虚拟校验
本篇核心命令:ibstat / ibswitches / ibroute / ibnetdiscover / smpquery / opensm
本篇权威依据:IBTA Vol 1 Release 1.3 / InfiniBand Network Architecture (O'Reilly) 第 27 章 SMP 校验
rdma-core include/rdma/ib_mad.h 与 include/rdma/ib_smi.h / libibverbs verbs.h
OpenSM 官方文档 current-routing.txt 与 opensm(8) man page / infiniband-diags smpquery(8) ibroute(8) ibswitches(8) 手册
InfiniBand子网初始化Fabric / SubnetSubnet Manager SMSMASMP 报文定向路由LID 分配LMCMin HopLFT 转发表SL-to-VLVL 仲裁QoS端口状态机VCRCibstatibswitchesibroute
★ 学完这一篇你能掌握什么(渐进式路径:1→2→3 不可跳跃)
- 第 1 步 · 边界(第一节、第二节)
• What:Fabric 是链路/交换机/路由器的物理集合,Subnet 是拥有共同子网 ID、由同一个 SM 管理的端口与链路集合;Fabric 必须经由 SM 初始化并激活后才成为 Subnet
• How:能说出 SM 的五项具体职责(发现拓扑 / 分配 LID / 计算并编程转发表 / 管理 fabric 全部元素 / 监控子网变化),并说明 SMA 存在的必要性
• Why:理解 "IB 网络为什么不能即插即用"——因为每个节点都需要 SMA 承接 SM 的配置指令,这不是可以省略的步骤- 第 2 步 · 发现(第三节、第四节、第五节)
• What:SM 依靠 SMP 报文发现拓扑,SMP 固定走 VL 15;报文分 LID 路由 与 定向路由两种寻址方式,方法分 Get(0x01)与 Get Response(0x81)
• How:能复述 SM 借助"已发现交换机作为跳板"逐跳扩散的发现过程,并判断节点级信息与端口级信息各自包含哪些字段
• Why:理解 "为什么发现遇到 HCA 就停止"——HCA 位于 fabric 边缘,不会被用作进一步发现的入口- 第 3 步 · 寻址与转发(第六节、第七节、第八节)
• What:LID 分配的三条规则——HCA 按端口 分配、单一 IC 的交换机 整台一个、多 IC 模块化交换机 按 IC分配;LMC > 0 时每端口获得 2^LMC 个 LID
• How:能手工数出"某交换机到某目的 LID"的三条候选路径各是多少跳,并按 端口 LID 计数最少 的规则判断 SM 会选哪一条
• Why:理解 "Min Hop 只负责选最短,负载均衡由端口计数器补齐"这一两阶段设计——两者目标不同,缺一都会导致链路偏斜- 第 4 步 · 配置与 QoS(第九节、第十节)
• What:SM 为每个端口配置的四个参数——LID / Width / MTU / Speed,以及 SL-to-VL 映射表与 VL 仲裁的分工
• How:能描述一个数据包到达交换机后"查 LFT 定出口端口 → 查 SL-to-VL 定虚拟通道 → 无映射则走 VL 0"的完整查表顺序
• Why:理解 "Speed 为什么受链路上最慢设备约束",以及 QoS 决策为什么发生在链路层而不是网络层- 第 5 步 · 激活(第十一节)
• What:端口的三个物理状态(Polling / Training / LinkUp)与四个逻辑状态(Down / Init / Armed / Active)各自的判定条件
• How:拿到 ibstat 输出后,能用"物理状态 + 逻辑状态"的组合直接定位问题落在哪一层
• Why:理解 "dummy packet + VCRC 校验"这一步的意义——它验证的是两个直连设备之间的链路级数据完整性,是 Armed → Active 的唯一前置条件★ 阅读前提 & 本篇不涉及的内容
- 前置知识:本系列第一篇《InfiniBand 架构简介:从五层模型到子网管理》中的 Fabric vs. Subnet、SM / SMA / MAD 三角色、GUID / LID / GID 三层地址。以及本系列第二篇《传输层:QP、分段重组、传输服务与分区》中的 VL 属于链路层概念、ICRC 与 VCRC 的分工。本篇不重复解释这些内容
- 信息来源:本篇所有属性编号、方法码、管理类值、状态枚举值均引自文末「参考资料」列出的 include/rdma/ib_mad.h、include/rdma/ib_smi.h、libibverbs/verbs.h 与 IBTA / O'Reilly 规范原文,工具输出格式引自 infiniband-diags 官方 man page 与 Oracle 官方文档
- 本篇不涉及:链路层信用计数器(Credit-Based Flow Control)的具体运行机制、SM 主备选举算法、交换机固件内部的转发表存储结构、组播转发表 MFT 的生成算法、QoS 策略文件的配置语法
📑 本节目录(按初始化阶段的自然顺序)
一、Fabric 与 Subnet:从物理集合到管理实体
What — 这两个词的精确定义
课程给出了一组非常精确的定义,这组定义是理解后面全部内容的基础:
- Fabric(织物):InfiniBand fabric 是一组链路、交换机和路由器的集合,它们把一组通道适配器连接起来。注意这个定义里全部是物理对象——线缆、交换机、路由器、HCA,没有一个"地址"或"编号"
- Subnet(子网):一个子网是一组拥有共同子网 ID(common subnet ID)并由同一个子网管理器管理的端口及其关联链路。注意这个定义里出现了一个 Fabric 定义中不存在的东西——子网 ID,以及一个"管理归属"关系
- 连接关系:子网之间可以通过路由器相互连接,形成更大的网络结构
最后一条关键结论:要让一个 fabric 成为一个 subnet,它必须由一个子网管理器初始化并激活。这是一句因果性极强的论断——它意味着 fabric 是先验存在的物理实体,subnet 是后验建立的管理实体。
1.1 两个定义的关键差异在哪
把上面两条定义并排放,差异集中在三个点上,每一个差异都直接决定了本篇后续要讲的内容:
| 对比维度 | Fabric 的定义里 | Subnet 的定义里 | 这个差异导致了什么 |
|---|---|---|---|
| 构成元素 | 链路、交换机、路由器、通道适配器 | 端口、关联链路 | Subnet 的粒度下沉到端口——所以第七节的 LID 分配规则才要区分"交换机整台"还是"单个 IC" |
| 标识 | 无标识要求 | 必须有共同的子网 ID | 子网 ID 是成员划分的依据,节点加入子网需要通过 SM 的检查 |
| 管理归属 | 无要求 | 由同一个 SM 管理 | 单一管理平面——这是第五、六、七、八节所有配置动作能够集中下发的前提 |
为什么这个区分在工程上有价值?因为它直接回答了一个运维问题:"我的交换机接在网上了,为什么业务不通?"
按照上面的定义,答案分两种情况:
- 情况一:交换机在物理上连通,但没有加入任何子网。此时设备是一组 fabric 组件,没有任何 LID,不在任何交换机的转发表里。业务不通的原因是子网尚未建立。
- 情况二:交换机加入了子网,但端口未激活。此时设备已有 LID,但逻辑状态未到 Active,链路层会丢弃业务报文。业务不通的原因是激活未完成。
这两种情况在 ibstat 输出上的区别非常明显,第十一节会给出判读方法。
与以太网的对照——为什么 InfiniBand 必须显式建"子网"这一层
以太网没有"子网"这个管理实体的概念。一台交换机插上线、配置好 VLAN 和路由表,就是一台可用的交换机。地址(MAC / IP)要么硬件固化,要么由 DHCP 分配,都不需要一个中心节点遍历全网才能确定。
InfiniBand 的做法不同:LID 不是设备出厂属性,也不是链路自动学到的,它必须由 SM 遍历全网、发现拓扑之后统一分配,再由 SM 写回每一台交换机。(指以太网中设备地址由硬件固化或 DHCP 分配,网络可自行形成转发关系)。因此"地址从哪来"这个问题在 IB 里必须先有回答,链路才可能工作。
把这句话再说得直白一点:在 InfiniBand 里,"地址"不是链路的产物,而是"初始化过程"的产物。这是理解本篇所有内容的第一块基石。
本节关键记忆:2 个定义 + 1 个差异 + 1 条因果
- 2 个定义:Fabric = 链路 + 交换机 + 路由器的物理集合;Subnet = 共同子网 ID + 同一 SM 管理的端口与链路集合
- 1 个关键差异:Fabric 无管理归属,Subnet 有;Subnet 的粒度到端口,Fabric 的粒度到设备
- 1 条因果:Fabric 必须由 SM 初始化并激活后才成为 Subnet——这是本篇全篇的起点
- 1 个以太网对照:IB 的地址是"初始化过程的产物",以太网的地址是"设备属性或 DHCP 的产物"
二、SM 与 SMA:谁在驱动这场初始化
What — SM 让 InfiniBand fabric 能够工作的五件事
课程指出:一个 InfiniBand fabric 必须有一个子网管理器(SM),它使得 fabric 能够完成五件事:
- 发现拓扑(discovering the topology)
- 为节点分配本地标识符 LID(assigning local IDs, LIDs, to nodes)
- 计算并编程交换机转发表(calculating and programming switch forwarding tables)
- 管理 fabric 中的所有元素(managing all the elements in the fabric)
- 监控子网中的变化(monitoring changes in the subnet)
这五件事正好对应本篇的六个初始化阶段。发现拓扑是第五、六节;分配 LID 是第七节;计算并编程转发表是第八节;配置节点与端口是第九、十节;监控变化是持续运行期的职责。
SM 可以实现在 fabric 中的任意一个节点上——课程明确列举了三类:一台服务器、一台交换机、或一台专用设备。这三条路径在实际部署中都存在,第三类是"集中式 SM 设备",前两类是"分布式部署"。
2.1 SMA:SM 之外的另一半
课程紧接着给出了 SM 存在的必要条件,这个条件常被忽略但极其关键:
fabric 中的每个被管理节点都需要一个子网管理器代理(SMA,Subnet Manager Agent),它让 SM 能够与该节点通信并配置它。
这句话的结构是"SM 主动 + SMA 被动"。把本系列第一篇的结论接上:节点是任何受管理的实体;SMA 运行在节点上;SMA 的常态是被动响应查询,必要时可主动发送 trap 消息。本篇的初始化过程,本质上就是 SM 反复向全网所有 SMA 发起 Get 请求、收集响应、再下发 Set 请求的过程。
控制面:谁在推,谁在收
┌──────────────────────────────────────────────────────────────┐
│ SM(主动方) │
│ 职责:发现拓扑 / 分配 LID / 计算并编程转发表 │
│ 管理全部元素 / 监控子网变化 │
│ │
│ 形态:服务器 | 交换机 | 专用设备(三选一即可) │
└───────────┬──────────────────┬──────────────────┬──────────┘
│ Get / Get Resp │ Get / Get Resp │ Get / Get Resp
▼ ▼ ▼
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ 交换机 + SMA │ │ 交换机 + SMA │ │ HCA + SMA │
│ │ │ │ │ │
│ 被管理节点 │ │ 被管理节点 │ │ 被管理节点 │
│ 常态:被动 │ │ 常态:被动 │ │ 常态:被动 │
│ 例外:发 trap │ │ 例外:发 trap │ │ 例外:发 trap │
└────────────────┘ └────────────────┘ └────────────────┘
▲ ▲
└────────── 介质:SMP 报文,走 VL 15 ──────────┘
(第五节展开)
把 SM 与 SMA 的关系放进协议报文的层面看,会发现一个不容妥协的事实:SMP 报文是普通的 InfiniBand 数据包,它和业务流量跑在同一条物理链路上,只不过被指定走 VL 15(详见第五节)。这意味着任何一台要被管理的节点,必须具备三样东西才能回应 SM 的查询:
- 其一,能解析 SMP 格式的数据包。SMP 的载体是 MAD(Management Datagram),MAD 头之后是 SMP 头,再往后才是具体的属性数据(node_info / port_info / node_desc 等)。这个解析动作由节点上的 SMA 承担。
- 其二,能在未分配 LID 的情况下回应。这一点尤其关键——发现阶段 LID 还没有分配,被查询的交换机与 HCA 都不知道自己的 LID。因此发现阶段的 SMP 必须走定向路由(Directed Route)而不是 LID 路由,报文中携带的是"从 SM 出发要依次经过哪些端口号"的显式路径。
- 其三,能接收 SM 下发的 Set 指令并写进本节点硬件。分配 LID、配置 MTU / 宽度 / 速率、编程 LFT、切换逻辑状态到 Active——这四类动作全部以 Set 形式下发,最终落到节点的端口寄存器与转发表存储里。
这三条同时成立,才能构成课程所说的"SM 能够与该节点通信并配置它"。反过来看,任何缺少 SMA 的设备,对 SM 而言就是不存在的——它不会被分配 LID,不会出现在转发表中,因此在业务侧表现为"接了线但完全不通"。这个结论解释了初始化流程中大量"看起来是软件问题、实际是硬件或固件未提供 SMA"的现象。
关于发现阶段的定向路由,infiniband-diags/smpquery.c 给出了直接的工具印证:smpquery -D nodeinfo 0 中的 -D 就是按定向路由寻址,路径写作 "0,1,2,1,4" 这样的端口号序列;而按 LID 寻址的写法是 smpquery portinfo 3 1,第一个参数直接是十进制 LID 3。两种寻址方式的差别,在命令行上就是这一个参数的差别。
2.2 SM 的五项职责如何对应六个阶段
课程强调的一点是:这些阶段将按照 SM 的动作顺序呈现。把这个顺序和第二节的五项职责对齐,可以得到一张精确的映射表,这张表也是本篇全篇的骨架:
| 阶段 | SM 在这一阶段的动作 | 对应 SM 职责 | 本篇位置 |
|---|---|---|---|
| 阶段 0 | 无(人工完成物理连线) | — | 第四节 |
| 阶段 1 | 与直连节点对话,逐跳扩散发现全网拓扑 | 发现拓扑 | 第五、六节 |
| 阶段 2 | 为每个被发现的受管理节点分配唯一 LID | 分配 LID | 第七节 |
| 阶段 3 | 计算各交换机到各节点的最佳路径 | 计算并编程转发表 | 第八节 |
| 阶段 4 | 配置各端口的 LID / 宽度 / MTU / 速率,编程 QoS 表 | 管理全部元素 | 第九、十节 |
| 阶段 5 | 向所有端口下发 Active,激活子网 | 管理全部元素 + 监控变化 | 第十一节 |
关于"监控子网中的变化"这一项:它是唯一一个不属于初始化阶段、却必须与之同等看待的职责。初始化是一次性的,但拓扑变化是持续的——交换机重启、链路 down、新 HCA 上线,都会触发 SM 重跑第五至第八节。理解这一点,就理解了为什么 IB 网络在扩缩容时不需要人工重配转发表。
本节关键记忆:5 项职责 + 1 个部署前提 + 1 个硬约束
- 5 项职责:发现拓扑 / 分配 LID / 计算并编程转发表 / 管理全部元素 / 监控变化
- 1 个部署前提:SM 可运行在服务器、交换机、专用设备三类载体之一
- 1 个硬约束:每个被管理节点都必须有 SMA,否则 SM 视其不存在
- 1 个动作顺序:课程明确"阶段按 SM 的动作顺序呈现"——这是本篇章节顺序的依据
三、初始化全景:六个阶段的总地图
本节是全篇的地图,不引入新概念。如果时间有限,只读第三节 + 第七节(LID 规则)+ 第十一节(状态机)+ FAQ,也能建立完整认知框架。后面每一节都会回到这张图。
课程对阶段 0 有一个明确的前置说明:要拥有一个 fabric,我们首先需要连接节点之间以及节点与 fabric 之间的所有线缆。这句话里"节点与 fabric 之间"的表述,指向的是 HCA 到交换机的连接。物理连通性建立之后,一个 SM 必须在其中某个节点上运行,然后"当 SM 唤醒时,fabric 发现过程被启动"。
InfiniBand Fabric 初始化的六个阶段
阶段 0 物理连接
┌─────────────────────────────────────────────────────────────┐
│ 人工连线:交换机互联、交换机到 HCA │
│ 规范约束:不弯折 / 不扭曲接头 / 不落地 │
│ 产物:一组"连着的"物理设备 │
└──────────────────────────┬──────────────────────────────────┘
▼
阶段 1 拓扑发现(Discovery)
┌─────────────────────────────────────────────────────────────┐
│ SM 与直连节点对话 → 逐跳扩散 → 覆盖全网 │
│ 通信载体:SMP 报文,固定走 VL 15 │
│ 寻址方式:定向路由(LID 尚未分配,只能用端口号序列) │
│ 消息方法:Get (0x01) / Get Response (0x81) │
│ 取回内容:节点级(类型/端口数/GUID/描述)+ 端口级(MTU/宽度/VL)│
│ 产物:完整拓扑数据库(节点 GUID + 端口号 + 链路) │
└──────────────────────────┬──────────────────────────────────┘
▼
阶段 2 LID 分配
┌─────────────────────────────────────────────────────────────┐
│ 为每个"受管理节点"分配子网内唯一 LID │
│ HCA:每个端口一个 LID │
│ 单一 IC 交换机:整台一个 LID │
│ 多 IC 模块化交换机:每个 IC 一个 LID │
│ LMC > 0 时:每端口 2^LMC 个 LID │
│ 产物:LID → 端口 的全局唯一映射 │
└──────────────────────────┬──────────────────────────────────┘
▼
阶段 3 路径计算
┌─────────────────────────────────────────────────────────────┐
│ 从每台交换机到每个节点,计算最少跳数 │
│ Min Hop:逐端口记录到达各 LID 的跳数,取最短 │
│ 跳数相同 → 选"已分配 LID 数最少"的端口(端口均衡计数) │
│ 备份路径不装入转发表,链路故障时启用 │
│ 产物:每台交换机的最佳出口端口决定 │
└──────────────────────────┬──────────────────────────────────┘
▼
阶段 4 节点与端口配置 + 交换机编程
┌─────────────────────────────────────────────────────────────┐
│ 端口四参数:LID / Width / MTU / Speed │
│ LFT 编程:目的 LID → 出口端口 │
│ QoS 编程:SL-to-VL 映射表 + VL 仲裁表 │
│ 产物:全网硬件就绪,但端口仍不转发业务 │
└──────────────────────────┬──────────────────────────────────┘
▼
阶段 5 子网激活(Activation)
┌─────────────────────────────────────────────────────────────┐
│ 物理状态:Polling → Training → LinkUp │
│ 逻辑状态:Down → Init → Armed → Active │
│ Armed → Active 的前置:dummy packet + VCRC 校验通过 │
│ 终态判据:物理 LinkUp 且 逻辑 Active │
│ 产物:可用的子网 │
└─────────────────────────────────────────────────────────────┘
这张图有一个极易被忽略的细节:阶段 4 和阶段 5 的顺序不可颠倒。
阶段 4 完成时,全网的地址与转发表已经全部就绪,但此时端口的逻辑状态还停留在 Init。而 Init 状态的定义是:链路层只能收发 SMP 报文和流控链路包,其他所有报文一律丢弃。也就是说,阶段 4 之后子网"已经知道该往哪转发",但"还不允许转发"。
SM 必须先确认每个端口都完成了配置(第 4 阶段),才允许把端口推进到 Active(第 5 阶段)。顺序反了会导致交换机按未完成的配置表转发数据包。
本节关键记忆:6 个阶段 + 1 条不可颠倒的顺序
- 阶段 0 物理连接(人工)→ 阶段 1 拓扑发现 → 阶段 2 LID 分配 → 阶段 3 路径计算 → 阶段 4 节点端口配置 → 阶段 5 子网激活
- 1 条顺序铁律:必须先完成阶段 4 的端口配置,才能执行阶段 5 的 Active 下发——因为 Init 状态下链路层丢弃一切非 SMP / 非流控报文
- 1 条起点:SM 唤醒 = 阶段 1 启动的触发点,此前的一切都是人工的
四、阶段一:物理连接——唯一无法自动修复的环节
What — 课程给出的三条布线准则
课程强调:强烈建议遵循这些布线准则(it is highly recommended to follow these cabling guidelines):
- 不要使线缆打结或过度弯折(do not kink or over bend cables)
- 不要扭曲 InfiniBand 接头(do not twist InfiniBand connectors)
- 不要把线缆留在地面上,可能被推车或人员踩踏损坏(do not leave cables on the floor where they can be damaged by carts or foot traffic)
4.1 为什么布线是整套流程里唯一"SM 管不了"的环节
Why — 把六���阶段按"责任主体"重新分组,会发现一个规律
把第三节的六个阶段按"谁来完成"重新分组,结论非常清楚:
- 阶段 1 → 阶段 5 全部由 SM 自动完成。发现问题、分配地址、计算路径、下发配置、激活端口,每一步都不需要人工介入。这正是本系列第一篇强调的"管理先行、集中控制"带来的运维优势。
- 只有阶段 0 需要人工,而且它是一切的起点。SM 唤醒后发出的第一个 SMP 报文,只能到达它物理直连的那些节点。线没插好,SM 就发现不到那个节点,后续所有阶段对它都是空谈。
因此三条布线准则的定位就清楚了:它们不是"建议性的整洁要求",而是"唯一一道 SM 无法代劳的质量关卡"。其余五个阶段出问题时,SM 会重试、会重算、会重下发;而布线问题在 SM 看来只是"那个方向上没有节点",是一句合法且安静的结论——不会报错,只会少一个节点。
三条准则各自规避的具体故障机理
课程只给出了准则本身,没有展开物理层面的原因。这里把每条准则对应的失效模式与最终在 ibstat 上的表现列出来,方便对照排查:
- 打结 / 过度弯折 → 影响传输信号完整性。这类损伤通常不会导致链路完全 down,而是表现为物理状态反复在 LinkUp 与 LinkErrorRecovery 之间跳变,或速率协商失败。物理状态枚举中的 LinkErrorRecovery(取值 6)正是这条链路的直接体现。
- 扭曲接头 → 影响连接器接触。IB 连接器对插拔与锁扣状态有明确要求,扭曲后可能插不到底或者锁扣不到位,表现为物理状态停在 Polling。
- 线缆落地 → 机械损伤与间歇性断连。这类故障往往是间歇的,最难排查:端口可能已经分配到 LID、状态一度正常,然后在运行中反复掉线。每一次掉线都会触发 SM 重跑阶段 3 重算路径。
排查顺序建议:当 ibstat 显示某个端口 Physical state: Polling 且 State: Down 时,按这个顺序检查:① 线缆两端是否插到底;② 对端交换机端口是否已启用(部分端口出厂为 Disabled);③ 光模块与线缆是否匹配;④ 才考虑固件与驱动。前两项占实际故障的绝大多数。
本节关键记忆:3 条准则 + 1 个定位
- 3 条准则:不弯折 / 不扭曲接头 / 不落地
- 1 个定位:阶段 0 是整套流程中唯一由人工完成、且 SM 无法代劳的环节
- 1 个排查含义:布线故障在 SM 视角里表现为"少一个节点"而非"报错",所以必须靠 ibstat 的物理状态主动发现
五、阶段二:拓扑发现——SMP 报文与两种寻址
What — 发现过程的三条核心机制
当 SM 唤醒,fabric 发现过程启动。课程给出了三条机制,它们是本节的主干:
- 对话方式:SM 与每一个和它相连的节点开始一次对话,收集交换机信息,然后是端口信息,然后是主机信息
- 扩散方式:任何已经被发现的交换机,都会被 SM 用作继续发现该交换机邻居的门户(gate)。SM 从直连节点开始,逐跳向外扩散,直到覆盖整个 fabric
- 通信载体:SM 通过发送与接收 SMP(Subnet Management Packet,子网管理包)来收集信息。SMP 通过 VL 15 发送,VL 15 是用于子网管理流量的专用虚拟通道
这三句话里,"gate(门户)"这个机制是理解发现算法效率的关键。它把一个 O(N²) 规模的查询问题,变成了 O(边数) 规模——因为 SM 只需要为每条链路做一次查询,而不是为每对节点做一次。
5.1 SMP 为什么固定走 VL 15
"SMP 通过 VL 15 发送"这句话在协议层面是硬性要求,而不是实现选择。IBTA 规范对收到的 SMP 有一组强制校验条件,任何一条不满足,该 SMP 就必须被丢弃。相关校验在《InfiniBand Network Architecture》第 27 章"SMP Validation"中列为一组检查项,其中与 VL 相关的部分原文要求为:
| 校验项 | 要求 | 不满足的后果 |
|---|---|---|
| 数据载荷长度 | 必须为 256 字节 | 丢弃 |
| LRH:VL | 必须为 15 | 丢弃 |
| BTH:DestQP | 必须为 0 | 丢弃 |
| BTH:Opcode | 必须是 UD Send-Only | 丢弃 |
| MADHeader:BaseVersion | 必须为 1 | 丢弃 |
| MADHeader:MgmtClass | 必须为 Subn 或 Directed-Route Subn 类 | 丢弃 |
| MADHeader:AttributeID | 必须指定某个 SM 属性 | 丢弃 |
这组校验把 SMP 的"专用通道"属性体现得非常彻底,四个数字(256 / 15 / 0 / 1)全部是常量,没有协商余地:
- VL = 15:管理流量独占一条虚拟通道,与业务流量物理隔离。这直接解释了本系列第二篇的结论——VL 是链路层概念,交换机为不同的 VL 分配独立的缓冲与仲裁资源。管理流量永远不会被业务流量饿死。
- DestQP = 0 + UD Send-Only:管理报文不经过任何传输层 QP,目的地队列号固定为 0。这意味着 SMP 不占用应用建立的 QP,不受应用层流控影响,也不需要任何连接建立过程。
- 载荷恒为 256 字节:SMP 报文长度固定,接收端不需要做变长解析,SLA 硬件处理时路径长度可预测。
一个容易忽略的推论:因为 SMP 走 VL 15 且需要交换机转发,所以链路层必须先处于能转发 SMP 的状态,SM 才可能发现在它。这与第十一节的 Init 状态定义完全吻合——Init 状态"只能收发 SMP 报文和流控链路包"这条规定,正是为了让发现与配置阶段能够进行,而业务流量一律丢弃。
5.2 两种寻址方式:LID 路由与定向路由
课程指出:SM 使用两种类型的定向路由 SMP 消息来收集信息:Get 消息与 Get Response 消息。在展开这两条消息之前,需要先说清"定向路由"与"LID 路由"这条并行的分类维度——这是两个不同维度,不能混为一谈:
| 寻址维度 | 报文中携带什么 | 管理类字段值 | 发现阶段能否使用 |
|---|---|---|---|
| LID 路由 (LID Routed) |
目的端口的 LID | 0x01 Subn |
不能——LID 尚未分配 |
| 定向路由 (Directed Route) |
一串"依次经过的端口号" | 0x81 Directed-Route Subn |
可以——这正是发现阶段的选择 |
这两个管理类常量可在 include/rdma/ib_mad.h 中直接读到定义:
/* 管理类(MgmtClass):子网管理 MAD 的寻址方式 */
#define IB_MGMT_BASE_VERSION 1
#define IB_MGMT_CLASS_SUBN_LID_ROUTED 0x01 /* 按 LID 寻址 */
#define IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE 0x81 /* 按定向路径寻址 */
#define IB_MGMT_CLASS_SUBN_ADM 0x03 /* 子网管理器 / 管理员 */
#define IB_MGMT_CLASS_MASK 0x7f
/* 方法(Method):SM 与 SMA 之间的操作类型 */
#define IB_MGMT_METHOD_GET 0x01 /* 读请求 */
#define IB_MGMT_METHOD_SET 0x02 /* 写请求 */
#define IB_MGMT_METHOD_GET_RESP 0x81 /* 读应答 */
#define IB_MGMT_METHOD_SEND 0x03
#define IB_MGMT_METHOD_TRAP 0x05 /* SMA 主动上报 */
#define IB_MGMT_METHOD_REPORT 0x06
#define IB_MGMT_METHOD_REPORT_RESP 0x86
#define IB_MGMT_METHOD_TRAP_REPRESS 0x07
课程用一句话讲了 SMP 走 VL 15。规范把这一句话展开成了一组必须全部满足的校验条件,它们分布在三个不同的报文层里。把它们按层次归位,就能看清"为什么这七条少一条都不行":
第一层 — 链路层路由头(LRH):VL 必须为 15。LRH 是链路层路由头,VL 字段在其中。这个字段值是 SMP 的"专用信道标记",接收端据此判断来包是否为管理报文。它被放在 LRH 而非更高层,意味着交换机在转发路径上就能完成这个判定,不需要解析上层内容。
第二层 — 基本传输头(BTH):DestQP 必须为 0,Opcode 必须是 UD Send-Only。DestQP 在 BTH 中占据 24 位(见本系列第二篇 BTH 字段表)。规定为 0,意味着管理报文不投递给任何用户队列对。Opcode 为 UD Send-Only 意味着它是数据报而非连接型报文——不需要建立 QP、不需要 PSN 确认、不需要重传。
第三层 — 管理数据报头(MAD Header):BaseVersion 必须为 1,MgmtClass 必须是 Subn 或 Directed-Route Subn,AttributeID 必须是某个 SM 属性。MgmtClass 就是在 5.2 节表格中那两个值 0x01 与 0x81;AttributeID 则指定了要读写的具体属性。
把第三层的 AttributeID 展开,就得到发现阶段实际会用到的全部属性编号。这些常量同样定义在 include/rdma/ib_smi.h 中:
| 属性名 | AttributeID | 十六进制 / 十进制 | 本篇用途 |
|---|---|---|---|
| Node Description | IB_SMP_ATTR_NODE_DESC | 0x0010 / 16 | 节点描述(课程列举的"node description") |
| Node Info | IB_SMP_ATTR_NODE_INFO | 0x0011 / 17 | 节点级信息:类型、端口数、GUID |
| Switch Info | IB_SMP_ATTR_SWITCH_INFO | 0x0012 / 18 | 交换机扩展信息 |
| GUID Info | IB_SMP_ATTR_GUID_INFO | 0x0014 / 20 | GUID 计数器 |
| Port Info | IB_SMP_ATTR_PORT_INFO | 0x0015 / 21 | 端口级信息:MTU、宽度、速率、VL 数 |
| P_Key Table | IB_SMP_ATTR_PKEY_TABLE | 0x0016 / 22 | 分区表(本系列第二篇已展开) |
| SL-to-VL Table | IB_SMP_ATTR_SL_TO_VL_TABLE | 0x0017 / 23 | QoS 映射表(第十节) |
| VL Arbitration Table | IB_SMP_ATTR_VL_ARB_TABLE | 0x0018 / 24 | VL 仲裁表(第十节) |
| Linear Forwarding Table | IB_SMP_ATTR_LINEAR_FORWARD_TABLE | 0x0019 / 25 | 单播转发表 LFT(第八节) |
| Random Forwarding Table | IB_SMP_ATTR_RANDOM_FORWARD_TABLE | 0x001A / 26 | 随机(散列)转发表 |
| Multicast Forwarding Table | IB_SMP_ATTR_MCAST_FORWARD_TABLE | 0x001B / 27 | 组播转发表 MFT |
| SM Info | IB_SMP_ATTR_SM_INFO | 0x0020 / 32 | SM 自身信息 |
把这张表和第三节的六个阶段对齐,可以得到一张精确的"谁在什么时候读哪个属性"对照。这张对照表是本篇最有实用价值的部分之一:它把"抽象的初始化阶段"翻译成了"具体要读写哪些表",也是排查"某一步为什么没做"时最直接的对照依据。
5.3 两种消息:Get 与 Get Response
在寻址方式确定之后,课程给出了消息层面的两条方法:
- Get 消息:SM 通过发送 Get 消息来拉取 fabric 的信息并学习其拓扑
- Get Response 消息:每个目的节点通过发送 Get Response 消息来回应,其中包含所请求的信息
从方法码的数值上能读出一点设计信息:Get = 0x01,Get Response = 0x81。响应方法码是请求方法码加上 0x80,而 0x80 在代码中定义为 IB_MGMT_METHOD_RESP,是"应答类方法"的统一标志位。同一规则也体现在 REPORT = 0x06 与 REPORT_RESP = 0x86 上。把最高位置 1 表示应答,这样接收方判断"这是请求还是应答"只需一次位测试,无需查表。
还要注意一个方向性事实:发现阶段 SM 只用 Get 和 Get Response 两个方向。这个阶段 SMA 不主动发起任何东西(除了 trap 类消息,属于监控职责而非发现职责)。SM 是唯一的发起方——这一点在 5.5 节的"gate 机制"里会体现得更清楚。
5.4 两级信息:节点级与端口级
课程把 Get 请求明确分成两类,并给出各自的字段清单:
| 层级 | 对应属性 | 包含的信息 | 在初始化中的作用 |
|---|---|---|---|
| 节点级 Node Level |
Node Info 0x0011 |
节点类型(node type) | 判定是交换机、HCA 还是路由器 |
| 端口数量(number of ports) | 决定后续要发起多少次端口级查询 | ||
| 端口级 Port Level |
Port Info 0x0015 |
MTU | 端口可用 MTU,参与阶段 4 配置协商 |
| 宽度(width) | 决定物理通道(lane)的数量,如 1x / 2x / 4x | ||
| VL 数 | 端口支持多少条虚拟通道,决定 QoS 能力上限 |
节点级与端口级的请求顺序是固定的:课程在描述收集顺序时明确写的是"收集交换机信息,然后是端口信息,然后是主机信息"。这个顺序有两层含义:
- 对交换机节点:先 Node Info 拿到它有几个端口,再对每个端口依次发 Port Info。所以端口级查询的次数由节点级返回的 num_ports 决定。
- 对主机(HCA)节点:课程把它排在最后。这类节点出现在发现流程的末端——原因见 5.5 节。
课程对"节点级信息"的完整列举是四项:节点类型、端口数量、GUID,以及节点描述(node description)。前两项是发现算法必需,后两项是身份标识。第六节的抓包截图里能看到 Subnet Get Node Info 与 Subnet Get Response Node Info 这一对报文,对应属性 0x0011;同屏还可见 Subnet Get Port Info 与 Subnet Get Response Port Info,对应属性 0x0015。
这四个名称(Get Node Info / Get Response Node Info / Get Port Info / Get Response Port Info)就是发现阶段在抓包中能看到的全部报文类型。如果抓包只看到其中一半,说明该方向的应答没有返回——这是发现卡住时第一个该看的现象。
5.5 "gate 机制":为什么发现不需要两两对话
Why — 跳板机制解决的是什么复杂度问题
假设一个 fabric 里有 N 个节点。最朴素的做法是 SM 与每个节点直接建立联系,需要 N 条直达路径——但 SM 只与其中极少数节点直连,这条路根本不存在。
课程给出的机制是:任何已经发现的交换机,都被 SM 用作进一步发现该交换机邻居的入口。这句话拆开就是三步循环:
- 对每个已知节点发一条定向路由 SMP,路径终点指向该节点
- 该节点回应 Get Response,报告它自己的信息以及哪些端口上有活着的邻居
- 把这些"活着的邻居"加入待查询队列,重复步骤 1
这个循环的复杂度是与链路数成正比,而不是与节点数的平方成正比。代价是路径描述变长了——每条查询都要携带从 SM 出发到目的地的完整端口号序列,这也是第六节示例的报文里能看到的 via 路径串。
关键推论:既然路径是"从 SM 出发依次经过的端口号",那么交换机能作为 gate 的前提是它会转发定向路由的 SMP 报文。交换机内部需要为定向路由维护一张"当前路径上下文",识别"这个包是从哪条路径进来的、下一步该往哪走"。这正是交换机固件的一项基本能力,也是为什么 fabrix 级的转发逻辑与普通 L2 转发是两套机制。
本节关键记忆:1 个通道 + 2 种寻址 + 2 条消息 + 2 级信息 + 1 个 gate
- 1 个通道:SMP 固定走 VL 15,与业务流量在链路层隔离——同时满足七项强制校验
- 2 种寻址:LID 路由 0x01(发现期不可用,LID 还没有)/ 定向路由 0x81(发现期的唯一选择)
- 2 条消息:Get 0x01 / Get Response 0x81——应答方法码 = 请求方法码 | 0x80
- 2 级信息:节点级 Node Info 0x0011(类型 / 端口数 / GUID / 描述)/ 端口级 Port Info 0x0015(MTU / 宽度 / VL)
- 1 个 gate 机制:交换机作为发现入口,把查询复杂度从 O(N²) 降到 O(链路数)
六、发现实例:一次跨四跳的拓扑遍历
本节把 5.5 节的算法跑一遍。课程给出的这个示例是理解 gate 机制最有效的材料——它把"请求"与"响应"两侧的完整路径串都写了出来,每一步都能和上一节的机制对上号。示例中出现的交换机命名沿用课程的 A / B / C / D / E,主机编号沿用课程的 10 / 13。
6.1 拓扑与遍历序列
先看这个示例的拓扑结构。课程描述的遍历路径涉及交换机 A、C、D、E、B 与主机 10,拓扑关系如下:
本节示例拓扑(端口编号沿用课程原始示例)
┌─────────┐
│ 主机 10 │
└────┬────┘
│ 端口 1
┌────▼────┐
│ 交换机 D│
└────┬────┘
端口1 │ ▲ 端口 3(通往 主机 13)
┌────▼────┐
│ 交换机 A│
└────┬────┘
端口 2 │ ▲ 端口 1
│ │
┌──────────┘ └───────────┐
│ │
┌─────▼─────┐ ┌───────▼─────┐
│ 交换机 E │ │ 交换机 C │
└─────┬─────┘ └───────┬─────┘
│ │ 端口 2
端口 2 │ │(通往 主机 10 一侧)
│ │
┌─────▼─────┐ │
│ 交换机 B │ │
└───────────┘ │
│
SM 出发:端口 1 ──────────────────────┘
(SM 与 交换机 C 直连)
目标:主机 13(LID 8)—— 主机 13 接在 交换机 D 的端口 3 上
下面按课程的原始叙述逐条拆解。这个过程分五轮对话,每一轮都是"SM 发 Get → 目标节点回 Get Response":
6.2 第 1 轮:发现交换机 C
SM 发出的请求:"我正在通过我的端口 1 请求信息"(I am requesting information via port number one)。
交换机 C 的响应:"我是一台交换机,我通过端口 2 回应。我有一个活着的端口 4。"(I am a switch responding via port two. I have a live port four.)
这一轮确立了第一个事实:交换机 C 是一台交换机(node type = Switch),它有一个对外的、状态为活跃的端口 4。课程强调:SM 将使用交换机 C 继续 fabric 发现。
6.3 第 2 轮:经交换机 C 发现交换机 A
SM 发出的请求:"我正在通过我的端口 1 请求信息。下一步:交换机 C 端口 4。"(I am requesting information via my port one. next, switch C port four.)
交换机 A 的响应:"我是一台交换机,我通过端口 1 回应。我有一个活着的端口 2。"(I am a switch responding via my port one. I have a live port two.)
这一轮出现了本节最关键的一个细节:响应报文里的路径是回程路径。"我通过端口 1 回应"指的是在交换机 A 这一侧的端口 1,也就是刚才 SM 请求进来的那个端口。回程路径 下一步:交换机 C 端口 2 与请求路径 下一步:交换机 C 端口 4 恰好是 C 的两个不同端口——这正是交换机内部为定向路由维护的路径上下文在起作用。
SM 继续使用交换机 A 作为 gate。
6.4 第 3 轮:经 A 发现交换机 D
SM 发出的请求:"我正在通过我的端口 1 请求信息。下一步:交换机 C 端口 4,下一步:交换机 A 端口 2。"
交换机 D 的响应:"我是一台交换机,我通过端口 1 回应。我有一个活着的端口 3。"回程路径为 下一步:交换机 A 端口 1,下一步:交换机 C 端口 2。
注意回程路径在 A 和 C 两处都换了端口,这说明路径的进出端口在同一台交换机上是不同的——这是交换机的基本行为,路径串必须完整记录每一跳。
6.5 第 4 轮:发现主机 10,分支结束
SM 发出的请求:"我正在通过我的端口 1 请求信息。下一步:交换机 C 端口 4,下一步:交换机 A 端口 2,下一步:交换机 D 端口 3。"
主机 10 的响应:"我是一个 HCA,我通过端口 1 回应。"回程路径为 下一步:交换机 D 端口 1,下一步:交换机 A 端口 1,下一步:交换机 C 端口 2。
课程给出了这一轮为何是终点的原因:因为一般来说 HCA 是 fabric 的边缘,不会被用于进一步发现(since generally HCAs are the edge of the fabric and will not be used for further discovery)。
这句话的技术含义是:发现算法在交换机上继续、在 HCA 上停止。原因很直接——HCA 后面不再挂交换机,节点级的"活跃端口"清单到 HCA 这里就没有后继可查了。课程用的是"一般来说"这个限定,本篇如实保留它——这是对典型拓扑的描述,不是协议的强制约束;协议层面并没有禁止一台被 SM 认作交换机的设备继续充当 gate。
本例中没有被发现的分支:课程在这个示例里只走了 C → A → D → 主机 10 这一条链。拓扑中的交换机 B、交换机 E、主机 13 属于另一条分支(A → E → B 与 D → 主机 13),需要 SM 在后续的扩散循环中分别独立发现。发现是一个队列驱动的迭代过程,课程的示例截取了其中一条链,用来展示路径串的构造方式。
6.6 发现完成后 SM 手里拿到了什么
课程明确列出了拓扑信息的三个组成部分,这是本节最该记住的结论:
| 组成部分 | 具体内容 | 在后续阶段的用途 |
|---|---|---|
| 所有 fabric 交换机和 HCA | 节点清单 | 阶段 2 的 LID 分配对象 |
| 所有端口链路 | 端口级连接关系 | 阶段 3 路径计算的唯一依据 |
| 拓扑由节点 GUID 与端口号描述 | GUID 标识身份,端口号标识连接点 | GUID 是发现阶段唯一可用的稳定标识符 |
把"拓扑由 GUID 和端口号描述"这条与课程列举的字段清单合起来看,SM 在发现阶段结束时,对每个节点与端口掌握的信息是完整的:
- 每个节点:节点类型、端口数量、GUID、节点描述
- 每个端口:MTU、VL 数、宽度——其中宽度决定物理通道(lane)的数量,以及速率
把 5.3 节到本节的发现过程串起来看,会发现一个清晰的寻址语言的切换点,这个切换点是整个初始化流程的分水岭:
阶段 1 只能用 GUID 语言。在此刻,fabric 中还没有任何 LID。SM 手上唯一能指认"某个具体端口"的稳定标识就是 Port GUID——它由厂商烧录,全球唯一,与拓扑、与本次启动、与 SM 是谁都没有关系。这就是为什么发现阶段的 SMP 只能走定向路由:报文中携带的是"从 SM 出发依次经过的端口号序列",路径的终点是端口号而不是地址,SM 通过"走到某个端口"来间接确认"我找到了某个 GUID 代表的设备"。
阶段 2 之后切换到 LID 语言。SM 为每个受管理节点分配 LID 之后,fabric 第一次拥有了子网内短地址。从这一刻起,所有面向数据面的转发决策都可以用 16 位的 LID 完成,而不必再携带 64 位的 GUID。
这次切换带来的收益是量化的。本系列第一篇已经说明 LID 出现在 LRH 中。LID 只有 16 位,GUID 是 64 位——放在 8 字节 LRH 里,前者只占 2 字节。这 6 个字节的节省对每一跳的每一个数据包都成立,在高包速率的转发场景下,这是转发表存储、缓存与解析开销上的实质差异。
这次切换也带来一条硬约束。LID 只在子网内有效——这正是第一节提到的"共同的子网 ID"这个属性存在的理由。一个端口换到一个子网去,它的 LID 就失效了,必须重新分配。所以第七节的 LID 分配不是一个一次性动作,而是与子网归属强绑定的动作。
用一句话概括这三个阶段的关系:GUID 用来"找到",LID 用来"转发",而切换发生的那一步,就是 LID 被分配的那一刻。理解了这条主线,第七节到第十一节的每一项配置动作就都有了明确的位置。
本节关键记忆:5 轮对话 + 1 条路径规则 + 1 个停止条件 + 3 项产物
- 5 轮对话:C → A → D → 主机 10,每轮的请求路径与响应路径分别记录进/出端口
- 1 条路径规则:交换机上"进端口 ≠ 出端口",因此路径串必须逐跳完整记录
- 1 个停止条件:发现到 HCA 时该分支结束——HCA 位于 fabric 边缘,不再向外扩展
- 3 项产物:全部交换机与 HCA 清单 + 全部端口链路 + 拓扑由 GUID 与端口号描述
- 1 次语言切换:阶段 1 用 GUID(十六进制稳定性),阶段 2 之后用 LID(16 位效率)
七、阶段三:LID 分配的三条规则
What — 分配的前提与三条规则
课程给出的前提条件是:一旦 fabric 拓扑发现完成,SM 就为每个被发现的节点分配一个唯一的 LID。并且明确:子网中的每个受管理节点,在初始化阶段由子网管理器分配 LID。LID 用于在本地子网内路由数据包。
三条分配规则如下,规则的核心判据是"什么算作一个受管理节点":
| 设备类型 | 分配规则 | 规则的理由 | 举例 |
|---|---|---|---|
| HCA | 每个端口一个 LID | 每个端口被视为一个单独的受管理节点(each port is considered a single managed node) | 双端口 HCA → 两个不同的 LID,两个端口各得一个 |
| 单一 IC 的交换机 | 整台一个 LID | 每台交换机被视为一个单独的受管理节点(each switch is considered a single managed node) | 单芯片交换机 → 一个 LID |
| 多 IC 的模块化交换机 | 每个 IC 一个 LID | 每个 IC 被视为一个单独的受管理节点(each IC is considered a single managed node) | 模块化 chassis 内每块交换芯片各得一个 LID |
7.1 规则背后的统一判据:粒度对齐
Why — 三条规则其实是同一条规则的三种应用
把这三条规则并排看,会发现它们反复用到同一个句式:"X 被视为一个单独的受管理节点"。这说明规则本身只有一条:
粒度对齐原则 —— LID 分配的单位,必须与"被管理实体"的粒度一致。
为什么粒度必须对齐?因为 LID 是交换机做转发决策时唯一使用的键。交换机拿到一个包,读取 LRH 里的目的 LID,然后在自己的转发表里查这个 LID 对应的出口端口。如果一个物理端口对应多个 LID,交换机就必须为该端口维护多条转发规则,而且这些规则在不同目的节点上必须走同一个出口端口——否则同一个端口会根据目的不同从不同方向出去,这在物理上不成立(除非那正是 LMC > 0 的多路径场景,见 7.3 节)。
反过来,如果一个受管理节点内部有多个物理端口却只分到一个 LID,交换机在转发到这个 LID 时就无法区分应该从哪个物理端口出去。所以粒度不匹配的两种情形都会导致转发歧义,协议必须强制它们对齐。
7.2 为什么 HCA 按端口而交换机按整机
这个不对称是很多初学者的困惑点。它的物理原因在于两种设备的可编程单元边界不同:
- HCA 的每个端口是一块独立的物理接口,各自有独立的光模块、独立的高速 SerDes 通道、以及独立的 MAC 层逻辑。对 HCA 而言,"把两个端口的地址空间合并成一个"在物理上没有对应物——数据要从哪根光纤出去,是硬件决定的,不由地址决定。
- 交换机的转发决策在一块交换芯片(IC)内部完成。一台单 IC 交换机,所有端口汇聚到同一块芯片的同一套转发表里,一个 IC 就是一台设备在协议层的化身。而模块化交换机包含多块 IC,每块 IC 有自己的转发表与自己的管理接口——所以每块 IC 都需要被独立寻址。
换句话说:HCA 的"受管理单元"是端口,交换机的"受管理单元"是交换芯片。规则统一,物理成因不同。
模块化交换机的可观测后果:一台 2 个 IC 的模块化交换机,在 ibswitches 输出里会出现两行——因为它有两个受管理节点,各有一个 LID,需要分别查询。排查时如果发现"交换机数量比预期多了一台",先确认那是不是模块化交换机的两个 IC。
7.3 进阶:LMC 与一个端口多个 LID
课程给出的规则是"每端口一个 LID"。这个规则在默认配置下成立,但 IB 规范提供了一个机制允许一个端口持有多个 LID,这个机制对理解第八节的路径选择至关重要。
这个机制叫 LMC(LID Mask Count,LID 掩码计数)。OpenSM 官方 man page 的定义是:分配给每个端口的 LID 数量是 2^LMC,LMC 取值范围 0 到 7。
| LMC 值 | 每端口 LID 数量 | 含义与后果 |
|---|---|---|
| 0 | 20 = 1 | OpenSM 的默认值。任意两个端口之间只有一条路径 |
| 1 | 21 = 2 | 两个端口之间可以有两条路径 |
| 2 | 22 = 4 | 四条路径 |
| … | … | … |
| 7 | 27 = 128 | 128 条路径 |
man page 同时给出了使用前提:LMC 大于 0 只应在子网拓扑实际提供了多条路径时使用,也就是交换机之间存在多条互联链路。这解释了 LMC 存在的意义——只有当拓扑里确实有多条等价路径时,才有"从哪条走"的选择;拓扑里只有一条链路时,多分配 LID 毫无意义。
LMC 的分配还有一条对齐要求:一个端口的 base LID 必须对齐到 LMC 块边界。OpenSM 源码 opensm/osm_lid_mgr.c 中计算掩码的方式是 lmc_mask = ~(num_lids - 1),即把低位清零。
LMC 这个机制表面上只是"多给几个 LID",但它揭示了 LID 编码里一个很精巧的设计:LID 的低位并不是纯粹的地址位,它们被复用为路径编号。
观察分配方式。2^LMC 个 LID 作为一个连续的块分配给同一个端口,并且这个块的起始 LID 对齐到块边界。以 LMC = 1 为例,一个端口拿到形如 L 与 L + 1 的两个 LID,其中 L 的最低位为 0(这是对齐要求)。这两个 LID 在低 1 位上正好是 0 和 1 两种取值。
这个低位就是路径选择位。对 LMC = 1 的情况,发送端发出一个目的为 L 的包,与发出一个目的为 L + 1 的包,走的是同一个目的节点——因为它们属于同一个端口。差别在于沿途的交换机可以把这个低位作为判据来选路:路径 0 的交换机把这个 LID 映射到出口端口 1,路径 1 的交换机把它映射到出口端口 2。由此实现了等价多路径。
这个设计的收益是零额外开销。多路径没有引入新的报文头字段、没有引入新的转发表结构——它完全复用已经存在的 LID 字段与已经存在的 LFT 查表流程。交换机不需要"知道"LMC 这个概念,它只需要按普通 LFT 查表即可;是 SM 在编程 LFT 时,把不同低位的目的 LID 填到了不同的出口端口上。
这个设计也解释了默认 LMC = 0 的选择。man page 明确写了 LMC 值大于 0 时 Connection Manager(或任何其他建立 RC 连接的方式)需要采取额外步骤才能利用路径迁移能力。换句话说,把 LMC 开到 0 以上是一个明确的取舍:换取链路级负载分担,代价是通信层要配合才能利用。因此在没有多链路互联的拓扑里,OpenSM 坚持默认值 0。
本节关键记忆:1 个前提 + 3 条规则 + 1 条判据 + 1 个进阶
- 1 个前提:拓扑发现完成后,SM 为每个被发现的节点分配唯一 LID;LID 用于本地子网内路由
- 3 条规则:HCA 按端口 / 单一 IC 交换机整台 / 多 IC 交换机按 IC
- 1 条判据:粒度对齐——LID 的分配单位必须等于"被管理实体"的粒度,否则交换机无法唯一定位出口端口
- 1 个进阶:LMC 取值 0~7,每端口获得 2^LMC 个连续且对齐的 LID;LMC = 0(1 个 LID)是默认值,LMC > 0 需拓扑具备多条等价路径
八、阶段四:Min Hop 路径计算与端口均衡
What — 计算目标与最小跳数算法
课程明确了三件事:
- SM 计算从每台交换机到子网中每个节点的路径(paths from each of the switches to each of the nodes in the subnet)
- 到达一个目的节点可能存在多条路径,但只有最佳路径会被安装进交换机转发表,其他路径用作链路中断时的备份
- SM 使用的最简路由算法是 Min Hop(最小跳数)。Min Hop 计算每个端口到达每个 LID 所需的跳数(交换机数),最短路径被选为最佳路径
注意第 1 条的措辞:路径是"从交换机"出发算的,不是从任意节点出发算的。原因是转发表在交换机上——交换机必须知道自己到每个目的 LID 该从哪个端口出去。这与 1.1 节的结论一致:只有交换机需要这张表,所以只有交换机需要算这条路。
8.1 实例:从交换机 A 到主机 13(LID 8)的三条候选路径
课程给出的示例是:从交换机 A 到分配了 LID 8 的主机 13 的所有路径的临时表计算。共有三条可能路径:
交换机 A 到 主机 13(LID 8)的三条候选路径
路径 1(经 交换机 C)
┌──────────┐ 端口1 端口6 ┌──────────┐ 端口3 ┌──────────┐
│ 交换机 A ├──────────►│ 交换机 C ├─────────►│ 交换机 D ├───────►│ 主机 13 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
跳数 = 2 (经由 2 台交换机:交换机 C、交换机 D)
路径 2(经 交换机 D)
┌──────────┐ 端口2 端口3 ┌──────────┐
│ 交换机 A ├──────────►│ 交换机 D ├─────────►│ 主机 13 │
└──────────┘ └──────────┘ └──────────┘
跳数 = 2 (经由 1 台交换机:交换机 D)
路径 3(经 交换机 E、交换机 B)
┌──────────┐ 端口3 端口2 ┌──────────┐ 端口2 ┌──────────┐ 端口2 ┌──────────┐ 端口3 ┌──────────┐
│ 交换机 A ├─────────►│ 交换机 E ├──────►│ 交换机 B ├──────►│ 交换机 D ├─────►│ 主机 13 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
跳数 = 4 (经由 4 台交换机:E、B、D)
关于跳数的计数口径,这里需要说清楚。课程原文写的是"有 2 跳""有 2 跳""有 4 跳",对应的描述是"最少的交换机或跳数"(fewest switches or hops)。从上面的图可以核对出口径:路径 1 经过交换机 C、交换机 D 两台中间交换机,路径 2 只经过交换机 D 一台中间交换机,路径 3 经过 E、B、D 三台中间交换机。
课程给出的数字(2 / 2 / 4)与"中间交换机台数 + 1"这个口径一致:路径 1 = 2 台中间交换机 + 1 = 3 段链路;路径 2 = 1 + 1 = 2 段;路径 3 = 3 + 1 = 4 段。课程原文把两者并列使用("fewest switches or hops"),本篇如实保留这一表述,并在上面的图中分别标出了两种计数,供读者按自己的口径核对。无论采用哪一种口径,路径 3 都是最长的、路径 1 与路径 2 属于同一梯队——这才是本例的结论所在,口径差异不影响选择结果。
8.2 第一步:选出最短的一批
按 Min Hop 的定义,最短路径被选为最佳路径。三条路径中,路径 1 与路径 2 属于同一梯队,路径 3 明显更长,被直接排除。
课程在这里给出了本节的第一个关键判断:在这个例子中,存在两条到达目的 LID 8 的 2 跳路径。SM 只会把其中一条作为最佳路径安装进交换机转发表(The SM will install only one of them as the best path in the switch forwarding table)。
8.3 第二步:跳数相同时按端口 LID 计数决胜
剩下两条候选怎么选?课程给出了明确的判据,完整表述有两句:
- 每个端口都有一个计数器,统计有多少个目的 LID 经过它(each port has a counter counting the number of target LIDs going through it)
- 当存在多个到同一 LID 跳数相同的候选端口时,选择已分配 LID 最少的那个端口(the port with the fewest LIDs assigned to it is selected)
把这两句放在一起,就能读出这个算法的完整意图:Min Hop 只负责"选最短",端口计数器负责"把最短的候选分摊开"。两者目标不同——前者优化路径长度,后者优化链路负载。合并起来才构成"最佳路径"的完整含义。
课程给出的最终结果是:从交换机 A 到 LID 8 的最佳路由是经由端口 1(from switch A, the best route to deal at eight is via port one),即路径 1。
课程对 Min Hop 的描述可以拆成两个动作,OpenSM 官方文档 doc/current-routing.txt 给出了与之结构一致的两阶段表述。把二者对齐,可以确认这不是对课程的转述偏差,而是对标准实现流程的准确概括:
阶段一 — MinHop 矩阵计算。官方文档的原问句是"How many hops are required to get from each port to each LID?"——这正是课程"计算每个端口到每个 LID 所需的跳数"的原文对应物。文档同时指出,标准(min hop)路由使用一种"松弛"(relaxation)算法把最小跳数从每个目的 LID 向外传播穿过邻居交换机。这一句解释了为什么阶段 1 必须在拓扑发现完全结束之后才能进行——松弛传播需要完整的连通性信息,中途停止会得到不完整的矩阵。
阶段二 — LFT 出口端口分配。文档明确写道:"Once MinHop matrices exist, each switch is visited and for each target LID, a decision is made as to what port should be used to get to that LID."——注意这里的 each switch is visited,它印证了 8.1 节开头"路径是从每台交换机出发计算"这一点。随后文档给出的判据与课程完全一致:每个端口有一个计数器统计经过它的目的 LID 数量;当存在多个同跳数候选端口时,选择此前已分配 LID 较少者。
官方文档还揭示了课程未展开的一个分支:LMC > 0 时的额外检查。当 LMC > 0(即 7.3 节说的一个端口持有多个 LID)时,判断顺序会变长,具体是:a. 只使用跳数相同的端口;b. 优先选择走向不同 systemImageGuid 的端口(然后是同一 LMC 组内的前一个 LID);c. 若都不满足,优先选择经过另一个 NodeGuid 的端口;d. 最后才回落到按路径数量判断。这四步的意图很清楚:先把链路负载分摊开,再把系统分摊开,最后才考虑节点分摊。b 与 c 之所以优先于 d,是因为它们保证流量不会集中在同一台物理主机或同一套系统映像上——这比单纯的计数均衡更有实际价值。
文档还说明了 Min Hop 的调用方式:不指定路由引擎时默认启用 Min Hop,也可以用 -R minhop 显式指定。OpenSM man page 列出的其他可选引擎包括 updn、dfss、sssp 等,并且明确 如果所有已配置的路由引擎都失败,OpenSM 总是会回落到 Min Hop(除非配置了 no_fallback)。把 Min Hop 设为最终回退,是官方对它的可靠性评价。
8.4 备份路径:为什么算了却不装表
课程明确指出:只有最佳路径会被安装进交换机转发表,其他路径将在链路中断时作为备份使用。
这引出一个值得想清楚的问题:既然拓扑里明明有这些路径,为什么不把它们也装进转发表?
答案在转发表的工作方式里。LFT 的作用是为一个目的 LID 唯一决定出口端口——交换机收到包、读出目的 LID、查表、得出唯一出口。一个 LID 在一张 LFT 里只能对应一个出口端口。因此"多条路径"在数据结构上无法同时表达,它必须表达为"平时用哪条,故障时换哪条"的时序关系。
所以备份路径的启用时机不是"平时并行分担",而是故障发生时由 SM 重新计算并重写转发表。这一点必须说清楚,否则容易得出"IB 默认做多路径负载均衡"的错误结论——那需要 LMC > 0 且通信层配合(见 7.3 节),是另一套机制。
一个重要的实践含义:链路 down 之后,SM 需要完成"重新发现 → 重新分配(可能不重分配)→ 重新计算路径 → 重新编程转发表"这一整套流程,在此期间受影响的流量会中断。这与本系列第一篇提到的"主备 SM 切换是软实时,毫秒级到秒级"属于同一类时间特性。对中断敏感的分布式存储,需要把"单链路故障到业务恢复"作为一个独立的验证项纳入测试范围。
本节关键记忆:1 个算法 + 2 个阶段 + 1 个判据 + 1 条约束
- 1 个算法:Min Hop,从每台交换机到每个节点计算;OpenSM 默认引擎,可用 -R minhop 显式指定
- 2 个阶段:先算 MinHop 矩阵(松弛传播,需完整拓扑)→ 再逐交换机分配 LFT 出口端口
- 1 个决胜判据:跳数相同时,选"已分配 LID 计数最少"的端口;本例结果为经端口 1
- 1 条约束:一个目的 LID 在 LFT 中只对应一个出口端口,所以备份路径不能并行分担,只能在链路故障时由 SM 重算后启用
- 1 个常见误解澄清:Min Hop + 端口计数 ≠ 默认多路径负载均衡,那需要 LMC > 0 且通信层配合
九、阶段五:节点与端口的四个配置参数
What — SM 为每个端口配置的四个参数
课程明确:子网管理器为每个端口配置以下参数:LID、宽度、MTU 和速率。本节把这四个参数逐个讲透,因为它们是"发现阶段采集到的信息"与"配置阶段写入硬件的值"之间的交接点。
| 参数 | 课程给出的定义 | 来源与去向 | 配错的后果 |
|---|---|---|---|
| LID Local Identifier |
由 SM 分配给端口的地址,在子网内唯一,用于子网内的数据包转发 | 来源:阶段 2 分配 去向:写入端口,供交换机建 LFT |
LID 冲突 → 转发到错误节点 |
| Width 宽度 |
物理通道(lane)的数量 | 来源:阶段 1 从对端 Port Info 采集 去向:写入端口 |
宽度协商失败 → 速率下降 |
| MTU Maximum Transfer Unit |
定义最大包载荷大小 | 来源:两端 Port Info 协商 去向:写入端口 |
两端不一致 → 大包被丢弃 |
| Speed 速率 |
端口工作的速率,应当与节点端口到线缆另一端设备之间最慢设备的速率一致 | 来源:两端协商 去向:写入端口 |
不匹配 → 链路无法建立 |
9.1 为什么速率必须匹配链路上最慢的设备
Why — 速率取"最慢"是链路层的物理约束,不是保守设计
课程给出了一个很具体的说法:速率应当与节点端口到线缆另一端设备之间最慢设备的速率一致。这条规则有清晰的物理解释:
一条链路上数据要连续流动,发送端的时钟与接收端的时钟必须能被锁存对齐。这个对齐(也就是链路训练要完成的核心目标)要求两端使用同一个速率档位。如果一端跑 200 Gb/s、另一端只能跑 100 Gb/s,接收端无法在正确的时间点采样,训练不收敛,物理状态无法从 Training 推进到 LinkUp。
因此实际部署中,速率的取值由这条路径上串接的所有设备中最慢的一个决定。课程原话在这里有一个很实用的例证逻辑:如果一端是 QDR 卡、另一端是 DDR 交换机,协商结果会是 DDR 而不是 QDR——因为 DDR 那一端是链路的瓶颈。
这条规则有两个直接的运维推论:
- 混插不同代际设备时会降速,但不会不通。新交换机配老 HCA,速率降到老设备的档位,这是预期行为而不是故障。
- 降速是"整段路径"的属性,不是"两端设备"的属性。一段路径上任何一个中间交换机降速,整条路径都降速——这意味着看 Rate 时要沿着 ibtracert 输出的完整路径逐跳核对,不能只看两端。
9.2 宽度:容易被当成带宽的量
课程对宽度的定义只有一句:宽度是物理通道(lane)的数量。这个定义需要配上一个容易出错的理解:
宽度 ≠ 速率。两者独立协商,独立显示。
ibstat 会分别显示 Rate(每通道的 Gb/s 速率)与宽度信息。有效带宽 ≈ 速率 × 宽度,但这两个数字分别来自两次独立的协商过程:速率是双侧的时钟协商,宽度是双侧的通道数协商。
因此存在"速率对但宽度降级"的情况(例如两端都支持 100 Gb/s,但只有一半通道连通),此时业务可用带宽下降而 Rate 显示不变。排查带宽问题时两个数字都要看。
9.3 四个参数与发现阶段采集内容的闭环
把第九节与第五、六节并排看,会发现一个完整的闭环,这也是本篇知识结构上最关键的一次收束:
| 参数 | 在发现阶段从哪里来 | 用哪个 SMP 属性读 | 属性 ID |
|---|---|---|---|
| 节点类型 | SM 直接询问 | Node Info | 0x0011 / 17 |
| 端口数量 | SM 直接询问 | Node Info | 0x0011 / 17 |
| GUID / 节点描述 | SM 直接询问 | Node Info / Node Desc | 0x0011 / 0x0010 |
| MTU | SM 向端口询问 | Port Info | 0x0015 / 21 |
| 宽度(lane 数) | SM 向端口询问 | Port Info | 0x0015 / 21 |
| VL 数 | SM 向端口询问 | Port Info | 0x0015 / 21 |
| 速率 | 链路训练协商结果 | Port Info / 训练后读取 | 0x0015 / 21 |
把六个阶段的输入与输出列成一张表,会发现一条严格的链式依赖:每一个阶段的输出都是下一个阶段的必要输入。这种依赖不是流程设计的偏好,而是由协议本身决定的。
阶段 0 → 阶段 1:物理连线的产出是"存在可达的邻居"。没有它,阶段 1 的定向路由路径串无从构造——路径串的每一跳都要求对应端口上确实接着另一台设备。
阶段 1 → 阶段 2:发现阶段的产出是"完整的节点与端口清单"。LID 分配必须覆盖这个清单里的每一个受管理节点,漏掉任何一个都会让该节点在转发表中不存在。这也解释了 2.1 节的结论——没有 SMA 的节点不会出现在清单里,因此永远拿不到 LID。
阶段 2 → 阶段 3:路径计算的输入是"LID 的全局映射"。Min Hop 矩阵的维度是"端口 × LID",没有分配完成的 LID 集合,这个矩阵的列数都不存在。课程明确把 LID 分配放在路径计算之前,顺序正是如此。
阶段 3 → 阶段 4:路径计算的产出是"每个目的 LID 的出口端口决定"。这个决定就是 LFT 的内容,阶段 4 的编程动作是把它写进交换机硬件。两者是同一件事的计算与执行,不是两件事。
阶段 4 → 阶段 5:端口配置完成的产出是"端口可以进入下一状态"。课程对 Armed 状态的定义是"端口配置完成,下一步是传输数据"——配置未完成就推进状态,交换机会按未完成的表转发数据包。
阶段 1 内部的次序也不能重排:节点级查询必须先于端口级查询,因为端口的数量本身是节点级查询的返回值。课程描述的顺序"先交换机信息,然后端口信息,然后主机信息"同时满足了这个依赖与效率要求——先用最少的报文确认"这里有一台设备、有几个端口",再按端口数展开查询。
把这条链式依赖完整列出来之后,一个很有价值的推论自然成立:初始化过程中的任何卡顿,都可以用"它卡在哪两个阶段之间"来定位。端口有 LID 说明阶段 2 完成了但阶段 5 没完成;端口连 LID 都没有说明阶段 1 就没发现到它。第十一节的状态判读方法,正是这条推论的直接应用。
本节关键记忆:4 个参数 + 1 条物理约束 + 1 个闭环
- 4 个参数:LID(子网内唯一,转发用)/ Width(lane 数)/ MTU(最大包载荷)/ Speed(端口工作速率)
- 1 条物理约束:速率必须匹配路径上最慢设备——因为发送接收两端时钟必须锁存对齐,训练不收敛就无法 LinkUp
- 1 个易错点:宽度 ≠ 速率,两者独立协商;有效带宽 ≈ 速率 × 宽度,排查带宽问题两个数字都要看
- 1 个闭环:四个参数全部来自阶段 1 用 SMP 采集的节点级与端口级信息——发现与配置是一对输入输出
十、QoS:SL-to-VL 映射与 VL 仲裁
What — QoS 与虚拟通道的关系
课程的定义是:QoS 使网络能够为一组用户或应用提供更好或更特别的服务。实现这一点的机制是虚拟通道:
- 虚拟通道(VL, Virtual Lane)提供了一种在单条物理链路上实现多个逻辑流的手段(provide a means to implement multiple logical flows over a single physical link)
这个定义里有三个关键词值得单独强调:逻辑流(不是物理通道)、单条物理链路(强调共享)、多个(强调隔离)。它们合起来说明了一件事:VL 是链路层对单条物理链路的软复用。
10.1 SL-to-VL 映射表:决定"走哪条虚拟通道"
课程对映射表的定义非常完整,必须逐项读完,因为其中每一个输入维度都对应一个独立的判据:
fabric 中的每台交换机都包含一张称为 SL-to-VL 映射表的表,它基于三件事来选择出口端口的虚拟通道:
- 数据包的服务等级(the packet service level)
- 数据包被接收的端口(the port on which the packet was received)
- 数据包将要去的端口(the port to which the packet is destined)
这三条输入里,前两条常被忽略,但它们恰恰解释了为什么需要一张表而不是一个简单的函数:
Why — 为什么必须同时看"服务等级"和"进端口"
如果映射只依赖服务等级,那么规则就是"SL 5 走 VL 5,其余走 VL 0",一张 16 项的一维表就够了。但课程明确要求同时考虑接收端口和目的端口,这意味着规则实际是二维甚至三维的:
- 进端口的作用:同一条物理链路的两端,如果对端设备的能力或配置不同,合理的映射就不同。把进端口纳入判据,等于承认"映射规则是逐链路独立配置的"。
- 目的端口的作用:出端口的缓冲与仲裁能力决定了它能承受多少条虚拟通道的竞争。把目的端口纳入判据,意味着同一个 SL 在通向不同交换机端口时可以用不同的 VL,避免把流量都压到一个带宽紧张的出口上。
所以映射表的实际组织方式是"对每一个 (进端口, SL) 组合,给出到每个出口端口应使用的 VL"。这解释了它的数据规模——交换机端口数 × 服务等级数 × 端口数,在大规格交换机上是一张很大的表。这正是它需要由 SM 统一编程的原因。
10.2 VL 仲裁:决定"哪条虚拟通道先发"
课程的定义是:虚拟通道仲裁是输出端口用来选择从哪条虚拟通道传输的机制(the mechanism an output port utilizes to select from which virtual lane to transmit)。
把 10.1 与 10.2 放在一起看,两个机制的分工就非常清楚了——它们回答的是两个完全不同的问题:
| 机制 | 回答的问题 | 作用对象 | 表属性 | 属性 ID |
|---|---|---|---|---|
| SL-to-VL 映射表 | 这个包应该进哪条虚拟通道? | 单个数据包 | SL-to-VL Table | 0x0017 / 23 |
| VL 仲裁表 | 这个端口上,下一个该发哪条虚拟通道的包? | 整个输出端口 | VL Arbitration Table | 0x0018 / 24 |
这张表把 QoS 的两个维度讲清楚了:映射决定分类,仲裁决定调度。前者是"这个包属于哪一类",后者是"这些类之间怎么排队"。QoS 能力之所以能实现,是因为这两件事都被硬件表格化并由 SM 编程,不依赖任何软件参与转发。
10.3 完整的查表顺序
课程在最后给出了一段完整的查表流程,这段流程把第十节与第八节、L2 转发串成了一条线:
- 当一个数据包到达交换机时,它查看 LRH 中的目的 LID
- 然后把目的 LID 与 LFT 条目匹配,决定出口端口
- 如果该端口存在 SL-to-VL 映射,就确定相应的 VL
- 否则,数据包被送到默认 VL,也就是 VL 0
- VL 仲裁提供了一种控制来自不同虚拟通道的数据包被服务顺序的机制
一个数据包在交换机内的完整转发路径
┌──────────────┐
│ 入端口 │ ← 收到包的物理端口
└──────┬───────┘
│
▼
┌──────────────────────────────────────────────────────────┐
│ ① 从 LRH 读出「目的 LID」 │
│ │
│ LRH: ┌─────────┬─────────┬─────────┬──────────────┐ │
│ │ VL │ SL │ DLID │ 其他 │ │
│ └─────────┴─────────┴─────────┴──────────────┘ │
└──────────────────────────┬───────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────┐
│ ② 查 LFT(Linear Forwarding Table,属性 0x0019) │
│ │
│ 目的 LID 出口端口 │
│ ───────── ──────── │
│ 5 → 1 │
│ 8 → 1 │
│ 12 → 3 │
│ ... │
│ │
│ 输出:唯一确定的出口端口 │
└──────────────────────────┬───────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────┐
│ ③ 查 SL-to-VL 映射表(属性 0x0017) │
│ 三个输入:① 数据包的服务等级 SL │
│ ② 数据包被接收的端口(入端口) │
│ ③ 数据包将要去的端口(出端口) │
│ │
│ 有映射 → 确定对应的 VL │
│ 无映射 → 走默认 VL 0 │
└──────────────────────────┬───────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────┐
│ ④ 出端口执行 VL 仲裁(属性 0x0018) │
│ 决定:出端口上有多条虚拟通道,下一个发哪一条的包 │
│ │
│ VL 0 队列 [ ][ ][ ] │
│ VL 1 队列 [ ][ ] │
│ VL 2 队列 [ ] ← 按 VL 仲裁表加权轮转挑选 │
│ ... │
└──────────────────────────┬───────────────────────────────┘
▼
从出端口发出
第十节的查表流程里有一个位置问题值得单独讨论:QoS 决策发生在链路层,而不是网络层。这个位置选择不是随意定的,它由 SL 与 VL 这两个字段在报文中的位置直接决定。
先看两个字段的归属。本系列第一篇已经确认:SL(服务等级)与 VL(虚拟通道)都在 LRH 中,而 LRH 是链路层路由头。同时它也确认了另一个关键事实——VL 在子网内是交换机可以修改的字段,因此它被纳入 VCRC 的覆盖范围。这两点合起来解释了 QoS 为什么必须落在链路层:交换机必须在逐跳转发的过程中不断重算虚拟通道,而这一动作需要 VCRC 机制提供完整性保护。如果 QoS 决策放在网络层或传输层,改一个包就得改动更外层的校验结构,代价完全不同。
再看 SL 与 VL 的分工。SL 表达的是意图——"这个包属于哪个服务质量等级",它在发送端由应用或传输层设定,在端到端过程中保持不变。VL 表达的是实现——"在这个端口的这条物理链路上,用哪条逻辑通道来传它",它可以逐跳改变。SL-to-VL 映射表做的正是这个转换:把一个全网一致的意图,翻译成一段可能逐跳不同的实现。
这个设计的收益是全局 QoS 与局部资源可以解耦。应用只管设 SL,不需要知道沿途每台交换机的端口配置;每台交换机只管维护自己的映射表,把收到的 SL 翻译成本地最合适的 VL。两边的策略各自独立演进,任意一方调整都不需要另一方配合。
VL 15 的选择也印证了这套机制的边界。既然 VL 是逐跳可变的,那"管理流量必须与业务流量隔离"就不能靠业务侧自觉,而要靠一个不可能被业务占用的通道——课程与规范都把子网管理报文固定在 VL 15,就是这个思路的极端形式:预留一个最高编号的虚拟通道专门给管理,任何业务配置都不应触碰它。第五节列出的那七项强制校验里,"LRH:VL 必须为 15"就是这条约定的强制执行点。
本节关键记忆:1 个定义 + 2 张表 + 5 步查表 + 1 个位置
- 1 个定义:VL = 在单条物理链路上实现多个逻辑流的手段;QoS 的目的是为一组用户或应用提供更好的服务
- 2 张表:SL-to-VL 映射表 0x0017 决定"进哪条 VL"(三个输入:SL / 入端口 / 出端口);VL 仲裁表 0x0018 决定"哪条 VL 先发"
- 5 步查表:读 LRH 的目的 LID → 查 LFT 定出口端口 → 查 SL-to-VL 定 VL(无映射走 VL 0)→ 出端口执行 VL 仲裁
- 1 个位置结论:QoS 决策在链路层——因为 SL 与 VL 都在 LRH 中,且 VL 逐跳可变、由 VCRC 保护
- 1 条分工:SL 是全网一致的意图,VL 是逐跳可变的实现,映射表负责把前者翻译成后者
十一、阶段六:子网激活——物理状态 × 逻辑状态
What — 激活阶段的前提
课程明确了进入激活阶段时的处境:SM 已经发现拓扑、配置了端口、配置并编程了交换机。最后一个阶段是激活子网。
激活的核心概念只有一句,但这一句把整个激活阶段组织了起来:每个 InfiniBand 端口都有一个物理状态和一个逻辑状态。当端口物理上是 up 且逻辑上是 active 时,它才能用于数据传输。
这就是一个二维状态机。本节要讲透的正是:两个维度各自有哪些状态、每个状态的判定条件是什么、以及两个维度如何交叉约束。
11.1 物理状态:链路本身的状态
课程列举了端口的若干物理状态,本节完整展开其中三个,并说明为什么"链路没连好"这件事必须先在物理层解决:
| 物理状态 | 课程定义 | 链路层行为 | 枚举值 |
|---|---|---|---|
| Polling | 端口的默认初始状态。此时端口的发送器在生成信标序列,接收器在等待响应该信标序列。此状态下该端口与相邻端口之间没有连接,最可能的原因是线缆未连接或未正常工作 | 未建立链路 | 2 |
| Training | 在两个链路端点之间建立链路同步的过程。它控制着 Link Down 到 Link Up 的状态转换 | 正在收敛 | 4 |
| Link Up | 端口的正常工作状态,此时链路可以传输数据包 | 可传输 | 5 |
枚举值可在 infiniband-diags/ibstat.c 的 port_phy_state_str[] 数组中直接读到,该数组完整定义为:"No state change", "Sleep", "Polling", "Disabled", "PortConfigurationTraining", "LinkUp", "LinkErrorRecovery", "PhyTest",下标即枚举值。因此 Polling = 2、PortConfigurationTraining = 4、LinkUp = 5。
Polling 状态的定义里有一个容易被一带而过的细节:发送器在生成信标序列,接收器在等待响应该信标序列。这个描述揭示了 InfiniBand 链路建立的一个关键设计选择——链路的探测是双向且对称的。
两个方向承担的角色是不同的。发送侧生成信标序列,它的职责是宣告"我在这里,我的物理参数是什么"——速率、宽度、调制方式等链路训练所需的信息都编码在信标里。接收侧等待并回应,职责是"我收到了你的宣告,我同意这些参数吗"——并且要把自己这一侧的能力一并带回去。只有这个往返完成,两端才可能对"用哪个速率、几个通道"达成一致。这正是第九节那条"速率必须匹配最慢设备"规则在链路层的执行机制——它不是一条配置规则,而是信标交互的一个必然结果。
"没有连接"这个措辞也需要准确理解。课程说 Polling 状态下"该端口与邻居端口之间没有连接",然后给出原因:最可能是因为线缆未连接或未正常工作。关键在于"最可能"这个限定——信标在等不到回应,与线缆没插好是同一种表现。端口发出信标、对端完全收不到,就不会回信标,本端就一直停在 Polling。所以从端口自身的视角,它无法区分"对端没插线"和"线插了但坏了",这两件事在 ibstat 输出上完全一样。
这解释了 Polling 状态排查的一个固定次序。既然端口无法区分线缆故障的两种成因,排查就只能按从外到内的顺序推进:先查线缆两端是否插到位,再查对端设备与端口状态,最后才查本端固件与驱动。课程把"线缆未连接或未正常工作"列为 Polling 的最可能原因,实质上就是给出了一个排查优先级。
最后一点与 Training 的关系。课程把 Training 定义为"控制 Link Down 到 Link Up 的状态转换",这两个说法指向同一个转换,只是从两端描述——Training 是过程,Link Up 是结果。而 Polling 到 Training 的切换条件,就是信标交互成功。三个状态连成一条链:Polling(探测 → 等不到回应)→ Training(同步 → 收敛中)→ Link Up(可用)。
11.2 逻辑状态:SM 眼中的端口状态
课程指出:InfiniBand 端口还有若干逻辑状态,它们指示端口是否 up,以及是否已被子网管理器发现并激活。逐个展开:
| 逻辑状态 | 课程定义 | 链路层行为 | 枚举值 |
|---|---|---|---|
| Down | 物理层没有 up。链路层丢弃所有提交给它的待发送数据包 | 全部丢弃 | 1 |
| Init | 物理状态是 up 的,链路层只能接收和发送 SMP 报文与流控链路包。链路层丢弃所有其他接收到的或提交给它的待发送数据包 | 只放行 SMP + 流控 | 2 |
| Armed | 端口配置已完成,下一步是传输数据 | 就绪待激活 | 3 |
| Active | 通过 dummy 数据包与 VCRC 校验后进入(见 11.3) | 可正常转发 | 4 |
枚举值定义在 libibverbs/verbs.h 的 enum ibv_port_state 中,完整定义为 IBV_PORT_NOP = 0, IBV_PORT_DOWN = 1, IBV_PORT_INIT = 2, IBV_PORT_ARMED = 3, IBV_PORT_ACTIVE = 4, IBV_PORT_ACTIVE_DEFER = 5。ibstat 正是用这个下标去查 port_state_str[] 数组得到显示字符串 "???", "Down", "Initializing", "Armed", "Active"。
状态名称在 ibstat 中的显示与规范名称不同:规范的 INIT 在 ibstat 里显示为 Initializing,规范的 ACTIVE 显示为 Active。读输出时不要因为字符串不同而对不上号。另外 ibstat 的字符串表只到下标 4,下标 5(ACTIVE_DEFER)会显示为 ???——看到 ??? 不是程序出错,而是该状态的显示字符串未收录。
11.3 从 Armed 到 Active:dummy 数据包与 VCRC
课程原文给出的这一步
课程对 Armed → Active 的转换给出了明确的前置条件与验证手段,这里逐句拆解:
- 目的:为了验证数据能够被成功传输(in order to verify that data can be transferred successfully)
- 手段:子网管理器生成一个附加了 VCRC 的虚拟数据包(the subnet manager generates a dummy data packet with an added VCRC)
- 作用:在两个直连设备之间提供链路级数据完整性(provides link level data integrity between two directly connected devices)
- 验证:所有收到该数据包的节点都校验其 VCRC,以确认数据包在传输过程中没有被损坏
- 结果:随后该节点从 Armed 状态进入 Active 状态
这四句话里有三个技术点值得展开:
- 为什么是 VCRC 而不是 ICRC。本系列第一篇已经确认:ICRC 覆盖不变字段,VCRC 覆盖可变字段,而 VL 属于可变字段。dummy 数据包的目的正是打通整条虚拟通道路径——它要验证的不仅是比特传输无误,还包括"这个 VL 上确实能通过有效流量"。只有校验 VCRC,才能同时确认包内容正确且 VL 通路可用。
- 为什么"所有收到该包的节点"都要校验。因为一个数据包可能经过多跳,每一跳的交换机都会修改 VL 从而重算 VCRC。任一节点的校验失败,都说明这条路径的某一段有问题。课程用"所有节点都校验 VCRC 来确认包在传输中未被损坏"这个表述,准确对应的就是这个分布式验证过程。
- 为什么这一步在 SM 侧发起。课程写的是"子网管理器生成 dummy 数据包"。由 SM 而非由设备自发发起,保证了验证是全局受控的——只有 SM 知道当前哪些端口已经配置完成、可以进入下一状态。如果每个端口自行激活,就会出现"部分端口已 Active、部分还在 Armed"的中间态,而此时业务的可达性是不确定的。
课程给出了激活的终局判定:当子网管理器已向所有端口发送 Active 之后,子网就是可用的(when the subnet manager has sent active to all ports, the subnet is operational)。
11.4 两个状态的交叉约束
课程用一张简表把两个维度交叉起来,这是本节最该记住的结论:
端口状态的二维约束关系
逻辑状态(Logical State)
Down Init Armed Active
┌──────────┬──────────┬──────────┬──────────┐
Polling │ │ │ │ │
│ 必然 │ × │ × │ × │
Training │ Down │ │ │ │
│ │ │ │ │
物理 ──────┼──────────┼──────────┼──────────┼──────────┤
状态 │ │ │ │ │
│ × │ │ │ ✔ │
LinkUp │ │ │ │ 正常 │
│ │ ↓ │ ↓ │ 工作 │
│ │ 只能收 │ 配置完成 │ 状态 │
│ │ 发 SMP │ │ │
└──────────┴──────────┴──────────┴──────────┘
└──────── 状态推进方向 ────────┘
课程结论:
· 物理状态是 Polling 或 Training 时,逻辑链路状态必然是 Down
· 物理状态是 LinkUp 时,逻辑状态会依次经过 Init → Armed → Active
· 正常工作的目标状态:物理 = LinkUp 且 逻辑 = Active
把 11.1 到 11.4 节的内容合起来看,会发现一个设计上的必然:端口的状态之所以要拆成两个维度,是因为"链路能通"和"链路被允许使用"是两个独立的条件。把它们压成一个状态机会丢失信息,而丢失的那部分信息恰好是排查故障最需要的。
先看两个维度各自回答什么问题。物理状态回答的是"这条链路在物理上能不能传比特"——由两端设备自主完成训练与协商,不需要 SM 参与,SM 无法强制它变成 LinkUp。逻辑状态回答的是"SM 是否已经把这条端口纳入子网并允许它转发业务"——由 SM 通过 SMP 的 Set 指令驱动,完全在 SM 控制之下。两个维度各有各的驱动主体与失败原因,压成一个维度就等于把两个不同的责任方混为一谈。
再看 Init 状态的设计意图,它是整个状态机里最有信息量的一格。课程规定:物理状态 up 时,链路层只能接收和发送 SMP 报文与流控链路包,丢弃所有其他数据包。这一条规定同时解决了两件事——一方面它让 SM 能够继续与端口通信(SMP 必须放行,否则配置无法下发、状态无法推进,形成了死锁),另一方面它严格禁止业务流量(在配置未完成时转发数据包会导致错误转发)。"只放行 SMP 与流控"是一条把控制面与数据面彻底分开的规则,它比简单的"禁用端口"精细得多。
再看流控链路包为什么也必须放行。链路层流控包承担的是信用(credit)管理职责——它决定发送端何时可以发送数据。如果流控包被丢弃,发送端的信用计数就无法正确更新,即使后续把端口推进到 Active,也会因为信用不足而无法有效发送。因此"只放行 SMP 与流控"这一条规定里的两项,缺一不可。
最后,交叉表提供了明确的排查价值。因为两个维度正交,任何一个异常组合都能唯一定位到问题层次:Polling + Down 是物理层问题(线缆、对端端口),与 SM 无关;LinkUp + Initializing 是管理面问题(SM 未运行、未发现到该端口、或配置未完成);LinkUp + Active 之外的其他组合都指向需要介入的状态。这种"正交分解"带来的定位效率,正是把状态拆成两个维度而非一个的根本价值。
11.5 状态判读:ibstat 输出的读法
课程给出了一个双端口 HCA 的实际观察,课程原话是:我们看到一个双端口 HCA 的状态。逐项读:
- 端口 1:物理状态是 Polling,此时逻辑状态必然是 Down。原因可能是线缆未连接或连接不当
- 端口 2:物理状态是 LinkUp 且逻辑状态是 Active,这是端口承载数据的正常工作状态。同时输出显示该端口已被 SM 发现,并被分配了 LID 5
这个例子把四种组合中的两种放在了同一台设备上对照,排查价值很高。把 ibstat 的输出字段与判读方法整理如下(字段含义引自 ibstat(8) man page,输出格式引自 rdma-core 的 infiniband-diags/ibstat.c):
| 输出字段 | 含义 | 排查时的用法 |
|---|---|---|
| State | 逻辑状态(ibv_port_state) | Active = 正常;Down = 物理未 up;Initializing = 物理 up 但未被 SM 纳入 |
| Physical state | 物理状态 | LinkUp = 链路正常;Polling = 等不到信标响应,查线缆;Disabled = 端口被禁用 |
| Rate | 端口工作的速率(Gb/s) | 应当等于路径上最慢设备的速率,比两端标称值低是正常的 |
| Base lid | 本端口的 base LID | 65535 = 未被 SM 分配 LID(未分配时的取值) |
| SM lid | SM 端口的 LID | 为 0 通常意味着该子网尚无可用的 SM |
| LMC | LID Mask Count(见 7.3 节) | 0 = 每端口 1 个 LID(默认);大于 0 时 LFT 存在等价多路径 |
| Port GUID | 本端口的 GUID | 发现阶段唯一稳定的身份标识,用它向 SM 查询信息 |
| Link layer | 链路类型 | InfiniBand / Ethernet |
两条字段组合的判读口诀
- Port GUID 有值 + Base lid = 65535 → 设备在,SM 没管到它。硬件与驱动正常,问题在管理面(SM 未运行 / SM 未发现到该节点 / 该节点无 SMA)。
- Base lid 正常 + State = Initializing &rsup; 已被发现,配置或激活未完成。问题在 SM 侧的下发流程(配置未下发、dummy 数据包校验未通过、或 SM 尚未下发 Active)。
- Rate 低于两端标称速率 → 沿 ibtracert 输出逐跳找降速点,最慢的那一跳就是原因。
本节关键记忆:3 物理 + 4 逻辑 + 1 个验证 + 1 个终态
- 3 个物理状态:Polling(2) 默认初始态,发信标等回应 / Training(4) 建立链路同步 / LinkUp(5) 正常可传
- 4 个逻辑状态:Down(1) 物理未 up / Init(2) 只放行 SMP + 流控 / Armed(3) 配置完成待激活 / Active(4) 可转发
- 1 个验证:SM 生成附加 VCRC 的 dummy 数据包,所有收到该包的节点校验 VCRC——通过后才从 Armed 进入 Active
- 1 个终态判据:物理 = LinkUp 且 逻辑 = Active;物理为 Polling / Training 时逻辑必然是 Down
- 1 个正交性:物理由两端自主训练决定,逻辑由 SM 下发决定——两个维度分别对应物理层问题与管理面问题
十二、FAQ 高频问答(20 组)
本节围绕子网初始化的 20 个高频易错点展开。题目覆盖概念边界、报文机制、算法细节、状态判读四类,答案中的属性编号、方法码、管理类值、状态枚举值均引自文末「参考资料」列出的头文件与规范原文。
Q1. Fabric 和 Subnet 到底差在哪里?
Fabric 是物理集合(链路 + 交换机 + 路由器 + 通道适配器);Subnet 是管理集合(一组拥有共同子网 ID、由同一个 SM 管理的端口及其关联链路)。两个关键差异:粒度不同(Fabric 到设备,Subnet 到端口)与有无管理归属不同(Fabric 无归属,Subnet 有)。Fabric 必须由 SM 初始化并激活后才成为 Subnet。
Q2. 多个 Subnet 之间是怎么连起来的?
子网之间可以通过路由器相互连接。路由器工作在网络层,使用 GRH 中的 GID 进行跨子网转发。这也解释了为什么 LID 只能在子网内有效——跨子网必须用 GID 路由,不能用 16 位的 LID。
Q3. SM 可以跑在哪些设备上?必须是一台独立服务器吗?
不是。SM 可以实现在 fabric 中的任意节点上,课程明确列举了三类载体:一台服务器、一台交换机、或一台专用设备。SM 本身是软件,没有强制硬件形态。需要注意的是:无论跑在哪里,SM 所在的那个节点自己也必须配 SMA 才能被管理。
Q4. 什么是 SMA?为什么每个节点都必须有它?
SMA(Subnet Manager Agent)是运行在被管理节点上的代理,它让 SM 能够与该节点通信并配置它。每个被管理节点都需要一个。原因是 SMP 报文需要节点来解析并应答,缺少 SMA 的设备对 SM 而言等于不存在——它不会被分配 LID,不会出现在任何转发表中,业务表现是"接了线但完全不通"。
Q5. 布线上明确的三条禁止事项是什么?为什么 SM 修不了布线问题?
三条是:不使线缆打结或过度弯折、不扭曲 InfiniBand 接头、不把线缆留在可能被推车或人员踩踏的地面上。因为阶段 1 到阶段 5 全部由 SM 自动完成,只有阶段 0 的物理连线是人工的。布线故障在 SM 看来只是"那个方向没有节点"——是一句合法且安静的结论,不报错。对应故障表现:过度弯折表现为物理状态在 LinkUp 与 LinkErrorRecovery 间跳变;接头扭曲表现为停在 Polling;线缆落地表现为间歇性断连,每次断连都会触发 SM 重算路径。
Q6. SM 用什么报文发现拓扑?为什么必须固定用 VL 15?
用 SMP(Subnet Management Packet),固定通过 VL 15 发送。这是规范对收到的 SMP 的一组强制校验之一,完整条件有七项:载荷长度必须 256 字节、LRH:VL 必须为 15、BTH:DestQP 必须为 0、BTH:Opcode 必须是 UD Send-Only、MADHeader:BaseVersion 必须为 1、MgmtClass 必须是 Subn 或 Directed-Route Subn、AttributeID 必须是某个 SM 属性。用独立的 VL 15 的好处是管理流量与业务流量在链路层隔离,不会被业务流量饿死。
Q7. LID 路由和定向路由的区别是什么?管理类字段的值分别是多少?
LID 路由携带目的端口的 LID,管理类为 0x01(IB_MGMT_CLASS_SUBN_LID_ROUTED);定向路由携带一串"依次经过的端口号",管理类为 0x81(IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)。发现阶段只能用定向路由——因为此刻 LID 还没有分配,被查询的设备不知道自己有任何地址。工具上可以直接看到这个差别:smpquery -D nodeinfo 0 用 -D 表示定向路由,路径写作 "0,1,2,1,4";smpquery portinfo 3 1 第一个参数 3 就是 LID。
Q8. Get 与 Get Response 的方法码是多少?为什么发现阶段只用这两个方向?
IB_MGMT_METHOD_GET = 0x01,IB_MGMT_METHOD_GET_RESP = 0x81。规律是应答方法码 = 请求方法码 | 0x80,其中 0x80 是 IB_MGMT_METHOD_RESP(应答标志位),同一规则也体现在 REPORT = 0x06 与 REPORT_RESP = 0x86。发现阶段只用这两个方向,因为SM 是唯一的发起方,SMA 常态是被动响应查询(trap 类消息属于监控职责)。
Q9. 节点级与端口级 Get 分别取什么?属性 ID 是多少?
节点级是 Node Info,属性 0x0011(17),取节点类型、端口数量、GUID、节点描述;端口级是 Port Info,属性 0x0015(21),取 MTU、宽度(lane 数)、VL 数、速率。顺序是固定的:先用节点级拿到 num_ports,再对每个端口发端口级查询——端口级查询的次数由节点级返回值决定。抓包中能看到的四个名称就是 Subnet Get Node Info / Get Response Node Info / Subnet Get Port Info / Get Response Port Info。
Q10. 为什么"已发现的交换机"能当跳板?中间交换机具体做了什么?
因为交换机内部为定向路由维护了路径上下文,能识别"这个包从哪条路径进来、下一步该往哪走"。这个机制把发现复杂度从"每个节点两两对话"降到"每条链路查一次"。在课程示例里可以看到它如何工作:SM 向交换机 C 的端口 4 发请求,交换机 A 从端口 1 回应,回程路径写的是"下一步:交换机 C 端口 2"——同一个交换机 C 上,进出端口不同,路径串必须逐跳完整记录。
Q11. 发现为什么遇到 HCA 就停止?
因为 HCA 位于 fabric 的边缘,不会被用于进一步发现。课程原话是"generally HCAs are the edge of the fabric and will not be used for further discovery"——这个表述是"一般来说",即对典型拓扑的描述,不是协议的强制约束。技术原因很直接:HCA 后面不挂交换机,节点级的"活跃端口"清单到 HCA 这里就没有后继可查,算法自然收敛。
Q12. 发现完成后 SM 手里到底拿到了什么?
三项:① 所有 fabric 交换机和 HCA;② 所有端口链路;③ 拓扑由节点 GUID 与端口号描述。逐节点看:节点级掌握节点类型、端口数量、GUID、节点描述;逐端口看:掌握 MTU、VL 数、宽度(lane 数)与速率。这四项恰好是第九节配置阶段要写入端口的内容——发现与配置构成一对输入输出闭环。
Q13. 双端口 HCA 和单 IC 交换机各分几个 LID?多 IC 模块化交换机呢?
规则统一为"粒度对齐"——LID 的分配单位必须等于被管理实体的粒度:HCA 按端口,所以双端口 HCA 得两个不同的 LID;单一 IC 的交换机整台一个;多 IC 的模块化交换机按 IC,每个 IC 一个。可观测后果:一台 2 个 IC 的模块化交换机,在 ibswitches 输出里会占两行,因为它有两个受管理节点。
Q14. LMC 是什么?为什么默认是 0?
LMC(LID Mask Count)决定每个端口获得多少个 LID,规则是 2^LMC 个,取值范围 0 到 7,因此 LMC = 0 时每端口 1 个。man page 明确两点:OpenSM 默认 LMC = 0,此时任意两个端口之间只有一条路径;LMC > 0 只应在拓扑实际提供了多条等价路径时使用(即交换机之间有多条互联链路)。因为 LMC > 0 时 Connection Manager 或其他 RC 建立方式需要额外步骤才能利用路径迁移能力——开高 LMC 是明确的取舍。分配时 base LID 必须对齐到块边界,OpenSM 源码中掩码算作 lmc_mask = ~(num_lids - 1)。
Q15. Min Hop 里的"hop"具体数的是什么?OpenSM 怎么算这个矩阵?
课程把口径表述为"最少需要的跳数或交换机数",两者并列。OpenSM 官方文档的问句是"How many hops are required to get from each port to each LID?",并说明标准(min hop)路由使用"松弛"(relaxation)算法把最小跳数从每个目的 LID 向外传播穿过邻居交换机。课程示例中路径 3 经过交换机 E、B、D 三台中间交换机,按"中间交换机 + 1"计为 4。无论采用哪种口径,路径 3 最长、路径 1 与路径 2 同梯队,这个结论不受口径影响。
Q16. 跳数相同的候选路径,SM 按什么规则选?
按"已分配 LID 最少"的端口选。完整机制是:每个端口有一个计数器,统计有多少个目的 LID 经过它;当存在多个到同一 LID 跳数相同的候选端口时,选择已分配 LID 较少者。课程示例中,从交换机 A 到 LID 8 的最佳路由最终确定为经由端口 1。OpenSM 官方文档描述一致,并补充 LMC > 0 时的额外检查顺序:只选跳数相同者 → 优先选走向不同 systemImageGuid 的 → 再优先经过另一个 NodeGuid 的 → 最后才按路径数量。
Q17. 备份路径是干什么的?它什么时候才会被用上?
备份路径用于链路中断时替代最佳路径,但它们不会被装进转发表。原因是转发表的结构:一个目的 LID 在一张 LFT 里只能对应一个出口端口,多条路径无法在数据结构上同时表达,只能表达为"平时用哪条、故障时换哪条"的时序关系。因此备份路径的启用不是"平时并行分担",而是链路故障后由 SM 重新计算并重写转发表。实践含义:故障后到恢复前有一段重算时间,期间流量会中断,对中断敏感的分布式存储需要把"单链路故障到业务恢复"作为独立验证项。
Q18. SM 给每个端口配哪几个参数?速率有什么约束?
四个:LID、Width、MTU、Speed。LID 是 SM 分配给端口的地址,子网内唯一,用于子网内转发;Width 是物理通道 lane 的数量;MTU 定义最大包载荷大小;Speed 的约束是必须与节点端口到线缆另一端设备之间最慢设备的速率一致。原因是发送接收两端时钟必须锁存对齐,训练不收敛就无法从 Training 推进到 LinkUp。推论:降速是整段路径的属性而非两端设备的属性,排查时要沿完整路径逐跳核对。
Q19. 端口停在 Polling 和停在 Initializing,排查方向有什么不同?
完全不同,因为两个状态对应两个正交的维度。Polling + Down 是物理层问题——端口在发信标等不到回应,端口自身无法区分"对端没插线"和"线插了但坏了",只能按从外到内的顺序查:线缆是否插到底 → 对端交换机端口是否启用 → 光模块与线缆是否匹配 → 最后查固件驱动。LinkUp + Initializing 是管理面问题——物理已通但未被 SM 发现或未完成配置,应查 SM 是否运行、SM 是否发现到该节点、该节点是否有 SMA。
Q20. ibstat 里 Base lid、SM lid、LMC、Rate 分别怎么用?
四条判读规则:① Base lid = 65535 表示未被 SM 分配 LID,此时若 Port GUID 正常则是管理面问题;② SM lid = 0 通常意味着该子网没有可用的 SM;③ LMC = 0 表示每端口 1 个 LID(默认,无等价多路径),大于 0 时 LFT 存在多路径;④ Rate 应当等于路径上最慢设备的速率,低于两端标称值是正常的降速行为,不是故障。另外注意 宽度与速率是两个独立协商的数字,有效带宽 ≈ 速率 × 宽度,排查带宽问题两个都要看。
FAQ 总纲(口诀式速记)
- 2 个边界:Fabric = 物理集合(无归属) / Subnet = 管理集合(共同子网 ID + 同一 SM,粒度到端口)
- 1 条因果:Fabric 必须由 SM 初始化并激活才成为 Subnet;没有 SMA 的节点对 SM 等于不存在
- 6 个阶段:物理连接 → 拓扑发现 → LID 分配 → 路径计算 → 端口配置 → 子网激活
- 1 个通道:SMP 走 VL 15,满足七项强制校验(256 字节 / VL 15 / DestQP 0 / UD Send-Only / BaseVersion 1 / MgmtClass / AttributeID)
- 2 种寻址:LID 路由 0x01(发现期不可用)/ 定向路由 0x81(发现期唯一选择)
- 2 条消息:Get 0x01 / Get Response 0x81(应答码 = 请求码 | 0x80)
- 2 级信息:Node Info 0x0011 / Port Info 0x0015
- 1 个 gate 机制:交换机作发现入口,复杂度从 O(N²) 降到 O(链路数);发现到 HCA 该分支结束
- 3 条 LID 规则:HCA 按端口 / 单 IC 交换机整台 / 多 IC 交换机按 IC——判据是粒度对齐
- 1 个进阶:LMC 取 0~7,每端口 2^LMC 个对齐的连续 LID,默认 0
- 1 个算法:Min Hop,两阶段(松弛传播算矩阵 → 逐交换机分配 LFT),跳数相同选已分配 LID 最少的端口
- 1 条硬约束:一个目的 LID 在 LFT 中只有一个出口端口——备份路径靠 SM 重算启用,不是并行分担
- 4 个端口参数:LID / Width(lane 数)/ MTU / Speed(取路径最慢值)
- 2 张 QoS 表:SL-to-VL 0x0017(三输入:SL / 入端口 / 出端口)→ VL 仲裁 0x0018;无映射走 VL 0
- 3 物理 + 4 逻辑:Polling(2) / Training(4) / LinkUp(5) → Down(1) / Init(2,只放行 SMP + 流控) / Armed(3) / Active(4)
- 1 个激活条件:SM 发出附加 VCRC 的 dummy 数据包,所有收到者校验通过 → Armed 变 Active
- 1 个终态:物理 LinkUp + 逻辑 Active;物理为 Polling / Training 时逻辑必然是 Down
十三、Roadmap 后续预告
本篇是 InfiniBand 专题的第八篇。它的位置很明确:本系列第一篇《InfiniBand 架构简介:从五层模型到子网管理》讲清了这个网络的骨架(分层、报文结构、三层地址、子网管理角色),第二篇《传输层:QP、分段重组、传输服务与分区》讲清了数据怎么在传输层搬运,本篇讲清了网络怎么从"一堆线缆"变成"一个能传数据的子网"。这三篇合起来覆盖了"从物理连接到应用数据"的完整链路中的前半段。
接下来的方向,按由初始化向运行期深入的顺序包括:
- 链路层流控(Credit-Based Flow Control):本篇第十一节反复提到 Init 状态"只放行 SMP 与流控链路包",但没有展开流控包本身。信用计数机制决定了发送端何时可以发送,是理解"为什么链路带宽用不满"的必备知识
- 组播转发表 MFT 与组播成员管理:本篇聚焦单播 LFT(属性 0x0019)。组播用 MFT(0x001B)与 MLID,走的是生成树而非最短路径,算法完全不同
- SM 主备选举与脑裂规避:本篇只讲了"SM 存在"的必要性与形态,没有讲多个 SM 时的选举机制、优先级比较、以及脑裂如何避免——这是生产环境高可用的关键
- QoS 策略的配置与验证:本篇讲了 SL-to-VL 映射表与 VL 仲裁表的结构与查表流程,但没有讲策略文件怎么写、怎么验证一条 QoS 策略是否真的生效——需要配合 smpquery 读表回读
- 随机转发表(Random Forwarding Table):属性 0x001A,用于散列转发(如按 GUID 散列),本篇只列出了编号未展开
- 拓扑变化后的重收敛时延:本篇第七、八节讲的是初次初始化的流程,链路 down 之后 SM 重跑发现与路径计算需要多久,是一个需要独立验证的工程指标
- 分区与 P_Key 表的编程:本系列第二篇讲了 P_Key 的报文结构与校验逻辑,但 P_Key 表(属性 0x0016)由 SM 编程下发这个环节属于初始化流程,是两篇的衔接点
- 软 RoCE 与硬件 InfiniBand 的管理面差异:rxe / Soft-RoCE 没有真实的 SM 硬件交互,很多管理动作靠模拟或简化实现,排查问题时不能把两者的行为直接类比
如果你在实践中遇到具体问题——例如端口停在 Initializing 且 SM lid 为 0、ibswitches 少列了一台交换机、ibroute 里某条目的出口端口与预期不符、QDR 卡接 DDR 交换机导致速率降级——欢迎在评论区留言,我会挑出共性问题单独扩展一篇专题。

浙公网安备 33010602011771号