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