文档说明
适用范围
本文档适用于需要将 OpenBMC 资产迁移到 openUBMC 框架的开发人员和技术团队,包括:
- 软件特性迁移:迁移 OpenBMC 的软件组件(如日志管理、状态管理等)
- 北向接口迁移:迁移 RESTful API、Redfish、IPMI 等北向接口
- 南向设备驱动迁移:迁移硬件设备驱动(如网卡、电源等)
文档目标
- 提供完整的迁移流程指导
- 说明不同迁移类型的技术路径和适配要求
- 提供常见问题解决方案
- 帮助开发者高效完成资产迁移
反馈渠道
如有问题或建议,请通过以下方式反馈:
- openUBMC社区论坛
1. 概述
1.1 为什么迁移?
迁移背景:多家伙伴存在 OpenBMC 的历史资产,为了应对快速迁移、低成本应用迁移的需求,我们提供了 OpenBMC 资产迁移的一整套解决方案。
解决方案:
- 构建系统迁移:采用 Conan2 作为包管理器,提供可预测的依赖管理、二进制包高效分发和跨平台构建支持
- 运行时兼容:通过
dbus-proxy实现 OpenBMC D-Bus 接口映射,OpenBMC 组件代码基本无需修改即可运行 - 预置核心框架:已预先提供了 OpenBMC 核心框架的 Conan 包(如
stdplus、sdbusplus等) - 基于 openUBMC 的适配层:对于 OpenBMC 和 openUBMC 都具备的功能,我们借助 dbus-proxy 代理层,实现将原本依赖 OpenBMC 组件的能力,无缝切换为 openUBMC 现有组件的能力,减少适配工作量,提升迁移效率
- 配置化的北向接口框架:对于北向接口的迁移,使用openUBMC的映射器和IPMI规范,能够做到配置化适配北向特性。
- 南向设备标准化框架 : 对于硬件侧设备,openUBMC提供了完整的南向标准,适用与应用层与驱动层的解耦。使用该标准进行硬件迁移,将低成本地完成硬件与openUBMC应用层的适配。
1.2 迁移类型概览
OpenBMC 资产迁移包含三种类型:
1. OpenBMC 软件特性迁移
- 适用场景:迁移 OpenBMC 的软件组件(如日志管理、状态管理、POST Code 管理等)
- 技术特点:使用 BiSheng 编译器和 Conan2 构建系统
- 迁移成本:极低,无需修改业务代码
- 参考章节:第2章
2. 北向接口迁移
- 适用场景:迁移 RESTful API、Redfish、IPMI 等北向接口
- 技术特点:满足 openUBMC 接口规范,无需 Conan 化,直接适配 openUBMC 框架
- 迁移成本:极低,需要接口适配
- 参考章节:第3章
3. 南向设备驱动迁移
- 适用场景:迁移硬件设备驱动(如网卡、电源等)
- 技术特点:满足 openUBMC 驱动框架规范,无需 Conan 化,直接适配 openUBMC 框架
- 迁移成本:中等,需要驱动适配
- 参考章节:第4章
1.3 迁移路径选择
根据您的迁移需求,选择合适的迁移路径:
迁移路径说明:
- 软件特性迁移:适用于 OpenBMC 软件组件,使用 BiSheng 编译器和 Conan2,迁移成本最低
- 北向接口迁移:适用于 RESTful API、Redfish、IPMI 等接口,需要适配 openUBMC 接口规范
- 南向设备驱动迁移:适用于硬件设备驱动,需要适配 openUBMC 驱动框架规范
2. OpenBMC 软件特性迁移
OpenBMC 软件特性迁移适用于迁移 OpenBMC 的软件组件(如日志管理、状态管理等),采用 BiSheng 编译器和 Conan2 构建系统,迁移成本极低。
迁移路径选择:
在开始迁移前,请根据以下情况选择合适的迁移路径:
直接迁移(推荐):如果您的组件是相对独立的顶层应用(如日志管理、状态管理等),且您熟悉该组件的设计和依赖关系,可以直接按照本章节的步骤进行迁移,通常无需进行深入的代码分析。
先分析后迁移:在以下情况下,建议先参考 附录A:代码分析章节进行依赖关系分析,制定迁移计划后再按照本章节进行迁移:
- 您对迁移的 OpenBMC 组件不够了解,或并非该组件的设计开发者
- 您的组件与 OpenBMC 中大多数组件之间都存在复杂的依赖关系
- 需要迁移多个相互依赖的组件或整个子系统
2.1 环境准备
环境准备确保开发环境、依赖库和构建工具的正确配置,为后续构建提供基础。
2.1.1 开发环境搭建
开发环境搭建:参考 openUBMC 社区文档,无需额外配置。
2.1.2 依赖库安装
依赖库安装:
- BiSheng编译器:需要开发者单独申请,并解压至
/opt目录下 - profile文件配置:用于添加新编译器的路径,模板如下:
{% set target_host = "aarch64-linux-gnu" %}
{% set standalone_toolchain = "/opt/BiSheng_arm64le" %}
{% set sysroot = "/opt/RTOS/208.10.0/arm64le_5.10_ek_preempt_pro/sdk" %}
{% set sdkroot = "/opt/hi1711sdk" %}
{% set cc_compiler = "clang" %}
{% set cxx_compiler = "clang++" %}
[settings]
os=Linux
arch=armv8
build_type=Release
compiler=clang
compiler.version=15
compiler.cppstd=20
compiler.runtime=dynamic
compiler.runtime_type=Release
compiler.runtime_version=v144
[buildenv]
PATH=+(path){{ standalone_toolchain }}/bin
KERNEL_PATH={{ sysroot }}/usr/src/kernel/
CONAN_CMAKE_SYSROOT={{ sysroot }}
CONAN_CMAKE_FIND_SDK_ROOT={{ sdkroot }}
CHOST={{ target_host }}
AR=llvm-ar
AS=as
LD=ld.lld
STRIP=llvm-strip
CC={{ cc_compiler }}
HOSTCC={{ cc_compiler }}
CXX={{ cxx_compiler }}
PKG_CONFIG_PATH={{ sysroot }}/lib64/pkgconfig:{{ sysroot }}/usr/lib64/pkgconfig
PKG_CONFIG=/usr/share/bingo/pkg_config.sh
SYS_ROOT = {{standalone_toolchain}}/sysroot
CFLAGS=-Wall -fPIC -fstack-protector-all -Os -fPIE -fno-common -std=gnu11
CXXFLAGS=-I{{ standalone_toolchain }}/{{ target_host }}/include/c++/v1 -I{{sysroot}}/usr/include -nostdinc++ -Wno-error -Wno-c99-extensions
LDFLAGS=-L{{standalone_toolchain}}/sysroot/lib64 -L{{sysroot}}/lib64
[conf]
tools.build:sysroot={{sysroot}}
tools.gnu:host_triplet={{target_host}}注意:请确认 standalone_toolchain 路径与实际 BiSheng 编译器安装路径一致。
2.1.3 构建工具配置
构建工具配置:构建工具是 bingo,执行 init.py 后自动安装最新版本。由于目前该技术项目还在开发调试中,bingo 主仓还不支持资产迁移能力,因此您还需要拉取代码https://gitcode.com/openUBMC/bingo.git,执行 sh install_local.sh,重新安装该调试版本 bingo。
2.2 构建迁移适配
openUBMC 采用 Conan2 作为核心 C/C++ 包管理器,实现可预测的依赖管理、二进制包高效分发和跨平台构建支持。我们已预先提供了 OpenBMC 核心框架的 Conan 包,您只需声明依赖即可快速构建。
2.2.1 构建框架介绍
双编译器策略:OpenBMC 组件使用 Bisheng LLVM 编译(支持 C++20),openUBMC 组件使用 GCC 7.3 编译。采用**"独立构建,Conan 包管理,统一集成"**策略:
+-----------------------+ +-----------------------+
| OpenBMC 组件 | | openUBMC 组件 |
| (源代码) | | (源代码) |
+-----------------------+ +-----------------------+
| Bisheng LLVM 编译 | GCC 7.3 编译
v v
+-----------------------+ +-----------------------+
| OpenBMC Conan 包 | | openUBMC Conan 包 |
| (Bisheng LLVM 编译版本) | | (GCC 7.3 编译版本) |
+-----------------------+ +-----------------------+
|
| 产品集成阶段 (Conan 包管理器)
v
+-------------------------------------------------------------+
| manifest/manifest.yaml (声明所需 OpenBMC & openUBMC Conan 组件) |
+-------------------------------------------------------------+
|
| Conan 包管理器解析依赖并解决冲突
| (若组件在 openUBMC 中已存在,则以 GCC 7.3 编译版本为主)
v
+-------------------------------------------------------------+
| 统一的 Conan 缓存 |
| (包含所有兼容的 OpenBMC & openUBMC 组件二进制包) |
+-------------------------------------------------------------+
|
v
+-------------------------------------------------------------+
| 最终产品包 (hpm) |
| (openUBMC + OpenBMC 组件) |
+-------------------------------------------------------------+2.2.2 Conan 依赖管理
2.2.2.1 Conan 组件构建策略
使用 conan_index:我们推荐使用 conan_index(https://gitcode.com/openUBMC/conan_index)作为引入开源/自定义组件的标准途径,确保依赖的透明性、可控性与合规性。
目录结构:
.
└── repo
└── recipes2
└── component_name
├── all
│ ├── patches # 存储特定版本的代码补丁
│ │ ├── 0001-1.0.0-adapting-conan-build.patch
│ ├── rootfs # 运行时配置文件目录(推荐)
│ │ ├── etc
│ │ │ └── dbus-1
│ │ │ └── system.d # D-Bus 策略文件
│ │ └── usr
│ │ └── lib
│ │ └── systemd
│ │ └── system # systemd 服务文件
│ ├── conandata.yml
│ ├── conanfile.py
└── config.yml文件作用:
config.yml:定义组件基线版本,确保版本一致性conandata.yml:承载组件元数据(源码下载链接、分支/提交、补丁、依赖配置)conanfile.py:定义组件构建工程和包的创建逻辑rootfs/:运行时配置文件目录,用于组织 systemd 服务文件、D-Bus 策略文件等运行时配置(推荐使用此目录结构)
2.2.2.2 config.yml 编写规范
versions:
"1.0.0": # 声明组件的特定版本
folder: "all" # 指示该版本对应的Conan recipe文件所在的目录2.2.2.3 conandata.yml 编写规范
sources: # 注意:使用 sources(复数)而非 source
"1.0.0": # 对应于config.yml中定义的组件版本
url: "https://gitcode.com/xxxx/xxxx.git" # 组件源码的Git仓库地址
branch: "main" # 指定Git分支,推荐使用稳定的分支或标签
shallow: true # 可选:浅克隆,加快下载速度
# commit: "abcdef1234567890abcdef1234567890abcdef12" # 或者,更精确地指定commit哈希
patches:
"1.0.0": # 补丁应用于哪个版本
- patch_file: "patches/0001-1.0.0-adapting-conan-build.patch" # 补丁文件的相对路径
requires:
"1.0.0": # 该版本组件的运行时/构建时依赖
- xxxx/1.0.0@openubmc.dev/dev # 依赖的其他Conan包及其版本
- yyyy/[>=1.0.0] # 支持版本范围声明
- .... # 可以列出多个依赖项2.2.2.4 conanfile.py 编写规范
对于基于 Meson 构建系统的 OpenBMC 组件,以下是 conanfile.py 模板:
import os
from conan import ConanFile
from conan.tools.meson import Meson, MesonToolchain
from conan.tools.files import copy, files
from conan.tools.layout import basic_layout
from conan.tools.scm import Git
required_conan_version = ">=2.13.0"
class ComponentConan(ConanFile):
name = "component_name" # 组件名称,与conan_index中的目录名一致
version = "1.0.0" # 组件版本,与config.yml和conandata.yml中的版本一致
# 项目描述信息
license = "GPL-2.0-or-later"
author = "Your Name <your.email@example.com>"
url = "https://gitcode.com/openUBMC/conan_index"
description = "A brief description of your OpenBMC component."
topics = ("openbmc", "conan", "meson")
# 构建和包类型相关设置
settings = "os", "compiler", "build_type", "arch"
options = {"shared": [True, False], "fPIC": [True, False]}
default_options = {"shared": False, "fPIC": True}
generators = "PkgConfigDeps", "VirtualBuildEnv"
def layout(self):
# 定义源文件和构建输出的布局
basic_layout(self)
# 自定义包目录结构(可选)
self.cpp.package.resdirs = ["usr/share"]
self.cpp.package.bindirs = ["usr/bin"]
def requirements(self):
# 依赖项 (运行时和构建时)
requires = self.conan_data.get("requires", {}).get(self.version, [])
for req in requires:
self.requires(req)
def build_requirements(self):
# 构建时工具依赖
self.tool_requires('pkgconf/2.0.3')
def export_sources(self):
# 导出源代码和配置文件
files.export_conandata_patches(self)
# 导出 rootfs 目录(包含运行时配置文件)
files.copy(self, "rootfs/*", self.recipe_folder, self.export_sources_folder)
# 导出其他配置文件(如果有)
# files.copy(self, "config.json", self.recipe_folder, self.export_sources_folder)
def source(self):
# 获取组件的源代码
git = Git(self)
git.fetch_commit(
url=self.conan_data["sources"][self.version]["url"],
commit=self.conan_data["sources"][self.version]["branch"])
def generate(self):
# 生成Meson所需的构建工具链文件
tc = MesonToolchain(self)
# 可以添加额外的编译标志(如果需要)
# cxxflag = ["-I/path/to/include"]
# tc.extra_cxxflags.extend(cxxflag)
tc.generate()
def build(self):
# 应用补丁
files.apply_conandata_patches(self)
# 执行Meson构建命令
meson = Meson(self)
meson.configure()
meson.build()
meson.install()
def package(self):
# 将构建好的文件打包到Conan包中
# Meson install 已经执行,这里主要处理 rootfs 目录
# 复制 rootfs 目录内容到 package_folder,覆盖 meson 安装的文件
files.copy(self, "*",
os.path.join(self.export_sources_folder, "rootfs"),
self.package_folder)
# 如果有其他配置文件需要覆盖,可以在这里处理
# config_dst_dir = os.path.join(self.package_folder, "usr/share/component_name")
# os.makedirs(config_dst_dir, exist_ok=True)
# files.copy(self, "config.json",
# src=self.export_sources_folder,
# dst=config_dst_dir)
def package_info(self):
# 定义包的消费者信息,例如库名、链接标志等
self.cpp_info.libs = ["component_name"] # 如果生成了库文件
self.cpp_info.include_dirs = ["include"]
self.cpp_info.set_property("cmake_find_mode", "both")
self.cpp_info.set_property("pkg_config_name", "component_name")关键方法说明:
layout():定义源文件和构建输出的布局,可自定义包目录结构requirements():声明组件的直接依赖项build_requirements():声明构建时工具依赖(如 pkgconf)export_sources():导出源代码和配置文件(包括rootfs目录)source():获取源代码(使用 Git 工具从conandata.yml配置的仓库获取)generate():生成 Meson 构建工具链文件build():应用补丁并执行 Meson 构建package():打包构建产物,将rootfs目录内容复制到包目录package_info():定义包的消费者信息
2.2.2.5 运行时依赖管理
推荐使用 rootfs 目录组织运行时配置文件:在 conan_index 的组件目录下创建 rootfs 目录,按照目标系统的目录结构组织运行时配置文件:
all/
├── rootfs/
│ ├── etc/
│ │ └── dbus-1/
│ │ └── system.d/ # D-Bus 策略文件目录
│ │ └── service_name.conf
│ └── usr/
│ └── lib/
│ └── systemd/
│ └── system/ # systemd 服务文件目录
│ ├── service_name.service
│ └── multi-user.target.wants/ # 服务自启动软链接目录
│ └── service_name.service -> ../service_name.service
├── conandata.yml
└── conanfile.py配置步骤:
创建
rootfs目录结构:按照目标系统的目录结构创建rootfs目录,将 D-Bus 策略文件和 systemd 服务文件放置到对应位置。在
conanfile.py中导出和打包:- 在
export_sources()方法中导出rootfs目录 - 在
package()方法中将rootfs目录内容复制到package_folder
- 在
D-Bus Policy 配置:将 D-Bus 策略文件(
.conf)放置在rootfs/etc/dbus-1/system.d/目录下。详细编写规范请参阅第2.3.2节。Systemd 服务自启动:将 systemd 服务文件(
.service)放置在rootfs/usr/lib/systemd/system/目录下,并在rootfs/usr/lib/systemd/system/multi-user.target.wants/目录下创建指向服务文件的软链接。详细配置请参阅第2.3.1节。
优势:使用 rootfs 目录结构可以清晰地组织运行时配置文件,便于管理和维护,同时与目标系统的目录结构保持一致。
2.2.2.6 组件构建注意事项
- 明确依赖关系:在
conanfile.py中精确声明所有直接和间接的 Conan 依赖,避免循环依赖 - Meson 配置适配:确保 Meson 项目的
meson.build文件能够正确接收来自 Conan 的配置 - 代码补丁管理:尽量保持对上游代码的修改最小化,补丁文件与组件版本严格对应
- 编译器和 C++ 标准兼容性:确保组件代码在 Bisheng LLVM 和 GCC 7.3 下都能正确编译
2.2.2.7 组件构建与打包命令
在 conan_index 目录下,执行以下命令进行组件的构建:
cd conan_index
bingo build -cp component_name/1.0.0@openubmc.dev/dev --conan2 -pr profile.llvm.ini命令参数说明:
-cp component_name/1.0.0@openubmc.dev/dev:Conan 包的完整引用(name/version@user/channel)--conan2:指定使用 Conan 2.x 版本-pr profile.llvm.ini:指定 Bisheng LLVM 编译器的配置文件
成功执行后,bingo build 会在 Conan 本地缓存中创建并存储对应的二进制包。
2.2.2.8 Conan 产品构建:集成 OpenBMC 组件到 openUBMC 产品包
产品构建核心:manifest.yml 文件定义了构成最终产品的所有组件、版本和构建选项。
配置步骤:
产品仓拉取:拉取产品仓 https://gitcode.com/openUBMC/manifest,定位到
build/product/BMC/openUBMC/manifest.yml文件添加
expand_product配置:
expand_product:
product_name: openbmc
profile: profile.llvm.ini
dependencies:
- conan: stdplus/1.0.0@openubmc/stable
- conan: component_name/1.0.0@openubmc/dev配置说明:
product_name:需要注入资产的源产品名称profile:构建该产品组件使用的 profile 文件(需确认~/.conan2/profiles目录下存在该文件)dependencies:OpenBMC 组件的 Conan 依赖列表,支持name、name/version或name/version@user/channel格式
完成配置后,openUBMC 产品构建系统将能够识别、获取并集成所需的 OpenBMC 组件,最终生成包含所有兼容组件的完整产品包。
2.3 服务迁移
2.3.1 systemd 服务文件迁移
systemd 服务文件定义了组件的启动方式、依赖关系和运行环境。
2.3.1.1 服务文件结构
标准 systemd 服务文件包含三个主要部分:
[Unit]
Description=服务描述
After=依赖的服务
[Service]
Environment=环境变量
ExecStart=启动命令
SyslogIdentifier=日志标识
Type=服务类型
BusName=D-Bus服务名(如为D-Bus服务)
[Install]
WantedBy=目标单元示例:以 phosphor-post-code-manager 的服务文件为例:
[Unit]
Description=Post code manager
After=dbus.service
[Service]
Environment=LD_LIBRARY_PATH=/lib
ExecStart=/bin/post-code-manager --host 0 --config /usr/share/phosphor-post-code-manager/post-code-handlers.json
SyslogIdentifier=post-code-manager
Type=dbus
BusName=xyz.openbmc_project.State.Boot.PostCode0
[Install]
WantedBy=multi-user.target2.3.1.2 服务自启动配置
在 conan_index 配置中,推荐使用 rootfs 目录结构来组织服务配置和自启动描述:
目录结构:
all/
├── rootfs/
│ └── usr/
│ └── lib/
│ └── systemd/
│ └── system/
│ ├── service_name.service # systemd 服务文件
│ └── multi-user.target.wants/ # 自启动软链接目录
│ └── service_name.service -> ../service_name.service
├── conandata.yml
└── conanfile.py配置说明:
- 将 systemd 服务文件放置在
rootfs/usr/lib/systemd/system/目录下 - 在
rootfs/usr/lib/systemd/system/multi-user.target.wants/目录下创建指向服务文件的软链接,实现服务自启动 - 在
conanfile.py的export_sources()和package()方法中处理rootfs目录(参考第2.2.2.4节)
2.3.1.3 服务依赖关系配置
推荐直接在服务文件的 [Unit] 段中显式声明依赖关系,这样更加直接和可控:
[Unit]
After=dbus.service
Requires=dbus.service2.3.2 D-Bus 服务配置迁移
D-Bus 策略文件定义了 D-Bus 服务的访问权限。在迁移到 Conan2 构建系统后,需要手动编写 D-Bus 策略配置文件。
2.3.2.1 D-Bus 策略文件结构
D-Bus 策略文件采用 XML 格式,文件通常命名为 <服务名>.conf,安装到 /etc/dbus-1/system.d/ 目录。
示例:以 phosphor-post-code-manager 的 D-Bus 策略文件为例:
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<!-- Allow root user to own the service -->
<policy user="root">
<allow own="xyz.openbmc_project.State.Boot.PostCode0"/>
<allow send_destination="xyz.openbmc_project.State.Boot.PostCode0"/>
<allow receive_sender="xyz.openbmc_project.State.Boot.PostCode0"/>
</policy>
<!-- Allow regular users to access the service -->
<policy user="*">
<allow send_destination="xyz.openbmc_project.State.Boot.PostCode0"/>
<allow receive_sender="xyz.openbmc_project.State.Boot.PostCode0"/>
<allow send_destination="xyz.openbmc_project.State.Boot.PostCode0"
send_interface="xyz.openbmc_project.State.Boot.PostCode"/>
<allow receive_sender="xyz.openbmc_project.State.Boot.PostCode0"
receive_interface="xyz.openbmc_project.State.Boot.PostCode"/>
</policy>
<!-- Allow other users/processes to send messages to the service -->
<policy context="default">
<allow send_destination="xyz.openbmc_project.State.Boot.PostCode0"
send_interface="xyz.openbmc_project.State.Boot.PostCode"/>
<allow receive_sender="xyz.openbmc_project.State.Boot.PostCode0"
receive_interface="xyz.openbmc_project.State.Boot.PostCode"/>
</policy>
</busconfig>2.3.2.2 策略文件配置要点
- 服务名注册权限:
<allow own="服务名"/>允许指定用户注册该 D-Bus 服务名 - 接口访问权限:
<allow send_destination="服务名" send_interface="接口名"/>:允许向指定服务的指定接口发送消息<allow receive_sender="服务名" receive_interface="接口名"/>:允许接收来自指定服务的指定接口的消息
- 权限策略类型:
<policy user="root">:针对 root 用户的策略<policy user="*">:针对所有用户的策略<policy context="default">:默认策略
- 配置原则:最小权限原则,明确接口,服务名一致性
2.3.2.3 策略文件安装配置
推荐方式:使用 rootfs 目录
在 conan_index 配置中,推荐将 D-Bus 策略文件放置在 rootfs 目录下:
目录结构:
all/
├── rootfs/
│ └── etc/
│ └── dbus-1/
│ └── system.d/
│ └── service_name.conf # D-Bus 策略文件
├── conandata.yml
└── conanfile.py在 conanfile.py 的 export_sources() 和 package() 方法中处理 rootfs 目录(参考第2.2.2.4节),策略文件会自动被打包到 Conan 包的 /etc/dbus-1/system.d/ 目录。
传统方式:在 meson.build 中安装
如果组件使用 Meson 构建系统,也可以在 meson.build 中安装 D-Bus 策略文件:
# Install D-Bus policy file
install_data(
'xyz.openbmc_project.State.Boot.PostCode.conf',
install_dir: '/etc/dbus-1/system.d')注意:如果同时使用两种方式,rootfs 目录中的文件会在 package() 方法中覆盖 Meson 安装的文件。
3. 北向接口迁移
北向接口迁移适用于迁移 RESTful API、Redfish 等北向接口,需要满足 openUBMC 接口规范。
北向接口迁移与其他组件迁移有显著差异:它不涉及底层业务代码的迁移,而是配置层面的转换。OpenBMC 的北向接口实现(如 bmcweb)采用代码驱动架构,而 openUBMC(rackmount)采用配置驱动架构。
3.1 架构差异
| 维度 | OpenBMC (bmcweb) | openUBMC (rackmount) |
|---|---|---|
| 实现方式 | C++ 硬编码 | JSON 配置 |
| D-Bus 交互 | sdbusplus 库调用 | ProcessingFlow 配置 |
| 响应构造 | 代码构建 JSON | RspBody 模板 |
| 扩展方式 | 修改代码重新编译 | 添加配置文件 |
示例对比:
// OpenBMC: C++ 代码
dbus::utility::getProperty<std::string>(
"xyz.openbmc_project.State.BMC", "/xyz/openbmc_project/state/bmc0",
"xyz.openbmc_project.State.BMC", "CurrentBMCState",
[asyncResp](const auto& ec, const std::string& state) {
asyncResp->res.jsonValue["Status"]["State"] = state;
});// openUBMC: JSON 配置
{
"RspBody": {
"Status": {
"State": "${ProcessingFlow[1]/Destination/State}"
}
},
"ProcessingFlow": [{
"Type": "Property",
"Path": "/xyz/openbmc_project/state/bmc0",
"Interface": "xyz.openbmc_project.State.BMC",
"Destination": {"State": "CurrentBMCState"}
}]
}3.2 配置文件结构
openUBMC 的 Redfish 配置目录(rackmount 项目):
interface_config/redfish/mapping_config/
├── v1.json # 服务根配置
├── Managers/ # Manager 资源
├── Systems/ # System 资源
├── Chassis/ # Chassis 资源
└── AccountService/ # 账户服务全局配置:oem/huawei/redfish/config.json
3.3 GET 请求配置
3.3.1 基本结构
{
"Resources": [{
"Uri": "/redfish/v1/Managers/:managerid",
"Interfaces": [{
"Type": "GET",
"RspBody": {
"@odata.id": "/redfish/v1/Managers/${Uri/managerid}",
"Id": "${Uri/managerid}",
"Name": "Manager",
"FirmwareVersion": "${ProcessingFlow[1]/Destination/Version}"
},
"ProcessingFlow": [{
"Type": "Property",
"Path": "/xyz/openbmc_project/software/bmc",
"Interface": "xyz.openbmc_project.Software.Version",
"Destination": {
"Version": "Version"
}
}]
}]
}]
}3.3.2 ProcessingFlow 配置
属性读取:
{
"ProcessingFlow": [{
"Type": "Property",
"Path": "/xyz/openbmc_project/state/bmc0",
"Interface": "xyz.openbmc_project.State.BMC",
"Destination": {
"CurrentBMCState": "State",
"LastRebootTime": "ResetTime"
}
}]
}在 RspBody 中引用:${ProcessingFlow[1]/Destination/State}
关键字段说明:
Path: OpenBMC D-Bus 对象路径Interface: OpenBMC D-Bus 接口名Destination: D-Bus 属性到响应字段的映射ProcessingFlow[n]: 数组索引从 1 开始
3.4 PATCH 请求配置
{
"Interfaces": [{
"Type": "PATCH",
"ReqBody": {
"Type": "object",
"Properties": {
"DateTime": {
"Type": "string",
"Validator": [{
"Type": "Regex",
"Formula": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T.*"
}]
}
}
},
"ProcessingFlow": [{
"Type": "Property",
"Path": "/xyz/openbmc_project/timedate1",
"Interface": "xyz.openbmc_project.timedate1",
"Source": {
"Timezone": "${ReqBody/DateTimeLocalOffset}"
},
"CallIf": {
"${ReqBody/DateTimeLocalOffset}": "#WITH"
}
}]
}]
}关键字段说明:
ReqBody: 请求体验证配置Source: 请求体字段到 D-Bus 属性的映射CallIf: 条件执行(仅当字段存在时执行)
3.5 配置部署
- 配置路径:
/opt/bmc/apps/redfish/interface_config/ - 权限设置:参考 rackmount/permissions.ini
- 验证工具:
mapper_check.py <config_file>
3.6 注意事项
- URI 参数:使用
:name语法定义参数(如:managerid) - 变量引用:
${Uri/xxx}:URI 参数${ProcessingFlow[n]/Destination/xxx}:D-Bus 返回值${ReqBody/xxx}:请求体字段
- D-Bus 路径:直接使用 OpenBMC 的 D-Bus 路径
- 数组索引:
ProcessingFlow索引从 1 开始
3.7 参考文档
4. 南向设备驱动迁移
南向设备驱动迁移适用于迁移硬件设备驱动(如传感器、风扇、电源、FRU 等),需要满足 openUBMC 驱动框架规范,无需 Conan 化,直接适配 openUBMC 框架。
在OpenBMC中,南向硬件都是由各个组件自己维护,并且是直接使用/dev下的字符设备进行操作。而openUBMC提供了一套完整的设备访问框架,统一由Component_driver组件来管理和各个南向硬件的交互,北向应用只需匹配接口即可。因此我们推荐OpenBMC中的南向设备访问的迁移采用openUBMC驱动框架进行改写。
4.1 迁移概述
4.1.1 什么是南向设备驱动
南向设备驱动是指 BMC 向下层硬件设备提供的驱动接口,主要包括:
- 传感器驱动:温度、电压、电流等传感器(如 LM75、ADS78)
- 风扇驱动:风扇控制与监控
- 电源驱动:电源管理与控制
- FRU 驱动:现场可更换单元管理
- GPIO 驱动:通用输入输出接口(如 PCA9555)
- I2C/SPI 驱动:总线设备驱动(如 I2C、I2C Mux)
4.1.2 迁移目标与原则
迁移目标:
- 将 OpenBMC 的设备驱动适配到 openUBMC 驱动框架
- 满足 openUBMC 驱动框架规范要求
- 保持驱动功能兼容性
迁移原则:
- 框架规范优先:遵循 openUBMC 驱动框架规范
- 功能兼容:保持原有驱动功能不变
- 硬件抽象:通过硬件抽象层实现硬件无关性
4.2 环境准备
4.2.1 openUBMC 开发环境
开发环境搭建:参考 openUBMC 社区文档。
4.2.2 驱动框架核心组件
openUBMC 驱动框架由以下三个核心仓库组成:
- libmcpp:基础库,提供反射、日志、异常处理等功能,详见 libmcpp 仓库
- component_drivers:设备驱动实现库,包含芯片驱动、总线驱动等,详见 component_drivers 仓库
- devmon:设备监控和管理系统,负责驱动加载、设备发现和拓扑管理,详见 devmon 仓库
4.2.3 驱动框架规范
驱动 ABI 接口规范:所有驱动必须实现 driver_abi.h 定义的接口,包括:
- 驱动注册函数:
register_device_driver() - 生命周期函数:
ctor(创建)、init(初始化)、start(启动)、stop(停止) - 调试函数:
dump(可选)
详细接口定义请参考:component_drivers/include/devmon/driver_abi.h
4.3 驱动适配
4.3.1 openUBMC 驱动框架架构
openUBMC 驱动框架采用插件化架构,驱动以动态库形式加载:
┌─────────────────────────────────────┐
│ devmon (设备管理服务) │
│ - 驱动加载与生命周期管理 │
│ - 设备发现与拓扑管理 │
│ - D-Bus 接口暴露 │
└──────────────┬──────────────────────┘
│ 加载驱动库
┌──────────────▼──────────────────────┐
│ component_drivers (驱动实现库) │
│ - 芯片驱动 (chip/) │
│ - 总线驱动 (bus/) │
│ - 设备驱动 (accessor/) │
└──────────────┬──────────────────────┘
│ 使用基础库
┌──────────────▼──────────────────────┐
│ libmcpp (基础库) │
│ - 反射系统 │
│ - 日志系统 │
│ - 异常处理 │
└─────────────────────────────────────┘详细架构设计请参考:devmon 架构文档
4.3.2 驱动实现步骤
步骤 1:实现驱动 ABI 接口
每个驱动需要实现以下 C 接口函数:
driver_handle_t ctor(void* service, const char* object_name):创建驱动实例status_t init(driver_handle_t, void* csr_object, void* connector):初始化驱动status_t start(driver_handle_t):启动驱动status_t stop(driver_handle_t):停止驱动status_t register_device_driver(device_driver_t**, uint8_t*):注册驱动
步骤 2:实现设备对象类
基于 mc::engine::service 框架实现设备对象,使用反射机制定义设备属性。
步骤 3:配置构建系统
在 meson.build 中配置驱动库的构建规则,确保生成动态库。
参考实现示例:LM75 温度传感器驱动
4.3.3 设备发现与拓扑管理
设备发现机制:
- devmon 通过扫描驱动库目录(
/opt/bmc/apps/devmon/drvlib/)自动发现可用驱动 - 根据设备树(Device Tree)配置匹配驱动与硬件设备
- 支持动态加载和卸载驱动
拓扑管理:
- devmon 维护设备拓扑树,管理设备间的层次关系
- 支持设备属性的 D-Bus 访问
- 提供设备状态监控和事件通知
详细机制请参考:devmon 设备管理文档
4.4 测试验证
4.4.1 功能测试
- 驱动 ABI 测试:验证驱动接口的正确实现,参考 component_drivers 测试用例
- 设备操作测试:验证设备属性的读写功能
- 错误处理测试:验证异常场景的处理
4.4.2 集成测试
- 与 devmon 集成测试:验证驱动在 devmon 框架下的加载和运行
- D-Bus 接口测试:验证设备属性的 D-Bus 访问
- 硬件兼容性测试:在实际硬件上验证驱动功能
5. 常见问题与故障排除
本章节汇总了三种迁移类型中可能遇到的常见问题及解决方案,按迁移类型分类组织,便于快速查找和解决。
5.1 构建问题
编译错误:
- 头文件找不到:检查
meson.build内容是否存在绝对路径、pkg-config 指定错误等问题 - C++ 类型检查编译错误:推荐使用 clang15 版本进行本地编译调试,clang 在类型检查上通常更加严格
- C++20 以上的特性编译错误:BiSheng LLVM 仅支持 C++20 的特性,对于高版本特性需要进行 C++ 降版本
- 构建依赖库版本不对应: 由于openUBMC中的运行使用了一些三方库,比如boost等。这些三方库的版本是比较固定的,如果在组件编译过程中出现了头文件不匹配、找不到某个定义。可以排查一下是否由于三方库版本不匹配导致的。通过执行
conan search xxx -r openubmc_dev查看openubmc中使用的三方库版本。
链接错误:
- 最可能出现的链接问题就是
conan_index中未声明 pkg-config 的路径。使用require或者添加 pkg-config 的 path 路径。
5.2 运行时问题
服务启动失败:
- 服务未自启动:检查是否配置了
multi-user.target.wants。如果已经配置,尝试手动执行服务配置中的启动命令,如果可以启动,那么最大的可能就是启动顺序问题,检查服务配置中是否配置了After=dbus.service - 手动拉起服务也失败:通常是由于服务中出现 core dump 之类的错误导致程序退出,通过
journalctl -xeu xxx(service的名称)来查看错误日志
D-Bus 问题:
- 服务注册失败:
- 检查 D-Bus 策略文件中是否配置了服务名注册权限(
<allow own="服务名"/>) - 确认策略文件已正确安装到
/etc/dbus-1/system.d/目录 - 验证服务运行的用户身份
- 检查是否有其他服务已占用相同的服务名
- 检查 D-Bus 策略文件中是否配置了服务名注册权限(
- 接口调用失败:
- 检查 D-Bus 策略文件中是否配置了接口访问权限
- 确认接口名称拼写正确
- 验证服务端是否已正确导出接口
- 权限拒绝:
- 审查 D-Bus 策略文件的权限配置,确保遵循最小权限原则
- 确认策略文件中的权限范围足够
- 验证策略文件的语法正确性
5.3 缺少 OpenBMC D-Bus 资源
5.3.1 问题现象
在迁移 OpenBMC 组件到 openUBMC 系统时,可能会遇到以下 D-Bus 资源缺失问题:
- 服务名不存在:组件尝试访问
xyz.openbmc_project.*命名空间的服务,但系统中找不到该服务 - 对象路径不存在:组件尝试访问
/xyz/openbmc_project/*路径的对象,但该路径不存在 - 接口调用失败:组件调用 OpenBMC 标准接口时返回 "Service unknown" 或 "Object not found" 错误
5.3.2 问题原因
该问题的产生是完全能够预料到的,因为 openUBMC 系统并非完整的 OpenBMC 系统,而是基于 openUBMC 架构重新设计的系统。openUBMC 采用了不同的 D-Bus 命名规范:
- 服务命名:openUBMC 使用
bmc.kepler.*命名空间,而非 OpenBMC 的xyz.openbmc_project.* - 对象路径:openUBMC 使用
/bmc/kepler/*路径,而非 OpenBMC 的/xyz/openbmc_project/* - 总线域:openUBMC 主要使用 User Bus,而 OpenBMC 主要使用 System Bus
5.3.3 解决方案
openUBMC 通过 dbus-proxy 组件实现 OpenBMC D-Bus 接口与 openUBMC D-Bus 接口之间的映射。dbus-proxy 采用反向代理机制,在 OpenBMC D-Bus 总线上创建"虚拟"的 OpenBMC 资源,将 OpenBMC 组件的调用转发到 openUBMC 的真实 D-Bus 资源。
解决步骤:
- 确认缺失的资源:通过日志或错误信息确认具体缺失的 D-Bus 服务、对象路径或接口
- 查找对应的 openUBMC 资源:在 openUBMC 系统中查找功能对应的 D-Bus 资源
- 配置映射规则:在
dbus-proxy的mapping_rules.json配置文件中添加映射规则 - 验证映射:重启
dbus-proxy服务,验证映射是否生效
详细配置方法:请参考 附录B:D-Bus 迁移章节,其中包含:
dbus-proxy架构设计说明- 属性映射配置示例
- 方法映射配置示例
- 信号映射配置示例
- 自定义处理器(Handler)开发指南
附录
附录A:代码分析(适用于软件特性迁移)
适用场景说明:
本章节主要面向复杂组件迁移场景,提供系统化的依赖关系分析方法。在以下情况下,建议使用本章节的方法进行代码分析:
- 您对迁移的 OpenBMC 组件不够了解,或并非该组件的设计开发者
- 您的组件与 OpenBMC 中大多数组件之间都存在复杂的依赖关系
- 需要迁移多个相互依赖的组件或整个子系统
无需使用本章节的情况:
如果您的组件是相对独立的顶层应用(如日志管理、状态管理等),且您熟悉该组件的设计和依赖关系,通常不需要进行深入的代码分析,可以直接参考 第2章:OpenBMC 软件特性迁移章节进行迁移。
A.1 依赖关系分析
依赖关系分析是 OpenBMC 组件迁移前期至关重要的一项任务。本迁移指导书推荐采用如下的维度进行分析:
构建时依赖 (Build-Time Dependencies):
- Meson 构建工程/Subprojects
- 代码生成依赖
运行时依赖 (Run-Time Dependencies):
- 动态链接库 (Dynamic Libraries)
- 系统服务与守护进程
- 配置文件与数据源
组件间接口依赖 (Inter-Component Interface Dependencies):
- D-Bus 接口
- 组件 ABI 接口
- 组件对外进程接口
- Lib 库依赖
外部接口依赖 (External Interface Dependencies):
- 开源软件依赖
- 驱动接口依赖
被依赖项 (该组件对外提供的接口):
- D-Bus 服务对外提供的接口
- 组件 ABI 接口
- 组件对外进程接口
- 工具接口
依赖关系分析表格模板:
| 组件名 | 功能简介 | 组件依赖情况 | 分类 | 子分类 | 分析说明 |
|---|---|---|---|---|---|
| xx 组件 | 功能描述 | 依赖项 | 构建依赖 | Meson构建工程/subprojects | - |
| 代码生成依赖 | - | ||||
| 组件间接口 | D-Bus 接口 | - | |||
| 组件ABI接口 | - | ||||
| 组件对外进程接口 | - | ||||
| Lib库依赖 | 依赖的Lib库的API | - | |||
| 外部接口依赖 | 开源软件依赖 | - | |||
| 驱动接口依赖 | - | ||||
| 被依赖项 | 组件间接口 | D-Bus服务对提供的接口 | - | ||
| 组件ABI接口 | - | ||||
| 组件对外进程接口 | - | ||||
| 工具接口 | - |
A.2 C++ 特性分析
在本 OpenBMC 资产迁移项目中,我们提供了完全支持 C++20 特性的 Bisheng LLVM 编译器。如果您的项目当前使用了 C++23 或更高版本的特定高级特性,那么在迁移到 C++20 兼容的 Bisheng LLVM 环境时,您需要进行审慎评估,可能需要对高级特性进行重写或适配。
A.3 功能特性分析
在迁移 OpenBMC 组件之前,进行彻底的功能特性分析是至关重要的一步。具体而言,功能特性分析应包括以下几个方面:
核心功能匹配度评估:
- 功能对齐:详细列出待迁移组件的所有核心功能,并逐一与 openUBMC 现有功能进行对比
- 功能冗余识别:如果 openUBMC 已经提供了相同或类似的功能,需要评估是否可以利用现有实现
- 功能差距分析:对于 openUBMC 尚未实现或部分实现的功能,需要明确功能差距
性能与资源考量:
- 性能基线对比
- 资源需求评估
安全性与合规性分析:
- 安全漏洞评估
- 合规性检查
可维护性与可扩展性:
- 架构适配性
- 代码质量评估
附录B:D-Bus 迁移(适用于软件特性迁移)
B.1 D-Bus 映射简介
dbus-proxy 是 openUBMC 项目中专门设计的 D-Bus 兼容性组件,它扮演着 OpenBMC D-Bus 接口与 openUBMC D-Bus 接口之间的"翻译官"角色。其核心价值在于实现反向代理:在 OpenBMC D-Bus 总线上创建"虚拟"的 OpenBMC 资源,使得迁移后的 OpenBMC 组件能够像在原生 OpenBMC 环境中一样调用这些虚拟资源,而 dbus-proxy 则将这些调用转发到 openUBMC 的真实 D-Bus 资源。
架构设计:dbus-proxy 采用**"配置化映射 + 代码化处理器"**的混合架构:
- 配置化映射:对于简单的 D-Bus 到 D-Bus 映射,通过
mapping_rules.json配置文件即可实现,无需编写代码 - 代码化处理器(Handler):对于复杂的业务逻辑,通过编写 C++ Handler 处理器来实现
工作流程:
OpenBMC 组件请求
↓
OpenBMC D-Bus System Bus (虚拟对象)
↓
dbus-proxy (RequestRouter)
├─→ 配置化映射 (PropertyProxy/MethodProxy/SignalProxy)
└─→ 代码化处理器 (Handler)
↓
openUBMC D-Bus User Bus (真实对象)B.2 属性映射配置示例
属性映射用于将 OpenBMC 组件的属性读取/写入请求转发到 openUBMC 的对应属性。
基本属性映射示例:
{
"id": "sensor_value_property",
"type": "property_to_property",
"source": {
"bus_domain": "system",
"bus": "xyz.openbmc_project.Sensors",
"path": "/xyz/openbmc_project/sensors/temperature/cpu0",
"interface_name": "xyz.openbmc_project.Sensor.Value",
"member": "Value"
},
"target": {
"bus_domain": "user",
"bus": "bmc.kepler.sensor",
"path": "/bmc/kepler/sensors/temperature/cpu0",
"interface_name": "bmc.kepler.Sensor",
"member": "Reading"
},
"return_mappings": [
{
"source_index": 0,
"target_index": 0,
"source_type": "d", // 显式声明:double 类型
"target_type": "d" // 显式声明:double 类型
}
]
}注意:即使源端和目标端的类型相同,也强烈推荐显式声明 source_type 和 target_type,以避免类型自动推断时的潜在错误。
带类型转换的属性映射:
{
"id": "temperature_kelvin_to_celsius",
"type": "property_to_property",
"source": {
"bus_domain": "system",
"bus": "xyz.openbmc_project.Sensors",
"path": "/xyz/openbmc_project/sensors/temp",
"interface_name": "xyz.openbmc_project.Sensor.Value",
"member": "Value"
},
"target": {
"bus_domain": "user",
"bus": "bmc.kepler.sensor",
"path": "/bmc/kepler/sensors/temp",
"interface_name": "bmc.kepler.Sensor",
"member": "ValueCelsius"
},
"return_mappings": [
{
"source_index": 0,
"target_index": 0,
"source_type": "d",
"target_type": "d",
"conversion": "kelvin_to_celsius"
}
]
}参数映射字段说明:
source_index:源端参数的索引(从0开始),对于属性读取,通常为0target_index:目标端参数的索引source_type:源端 D-Bus 类型签名(如d表示 double,s表示 string,y表示 uint8)target_type:目标端 D-Bus 类型签名conversion:类型转换函数名称(可选),如kelvin_to_celsius、multiply_1000等
更多 D-Bus 迁移内容:包括方法映射、信号映射、Handler 处理器编写等详细内容,请参考dbus-proxy
附录C:配置文件模板
C.1 rootfs 目录结构模板
推荐使用 rootfs 目录组织运行时配置文件:
all/
├── rootfs/
│ ├── etc/
│ │ └── dbus-1/
│ │ └── system.d/
│ │ └── component_name.conf # D-Bus 策略文件
│ └── usr/
│ └── lib/
│ └── systemd/
│ └── system/
│ ├── component_name.service # systemd 服务文件
│ └── multi-user.target.wants/
│ └── component_name.service -> ../component_name.service # 自启动软链接
├── patches/
│ └── 0001-1.0.0-adapting-conan-build.patch
├── conandata.yml
└── conanfile.py说明:
rootfs/etc/dbus-1/system.d/:放置 D-Bus 策略文件(.conf)rootfs/usr/lib/systemd/system/:放置 systemd 服务文件(.service)rootfs/usr/lib/systemd/system/multi-user.target.wants/:放置服务自启动软链接
C.2 conanfile.py 模板
(见第2.2.2.4节)
C.3 systemd 服务文件模板
[Unit]
Description=Component Name Service
After=dbus.service
[Service]
Environment=LD_LIBRARY_PATH=/lib
ExecStart=/bin/component_name
SyslogIdentifier=component-name
Type=dbus
BusName=xyz.openbmc_project.Component.Name
[Install]
WantedBy=multi-user.targetC.4 D-Bus 配置文件模板
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy user="root">
<allow own="xyz.openbmc_project.Component.Name"/>
<allow send_destination="xyz.openbmc_project.Component.Name"/>
<allow receive_sender="xyz.openbmc_project.Component.Name"/>
</policy>
<policy user="*">
<allow send_destination="xyz.openbmc_project.Component.Name"/>
<allow receive_sender="xyz.openbmc_project.Component.Name"/>
<allow send_destination="xyz.openbmc_project.Component.Name"
send_interface="xyz.openbmc_project.Component.Interface"/>
<allow receive_sender="xyz.openbmc_project.Component.Name"
receive_interface="xyz.openbmc_project.Component.Interface"/>
</policy>
<policy context="default">
<allow send_destination="xyz.openbmc_project.Component.Name"
send_interface="xyz.openbmc_project.Component.Interface"/>
<allow receive_sender="xyz.openbmc_project.Component.Name"
receive_interface="xyz.openbmc_project.Component.Interface"/>
</policy>
</busconfig>附录D:参考资源
- openUBMC 社区文档:https://www.openubmc.cn/docs
- conan_index:https://gitcode.com/openUBMC/conan_index
- dbus-proxy:https://gitcode.com/BMC2UBMC/dbus-proxy
- bingo:https://gitcode.com/BMC2UBMC/bingo
附录E:术语表
- Conan2:C/C++ 包管理器,用于依赖管理和二进制包分发
- dbus-proxy:D-Bus 兼容性组件,实现 OpenBMC 与 openUBMC 之间的 D-Bus 接口映射
- Bisheng LLVM:基于 LLVM-17 的嵌入式编译工具链,支持 C++20
- conan_index:中心化的组件配置仓库,用于管理 Conan 包的元数据和构建逻辑
- manifest.yml:产品级配置清单,定义构成最终产品的所有组件和版本
- 北向接口:BMC 向上层管理系统或用户提供的接口(如 RESTful API、Redfish、IPMI 等)
- 南向设备驱动:BMC 向下层硬件设备提供的驱动接口(如传感器、风扇、电源等)