|
| 1 | +# Using the Firecracker Virtio-vsock Device |
| 2 | + |
| 3 | +## Table of Contents |
| 4 | + |
| 5 | +- [Prerequisites](#prerequisites) |
| 6 | +- [Firecracker Virtio-vsock Design](#firecracker-virtio-vsock-design) |
| 7 | +- [Setting up the Virtio-vsock Device](#setting-up-the-virtio-vsock-device) |
| 8 | +- [Examples](#examples) |
| 9 | + |
| 10 | +## Prerequisites |
| 11 | + |
| 12 | +This document assumes the reader is familiar with running Firecracker and |
| 13 | +issuing API commands over its API socket. For a more details on how to run |
| 14 | +Firecracker, check out the [getting started guide](getting-started.md). |
| 15 | + |
| 16 | +Familiarty with socket programming, in particular Unix sockets, is also |
| 17 | +assumed. |
| 18 | + |
| 19 | +## Firecracker Virtio-vsock Design |
| 20 | + |
| 21 | +The Firecracker vsock device aims to provide full virtio-vsock support to |
| 22 | +software running inside the guest VM, while bypassing vhost kernel code on the |
| 23 | +host. To that end, Firecracker implements the virtio-vsock device model, and |
| 24 | +mediate communication between AF_UNIX sockets (on the host end) and AF_VSOCK |
| 25 | +sockets (on the guest end). |
| 26 | + |
| 27 | +In order to provide channel multiplexing, AF_VSOCK ports are translated into |
| 28 | +multiple AF_UNIX sockets (one Unix socket per vsock port). The virtio-vsock |
| 29 | +device must be configured with a file path to an AF_UNIX socket (e.g. |
| 30 | +`/path/to/v.sock`). There are two scenarios to be considered, depending on |
| 31 | +where the connection is initiated. |
| 32 | + |
| 33 | +### Host-Initiated Connections |
| 34 | + |
| 35 | +When a microvm having a vsock device attached is started, Firecracker will |
| 36 | +begin listening on an AF_UNIX socket (e.g. `/path/to/v.sock`). When the host |
| 37 | +needs to initiate a connection, it should connect to that Unix socket, then |
| 38 | +send a connect command, in text form, specifying the destination AF_VSOCK port: |
| 39 | +"CONNECT PORT\n". Where PORT is the decimal port number, and "\n" is EOL (ASCII |
| 40 | +0x0A). Following that, the same connection will be forwarded by Firecracker to |
| 41 | +the guest software listening on that port, thus establishing the requested |
| 42 | +channel. If no one is listening, Firecracker will terminate the host |
| 43 | +connection. |
| 44 | + |
| 45 | +1. Host: At VM configuration time, add a virtio-vsock device, with some path |
| 46 | + specified in `uds_path`; |
| 47 | +2. Guest: create an AF_VSOCK socket and `listen()` on `<port_num>`; |
| 48 | +3. Host: `connect()` to AF_UNIX at `uds_path`. |
| 49 | +4. Host: `send()` "CONNECT <port_num>\n". |
| 50 | +5. Guest: `accept()` the new connection. |
| 51 | + |
| 52 | +The channel is established between the sockets obtained at steps 3 (host) |
| 53 | +and 5 (guest). |
| 54 | + |
| 55 | +### Guest-Initiated Connections |
| 56 | + |
| 57 | +When the virtio-vsock device model in Firecracker detects a connection request |
| 58 | +coming from the guest (a VIRTIO_VSOCK_OP_REQUEST packet), it tries to forward |
| 59 | +the connection to an AF_UNIX socket listening on the host, at |
| 60 | +`/path/to/v.sock_PORT` (or whatever path was configured via the `uds_path` |
| 61 | +property of the vsock device), where `PORT` is the destination port (in |
| 62 | +decimal), as specified in the connection request packet. If no such socket |
| 63 | +exists, or no one is listening on it, a connection cannot be established, and a |
| 64 | +VIRTIO_VSOCK_OP_RST packet will be sent back to the guest. |
| 65 | + |
| 66 | +From the user perspective, these would be the steps taken to establish a |
| 67 | +communication channel: |
| 68 | + |
| 69 | +1. Host: At VM configuration time, add a virtio-vsock device, with some |
| 70 | + `uds_path` (e.g. `/path/to/v.sock`). |
| 71 | +2. Host: create and listen on an AF_UNIX socket at `/path/to/v.sock_PORT`. |
| 72 | +3. Guest: create an AF_VSOCK socket and connect to `HOST_CID` (i.e. integer |
| 73 | + value 2) and `PORT`; |
| 74 | +4. Host: `accept()` the new connection. |
| 75 | + |
| 76 | +The channel is established between the sockets obtained at steps 4 (host) |
| 77 | +and 3 (guest). |
| 78 | + |
| 79 | +## Setting up the virtio-vsock device |
| 80 | + |
| 81 | +The virtio-vsock device will require an ID, a CID, and the path to a backing |
| 82 | +AF_UNIX socket: |
| 83 | + |
| 84 | +```bash |
| 85 | +curl -X PUT \ |
| 86 | + --unix-socket ./firecracker-api.sock \ |
| 87 | + /vsocks/1 \ |
| 88 | + -H accept:application/json \ |
| 89 | + -H content-type:application/json \ |
| 90 | + -d '{ |
| 91 | + "vsock_id": "1", |
| 92 | + "guest_cid": 3, |
| 93 | + "uds_path": "./v.sock" |
| 94 | + }' |
| 95 | +``` |
| 96 | + |
| 97 | +Once the microvm is started, Firecracker will create and start listening on the |
| 98 | +AF_UNIX socket at `uds_path`. Incoming connections will get forwarded to the |
| 99 | +guest microvm, and translated to AF_VSOCK. The destination port is expected to |
| 100 | +be specified by sending the text command "CONNECT <port_num>\n", immediately |
| 101 | +after the AF_UNIX connection is established. Connections initiated from within |
| 102 | +the guest will be forwarded to AF_UNIX sockets expected to be listening at |
| 103 | +`./v.sock_<port_num>`. I.e. a guest connection to port 52 will get forwarded to |
| 104 | +`./v.sock_52`. |
| 105 | + |
| 106 | +## Examples |
| 107 | + |
| 108 | +The examples below assume a running microvm, with a vsock device configured as |
| 109 | +shown [above](#setting-up-the-virtio-vsock-device). |
| 110 | + |
| 111 | + |
| 112 | +### Using External Socket Tools (`nc-vsock` and `socat`) |
| 113 | + |
| 114 | +#### Connecting From Host to Guest |
| 115 | + |
| 116 | +First, make sure the vsock port is bound and listened to on the guest side. |
| 117 | +Say, port 52: |
| 118 | + |
| 119 | +```bash |
| 120 | +$ nc-vsock -l 52 |
| 121 | +``` |
| 122 | + |
| 123 | +On the host side, connect to `./v.sock` and issue a connection request to that |
| 124 | +port: |
| 125 | + |
| 126 | +```bash |
| 127 | +$ socat - UNIX-CONNECT:./v.sock |
| 128 | +CONNECT 52 |
| 129 | + |
| 130 | +``` |
| 131 | + |
| 132 | +The connection should now be established (in the above example, between |
| 133 | +`nc-vsock` on the guest side, and `socat` on the host side). |
| 134 | + |
| 135 | +#### Connecting From Guest To Host |
| 136 | + |
| 137 | +First make sure the AF_UNIX corresponding to your desired port is listened to |
| 138 | +on the host side: |
| 139 | + |
| 140 | +```bash |
| 141 | +$ socat - UNIX-LISTEN:./v.sock_52 |
| 142 | +``` |
| 143 | + |
| 144 | +On the guest side, create an AF_VSOCK socket and connect it to the previously |
| 145 | +chosen port on the host (CID=2): |
| 146 | + |
| 147 | +```bash |
| 148 | +$ nc-vsock 2 52 |
| 149 | +``` |
0 commit comments