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