Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 100 additions & 32 deletions doc/bmc/bmc_hld.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,30 @@
Board Management Controller (BMC) is a specialized microcontroller embedded on a motherboard. It manages the interface between system management software and hardware. BMC provides out-of-band management capabilities, allowing administrators to monitor and manage hardware remotely.
OpenBMC is an open-source project that provides a Linux-based firmware stack for Board Management Controllers (BMCs). It implements the Redfish standard, allowing for standardized and secure remote management of server hardware. In essence, OpenBMC serves as the software that runs on BMC hardware, utilizing the Redfish API to facilitate efficient hardware management.
Redfish is a standard for managing and interacting with hardware in a datacenter, designed to be simple, secure, and scalable. It works with BMC to provide a RESTful API for remote management of servers. Together, Redfish and BMC enable efficient and standardized hardware management.
In summary, NOS will deal with BMC through the redfish RESTful API.

In summary, when the BMC runs OpenBMC, the Switch-Host NOS interacts with the BMC through the Redfish RESTful API.

When the BMC runs SONiC OS, the Switch-Host NOS interacts with the BMC through Redis over the host–BMC link (`usb0`). The host connects to the Redis instance on the BMC and reads platform data.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't we implement the API's in SONiC Redfish too (barring the dump)? Should be fairly straightforward to implement. This way we keep the API layer clean and do away with the bmc os config too?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As part of the SONiC BMC project architecture, the agreed-upon design was that communication between the host side and the BMC side would be via Redis. Dedicated Redfish endpoints will be added for specific use cases, but those are outside the scope of this PR.

Most of the existing BMC APIs (bmc_base.py) are OpenBMC-specific and are therefore not relevant for SONiC BMC. Examples include session management, resetting the root password, and firmware updates, which in our case will be handled directly on the BMC side.

However, the host still needs access to the BMC EEPROM data so that we can continue supporting the existing show platform bmc eeprom CLI. For that reason, the EEPROM information is retrieved from the SONiC BMC Redis database.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this design needs another look. It exposes the BMCs internal OS details to every hostside consumer instead of encapsulating them behind a stable API abstraction. this way sharing implementation details across layers and tightly couples consumers(of BMC) to the BMC OS internals, which could make maintenance and future changes significantly harder. please think about it


The host selects the communication path at runtime based on `DEVICE_METADATA|bmc.os`.


## 2. BMC flows in SONiC
The implementation is straightforward: SONiC will incorporate a Redfish client as the underlying infrastructure to support the BMC action. This Redfish client object is implemented and initialized at runtime by SONiC itself.

SONiC supports two BMC operating-system cases on the Switch-Host side:

| BMC OS | Transport | Client on Switch-Host |
|--------|-----------|------------------------|
| **OpenBMC** (default) | Redfish over `usb0` / `bmc_addr` | `RedfishClient` (`redfish_client.py`) |
| **SONiC** | Redis over `usb0` / `bmc_addr` | Remote STATE_DB connector (`db_connect_remote`) |

For **OpenBMC**, SONiC incorporates a Redfish client as the underlying infrastructure to support BMC actions.

![general flow](https://github.com/yuazhe/SONiC/blob/90aa83c07c4ae9502a78bd33ce5dc8b8e41b8b7e/images/bmc/bmc_overall_flow.png)

For **SONiC BMC**, the host opens a TCP connection to the BMC Redis instance (STATE_DB, db 6), using the same `bmc_addr` from `bmc.json` / `DEVICE_METADATA|bmc`.
On Switch-BMC systems, Redis is bound to the BMC link IP at startup (see `dockers/docker-database/docker-database-init.sh` and `dockers/docker-database/supervisord.conf.j2`).

## 3. BMC ip address initialization
This is the flow of the bmc ip address configuration:
- device/platform/bmc.json contains bmc_if_name,bmc_if_addr,bmc_addr,bmc_net_mask
Expand All @@ -27,16 +44,19 @@ iface usb0 inet static
![ip address init flow](https://github.com/yuazhe/SONiC/blob/c3912566a589767e43f12d822dc3611734ae84dc/images/bmc/bmc_ip_set_flow.png)


## 3. BMC firmware upgrade flow
## 3. BMC firmware upgrade flow (OpenBMC only)

It requires a new ComponenetBMC object to be added to the component.py

![firmware upgrade flow](https://github.com/yuazhe/SONiC/blob/90aa83c07c4ae9502a78bd33ce5dc8b8e41b8b7e/images/bmc/bmc_firmware_upgrade_flow.png)

## 4. Sonic-platform-common support for bmc

### 4.1 BMC redfish client
The redfish_client.py module provides the RedfishClient class, which facilitates BMC access via cURL requests to Redfish APIs. This class serves as a cURL wrapper for executing various Redfish commands. The class utilizes callback functions to obtain user credentials securely and supports asynchronous task monitoring to handle long-running operations like firmware updates and log dump.
### 4.1 BMC Redfish client (OpenBMC only)

The `redfish_client.py` module provides the `RedfishClient` class, which facilitates BMC access via cURL requests to Redfish APIs. This class serves as a cURL wrapper for executing various Redfish commands. The class utilizes callback functions to obtain user credentials securely and supports asynchronous task monitoring to handle long-running operations like firmware updates and log dump.

Used when `DEVICE_METADATA|bmc.os` is `openbmc` (default).

Key functionalities:
1. Session Management: Handles login and logout operations, ensuring secure sessions with the BMC. It manages tokens and session IDs, and automates re-login if tokens expire.
Expand All @@ -45,35 +65,41 @@ Key functionalities:
4. Error Handling: Maps cURL error codes to RedfishClient error codes, and includes comprehensive error handling and logging.
5. Security: Obfuscates sensitive information such as tokens and passwords in logs and command outputs.

### 4.2 BMC api scope
Because in SONiC, each command will be executed as a separate process, nothing will be shared between 2 commands. This requires 2 separate BMC RF sessions, so to avoid exhausting session numbers, we will have a logout call after each of the commands executed.
Thus, there will be a python decorator used for each API/fucntion, for both login and logout.
```
APIs inherited from Device Base
get_name()
get_presence()
get_model()
get_serial()
get_revision()
get_status()
is_replaceable()

BMC general APIs
Return dictionary (Manufacturer, Model, PartNumber, PowerState, SerialNumber) to show the eeprom info or exception with the failure reason
### 4.2 BMC Redis client (SONiC BMC only)

When the BMC runs SONiC OS, the Switch-Host does not use Redfish. Instead, `bmc_base.py` connects to the BMC Redis instance over the host–BMC link.

Implementation reference: `sonic_py_common.daemon_base.db_connect_remote()` (same pattern as `thermalctld` mirroring thermals to the BMC).

### 4.3 BMC API scope

**APIs inherited from Device Base** — both BMC OS types where applicable:

| API | OpenBMC | SONiC BMC |
|-----|---------|-----------|
| `get_name()` | Yes | Yes |
| `get_presence()` | Yes | Yes |
| `get_model()` | Yes | Yes |
| `get_serial()` | Yes | Yes |
| `get_revision()` | Yes | Yes |
| `get_status()` | Yes | Yes |
| `is_replaceable()` | Yes | Yes |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenBMC and SONiC BMC already provide almost all of the capabilities we need (EEPROM, presence, model/serial, status, version, etc.). For those common capabilities, we should expose a single interface that hides the underlying BMC OS.

The current design seems to push the BMC OS decision into the caller and we need to hard code like this

if (bmc.os == OpenBMC)
use OpenBMC-specific API
else
use SONiC BMC API

That means every consumer now needs to know which BMC OS is running, which creates unnecessary tight coupling.

My proposal :

  • I think we should separate this by capability, not by BMC OS. Common functionality should always be accessed through Redfish (or another common API), regardless of whether the platform is running OpenBMC or SONiC BMC.
  • only genuinely platform specific features should require a platform extension.

The underlying BMC OS should remain an implementation detail. hostside consumers should nt need to know or care about which BMC OS is running.


**BMC general APIs:**

Return dictionary to show the eeprom info or exception with the failure reason
Returns an empty dictionary {} if EEPROM information cannot be retrieved
get_eeprom()

Return string to show the firmware version or exception with the failure reason
Returns 'N/A' if the BMC firmware version cannot be retrieved
get_version()


Returns: A tuple (ret, msg) where:
ret: An integer return code indicating success (0) or failure
msg: A string containing success message or error description
reset_root_password()


Returns: A tuple (ret, (task_id, err_msg)) where:
ret: An integer return code indicating success (0) or failure
task_id: A string containing the Redfish task ID for monitoring
Expand All @@ -90,22 +116,57 @@ get_bmc_debug_log_dump(task_id, filename, path)
param fw_image: string to indicate the path of the firmware image
Returns:A tuple (ret, msg) where:
ret: An integer return code indicating success (0) or failure
msg: A string containing status message about the firmware update

msg: A string containing status message about the firmware update
update_firmware(fw_image)

```
### 4.4 BMC API details

| API | OpenBMC | SONiC BMC | Notes |
|-----|---------|-----------|-------|
| `get_eeprom()` | Yes | Yes | OpenBMC: Redfish dict (`Manufacturer`, `Model`, `PartNumber`, `PowerState`, `SerialNumber`). SONiC BMC: from `EEPROM_INFO`. Returns `{}` on failure. |
| `get_version()` | Yes | **No** | Redfish firmware query only |
| `reset_root_password()` | Yes | **No** | Redfish only |
| `trigger_bmc_debug_log_dump()` | Yes | **No** | Redfish only |
| `get_bmc_debug_log_dump()` | Yes | **No** | Redfish only |
| `update_firmware(fw_image)` | Yes | **No** | Redfish only |

## 5. CLI commands

### 5.1 BMC OS selection

The Switch-Host stores the configured BMC operating system in CONFIG_DB:

- **Table/key**: `DEVICE_METADATA|bmc`
- **Field**: `os`
- **Values**: `openbmc` | `sonic`
- **Default**: `openbmc`

YANG: `leaf os` under `container bmc` in `sonic-device_metadata.yang`.

Runtime API: `sonic_py_common.device_info.get_bmc_os()`.

```
show platform bmc summary
show platform bmc os
---------------------------
openbmc

config bmc os sonic
config bmc os openbmc
```

`config bmc os` writes `DEVICE_METADATA|bmc.os`. Subsequent BMC CLI/API calls on the Switch-Host use Redfish or Redis according to this setting.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why an operator need this API at all ? exposing config bmc os as a configurable option suggests the BMC OS is a runtime choice, which it is not.

I would recommend removing it, or at most exposing it as read only platform metadata. a get is ok but not set . please think about it.


### 5.2 Platform BMC CLIs

```
show platform bmc summary # OpenBMC and SONiC BMC (FirmwareVersion is N/A since it cannot be retrieved without Redfish)
---------------------------
Manufacturer: XXXXX
Model: XXXXX
PartNumber: XXXXX
SerialNumber: XXXXX
PowerState: XXXXX
FirmwareVersion: XXXXX
FirmwareVersion: N/A

show platform firmware status
Component Version Description
Expand All @@ -118,23 +179,30 @@ CPLD2 XXXXXXXXXXXXXXXXXXXXXXXXX CPLD - Complex Programmable Logic Device
CPLD3 XXXXXXXXXXXXXXXXXXXXXXXXX CPLD - Complex Programmable Logic Device
BMC XXXXXXXXXXXXXXXXXXXXXXXXX BMC – Board Management Controller

show platform bmc eeprom
show platform bmc eeprom # OpenBMC and SONiC BMC
---------------------------
Manufacturer: XXXXX
Model: XXXXX
PartNumber: XXXXX
PowerState: XXXXX
SerialNumber: XXXXX

config platform firmware install chassis component BMC fw -y ${BMC_IMAGE}
config platform firmware install chassis component BMC fw -y ${BMC_IMAGE} # OpenBMC only

```

## 6. show techsupport
Bmc dump will be included in the show techsupport, trigger_bmc_debug_log_dump() and get_bmc_debug_log_dump() shall be called by the generate-dump script.

### OpenBMC (Switch-Host techsupport)

On Switch-Host, BMC dump collection via Redfish is **OpenBMC only**. `generate_dump` calls `is_bmc_supported()`, which requires Switch-Host, `bmc.json`, and `get_bmc_os() == openbmc`. When the BMC runs SONiC OS, host-side BMC dump collection is skipped.

For SONiC BMC, collect diagnostics by running `show techsupport` **on the BMC** (local SONiC instance), not from the Switch-Host Redfish path.

`trigger_bmc_debug_log_dump()` and `get_bmc_debug_log_dump()` are called by the generate-dump script on the Switch-Host for OpenBMC only.

### 6.1. Overview
The 'show techsupport' command is extended to collect BMC dump logs via Redfish API.
The Switch-Host `show techsupport` command is extended to collect BMC dump logs via Redfish API when the BMC OS is OpenBMC.
This integration is non-blocking and asynchronous:
It triggers a BMC dump task at the start of the script, then continues with regular
system data collection. Before the script finishes, it collects the dump from BMC
Expand All @@ -146,7 +214,7 @@ do not block or interrupt the standard dump flow.
![show techsupport flow](https://github.com/sonic-net/SONiC/blob/30d7b3524e1e1f25abb4679f7ffa777eabe9f499/images/bmc/show_techsupport_flow.png)

### 6.3 Errors Handling:
- generate_dump check whether BMC is suppported (via bmc.json file). If not, BMC logic is skipped.
- `generate_dump` checks whether BMC Redfish dump is supported: Switch-Host, `bmc.json` present, and `get_bmc_os() == openbmc`. If not, host-side BMC dump logic is skipped.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_bmc_os() == openbmc is not looking good .

ideally , this check should be be in only one place something like "ChassisBase.get_bmc()" ( from bmc.json) , all implementation of subclass creation like vendor specific custom code and transport strategy can grow independently

- Errors in BMC initialization, trigger, or collect phases are caught and logged.
- The timeout in techsupport script for collect_bmc_dump is set to 60 seconds.
In practice, the dump is typically ready before collection begins.
Expand Down