设备接口(Device Interfaces)软件设计方案

1. 概述

设备接口是设备监控系统(devmon)的核心抽象层,定义了各类设备的标准操作接口和属性集合。它通过提供一套统一的面向对象接口,使上层应用能够以相同的方式访问不同类型和厂商的硬件设备,实现了设备访问的标准化和简化。

2. 设计目标

  • 提供统一、清晰的设备访问接口
  • 实现硬件细节与应用逻辑的解耦
  • 支持面向对象的属性和方法访问
  • 允许接口的可扩展性和组合性
  • 支持各厂商不同实现的适配
  • 实现基于反射的动态访问机制

3. 接口架构设计

3.1 接口定义机制

设备接口采用"JSON定义+代码生成"的机制,将接口规范与实现分离:

flowchart LR
    JSON[JSON接口定义] -->|代码生成| GenInterface[生成的接口类]
    GenInterface -->|继承| VendorImpl[厂商实现类]
    VendorImpl -->|组合| Object[设备对象类]
    Object -->|使用| Application[应用层]
  1. JSON接口定义:在mdb_interface目录下,通过JSON文件定义接口的属性、方法和元数据
  2. 代码生成:通过工具链将JSON定义转换为C++接口基类(gen::命名空间)
  3. 厂商实现:厂商在interface目录下继承生成的基类,提供具体实现
  4. 接口使用:设备对象通过组合多个接口实现复杂功能

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

代码职责划分:

  1. 自动生成部分(代码生成工具):

    • 接口基类定义(gen/device_tree/interface/PCIeDevice.h等)
    • 反射代码(MC_REFLECT宏实现)
    • 属性访问器
    • 序列化/反序列化支持
  2. 手动编写部分(开发者):

    • 厂商接口实现(plugins/.../interface/pcie_device.h等)
    • 子接口实现(network_adapter/cooling.h等)
    • 设备对象类(hi182x_card.h、hi182x_port.h等)
    • 驱动ABI导出(hi182x_abi.cpp)
  3. 文件目录对应关系:

    • /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")))

此机制实现了:

  1. 属性的自省(查询类具有哪些属性)
  2. 动态属性访问(通过名称获取/设置属性值)
  3. 序列化/反序列化支持(JSON转换等)
  4. 属性的双向绑定(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++接口

接口定义过程:

  1. 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"}
          ]
        }
      ]
    }
    
  2. 生成的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;
        };
    }
    
  3. 厂商实现类:

    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);
        };
    }
    
  4. 设备对象中使用接口:

    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 添加新接口

扩展系统时添加新接口的步骤:

  1. 在mdb_interface/json目录下创建新的JSON接口定义
  2. 使用代码生成工具生成C++接口基类(gen命名空间)
  3. 在plugins/.../interface目录下创建厂商实现类(dev命名空间)
  4. 实现接口的具体方法和NCSI集成
  5. 在设备对象类中组合使用新接口
  6. 更新meson.build构建配置

7.2 扩展现有接口

扩展现有接口的方法:

  1. 添加子接口:创建新的子接口类,专注于特定功能域

    // 添加新的网络端口子接口
    class NetworkPort_Security : public gen::NetworkPort_Security {
    public:
        bool enable_port_security();
        bool configure_mac_filter();
    };
    
  2. 扩展厂商实现:在现有厂商实现类中添加新方法

    class PCIeDevice : public gen::PCIeDevice {
    public:
        // 现有方法...
    
        // 新增方法
        bool configure_power_management();
        bool enable_error_reporting();
    };
    
  3. 组合多接口:在设备对象中组合多个接口实现复杂功能

7.3 接口版本兼容策略

接口版本控制遵循以下原则:

  1. 向后兼容性:新版本接口应兼容旧版应用
  2. 接口版本号:通过版本号管理接口变更
  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响应,不阻塞接口调用
  • 错误处理和重试机制,提高通信可靠性