点击此处查看详细分析解答
关于 NC-SI over MCTP over SMBus 长应答报文分片处理的分析与建议
针对您在 米尔3093开发板(I2C-8 接口,SMBus_OEM 协议) 上使用 NC-SI over MCTP over SMBus 通信时,遇到 长应答报文(如端口统计、光模块信息)需分片但 BMC 仅读取首片 的问题,本文基于提供的知识库内容进行深入分析,并提出可能的解决方案和调试建议。
问题描述总结
- 平台:米尔3093开发板(Mil-3093 Development Board),使用 I2C-8 作为 SMBus_OEM 物理层。
- 协议栈:NC-SI over MCTP over SMBus。
- 现象:
- 网卡侧对长度超过 MTU 的 NC-SI 应答进行分片(按 64 字节)。
- BMC 成功读取首片(MCTP 报文头中
SOM=1, EOM=0)。
- 后续分片未被读取,导致通信卡住。
- 日志显示读取成功,数据长度为 129 字节,说明 I2C 层已接收完整内容。
- 目标:如何确保 BMC 正确处理多片 MCTP 响应,完成完整报文重组。
核心机制分析: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 数据载荷起始位置)。
您已正确设置 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 为何没有继续读取后续分片?关键可能在于 协议层的流控与重试机制缺失。
可能原因分析
1. MCTPD 不支持自动分片重组
虽然 I2C 层读到了首片,但 MCTPD 可能期望在单次 I2C 读操作中获取完整 MCTP 消息,而非支持跨多次读取的分片重组。
- MCTP over SMBus 的标准做法是:BMC 发起一次写(Request),然后多次读(Response 分片)。
- 但如果 MCTPD 内部仅执行一次
i2c_read 并认为响应已完成,则不会发起第二次读。
证据支持:
- 在文档中有提到:
"smbus response byte count is invalid" 错误(见 unknown_service ERROR 日志)
- 这表明 BMC 对接收到的字节数有预判或限制。
MCTP 的默认传输单元通常是 64 字节,若超出,需协议栈支持分片重组。当前 MCTPD 可能未处理此场景。
2. 网卡未实现“等待轮询”机制
在 SMBus_OEM 中,常见模式是:BMC 主动轮询读取。
- 网卡发送首片后,应进入“等待状态”。
- BMC 应在收到
SOM=1, EOM=0 后,主动发起下一次读操作以获取后续分片。
- 若网卡没有保留剩余数据、或未响应后续读请求,则导致失败。
建议验证网卡是否支持如下行为:
- 接收到第一次读之后,保持后续分片在缓冲区可读。
- 响应多次 I2C read,每次返回一个分片。
- 在最后分片设置
EOM=1。
3. 物理层 MTU 与逻辑层 MTU 不一致
虽然您按 64 字节分片,但日志显示 data length: 129,说明:
- 可能并非严格按照 MCTP 分片格式发送。
- 或者是网卡将多个 MCTP 帧打包在一个 I2C 读回应中(违反协议)。
需确认:
- 每个 I2C read 操作是否只对应一个 MCTP 分片?
- 是否在 MCTP 层切片,而非在 I2C 层。
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 {
// 完整接收
}
而目前实现可能缺少该分支。
解决建议与调试步骤
建议 1:确认 MCTPD 是否支持 MCTP 分片重组
查看 mctp.cpp 或 smbus_transport.lua 中的接收逻辑:
- 是否解析了
SOM/EOM/SeqNum?
- 是否在
EOM=0 时启动定时重试读取?
- 是否缓存部分消息等待下一片?
若不支持,需扩展 MCTP 接收状态机以支持多帧重组。
建议 2:调整网卡分片大小以适应实际 MTU
尽管您假设 MTU 为 64 字节,但实测接收 129 字节成功,说明 硬件层允许更长读取。
可行方案:
- 尝试在网卡侧 不分片,一次性返回完整响应。
- 若仍失败,说明问题在协议解析而非长度。
提示:某些实现中,MCTP over SMBus 允许最多 512 字节 载荷(通过分块读实现),但需 BMC 支持。
建议 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." }
建议 4:参考华为 Hi182x 驱动行为
您提到使用了 “Hi182x” 驱动并注释了 PCIe 检查。可参考如下实践:
- 查询
hi182x_card.cpp 中 start_ncsi_protocol() 是否处理长响应。
- 查看
libraries/mctp/mctp.cpp 中 request() 超时设置为 15 秒,但实际日志显示 25 秒超时 —— 说明底层存在其他机制。
注意:部分 NC-SI OEM 命应答确实超过 64 字节,必须支持分片或大块传输。
建议 5:启用更详细的日志跟踪
在以下位置增加日志:
i2c.cpp::normal_read():记录每次读取的数据长度与内容。
mctp.cpp::receive():记录是否检测到 EOM=0 并决定是否重读。
smbus_write_read_service.lua:跟踪 SMBus 请求/响应流程。
范例日志关键字:
"smbus response byte count is invalid" → 来自 smbus_write_read_service.lua
建议 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 重组完整消息 |
缓冲区清空 |
注意:SMBus 读操作通常是“重复启动”(Repeated Start),地址不变。
参考资料摘要
| 来源 |
关键点 |
| 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 实现标准协议通信 |
结论与推荐方案
| 问题 |
判断 |
建议 |
| BMC 不读后续分片 |
极有可能 |
检查 MCTPD 是否缺失分片重组逻辑 |
| 网卡未正确保留分片 |
可能 |
确保支持连续多读 |
| MTU 限制非 64 字节 |
存疑 |
尝试一次性返回完整响应 |
| 协议解析错误 |
相关 |
使用 tracemctp 抓包分析 |
推荐操作顺序
- 使用
tracemctp 抓包,确认 BMC 是否发出多次读请求。
- 修改网卡固件,支持多次读取分片,并打印调试日志。
- 在 BMC 侧增强日志,查看
mctp.cpp 是否识别 EOM=0。
- 尝试不分片发送完整响应,验证是否因分片机制导致失败。
- 如确认 MCTPD 缺乏支持,提交 issue 或 patch 实现 MCTP 分片重组状态机。
最终目标:让 BMC 的 MCTPD 在收到 EOM=0 后,自动发起后续 I2C 读取,直到 EOM=1,完成完整报文重组。
如有更多日志细节(如 tracemctp 输出、完整 app.log 片段),可进一步精准定位。