blob: f5ba072cdf2e2d352a5024cf839d9b5fca6b2d6a [file] [log] [blame] [view]
# Onboarding NPIs to tlBMC
go/tlbmc-onboarding-npis
<!--*
# Document freshness: For more information, see go/fresh-source.
freshness: { owner: 'tlbmc-dev' reviewed: '2025-03-12' }
*-->
This document outlines the additions necessary to Entity-Manager (EM)
configuration files to onboard an NPI to tlBMC.
[Entity-Manager](https://github.com/openbmc/entity-manager) provides mappings
from hardware components to software components within a system, these mappings
are managed through EM configuration files as described here.
Note: tlBMC requires only additions to existing EM config files, no deletions or
modifications of existing properties should occur. This allows tlBMC to be
backward compatible with existing bmcweb without conflicting behavior. Original
design doc can be viewed at go/tlbmc-data-completeness
Tip: Existing daemons, e.g. PSU sensors, will still coexist if not disabled
explicitly. Whether these should be configured depends on the use case. If the
sensor is only used in telemetry reporting not control, e.g. PID, tlBMC can
fully replace existing daemons. In this case, see the section **SkipDbusRead
Property** which describes how to disable sensor polling over dbus to
significantly improve CPU utilization.
[TOC]
## Chassis
### ProbeV2
The addition of the ProbeV2 field makes the config detectable by tlBMC. The
value of the `IpmiFru` JSON within the ProbeV2 field corresponds with the
existing `Probe` field in EM configs. `BOARD_CONFIG_NAME`,
`PRODUCT_CONFIG_NAME`, and `BOARD_PART_NUMBER` are valid probe fields, and if a
scanned FRU matches these fields, the object will be created from this config.
An example definition:
```
...
"ProbeV2": {
"IpmiFru": {
"BOARD_PRODUCT_NAME": "foo"
}
},
...
```
The `ProbeV2` field can also be set to `TRUE` to always be populated regardless
of matching a scanned FRU, or it can be set to `FALSE` to be ignored.
An example definition:
```
...
"ProbeV2": "TRUE",
...
```
#### Logical AND and OR Syntax
Logical AND and OR syntax is supported for the IpmiFru field if given an array
of JSON objects instead of a single JSON.
The logical AND operation is applied for all fields within a single IpmiFru
JSON. For the matcher to evaluate as True, every field must be a match.
An example definition:
```
// In this example, the scanned FRU must have both the BOARD_PRODUCT_NAME = foo
// and the BOARD_PART_NUMBER = 1234567890 to successfully probe to True
...
"ProbeV2": {
"IpmiFru": [
{
"BOARD_PRODUCT_NAME": "foo",
"BOARD_PART_NUMBER": "1234567890"
}
]
}
...
```
The logical OR operation is applied between matcher objects within the array of
IpmiFru JSONs. If any one of the matchers evaluates to True, considering the
logical AND syntax above, the Probe will be evaluated as True.
An example definition:
```
// In this example, the scanned FRU must have either the BOARD_PRODUCT_NAME = foo
// or the BOARD_PART_NUMBER = 1234567890 to successfully probe to True. If either
// field matches, the probe will be successful regardless of the value of the other field
...
"ProbeV2": {
"IpmiFru": [
{
"BOARD_PRODUCT_NAME": "foo"
},
{
"BOARD_PART_NUMBER": "1234567890"
}
]
}
...
```
Note: `FOUND` behaviors are not yet supported by tlBMC.
### ResourceType
`ResourceType` has parity with the `Type` field in existing EM configs.
Supported resource types are defined in `tlbmc/resource/resource.proto`.
An example definition:
```
...
"ResourceType": "RESOURCE_TYPE_BOARD",
...
```
#### ChassisType
For configs of `RESOURCE_TYPE_BOARD` an `ChassisType` is needed as a additional
field. This field has parity with the EM config field
`xyz.openbmc_project.Inventory.Item.Chassis.ChassisType`. This field will
default to type `RackMount`.
Supported chassis types are defined in `tlbmc/resource/resource.proto`.
An example definition:
```
...
"ChassisType": "CHASSIS_TYPE_COMPONENT",
...
```
### Downstream/Upstream Ports
Physical ports are modeled as downstream/upstream ports between Chassis. These
are fields in the `Exposes` array of a config and may correspond to existing
ports. Similar to existing EM configs, a port on an upstream chassis to a
downstream chassis has a `Label` field, used to populate the devpath. These
ports will have the `Type` of `PortDownstream`. On the downstream chassis, there
will be a corresponding port with the same name, but the `Type` will be
`UpstreamConnection`.
Tip: Only one chassis (the root chassis) will have no `UpstreamConnection` or
`CableUpstreamConnection`. This is enforced by tlBMC and the store will fail to
create if this condition is not true.
Note: In contrast to Entity Manager, "Upstream" and "Downstream" in tlBMC refers
to the relationship of a component that is upstream/downstream of the component
where the port exists. For instance, a root chassis has no `UpstreamConnection`,
but can have many `PortDownstream` since all other components must be downstream
in relation to the root chassis. In traditional Entity Manager,
upstream/downstream refers to the role of the component directly.
An example of a `PortDownstream` port:
```
"Exposes": [
...
{
"Label": "bar",
"Name": "Foo $bus Port",
"Type": "PortDownstream",
"User": "tlbmc"
},
...
],
```
and the corresponding `UpstreamConnection` port:
```
"Exposes": [
...
{
"Name": "Foo $bus Port",
"Type": "UpstreamConnection",
"User": "tlbmc"
},
...
],
```
Note: The name field must match exactly between `PortDownstream` and
`UpstreamConnection` ports. This is how topology is created and `contains` and
`contained_by` associations are populated.
### Substitution
Any fields in the `Exposes` field, including all Port configurations will
support `$bus` and `$index` substitution. This includes substitution with
mathematical expressions. Mathematical expressions are evaluated strictly left
to right in substitution and will stop at the end of the string or first
non-numeric/operator character encountered. An ill-formed mathematical
expression will cause parsing error.
Examples of substitution:
```
Assuming bus = 3,
"Exposes": [
{
"Label": "IO0",
"Name": "Port $bus",
"Type": "PortDownstream",
"REASON": "Valid, simple bus substitution. Evaluates to `Port 3`."
},
{
"Label": "IO0",
"Name": "Port $bus - 5 * 3 + 54",
"Type": "PortDownstream",
"REASON": "Valid, bus substitution with mathematical expression. Evaluates to `Port 48`."
},
{
"Label": "IO0",
"Name": "Port $bus - 5 * 3 + 54 something",
"Type": "PortDownstream",
"REASON": "Valid, simple bus substitution with mathematical expression and remainder. Evaluates to `Port 48 something`."
},
{
"Label": "IO0",
"Name": "Port $bus / 0",
"Type": "PortDownstream",
"REASON": "Invalid, division by zero"
},
{
"Label": "IO0",
"Name": "Port $bus - something",
"Type": "PortDownstream",
"REASON": "Invalid, hanging operator"
}
]
```
### PartLocationType
`PartLocationType` has parity with the `xyz.openbmc_project.Inventory.Connector`
field in existing EM configs.
PartLocationTypes are defined in
[topology_config.proto](https://gbmc.googlesource.com/gbmcweb/+/refs/heads/master/tlbmc/topology_config.proto).
Note: All subfrus MUST have a PartLocationType of PART_LOCATION_TYPE_EMBEDDED.
tlBMC will error if a subfru is misconfigured to not use the embedded type.
An example definition:
```
...
"PartLocationType": "PART_LOCATION_TYPE_SLOT",
...
```
### Processors
`Processor` is a field unique to tlBMC, since these can no longer be detected
through dbus, they must be defined in the static configuration. Processors are
defined in the `Exposes` field of a config, with a `Name` and `"Type":
"Processor"`.
An example definition:
```
"Exposes": [
...
{
"Name": "cpu0",
"Type": "Processor",
"User": "tlbmc"
},
...
],
```
### Storage
`Storage` has parity with the `xyz.openbmc_project.Inventory.Item.Storage`
field. This field is a JSON with a single `Id` field. The storage field is used
to create the link to the associated Storage object in the redfish query
response, the value of `Id` should be the `Id` of the associated Storage object.
An example definition:
```
...
"Storage": {
"Id": "foo_storage_$index"
},
...
```
### Asset
`Asset` has parity with the `xyz.openbmc_project.Inventory.Decorator.Asset`
field in existing EM configs. This field allows users to override the
Manufacturer, Model, PartNumber, or SerialNumber in the redfish response. Valid
substitutions are defined in the same way as in the OpenBMC definition, for
example: `$PRODUCT_PART_NUMBER` or `$BOARD_MANUFACTURER` will substitute the
respective field from the scanned FRU object. Fields can also be overridden with
any string that is not prefixed with `$`.
Tip: if a substitution is attempted (prefixed with `$`) but fails, tlBMC will
error.
An example definition:
```
...
"Asset": {
"Manufacturer": "$BOARD_MANUFACTURER",
"Model": "foo",
"PartNumber": "$BOARD_PART_NUMBER",
"SerialNumber": "$BOARD_SERIAL_NUMBER",
"User": "tlbmc"
},
...
```
### Ad-Hoc Frus
Certain FRUs require special handling as they may not be scannable when bmcweb
comes up. For this purpose, we have created something called an "Ad-Hoc Fru
Scanner". This will allow you to configure exactly how you want to scan a FRU.
An example is below:
```
"AdHocFruConfig": {
"name": "AdHocFru",
"i2c_common_config": {
"bus": "4",
"address": "83"
},
"delay_between_reads": "0.001s",
"periodic_scan_config": [
{
"scan_interval": "10s",
"scan_count": 6
},
{
"scan_interval": "60s",
"scan_count": 9
},
{
"scan_interval": "600s",
"scan_count": 5
}
]
}
```
The proto definition is found
[here](https://gbmc.googlesource.com/gbmcweb/+/refs/heads/master/tlbmc/ad_hoc_fru_config.proto).
> NOTE: This must go inside the ProbeV2 Json Object.
## Subfrus
Some objects are not uniquely FRU-detectable like a regular chassis and are
logically separate from a given chassis, defined in their own EM configuration.
These objects are considered Subfrus.
### Assemblies
Assemblies are subfrus that may have their own devpath, Manufacturer, Serial
Number, Model, etc. Assemblies represent a component that is logically separate
but are not I2C scannable and do not have an eeprom.
An assembly is always defined with `"ResourceType": "RESOURCE_TYPE_ASSEMBLY"`,
this has parity with the `"Type": "Component"` field in existing EM configs.
Assemblies will have PartLocationType of either `PART_LOCATION_TYPE_EMBEDDED` or
`PART_LOCATION_TYPE_SLOT`. This should follow what is in the existing EM config.
* `PART_LOCATION_TYPE_EMBEDDED`: This represents an assembly that is
physically attached to the parent board and cannot be replaced on its own.
An example of this configuration is provided below:
```
{
"Exposes": [
{
"Name": "Foo Sensor Controller 0 Port",
"Type": "UpstreamConnection",
"User": "tlbmc"
},
{
"Name": "foo_0_variant_a_sensors",
"Address": "0x68",
"Bus": "64",
"Labels": [
"vin1",
"iin1",
"pin1"
],
"vin1_Name": "foo_0_a_vin",
"iin1_Name": "foo_0_a_iin",
"pin1_Name": "foo_0_a_pin",
"Type": "XDPE1A2G5B",
"TlbmcOwned": true,
"SkipDbusRead": true
}
],
"Name": "Foo Sensor Controller 0 Var A",
"ProbeV2": {
"IpmiFru": {
"PRODUCT_PRODUCT_NAME": "^Foo_Parent_Variant_A$"
}
},
"ResourceType": "RESOURCE_TYPE_ASSEMBLY",
"PartLocationType": "PART_LOCATION_TYPE_EMBEDDED",
"Type": "Component",
"xyz.openbmc_project.Inventory.Connector.Embedded": {},
"xyz.openbmc_project.Inventory.Decorator.Asset": {
"Manufacturer": "Foo_Manufacturer",
"Model": "Foo_Controller_Model"
}
},
```
* `PART_LOCATION_TYPE_SLOT`: This represents a component that is attached to
the parent chassis through a slot and can be individually replaced, although
it is not FRU detectable.
An example of this configuration is provided below:
```
{
"Exposes": [
{
"Name": "Bar Port",
"Type": "UpstreamConnection",
"User": "tlbmc"
},
{
"Address": "0x42",
"Bus": "21",
"Name": "bar_sensor1",
"Name1": "bar_sensor2",
"Name2": "bar_sensor3",
"Labels": [
"sensor1",
"sensor2",
"sensor3"
],
"Type": "TMP75",
"TlbmcOwned": true,
"SkipDbusRead": true
}
],
"Name": "Bar Assembly",
"ProbeV2": "TRUE",
"ResourceType": "RESOURCE_TYPE_ASSEMBLY",
"PartLocationType": "PART_LOCATION_TYPE_SLOT",
"Type": "Component",
"xyz.openbmc_project.Inventory.Connector.Slot": {},
"Asset": {
"Model": "Bar_Assembly_Model"
}
}
```
Assemblies may have their own sensors defined. These will be propagated to the
parent chassis object since Assemblies cannot directly own sensors. This allows
for sensors that will only be present on certain board variants to be defined in
a separate config without having to duplicate the whole parent board
configuration.
Note: tlBMC does not currently own the Assembly redfish path. The sensor
propagation described above is the only feature supported by tlBMC. Querying
assemblies at `/redfish/v1/Chassis/{ChassisId}/Assembly` will be routed through
non-tlBMC Bmcweb.
An example definition:
```
{
"Exposes": [
{
"Name": "Assembly A Port",
"Type": "UpstreamConnection",
"User": "tlbmc"
},
{
"Name": "variant_a_psu_sensor",
"Address": "0x68",
"Bus": "64",
"Labels": [
"vin1",
"pin1",
"vout1",
"iout1"
],
"vin1_Name": "foo_a_vin",
"pin1_Name": "foo_a_pin",
"vout1_Name": "foo_a_vout",
"iout1_Name": "foo_a_iout",
"Type": "ADM1266",
"TlbmcOwned": true,
"SkipDbusRead": true
}
],
"Name": "Foo Assembly A",
"ProbeV2": {
"IpmiFru": {
"PRODUCT_PRODUCT_NAME": "^FooVariant$"
}
},
"ResourceType": "RESOURCE_TYPE_ASSEMBLY",
"PartLocationType": "PART_LOCATION_TYPE_EMBEDDED",
"Type": "Component",
"xyz.openbmc_project.Inventory.Connector.Embedded": {},
...
},
```
The sensors defined here in the `variant_a_psu_sensor` config would be
propagated to the parent board, `Foo` which would be expected to have a
`PortDownstream` connection with the name `Assembly A Port`. Note again that
tlBMC does not own Assemblies, but due to `"Type": "Component",` being in the
config, `Foo Assembly A` can be queried under
`/redfish/v1/Chassis/Foo/Assembly`.
## Sensor
Note: For any sensor configuration to be parsed by tlBMC, must add the property
`"TlbmcOwned": true` to the sensor EM config. This **must** be added per sensor.
tlBMC will error if a sensor is marked as TlbmcOwned but is not a supported
type.
### HWMon Temp Sensors
There are no specific changes that need to be made to HWMon Temp Sensor configs
to be compatible with tlBMC.
Not all sensor types are currently supported by tlBMC, see
kSupportedHwmonTempSensorTypes in tlbmc/configs/entity_config_json_impl.cc.
### PSU Sensors
There are no specific changes that need to be made to PSU Sensor configs to be
compatible with tlBMC.
Not all sensor types are currently supported by tlBMC, see
kSupportedPsuSensorTypes in tlbmc/configs/entity_config_json_impl.cc.
### SkipDbusRead Property
For Hwmon Temp Sensors and PSU Sensors, if the dbus interface of the sensor is
not being consumed by other processes such as PID loop, we can stop polling over
dbus to significantly reduce CPU usage on BMC. By adding the property
`"SkipDbusRead": true` in the sensor configuration, the dbus-sensor daemon will
stop polling the sensor. tlBMC backend will still supply the reading as expected
when queried through redfish.
### Fan Controller
All I2C fans need a corresponding fan controller defined in the EM config that
share the bus/address combination as the fans. Without this field, no I2C fans
will be populated.
An example definition:
```
"Exposes": [
...
{
"Address": "0x2c",
"Bus": "34",
"Name": "FAN_CONTROLLER",
"Type": "MAX31790",
"TlbmcOwned": true
},
...
],
```
### I2C Fans (Tach/PWM)
For all I2C configs, there must be a JSON `Connector` field that contains at
least `Pwm` (the index of the fan) and `PwmName` (name of the PWM Fan sensor).
Some configs may already have this present. No other changes are required to
make I2C fans compatible with tlBMC.
An example definition:
```
"Exposes": [
...
{
"Address": "0x2c",
"BindConnector": "fan1_tach_connector",
"Bus": "32",
"Connector": {
"Pwm": 1,
"PwmName": "fan1_pwm"
},
"EntityId": "0x1A",
"EntityInstance": "0x01",
"Index": 1,
"Name": "fan1_tach",
...
}
...
]
```
### Related Item
`RelatedItem` is a field unique to tlBMC, since RelatedItem can no longer be
detected through dbus calls, they must be defined in the static configuration.
The `RelatedItem` of any sensor must be defined as a `RelatedItem` JSON object
within the sensor config. It contains the fields `Id` (the redfish Id of the
related item) and `Type` (the `ResourceType` of the related item). By default,
the related item will be the parent chassis object. This field only needs to be
overridden in the case that the related item should be a different object e.g. a
fan.
An example definition:
```
"Exposes": [
...
{
...
"Name": "fan1_tach",
"RelatedItem": {
"Id": "Fan1",
"Type": "RESOURCE_TYPE_FAN",
"User": "tlbmc"
},
...
}
...
]
```
## Cables
### Cable Downstream/Upstream Connections
Cables are defined in separate EM config files from their associated Chassis,
and are associated through `CableDownstreamConnection` or
`CableUpstreamConnection` type ports in their `Exposes` field. All Cable configs
should have their `ProbeV2` field set to `TRUE` (since Cables cannot be detected
over I2C) and their `ResourceType` set to `RESOURCE_TYPE_CABLE`. The associated
upstream or downstream Chassis must have a port with the opposite connection
type and the same `Name` to form a connection. Also defined in the exposed port
is `CableId`. This field must match the `Name` field in the Cable config.
Note: There is a difference between the `Name` field in the port config (name of
the port) and `CableId`, which should match the `Name` of a Cable config JSON
An example Cable config:
```
{
"Exposes": [
{
"Name": "Foo Cable Downstream",
"CableId": "FooCable",
"Type": "CableUpstreamConnection",
"User": "tlbmc"
},
{
"Name": "Foo Cable Upstream",
"CableId": "FooCable",
"Type": "CableDownstreamConnection",
"User": "tlbmc"
}
],
"Name": "FooCable",
"Probe": "xyz.openbmc_project.Network.EthernetInterface({'InterfaceName': '^foo$', 'LinkUp': true})",
"ProbeV2": "TRUE",
"ResourceType": "RESOURCE_TYPE_CABLE",
"Type": "Cable"
}
```
The upstream chassis exposes a CableDownstreamConnection:
```
"Exposes": {
...
{
"Name": "Foo Cable Downstream",
"CableId": "FooCable",
"Type": "CableDownstreamConnection",
"User": "tlbmc"
},
...
},
```
and the downstream chassis exposes a CableUpstreamConnection:
```
"Exposes": {
...
{
"Name": "Foo Cable Upstream",
"CableId": "FooCable",
"Type": "CableUpstreamConnection",
"User": "tlbmc"
},
...
},
```