summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick Venture <venture@google.com>2018-09-15 13:08:24 -0700
committerPatrick Venture <venture@google.com>2018-09-15 13:09:18 -0700
commitbaa73da1abaaf05ea1133319405fb2b891825618 (patch)
treeaed872afe6b442a28446a78e49f86be2d22307d0
parente2f7bceeafa1f35aed695b1383250fe18b2a8c38 (diff)
downloadphosphor-ipmi-blobs-baa73da1abaaf05ea1133319405fb2b891825618.tar.gz
phosphor-ipmi-blobs-baa73da1abaaf05ea1133319405fb2b891825618.zip
adds README.md
Adds the design document as a README for the project. Change-Id: Ida502441c0dd0fef7c9a63e9bee69122b7c7e24b Signed-off-by: Patrick Venture <venture@google.com>
-rw-r--r--README.md344
1 files changed, 344 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..997d70d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,344 @@
+# Phosphor Blob Transfer Interface
+
+This document describes the commands implementing a generic blob transfer
+interface. This document does not specify how blobs are stored; that is left up
+to blob-specific implementations. Introduction This mechanism supports reading
+and writing from a generic blob store. This mechanism can be leveraged to
+support firmware upgrades,
+
+The interface defined in this document supports:
+
+* Enumerating blobs
+* Opening a blob for reading or writing
+* Writing blob content
+* Committing a blob
+* Polling until the blob has been committed
+* Closing a blob
+* Reading blob content
+* Deleting a blob
+
+Some blobs will only support a subset of these operations. For example, firmware
+cannot generally be read, as the firmware file is not persisted on the BMC after
+it has been activated.
+
+This specification supports IPMI as a transport layer. This can be quite slow,
+however; IPMI transport speeds range from 23 kbps to 256 kbps. LPC/P2A ("PCI to
+Aspeed") MMIO bridges are currently unsupported. Blob Identifiers Blobs are
+identified by NULL-terminated C strings. This protocol supports
+implementation-specific blob identifiers; some blobs may have single well-known
+names, while others may be defined only by a prefix, with the client specifying
+the rest of the blob name. For example, "/g/bmc_firmware" may represent a single
+well-known blob that supports BMC firmware updates, whereas "/g/skm/[N]" may
+represent an arbitrary number of SKM keys, with the index specified on the host
+when opening the blob.
+
+Blob identifiers are limited based on the maximum size of the IPMI packet. This
+maximum size is platform-dependent; theoretically a packet could be up to 256
+bytes, but some hardware only supports packets up to 64 bytes.
+
+If an identifier is malformed, e.g. does not have a trailing NUL-byte or is
+otherwise unrecognizable by the BMC, an error is returned.
+
+## Commands
+
+The following details each subcommand in the blob spec. In the following, any
+reference to the command body starts after the 3 bytes of OEM header, the 1-byte
+subcommand code, and (in the cases where the command body is non-empty) a
+two-byte CRC over all data that follows in the body.
+
+All non-empty responses should lead with a two-byte CRC. The CRC algorithm is
+CRC-16-CCITT (poly 0x1021).
+
+All multi-byte values are encoded as little-endian. All structs are assumed
+packed. Success codes are returned via the "completion code" field from the IPMI
+spec.
+
+### BmcBlobGetCount (0)
+
+The `BmcBlobGetCount` command expects to receive an empty body. The BMC will
+return the number of enumerable blobs:
+
+```
+struct BmcBlobCountRx {
+ uint16_t crc16;
+ uint32_t blob_count;
+};
+```
+
+### BmcBlobEnumerate (1)
+
+The `BmcBlobEnumerate` command expects to receive a body of:
+
+```
+struct BmcBlobEnumerateTx {
+ uint16_t crc16;
+ uint32_t blob_idx; /* 0-based index of blob to retrieve. */
+};
+```
+
+The BMC will return the corresponding blob identifier:
+
+```
+struct BmcBlobEnumerateRx {
+ uint16_t crc16;
+ char blob_id[];
+};
+```
+
+Note that the index for a given blob ID is not expected to be stable across a
+long term. Callers are expected to call `BmcBlobGetCount`, followed by N calls
+to `BmcBlobEnumerate`, to collect all blob IDs. Callers can then call
+`BmcBlobStat` with each blob ID. If this process is interleaved with Open or
+Delete calls that modify the number of enumerable blobs, this operation will be
+subject to concurrent modification issues.
+
+### BmcBlobOpen (2)
+
+The BmcBlobOpen command expects to receive a body of:
+
+```
+struct BmcBlobOpenTx {
+ uint16_t crc16;
+ uint16_t flags;
+ char blob_id[]; /* Must correspond to a valid blob. */
+};
+```
+
+The flags field allows the caller to specify whether the blob is being opened
+for reading or writing:
+
+```
+enum BmcBlobOpenFlagBits {
+ READ = 0,
+ WRITE = 1,
+ <bits 2-7 reserved>
+ <bits 8-15 given blob-specific definitions>
+};
+```
+
+If the `WRITE` flag is specified, the BMC will mark the specified blob as "open
+for writing". Optional blob-specific behavior: if the blob has been open for
+more than one minute without any activity, the existing session will be torn
+down and the open will succeed. Alternatively, blobs may allow multiple write
+sessions to be active at once.
+
+The BMC allocates a unique session identifier, and internally maps it to the
+blob identifier.
+
+```
+struct BmcBlobOpenRx {
+ uint16_t crc16;
+ uint16_t session_id;
+};
+```
+
+### BmcBlobRead (3)
+
+The BmcBlobRead command is used to read blob data. It expects to receive a body
+of:
+
+```
+struct BmcBlobReadTx {
+ uint16_t crc16;
+ uint16_t session_id; /* Returned from BmcBlobOpen. */
+ uint32_t offset; /* The byte sequence start, 0-based. */
+ uint32_t requested_size; /* The number of bytes requested for reading. */
+};
+```
+
+Blob handlers may require the blob’s "state" to equal `OPEN_R` before reading is
+successful.
+
+```
+struct BmcBlobReadRx {
+ uint16_t crc16;
+ uint8_t data[];
+};
+```
+
+Immediately following this structure are the bytes being read. The number of
+bytes transferred is the size of the response body less the OEN ("OEM number")
+(3 bytes), sub-command (1 byte), and the structure size (4 bytes). If no bytes
+are transferred, the CRC is still sent.
+
+If the BMC cannot return the number of requested bytes, it simply returns the
+number of bytes available for reading. If the host tries to read at an invalid
+offset or if the host tries to read at the end of the blob, an empty successful
+response is returned; e.g., data is empty.
+
+### BmcBlobWrite (4)
+
+The `BmcBlobWrite` command expects to receive a body of:
+
+```
+struct BmcBlobWriteTx {
+ uint16_t crc16;
+ uint16_t session_id; /* Returned from BmcBlobOpen. */
+ uint32_t offset; /* The byte sequence start, 0-based. */
+ uint8_t data[];
+};
+```
+
+Immediately following this structure are the bytes to write. The length of the
+entire packet is variable and handled at a higher level, therefore the number of
+bytes to write is the size of the command body less the OEN and sub-command (4
+bytes) and less the structure size (10 bytes). It is assumed that all writes are
+sequential, and begin at offset zero.
+
+On success it will return a success completion code.
+
+### BmcBlobCommit (5)
+
+The `BmcBlobCommit` command expects to receive a body of:
+
+```
+struct BmcBlobCommitTx {
+ uint16_t crc16;
+ uint16_t session_id; /* Returned from BmcBlobOpen. */
+ uint8_t commit_data_len;
+ uint8_t commit_data[]; /* Optional blob-specific commit data. */
+};
+```
+
+Each blob defines its own commit behavior. A BMC firmware blob may be verified
+and saved to the filesystem. Commit operations may require additional
+data, which
+would be provided following the structure in the IPMI packet.
+
+The commit operation may exceed the IPMI timeout duration of ~5 seconds
+(implementation dependant). Callers are expected to poll on `BmcBlobSessionStat`
+or `BmcBlobStat` (as appropriate) until committing has finished. To address race
+conditions, blobs should not allow concurrent sessions that modify state.
+
+On success, the BMC returns success completion code.
+
+### BmcBlobClose (6)
+
+The `BmcBlobClose` command must be called after commit-polling has finished,
+regardless of the result. It expects to receive a body of:
+
+```
+struct BmcBlobCloseTx {
+ uint16_t crc16;
+ uint16_t session_id; /* Returned from BmcBlobOpen. */
+};
+```
+
+The BMC marks the specified blob as closed. On success, the BMC returns a
+success completion code.
+
+### BmcBlobDelete (7)
+
+The `BmcBlobDelete` command is used to delete a blob. Not all blobs will support
+deletion. This command expects to receive a body of:
+
+```
+struct BmcBlobDeleteTx {
+ uint16_t crc16;
+ char blob_id[]; /* Must correspond to a valid blob. */
+};
+```
+
+If the operation is supported, the blob is deleted. On success, the BMC returns
+a success completion code. This command will fail if there are open sessions for
+the blob.
+
+### BmcBlobStat (8)
+
+The `BmcBlobStat` command is used to retrieve statistics about a blob. Not all
+blobs must support this command; this is only useful when blob_id semantics are
+more useful than session IDs. This command expects to receive a body of:
+
+```
+struct BmcBlobStatTx {
+ uint16_t crc16;
+ char blob_id[]; /* Must correspond to a valid blob. */
+};
+```
+
+The BMC returns the following data:
+
+```
+struct BmcBlobStatRx {
+ uint16_t crc16;
+ uint16_t blob_state;
+ uint32_t size; /* Size in bytes of the blob. */
+ uint8_t metadata_len;
+ uint8_t metadata[]; /* Optional blob-specific metadata. */
+};
+```
+
+The blob_state field is a bit field with the following flags:
+
+```
+enum BmcBlobStateFlagBits {
+ OPEN_R = 0,
+ OPEN_W = 1,
+ COMMITTING = 2,
+ COMMITTED = 3,
+ COMMIT_ERROR = 4,
+ <bits 5-7 reserved>
+ <bits 8-15 given blob-specific definitions>
+};
+```
+
+If the state is `COMMITTING`, the blob is not currently available for reading or
+writing. If the state is `COMMITTED`, the blob may be available for reading.
+
+The size field may be zero if the blob does not support reading.
+
+Immediately following this structure are optional blob-specific bytes. The
+number of bytes transferred is the size of the response body less the OEN and
+sub-command and less the structure size. The metadata must fit in a single IPMI
+packet, which has a platform-dependent maximum size. (For reference, Aspeed
+supports 64 bytes max.)
+
+If the blob is open or committed but has been inactive for longer than the
+specified activity timeout, the blob is closed, and blob_status is set to
+`CLOSED` in the response.
+
+### BmcBlobSessionStat (9)
+
+The `BmcBlobSessionStat` command returns the same data as `BmcBlobStat`.
+However, this command operates on sessions, rather than blob IDs. Not all blobs
+must support this command; this is only useful when session semantics are more
+useful than raw blob IDs.
+
+```
+struct BmcBlobSessionStatTx {
+ uint16_t crc16;
+ uint16_t session_id; /* Returned from BmcBlobOpen. */
+};
+```
+
+```
+struct BmcBlobSessionStatRx {
+ uint16_t crc16;
+ uint16_t blob_state;
+ uint32_t size; /* Size in bytes of the blob. */
+ uint8_t metadata_size;
+ uint8_t metadata[]; /* Optional blob-specific metadata. */
+};
+```
+
+## Idempotent Commands
+
+The IPMI transport layer is somewhat flaky. Client code must rely on a
+"send-with-retries" strategy to ensure that commands make their way from the
+host to the BMC. Commands can fail if the BMC is busy with other commands.
+
+It is possible that an IPMI command successfully invokes the BMC-side handler,
+but that the response does not successfully make its way back to the host. In
+this case, the host may decide to retry the command. Thus, command handlers
+should be idempotent where possible; duplicate calls should return the same
+value if repeated, while avoiding potentially destructive side-effects.
+
+## Stale Sessions
+
+Each blob type will define an operation for cleansing stale sessions. This could
+involve scrubbing secrets or freeing buffers. A function will be provided that
+will scan over each open session, to determine which if any sessions have been
+open for longer than 10 minutes with no activity. For each session, the
+associated blob type’s cleansing routine will be invoked, and the associated
+session ID will be freed. This function will be invoked from the `BmcBlobOpen`
+command handler, though not more than once every minute.
OpenPOWER on IntegriCloud