Vsocks are a means of providing socket communication (either stream or datagram) directly between VMs and their host operating system. The host and each VM have a 32 bit CID (Context IDentifier) and may connect or bind to a 32 bit port number. Ports < 1024 are privileged ports.
- Vsock communication between VMs does not seem to work.
- Only one vsock device per VM is supported.
name | value | description |
---|---|---|
VMADDR_PORT_ANY | -1 | Bind to a random available port. |
VMADDR_CID_ANY | -1 | Bind to any CID. This seems to work inside VMs only. |
VMADDR_CID_HYPERVISOR | 0 | The hypervisor's CID. |
VMADDR_CID_RESERVED | 1 | Reserved; this must not be used. |
VMADDR_CID_HOST | 2 | The host's CID. |
This creates a VM with a vsock device with CID 123.
qemu-system-x86_64 -device vhost-vsock-pci,guest-cid=123
#include <sys/socket.h>
#include <linux/vm_sockets.h>
#include <string.h>
#include <stdio.h>
int main()
{
int s = socket(AF_VSOCK, SOCK_STREAM, 0);
struct sockaddr_vm addr;
memset(&addr, 0, sizeof(struct sockaddr_vm));
addr.svm_family = AF_VSOCK;
addr.svm_port = 9999;
addr.svm_cid = VMADDR_CID_HOST;
bind(s, &addr, sizeof(struct sockaddr_vm));
listen(s, 0);
struct sockaddr_vm peer_addr;
socklen_t peer_addr_size = sizeof(struct sockaddr_vm);
int peer_fd = accept(s, &peer_addr, &peer_addr_size);
char buf[64];
size_t msg_len;
while ((msg_len = recv(peer_fd, &buf, 64, 0)) > 0) {
printf("Received %lu bytes: %.*s\n", msg_len, msg_len, buf);
}
return 0;
}
#!/usr/bin/env python3
import socket
CID = socket.VMADDR_CID_HOST
PORT = 9999
s = socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM)
s.bind((CID, PORT))
s.listen()
(conn, (remote_cid, remote_port)) = s.accept()
print(f"Connection opened by cid={remote_cid} port={remote_port}")
while True:
buf = conn.recv(64)
if not buf:
break
print(f"Received bytes: {buf}")
#include <sys/socket.h>
#include <linux/vm_sockets.h>
#include <string.h>
int main()
{
int s = socket(AF_VSOCK, SOCK_STREAM, 0);
struct sockaddr_vm addr;
memset(&addr, 0, sizeof(struct sockaddr_vm));
addr.svm_family = AF_VSOCK;
addr.svm_port = 9999;
addr.svm_cid = VMADDR_CID_HOST;
connect(s, &addr, sizeof(struct sockaddr_vm));
send(s, "Hello, world!", 13, 0);
close(s);
return 0;
}
#!/usr/bin/env python3
import socket
CID = socket.VMADDR_CID_HOST
PORT = 9999
s = socket.socket(socket.AF_VSOCK, socket.SOCK_STREAM)
s.connect((CID, PORT))
s.sendall(b"Hello, world!")
s.close()
ip link add type vsockmon
ip link set vsockmon0 up
wireshark -k -i vsockmon0
ip link set vsockmon0 down
ip link del vsockmon0
- https://stefano-garzarella.github.io/posts/2019-11-08-kvmforum-2019-vsock/
- http://man7.org/linux/man-pages/man7/vsock.7.html
- https://wiki.qemu.org/Features/VirtioVsock
- https://gist.github.com/mcastelino/9a57d00ccf245b98de2129f0efe39857
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/vm_sockets.h
- https://libvirt.org/formatdomain.html#vsock
Nice notes!
Just an update, starting from Linux v5.6 we also support loopback communication (mainly for CI and developing) and we used the CID = 1 for this. So VMADDR_CID_RESERVED is now VMADDR_CID_LOCAL and can be used for local communication.
More details here: https://stefano-garzarella.github.io/posts/2020-02-20-vsock-nested-vms-loopback/