Name Date Size #Lines LOC

..Today-

blobs-ipmid/H21-Oct-2023-19575

example/H21-Oct-2023-299217

internal/H07-Mar-2021-10144

subprojects/H15-Aug-2023-2216

test/H21-Oct-2023-2,5201,756

.clang-formatH A D21-Oct-20233.6 KiB136134

.gitignoreH A D22-Jun-202125 32

.lcovrcH A D07-Mar-202180 43

LICENSEH A D07-Mar-202111.1 KiB202169

OWNERSH A D22-Jul-20221.7 KiB5348

README.mdH A D08-Dec-202212.6 KiB384299

fs.cppH A D07-Mar-20211.2 KiB4722

fs.hppH A D07-Mar-2021620 2410

ipmi.cppH A D11-May-20238.9 KiB316222

ipmi.hppH A D11-May-20234.5 KiB206106

main.cppH A D11-May-20232.1 KiB7343

manager.cppH A D21-Oct-20238.1 KiB342234

manager.hppH A D11-May-20239.3 KiB29499

meson.buildH A D15-Aug-20231.7 KiB8168

meson.optionsH A D17-Aug-2023141 32

process.cppH A D11-May-20235.6 KiB184116

process.hppH A D11-May-20231.3 KiB4918

utils.cppH A D11-May-20232.8 KiB10569

utils.hppH A D07-Mar-2021942 3512

README.md

1# Phosphor Blob Transfer Interface
2
3This document describes the commands implementing a generic blob transfer
4interface. This document does not specify how blobs are stored; that is left up
5to blob-specific implementations. Introduction This mechanism supports reading
6and writing from a generic blob store. This mechanism can be leveraged to
7support firmware upgrades,
8
9The interface defined in this document supports:
10
11- Enumerating blobs
12- Opening a blob for reading or writing
13- Writing blob content
14- Committing a blob
15- Polling until the blob has been committed
16- Closing a blob
17- Reading blob content
18- Deleting a blob
19
20Some blobs will only support a subset of these operations. For example, firmware
21cannot generally be read, as the firmware file is not persisted on the BMC after
22it has been activated.
23
24This specification supports IPMI as a transport layer. This can be quite slow,
25however; IPMI transport speeds range from 23 kbps to 256 kbps. LPC/P2A ("PCI to
26Aspeed") MMIO bridges are currently unsupported. Blob Identifiers Blobs are
27identified by NULL-terminated C strings. This protocol supports
28implementation-specific blob identifiers; some blobs may have single well-known
29names, while others may be defined only by a prefix, with the client specifying
30the rest of the blob name. For example, "/g/bmc_firmware" may represent a single
31well-known blob that supports BMC firmware updates, whereas "/g/skm/[N]" may
32represent an arbitrary number of SKM keys, with the index specified on the host
33when opening the blob.
34
35Blob identifiers are limited based on the maximum size of the IPMI packet. This
36maximum size is platform-dependent; theoretically a packet could be up to 256
37bytes, but some hardware only supports packets up to 64 bytes.
38
39If an identifier is malformed, e.g. does not have a trailing NUL-byte or is
40otherwise unrecognizable by the BMC, an error is returned.
41
42The OEM Number to use with these commands is
43[openbmc oen](https://github.com/openbmc/phosphor-host-ipmid/blob/194375f2676715a0e0697bab63234a4efe39fb96/include/ipmid/iana.hpp#L12) 49871.
44
45## Commands
46
47The following details each subcommand in the blob spec. In the following, any
48reference to the command body starts after the 3 bytes of OEM header, the 1-byte
49subcommand code, and (in the cases where the command body is non-empty) a
50two-byte CRC over all data that follows in the body.
51
52All non-empty responses should lead with a two-byte CRC. The CRC algorithm is
53CRC-16-CCITT (poly 0x1021).
54
55All multi-byte values are encoded as little-endian. All structs are assumed
56packed. Success codes are returned via the "completion code" field from the IPMI
57spec.
58
59### BmcBlobGetCount (0)
60
61The `BmcBlobGetCount` command expects to receive an empty body. The BMC will
62return the number of enumerable blobs:
63
64```cpp
65struct BmcBlobCountRx {
66    uint16_t crc16;
67    uint32_t blob_count;
68};
69```
70
71### BmcBlobEnumerate (1)
72
73The `BmcBlobEnumerate` command expects to receive a body of:
74
75```cpp
76struct BmcBlobEnumerateTx {
77    uint16_t crc16;
78    uint32_t blob_idx; /* 0-based index of blob to retrieve. */
79};
80```
81
82The BMC will return the corresponding blob identifier:
83
84```cpp
85struct BmcBlobEnumerateRx {
86    uint16_t crc16;
87    char     blob_id[];
88};
89```
90
91Note that the index for a given blob ID is not expected to be stable across a
92long term. Callers are expected to call `BmcBlobGetCount`, followed by N calls
93to `BmcBlobEnumerate`, to collect all blob IDs. Callers can then call
94`BmcBlobStat` with each blob ID. If this process is interleaved with Open or
95Delete calls that modify the number of enumerable blobs, this operation will be
96subject to concurrent modification issues.
97
98### BmcBlobOpen (2)
99
100The BmcBlobOpen command expects to receive a body of:
101
102```cpp
103struct BmcBlobOpenTx {
104    uint16_t crc16;
105    uint16_t flags;
106    char     blob_id[]; /* Must correspond to a valid blob. */
107};
108```
109
110The flags field allows the caller to specify whether the blob is being opened
111for reading or writing:
112
113```cpp
114enum BmcBlobOpenFlagBits {
115    READ = 0,
116    WRITE = 1,
117    <bits 2-7 reserved>
118    <bits 8-15 given blob-specific definitions>
119};
120```
121
122If the `WRITE` flag is specified, the BMC will mark the specified blob as "open
123for writing". Optional blob-specific behavior: if the blob has been open for
124more than one minute without any activity, the existing session will be torn
125down and the open will succeed. Alternatively, blobs may allow multiple write
126sessions to be active at once.
127
128The BMC allocates a unique session identifier, and internally maps it to the
129blob identifier.
130
131```cpp
132struct BmcBlobOpenRx {
133    uint16_t crc16;
134    uint16_t session_id;
135};
136```
137
138### BmcBlobRead (3)
139
140The BmcBlobRead command is used to read blob data. It expects to receive a body
141of:
142
143```cpp
144struct BmcBlobReadTx {
145    uint16_t crc16;
146    uint16_t session_id; /* Returned from BmcBlobOpen. */
147    uint32_t offset; /* The byte sequence start, 0-based. */
148    uint32_t requested_size; /* The number of bytes requested for reading. */
149};
150```
151
152Blob handlers may require the blob’s "state" to equal `OPEN_R` before reading is
153successful.
154
155```cpp
156struct BmcBlobReadRx {
157    uint16_t crc16;
158    uint8_t  data[];
159};
160```
161
162Immediately following this structure are the bytes being read. The number of
163bytes transferred is the size of the response body less the OEN ("OEM number")
164(3 bytes), sub-command (1 byte), and the structure size (4 bytes). If no bytes
165are transferred, the CRC is still sent.
166
167If the BMC cannot return the number of requested bytes, it simply returns the
168number of bytes available for reading. If the host tries to read at an invalid
169offset or if the host tries to read at the end of the blob, an empty successful
170response is returned; e.g., data is empty.
171
172### BmcBlobWrite (4)
173
174The `BmcBlobWrite` command expects to receive a body of:
175
176```cpp
177struct BmcBlobWriteTx {
178    uint16_t crc16;
179    uint16_t session_id; /* Returned from BmcBlobOpen. */
180    uint32_t offset; /* The byte sequence start, 0-based. */
181    uint8_t  data[];
182};
183```
184
185Immediately following this structure are the bytes to write. The length of the
186entire packet is variable and handled at a higher level, therefore the number of
187bytes to write is the size of the command body less the OEN and sub-command (4
188bytes) and less the structure size (10 bytes). It is assumed that all writes are
189sequential, and begin at offset zero.
190
191On success it will return a success completion code.
192
193### BmcBlobCommit (5)
194
195The `BmcBlobCommit` command expects to receive a body of:
196
197```cpp
198struct BmcBlobCommitTx {
199    uint16_t crc16;
200    uint16_t session_id; /* Returned from BmcBlobOpen. */
201    uint8_t  commit_data_len;
202    uint8_t  commit_data[]; /* Optional blob-specific commit data. */
203};
204```
205
206Each blob defines its own commit behavior. A BMC firmware blob may be verified
207and saved to the filesystem. Commit operations may require additional data,
208which would be provided following the structure in the IPMI packet.
209
210The commit operation may exceed the IPMI timeout duration of ~5 seconds
211(implementation dependant). Callers are expected to poll on `BmcBlobSessionStat`
212or `BmcBlobStat` (as appropriate) until committing has finished. To address race
213conditions, blobs should not allow concurrent sessions that modify state.
214
215On success, the BMC returns success completion code.
216
217### BmcBlobClose (6)
218
219The `BmcBlobClose` command must be called after commit-polling has finished,
220regardless of the result. It expects to receive a body of:
221
222```cpp
223struct BmcBlobCloseTx {
224    uint16_t crc16;
225    uint16_t session_id; /* Returned from BmcBlobOpen. */
226};
227```
228
229The BMC marks the specified blob as closed. On success, the BMC returns a
230success completion code.
231
232### BmcBlobDelete (7)
233
234The `BmcBlobDelete` command is used to delete a blob. Not all blobs will support
235deletion. This command expects to receive a body of:
236
237```cpp
238struct BmcBlobDeleteTx {
239    uint16_t crc16;
240    char     blob_id[]; /* Must correspond to a valid blob. */
241};
242```
243
244If the operation is supported, the blob is deleted. On success, the BMC returns
245a success completion code. This command will fail if there are open sessions for
246the blob.
247
248### BmcBlobStat (8)
249
250The `BmcBlobStat` command is used to retrieve statistics about a blob. Not all
251blobs must support this command; this is only useful when blob_id semantics are
252more useful than session IDs. This command expects to receive a body of:
253
254```cpp
255struct BmcBlobStatTx {
256    uint16_t crc16;
257    char     blob_id[]; /* Must correspond to a valid blob. */
258};
259```
260
261The BMC returns the following data:
262
263```cpp
264struct BmcBlobStatRx {
265    uint16_t crc16;
266    uint16_t blob_state;
267    uint32_t size; /* Size in bytes of the blob. */
268    uint8_t  metadata_len;
269    uint8_t  metadata[]; /* Optional blob-specific metadata. */
270};
271```
272
273The blob_state field is a bit field with the following flags:
274
275```cpp
276enum BmcBlobStateFlagBits {
277    OPEN_R = 0,
278    OPEN_W = 1,
279    COMMITTING = 2,
280    COMMITTED = 3,
281    COMMIT_ERROR = 4,
282    <bits 5-7 reserved>
283    <bits 8-15 given blob-specific definitions>
284};
285```
286
287If the state is `COMMITTING`, the blob is not currently available for reading or
288writing. If the state is `COMMITTED`, the blob may be available for reading.
289
290The size field may be zero if the blob does not support reading.
291
292Immediately following this structure are optional blob-specific bytes. The
293number of bytes transferred is the size of the response body less the OEN and
294sub-command and less the structure size. The metadata must fit in a single IPMI
295packet, which has a platform-dependent maximum size. (For reference, Aspeed
296supports 64 bytes max.)
297
298If the blob is open or committed but has been inactive for longer than the
299specified activity timeout, the blob is closed, and blob_status is set to
300`CLOSED` in the response.
301
302### BmcBlobSessionStat (9)
303
304The `BmcBlobSessionStat` command returns the same data as `BmcBlobStat`.
305However, this command operates on sessions, rather than blob IDs. Not all blobs
306must support this command; this is only useful when session semantics are more
307useful than raw blob IDs.
308
309```cpp
310struct BmcBlobSessionStatTx {
311    uint16_t crc16;
312    uint16_t session_id; /* Returned from BmcBlobOpen. */
313};
314```
315
316```cpp
317struct BmcBlobSessionStatRx {
318    uint16_t crc16;
319    uint16_t blob_state;
320    uint32_t size; /* Size in bytes of the blob. */
321    uint8_t  metadata_size;
322    uint8_t  metadata[]; /* Optional blob-specific metadata. */
323};
324```
325
326### BmcBlobWriteMeta (10)
327
328The `BmcBlobWriteMeta` command behaves like `BmcBlobWrite`. Its purpose is
329blob-specific, and not all blobs must support it.
330
331The `BmcBlobWriteMeta` command expects to receive a body of:
332
333```cpp
334struct BmcBlobWriteMetaTx
335{
336    uint16_t crc16;
337    uint16_t session_id; /* Returned from BmcBlobOpen. */
338    uint32_t offset; /* The byte sequence start, 0-based. */
339    uint8_t  data[];
340};
341```
342
343Immediately following this structure are the bytes to write. The length of the
344entire packet is variable and handled at a higher level, therefore the number of
345bytes to write is the size of the command body less the OEN and sub-command (4
346bytes) and less the structure size.
347
348On success it will return a success completion code.
349
350## Idempotent Commands
351
352The IPMI transport layer is somewhat flaky. Client code must rely on a
353"send-with-retries" strategy to ensure that commands make their way from the
354host to the BMC. Commands can fail if the BMC is busy with other commands.
355
356It is possible that an IPMI command successfully invokes the BMC-side handler,
357but that the response does not successfully make its way back to the host. In
358this case, the host may decide to retry the command. Thus, command handlers
359should be idempotent where possible; duplicate calls should return the same
360value if repeated, while avoiding potentially destructive side-effects.
361
362## Stale Sessions
363
364Each blob type will define an operation for cleansing stale sessions. This could
365involve scrubbing secrets or freeing buffers. A function will be provided that
366will scan over each open session, to determine which if any sessions have been
367open for longer than 10 minutes with no activity. For each session, the
368associated blob type’s cleansing routine will be invoked, and the associated
369session ID will be freed. This function will be invoked from the `BmcBlobOpen`
370command handler, though not more than once every minute.
371
372## Handler Calling Contract
373
374The blob manager provides the following calling contract guarantees:
375
376- The blob manager will only call `open()` on your handler if the handler
377  responds that they can handle the path.
378- The blob manager will only call a session-based command against your handler
379  if that session is already open (e.g. `stat()` or `commit()`).
380  - The caveat is the open command where the session is provided to the handler
381    within the call.
382- The blob manager will only call `delete()` on a blob if there are no open
383  sessions to that blob id.
384