xref: /openbmc/docs/designs/virtual-media.md (revision 0473e2c9)
1# Virtual Media (a.k.a. Remote Media)
2
3Author:
4Pawel Rapkiewicz <pawel.rapkiewicz@intel.com> <pawelr>
5
6Primary assignee:
7None
8
9Other contributors:
10Przemyslaw Czarnowski <przemyslaw.hawrylewicz.czarnowski@intel.com>
11
12Created:
136/4/2019
14
15## Problem Description
16
17Virtual Media allows users to remotely mount given ISO/IMG drive images through
18BMC to Server HOST. The Remote drive is visible in HOST as USB storage device,
19and operates in RO mode, or RW mode (keeping in mind container limitations,
20and write protection switches). This can even be used to install OS on bare
21metal system. This document focuses on few redirection options, like in-browser
22ISO/IMG image mounting, and remote CIFS/HTTPS image mounting.
23
24## References
25
26* Virtual Media is going to use Network Block Device as primary disk image
27forwarder.
28* NBDkit is being used, to serve images from remote storages over HTTPS/CIFS.
29USBGadget as way to expose Media Storage Device to HOST.
30
31## Requirements
32None
33
34## Proposed Design
35
36Virtual Media splits into two modes of operation, lets call it Proxy, and
37Legacy.
38
39* Proxy mode - works directly from browser and uses JavaScript/HTML5 to
40communicate over Secure WebSockets directly to HTTPS endpoint hosted by bmcweb
41on BMC.
42* Legacy mode - is initiated from browser using Redfish defined VirtualMedia
43schemas, then BMC process connects to external CIFS/HTTPS image pointed during
44initialization.
45
46Both methods inherit from default Redfish/BMCWeb authentication and privileges
47mechanisms.
48
49The component diagram below shows Virtual Media high-level overview
50
51```ascii
52+------------------+           +----------------------------------+     +-----------------------+
53|Remote Device|    |           |BMC|              +------------+  |     |HOST|                  |
54+-------------/    |           +---/ +--Dbus----->+VirtualMedia|  |     +----/                  |
55|                  |           |     v            +------------+  |     |                       |
56|  +------------+  |           |   +-+--------+                   |     |                       |
57|  |WebBrowser  +<----HTTPS------->+BMCWeb    |      +---------+  |     |  +----------+         |
58|  +------------+  |           |   +-+--------+      |USBGadget+<--------->+USB Device|         |
59+------------------+           |     ^               +----+----+  |     |  +----------+         |
60                               |     |                    ^       |     |                       |
61                               |     |    +------+        v       |     |                       |
62                               |     +--->+UNIX  |   +----+----+  |     |                       |
63                               |          |SOCKET+<->+NBDClient|  |     |                       |
64+------------------+           |     +--->+      |   +---------+  |     |                       |
65|Remote Storage|   |           |     |    +------+                |     |                       |
66+--------------/   |           |     |                            |     |                       |
67|                  |           |     v                            |     |                       |
68|   +-----------+  |           |   +-+-------+                    |     |                       |
69|   |ISO/IMG    +<---CIFS/HTTPS+-->+NBDkit   |                    |     |                       |
70|   +-----------+  |           |   +---------+                    |     +-----------------------+
71|                  |           |                                  |
72+------------------+           +----------------------------------+
73```
74
75Virtual Media feature supports multiple, simultaneous connections in both
76modes.
77
78### Network Block Device (NBD)
79
80Reader can notice that most connections on diagram are based on Network Block
81Device. After Sourceforge project description:
82
83> With this compiled into your kernel, Linux can use a remote server as one of
84> its block devices. Every time the client computer wants to read /dev/nbd0,
85> it will send a request to the server via TCP, which will reply with the data
86> requested. This can be used for stations with low disk space (or even
87> diskless - if you use an initrd) to borrow disk space from other computers.
88> Unlike NFS, it is possible to put any file system on it. But (also unlike
89> NFS), if someone has mounted NBD read/write, you must assure that no one else
90> will have it mounted.
91>
92> -- [https://nbd.sourceforge.io/](https://nbd.sourceforge.io/)
93
94In Virtual Media use case, it's being used to pull data from remote client, and
95present it into non BMC mounted `/dev/nbdXX` device. Then the block device is
96being provided to Host through USB Gadget.
97
98### USB Gadget
99
100Part of Linux kernel that makes *emulation* of certain USB device classes
101possible through USB "On-The-Go", if connect appropriately to Host. In Virtual
102Media case it emulates USB mass storage connected to HOST. The source or
103redirection is block device created by nbd-client `/dev/nbdXX`
104
105### Proxy Mode
106
107Proxy Mode uses browser JavaScript and WebSockets support, to create JS NBD
108Server. Browser is responsible for create HTTPS session, authenticate user, and
109receive given privileges, then upgrade HTTPS session to WSS, through mechanisms
110described by [RFC6455](HTTPS://tools.ietf.org/html/rfc6455). Since WSS upgrade,
111JS application is responsible for handling all required by specification NBD
112Server commands.
113
114Multiple, simultaneous connections are supported per opening connections on
115different URIs in HTTPS server. Number of available simultaneous connections is
116being defined in configuration file described in next chapter.
117
118Encryption for proxy is supported through HTTPS/WSS channel and inherits
119encryption mechanisms directly from HTTPS server, all data transactions go
120through bmcweb.
121
122The initialization of connection will look as on diagram:
123
124```ascii
125┌───────┐                  ┌──────┐       ┌────────────┐          ┌─────────┐   ┌────┐ ┌─────────┐
126│Browser│                  │bmcweb│       │VirtualMedia│          │NBDClient│   │uDEV│ │USBGadget│
127└───┬───┘                  └──┬───┘       └─────┬──────┘          └────┬────┘   └─┬──┘ └────┬────┘
128    │ establish HTTPS session │                 │                      │          │         │
129    │─────────────────────────>                 │                      │          │         │
130    │                         │                 │                      │          │         │
131    │   upgrade to WSS on     │                 │                      │          │         │
132    │    /nbd/X endpoint      │  ╔══════════════╧════╗                 │          │         │
133    │─────────────────────────>  ║* bmcweb creates  ░║                 │          │         │
134    │                         │  ║  /tmp/nbd.X.sock  ║                 │          │         │
135    │                         │  ║* bmcweb locks new ║                 │          │         │
136    │                         │  ║  connections on   ║                 │          │         │
137    │                         │  ║  endpoint /nbd/X  ║                 │          │         │
138    │                         │  ╚══════════════╤════╝                 │          │         │
139    │                         │    Mount from:  │                      │          │         │
140    │                         │ /tmp/nbd.X.sock │                      │          │         │
141    │                         │ ────────────────>                      │          │         │
142    │                         │                 │                      │          │         │
143    │                         │                 │ Spawn NBDClient from │          │         │
144    │                         │                 │    /tmp/nbd.x.sock   │          │         │
145    │                         │                 │      to /dev/nbdX   ┌┴┐         │         │
146    │                         │                 │ ──────────────────> │ │         │         │
147    │                         │                 │                     │ │         │         │
148    │                         │                 │     Block Device    │ │         │         │
149    │                         │                 │  properties changed │ │         │         │
150    │                         │                 │ <───────────────────────────────│         │
151    │                         │                 │                     │ │         │         │
152    │                         │                 │      Configure USB mass         │         │
153    │                         │                 │    storage from /dev/nbd/X      │         │
154    │                         │                 │ ─────────────────────────────────────────>│
155    │                         │                 │                     │ │         │         │
156    │                         │                 │         Data        │ │         │         │
157    │<─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─>│
158    │                         │                 │                     │ │         │         │
159```
160
161### Legacy Mode
162
163Legacy Mode uses VirtualMedia schema, defined by DMTF, for mounting external
164CIFS/HTTPS images. The current implementation supports only stream mounting
165as for now. In this case Redfish is only used as mechanism for Virtual Media
166initialization, and is not responsible for data transmission. For data there
167is a separate component responsible for handling CIFS/HTTPS traffic called
168NBDkit.
169
170Multiple, simultaneous connections are supported through spawning additional
171nbkit instances, the number of available instances for CIFS/HTTPS is configured
172and described in details in next chapter.
173
174Encryption is based on remote storage connection, and follows Intel's Best
175security practices, as remote server support such (i.e. HTTPS requires SSL, and
176pure HTTP is not supported, for CIFS protocol version 3.0 allows enabling
177encryption and that will be provided).
178
179The flow looks like below:
180
181```ascii
182┌───────┐  ┌──────────┐  ┌──────┐  ┌────────────┐           ┌──────┐┌─────────┐┌────┐ ┌─────────┐
183│Browser│  │CIFS/HTTPS│  │bmcweb│  │VirtualMedia│           │NBDkit││NBDClient││uDEV│ │USBGadget│
184└───┬───┘  └────┬─────┘  └──┬───┘  └─────┬──────┘           └──┬───┘└────┬────┘└─┬──┘ └────┬────┘
185    │establish HTTPS session│            │                     │         │       │         │
186    │───────────────────────>            │                     │         │       │         │
187    │           │           │            │                     │         │       │         │
188    │Create new VirtualMedia│            │                     │         │       │         │
189    │  mountpoint via POST  │            │                     │         │       │         │
190    │───────────────────────>            │                     │         │       │         │
191    │           │           │            │                     │         │       │         │
192    │           │           │ Mount from │                     │         │       │         │
193    │           │           │ CIFS/HTTPS │                     │         │       │         │
194    │           │           │  location  │                     │         │       │         │
195    │           │           │────────────>                     │         │       │         │
196    │           │           │            │                     │         │       │         │
197    │           │           │            │Spawn NBDKit mounting│         │       │         │
198    │           │           │            │    given location   │         │       │         │
199    │           │           │            │     appropriate     │         │       │         │
200    │           │           │            │   /tmp/nbd.X.sock  ┌┴┐        │       │         │
201    │           │           │            │ ──────────────────>│ │        │       │         │
202    │           │           │            │                    │ │        │       │         │
203    │           │           │            │      Spawn NBDClient from     │       │         │
204    │           │           │            │ /tmp/nbd.X.sock to /dev/nbdX ┌┴┐      │         │
205    │           │           │            │ ────────────────────────────>│ │      │         │
206    │           │           │            │                    │ │       │ │      │         │
207    │           │           │            │    Block Device properties changed    │         │
208    │           │           │            │ <──────────────────────────────────────         │
209    │           │           │            │                    │ │       │ │      │         │
210    │           │           │            │    Configure USB mass storage from /dev/nbd/X   │
211    │           │           │            │ ───────────────────────────────────────────────>│
212    │           │           │            │                    │ │       │ │      │         │
213    │           │           │            │               Data │ │       │ │      │         │
214    │           │ <─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─>│
215```
216
217### Redfish support
218
219Virtual Media Service will be exposed as Redfish VirtualMedia endpoint as
220defined by DMTF. Here are some examples.
221
222#### Virtual Media Collection schema
223Members in collection will be defined based on configuration file described in
224next sections. And will be visible despite media is inserted or not.
225
226```json
227{
228    "@odata.type": "#VirtualMediaCollection.VirtualMediaCollection",
229    "Name": "Virtual Media Services",
230    "Description": "Redfish-BMC Virtual Media Service Settings",
231    "Members@odata.count": 2,
232    "Members": [
233        {
234            "@odata.id": "/redfish/v1/Managers/BMC/VirtualMedia/ISO0"
235        } ,
236        {
237            "@odata.id": "/redfish/v1/Managers/BMC/VirtualMedia/1"
238        }
239    ],
240    "@odata.context": "/redfish/v1/$metadata#VirtualMediaCollection.VirtualMediaCollection",
241    "@odata.id": "/redfish/v1/Managers/BMC/VirtualMedia"
242}
243```
244
245#### Virtual Media schema
246
247```json
248{
249    "@odata.type": "#VirtualMedia.v1_1_0.VirtualMedia",
250    "Id": "ISO0",
251    "Name": "Virtual Removable Media",
252    "MediaTypes": [
253        "CD",
254        "USBStick"
255    ],
256    "Image": "https://192.168.0.1/Images/os.iso",
257    "ImageName": "Os",
258    "ConnectedVia": "URI",
259    "Inserted": true,
260    "WriteProtected": false,
261    "@odata.context": "/redfish/v1/$metadata#VirtualMedia.VirtualMedia",
262    "@odata.id": "/redfish/v1/Managers/BMC/VirtualMedia/ISO0",
263    "Oem": {
264        "OpenBMC": {
265             "@odata.type": "#OemVirtualMedia.v1_0_0.VirtualMedia",
266             "WebSocketEndpoint": "/nbd/0"
267        }
268    },
269}
270```
271
272Schema will look similar for both Proxy and Legacy Mode. Some key
273differences as follows:
274
275| Field Name           | Proxy Mode | Legacy Mode                      | Comment                             |
276| -------------------- | ---------- | -------------------------------- | ----------------------------------- |
277| InsertMedia          | N/A        | action as described by DMTF spec |                                     |
278| Image                | N/A        | image location                   |                                     |
279| ImageName            | N/A        | image name                       |                                     |
280| ConnectedVia         | "Applet"   | as described by DMTF spec        | applies only for connected media    |
281| TransferMethod       | "Stream"   | "Stream"                         | "upload" is not supported by design |
282| TransferProtocolType | "OEM"      | as described by DMTF spec        |                                     |
283
284#### Virtual Media OEM Extension
285
286Virtual Media schema is adapted to Legacy Mode where image is given by user
287directly via Redfish action and whole connection is processed between service
288and web server.
289
290For [Proxy Mode](#Proxy-Mode) nbd data is
291served by client web browser. Having multiple connections, in order to setup
292connection, client needs the information about the location of websocket
293created by web server. This value is exposed as OEM ``WebSocketEndpoint``
294property for each item.
295
296### Inactivity timeout
297
298Virtual Media supports inactivity timeout, which will break Virtual Media
299connection after certain number of seconds of inactivity. Because nbdclient has
300mechanism for caching image, also kernel has home buffer mechanisms for block
301device, the idea is to prepare a patch on USBGadget driver, that will write USB
302gadget statistics under /proc/USBGadget/lun.X file. Those statistics will be
303observed by Virtual Media application.
304
305### Virtual Media Service
306
307Virtual Media Service is separate application that will coexist on DBus. It
308will be initialized from configuration json file, and expose all available
309for provisioning VirtualMedia objects. Virtual Media is responsible for:
310
311* Exposing current Virtual Media configuration to DBus user.
312* Spawning nbdclient, and monitor its lifetime, for Proxy connections.
313* Spawning nbdkit, and monitor its lifetime, for CIFS/HTTPS connections.
314* Monitoring uDEV for all NBD related block device changes, and
315  configure/de-configure USB Gadget accordingly.
316* Monitor NBD device inactivity period to support inactivity timeout.
317
318### Configuration
319
320Upon process startup, Virtual Media reads its config file, with the following
321structure:
322
323```json
324"InactivityTimeout": 1800,              # Timeout of inactivity on device in seconds, that will lead to automatic disconnection
325"MountPoints": {
326    "ISO0": {
327        "EndpointId": "/nbd/0",         # bmcweb endpoint (URL) configured for this type of connection
328        "Mode": 0,                      # 0 - Proxy Mode, 1 - Legacy Mode
329        "NBDDevice": "/dev/nbd0",       # nbd endpoint on device usually matches numeric value with EndpointId
330        "UnixSocket": "/tmp/nbd.sock",  # defines which Unix socket will be occupied by connection
331        "Timeout": 30,                  # timeout in seconds passed to nbdclient
332        "BlockSize": 512,               # Block size passed to nbdclient
333    }
334},
335```
336
337### DBus Interface
338
339Virtual Media will expose the following object structure. All object paths
340are representation of configuration file described above
341
342```ascii
343/xyz/openbmc_project/VirtualMedia/Proxy/ISO0
344/xyz/openbmc_project/VirtualMedia/Proxy/1
345/xyz/openbmc_project/VirtualMedia/Legacy/0
346/xyz/openbmc_project/VirtualMedia/Legacy/1
347```
348
349Each of object will implement ``xyz.openbmc_project.VirtualMedia.Process``
350interface, which will be defined as follow:
351
352| Name     | type     | input | return  | description                                                         |
353| -------- | -------- | ----- | ------- | ------------------------------------------------------------------- |
354| Active   | Property | -     | BOOLEAN | `True`, if object is occupied by active process, `False` otherwise  |
355| ExitCode | Property | -     | INT32   | If process terminates this property will contain returned exit code |
356
357Each object will also expose configuration of its own under
358``xyz.openbmc_project.VirtualMedia.MountPoint`` (all properties are RO)
359
360| Name                       | type     | input | return | description                                                               |
361| -------------------------- | -------- | ----- | ------ | ------------------------------------------------------------------------- |
362| EndPointId                 | Property | -     | STRING | As per configuration                                                      |
363| Mode                       | Property | -     | BYTE   | As per configuration                                                      |
364| Device                     | Property | -     | STRING | As per configuration                                                      |
365| Socket                     | Property | -     | STRING | As per configuration                                                      |
366| Timeout                    | Property | -     | UINT16 | As per configuration                                                      |
367| BlockSize                  | Property | -     | UINT16 | As per configuration                                                      |
368| RemainingInactivityTimeout | Property | -     | UINT16 | Seconds to drop connection by server, for activated endpoint, 0 otherwise |
369| ImageURL                   | Property | -     | STRING | URL to mounted image                                                      |
370
371Another interface exposed by each object are stats under
372```xyz.openbmc_project.VirtualMedia.Stats``` (all properties are RO):
373
374| Name    | type     | input | return | description                              |
375| ------- | -------- | ----- | ------ | ---------------------------------------- |
376| ReadIO  | Property | -     | UINT64 | Number of read IOs since image mounting  |
377| WriteIO | Property | -     | UINT64 | Number of write IOs since image mounting |
378
379Depends on object path, object will expose different interface for mounting image.
380
381For Proxy its ```xyz.openbmc_project.VirtualMedia.Proxy```, defined as follow:
382
383| Name    | type   | input | return  | description                                       |
384| ------- | ------ | ----- | ------- | ------------------------------------------------- |
385| Mount   | Method | -     | BOOLEAN | Perform a mount to HOST operation on given object |
386| Unmount | Method | -     | BOOLEAN | Perform an unmount from HOST on given object      |
387
388For Legacy its ```xyz.openbmc_project.VirtualMedia.Legacy```, defined as follow:
389
390| Name    | type   | input  | return  | description                                                                                |
391| ------- | ------ | ------ | ------- | ------------------------------------------------------------------------------------------ |
392| Mount   | Method | STRING | BOOLEAN | Perform a mount to HOST operation on given object, with location given as STRING parameter |
393| Mount   | Method | STRING<br>BOOLEAN<br>VARIANT<UNIX_FD,INT> | BOOLEAN | Perform a mount to HOST operation on given object, with parameters:<br><br>`STRING` : url to image. It should start with either `smb://` or `https://` prefix<br>`BOOLEAN` : RW flag for mounted gadget (should be consistent with remote image capabilities)<br>`VARIANT<UNIX_FD,INT>` : file descriptor of named pipe used for passing null-delimited secret data (username and password). When there is no data to pass `-1` should be passed as `INT`|
394| Unmount | Method | -      | BOOLEAN | Perform an unmount from HOST on given object                                               |
395
396## Alternatives Considered
397Existing implementation in OpenBMC
398
399## Impact
400Shall not affect usability of current Virtual Media implementation
401
402## Testing
403TBD
404