设备接口(Device Interfaces)软件设计方案
1. 概述
设备接口是设备监控系统(devmon)的核心抽象层,定义了各类设备的标准操作接口和属性集合。它通过提供一套统一的面向对象接口,使上层应用能够以相同的方式访问不同类型和厂商的硬件设备,实现了设备访问的标准化和简化。
2. 设计目标
- 提供统一、清晰的设备访问接口
- 实现硬件细节与应用逻辑的解耦
- 支持面向对象的属性和方法访问
- 允许接口的可扩展性和组合性
- 支持各厂商不同实现的适配
- 实现基于反射的动态访问机制
3. 接口架构设计
3.1 接口定义机制
设备接口采用"JSON定义+代码生成"的机制,将接口规范与实现分离:
flowchart LR
JSON[JSON接口定义] -->|代码生成| GenInterface[生成的接口类]
GenInterface -->|继承| VendorImpl[厂商实现类]
VendorImpl -->|组合| Object[设备对象类]
Object -->|使用| Application[应用层]
- JSON接口定义:在
mdb_interface目录下,通过JSON文件定义接口的属性、方法和元数据 - 代码生成:通过工具链将JSON定义转换为C++接口基类(gen::命名空间)
- 厂商实现:厂商在interface目录下继承生成的基类,提供具体实现
- 接口使用:设备对象通过组合多个接口实现复杂功能
3.2 自动生成代码与手写代码关系
设备接口系统中,清晰区分了自动生成的代码和需要手动编写的代码,以实现标准化与定制化的平衡:
flowchart TD
subgraph 自动生成["自动生成部分(代码生成工具)"]
direction TB
JSON["JSON接口定义<br>mdb_interface/json/<br>PCIeDevice.json等"] -->|"代码生成工具"| GenHeaders["生成的接口头文件<br>gen/device_tree/interface/<br>PCIeDevice.h等"]
JSON -->|"代码生成工具"| GenReflect["生成的反射代码<br>MC_REFLECT宏"]
end
subgraph 手写代码["手动编写部分(开发者)"]
direction TB
BaseInterface["基础接口定义<br>device_interfaces/<br>PCIeDevice.h等"] -->|"包含"| GenHeaders
ObjClasses["设备对象类<br>pcie_nic_card.h<br>network_port.h"] -->|"组合使用"| GenHeaders
VendorImpl["厂商特定实现<br>hisi/interface/<br>pcie_device.h等"] -->|"继承实现"| GenHeaders
ABI["驱动ABI导出<br>hi182x_abi.cpp"] -->|"创建对象"| VendorImpl
end
GenHeaders -->|"提供接口规范"| VendorImpl
GenReflect -->|"提供反射支持"| VendorImpl
subgraph 运行时["运行时系统"]
Driver["动态加载的<br>驱动库(.so)"]
DeviceObj["设备对象实例"]
end
ObjClasses -->|"编译构建"| Driver
VendorImpl -->|"编译构建"| Driver
ABI -->|"编译构建"| Driver
Driver -->|"创建"| DeviceObj
代码职责划分:
-
自动生成部分(代码生成工具):
- 接口基类定义(
gen/device_tree/interface/PCIeDevice.h等) - 反射代码(
MC_REFLECT宏实现) - 属性访问器
- 序列化/反序列化支持
- 接口基类定义(
-
手动编写部分(开发者):
- 厂商接口实现(
plugins/.../interface/pcie_device.h等) - 子接口实现(
network_adapter/cooling.h等) - 设备对象类(
hi182x_card.h、hi182x_port.h等) - 驱动ABI导出(
hi182x_abi.cpp)
- 厂商接口实现(
-
文件目录对应关系:
/mdb_interface/json/- JSON接口定义/devmon/gen/device_tree/interface/- 自动生成的接口基类/devmon/plugins/.../interface/- 手写的厂商接口实现/devmon/plugins/.../hi182x/- 手写的设备对象类
3.3 接口层次结构
设备接口采用多层次的组织结构,形成清晰的类型层次:
classDiagram
class gen_PCIeDevice {
<<generated>>
+DeviceName: string
+VendorId: string
+DeviceId: string
+Bus: uint8_t
+Device: uint8_t
+Function: uint8_t
}
class dev_PCIeDevice {
+SetRootBDF()
+SetDeviceBDF()
+update_pcie_device_id_by_ncsi()
+start_ncsi_update_task_huawei()
+replace_dynamic_property()
+pcie_device_bdf_changed: signal
}
class gen_NetworkAdapter {
<<generated>>
+AdapterType: string
+MaxPorts: uint8_t
+ChipModel: string
}
class dev_NetworkAdapter {
+update_firmware_version_by_ncsi()
+start_ncsi_update_task_huawei()
}
class gen_NetworkPort {
<<generated>>
+PortId: uint8_t
+MACAddress: string
+MediumType: string
}
class dev_NetworkPort {
+update_bdf_by_ncsi()
+update_mac_addr_by_ncsi()
+start_ncsi_update_task_huawei()
}
class gen_OpticalModule {
<<generated>>
+PortId: uint8_t
+Manufacturer: string
+PartNumber: string
+SerialNumber: string
}
class dev_OpticalModule {
+get_optical_module_info_by_ncsi()
+start_ncsi_update_task_huawei()
}
class gen_Board {
<<generated>>
+BoardName: string
+SerialNumber: string
}
class dev_Board {
+replace_dynamic_property()
}
class gen_PCIeCard {
<<generated>>
+CardType: string
+SlotNumber: uint8_t
}
class dev_PCIeCard {
+SystemId: uint8_t
}
gen_PCIeDevice <|-- dev_PCIeDevice
gen_NetworkAdapter <|-- dev_NetworkAdapter
gen_NetworkPort <|-- dev_NetworkPort
gen_OpticalModule <|-- dev_OpticalModule
gen_Board <|-- dev_Board
gen_PCIeCard <|-- dev_PCIeCard
3.4 核心接口类型
系统定义了以下核心设备接口:
| 接口名称 | 生成基类 | 厂商实现类 | 主要功能 | 特殊方法 |
|---|---|---|---|---|
| PCIeDevice | gen::PCIeDevice | dev::PCIeDevice | PCIe设备管理 | SetRootBDF, SetDeviceBDF, NCSI更新 |
| NetworkAdapter | gen::NetworkAdapter | dev::NetworkAdapter | 网络适配器管理 | 固件版本更新, NCSI任务 |
| NetworkPort | gen::NetworkPort | dev::NetworkPort | 网络端口管理 | BDF更新, MAC地址更新 |
| OpticalModule | gen::OpticalModule | dev::OpticalModule | 光模块管理 | 光模块信息获取 |
| PCIeCard | gen::PCIeCard | dev::PCIeCard | PCIe卡管理 | 系统ID管理 |
| Board | gen::Board | dev::Board | 主板管理 | 动态属性替换 |
3.5 子接口设计
为了增强组合能力和功能分离,系统采用子接口设计模式:
NetworkPort (主接口)
├── NetworkPort_LinkInfo - 链路信息子接口
│ ├── link_info.h/cpp
│ └── 链路状态、速度、双工模式等
├── NetworkPort_DataCenterBridging - 数据中心桥接子接口
│ ├── data_center_bridging.h/cpp
│ └── DCB配置、优先级控制等
├── NetworkPort_LLDPReceive - LLDP接收子接口
│ ├── lldp_receive.h/cpp
│ └── LLDP协议数据接收处理
└── NetworkPort_Metrics - 度量指标子接口
├── metrics.h/cpp
└── 性能统计、流量监控等
NetworkAdapter (主接口)
├── NetworkAdapter_FaultStatus - 故障状态子接口
│ ├── fault_status.h/cpp
│ └── 故障检测、状态报告等
├── NetworkAdapter_Cooling - 散热子接口
│ ├── cooling.h/cpp
│ └── 温度监控、散热控制等
└── NetworkAdapter_LogCollection - 日志收集子接口
├── log_collection.h/cpp
└── 日志收集、事件记录等
OpticalModule (主接口)
├── OpticalModule_Status - 状态子接口
│ ├── status.h/cpp
│ └── 光模块状态监控
└── OpticalModule_Cooling - 散热子接口
├── cooling.h/cpp
└── 光模块温度管理
PCIeDevice (主接口)
└── PCIeDevice_Bandwidth - 带宽子接口
├── bandwidth.h/cpp
└── PCIe带宽监控和管理
这种设计允许更灵活的接口组合和功能扩展,同时保持核心接口的简洁性。
4. 接口定义技术
4.1 基于继承的接口实现
设备接口使用继承机制实现,厂商实现类继承自动生成的基类:
// 自动生成的基类 (gen命名空间)
namespace gen {
class PCIeDevice {
public:
// 自动生成的属性
std::string DeviceName;
std::string VendorId;
std::string DeviceId;
uint8_t Bus;
uint8_t Device;
uint8_t Function;
// 其他属性...
};
}
// 厂商实现类 (dev命名空间)
namespace dev {
class PCIeDevice : public gen::PCIeDevice {
public:
PCIeDevice() = default;
~PCIeDevice() = default;
public:
// 设备接口实现
bool SetRootBDF(uint8_t bus, uint8_t device, uint8_t function) override;
bool SetDeviceBDF(uint8_t bus, uint8_t device, uint8_t function) override;
public:
// NCSI over MCTP 华为自定义命令实现
bool update_pcie_device_id_by_ncsi();
void start_ncsi_update_task_huawei(ncsi_over_mctp_hw_ptr ncsi_over_mctp,
mc::milliseconds interval);
void stop_ncsi_update_task();
private:
ncsi_over_mctp_hw_ptr m_ncsi_over_mctp_huawei;
mc::timer* m_ncsi_timer;
public:
void replace_dynamic_property(mc::mutable_dict& object, const mc::dict& connector);
mc::signal<void(uint8_t, uint8_t, uint8_t)> pcie_device_bdf_changed;
};
}
4.2 基于MC_REFLECT的反射机制
接口使用MC_REFLECT宏实现属性的反射功能,支持运行时属性访问:
// 厂商实现类的反射定义
MC_REFLECT(dev::PCIeDevice, (gen::PCIeDevice), ())
MC_REFLECT(dev::NetworkPort, (gen::NetworkPort), ())
MC_REFLECT(dev::OpticalModule, (gen::OpticalModule), ())
// 带有额外属性的反射定义
MC_REFLECT(dev::PCIeCard, (gen::PCIeCard), ((SystemId, "SystemId")))
此机制实现了:
- 属性的自省(查询类具有哪些属性)
- 动态属性访问(通过名称获取/设置属性值)
- 序列化/反序列化支持(JSON转换等)
- 属性的双向绑定(C++对象与外部表示间的映射)
4.3 NCSI over MCTP集成
大部分接口都集成了NCSI over MCTP协议支持,用于与硬件设备通信:
class NetworkAdapter : public gen::NetworkAdapter {
public:
// NCSI over MCTP 华为自定义命令实现
bool update_firmware_version_by_ncsi();
void start_ncsi_update_task_huawei(ncsi_over_mctp_hw_ptr ncsi_over_mctp,
mc::milliseconds interval);
void stop_ncsi_update_task();
private:
mc::timer* m_ncsi_timer;
ncsi_over_mctp_hw_ptr m_ncsi_over_mctp_huawei;
};
4.4 信号机制
接口支持信号机制,用于事件通知:
class PCIeDevice : public gen::PCIeDevice {
public:
// BDF变化信号
mc::signal<void(uint8_t, uint8_t, uint8_t)> pcie_device_bdf_changed;
bool SetDeviceBDF(uint8_t bus, uint8_t device, uint8_t function) {
// 设置BDF值
DevBus = bus;
DevDevice = device;
DevFunction = function;
// 发送信号通知
post([this, bus, device, function]() {
pcie_device_bdf_changed(bus, device, function);
});
return true;
}
};
5. 接口实现机制
5.1 从JSON到C++接口
接口定义过程:
-
JSON接口定义:
{ "name": "PCIeDevice", "namespace": "bmc.dev", "properties": [ {"name": "DeviceName", "type": "string"}, {"name": "VendorId", "type": "string"}, {"name": "DeviceId", "type": "string"}, {"name": "Bus", "type": "uint8_t"}, {"name": "Device", "type": "uint8_t"}, {"name": "Function", "type": "uint8_t"} ], "methods": [ { "name": "SetRootBDF", "returnType": "bool", "parameters": [ {"name": "bus", "type": "uint8_t"}, {"name": "device", "type": "uint8_t"}, {"name": "function", "type": "uint8_t"} ] } ] } -
生成的C++基类:
namespace gen { class PCIeDevice { public: std::string DeviceName; std::string VendorId; std::string DeviceId; uint8_t Bus; uint8_t Device; uint8_t Function; virtual bool SetRootBDF(uint8_t bus, uint8_t device, uint8_t function) = 0; }; } -
厂商实现类:
namespace dev { class PCIeDevice : public gen::PCIeDevice { public: bool SetRootBDF(uint8_t bus, uint8_t device, uint8_t function) override { if (bus == 0 && device == 0 && function == 0) { return false; } Bus = bus; Device = device; Function = function; return true; } // 厂商特定的扩展方法 bool update_pcie_device_id_by_ncsi(); void start_ncsi_update_task_huawei(ncsi_over_mctp_hw_ptr ncsi_over_mctp, mc::milliseconds interval); }; } -
设备对象中使用接口:
class hi182x_card : public mc::engine::object<hi182x_card> { public: MC_OBJECT( hi182x_card, "PCIeNicCard", "/bmc/dev/Systems/1/PCIeNicCard/${DeviceName}", (PCIeDevice)(PCIeCard)(NetworkAdapter)) dev::PCIeDevice m_pcie_device; dev::PCIeCard m_pcie_card; dev::NetworkAdapter m_network_adapter; };
5.2 动态属性替换机制
接口支持动态属性替换,用于配置时的参数替换:
void PCIeDevice::replace_dynamic_property(mc::mutable_dict& object, const mc::dict& connector) {
mc::mutable_dict pcie_device_obj = object["bmc.dev.PCIeDevice"].as<mc::mutable_dict>();
// 替换Slot参数
if (pcie_device_obj.contains("Slot")) {
if (pcie_device_obj["Slot"].as<std::string>() == "${Slot}") {
pcie_device_obj["Slot"] = connector["Slot"].as<uint8_t>();
}
}
// 替换DeviceName中的参数
if (pcie_device_obj.contains("DeviceName")) {
std::string device_name = pcie_device_obj["DeviceName"].as<std::string>();
if (device_name.find("${Slot}") != std::string::npos) {
mc::string::format(device_name, connector);
pcie_device_obj["DeviceName"] = device_name;
}
}
object["bmc.dev.PCIeDevice"] = pcie_device_obj;
}
5.3 子接口实现示例
子接口实现了特定功能域的管理:
// 网络适配器散热子接口
class NetworkAdapter_Cooling : public gen::NetworkAdapter_Cooling {
public:
NetworkAdapter_Cooling() = default;
~NetworkAdapter_Cooling() = default;
public:
// NCSI over MCTP 华为自定义命令实现
bool update_chip_temp_by_ncsi();
bool update_max_sfp_temperature(uint16_t max_temperature, uint8_t status);
void start_ncsi_update_task_huawei(ncsi_over_mctp_hw_ptr ncsi_over_mctp,
mc::milliseconds interval);
void stop_ncsi_update_task();
private:
mc::timer* m_ncsi_timer;
ncsi_over_mctp_hw_ptr m_ncsi_over_mctp_huawei;
};
6. 接口使用示例
6.1 应用层访问接口
// 通过路径获取设备对象
auto card = service->get_object<hi182x_card>("/bmc/dev/Systems/1/PCIeNicCard/hi182x");
// 直接访问属性
std::string vendor_id = card->m_pcie_device.VendorId;
uint8_t port_id = card->m_network_ports[0]->m_network_port.PortId;
// 调用方法
bool result = card->m_pcie_device.SetRootBDF(0x01, 0x00, 0x00);
// 启动NCSI更新任务
card->m_pcie_device.start_ncsi_update_task_huawei(ncsi_ptr, mc::milliseconds(5000));
// 访问子接口
uint16_t chip_temp = card->m_network_adapter_cooling.ChipTemperature;
6.2 信号连接示例
// 连接BDF变化信号
card->m_pcie_device.pcie_device_bdf_changed.connect([](uint8_t bus, uint8_t device, uint8_t function) {
ilog("PCIe device BDF changed: ${bus}:${device}.${function}",
("bus", bus)("device", device)("function", function));
});
// 设置BDF时会自动触发信号
card->m_pcie_device.SetDeviceBDF(0x02, 0x01, 0x00);
6.3 动态属性访问
// 动态获取属性值
mc::dict properties;
card->get_properties("PCIeDevice", properties);
std::string vendor_id = properties["VendorId"].as<std::string>();
// 动态设置属性值
mc::dict updates = {{"DeviceName", "Updated Name"}};
card->set_properties("PCIeDevice", updates);
7. 接口扩展机制
7.1 添加新接口
扩展系统时添加新接口的步骤:
- 在
mdb_interface/json目录下创建新的JSON接口定义 - 使用代码生成工具生成C++接口基类(gen命名空间)
- 在
plugins/.../interface目录下创建厂商实现类(dev命名空间) - 实现接口的具体方法和NCSI集成
- 在设备对象类中组合使用新接口
- 更新meson.build构建配置
7.2 扩展现有接口
扩展现有接口的方法:
-
添加子接口:创建新的子接口类,专注于特定功能域
// 添加新的网络端口子接口 class NetworkPort_Security : public gen::NetworkPort_Security { public: bool enable_port_security(); bool configure_mac_filter(); }; -
扩展厂商实现:在现有厂商实现类中添加新方法
class PCIeDevice : public gen::PCIeDevice { public: // 现有方法... // 新增方法 bool configure_power_management(); bool enable_error_reporting(); }; -
组合多接口:在设备对象中组合多个接口实现复杂功能
7.3 接口版本兼容策略
接口版本控制遵循以下原则:
- 向后兼容性:新版本接口应兼容旧版应用
- 接口版本号:通过版本号管理接口变更
- 兼容层设计:在必要时提供兼容层转换
8. 接口性能考量
8.1 反射机制性能
MC_REFLECT实现的反射机制性能特点:
- 直接属性访问时间复杂度为O(1)
- 编译期生成元数据,运行时几乎无额外开销
- 动态属性查找时间复杂度为O(1)~O(log n)
- 序列化/反序列化过程线性时间复杂度O(n)
8.2 接口调用开销
接口调用性能优化:
- 虚函数表实现虚方法调用,单次调用开销极小
- 属性访问通过直接成员变量,没有额外间接层
- NCSI通信采用异步机制,避免阻塞主线程
- 复杂操作可通过批量接口减少调用次数
8.3 NCSI通信优化
NCSI over MCTP通信的性能优化:
- 使用定时器实现周期性更新,避免频繁轮询
- 支持任务启动和停止,按需进行通信
- 异步处理NCSI响应,不阻塞接口调用
- 错误处理和重试机制,提高通信可靠性