host-app带内资源代理与BMC接口与流程介绍
文档参考
1. 简介
- host-app 是运行在服务器主机 OS 内的轻量代理:周期采集主机资源,通过 Redfish 资源树暴露,并经 IPMI 带内通道向 BMC 注册自身端点、维持心跳,使 BMC 能够主动遍历并展示资源。
2. 总体架构与端到端流程
2.1 组件关系
┌───────────────── host app ─────────────────┐
┌──────────┐ IPMI │ ┌─────────────┐ 内部取数 ┌──────────┐ │
│ BMC │◀──────┼──│ BMC 通道 │──────────▶│ 采集注册表 │ │
│ openUBMC │ 注册/ │ │ (注册/心跳/ │ │ + 缓存 │ │
│ │ 心跳 │ │ 令牌) │◀──GET─────│ (周期刷新) │ │
│ │ │ └──────┬──────┘ 资源树 └────┬─────┘ │
│ nginx │◀─https─┼───────┼─────────────────────────▶│周期采集│
│ proxy │ 遍历拉取│ ┌────▼─────────┐ │ │
└──────────┘ │ │ Redfish 服务 │ ▼ │
│ │ (HTTP/TLS) │ 采集器(数据源) │
│ └──────────────┘ │
└──────────────────────────────────────────┘
2.2 两条通道
| # | 通道 | 方向 | 传输 | 用途 |
|---|---|---|---|---|
| ① 控制 | host-app→BMC | 厂商 IPMI(EDMA驱动/dev/hwibmc0 字符设备,非网络) |
SMS-ID / 令牌 / 注册 / 心跳 | |
| ② 拉取 | BMC→host-app(BMC 主动) | TCP over veth,经 BMC 本地 nginx 反代 |
资源树遍历、Web 面板 |
2.3 端到端时序
host app BMC
│ ① 打开带内通道 /dev/hwibmc0 │
│ ② 请求 SMS-ID ─────────────────────────────────▶│
│ ◀────────────── 返回 SMS-ID(如 "/Sms/1")───────│
│ ③ 用 SMS-ID 更新自身 Redfish URL 前缀 │
│ ④ 请求令牌 ────────────────────────────────────▶│
│ ◀────────────── 返回 64 字符令牌 ────────────────│
│ ⑤ 令牌注入 Redfish 鉴权层 │
│ ⑥ 注销(清除 BMC 侧残留注册)───────────────────▶│
│ ⑦ 注册(携带端点 veth-IPv6:port)──────────────▶│
│ │ Registered false→true
│ ⑧ 心跳(每 10s)──────────────────────────────▶│ 心跳计数递增
│ │
│ ◀────────── ⑨ 遍历:GET /redfish/v1/{Sms}/{id} ─│ (nginx https 反代)
│ ◀────────── ⑩ 沿每个 @odata.id 递归 GET 资源 ────│
│ ◀────────── ⑪ 每 ~5s 重拉 Systems/1/Summary ────│ (类型 OemSummary)
2.4 端到端时序命令清单
每一步列出需要实现的动作(自然语言描述)与涉及的命令字(对 BMC 的线协议命令,
帧格式见 §7.3/§7.4)。命令字为“—”的步骤仅在本机完成,不与 BMC 交互。
| 时序步 | 需要实现的动作 | 命令字 |
|---|---|---|
| ① 打开带内通道 | 打开 /dev/hwibmc0 字符设备;设备不存在则报错并提示加载驱动;同时探测 veth 链路本地地址(fe80::…%veth),供 ⑦ 注册与 HTTPS 绑定使用(流程见 §7.6) |
— |
| ② 请求 SMS-ID | 向 BMC 发送 SMS-ID 请求(请求载荷 magic “SP”);从响应第 7 字节起提取 SMS-ID(如 /Sms/1) |
GET_SMS_ID |
| ③ 更新 URL 前缀 | 解析 SMS-ID:把 Redfish URL 前缀的软件名与 ID 更新为 BMC 下发的值(如 /redfish/v1/Sms/1/…) |
— |
| ④ 请求令牌 | 向 BMC 请求令牌;从响应第 9 字节起提取 64 字符令牌 | GET_TOKEN |
| ⑤ 令牌注入鉴权层 | 保存令牌,用于校验 BMC 遍历请求的 X-Auth-Token 头 |
— |
| ⑥ 注销 | 向 BMC 发送注销(注册标志=0),清除 BMC 侧残留注册,保证 ⑦ 触发 Registered false→true | UNREGISTER |
| ⑦ 注册 | 构造注册帧并发送:选择子 0xC4、MaskRedfish≠0、SourceType=0、注册标志=1、HttpType=1、veth 链路本地地址(① 的探测结果)、Redfish 端口 | REGISTER |
| ⑧ 心跳(每 10s) | 周期发送心跳(SoftwareId=101),响应成功码 0 即存活;连续 3 次失败进入 IDLE(只重试、不注销);恢复后保持注册、等待 BMC 自行重遍历;长时间失联则周期性重新执行 ②~⑦(流程见 §7.5) | HEARTBEAT |
| ⑨ 响应遍历 ServiceRoot | 接收 GET 请求 → 匹配路径(标准与 SMS-ID 前缀双形态)→ 校验鉴权(令牌/Basic/带内信任,见 §6.3)→ 构建并返回 ServiceRoot(必带 @odata.type,含 Systems/Managers/UpdateService 链接) |
—(HTTP GET) |
| ⑩ 响应沿 @odata.id 递归 GET | 按请求路径构建并返回对应资源体:Systems 集合与 Systems/1(含 Oem.Huawei 8 字段)、Memory、Processors、网卡集合/成员/统计、Storage 与磁盘成员、Managers 集合与 Manager(含 DriverInfo)、时间、UpdateService 占位;取数统一为缓存优先、未命中实时采集(流程见 §5.1) | —(HTTP GET) |
| ⑪ 响应 Summary 周期重拉(~5s) | 实时采集(不读缓存)处理器使用率与内存占用,构建并返回 Summary;响应类型必须为 #OemSummary.v1_0_0.OemSummary,才会被 BMC 每 ~5s 重扫 |
—(HTTP GET) |
命令字详细说明
传输语义:同步写一帧、读一帧(无标准 IPMI 头部前缀);响应第 5 字节为成功码,0 表示成功。
成功码非 0 时视为该命令失败,按 §7.5 的失败策略处理。
| 命令字 | 时序步 | 作用 | 请求内容 | 响应内容 | 关键约束 |
|---|---|---|---|---|---|
| GET_SMS_ID | ② | 向 BMC 获取软件标识(SMS-ID),同步自身 Redfish URL 前缀 | 载荷 magic “SP” | 成功码;SMS-ID C 串(自响应第 7 字节起,如 /Sms/1) |
失败则重试整个注册序列;SMS-ID 决定后续 URL 前缀形态 |
| GET_TOKEN | ④ | 向 BMC 获取访问令牌 | 固定载荷 | 成功码;64 字符令牌 C 串(自响应第 9 字节起) | 令牌用于 BMC 遍历请求鉴权(X-Auth-Token 头);丢失后需重新请求 |
| UNREGISTER | ⑥ | 清除 BMC 侧残留注册,使 ⑦ 触发 Registered false→true | 同注册帧,注册标志=0 | 成功码 | 必须紧随 REGISTER 之前执行;跳过将导致 BMC 认为注册未变化而不遍历 |
| REGISTER | ⑦ | 向 BMC 注册自身 Redfish 端点(veth IPv6 + 端口 + https 标志) | 端点数据区(选择子 0xC4、MaskRedfish≠0、SourceType=0、注册标志=1、位标志含 HttpType=1、16 字节 IPv6、端口) | 成功码 | SourceType 必须=0(=1 时 BMC 不遍历);IP 必须是真实存在且已 UP 的 veth 链路本地地址;帧布局见 §7.4 |
| HEARTBEAT | ⑧ | 周期保活,维持 BMC 侧注册状态 | SoftwareId=101(AGENT_TYPE_BMA) | 成功码(0 即存活) | 每 10s 一次;连续 3 次失败进入 IDLE(只重试、不注销);长时间失联后重新执行注册序列 |
各命令字实现细节(真机验证事实)
通用传输:同步写一帧、读一帧(无 SEQ 前缀);写失败 / 5s 超时 / 读错误均视为命令失败,
按 §7.5 策略处理。成功码即响应第 5 字节,0 表示成功。
GET_SMS_ID
请求帧(14 字节,固定):01 0c 18 3d 58 ca 53 50 00 00 00 00 00 00
| 帧字段 | 值 | 含义 |
|---|---|---|
| [0] | 0x01 | MsgType 固定 |
| [1] | 0x0c | Length 载荷长度 |
| [2] | 0x18 | netfn/lun(netfn 6 / lun 0) |
| [3] | 0x3d | Seq |
| [4] | 0x58 | Cmd 命令字 |
| [5] | 0xca | 固定 |
| [6:8] | 53 50(“SP”) |
magic 载荷 |
响应:[5]=成功码;SMS-ID C 串自 [7] 起、遇 \x00 截止(如 /Sms/1)。
失败 → 间隔 3s 重试完整注册序列。
GET_TOKEN
请求帧(30 字节,固定):01 1f c0 3e 94 db 07 00 39 04 01 + 19×00
| 帧字段 | 值 | 含义 |
|---|---|---|
| [0] | 0x01 | MsgType 固定 |
| [1] | 0x1f | Length 载荷长度 |
| [2] | 0xc0 | netfn/lun(OEM netfn) |
| [3] | 0x3e | Seq(令牌标签) |
| [4] | 0x94 | Cmd 命令字 |
| [5] | 0xdb | 固定 |
| [6:11] | 07 00 39 04 01 |
固定载荷 |
响应:[5]=成功码;64 字符令牌 C 串自 [9] 起、遇 \x00 截止。
令牌随后注入鉴权层(BMC 遍历请求 X-Auth-Token 校验)。失败 → 重试注册序列。
REGISTER / UNREGISTER
请求帧(37 字节,动态构造):01 23 18 <seq> 58 c4 01 00 + 6×00 + <注册标志> + <位标志> + 16 字节 IP + 2 字节端口 + 7×00
| 帧字段 | 值 | 含义 |
|---|---|---|
| [0] | 0x01 | MsgType 固定 |
| [1] | 0x23 | Length 载荷长度 |
| [2] | 0x18 | netfn/lun |
| [3] | 0..16 循环 | Seq 序列号 |
| [4] | 0x58 | Cmd 命令字 |
| [5] | 0xc4 | 选择子 |
| [6] | 0x01 | MaskRedfish(必须≠0) |
| [7] | 0x00 | SourceType(必须=0,AGENT_TYPE_BMA;=1 时 BMC 不遍历) |
| [8:10] | 0 | 保留 |
| [10] | 1/0 | 注册标志(1=注册 / 0=注销) |
| [11] | 位打包 | bit0=IPv6(1);bit1=HttpType(必须=1);bit2=cdev;bit3=USB(veth 时 bit2/3=0) |
| [12:28] | 16 字节 | IP = veth IPv6 链路本地地址(去 %scope 后转为原始字节;转换失败回退 127.0.0.1) |
| [28:30] | 大端 | Redfish 端口 |
| [30:] | 0 | 保留 |
构造要点:HttpType 固定置 1;注册/注销仅 [10] 不同;UNREGISTER 必须紧随 REGISTER 之前(间隔 0.5s)。
响应:[5]=成功码,0 即成功;0xC9 = IP 非真实 veth 链路本地地址或 veth 未 UP,被拒绝。
HEARTBEAT
请求帧(37 字节,固定):01 23 18 00 58 c5 65 01 + 29×00
| 帧字段 | 值 | 含义 |
|---|---|---|
| [0] | 0x01 | MsgType 固定 |
| [1] | 0x23 | Length 载荷长度 |
| [2] | 0x18 | netfn/lun |
| [3] | 0x00 | Seq 固定 |
| [4] | 0x58 | Cmd 命令字 |
| [5] | 0xc5 | 心跳选择子 |
| [6] | 101 | SoftwareId(AGENT_TYPE_BMA) |
| [7] | 0x01 | 固定 |
响应:[5]=成功码,0 即存活。每 10s 发送;连续 3 次失败进入 IDLE;
每 18 次失败(约 3 分钟)强制重新执行注册序列;恢复后不注销、等待 BMC 自行重遍历。
3. host-app Redfish 接口实现
3.1 Redfish 资源树总览(参考)
/redfish/v1/{SoftwareName}/{smsID}/ ← 前缀,注册时由 SMS-ID 决定(如 /Sms/1 → Sms/1)
├── ServiceRoot #ServiceRoot.v1_5_0.ServiceRoot
├── Systems #ComputerSystemCollection.ComputerSystemCollection
│ └── Systems/1 #ComputerSystem.v1_10_0.ComputerSystem
│ ├── Summary #OemSummary.v1_0_0.OemSummary(实时,~5s 重扫)
│ ├── Memory #MemoryCollection.MemoryCollection
│ │ └── Memory/1 #Memory.v1_7_0.Memory
│ ├── Processors #ProcessorCollection.ProcessorCollection
│ │ └── Processors/1 #Processor.v1_7_0.Processor
│ ├── EthernetInterfaces #EthernetInterfaceCollection.EthernetInterfaceCollection
│ │ ├── EthernetInterfaces/{if} #EthernetInterface.v1_4_0.EthernetInterface
│ │ └── EthernetInterfaces/{if}/Statistics #EthernetInterfaceMetrics.v1_0_0.EthernetInterfaceMetrics
│ └── Storage #StorageCollection.StorageCollection
│ └── Storage/1 #Storage.v1_7_0.Storage
│ └── Storage/1/Drives/{id} #Drive.v1_5_0.Drive
├── Managers #ManagerCollection.ManagerCollection
│ └── Managers/{host-app} #Manager.v1_5_0.Manager({host-app}=配置的软件名)
│ └── Managers/{host-app}/DateTime #DateTime.v1_0_0.DateTime
└── UpdateService #UpdateService.UpdateService(占位)