devmon
版本信息
| 项目 | 内容 |
|---|---|
| 组件版本 | 1.2.109 |
| 首发版本 | openUBMC 26.09 |
| 文档作者 | openUBMC 社区 |
| 最后更新 | 2026-09-15 |
| 许可证 | Mulan PSL v2 |
1. 组件概述
1.1 组件简介
devmon(Device Monitor)是 openUBMC 的设备监控与南向设备管理组件。它解析 CSR(.sr 自描述文件),按 driver_abi.h 用 dlopen 加载 component_drivers 产出的设备驱动 .so,并按 Position 管理对象组、拓扑与热插拔生命周期。
组件类型为 application(mds/service.json)。Linux 产物安装到 /opt/bmc/apps/devmon,可执行文件为 /opt/bmc/apps/devmon/devmon。systemd 单元 devmon.service 在 framework.service 之后启动,依赖 dbus.service 与 framework.service,MemoryMax=150M。
默认构建选项 unidev=false 时,进程只注册 D-Bus 服务名 bmc.kepler.devmon。unidev=true 时,同一进程内再注册 bmc.kepler.hwproxy 与 bmc.kepler.hwdiscovery。
仓库中没有 mds/ipmi.json,组件不提供 IPMI 命令。业务侧也没有可 require 的公开 Lua 模块;应用层 Lua 插件由 hwproxy 加载,业务通过 Chip 的 PluginRequest 点名调用。根目录 mds/model.json 当前为空对象;Scanner / Accessor / Chip / Bus 定义在 mds/hwproxy/model.json,Connector / ObjectGroup 定义在 mds/hwdiscovery/model.json。
1.2 解决什么问题
BMC 需要把机型与部件的硬件自描述变成可协作的对象树,并在热插拔时完成驱动加载、对象上树和下树。devmon 把这些公共能力收敛到统一服务:
- 解析 CSR,实例化总线、芯片、Scanner、Accessor 以及业务设备对象。
- 按 Position 维护对象组,供其他组件查询本位置上的对象与拓扑。
- 通过
bmc.dev提供 AddDevice / RemoveDevice 热插拔入口。 - 对硬件访问做域调度(AccessScheduler),避免总线过载。
- 通过驱动 ABI 加载厂商
.so,使具体网卡 / GPU 等实现不进入本仓。
1.3 核心功能
核心功能一:CSR 解析与对象实例化
解析
.sr中的Objects、ManagementTopology、$ref、|>表达式和定制合并,生成引擎对象树。核心功能二:热插拔与对象组
对外暴露
bmc.dev的AddDevice/AddDeviceWithData/RemoveDevice;按 Position 创建bmc.dev.ObjectGroup。核心功能三:驱动 ABI 动态加载
按
register_device_driver函数表dlopencomponent_drivers产出的lib<Name>.so(CSR1 另试libCsr1<Name>.so)。运行时按 gold → temp → image 选库:生产默认 image 目录为配置项driver_path(/opt/bmc/drivers/),升级副本默认在/data/opt/bmc/drivers/gold与/data/opt/bmc/drivers/temp。核心功能四:可选三层架构(unidev)
同一进程拆成
devmon_service、hwproxy_service、discovery_service。FormatVersion < 5.00走 CSR1 /abi_v1并转发到 hwdiscovery;>= 5.00(缺省)走 CSR2 /abi_v2。
1.4 关键术语表
| 术语 | 解释 |
|---|---|
CSR / .sr | Component Self-Description Record,硬件自描述文件。 |
| Position / GroupPosition | 对象组位置。热插拔与对象组都以它为键。 |
| FormatVersion | CSR 格式版本。阈值 5.00:小于阈值走 CSR1 / abi_v1,否则走 CSR2 / abi_v2。 |
| unidev | 构建选项。为 true 时本进程同时注册 hwproxy 与 hwdiscovery。 |
| driver ABI | include/devmon/driver_abi.h 中的 C 函数表,设备 .so 必须导出 register_device_driver。 |
| ObjectGroup | 某一 Position 上已上树对象的集合,供其他组件拉取类名、对象名和属性。 |
| Connector | 连接器对象,描述下级板卡的 Bom / Id / AuxId / Presence / 总线等。 |
| Scanner / Accessor | 周期性扫描对象与按需读写对象,通常挂在 hwproxy。 |
| PluginRequest | Chip.BlockIO 上的应用层 Lua 插件调用入口。 |
| AccessScheduler | 硬件访问域调度器,限制并发硬件事务与等待队列。 |
1.5 外部交互边界图
构建依赖见 mds/service.json:component_drivers/[>1.1.0]@openubmc/stable。运行时还依赖 libmcpp、会话总线和 systemd。组件自身没有独立监听端口。
2. API 使用说明与示例
对外发布的主服务名为 bmc.kepler.devmon。热插拔入口路径为 /bmc/dev,接口名为 bmc.dev。均可通过 busctl 调试。
方法不使用 libmc4lua 风格的首参 a{ss} 上下文;AddDevice 的 connector 为 a{sv} 字典。
# 查看资源协作接口
busctl --user tree bmc.kepler.devmon默认单层模式下,Scanner / Chip / Connector 不由本进程创建,而是订阅外部 bmc.kepler.hwdiscovery。以下 2.4~2.6 节接口的 MDS 在本仓,运行时仅在 unidev=true 或由独立 hwproxy / hwdiscovery 进程提供时可用。
2.1 bmc.dev(Devmon 根对象)
功能说明
热插拔入口:按 CSR 文件或 CSR 数据加载设备,或按 connector 卸载设备。
路径:/bmc/dev
对象名:Devmon
服务名:bmc.kepler.devmon
| 属性 | 内容 |
|---|---|
| 首发版本 | openUBMC 26.09 |
| 废弃状态 | 正常可用 |
参数说明
| 方法 | D-Bus 签名 | 入参 | 出参 | 说明 |
|---|---|---|---|---|
AddDevice | sa{sv} | csr_file(CSR 文件路径)、connector | 无 | 读取文件后转调 AddDeviceWithData。 |
AddDeviceWithData | 变体 + a{sv} | csr_data(JSON 字符串或 dict)、connector | 无 | 解析 CSR 并创建对象组。 |
RemoveDevice | a{sv} | connector | 无 | 按 Position 卸载设备及对象组。 |
connector 常用键:
| 键 | 类型 | 说明 |
|---|---|---|
Position | integer / string | 槽位或位置。源码用它生成 GroupPosition;为空则抛 Connector Position is not initialized。 |
SystemId | integer | 系统标识,缺省为 1。 |
Slot | integer | 槽位号。 |
GroupPosition | string | 对象组位置。未提供时由 Position 推导并写回 connector。 |
ManagerId / ChassisId | string | 管理标识 / 机框标识,缺省均为 "1"。 |
返回值与异常
成功无返回值(mc::resolve())。失败抛 libmcpp 异常,不能当作整数完成码解读。
| 异常 / 行为 | 含义 | 触发条件 | 处理建议 |
|---|---|---|---|
invalid_arg_exception:Failed to read csr file | 读文件失败 | AddDevice 的路径不存在或不可读 | 核对 CSR 路径与权限。 |
invalid_arg_exception:invalid csr_data type | CSR 数据类型非法 | csr_data 既不是 string 也不是 dict | 传入 JSON 文本或字典。 |
parse_error_exception:Connector Position is not initialized | 无法得到 Position | connector 缺少可推导的位置 | 补 Position 或 GroupPosition。 |
system_exception:no valid service for AddDeviceWithData | 服务指针为空 | unidev 转发路径上服务未就绪 | 确认进程已完成 on_start。 |
日志 device already exists, skip add device | 幂等跳过 | 该 Position 已有 unit 信息 | 视为成功;需要重建时先 RemoveDevice。 |
unidev 且 FormatVersion < 5.00 时,本方法把请求转发到 bmc.kepler.hwdiscovery 的同名 bmc.dev 接口(转发签名为 sa{sv})。
应用场景
开发调试时手动加载一块网卡 CSR;自动化测试模拟热插拔;Connector 驱动 Reload 时内部调用 RemoveDevice 再重新发现。
限制条件
- Position 重复时直接跳过,不会覆盖已有设备。
- 单层模式强制
abi_v2。CSR1 转发只在unidev=true时发生。 RemoveDevice在 Position 为空时直接成功返回,不卸载任何对象。- 卸载由
device_manager统一处理共享总线 / 芯片引用,调用方不要自行按路径递归删对象。
调试示例
busctl --user call bmc.kepler.devmon /bmc/dev bmc.dev AddDevice sa{sv} \
"../tests/tests_data/csr/14140130_19e50222_19e500a1.sr" \
3 Position i 2 SystemId i 1 Slot i 2
busctl --user call bmc.kepler.devmon /bmc/dev bmc.dev RemoveDevice a{sv} \
3 Position i 2 SystemId i 1 Slot i 22.2 bmc.dev.ObjectGroup
功能说明
查询某一 Position 上已上树对象的类名、对象名、属性 JSON 和拓扑。
路径:
- 根:
/bmc/dev/ObjectGroup - 实例:
/bmc/dev/ObjectGroup/${Position}
| 属性 | 内容 |
|---|---|
| 首发版本 | openUBMC 26.09 |
| 废弃状态 | 正常可用 |
unidev 下 hwdiscovery 另有 bmc.kepler.ObjectGroup,路径为 /bmc/kepler/ObjectGroup/${Position},方法名与字段含义相同(MDS:mds/hwdiscovery/model.json)。
参数说明
| 属性 | 类型 | 读写 | 说明 |
|---|---|---|---|
Position | s | 只读 | 对象组位置。 |
Owners | as | 只读 | 对象组所有者 App 名称列表。 |
OnlineTimestamp | t | 只读 | 上树时刻,单位 ms(tick)。 |
Slot | y | 只读 | 槽位号。 |
| 方法 | 入参 | 出参 | 说明 |
|---|---|---|---|
GetObjects | s(Owner,App 名称) | (s a(ssss) u):Position、对象元组数组、LifeCycleId | 每项元组为 (ClassName, ObjectName, ObjectProps, ObjectExtends)。 |
GetTopology | 无 | s | 该 Position 的拓扑 JSON 字符串。 |
返回值与异常
GetObjects 始终返回元组;无对象时数组为空,LifeCycleId 来自对象组数据(CSR 解析默认 1)。调用成功会打 notice 日志 get objects count。
应用场景
业务组件在硬件对象上树后,按 Owner 拉取本位置的设备对象并完成自身注册。
限制条件
对象组在 AddDevice 成功创建之后才存在。RemoveDevice 会注销 /bmc/dev/ObjectGroup/${Position}。
调试示例
busctl --user introspect bmc.kepler.devmon /bmc/dev/ObjectGroup/02
busctl --user call bmc.kepler.devmon /bmc/dev/ObjectGroup/02 \
bmc.dev.ObjectGroup GetObjects s general_hardware
busctl --user call bmc.kepler.devmon /bmc/dev/ObjectGroup/02 \
bmc.dev.ObjectGroup GetTopology2.3 bmc.dev.Devmon.AccessScheduler
功能说明
查询硬件访问域调度器快照,用于诊断并发硬件事务、拒绝和超时。接口挂在 Devmon 根对象上,与 bmc.dev 同路径。
路径:/bmc/dev
| 属性 | 内容 |
|---|---|
| 首发版本 | openUBMC 26.09 |
| 废弃状态 | 正常可用 |
参数说明
| 方法 | 入参 | 出参 | 说明 |
|---|---|---|---|
GetSummary | 无 | a{sv} | 全局摘要。调度器不可用时 Available=false,Error=scheduler_unavailable。 |
GetDomains | 无 | aa{sv} | 全部域快照;调度器不可用时返回空数组。 |
GetDomain | s(域 ID) | a{sv} | 单个域。未找到时 Found=false,Error 为 scheduler_unavailable 或 domain_unresolved。 |
GetSummary 已核实字段包括:Version(1)、SnapshotId、TimestampUs、Available、Accepting、WorkThreads、MaxActiveHardware、ActiveHardware、ReadyDomains、DomainCount、PermitWaitP50Us / P95Us / P99Us / MaxUs、RawP50Us / P95Us / P99Us / MaxUs,以及累计 Submitted / Completed / Failed / Rejected / TimedOut / Cancelled / Coalesced / SourceLimited / ResourceLimited / PhysicalLimited / LogicalDispatches / HardwareDispatches。
访问来源名(域快照使用):interactive、control、plugin_high、plugin_secondary、accessor、scanner、background、unknown。优先级名:high、secondary、normal、low。
配置项见 config.single.json.in:max_active_hardware 默认 2,max_domain_waiters 默认 512,hardware_request_timeout_ms 默认 120000。
返回值与异常
方法本身不抛业务完成码。调度器未绑定到根对象时返回带 Error 的字典或空数组。
应用场景
硬件访问超时、请求被拒绝、总线排队过长时抓调度快照。一键收集也会把同样的摘要写入 access_scheduler.json。
限制条件
诊断接口,不改变调度策略。生产环境不要高频轮询全部域。
调试示例
busctl --user call bmc.kepler.devmon /bmc/dev \
bmc.dev.Devmon.AccessScheduler GetSummary
busctl --user call bmc.kepler.devmon /bmc/dev \
bmc.dev.Devmon.AccessScheduler GetDomains2.4 bmc.kepler.Connector(MDS:mds/hwdiscovery/model.json)
功能说明
连接器对象:描述下级板卡身份、在位和加载状态,并提供 Reload 重新加载。
路径:/bmc/kepler/Connector/:ID
服务名:unidev 下为 bmc.kepler.hwdiscovery;独立 hwdiscovery 进程同名。实现位于 component_drivers 的 Connector 驱动,Reload 在加载成功时会向名为 Devmon 的对象调用 RemoveDevice。
参数说明
| 属性 | 类型 | 读写 | 说明 |
|---|---|---|---|
Bom | s | 只读 | 下级板卡 Bom。 |
Slot | y | 可读写 | 槽位号。 |
Presence | y | 可读写 | 0 不在位,1 在位,255 初始化。 |
Id / AuxId | s | 可读写 | 唯一标识 / 辅助标识。 |
Buses | as | 只读 | 下级板卡连接的总线名。 |
SystemId | y | 只读 | 缺省 1。 |
ManagerId / ChassisId | s | 只读 | 管理标识 / 机框标识。 |
Type | s | 只读 | 如 PCIeSlot、PCIeRiser。 |
GroupPosition | s | 只读 | 对象组位置。 |
LoadStatus | y | 只读 | 0 加载成功,非 0 失败,255 初始化。 |
| 方法 | 入参 | 出参 | 权限 | 说明 |
|---|---|---|---|---|
Reload | Bom、Id、AuxId(string)、IdentifyMode(y) | 无 | BasicSetting | 按新身份重新加载连接器。 |
CSR 额外字段(不上 D-Bus 接口,仅模型):Chip(refInterface 为 bmc.kepler.Chip.BlockIO)、Container、Position、IdChipAddr、CSRVersion。
返回值与异常
属性按模型读写。Reload 失败时 Connector 驱动打 Reload attempt ... failed 日志;成功打 Reload successfully。
应用场景
热插拔后强制按新 Bom/Id 重新发现;装备或维护时手动改身份再加载。
限制条件
需要 Connector 驱动 .so 已加载。不要用客户定制 CSR 的 DeletedObjects 删除 Connector_*、I2c_* 等硬件 / 拓扑对象。
调试示例
busctl --user introspect bmc.kepler.hwdiscovery /bmc/kepler/Connector/12.5 bmc.kepler.Scanner / bmc.kepler.Accessor
功能说明
Scanner 按周期从 Chip 读值;Accessor 提供可写的按需访问,并给出可打印 ASCII 值。
路径:/bmc/kepler/Scanner/:Id、/bmc/kepler/Accessor/:Id
服务名:unidev 下为 bmc.kepler.hwproxy。
参数说明
Scanner / Accessor 公共状态枚举(Status):
| 取值 | 含义 |
|---|---|
0 | 正常获取值 |
1 | 获取值失败 |
2 | 预失败,正在防抖 |
3 | 无效状态 |
4 | 初始状态(默认) |
| 接口 | 属性 | 类型 | 读写 | 说明 |
|---|---|---|---|---|
bmc.kepler.Scanner | Value | t | 只读 | Scanner 当前值。 |
bmc.kepler.Scanner | Status | y | 只读 | 见上表。 |
bmc.kepler.Scanner.Aggregate | AggregateOffset | u | 只读 | 汇聚数据相对偏移。 |
bmc.kepler.Scanner.Aggregate | AggregateStatus | b | 只读 | 是否从汇聚数据读到。 |
bmc.kepler.Accessor | Value | t | 可读写 | Accessor 值。 |
bmc.kepler.Accessor | Status | y | 只读 | 含义同 Scanner。 |
bmc.kepler.Accessor | PrintableValue | s | 只读 | 可打印 ASCII;含不可见字符时不更新。不能用该属性触发写硬件。 |
| 方法 | 接口 | 入参 | 权限 | 说明 |
|---|---|---|---|---|
TraceDebounce | bmc.kepler.Release.Scanner | Action:start / stop | DiagnoseMgmt | 跟踪该 Scanner 的防抖输入、表达式和结果。CLI 名 tracedebounce。 |
CSR 字段(不上接口,仅配置):Chip、Size、Offset、Mask、Period、Type(0 位读 / 1 块读)、Debounce、ScanEnabled、NominalValue、FailureDebounceCount / SuccessDebounceCount(默认 10)。
返回值与异常
属性只读失败表现为 Status 非 0,而不是 D-Bus 完成码。TraceDebounce 的 Action 必须为 start 或 stop。
应用场景
温度 / 在位等周期采样;维护时跟踪防抖是否把瞬时毛刺滤掉。
限制条件
ScanEnabled 可通过表达式同步其他 Scanner,但不能依赖成环。块读时 Mask 无效。Accessor 仅块读场景更新 PrintableValue。
调试示例
busctl --user get-property bmc.kepler.hwproxy /bmc/kepler/Scanner/1 \
bmc.kepler.Scanner Value
busctl --user call bmc.kepler.hwproxy /bmc/kepler/Scanner/1 \
bmc.kepler.Release.Scanner TraceDebounce s start2.6 bmc.kepler.Chip.*(MDS:mds/hwproxy/model.json)
功能说明
芯片访问接口。本仓以 Chip 类(路径 /bmc/kepler/Chip/Complex/:Id)为完整模板;Eeprom 等其它器件类复用同一套 BlockIO / BitIO / TraceChip 方法,仅路径与 CSR 字段不同。方法由 component_drivers 的 Chip 驱动实现,unidev 时对象挂在 bmc.kepler.hwproxy。
参数说明
bmc.kepler.Chip
| 属性 | 类型 | 读写 | 说明 |
|---|---|---|---|
HealthStatus | y | 可读写 | 0 访问正常,1 访问失败。 |
PowerStatus | y | 只读 | 上电状态,默认 1。 |
SelfTestResult | y | 只读 | 自检结果,默认 1。 |
ChipType | s | 只读 | 器件类型名。 |
HealthStatusValidity | b | 只读 | HealthStatus 是否有效。 |
LockStatus | y | 只读 | 0 未锁定,1 锁定。 |
| 方法 | 入参 | 出参 | 说明 |
|---|---|---|---|
SetAccessibility | Status(b)、DisableDuration(q,秒,1~1800) | 无 | 禁止访问后到期自动恢复。MDS 英文描述写 “status is true 时 DisableDuration 生效”,中文描述写禁止时长;以实现与现场验证为准。 |
SetLockStatus | OpType(y:0 解锁 / 1 加锁)、LockTime(u,秒,加锁时 <= 30min) | ResultCode | 见下表。 |
SetLockStatus 的 ResultCode:
| 值 | 名 | 含义 |
|---|---|---|
0 | OK | 成功。 |
1 | InvalidParameter | LockTime 非法。 |
2 | UnlockedError | 通道未锁定(解锁时)。 |
3 | RequestorMismatchedError | 请求者与锁定者不一致。 |
4 | ChipMismatchedError | 同通道其它器件已锁总线。 |
5 | ChannelMismatchedError | 同总线其它通道已锁总线。 |
bmc.kepler.Chip.BlockIO
| 方法 | 入参 | 出参 | 说明 |
|---|---|---|---|
Read | Offset(u)、Length(u) | OutData(ay) | 按字节读取。 |
Write | Offset(u)、InData(ay) | 无 | 按字节写入。 |
WriteRead | InData(ay)、ReadLength(u) | OutData | 先写再从固定 offset 读。 |
ComboWriteRead | WriteOffset、InData、ReadOffset、ReadLength | OutData | 指定写/读偏移的组合事务。 |
BatchWrite | WriteData 数组,每项 {Offset, InData} | 无 | 一次写入多个偏移。 |
PluginRequest | PluginName、Cmd、Params(ay) | OutData | 加载 hwproxy 插件并执行命令;占用总线通道。 |
PluginRequestEx | 同上,外加 ControlParams(a{ss}) | OutData | 拓展插件请求。MDS 声明 Priority 可为 High / Secondary。 |
WriteReadByProtocol | InData、ReadLength、Protocol(y) | OutData | 当前仅支持 0x02 SMBus/I2C。 |
bmc.kepler.Chip.BitIO
| 方法 | 入参 | 出参 | 说明 |
|---|---|---|---|
Read | Offset(u)、Length(y)、Mask(u) | OutData | 读值与 Mask 按位与。 |
Write | Offset、Length、Mask、InData | 无 | 先读后按 Mask 改写。 |
bmc.kepler.Release.TraceChip
| 方法 | 入参 | 权限 | 说明 |
|---|---|---|---|
TraceChip | Action:start / stop | DiagnoseMgmt | 跟踪该 Chip 读写数据。CLI 名 tracechip。 |
bmc.kepler.Release.Chip
维护 CLI read:按 Offset/Length 读原始字节,权限 DiagnoseMgmt。
bmc.kepler.Bus / bmc.kepler.Bus.BlockIO
总线类(I2c 路径 /bmc/kepler/Bus/I2c/:Id 等)提供 AccessEnabled、Timeout 与 SetAccessibility(DisableDuration 范围 1~1800 秒)。I2C 另有 Read / Write / WriteRead(按从地址)。
返回值与异常
硬件访问失败通常反映为 Chip HealthStatus=1 或 D-Bus 调用异常,而不是 IPMI 完成码。PluginRequest 查不到插件命令时由宿主报错,不会落到其它函数。
应用场景
业务组件通过 Chip 代理读写 EEPROM / 温度传感器;mctpd / storage / power_mgmt 通过 PluginRequest 调用 smbus / sml / power_mgmt 等插件。
限制条件
- 调用方须在自身
mds/service.json声明对相应 Chip 接口的依赖。 PluginRequest执行期间占据总线,长事务应按插件文档使用可调度模式,避免独占。- 本仓文档只列出 MDS 已核实的方法名与字段;各厂商 Chip 的超时、重试和页切换行为以
component_drivers实现为准。
调试示例
busctl --user introspect bmc.kepler.hwproxy /bmc/kepler/Chip/Complex/1
busctl --user call bmc.kepler.hwproxy /bmc/kepler/Chip/Complex/1 \
bmc.kepler.Chip.BlockIO Read uu 0 2
busctl --user call bmc.kepler.hwproxy /bmc/kepler/Chip/Complex/1 \
bmc.kepler.Release.TraceChip TraceChip s start2.7 驱动 ABI(C 接口,include/devmon/driver_abi.h)
功能说明
设备 .so 必须导出 register_device_driver,向 devmon 登记一张或多张 device_driver 函数表。这是进程内 C ABI,不能通过 busctl 调用。
参数说明
| 符号 | 说明 |
|---|---|
register_device_driver(device_driver_t** device_driver, uint8_t* count) | 输出驱动表指针与条数。 |
device_name | 驱动名,与 CSR 类名对应。 |
ctor(service, object_name) | 创建 driver_handle_t。 |
init(handle, csr_object, connector) | 用 CSR 与 connector 初始化。 |
start / stop | 启动 / 停止。 |
dump | 返回诊断文本;指针由驱动持有,调用方不得 free,跨下一次 dump 前应自行拷贝。 |
status_t(返回值) | register_device_driver、init、start、stop 的返回类型,取值见下表。 |
status_t:
| 值 | 宏 | 含义 |
|---|---|---|
0 | STATUS_OK | 成功 |
1 | STATUS_ERROR | 一般错误 |
2 | STATUS_NOT_FOUND | 未找到 |
3 | STATUS_INVALID_ARG | 参数非法 |
4 | STATUS_NOT_IMPLEMENTED | 未实现 |
5 | STATUS_TIMEOUT | 超时 |
6 | STATUS_BUSY | 忙 |
7 | STATUS_NO_MEMORY | 内存不足 |
返回值与异常
register_device_driver 与 init / start / stop 返回 status_t。C 接口不抛异常。
应用场景
在 component_drivers 仓实现新器件 / 新总线驱动,而不是在 devmon 仓新增 plugins/。
限制条件
不要在设备 so 里重写应用层 has_cmd / run_cmd。应用层 Lua 插件见仓内 docs/2.2.应用层插件.md。Zephyr 形态无 dlopen,驱动在 SYS_INIT 期静态注册。
调试示例
#include "devmon/driver_abi.h"
status_t register_device_driver(device_driver_t** device_driver, uint8_t* count)
{
static device_driver_t table[] = {
{"MyChip", my_ctor, my_init, my_start, my_stop, my_dump},
};
*device_driver = table;
*count = 1;
return STATUS_OK;
}3. 组件扩展案例
3.1 扩展能力概述
devmon 不在本仓扩展具体网卡 / GPU 逻辑。支持的扩展方式:
- 在
component_drivers实现driver_abi.h,由 bingo/Conan 把.so装到驱动目录。 - 机型 CSR 增加 Connector / Endpoint / Chip / Scanner 对象。
- 客户定制 CSR:
/opt/bmc/extend/{customer}/sr/下{identity}_cust.sr,或index.json按前缀 / 后缀共享定制文件。 - 应用层 Lua 插件放到 hwproxy 插件目录,经
PluginRequest调用。 - 构建选项
unidev切换单层 / 三层。
3.2 扩展点说明
| 扩展点 | 位置 | 触发时机 |
|---|---|---|
| 设备 so | component_drivers,ABI 见 include/devmon/driver_abi.h | AddDevice / 发现加载 |
| 应用层 Lua 插件 | /opt/bmc/lualib/hwproxy/plugins/<PluginName>/ | PluginRequest |
| 客户定制 CSR | /opt/bmc/extend/{customer}/sr/ | CSR 合并 |
| 机型定制 CSR | /opt/bmc/extend/{platform_id}_{board_id}/sr/ | CSR 合并;不读 index.json |
| 直挂对象路由 | DIRECT_SERVICE_OBJECT_POLICIES | unidev 解析 CSR 时 |
| 白名单重命名 | whitelist.json | 对象名冲突时 |
直挂策略表已核实的类名:Connector → hwdiscovery;Accessor / Scanner / SmcDfxInfo / Median / MidAvg / Cont / ContBin / DftPca9545 / DftPca9555 / DftLm75 / DftI2c / DftCan → hwproxy。
3.3 二次开发指导
3.3.1 客户定制 CSR
将 {Bom}_{Id}_{AuxId}_cust.sr 放到 /opt/bmc/extend/{customer}/sr/。加载时与基础 CSR 的 Objects 合并:同名对象合并属性,新对象直接加入。
仅允许删除软件对象(如 PCIeNicCard_1、NetworkPort_0、OpticalModule_0、SRUpgrade_1):
{
"Objects": {
"PCIeNicCard_1": {
"bmc.dev.PCIeDevice": {
"DeviceName": "hisi_1822"
}
}
},
"Customization": {
"DeletedObjects": ["OpticalModule_0"]
}
}index.json 的 Rules 仅支持 Prefix / Suffix。命中优先级:Prefix 优于 Suffix;同类中 Pattern 更长者胜。机型定制目录不读索引。
验证方法:加载部件后检查对象属性是否被覆盖,以及 DeletedObjects 中的软件对象是否消失。
注意事项:不要删除 I2c_*、Eeprom_*、Connector_*、Scanner_* 等硬件或拓扑对象。
3.3.2 新增设备驱动
- 在
component_drivers实现register_device_driver。 - 不要修改 devmon 仓
subprojects/component_drivers副本后当作上游。 - 用
bingo test -ut -jit跑 devmon 侧 UT(需-jit)。
3.3.3 应用层插件
业务进程只拿 Chip 代理调用 PluginRequest,不要 require 插件、不要 open("/dev/i2c-x")。公开点名与仓名的差异(如 mctpd 点 'smbus'、storage 点 'sml')见仓内 docs/2.2.应用层插件.md。
4. 日志说明
组件使用 libmcpp 日志。配置模板 config.single.json.in 中 Logging 的 module_name 为 devmon,默认级别 notice。unidev 下 hwdiscovery / hwproxy 各自安装组件日志作用域,文件日志归属对应组件,不随执行线程漂移。
4.1 一键日志收集
devmon_service::on_dump、hwproxy_service::on_dump、discovery_service::on_dump 分别在对应服务的 Dump 回调中执行。
| 文件 | 产生服务 | 内容说明 |
|---|---|---|
<dump_path>/access_scheduler.json | devmon | GetSummary + GetDomains 的 JSON。 |
<dump_path>/topology.txt | devmon / hwproxy | 根对象 DevTopology 或 HwProxy 下的拓扑树。 |
<dump_path>/snapshot.csv | devmon / hwproxy | Scanner / Accessor dump 文本。 |
<dump_path>/drivers_load_info.csv | devmon | 驱动加载信息。 |
<dump_path>/chips_access_statistic.csv | devmon / hwproxy | 芯片访问统计;Release 构建跳过。 |
JBOG box_info | devmon | 目录权限 0750,basic_info / cpld_info 文件权限 0640。 |
<dump_path>/connectors.txt | hwdiscovery | Connector dump,含 root 头。 |
<dump_path>/root.sr、platform.sr | hwdiscovery | 从允许路径复制的根 / 机型 CSR。 |
<dump_path>/<connector>.sr / .bin | hwdiscovery | 按 Connector dump 中的 SourcePath 复制;在位且 IdentifyMode=3 时最多复制 65 份 EEPROM 备份。 |
4.2 关键日志信息
| 日志片段 | 日志级别 | 含义解读 | 建议处理动作 |
|---|---|---|---|
architecture mode: three-layer | single | 启动日志 | 当前是 unidev 还是单层 | 与构建选项核对 |
AddDevice forward to hwdiscovery | INFO | CSR1 已转发 | 确认 FormatVersion 是否故意小于 5.00 |
device already exists, skip add device | WARN | Position 重复,幂等跳过 | 先 RemoveDevice 再加载 |
object_group created for position | NOTICE | 对象组已创建 | 无 |
Connector Position is not initialized | 异常 | connector 无位置 | 补 Position |
Failed to read csr file | 异常 | 文件不可读 | 检查路径 |
RemoveDevice routing CSR1 position ... to hwdiscovery | INFO | CSR1 卸载转发 | 无 |
open mctp device failed 等驱动错误 | 视驱动 | 不在本组件核心路径 | 查对应驱动仓 |
discovery dump started / connectors dump success | NOTICE | hwdiscovery Dump | 无 |
failed to dump access scheduler diagnostics | WARN | 调度快照写出失败 | 检查 Dump 目录权限 |
5. 问题定界指南
5.1 典型问题定界
| 问题描述 | 是否为本组件问题 | 判断依据 | 关键证据收集方法 |
|---|---|---|---|
AddDevice 抛读文件失败 | 是。若调用方传入的 CSR 路径不可读,则根因在调用方 | 异常文本含 Failed to read csr file | 核对路径是否在板端可读 |
| 设备未上树但 AddDevice 成功 | 可能是幂等跳过 | device already exists 日志 | busctl tree 看 ObjectGroup;必要时先 RemoveDevice |
| PCIe 业务对象不上树 | 可能是 CSR / 路由 / 驱动 | 无对应 ObjectGroup 或驱动未 dlopen | 查 FormatVersion、drivers_load_info.csv、驱动目录 |
| Scanner 值为空或 Status=1 | 可能是 hwproxy / 硬件 | 对象在 hwproxy 树上 | 查 Chip HealthStatus、总线 AccessEnabled、防抖 |
PluginRequest 失败 | 通常是插件或 Chip | 插件目录名 / Cmd 不匹配 | 对照 docs/2.2.应用层插件.md 的点名表 |
| IPMI 命令失败 | 否 | 本组件无 IPMI 接口 | 转向实现该命令的业务组件 |
| 进程被 systemd 杀掉 | 可能是内存 | MemoryMax=150M | 查 OOM 与 RSS |
require('devmon...') 找不到模块 | 否 | 本组件不导出业务 Lua 模块 | 改用 D-Bus 或 Chip 代理 |
5.2 错误码速查表
| 错误码 | 来源 | 含义 | 排查建议 |
|---|---|---|---|
| (无返回值) | bmc.dev 成功 | mc::resolve() | 结合日志确认是否 skip |
invalid_arg_exception | 根接口 | 文件或 csr_data 类型非法 | 见 2.1 |
parse_error_exception | 根接口 / CSR 解析 | Position 或 CSR 内容非法 | 保存脱敏 CSR 与 connector |
system_exception | 根接口 | 服务未就绪或转发目标无效 | 查进程启动与 unidev 服务名 |
0~7 | driver_abi.h status_t | 驱动内部状态 | 见 2.7 |
SetLockStatus 0~5 | Chip MDS | 锁结果 | 见 2.6 |
Found=false | AccessScheduler | 域不存在或调度器不可用 | 先 GetSummary 看 Available |
仓库没有 mds/errors.json,没有 IPMI 完成码表。
5.3 最小化复现与证据收集
- 记录
unidev构建选项、CSRFormatVersion、connector 的 Position / SystemId / Slot。 busctl --user tree bmc.kepler.devmon,必要时再看bmc.kepler.hwproxy/bmc.kepler.hwdiscovery。- 保存 AddDevice 异常文本与
device already exists/forward to hwdiscovery日志。 - 执行一键收集,保留
topology.txt、snapshot.csv、drivers_load_info.csv、access_scheduler.json、connectors.txt。 - 插件问题记录
PluginName、Cmd和 Chip 路径,不要采集完整 EEPROM 明文。
5.4 调试方法
busctl --user tree bmc.kepler.devmon
busctl --user introspect bmc.kepler.devmon /bmc/dev
busctl --user call bmc.kepler.devmon /bmc/dev \
bmc.dev.Devmon.AccessScheduler GetSummary- 单元测试:
bingo test -ut -jit(必须加-jit)。 - 本地 meson:
./scripts/smart_build.sh;三层测试加-Dunidev=true。 - 对单个 Chip 调用
TraceChip start,对 Scanner 调用TraceDebounce start。
6. 常见问题解答
Q1:AddDevice 报 Failed to read csr file 怎么办?
- 问题描述:
busctl调用AddDevice抛invalid_arg_exception。 - 一句话答案:第一个参数必须是进程能读到的
.sr路径。 - 根因说明:
add_device先read_file,失败即抛错,不会进入解析。 - 解决方案:使用板端绝对路径,或改用
AddDeviceWithData传入 JSON 文本。 - 规避方案:通过正式发现流程加载 CSR,而不是从开发机相对路径调用。
- 适用版本:1.2.109。
Q2:为什么 AddDevice 成功但对象没有变化?
- 问题描述:重复加载同一 Position,树上仍是旧对象。
- 一句话答案:该 Position 已存在时实现会跳过解析并返回成功。
- 根因说明:日志为
device already exists, skip add device,避免重复创建。 - 解决方案:先
RemoveDevice再AddDevice,或使用 ConnectorReload。 - 规避方案:热插拔脚本以 Position 为键做卸载/加载配对。
- 适用版本:1.2.109。
Q3:单层构建下为什么没有 bmc.kepler.hwproxy?
- 问题描述:
busctl tree看不到 Scanner / Chip,或 hwproxy 服务名不存在。 - 一句话答案:默认
unidev=false只注册bmc.kepler.devmon。 - 根因说明:三层服务由编译宏
DEVMON_ENABLE_UNIDEV控制;单层通过topology_discovery订阅外部 hwdiscovery。 - 解决方案:产品若拆分进程,分别查 hwproxy / hwdiscovery 组件;需要同进程三层时用
-o unidev=True构建。 - 规避方案:不要假设 Chip 路径一定在
bmc.kepler.devmon树上。 - 适用版本:1.2.109。
Q4:业务能否 require 某个 devmon Lua 模块?
- 问题描述:Lua 报 module not found。
- 一句话答案:devmon 不向业务导出 Lua API;设备管理走 D-Bus,插件走
PluginRequest。 - 根因说明:进程是 C++
mc::app,驱动是 C ABI.so,应用层插件由 hwproxy 加载。 - 解决方案:对热插拔用
bmc.dev;对硬件命令用 Chip 代理的PluginRequest,第二参为插件目录名。 - 规避方案:不要把 hwproxy 插件路径加入业务进程的
package.path再直接require。 - 适用版本:1.2.109。
Q5:CSR1 设备加不上或卸不掉?
- 问题描述:
FormatVersion小于5.00时加载或卸载不符合预期。 - 一句话答案:unidev 会把 CSR1 转发到
bmc.kepler.hwdiscovery的bmc.dev。 - 根因说明:阈值定义为
FORMAT_VERSION_THRESHOLD = 5.00;缺省 FormatVersion 按5.00走 CSR2。单层模式不转发,且强制abi_v2。 - 解决方案:查
AddDevice forward to hwdiscovery/RemoveDevice routing CSR1日志,并确认 hwdiscovery 服务已就绪。 - 规避方案:新机型 CSR 使用
FormatVersion≥ 5.00。 - 适用版本:1.2.109。