Skip to content

Commit d5c0879

Browse files
kzysaustinvazquez
authored andcommitted
Support Firecracker 0.20.0's vsock handshake protocol
Since 0.20.0, Firecracker itself writes "OK <port>" as ACK. So we don't have to write our own "IMALIVE" message anymore. Signed-off-by: Kazuyoshi Kato <[email protected]>
1 parent 9d17bdb commit d5c0879

File tree

1 file changed

+15
-29
lines changed

1 file changed

+15
-29
lines changed

internal/vm/vsock.go

Lines changed: 15 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
package vm
1515

1616
import (
17+
"bufio"
1718
"context"
1819
"fmt"
1920
"net"
21+
"strings"
2022
"time"
2123

2224
"github.com/mdlayher/vsock"
@@ -184,14 +186,6 @@ func vsockConnectMsg(port uint32) string {
184186
return fmt.Sprintf("CONNECT %d\n", port)
185187
}
186188

187-
func vsockAckMsg(port uint32) string {
188-
// The message a guest-side connection will write after accepting a connection from
189-
// a host dial. This is not part of the official Firecracker vsock spec, but is
190-
// recommended in order to allow the host to verify connections were established
191-
// successfully: https://github.com/firecracker-microvm/firecracker/issues/1272#issuecomment-533004066
192-
return fmt.Sprintf("IMALIVE %d\n", port)
193-
}
194-
195189
// tryConnect attempts to dial a guest vsock listener at the provided host-side
196190
// unix socket and provided guest-listener port.
197191
func tryConnect(logger *logrus.Entry, udsPath string, port uint32) (net.Conn, error) {
@@ -215,10 +209,18 @@ func tryConnect(logger *logrus.Entry, udsPath string, port uint32) (net.Conn, er
215209
return nil, vsockConnectMsgError{cause: err}
216210
}
217211

218-
err = tryConnRead(conn, vsockAckMsg(port), vsockAckMsgTimeout)
212+
line, err := tryConnReadUntil(conn, '\n', vsockAckMsgTimeout)
219213
if err != nil {
220214
return nil, vsockAckError{cause: err}
221215
}
216+
217+
// The line would be "OK <assigned_hostside_port>\n", but we don't use the hostside port here.
218+
// https://github.com/firecracker-microvm/firecracker/blob/master/docs/vsock.md#host-initiated-connections
219+
if !strings.HasPrefix(line, "OK ") {
220+
return nil, vsockAckError{
221+
cause: errors.Errorf(`expected to read "OK <port>", but instead read %q`, line),
222+
}
223+
}
222224
return conn, nil
223225
}
224226

@@ -240,35 +242,19 @@ func tryAccept(logger *logrus.Entry, listener net.Listener, port uint32) (net.Co
240242
}
241243
}()
242244

243-
err = tryConnWrite(conn, vsockAckMsg(port), vsockAckMsgTimeout)
244-
if err != nil {
245-
return nil, vsockAckError{cause: err}
246-
}
247-
248245
return conn, nil
249246
}
250247

251-
// tryConnRead will try to do a read from the provided conn, returning an error if
252-
// the bytes read does not match what was provided or if the read does not complete
248+
// tryConnReadUntil will try to do a read from the provided conn until the specified
249+
// end character is encounteed. Returning an error if the read does not complete
253250
// within the provided timeout. It will reset socket deadlines to none after returning.
254251
// It's only intended to be used for connect/ack messages, not general purpose reads
255252
// after the vsock connection is established fully.
256-
func tryConnRead(conn net.Conn, expectedRead string, timeout time.Duration) error {
253+
func tryConnReadUntil(conn net.Conn, end byte, timeout time.Duration) (string, error) {
257254
conn.SetDeadline(time.Now().Add(timeout))
258255
defer conn.SetDeadline(time.Time{})
259256

260-
actualRead := make([]byte, len(expectedRead))
261-
_, err := conn.Read(actualRead)
262-
if err != nil {
263-
return err
264-
}
265-
266-
if expectedRead != string(actualRead) {
267-
return errors.Errorf("expected to read %q, but instead read %q",
268-
expectedRead, string(actualRead))
269-
}
270-
271-
return nil
257+
return bufio.NewReaderSize(conn, 32).ReadString(end)
272258
}
273259

274260
// tryConnWrite will try to do a write to the provided conn, returning an error if

0 commit comments

Comments
 (0)