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### Network Block Device (NBD) 80 81Reader can notice that most connections on diagram are based on Network Block 82Device. 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 95In Virtual Media use case, it's being used to pull data from remote client, and 96present it into non BMC mounted `/dev/nbdXX` device. Then the block device is 97being provided to Host through USB Gadget. 98 99### USB Gadget 100 101Part of Linux kernel that makes *emulation* of certain USB device classes 102possible through USB "On-The-Go", if connect appropriately to Host. In Virtual 103Media case it emulates USB mass storage connected to HOST. The source or 104redirection is block device created by nbd-client `/dev/nbdXX` 105 106### Proxy Mode 107 108Proxy Mode uses browser JavaScript and WebSockets support, to create JS NBD 109Server. Browser is responsible for create HTTPS session, authenticate user, and 110receive given privileges, then upgrade HTTPS session to WSS, through mechanisms 111described by [RFC6455](HTTPS://tools.ietf.org/html/rfc6455). Since WSS upgrade, 112JS application is responsible for handling all required by specification NBD 113Server commands. 114 115Multiple, simultaneous connections are supported per opening connections on 116different URIs in HTTPS server. Number of available simultaneous connections is 117being defined in configuration file described in next chapter. 118 119Encryption for proxy is supported through HTTPS/WSS channel and inherits 120encryption mechanisms directly from HTTPS server, all data transactions go 121through bmcweb. 122 123The 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 164Legacy Mode uses VirtualMedia schema, defined by DMTF, for mounting external 165CIFS/HTTPS images. The current implementation supports only stream mounting 166as for now. In this case Redfish is only used as mechanism for Virtual Media 167initialization, and is not responsible for data transmission. For data there 168is a separate component responsible for handling CIFS/HTTPS traffic called 169NBDkit. 170 171Multiple, simultaneous connections are supported through spawning additional 172nbkit instances, the number of available instances for CIFS/HTTPS is configured 173and described in details in next chapter. 174 175Encryption is based on remote storage connection, and follows Intel's Best 176security practices, as remote server support such (i.e. HTTPS requires SSL, and 177pure HTTP is not supported, for CIFS protocol version 3.0 allows enabling 178encryption and that will be provided). 179 180The 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 220Virtual Media Service will be exposed as Redfish VirtualMedia endpoint as 221defined by DMTF. Here are some examples. 222 223#### Virtual Media Collection schema 224Members in collection will be defined based on configuration file described in 225next 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 273Schema will look similar for both Proxy and Legacy Mode. Some key 274differences 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 287Virtual Media schema is adapted to Legacy Mode where image is given by user 288directly via Redfish action and whole connection is processed between service 289and web server. 290 291For [Proxy Mode](#Proxy-Mode) nbd data is 292served by client web browser. Having multiple connections, in order to setup 293connection, client needs the information about the location of websocket 294created by web server. This value is exposed as OEM ``WebSocketEndpoint`` 295property for each item. 296 297### Inactivity timeout 298 299Virtual Media supports inactivity timeout, which will break Virtual Media 300connection after certain number of seconds of inactivity. Because nbdclient has 301mechanism for caching image, also kernel has home buffer mechanisms for block 302device, the idea is to prepare a patch on USBGadget driver, that will write USB 303gadget statistics under /proc/USBGadget/lun.X file. Those statistics will be 304observed by Virtual Media application. 305 306### Virtual Media Service 307 308Virtual Media Service is separate application that will coexist on DBus. It 309will be initialized from configuration json file, and expose all available 310for 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 321Upon process startup, Virtual Media reads its config file, with the following 322structure: 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 340Virtual Media will expose the following object structure. All object paths 341are 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 350Each of object will implement ``xyz.openbmc_project.VirtualMedia.Process`` 351interface, 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 358Each 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 373Another 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 381Depends on object path, object will expose different interface for mounting image. 382 383For 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 390For 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 399Existing implementation in OpenBMC 400 401## Impact 402Shall not affect usability of current Virtual Media implementation 403 404## Testing 405TBD 406