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