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