4、子网管理器协议:SMP(子网管理包)格式、报文类型、常见操作(Get/Set)
核心原理:SMP 是子网管理器的“控制信道”
InfiniBand 网络中的数据报文分为两类:IB 数据报文(承载应用程序流量)与管理报文(承载子网管理、子网管理通告等控制流量)。SMP(Subnet Management Packet,子网管理包)是子网管理器(SM)与子网管理代理(SMA)之间通信的唯一协议载体。每个 IB 端口(无论是交换机端口、路由器端口还是 HCA/适配器端口)内部都实现了一个 SMA,负责响应 SM 发来的 SMP 请求。
SMP 报文直接承载在 InfiniBand 链路层的 管理数据报(Management Datagram,MAD) 之上,其报文格式与普通 IB 数据报文有显著区别:SMP 不使用 LID 路由(即不依赖子网内 LID 转发),而是使用 DGRH(Directed Route Header,定向路由头) 或 LID 路由头 进行寻址。在子网初始化阶段,当 LID 尚未分配时,SM 只能通过 DGRH 逐跳指定端口路径来访问每个节点;当 LID 分配完成后,SM 也可以使用 LID 路由头直接访问目标端口。
SMP 报文的关键特征包括:固定 256 字节的 MAD 载荷、Base Version 必须为 1、Management Class 必须为 1(对应 Subnet Management)、Class Version 为 1 或 2(取决于是否支持扩展属性)。SMP 报文在链路层以 VL15(虚拟通道 15)发送,这是专门为子网管理保留的最高优先级虚拟通道,确保即使网络拥塞,管理报文也能优先通过。
方法流程:SMP 报文类型与 Get/Set 操作机制
SMP 报文通过 Method 字段区分操作类型,核心方法包括以下四种:
| Method 值 | 名称 | 方向 | 说明 |
|---|---|---|---|
| 0x01 | Get | SM → SMA | 请求读取某个属性(如 NodeInfo、PortInfo) |
| 0x02 | Set | SM → SMA | 请求修改某个属性(如设置 LID、清空转发表) |
| 0x03 | GetResp | SMA → SM | 对 Get 请求的响应,携带属性数据或错误状态 |
| 0x04 | SetResp | SMA → SM | 对 Set 请求的响应,确认操作结果 |
除了上述四种基本方法,SMP 还支持 GetTable(0x12)和 SetTable(0x13),用于批量读取或写入大型表属性(如线性转发表、随机转发表),这些方法通过 AttrMod 字段中的偏移量分块访问。
一次典型的 Get 操作流程如下:
- SM 构造 SMP 报文,设置 Method=0x01(Get),填写目标属性 ID(如 0x15 表示 NodeInfo),并设置 TID(事务 ID)用于匹配响应。
- SM 通过 DGRH 或 LID 路由头将报文发送到目标端口的 SMA。
- SMA 收到后校验 M_Key(若属性需要)、检查属性是否可读,然后构造 GetResp 报文,将属性数据填入 Data 字段,Status 设为 0(成功)。
- SM 收到 GetResp 后,通过 TID 匹配请求,解析 Data 字段中的属性内容。
Set 操作流程与 Get 类似,但关键区别在于:
- SM 在 Data 字段中携带要写入的完整属性值(如新的 LID、端口状态等)。
- SMA 必须校验 M_Key 是否正确。若 M_Key 不匹配,返回 Status=2(无效 M_Key),且不执行任何修改。
- 部分属性(如 PortInfo)在修改后需要触发端口重启或重新初始化,SMA 会在 SetResp 中返回相应状态。
ibswitches 或 ibqueryerrors 等工具时,底层就是通过发送 Get 请求获取节点和端口信息;而 iblinkinfo 则通过 Get(PortInfo) 轮询所有端口的链路状态。当使用 ibdebug 工具时,可以实时打印 SM 发出的每个 SMP 报文,观察 Method、AttrID 和 TID 的变化。
案例/场景:用 SMP 完成节点发现与 LID 分配
以子网管理器启动时的 节点发现 阶段为例,SM 通过以下 SMP 操作序列完成全网扫描:
# 阶段1:扫描所有可能端口(使用 DGRH 逐跳访问)
# 对每个交换机端口发送 Get(NodeInfo)
SMP Get: DGRH[hop=0, port=0] → 目标端口 SMA
Method=0x01, AttrID=0x15 (NodeInfo)
TID=0x00000001
# 收到响应
SMP GetResp: Status=0 (成功)
Data: NodeGUID=0x0011750000012345
PortCount=36, LID=0x0000 (尚未分配)
# 阶段2:为每个端口分配 LID
# 对每个端口发送 Set(PortInfo)
SMP Set: DGRH[hop=0, port=0] → 目标端口 SMA
Method=0x02, AttrID=0x20 (PortInfo)
M_Key=0x0000000000000001
Data: LID=0x0002, MTU=4096, LinkSpeed=25Gbps
# 收到响应
SMP SetResp: Status=0 (成功)
Data: LID=0x0002 (确认已生效)
在上述过程中,SM 首先通过 Get 请求读取每个端口的 NodeInfo,了解节点的 GUID、端口数量、交换机能力等信息;随后通过 Set 请求写入 PortInfo,为每个端口分配唯一的 LID。整个过程中,SMP 报文始终使用 VL15 发送,确保即使数据通道尚未建立,管理报文也能正常传输。
另一个典型场景是 链路状态监控:SM 周期性向所有交换机端口发送 Get(PortInfo),读取端口的 LinkState 字段(值为 1 表示 Down,2 表示 Initialize,3 表示 Armed,4 表示 Active)。如果发现某个端口的 LinkState 从 Active 变为 Down,SM 会触发重新路由或拓扑重计算。
误区/复盘:SMP 使用中的常见问题
ibswitches 读取信息成功,但执行 ibportstate 修改端口状态时却收到“M_Key mismatch”错误。这是因为读取操作(Get)通常不需要 M_Key,而修改操作(Set)必须携带正确的 M_Key。若 SM 与 SMA 的 M_Key 不一致,所有 Set 操作都会被拒绝。
复盘建议:在排查子网管理问题时,使用 ibdebug 工具抓取 SMP 报文,重点关注以下字段:
- Method:确认是 Get 还是 Set,以及响应类型是否匹配。
- AttrID:确认访问的属性是否正确(如 0x15 是 NodeInfo,0x20 是 PortInfo)。
- Status:响应中的状态码是排障的第一线索。
- TID:确认请求与响应是否一一对应,避免混淆。
- M_Key:检查是否与目标端口的 M_Key 一致。