VMSocket is a mechanism to expose UNIX Sockets (sockets in AF_UNIX domain) from the host operating system to the KVM’s virtual machines.
It provides a really fast communication channel between host and guests os. It can ben used for communication that needs to be fast, such as HPC (High Performance Computing) software solutions and so on.
The socket is bounded on the host os and the guests can connect to the socket using special drivers. At this time only the driver for linux is ready.
The sources of the patched qemu to support vmsocket are found on: http://github.com/cjg/qemu/tree/vmsocket/.
Usage
To use VMSocket you should compile qemu grabbing the sources from the branch vmsocket of the my qemu fork on github: http://github.com/cjg/qemu/tree/vmsocket:
git clone git://github.com/cjg/qemu.git cd qemu git checkout origin/vmsocket ./configure make make install
Now to use it you have to add the option
-vmsocket unix:/path/to/the/unix/socket
to the usual qemu options that you have to use.
To use vmsocket you have to use a gnu/linux distribution as guest os.
The guest driver for linux is kvm_vmsocket, it is provided as an “out-of-tree” kernel module, and it’s found on http://github.com/cjg/linux-vmsocket, so to obtain the driver, on the guest os you have to do:
git clone git://github.com/cjg/linux-vmsocket.git cd linux-vmsocket make make modules_install modprobe kvm_vmsocket
Now a character device “vmsocket0” will be created, and from the user space it’s possible to interact with the socket through this file: the opening of vmsocket0 corresponds to the connect on the socket, the write to the send, the read to the receive and the close to the close of course.
Implementation Details
On the host side VMSocket is implemented as a qemu device, vmsocket, attached on the virtual PCI bus. The virtual device has some registers for controlling the Input/Output actions and two buffers, one for input and another one for output.
The registers are on the first pci bar, and they are:
- Status: read only long, mapped at 0x0, it’s used by the driver to obtain the status of the device (i.e.: the result code of the last action performed).
- Connect: write only word, mapped at 0x20, it’s used to request a connection to the socket. The driver to request a connection have to write a string of 1 to this register.
- Close: write only word, mapped at 0x30, it’s used to close the connection from the socket. The driver to request the release of the connection have to write a string of 1 to this register.
- WriteCommit: write only long, mapped at 0x40, it’s used to request the sending (or writing) the data stored in the output buffer to the connection already opened. The driver to request the sending of the data have to write to this register the size of the data to send.
- Read: write only long, mapped at 0x60, it’s used to request the receiving (or reading) the data to the input buffer from the connection already opened. The driver to request the receiving of the data have to write to this register the size of the data to receive.
The input buffer is on the second pci bar and the output buffer is on the third one.
Imagining to have bounded an “echo server” on the host’s socket, the driver that want’s (or that have to) to use the services of the server should:
- Write a string of 1 to the Connect register
- Check the status, reading the Status register
- Copy the buffer to send to the “output buffer”, the memory situated on the third pci bar of the device
- Write the size of the buffer to the WriteCommit register
- Check the status, reading the Status register
- Write the size of the data to receive to the Read register
- Check the status, reading the Status register
- Copy from the device’s “input buffer” the received data
- Write a string of 1 to the Close register
- Check the status, reading the Status register