
简介这是一份面向高性能计算与数据中心网络工程师、研究人员和IT架构师的技术规范文档对应InfiniBand架构第一卷Release 1.9草案2024年8月31日版。文档以修订历史为主线完整覆盖从2000年1.0版到1.9版的主要变更包括1.1的系统架构与CM类更新、1.3整合XRC、1.4新增虚拟化与RoCE-v1/v2附录、1.5的NDR与最小带宽保证、1.6的扩展操作码和VERIFY操作、1.7的网络探测A20附录及XDR支持直至1.8引入NeVerMore解决方案和最大64K端口的大规模交换机管理能力并明确1.9为最终发布于2025年7月的草案版。资源为单个PDF文件共1份压缩包约14.39MB适合需要跟踪IBTA规范演进、核对协议细节或设计兼容方案的读者阅读。目前已有841人浏览学习可帮助快速建立对InfiniBand最新特性的系统认知。1. IB Specification Vol 1.9为什么 400G 网卡会协商成 2.5G先给结论IB Specification Vol 1-Release-1.9-Draft-2024-08-31 不是一份拿来通读的文档而是一张对 InfiniBand 集群做体检的检查单。很多人压着 MLNX_OFED 版本、插着标称 400G 的线缆ping 通了就觉得万事大吉结果 HPC 作业一多就在丢包和降速上翻车。回头查原因答案基本都能在这份草稿里找到端口状态、链路宽度、QP 超时字段、子网管理属性规范里白纸黑字给了边界只是没人对着查。这篇笔记就按协议栈顺序拆一遍把规范里的关键参数和日常运维命令对齐适合被性能问题缠住的 HPC 运维、刚上手 IB 网络的新手以及想给 RoCE 配置找依据的存储工程师。2. 规范里的三层落点从链路状态、QP 状态机到 timeout 参数的物理含义IB 规范 Vol 1 的核心是 Channel AdapterHCA加子网管理这部分和以太网完全不是一套逻辑。理解它才能看懂后面所有命令输出。2.1 端口与子网模型SM 是 IB 子网的交警Vol 1.9 最开头定义的三个实体CAChannel Adapter、交换机Switch、路由器Router。一个 CA 端口就是一个节点每个端口由子网管理器Subnet ManagerSM分配一个唯一的 LID。LID 是 16 位字段实际可用范围是 0x0001 到 0xBFFF0xC000 到 0xFFFF 预留给组播0x0000 保留。每次插拔线缆后LID 都可能变这正是 IB 和以太网 IP 配置最大的区别。端口状态机也是 Vol 1 的重点。普通端口有 Down、Init、Armed、Active 四个主状态规范里用PortState属性承载数值分别是 1/2/3/4。端口从 Down 走到 Active中间必须经过 SM 的管理报文交换SM 通过定向管理报文QP0SMA下发PortInfo和SubnetRoutingTable端口拿到有效服务名Service ID和路径信息后才进入 Active。所以如果一台机器ibstat显示State: Init或者Armed不用查线先看 SM 是否活着这是规范定义的状态依赖关系带来的最直接排查方向。管理报文本身走 QP0 和 QP1。QP0 是子网管理接口SMAQP1 是通用服务接口GSI这两个 Queue Pair 由硬件保留普通用户程序碰不到。规范里对这两个特殊 QP 的行为描述非常详细但运维层面只需要记住如果 opensm 没跑ibstat看到的所有 State 都会停在 Down 或 Init这就是规范层面给出的判断依据。2.2 物理层与链路层SDR 到 NDR 的速率谱系链路层参数是 Vol 1.9 里最有实操价值的部分因为它直接解释了为什么速率会“掉档”。IB 物理层的速率演进是固定倍数关系SDR 2.5 GT/s、DDR 5.0、QDR 10.0、FDR 14.0625、EDR 25、HDR 50、NDR 100单位是每秒每 lane 的 Giga transfers。链路宽度又分 x1、x2、x4、x8、x12。所以一根标称 NDR 400G 的线物理上是 4 lane 每 lane 100G。只要有一个 lane 训练失败链路宽度自动降级速率就变成 100G甚至更低。规范里对应的属性有三个LinkSpeedActive、LinkWidthActive、PortPhysState。PortPhysState是物理层状态和上面说的逻辑状态不同它描述的是链路训练过程Sleep、Polling、Training、LinkUp、LinkErrorRecovery。运行ibstat时能看到两行State: Active逻辑状态表示 SM 已经完成子网融入Physical state: LinkUp物理状态表示链路训练完成这两个必须同时满足才算健康。常见翻车现场是State: Active但Physical state: LinkErrorRecovery这在规范里对应物理层连续发生链路错误后自动恢复的中间态。如果频繁抖动大概率是信号质量差和 upper layer 的丢包率直接相关。链路层的另一个关键项是 MTU。IB 的 MTU 只有五档256、512、1024、2048、4096。路径上所有端口的 MTU 必须取最小值而且 IB 流控的 credit 是以 64 字节为单位的MTU 越大单次 credit 能发送的数据越多吞吐越高。但注意MTU 和消息大小没有绝对关系比如写 1 字节到对端线路上也要消耗一个完整报文的最小开销。规范要求所有端口配置的 MTU 在路径上一致否则连接建立时ibv_modify_qp会报EPERM。2.3 传输层QP 状态机与 timeout 字段才是性能分水岭传输层是 Vol 1 里信息密度最高的部分。IB 通信的基本单位是 Queue Pair一个 QP 由发送队列和接收队列组成。QP 类型分四类可靠连接RC、不可靠连接UC、不可靠数据报UD、原始数据报Raw。RC 提供保序、可靠、拥塞控制的端到端语义是 MPI 和存储主路径上最常用的类型UD 更轻量适合多对多通信但不保证可靠。QP 状态机是排障的关键。QP 依次经过 Reset、Init、RTR、RTS 四个状态出问题后会进入 SQErr 或 Error。每一步都有前置条件Init 状态必须指定 PKey 和端口号转 RTR 必须带上path_mtu、rq_psn、max_dest_rd_atomic转 RTS 必须带timeout、retry_cnt、rnr_retry。这些字段不是随便填的规范对每个字段都给了边界范围。以timeout字段为例它占 5 bit实际值的意思是本地等待 ACK 的定时器换算公式是4.096us * 2^timeout。这个参数直接影响 RC 语义下链路故障的恢复时长。我一般用下面这段代码设置 QP 的 RTR 和 RTS 参数struct ibv_qp_attr attr {0}; attr.qp_state IBV_QPS_RTR; attr.path_mtu IBV_MTU_4096; attr.rq_psn 0; attr.max_dest_rd_atomic 1; attr.min_rnr_timer 0x12; ibv_modify_qp(qp, attr, IBV_QP_STATE | IBV_QP_PATH_MTU | IBV_QP_RQ_PSN | IBV_QP_MAX_DEST_RD_ATOMIC | IBV_QP_MIN_RNR_TIMER); attr.qp_state IBV_QPS_RTS; attr.timeout 20; /* 4.096us * 2^20 ≈ 4.29s */ attr.retry_cnt 7; /* 本地重试7 次 */ attr.rnr_retry 7; /* RNR 重试7 次 */ ibv_modify_qp(qp, attr, IBV_QP_STATE | IBV_QP_TIMEOUT | IBV_QP_RETRY_CNT | IBV_QP_RNR_RETRY | IBV_QP_SQ_PSN | IBV_QP_MAX_ATA);这里的逻辑有两层。第一timeout 20对应约 4.29 秒适合跨机房长链路如果是机架内短链路timeout 14约 67 毫秒更合理太大了故障切换慢太小了轻微拥塞就误判。第二rnr_retry是解决接收端没有预置 receive buffer 时的重试次数这个值设成 0 表示无限重试生产环境千万别设 0否则接收进程死锁时发送端会永远挂着。handler 部分的min_rnr_timer 0x12表示 RNR 等待的初始退避时间这也是规范里的固定换算值越大退避越激进对共享链路的公平性影响很明显。这个片段在配置 RoCE 时同样适用因为 RoCE v1 和 v2 在传输层复用了 IB 的定义。区别只在网络层RoCE v2 把 GRH 换成了 UDP/IP。所以 Vol 1.9 里所有关于 QP 状态、超时、重试的参数RoCE 场景下一字不差地照用。3. 把规范对到命令用 ibstat、ibv_devinfo、ibdiagnet 验证子网一致性规范读完了接下来是落地动作。这一章把 Vol 1.9 里的属性名和 Linux 命令行输出做映射让读者拿到手就能照着查。3.1 端口属性ibstat每一行对应规范哪个字段ibstat是排查 IB 端口最常用的命令。它输出的字段其实直接照搬规范中的属性定义。实例如下$ ibstat mlx5_0 CA mlx5_0 CA type: MT4129 Number of ports: 1 Firmware version: 16.33.1000 Hardware version: 0 Node GUID: 0x248a070300xxxxxx System image GUID: 0x248a070300xxxxxx Port 1: State: Active Physical state: LinkUp Rate: 200 Base Lid: 0x26 LMC: 0 SM lid: 0x1 Capability mask: 0x0259486a Port GUID: 0x248a070300xxxxxx Link layer: InfiniBandState对应PortState注意 ibstat 显示的是字符串数值 4 才是 Active。Physical state对应PortPhysState。Rate: 200对应LinkSpeedActive200 表示 200 Gbit/s即 EDR 4x如果是 400表示 NDR 4x。Base Lid对应PortLid。LMC对应LidMaskControl表示这个端口分配了几个 LID0 代表只有一个。参数说明LMC大于 0 时端口会占用一段连续的 LID 地址规格书里叫多 LID 支持用于自适应路由。看到State: ActiveRate正常还不够还要确认Base Lid在 0x0001~0xBFFF 范围内。如果看到Base Lid: 0x0000说明 SM 还没给这个端口分 LID等于端口在子网里不可达这是规范里 LID 合法范围的使用场景。3.2 子网一致性ibdiagnet怎么检查规范约束ibdiagnet是 OFED 自带的子网级巡检工具作用是扫描整个 IB 子网把拓扑、LID、路径、链路情况全部 dump 下来然后对照规范做一致性检查包括 LID 是否冲突、链路宽度是否两端一致、速率是否两端一致、是否有设备没有 SM 分配的路径。我常用的检查命令如下$ ibdiagnet -r -c -o /tmp/ibd_dump /tmp/ibd.log 21 $ grep -iE bad|conflict|error|warn /tmp/ibd.log | head -50 $ ls /tmp/ibd_dump ibdiagnet.fdbs ibdiagnet.lid2port.map ibdiagnet.links ibdiagnet.mcasts ibdiagnet.output需要说明的是-r表示 dump 路由表-c表示做一致性检查-o指定输出目录。扫描完成后ibdiagnet.lid2port.map是每个 LID 对应的物理端口ibdiagnet.links是链路协商出来的速率/宽度ibdiagnet.output里会给出各类 error 摘要。实际使用中我把它当作规范合规性的“体检报告”。比如ibdiagnet.links里能看到每对链路的WidthActive和SpeedActive。两端不一致时规范要求以较低端为准体现在文件里就是某条链路width_active: x1但再看线缆标称是x4。这时候不用怀疑规范直接查物理层训练状态即可。这个工具每次硬件变更后跑一遍是最低成本的合规验证方式。3.3 巡检脚本从规范字段到可复用的一键检查下面这段脚本是我在现网用的简化版检查逻辑先遍历 CA 查端口字段再跑ibdiagnet抓子网异常。建议放到 cron 里每天一次。#!/bin/bash # check_ib_health.sh for ca in $(ibstat -l); do echo $ca ibstat $ca | grep -E State|Physical state|Rate|Base Lid|Link layer done # 子网一致性 ibdiagnet -r -c -o /tmp/ibd_dump /tmp/ibd.log 21 # 提取异常行 grep -iE bad|conflict|error|warn /tmp/ibd.log | head -30这里有个细节ibstat -l列出的是 CA 实例名不是物理端口所以脚本里先获取 CA再逐个调用ibstat。如果机器上有双端口 HCAibstat会把 Port 1 和 Port 2 都输出不需要额外处理。脚本的核心思想就是让规范字段变成可观测的文本ibstat回答“端口状态对不对”ibdiagnet回答“子网规则守不守”。如果输出里出现State: Down或者 grep 到bad下一步就该按第 5 章的坑位去排。4. 把边界值变成配置opensm、LMC、FEC 与超时字段的落地参数看完规范之后紧接着的问题是这些字段在生产环境怎么设。我给读者梳理三条主线子网管理器参数、流控与 FEC、超时重试边界。4.1 opensm 参数与规范对齐opensm 是 OpenFabrics 自带的子网管理器是网络上所有 LID 分配、路径计算、状态推进的源头。规范里规定 SM 要维护全县拓扑视图而 opensm 的参数控制具体怎么做。启动命令我常用这样$ opensm -R ftree -l 1 -Q --qos_policy /etc/opensm/qos-policy.conf-R ftree指定路由算法为 Fat Tree适合对称拓扑-l 1把 LMC 设为 1意味着给每个端口分配 2 个 LID这样可以用自适应路由AR做粗粒度的多路径分担-Q加上--qos_policy启用 QoS 策略文件。QoS 策略里最关键的是 SL2VL 映射把不同 SL 映射到不同 Virtual Lane避免存储流量和高性能计算流量互相挤占。从规范角度解释VL 是链路层资源VL0~VL14 是数据流VL15 固定给子网管理。如果不开 QoS所有流量默认走 VL0拥塞时管理报文和业务互相干扰。这个参数在机架规模不大时看不出差别一旦跨交换机聚合拥塞丢包的影响会被放大很多。所以我在生产环境都建议至少给存储服务单独分一个 SL 和 VL。4.2 timeout、retry 与 RNR 的边界值第 2 章给了代码这里用一个换算表把核心边界值列清。表里的 timeout 字段是 5 bit取值 0~31retry_cnt 和 rnr_retry 都是 3 bit取值 0~7。注意 retry_cnt0 不是不重试而是“重试 0 次之后就报错”和很多人的直觉相反。场景timeout 字段实际超时retry_cntrnr_retry机架内短链路5m14~67 ms77跨机柜铜缆30m17~536 ms77跨机房长链路20~4.29 s77接收端未预置 bufferRNR 场景17~536 ms73不推荐的生产配置0特殊处理00这个表怎么用两个原则。第一timeout 的换算单位是 4.096 微秒乘 2 的幂次选值必须大于对端最长响应时间否则链路正常但响应稍慢就会误判超时。第二rnr_retry 不要设 0因为 0 表示无限重试接收端一旦僵死发送端会挂住最终靠更高层看门狗去救排障成本极高。4.3 FEC 与链路宽度物理层边界值物理层的配置项不多最容易踩的是 FEC。FDR 以上速率IB 链路默认要求开启 Reed-Solomon FECRS-FEC具体前向纠错的编解码方式在 Vol 1.9 物理层章节。Mellanox 网卡上可以用mlxconfig查询和修改$ mlxconfig -d mlx5_0 q | grep FEC FEC_MODE_P1 RS_544_528_P1(6)逻辑说明FEC_MODE_P1表示端口 1 的 FEC 模式常见的值是RS_544_528意思是使用 544 比特 RS 码块内含 528 比特有效数据。这个模式在两端的设置必须一致否则链路协商会退化。参数边界是EDR 和 HDR 速率下RS FEC 带来的编码开销约 3%但换来了对信号劣化的容错能力。如果两端一台交换机只支持 Fire Code 而网卡设成 RS-FEC协商结果就会掉到较低速度档。链路宽度边界也和 FEC 相关宽度越高并行 lane 越多对信号质量的要求越高。因此一根短距离 DAC 线2 米内可以跑 NDR x4如果同一根线拉到 5 米信号质量不够链路宽度可能协商成 x2。这种物理层行为规范管不了但通过对LinkWidthActive的持续监控可以发现。5. 避坑与常见问题排查链路协商、LID 冲突、CRC 增长三个现场这一章是我实际排障里遇到最多的三类问题每条都按“现象→原因→解决”写清楚。5.1 现象ibstat显示速率掉到 2.5G实例如下State: Active Physical state: LinkUp Rate: 2.5 Base Lid: 0x32原因这代表端口协商到了 SDR x1而不是线缆标称的 HDR x4。两类原因最常见一类是物理层训练失败后自动降级比如轧线导致的单 lane 信号劣化链路宽度降为 x1速度同时降到最低支持档 2.5G另一类是两端 FEC 配置不匹配比如一端强制 Fire Code另一端自动协商双方只能退到最保守的 SDR。解决先用ibstatus看两端各自的rate和width_active确认是不是两端一致。然后检查交换机那侧的 FEC 配置尽量让两端都设成 Auto 或同样的 RS-FEC。如果线缆是 DAC把线换到另一个端口排除物理损坏。最后用mlxconfig -d mlx5_0 s FEC_MODE_P16显式指定 RS-FEC等一分钟重新 link up。从那之后我遇到 Rate 异常第一步永远是先看width_active因为下降的速度档位是由 lane 数决定的。5.2 现象LID 冲突新机器插上后业务不通现象把一个新节点接入子网ibdiagnet输出里写duplicate LID或者新节点端口状态停在 Init 不进入 Active。原因这是静态 LID 分配和动态分配打架的典型场景。某些集群为了固定存储节点的地址会在 opensm 的配置文件里给特定 GUID 手写 LID但新节点插上来时网卡写入过非易失性静态 LID或者和已有静态配置段重叠SM 在检查时发现同一 LID 被两个端口占用。解决先停止 opensm执行ibdiagnet确认当前 LID 分配表。然后进入 opensm 配置目录通常/etc/opensm下有osm.conf检查routing_engine和固定的 GUID-to-LID 映射把新节点的 Node GUID 写进配置并指定一个未被占用的 LID或者干脆清掉网卡上持久化的lid属性$ mlxconfig -d mlx5_0 s LID_MASK_CONTROL_P10这条命令的作用是把端口上的 LID mask 重置为 0让 SM 重新分配。注意执行后需要重启驱动或 reboot 才会生效。核心教训是物理机上层的 LID 和 GUID 不是等价的GUID 才是设备的唯一身份LID 只是 SM 分配的临时地址。5.3 现象CRC 错误计数持续上涨现象用perftest跑ib_write_bw时持续吞吐不稳定ibdiagnet输出里看到symbol_error或者link_error_recovery计数非零更直观的是/sys/class/infiniband/mlx5_0/ports/1/counters/symbol_error数字增长。原因CRC 计数涨有两个方向。一个是物理层信号质量问题常见于光模块老化、光纤脏污、DAC 线弯折半径太小这类现场伴随LocalLinkIntegrityErrors增长并且往往只是单条链路。另一个是 FEC 配置不匹配导致的残余错误报错会在link_error_recovery上体现链路本身还是 Active但会频繁进入错误恢复状态。解决先确认是哪一类错误。cat /sys/class/infiniband/mlx5_0/ports/1/counters/symbol_error如果数值持续增加重点查物理光路如果link_error_recovery增加改用两端一致的 FEC。光模块问题就用光功率计扫DAC 问题直接换线。排查完硬件后用ibstat确认Physical state没有频繁跳变为LinkErrorRecovery。我认为最大的坑是很多人看到 CRC 上涨就去调 QP 的重试参数这是本末倒置——重试参数只能掩盖错误不会消除物理层的根源。6. 进阶技巧用 Vol 1.9 的计数器口径给集群建健康基线前面都是按“问题发生时怎么查”的思路更实用的做法是把这张规范变成一张长期健康表。6.1 把计数器变成基线IB 端口在 sysfs 里暴露了一组和 Vol 1.9 直接对应的计数器常见的有symbol_error、link_error_recovery、link_integrity_errors、excessive_buffer_overrun、vl15_dropped。这些不是随便起的名字每个在规范里都有明确定义。比如vl15_dropped表示因为接收缓冲不足而丢弃的 VL15 管理报文数这个值一旦增长说明子网管理报文被淹了拓扑发现会不正常。我一般会在每次新集群上线、版本升级后抓一把基线$ for counter in symbol_error link_error_recovery link_integrity_errors excessive_buffer_overrun vl15_dropped; do echo $counter$(cat /sys/class/infiniband/mlx5_0/ports/1/counters/$counter) done把这组值存成文件之后每两周对比一次。这里的关键是理解规范对计数字段的定义symbol_error只在物理层链路训练完成后统计链路掉线时计数会清零所以看到数字不涨反降不一定是好消息要先确认端口物理状态。对比基线时只看“端口稳定处于 Active 期间”的增量否则会被状态切换干扰。6.2 把基线变成告警进阶一步在计算节点上写一个以 5 分钟为周期的轮询脚本把增量反馈给监控系统。日志格式统一为hostname counter delta告警阈值我通常这样定link_integrity_errors的 delta 大于 10 就要检查物理链路vl15_dropped的 delta 大于 1 就要检查 SM 负载symbol_error只要非零就值得报出来看。这些阈值不是规范给的但规范定义的计数语义让这些阈值有了可解释性。6.3 和版本变更结合Vol 1.9 是 2024-08-31 的草稿不是最终版所以线上抓基线时要留意当前固件和驱动版本是否支持这些计数器的全部语义。比如旧固件对link_error_recovery的上报粒度可能和新版本不一样。读字段时先看ibv_devinfo -v打印的active_speed和active_width确认端口工作状态再读计数器才有意义。从那以后我每次交付 IB 网络第一件事就是把所有端口的 LID、速率、宽度、MTU 和计数器基线存成一份 JSON而不是等报障了才去翻ibdiagnet。这套动作成本很低但能帮你把“软故障”变成“早期信号”。希望这篇笔记能帮到你。本文还有配套的精品资源点击获取