host-app带内资源代理与BMC接口与流程介绍

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(占位)