OpenBMC D-Bus 介绍

张开发
2026/4/17 8:08:18 15 分钟阅读

分享文章

OpenBMC D-Bus 介绍
OpenBMC D-Bus 介绍D-Bus(Desktop Bus)本质是消息总线 服务注册中心 事件通知机制。是 OpenBMC 的核心中枢是一套标准化、面向对象的进程间通信(IPC)总线系统负责连接所有 BMC 内部服务、硬件抽象层与外部管理接口(IPMI/Redfish/REST)。在 OpenBMC 中定位为系统 “中枢神经”所有组件(传感器、风扇、电源、日志、用户、状态机)通过 D-Bus 交互服务化架构底座每个功能模块以 服务名 对象路径 接口 方法 属性 信号 暴露能力硬件抽象层(HAL)驱动层把硬件状态映射为 D-Bus 对象上层协议(IPMI/Redfish)只调用 D-Bus 接口事件驱动核心状态变更(温度越限、电源切换)通过 PropertiesChanged 信号广播OpenBMC 中的协作架构客户端(ipmitool) ↓(RMCP/KCS/BT) ┌─────────────────────┐ │ phosphor-ipmi-host │ → IPMI 协议栈(解析命令、权限、会话) │ (ipmid 守护进程) │ └───────────┬─────────┘ ↓(D-Bus 调用) ┌─────────────────────────────────────┐ │ D-Bus 总线 │ └───────────┬─────────┬─────────┬──────┘ ↓ ↓ ↓ 传感器服务 电源服务 日志服务 FRU服务IPMI 请求数据流基础概念核心作用进程间通信(IPC)替代 Socket、管道提供标准化、跨语言、跨服务的调用机制服务发现通过 ObjectMapper 动态查找服务 / 对象无需硬编码地址统一接口所有功能以对象 接口 方法 / 属性 / 信号形式暴漏三大核心元素1. 服务名(Service Name)格式xyz.openbmc_project.组件名.子组件名示例xyz.openbmc_project.State.Host (主机状态服务)xyz.openbmc_project.Sensor.Manager (传感器服务)xyz.openbmc_project.ObjectMapper (服务发现核心)2. 对象路径(Object Path)格式/xyz/openbmc_project/类别/子类别/实例示例/xyz/openbmc_project/state/host0 (主机 0 对象状态)/xyz/openbmc_project/sensors/temperature/cpu0 (CPU0 温度传感器对象)3. 接口(Interface)格式xyz.openbmc_project.组件.接口名包含方法(Method)、属性(Property)、信号(Signal)示例xyz.openbmc_project.State.Host(主机状态接口)xyz.openbmc_project.Sensor.Value(传感器值接口)数据类型(D-Bus Signature)常用类型与 C 对应关系签名类型C 类型s字符串std::stringi32位整数int32_tu32位无符号uint32_tb布尔boold双精度doublea字符串数组std::vectorstd::stringv变体(任意类型)std::variant命令行调试busctl# 1. 查看所有服务 busctl list # 2. 查看对象树(以Sensor为例) busctl tree xyz.openbmc_project.Sensor.Manager # 3. 查看对象详情(方法/属性/信号) busctl introspect xyz.openbmc_project.State.Host /xyz/openbmc_project/state/host0 # 4. 调用方法(主机开机) busctl call xyz.openbmc_project.State.Host \ /xyz/openbmc_project/state/host0 \ xyz.openbmc_project.State.Host \ RequestedHostTransition s xyz.openbmc_project.State.Host.Transition.On # 5. 读取属性(CPU温度) busctl get-property xyz.openbmc_project.Sensor.Manager \ /xyz/openbmc_project/sensors/temperature/cpu0 \ xyz.openbmc_project.Sensor.Value Value # 6. 监控所有D-Bus消息 busctl monitor --allmapper(ObjectMapper 工具服务发现)# 1. 获取某接口的所有对象 mapper get-subtree / xyz.openbmc_project.Sensor.Value # 2. 查找对象所属服务(核心避免硬编码) mapper get-service /xyz/openbmc_project/state/host0 # 3. 获取对象所有接口 mapper get-interfaces /xyz/openbmc_project/sensors/temperature/cpu0dbus-monitor# 监控指定接口的方法调用 dbus-monitor --system typemethod_call,interfacexyz.openbmc_project.State.HostOpenBMC D-Bus 开发sdbusplus(C 标准库)OpenBMC 统一使用 sdbusplus 库开发 D-Bus 服务 / 客户端基于 systemd D-Bus 封装。开发流程(标准步骤)定义接口(YAML)→ phosphor-dbus-interfaces 仓库生成代码→ 编译自动生成 C 头文件服务端实现→ 继承接口类、实现方法 / 属性客户端调用→ 连接总线、发起方法调用注册服务→ 连接 System Bus、发布对象接口定义(YAML推荐)# xyz/openbmc_project/Example/Demo.interface.yaml description: 示例D-Bus接口 methods: - name: SayHello description: 打招呼 parameters: - name: name type: string description: 姓名 returns: - name: message type: string description: 返回消息 properties: - name: Status type: boolean description: 运行状态 flags: [readwrite] signals: - name: StatusChanged description: 状态变更信号 parameters: - name: new_status type: boolean服务端代码(C)#include sdbusplus/bus.hpp #include sdbusplus/server/object.hpp #include xyz/openbmc_project/Example/Demo/server.hpp // 接口别名 using DemoInterface sdbusplus::server::object_t sdbusplus::xyz::openbmc_project::Example::server::Demo; class DemoService : public DemoInterface { public: // 构造函数绑定总线与对象路径 DemoService(sdbusplus::bus_t bus, const char* path) : DemoInterface(bus, path) {} // 实现方法SayHello std::string SayHello(const std::string name) override { return Hello, name !; } // 重写属性Setter(可选) bool status(bool value) override { bool old status(); if (old ! value) { // 发送信号 DemoInterface::StatusChanged(value); } return DemoInterface::status(value); } }; int main() { // 1. 连接System Bus auto bus sdbusplus::bus::new_default_system(); // 2. 申请服务名 bus.request_name(xyz.openbmc_project.Example.Demo); // 3. 创建服务对象 DemoService service(bus, /xyz/openbmc_project/example/demo); // 4. 事件循环 while (true) { bus.process_discard(); bus.wait(); } return 0; }客户端代码(C)#include sdbusplus/bus.hpp #include iostream int main() { // 1. 连接总线 auto bus sdbusplus::bus::new_default_system(); // 2. 创建方法调用 auto call bus.new_method_call( xyz.openbmc_project.Example.Demo, // 服务名 /xyz/openbmc_project/example/demo, // 对象路径 xyz.openbmc_project.Example.Demo, // 接口名 SayHello // 方法名 ); // 3. 添加参数 call.append(OpenBMC); // 4. 调用并获取结果 auto reply bus.call(call); std::string msg; reply.read(msg); std::cout 响应: msg std::endl; return 0; }ObjectMapper(服务发现)作用解耦服务与客户端客户端不硬编码服务名通过对象路径查找服务全局对象目录记录所有 D-Bus 对象、接口、服务的映射关系常用方法(命令 / 代码)# 命令行GetObject(查对象所属服务) busctl call xyz.openbmc_project.ObjectMapper \ /xyz/openbmc_project/object_mapper \ xyz.openbmc_project.ObjectMapper \ GetObject sas /xyz/openbmc_project/state/host0 0// C通过ObjectMapper查找服务 auto mapper bus.new_method_call( xyz.openbmc_project.ObjectMapper, /xyz/openbmc_project/object_mapper, xyz.openbmc_project.ObjectMapper, GetObject ); mapper.append(/xyz/openbmc_project/state/host0); mapper.append(std::vectorstd::string{}); auto reply bus.call(mapper); std::mapstd::string, std::vectorstd::string services; reply.read(services); // services.begin()-first 即为服务名可运行的 OpenBMC D-Bus 完整工程最小可用、可直接编译的工程包含 YAML 接口定义 C 服务端 C 客户端 编译脚本工程目录结构dbus-demo/ ├── interfaces/ # D-Bus 接口定义(YAML) │ └── xyz/ │ └── openbmc_project/ │ └── Example/ │ └── Demo.interface.yaml ├── src/ │ ├── server.cpp # 服务端代码 │ └── client.cpp # 客户端代码 ├── meson.build # 编译脚本(OpenBMC 标准) └── README.md # 使用说明文件内容1. 接口定义Demo.interface.yamldescription: OpenBMC D-Bus 演示接口 methods: - name: SayHello description: 打招呼方法 parameters: - name: name type: string description: 你的名字 returns: - name: reply type: string description: 返回消息 - name: Add description: 加法计算 parameters: - name: a type: int64 - name: b type: int64 returns: - name: sum type: int64 properties: - name: Status type: boolean description: 运行状态 flags: [readwrite] signals: - name: StatusChanged description: 状态变化信号 parameters: - name: newStatus type: boolean2. 服务端server.cpp#include sdbusplus/bus.hpp #include sdbusplus/server/object.hpp #include xyz/openbmc_project/Example/Demo/server.hpp #include iostream // 接口别名 using DemoItf sdbusplus::server::object_t sdbusplus::xyz::openbmc_project::Example::server::Demo; // 服务类 class DemoServer : public DemoItf { public: DemoServer(sdbusplus::bus_t bus, const char* path) : DemoItf(bus, path) { std::cout D-Bus 服务已启动: xyz.openbmc_project.Example.Demo\n; std::cout 对象路径: /xyz/openbmc_project/example/demo\n; } // 实现 SayHello 方法 std::string SayHello(const std::string name) override { std::cout 收到调用: SayHello( name )\n; return Hello name ! 来自 OpenBMC D-Bus 服务; } // 实现 Add 方法 int64_t Add(int64_t a, int64_t b) override { std::cout 收到调用: Add( a , b )\n; return a b; } // 重写 Status 属性 set bool status(bool value) override { bool old status(); if (old ! value) { std::cout 状态变化: old → value \n; // 发送信号 DemoItf::StatusChanged(value); } return DemoItf::status(value); } }; int main() { // 连接系统总线 auto bus sdbusplus::bus::new_system(); // 注册服务名 bus.request_name(xyz.openbmc_project.Example.Demo); // 创建对象 DemoServer server(bus, /xyz/openbmc_project/example/demo); // 循环处理消息 while (true) { bus.process_discard(); bus.wait(); } return 0; }3. 客户端client.cpp硬编码版本实际项目中不会这样用#include sdbusplus/bus.hpp #include iostream int main() { auto bus sdbusplus::bus::new_system(); // 调用 SayHello auto msg bus.new_method_call( xyz.openbmc_project.Example.Demo, /xyz/openbmc_project/example/demo, xyz.openbmc_project.Example.Demo, SayHello); msg.append(OpenBMC User); auto reply bus.call(msg); std::string res; reply.read(res); std::cout SayHello 结果: res \n; // 调用 Add auto msg2 bus.new_method_call( xyz.openbmc_project.Example.Demo, /xyz/openbmc_project/example/demo, xyz.openbmc_project.Example.Demo, Add); msg2.append(int64_t(10), int64_t(20)); auto reply2 bus.call(msg2); int64_t sum; reply2.read(sum); std::cout Add(10,20) 结果: sum \n; // 设置 Status 属性 auto msg3 bus.new_method_call( xyz.openbmc_project.Example.Demo, /xyz/openbmc_project/example/demo, org.freedesktop.DBus.Properties, Set); msg3.append( xyz.openbmc_project.Example.Demo, Status, std::variantbool(true)); bus.call(msg3); std::cout 已设置 Status true\n; return 0; }ObjectMapper 服务发现版本实际项目都会这样用#include sdbusplus/bus.hpp #include sdbusplus/message.hpp #include iostream #include map #include vector #include stdexcept // 工具函数通过 ObjectMapper 获取对象的服务名(OpenBMC 标准写法) std::string getServiceName(sdbusplus::bus_t bus, const std::string objPath) { try { // 调用 ObjectMapper GetObject 方法 auto msg bus.new_method_call( xyz.openbmc_project.ObjectMapper, // 固定服务名 /xyz/openbmc_project/object_mapper, // 固定对象路径 xyz.openbmc_project.ObjectMapper, // 固定接口 GetObject); // 固定方法 // 参数对象路径 空接口列表 msg.append(objPath); msg.append(std::vectorstd::string{}); // 调用并解析返回值map服务名, 接口列表 auto reply bus.call(msg); std::mapstd::string, std::vectorstd::string services; reply.read(services); if (services.empty()) { throw std::runtime_error(对象不存在 objPath); } // 返回第一个服务名 return services.begin()-first; } catch (const std::exception e) { std::cerr ObjectMapper 查询失败: e.what() \n; throw; } } int main() { try { auto bus sdbusplus::bus::new_system(); const char* objPath /xyz/openbmc_project/example/demo; const char* intf xyz.openbmc_project.Example.Demo; // 核心通过 ObjectMapper 获取服务名 std::string service getServiceName(bus, objPath); std::cout ✅ 发现服务: service \n\n; // 1. 调用 SayHello auto msg bus.new_method_call(service.c_str(), objPath, intf, SayHello); msg.append(OpenBMC User); auto reply bus.call(msg); std::string res; reply.read(res); std::cout SayHello 结果: res \n; // 2. 调用 Add auto msg2 bus.new_method_call(service.c_str(), objPath, intf, Add); msg2.append(int64_t(10), int64_t(20)); auto reply2 bus.call(msg2); int64_t sum; reply2.read(sum); std::cout Add(10,20) 结果: sum \n; // 3. 设置 Status 属性 auto msg3 bus.new_method_call( service.c_str(), objPath, org.freedesktop.DBus.Properties, Set); msg3.append(intf, Status, std::variantbool(true)); bus.call(msg3); std::cout \n✅ 已设置 Status true\n; // 4. 读取 Status 属性 auto msg4 bus.new_method_call( service.c_str(), objPath, org.freedesktop.DBus.Properties, Get); msg4.append(intf, Status); auto reply4 bus.call(msg4); std::variantbool statusVal; reply4.read(statusVal); std::cout ✅ 当前 Status: std::getbool(statusVal) \n; } catch (const std::exception e) { std::cerr \n❌ 错误: e.what() \n; return 1; } return 0; }4. 编译脚本meson.buildproject(dbus-demo, cpp, version: 1.0, default_library: static) # 依赖 sdbusplus dependency(sdbusplus) phosphor_dbus_interfaces dependency(phosphor-dbus-interfaces) # 生成 D-Bus 代码 sdbuspp find_program(sdbus) generated custom_target( demo_interface, input: interfaces/xyz/openbmc_project/Example/Demo.interface.yaml, output: [server.hpp, client.hpp], command: [ sdbuspp, server, --output-dir, OUTDIR, --input, INPUT ], ) # 包含路径 inc_dir include_directories(., meson.current_build_dir()) # 编译服务端 demo_server executable(demo-server, src/server.cpp, generated, dependencies: [sdbusplus, phosphor_dbus_interfaces], include_directories: inc_dir, install: true, ) # 编译客户端 demo_client executable(demo-client, src/client.cpp, generated, dependencies: [sdbusplus, phosphor_dbus_interfaces], include_directories: inc_dir, install: true, )5. README.md# OpenBMC D-Bus Demo 编译运行 1. 编译 meson build ninja -C build 2. 运行服务端(新终端) ./build/demo-server 3. 运行客户端(新终端) ./build/demo-client 4. 命令行测试 busctl introspect xyz.openbmc_project.Example.Demo /xyz/openbmc_project/example/demo命令行调试# 查看服务 busctl list | grep Example # 查看对象所有方法/属性/信号 busctl introspect xyz.openbmc_project.Example.Demo /xyz/openbmc_project/example/demo # 调用方法 busctl call xyz.openbmc_project.Example.Demo /xyz/openbmc_project/example/demo xyz.openbmc_project.Example.Demo SayHello s 张三 # 读取属性 busctl get-property xyz.openbmc_project.Example.Demo /xyz/openbmc_project/example/demo xyz.openbmc_project.Example.Demo Status # 设置属性 busctl set-property xyz.openbmc_project.Example.Demo /xyz/openbmc_project/example/demo xyz.openbmc_project.Example.Demo Status b true # 监控信号 busctl monitor xyz.openbmc_project.Example.Demo

更多文章