openubmc 扩展对外接口-新增ipmi命令

新增IPMI命令 ​

IPMI(智能平台管理接口),Intelligent Platform Management Interface 的缩写,是常用的服务器带外管理协议之一。

IPMI模型定义 ​

openUBMC中提供了一套描述IPMI模型的方式,也属于MDS模型的一部分,因此仅需在MDS中定义IPMI命令,便可自动生成IPMI命令的封装解析帮助函数代码。

详细的IPMI模型定义,请参考《MDS》
也是在 my_app 组件下增加

cd /home/workspace/my_app

打开mds/ipmi.json(如果没有该文件,请新建),粘贴下面的代码

{
    "package": "MyAppIpmiCmds",
    "cmds": {
        "GetSecretNumber": {
            "netfn": "0x30",
            "cmd": "0x90",
            "priority": "OEM",
            "role": "Operator",
            "privilege": ["BasicSetting"],
            "req": [
                {"data": "SubCommand", "baseType": "U8", "len": "1B", "value": "0x88"},
                {"data": "ManufactureId", "baseType": "U32", "len": "3B", "value": "0x0007db"},
                {"data": "Action", "baseType": "U8", "len": "1B", "value": "0x00"}
            ],
            "rsp": [
                {"data": "CompletionCode", "baseType": "U8", "len": "1B"},
                {"data": "SecretNumber", "baseType": "U32", "len": "3B"}
            ]
        },
        "SetSecretNumber": {
            "netfn": "0x30",
            "cmd": "0x90",
            "priority": "OEM",
            "role": "Operator",
            "privilege": ["BasicSetting"],
            "req": [
                {"data": "SubCommand", "baseType": "U8", "len": "1B", "value": "0x88"},
                {"data": "ManufactureId", "baseType": "U32", "len": "3B", "value": "0x0007db"},
                {"data": "Action", "baseType": "U8", "len": "1B", "value": "0x01"},
                {"data": "Data", "baseType": "U32", "len": "3B"}
            ],
            "rsp": [
                {"data": "CompletionCode", "baseType": "U8", "len": "1B"}
            ]
        }
    }
}

这里我们创建了两个IPMI命令,都是NetFn 0x30, CMD 0x90

0x30 0x90 0x88 0xdb 0x07 0x00 0x00此命令用于查询SecretNumber

0x30 0x90 0x88 0xdb 0x07 0x00 0x01此命令用于设置SecretNumber

定义完后,我们需要使用自动生成代码进行代码生成。

bingo gen

代码编写 ​

通过自动生成代码,我们获得了IPMI命令解析、封装和路由的能力,但我们仍需编写IPMI命令的业务部分,即将数据返回出去,或者将传入的数据设置在内存中。

打开my_app_app.lua,

首先要在头部加载生成的IPMI文件

local class = require 'mc.class' -- lua开发框架提供的增强类型系统
local c_service = require 'my_app.service' -- 自动生成代码生成的组件基类
-- 新增ipmi相关文件
local ipmi_struct = require 'my_app.ipmi.ipmi'
local ipmi_msg = require 'my_app.ipmi.ipmi_message'
local ipmi = require 'ipmi'

然后在app:init()中,注册对应IPMI的回调函数

function app:init() -- 组件的初始化函数
    app.super.init(self) -- 先调用基类的初始化函数
    self.my_mds_model = self:CreateMyMDSModel(1, function(object) -- 创建一个mds对象实例
        object.ObjectName = "MyMDSModel_1"  -- 在回调函数中进行对象的属性赋值
        object.WelcomeMessage = "Hello OpenUBMC!"
        object.SecretNumber = 330
    end)
    self:register_ipmi()
end

function app:register_ipmi()
    self:register_ipmi_cmd(ipmi_struct.GetSecretNumber, function(req, ctx, ...)
        return ipmi_msg.GetSecretNumberRsp.new(ipmi.types.Cc.Success, self.my_mds_model.SecretNumber)
    end)
    self:register_ipmi_cmd(ipmi_struct.SetSecretNumber, function(req, ctx, ...)
        if req.Data > 630 then
            return ipmi_msg.SetSecretNumberRsp.new(ipmi.types.Cc.InvalidFieldRequest)
        end
        self.my_mds_model.SecretNumber = req.Data
        return ipmi_msg.SetSecretNumberRsp.new(ipmi.types.Cc.Success)
    end)
end

完整 my_app_app.lua

local class = require 'mc.class' -- lua开发框架提供的增强类型系统
local c_service = require 'my_app.service' -- 自动生成代码生成的组件基类

-- 新增ipmi相关文件
local ipmi_struct = require 'my_app.ipmi.ipmi'
local ipmi_msg = require 'my_app.ipmi.ipmi_message'
local ipmi = require 'ipmi'

local app = class(c_service) -- 创建一个组件类型

function app:ctor() -- 组件的构造函数
end

function app:init() -- 组件的初始化函数
    app.super.init(self) -- 先调用基类的初始化函数
    self.my_mds_model = self:CreateMyMDSModel(1, function(object) -- 创建一个mds对象实例,名字为1
        object.ObjectName = "MyMDSModel_1"  -- 在回调函数中进行对象的属性赋值
        object.WelcomeMessage = "Hello OpenUBMC!"
        object.SecretNumber = 330
    end)
    self.register_ipmi() -- 注册对应IPMI的回调函数
end

function app:register_ipmi()
    self:register_ipmi_cmd(ipmi_struct.GetSecretNumber, function(req, ctx, ...)
        return ipmi_msg.GetSecretNumberRsp.new(ipmi.types.Cc.Success, self.my_mds_model.SecretNumber)
    end)
    self:register_ipmi_cmd(ipmi_struct.SetSecretNumber, function(req, ctx, ...)
        if req.Data > 630 then
            return ipmi_msg.SetSecretNumberRsp.new(ipmi.types.Cc.InvalidFieldRequest)
        end
        self.my_mds_model.SecretNumber = req.Data
        return ipmi_msg.SetSecretNumberRsp.new(ipmi.types.Cc.Success)
    end)
end

return app

当查询IPMI命令来的时候,我们返回MyMDSModel中存储的SecretNumber

当设置IPMI命令来的时候,我们先判断数值是否有效,如果有效,则修改对应的内存数据,并返回成功。

组件构建 ​

代码写完后,我们需要测试一下我们写的代码。首先先进行组件构建。

因为我们对组件的功能进行了修改,因此我们可以通过递增组件的版本用于区分。

首先打开mds/service.json,修改version字段,从0.0.1修改至0.0.2

bingo build --stage=stable

构建完成后我们可以通过日志发现,我们构建了一个构建标签为 my_app/0.0.2@openubmc/stable 的版本。我们之前的 my_app/0.0.1@openubmc/stable 版本仍存在,且不受影响。如果需要使用之前的版本,仍可以通过依赖 my_app/0.0.1@openubmc/stable 标签进行使用。

整包构建 ​

之前的版本我们使用的是my_app/0.0.1版本,现在我们需要将版本改至my_app/0.0.2,然后再进行整包构建。

bingo build

构建完成后,便可在manifest/output中查看构建包。

整包测试 ​

整包升级后,我们再次查看一下my_app的资源

source /etc/profile
busctl --user tree bmc.kepler.my_app
└─/bmc
  |─/bmc/demo
  | └─/bmc/demo/MyMDSModel
  |   └─/bmc/demo/MyMDSModel/1
  |─/bmc/kepler
    |─/bmc/kepler/IpmiCmds
    | └─/bmc/kepler/IpmiCmds/30
    |   └─/bmc/kepler/IpmiCmds/30/90
    |     |─/bmc/kepler/IpmiCmds/30/90/GetSecretNumber
    |     └─/bmc/kepler/IpmiCmds/30/90/SetSecretNumber
    └─/bmc/kepler/my_app
      └─/bmc/kepler/my_app/MicroComponent

这里多了一些IPMI的资源,证明我们成功的将IPMI注册到了我们组件上面,SDK在启动阶段会通过遍历这些资源,更新系统整体IPMI路由表。

通过ipmitool,我们可以快速测试ipmi命令是否可以访问。

> ./ipmitool.exe -H ip -I lanplus -p 623 -U TestUser -P OpenUBMC@123 -C 17 raw 0x30 0x90 0x88 0xdb 0x07 0x00 0x00
> 00 30 03

命令返回330,正是我们在代码中定义的SecretNumber

再次通过设置命令,将SecretNumber设置成630。ipmitool需要输入十六进制,也就是0x000276

# SetSecretNumber
> ./ipmitool.exe -H ip -I lanplus -p 623 -U TestUser -P OpenUBMC@123 -C 17 raw 0x30 0x90 0x88 0xdb 0x07 0x00 0x01 0x76 0x02 0x00
>
# 当命令成功时,成功码不会显示,返回显示为空行

# GetSecretNumber
> ./ipmitool.exe -H ip -I lanplus -p 623 -U TestUser -P OpenUBMC@123 -C 17 raw 0x30 0x90 0x88 0xdb 0x07 0x00 0x00
> 76 02 00

设置成功,并再次下发查询命令,得到630,与我们设置的数值一致。

posted @ 2026-09-15 17:28  一枚码农  阅读(9)  评论(0)    收藏  举报