南向 IPMI 追踪能力
概述
南向 IPMI 追踪(TraceIpmi)用于在 BMC 与主机/ME 等南向设备通信时,按通道、NetFn、Cmd 等条件抓取 BT、IPMB 等介质上的原始报文,并输出为可读的十六进制日志,便于现场调试与问题定位。
模块核心组成:
- trace_ipmi_obj:追踪能力对象,承载配置属性与报文处理逻辑
- ipmi_trace_hook:传输层与追踪对象之间的轻量回调桥接
- channel_context:在 send/recv 路径上采集线路上下文并上报 hook
追踪仅在显式开启后生效,默认关闭,不影响正常 IPMI 通信性能。传输层架构见 transport_architecture.md。
总体设计
┌─────────────────────────────────────────────────────────────────────┐
│ trace_ipmi_obj │
│ - Trace 接口配置(通道 / NetFn / Cmd / 日志类型) │
│ - monitor_ipmi_message:过滤、格式化、敏感掩码、落盘/本地日志 │
└───────────────────────────────┬─────────────────────────────────────┘
│ on_register 注册回调
▼
┌─────────────────────────────────────────────────────────────────────┐
│ ipmi_trace_hook(全局回调) │
│ set_ipmi_trace_callback / report_ipmi_trace │
└───────────────────────────────┬─────────────────────────────────────┘
│ send / recv 路径调用
▼
┌─────────────────────────────────────────────────────────────────────┐
│ channel_context │
│ process_send_data → serialize 后 report(trace_direction::send) │
│ read_dev_data_loop → 原始字节 report(trace_direction::recv) │
└───────────────────────────────┬─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ bt_service / ipmb_service + driver + protocol │
└─────────────────────────────────────────────────────────────────────┘
设计要点:
- Hook 与传输层解耦:
channel_context只调用report_ipmi_trace,不直接依赖trace_ipmi_obj - 对象自注册:
trace_ipmi_obj::on_register()向 hook 注册monitor_ipmi_message回调 - 线路上下文与逻辑消息分离:
trace_data为完整线路字节流;ipmi_message提供 NetFn/Cmd、ctx 等逻辑字段
TraceIpmi 对象
Class Name: TraceIpmi
Object Path: /bmc/kepler/Debug/IpmiCore/TraceIpmi
对象通过 discover_objects() 注册到对象自发现表,由 MDS/CSR 配置实例化。
Interfaces
| Interface | Description |
|---|---|
bmc.kepler.Debug.IpmiCore.TraceIpmi |
南向追踪配置与 Trace 方法 |
Properties (bmc.kepler.Debug.IpmiCore.TraceIpmi)
| Property | Type | Default | Description |
|---|---|---|---|
EnableTrace |
bool |
false |
追踪使能开关,由 Trace 方法写入 |
Channel |
string |
"" |
追踪通道,支持 bt、ipmb、edma、ipmbeth |
Netfn |
uint8 |
0 |
过滤用 NetFn;0xFF 表示不过滤 |
Cmd |
uint8 |
0 |
过滤用 Cmd;0xFF 表示不过滤 |
Filter |
string |
"" |
预留过滤字段,当前以十六进制字符串形式保存(如 0a-ff-00-) |
LogType |
string |
"" |
日志输出方式:file 写文件,local 本地日志 |
属性均为只读暴露,配置统一通过 Trace 方法下发。
Methods (bmc.kepler.Debug.IpmiCore.TraceIpmi)
| Method | Parameters | Return | Description |
|---|---|---|---|
Trace |
EnableTrace, Channel, Netfn, Cmd, Filter, LogType |
void |
配置并开启/关闭南向追踪 |
Trace 方法参数说明:
| Parameter | Type | Description |
|---|---|---|
EnableTrace |
bool |
是否开启追踪 |
Channel |
string |
通道名,枚举:bt / ipmb / edma / ipmbeth |
Netfn |
uint8 |
目标 NetFn,0xFF 表示匹配任意 NetFn |
Cmd |
uint8 |
目标 Cmd,0xFF 表示匹配任意 Cmd |
Filter |
string |
原始过滤字节流;接口侧转换为 xx- 格式写入 Filter 属性 |
LogType |
string |
file 或 local;非法值拒绝配置并保持关闭状态 |
权限:Trace 方法需要 BasicSetting;对象属性读取需要 ReadOnly(见 gen/model.json)。
追踪 Hook 机制
ipmi_trace_hook
位于 src/service/core/ipmi_trace_hook.{h,cpp},提供进程内全局回调注册:
| API | Description |
|---|---|
set_ipmi_trace_callback(cb) |
注册/替换追踪回调;trace_ipmi_obj::on_register 时绑定 |
report_ipmi_trace(msg, trace_data, dir) |
传输层上报入口;无回调时直接返回 |
回调签名:
void(const ipmi_message& msg,
const std::vector<uint8_t>& trace_data,
trace_direction dir);
trace_direction 取值:send(BMC 发出)、recv(BMC 收到)。
channel_context 调用点
| 路径 | 时机 | trace_data 来源 | 方向 |
|---|---|---|---|
process_send_data |
协议序列化之后、驱动写入之前 | protocol_->serialize(...) 结果 |
send |
read_dev_data_loop |
驱动读入之后、反序列化入队之前 | 驱动 read 的原始字节 |
recv |
差异说明:
- send:使用协议层序列化后的完整报文,与线路上实际发送内容一致
- recv:使用驱动读到的原始字节,在反序列化为
ipmi_message之前上报,保留线路全貌
channel_context 在填充通用 ctx 时写入 ctx_key::REQ_SERVICE_NAME(如 bt_service、ipmb_service),供前缀构造时校验通道与服务一致性。
追踪处理流程
1. 外部调用 Trace 方法配置 EnableTrace / Channel / NetFn / Cmd / LogType
↓
2. 传输层 channel_context 在 send 或 recv 路径调用 report_ipmi_trace
↓
3. trace_ipmi_obj::monitor_ipmi_message
├─ EnableTrace=false → 直接返回
├─ build_trace_prefix 失败(通道/服务不匹配)→ 返回
├─ NetFn/Cmd 过滤不匹配 → 返回
├─ trace_data 为空 → 返回
└─ 格式化日志
├─ 时间戳 + 前缀 + 十六进制数据
├─ 敏感掩码(见下文)
├─ 超长截断(MAX_TRACE_LEN=256 字节)
└─ 按 LogType 输出(file / local)
时序(send 方向)
channel_context protocol ipmi_trace_hook trace_ipmi_obj /tmp/ipmi.txt
│ │ │ │ │
│ serialize │ │ │ │
├──────────────>│ │ │ │
│ report(send) │ │ │ │
├─────────────────────────────>│ monitor │ │
│ │ ├─────────────────>│ │
│ │ │ │ trace_by_file │
│ │ │ ├────────────────>│
│ driver write │ │ │ │
├──────────────>│ │ │ │
过滤与匹配规则
追踪是否记录一条报文,需依次通过以下检查:
| 序号 | 检查项 | 规则 |
|---|---|---|
| 1 | 使能 | EnableTrace == true |
| 2 | 通道 | Channel 非空,且 msg.ctx()[REQ_SERVICE_NAME] 包含通道名(如 bt 匹配 bt_service) |
| 3 | NetFn | 配置为 0xFF 或等于 msg 中 dest_netfn_lun >> 2 |
| 4 | Cmd | 配置为 0xFF 或等于 msg 中 cmd |
| 5 | 数据 | trace_data 非空 |
通配示例:
- 追踪 BT 通道全部命令:
Channel=bt, Netfn=0xFF, Cmd=0xFF - 仅追踪 Set Watchdog(0x06/0x24):
Channel=bt, Netfn=0x06, Cmd=0x24
日志前缀格式
前缀由 build_trace_prefix 生成,用于区分通道实例与方向:
| 通道 | 格式 | 示例 |
|---|---|---|
| BT | bt-{iface}-{send|recv} |
bt-0-send |
| IPMB | ipmb-{iface}-{send|recv}--0x{src}->0x{dest} |
ipmb-0-recv--0x20->0x2c |
| EDMA | edma-{send|recv} |
edma-recv |
iface:msg.get_interface_id(),对应通道实例编号- IPMB 的
src/dest取自ipmi_data.header.src_addr/dest_addr
当前前缀构造已实现 BT、IPMB、EDMA;ipmbeth 在 MDS 枚举中声明,前缀逻辑待扩展。
敏感数据掩码
当路由结果标记响应为敏感(msg.ctx()[RSP_SENSITIVE] == true,由 service_manager 在 route_request 路径写入)时,对 payload 做脱敏输出:
| 消息类型 | 判断方式 | 掩码规则 |
|---|---|---|
| 请求(NetFn 偶数) | netfn & 0x01 == 0 |
头部之后、敏感起始位置之前正常输出;其余字节输出 ** |
| 响应(NetFn 奇数) | netfn & 0x01 == 1 |
仅输出通道头部长度,后续全部 ** |
通道头部长度(get_header_len):
| Channel | Header Len |
|---|---|
bt |
4 |
edma |
5 |
ipmb |
6 |
敏感命令精细匹配依赖内部表 m_sensitive_ipmicmds(NetFn + Cmd + filter 字节匹配,0xFF 为通配)。该表当前尚未从 Filter 属性或 CSR 填充,精细脱敏规则为预留能力;在表为空时,请求侧敏感掩码退化为输出完整 trace_data。
日志输出
file 模式
- 目标文件:
/tmp/ipmi.txt - 不存在时创建,权限
0664,属主root:204(ADMIN_GID) - 单行格式:
[YYYY-MM-DD HH:MM:SS.mmm]{prefix} ---- {hex bytes...} - 文件超过 5MB 时截断重写,避免无限增长
- 每条记录末尾追加换行
输出示例:
[2026-06-06 10:15:30.123]bt-0-send ---- 20 18 c8 81 04 01 02 03
[2026-06-06 10:15:30.456]ipmb-0-recv--0x20->0x2c ---- 2c 18 06 00 20 00 00 00
[2026-06-06 10:15:30.789]edma-recv ---- 20 18 c8 81 04 01 02 03
local 模式
- 调用
trace_by_local_log,计划对接框架mdbctl_log接口 - 当前为空实现,配置
LogType=local时格式化完成但不输出
长度限制
- 单条日志最多展示 256 字节十六进制数据(
MAX_TRACE_LEN) - 超出部分以
...结尾截断
关键点说明
- 默认关闭:
EnableTrace默认为false,未配置时不产生日志开销 - 单例回调:全局仅一个
ipmi_trace_callback,由首个注册的trace_ipmi_obj占用 - recv 用原始字节:recv 路径的
trace_data为驱动原始读数,与 send 路径序列化结果可能在封包细节上存在差异,均代表各方向线路真实数据 - Filter 预留:
Filter属性与Trace入参已定义,用于后续按 payload 前缀精细过滤/脱敏;当前仅持久化为十六进制字符串 - local 日志待实现:
trace_by_local_log尚未对接框架日志接口 - 通道扩展:
ipmbeth的前缀格式与 hook 覆盖范围随传输服务扩展逐步补齐