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 是带外管理协议,它不依赖 IP、不依赖 TCP/UDP、不依赖 LID 路由表。即使交换机转发表完全为空,SM 依然可以通过 DGRH 逐跳访问任意端口。这也是子网管理器能够在“裸网络”上完成初始化的根本原因。
SMP 报文格式与 Get/Set 操作流程 SMP 报文结构(MAD 载荷 256 字节) Base Ver(1B) Mgmt Class(1B) Class Ver(1B) Method (1B) Status (2B) TID (8B) AttrID (2B) AttrMod (4B) M_Key (8B) Data (0~192B) 偏移 0 偏移 24 偏移 216 Method 字段:0x01=Get, 0x02=Set, 0x03=GetResp, 0x04=SetResp 子网管理器 (SM) 运行在控制节点或交换机上 子网管理代理 (SMA) 每个 IB 端口内置 Get(AttrID=0x15, NodeInfo) GetResp(Status=SUCCESS, Data) Set(AttrID=0x20, PortInfo, M_Key 校验) 常见 SMP 属性 • NodeInfo (0x15) — 节点 GUID、端口数 • PortInfo (0x20) — LID、MTU、速率、状态 • SwitchInfo (0x30) — 交换机能力 • LinearForwardTable (0x32) — LID 转发表 • PKeyTable (0x33) — 分区键表 M_Key 机制 • 每个端口有 64 位 M_Key • Set 操作必须携带正确 M_Key • 错误 M_Key 返回 Status=2 • 用于防止未授权管理操作 • 可通过 Set(PortInfo) 修改

方法流程:SMP 报文类型与 Get/Set 操作机制

SMP 报文通过 Method 字段区分操作类型,核心方法包括以下四种:

Method 值名称方向说明
0x01GetSM → SMA请求读取某个属性(如 NodeInfo、PortInfo)
0x02SetSM → SMA请求修改某个属性(如设置 LID、清空转发表)
0x03GetRespSMA → SM对 Get 请求的响应,携带属性数据或错误状态
0x04SetRespSMA → SM对 Set 请求的响应,确认操作结果

除了上述四种基本方法,SMP 还支持 GetTable(0x12)和 SetTable(0x13),用于批量读取或写入大型表属性(如线性转发表、随机转发表),这些方法通过 AttrMod 字段中的偏移量分块访问。

一次典型的 Get 操作流程如下:

  1. SM 构造 SMP 报文,设置 Method=0x01(Get),填写目标属性 ID(如 0x15 表示 NodeInfo),并设置 TID(事务 ID)用于匹配响应。
  2. SM 通过 DGRH 或 LID 路由头将报文发送到目标端口的 SMA。
  3. SMA 收到后校验 M_Key(若属性需要)、检查属性是否可读,然后构造 GetResp 报文,将属性数据填入 Data 字段,Status 设为 0(成功)。
  4. 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 使用中的常见问题

常见误区 1:混淆 SMP 与 IB 数据报文的寻址方式。 SMP 在子网初始化阶段使用 DGRH 定向路由,逐跳指定端口路径;而普通数据报文只能使用 LID 路由。初学者常试图在 LID 未分配时用 LID 发送 SMP,这必然失败。正确做法是:在 LID 分配前使用 DGRH,分配后可以改用 LID 路由头。
常见误区 2:忽略 M_Key 校验机制。 某些管理员在测试时使用 ibswitches 读取信息成功,但执行 ibportstate 修改端口状态时却收到“M_Key mismatch”错误。这是因为读取操作(Get)通常不需要 M_Key,而修改操作(Set)必须携带正确的 M_Key。若 SM 与 SMA 的 M_Key 不一致,所有 Set 操作都会被拒绝。
常见误区 3:认为 GetResp 一定成功。 SMP 响应报文中的 Status 字段可能返回多种错误码:Status=1 表示无效属性,Status=2 表示无效 M_Key,Status=3 表示属性不可修改,Status=4 表示请求超时。排障时应先检查 Status 字段,而不是盲目重发请求。

复盘建议:在排查子网管理问题时,使用 ibdebug 工具抓取 SMP 报文,重点关注以下字段:

  • Method:确认是 Get 还是 Set,以及响应类型是否匹配。
  • AttrID:确认访问的属性是否正确(如 0x15 是 NodeInfo,0x20 是 PortInfo)。
  • Status:响应中的状态码是排障的第一线索。
  • TID:确认请求与响应是否一一对应,避免混淆。
  • M_Key:检查是否与目标端口的 M_Key 一致。