IMPORTANT
To get the most out of this chapter, make sure you've already completed Extend the BMC API.
As out-of-band server management software, the BMC most often deals with adapting to varied hardware. Drawing on years of experience, the openUBMC SDK offers a range of hardware-adaptation capabilities that streamline this work.
This chapter walks through incremental development on top of an existing hardware adaptation, to help you understand the overall flow. For the specifics of adapting different kinds of hardware, see the Hardware Component Adaptation Guide.
Add an IPMI Sensor
A common scenario is exposing a reading from some hardware part to users as a threshold sensor defined by the IPMI protocol. In this chapter, we'll configure an LM75 temperature part along with a matching IPMI threshold sensor, and surface it through an external API.
CSR Configuration
openUBMC uses a software description language to capture the details of a piece of hardware. This language is called the Component Self-Description Record (CSR).
NOTE
For a full introduction to the CSR, see Component Self-Description Record (CSR).
First, clone the CSR repository:
git clone https://gitcode.com/openUBMC/vpd.gitOpen the root.sr of the server model (vendor/Huawei/Server/Kunpeng/openUBMC).
Inside you'll find a series of configurations. First, we declare an LM75 part in the hardware topology.
On the actual hardware, there's an LM75 temperature-sensing chip at address 0x90 on the I2c_8 bus.
In the CSR's ManagementTopology, find the I2c_8 configuration; if there's no I2c_8, paste the configuration below into ManagementTopology (you can model it on I2c_2).
"ManagementTopology": {
...
"I2c_8": {
"Chip": [
"Lm75_DemoSensor"
]
}
...
}That completes the hardware topology configuration in the CSR.
Next, alongside ManagementTopology, under Objects, define the details of the LM75 part along with its business objects:
"Objects": {
...
"Lm75_DemoSensor": {
"OffsetWidth": 1,
"AddrWidth": 1,
"Address": 144
},
"Scanner_GetTemperature": {
"Chip": "#/Lm75_DemoSensor",
"Size": 1,
"Offset": 0,
"Mask": 255,
"Period": 1000
},
"ThresholdSensor_DemoSensor": {
"AssertMask": 29312,
"DeassertMask": 29312,
"ReadingMask": 6168,
"Linearization": 0,
"M": 100,
"RBExp": 224,
"UpperCritical": 48,
"UpperNoncritical": 46,
"PositiveHysteresis": 2,
"NegativeHysteresis": 2,
"OwnerId": 32,
"OwnerLun": 0,
"EntityId": "<=/Entity_DemoSensor.Id",
"EntityInstance": "<=/Entity_DemoSensor.Instance",
"Initialization": 127,
"Capabilities": 104,
"SensorType": 1,
"ReadingType": 1,
"SensorName": "Demo Temperature Sensor",
"Unit": 128,
"BaseUnit": 1,
"ModifierUnit": 0,
"Analog": 1,
"MaximumReading": 127,
"MinimumReading": 128,
"Reading": "<=/Scanner_GetTemperature.Value"
},
"Entity_DemoSensor":{
"Id": 99,
"Name": "Demo Temperature Sensor",
"PowerState": 1,
"Presence": 1,
"Instance": 96
},
...
}Here we define several objects: the LM75 part, a periodic scan task (Scanner), and the software object for the IPMI threshold sensor. We link the Scanner to the LM75 part using reference syntax, and synchronize the Scanner's reading into the ThresholdSensor's reading using sync syntax.
NOTE
For IPMI sensor configuration details, see IPMI Sensor & SEL.
Build the App
Since we changed the vpd repository, we need to rebuild it.
To distinguish it from the previous version, bump the version field in service.json.
bingo build --stage=stableBuild the Full Image
Find where vpd is declared, update its version to the one you just built, then build the full image again from the manifest.
bingo buildTest the Full Build
After upgrading with the full image, we can query the sensor with ipmitool:
> ./ipmitool.exe -H ip -I lanplus -p 623 -U TestUser -P OpenUBMC@123 -C 17 sdr
> Demo Temperature | 28 degrees C | okAdd a Hardware Resource Object
The object definitions in the CSR come from the MDS model. By instantiating an MDS class definition, you can lay out all the hardware-management data you need in the relevant device configuration, then write the business logic around those resource objects in your app.
Define the MDS Object
First, we define a resource class in the my_app app's MDS model.
Open mds/model.json in the my_app app you created in Create an App, and add the model definition below:
NOTE
MDS (Model Description Source) describes the resource model.
For the detailed design, see MDS.
{
"MyCSRModel": {
"path": "/bmc/demo/MyCSRModel/${id}",
"interfaces": {
"bmc.demo.OpenUBMC.Reading": {
"properties":{
"TemperatureCelsius": {
"usage": [
"CSR"
]
}
}
}
}
}
}Unlike an ordinary app MDS object definition, here we add a "usage": ["CSR"] declaration. It says that within some CSR there's an object called MyCSRModel carrying a TemperatureCelsius property.
Add the CSR Object
NOTE
For the design of hardware self-discovery, see Hardware Self-Discovery.
As the usage declaration above shows, TemperatureCelsius comes from the CSR, so we need to define a MyCSRModel in that CSR; hardware self-discovery then dispatches the CSR object to my_app.
"Objects": {
...
"MyCSRModel_DemoSensor": {
"TemperatureCelsius": "<=/Scanner_GetTemperature.Value"
},
...
}Generate Code
Since we added a model definition, we regenerate the helper code. Run the following in my_app:
bingo genWrite the Code
Because the MyCSRModel instance is already "created" in root.sr, we wait for the object to be dispatched rather than creating it ourselves. Here's how to receive that dispatch in code.
Open my_app_app.lua and add object-added callbacks in app:init().
local object_manage = require 'mc.mdb.object_manage'function app:init() -- The app's initialization function
app.super.init(self) -- Call the base class initializer first
self.my_mds_model = self:CreateMyMDSModel(1, function(object) -- Create an MDS object instance
object.ObjectName = "MyMDSModel_1" -- Assign the object's properties inside the callback
object.WelcomeMessage = "Hello OpenUBMC!"
object.SecretNumber = 330
end)
self:register_ipmi()
self:register_mds_callback() -- Newly added MDS callbacks
end
function app:register_mds_callback()
object_manage.on_add_object(self.bus, function(class_name, object, position)
if class_name == 'MyCSRModel' then
self.my_csr_model = object
end
end)
object_manage.on_add_object_complete(self.bus, function(position)
end)
object_manage.on_delete_object(self.bus, function(class_name, object, position)
if self.my_csr_model == object then
self.my_csr_model = nil
end
end)
object_manage.on_delete_object_complete(self.bus, function(position)
end)
endBuild the App
Since we changed the my_app repository, we need to build it.
To distinguish it from the previous version, manually bump the version field in mds/service.json—usually by incrementing the last digit—then run the app build.
bingo build --stage=rcBuild the Full Image
In the manifest, find where my_app was declared earlier (in Create an App it was placed in manifest/build/product/openUBMC/openUBMC/manifest.yml), update its version to the one you just built, then build the full image.
bingo buildTest the Full Build
After upgrading with the full image, we can inspect the MDB interface (resource collaboration interface) object:
source /etc/profile
busctl --user tree bmc.kepler.my_app└─/bmc
|─/bmc/demo
| |─/bmc/demo/MyCSRModel
| | └─/bmc/demo/MyCSRModel/MyCSRModel_DemoSensor_01
| └─/bmc/kepler/MyMDSModel
| └─/bmc/kepler/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/MicroComponentThe busctl --user tree output now shows an extra object—the one configured in the CSR. We can inspect it with busctl --user introspect:
busctl --user introspect bmc.kepler.my_app /bmc/demo/MyCSRModel/MyCSRModel_DemoSensor_01NAME TYPE SIGNATURE RESULT/VALUE FLAGS
bmc.kepler.OpenUBMC.Reading interface - - -
.TemperatureCelsius property n 28 emits-change writable
bmc.kepler.Object.Properties interface - - -
.GetAllWithContext method a{ss}s a{sv} -
.GetOptions method a{ss}ss a{ss} -
.GetPropertiesByNames method a{ss}sas a{sv}a{sv} -
.GetPropertiesByOptions method a{ss}sa{ss} as -
.GetWithContext method a{ss}ss v -
.SetWithContext method a{ss}ssv - -
.ClassName property s "MyCSRModel" emits-change
.ObjectIdentifier property (ysss) 0 "1" "" "01" emits-change
.ObjectName property s "MyCSRModel_DemoSensor_01" emits-change
org.freedesktop.DBus.Introspectable interface - - -
.Introspect method - s -
org.freedesktop.DBus.ObjectManager interface - - -
.GetManagedObjects method - a{oa{sa{sv}}} -
org.freedesktop.DBus.Peer interface - - -
.GetMachineId method - s -
.Ping method - - -
org.freedesktop.DBus.Properties interface - - -
.Get method ss v -
.GetAll method s a{sv} -
.Set method ssv - -
.PropertiesChanged signal sa{sv}as - -