【求助】如何封装需要分片的NC-SI over MCTP over SMBus应答报文

平台:米尔3093开发板,I2C-8用于SMBus_OEM
代码:2603版本
问题:

对于应答超过OpenUBMC MCTPD服务的MTU(当前实测应该是128Bytes)报文,需要切片。

网卡对长应答按照MTU=64进行分片,在BMC读走网卡首个分片后(MCTP头部SOM = 1, EOM=0)、BMC未读取后续分片。想请教一下如何才能让BMC读走所有分片。

需要分片的应答报文有:

  • 端口报文统计(NC-SI 标准命令 0x18)
  • 光模块信息(NC-SI OEM命令)

下图是“端口报文统计”应答的交互过程:

不知道是应答报文首个分片错误,还是其他?

答案内容由AI生成,仅供参考:
:white_check_mark: 结论与推荐方案

问题 判断 建议
BMC 不读后续分片 :check_mark: 极有可能 检查 MCTPD 是否缺失分片重组逻辑
网卡未正确保留分片 :check_mark: 可能 确保支持连续多读
MTU 限制非 64 字节 :warning: 存疑 尝试一次性返回完整响应
协议解析错误 :check_mark: 相关 使用 tracemctp 抓包分析
点击此处查看详细分析解答

关于 NC-SI over MCTP over SMBus 长应答报文分片处理的分析与建议

针对您在 米尔3093开发板(I2C-8 接口,SMBus_OEM 协议) 上使用 NC-SI over MCTP over SMBus 通信时,遇到 长应答报文(如端口统计、光模块信息)需分片但 BMC 仅读取首片 的问题,本文基于提供的知识库内容进行深入分析,并提出可能的解决方案和调试建议。


:magnifying_glass_tilted_left: 问题描述总结

  • 平台:米尔3093开发板(Mil-3093 Development Board),使用 I2C-8 作为 SMBus_OEM 物理层。
  • 协议栈:NC-SI over MCTP over SMBus。
  • 现象
    1. 网卡侧对长度超过 MTU 的 NC-SI 应答进行分片(按 64 字节)。
    2. BMC 成功读取首片(MCTP 报文头中 SOM=1, EOM=0)。
    3. 后续分片未被读取,导致通信卡住。
    4. 日志显示读取成功,数据长度为 129 字节,说明 I2C 层已接收完整内容。
  • 目标:如何确保 BMC 正确处理多片 MCTP 响应,完成完整报文重组。

:puzzle_piece: 核心机制分析:MCTP over SMBus 分片机制

1. MCTP 分片机制(SOM/EOM 标志位)

在 MCTP 协议中,当报文超过底层传输单元(如 SMBus 的 MTU)时,需进行分片传输:

字段 说明
Start of Message (SOM) 1 表示该帧是消息的第一片
End of Message (EOM) 1 表示该帧是消息的最后一片
Sequence Number 分片序号,用于重组

在 SMBus_OEM 场景中,这些字段包含在 MCTP 消息头中(位于 I2C 数据载荷起始位置)。

:white_check_mark: 您已正确设置 SOM=1, EOM=0 在首片,后续片应 SOM=0, EOM=1


2. OpenUBMC 中的 MCTPD 处理流程

根据知识库中的信息:

  • MCTPD 是 OpenUBMC 中负责 MCTP 协议处理的核心守护进程(daemon)。
  • 它通过 smbus_write_read_service.lua 等模块与 Chip_SmbusChip_0103_dev 通信。
  • 支持 NC-SI over MCTP,其消息类型码为 0x02
  • 使用 create_mctp_endpoint_for_smbus 函数在 SMBus 上创建 MCTP 端点。
{
  "entity": "NC-SI over MCTP",
  "description": "NC-SI over MCTP is a hybrid communication protocol that uses MCTP as a transport layer for NC-SI messages."
}

3. I2C 读取行为分析

从日志可见:

i2c read success, data length: 129
i2c read hex: 45 65 01 08 1e 82 02 00 ...

这表明:

  • I2C 层已成功从从设备(网卡)读取了 129 字节数据
  • 但 MCTPD 为何没有继续读取后续分片?关键可能在于 协议层的流控与重试机制缺失

:warning: 可能原因分析

:white_check_mark: 1. MCTPD 不支持自动分片重组

虽然 I2C 层读到了首片,但 MCTPD 可能期望在单次 I2C 读操作中获取完整 MCTP 消息,而非支持跨多次读取的分片重组。

  • MCTP over SMBus 的标准做法是:BMC 发起一次写(Request),然后多次读(Response 分片)。
  • 但如果 MCTPD 内部仅执行一次 i2c_read 并认为响应已完成,则不会发起第二次读。

:magnifying_glass_tilted_left: 证据支持

  • 在文档中有提到:

    "smbus response byte count is invalid" 错误(见 unknown_service ERROR 日志)

  • 这表明 BMC 对接收到的字节数有预判或限制。

:light_bulb: MCTP 的默认传输单元通常是 64 字节,若超出,需协议栈支持分片重组。当前 MCTPD 可能未处理此场景。


:white_check_mark: 2. 网卡未实现“等待轮询”机制

在 SMBus_OEM 中,常见模式是:BMC 主动轮询读取

  • 网卡发送首片后,应进入“等待状态”。
  • BMC 应在收到 SOM=1, EOM=0 后,主动发起下一次读操作以获取后续分片。
  • 若网卡没有保留剩余数据、或未响应后续读请求,则导致失败。

:pushpin: 建议验证网卡是否支持如下行为

  • 接收到第一次读之后,保持后续分片在缓冲区可读。
  • 响应多次 I2C read,每次返回一个分片。
  • 在最后分片设置 EOM=1

:white_check_mark: 3. 物理层 MTU 与逻辑层 MTU 不一致

虽然您按 64 字节分片,但日志显示 data length: 129,说明:

  • 可能并非严格按照 MCTP 分片格式发送。
  • 或者是网卡将多个 MCTP 帧打包在一个 I2C 读回应中(违反协议)。

:wrench: 需确认

  • 每个 I2C read 操作是否只对应一个 MCTP 分片?
  • 是否在 MCTP 层切片,而非在 I2C 层。

:cross_mark: 4. SMBus Master(BMC)未触发后续读取

从逻辑上讲,BMC 应当在检测到 EOM=0 后主动发起新的读操作。否则通信无法继续。

但当前行为表明:BMC 只做了一次读,然后超时。

可能原因:

  • MCTPD 没有实现分片状态机,未识别 EOM=0 需要继续读。
  • component_drivers 中的 mctp.cpp request() 实现可能仅执行单次读。
// 伪代码示意
if (response.header.EOM == 0) {
    // 应继续读取下一个分片
    next_response = i2c_read();
   重组完整消息;
} else {
    // 完整接收
}

而目前实现可能缺少该分支。


:white_check_mark: 解决建议与调试步骤

:white_check_mark: 建议 1:确认 MCTPD 是否支持 MCTP 分片重组

查看 mctp.cppsmbus_transport.lua 中的接收逻辑:

  • 是否解析了 SOM/EOM/SeqNum
  • 是否在 EOM=0 时启动定时重试读取?
  • 是否缓存部分消息等待下一片?

若不支持,需扩展 MCTP 接收状态机以支持多帧重组。


:white_check_mark: 建议 2:调整网卡分片大小以适应实际 MTU

尽管您假设 MTU 为 64 字节,但实测接收 129 字节成功,说明 硬件层允许更长读取

:pushpin: 可行方案

  • 尝试在网卡侧 不分片,一次性返回完整响应。
  • 若仍失败,说明问题在协议解析而非长度。

提示:某些实现中,MCTP over SMBus 允许最多 512 字节 载荷(通过分块读实现),但需 BMC 支持。


:white_check_mark: 建议 3:使用 tracemctp 工具抓取完整交互过程

利用 tracemctp 命令(OpenUBMC 提供的诊断工具)分析 MCTP 流量:

tracemctp start
# 执行 NC-SI 命令
tracemctp stop

检查输出是否显示:

  • 分片被识别为同一事务(Transaction ID)。
  • BMC 是否发送了多个 Read 请求。

相关实体:

{ "entity": "tracemctp", "description": "tracemctp is a diagnostic tool used to capture and analyze Mctp communication traffic." }

:white_check_mark: 建议 4:参考华为 Hi182x 驱动行为

您提到使用了 “Hi182x” 驱动并注释了 PCIe 检查。可参考如下实践:

  • 查询 hi182x_card.cppstart_ncsi_protocol() 是否处理长响应。
  • 查看 libraries/mctp/mctp.cpprequest() 超时设置为 15 秒,但实际日志显示 25 秒超时 —— 说明底层存在其他机制。

注意:部分 NC-SI OEM 命应答确实超过 64 字节,必须支持分片或大块传输


:white_check_mark: 建议 5:启用更详细的日志跟踪

在以下位置增加日志:

  1. i2c.cpp::normal_read():记录每次读取的数据长度与内容。
  2. mctp.cpp::receive():记录是否检测到 EOM=0 并决定是否重读。
  3. smbus_write_read_service.lua:跟踪 SMBus 请求/响应流程。

范例日志关键字:

  • "smbus response byte count is invalid" → 来自 smbus_write_read_service.lua

:white_check_mark: 建议 6:修改网卡行为:支持轮询式多读

确保网卡实现以下行为:

步骤 BMC 行为 网卡行为
1 写 Request 接收并准备好响应(分多片)
2 读首片(offset=0x1F) 返回第 1 片:SOM=1, EOM=0, Seq=0
3 再次读(offset=0x1F) 返回第 2 片:SOM=0, EOM=1, Seq=1
4 MCTPD 重组完整消息 缓冲区清空

:white_check_mark: 注意:SMBus 读操作通常是“重复启动”(Repeated Start),地址不变。


:books: 参考资料摘要

来源 关键点
Knowledge Graph - MCTPD 是 MCTP 消息处理核心
- SMBus_OEM 支持 NC-SI over MCTP
- tracemctp 用于抓包调试
Document Chunk 1 - 单次响应 >64 字节会导致解封失败
- smbus oem response byte count is invalid 是关键错误
Search Result #2 (mctpd使用说明) - libmgmt_protocol 封装了 NC-SI over MCTP
- 提供 API 建议使用封装库而非手动调用
Search Result #9 (南向硬件协议库) - 推荐使用 ncsi_standard.lua 实现标准协议通信

:white_check_mark: 结论与推荐方案

问题 判断 建议
BMC 不读后续分片 :check_mark: 极有可能 检查 MCTPD 是否缺失分片重组逻辑
网卡未正确保留分片 :check_mark: 可能 确保支持连续多读
MTU 限制非 64 字节 :warning: 存疑 尝试一次性返回完整响应
协议解析错误 :check_mark: 相关 使用 tracemctp 抓包分析

:white_check_mark: 推荐操作顺序

  1. 使用 tracemctp 抓包,确认 BMC 是否发出多次读请求。
  2. 修改网卡固件,支持多次读取分片,并打印调试日志。
  3. 在 BMC 侧增强日志,查看 mctp.cpp 是否识别 EOM=0
  4. 尝试不分片发送完整响应,验证是否因分片机制导致失败。
  5. 如确认 MCTPD 缺乏支持,提交 issue 或 patch 实现 MCTP 分片重组状态机

:light_bulb: 最终目标:让 BMC 的 MCTPD 在收到 EOM=0 后,自动发起后续 I2C 读取,直到 EOM=1,完成完整报文重组。

如有更多日志细节(如 tracemctp 输出、完整 app.log 片段),可进一步精准定位。

smbus_oem好像没有多帧的处理