Make your own integration services
Starting in Windows 10 Anniversary Update, anyone can make applications that communicate between the Hyper-V host and its virtual machines using Hyper-V sockets -- a Windows Socket with a new address family and specialized endpoint for targeting virtual machines. All communication over Hyper-V sockets runs without using networking and all data stays on the same physical memory. Applications using Hyper-V sockets are similar to Hyper-V's integration services.
This document walks through creating a simple program built on Hyper-V sockets.
Supported Host OS
- Windows 10 and later
- Windows Server 2016 and later
Supported Guest OS
- Windows 10 and later
- Windows Server 2016 and later
- Linux guests with Linux Integration Services. See Supported Linux and FreeBSD virtual machines for Hyper-V on Windows
Note
A supported Linux guest must have kernel support for:
CONFIG_VSOCKET=y
CONFIG_HYPERV_VSOCKETS=y
Capabilities and Limitations
- Supports kernel mode or user mode actions
- Data stream only
- No block memory (not the best for backup/video)
Getting started
Requirements:
- C/C++ compiler. If you don't have one, checkout Visual Studio Community
- Windows SDK -- pre-installed in Visual Studio 2015 with Update 3 and later.
- A computer running one of the host operating systems specified with at least one vitual machine. -- this is for testing your application.
Note: The API for Hyper-V sockets became publicly available in Windows 10 Anniversary Update. Applications that use HVSocket will run on any Windows 10 host and guest but can only be developed with a Windows SDK later than build 14290.
Register a new application
In order to use Hyper-V sockets, the application must be registered with the Hyper-V Host's registry.
By registering the service in the registry, you get:
- WMI management for enable, disable, and listing available services
- Permission to communicate with virtual machines directly
The following PowerShell will register a new application named "HV Socket Demo". This must be run as administrator. Manual instructions below.
$friendlyName = "HV Socket Demo"
# Create a new random GUID. Add it to the services list
$service = New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\GuestCommunicationServices" -Name ((New-Guid).Guid)
# Set a friendly name
$service.SetValue("ElementName", $friendlyName)
# Copy GUID to clipboard for later use
$service.PSChildName | clip.exe
Registry location and information:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\GuestCommunicationServices\
In this registry location, you'll see several GUIDs. Those are our in-box services.
Information in the registry per service:
Service GUID
ElementName (REG_SZ)
-- this is the service's friendly name
To register your own service, create a new registry key using your own GUID and friendly name.
The friendly name will be associated with your new application. It'll appear in performance counters and other places where a GUID isn't appropriate.
The registry entry looks like this:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\GuestCommunicationServices\
999E53D4-3D5C-4C3E-8779-BED06EC056E1\
ElementName REG_SZ VM Session Service
YourGUID\
ElementName REG_SZ Your Service Friendly Name
Note
The Service GUID for a Linux guest uses the VSOCK protocol which addresses via a svm_cid
and svm_port
rather than a guids. To bridge this inconsistency with Windows the well-known GUID is used as the service template on the host which translates to a port in the guest. To customize your Service GUID simply change the first "00000000" to the port number desired. Ex: "00000ac9" is port 2761.
// Hyper-V Socket Linux guest VSOCK template GUID
struct __declspec(uuid("00000000-facb-11e6-bd58-64006a7986d3")) VSockTemplate{};
/*
* GUID example = __uuidof(VSockTemplate);
* example.Data1 = 2761; // 0x00000AC9
*/
Tip: To generate a GUID in PowerShell and copy it to the clipboard, run:
(New-Guid).Guid | clip.exe
Create a Hyper-V socket
In the most basic case, defining a socket requires an address family, connection type, and protocol.
Here is a simple socket definition
// Windows
SOCKET WSAAPI socket(
_In_ int af,
_In_ int type,
_In_ int protocol
);
// Linux guest
int socket(int domain, int type, int protocol);
For a Hyper-V socket:
- Address family -
AF_HYPERV
(Windows) orAF_VSOCK
(Linux guest) - type -
SOCK_STREAM
- protocol -
HV_PROTOCOL_RAW
(Windows) or0
(Linux guest)
Here is an example declaration/instantiation:
// Windows
SOCKET sock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW);
// Linux guest
int sock = socket(AF_VSOCK, SOCK_STREAM, 0);
Bind to a Hyper-V socket
Bind associates a socket with connection information.
The function definition is copied below for convinience, read more about bind here.
// Windows
int bind(
_In_ SOCKET s,
_In_ const struct sockaddr *name,
_In_ int namelen
);
// Linux guest
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
In contrast to the socket address (sockaddr) for a standard Internet Protocol address family (AF_INET
) which consists of the host machine's IP address and a port number on that host, the socket address for AF_HYPERV
uses the virtual machine's ID and the application ID defined above to establish a connection. If binding from a Linux guest AF_VSOCK
uses the svm_cid
and the svm_port
.
Since Hyper-V sockets do not depend on a networking stack, TCP/IP, DNS, etc. the socket endpoint needed a non-IP, not hostname, format that still unambiguously describes the connection.
Here is the definition for a Hyper-V socket's socket address:
// Windows
struct SOCKADDR_HV
{
ADDRESS_FAMILY Family;
USHORT Reserved;
GUID VmId;
GUID ServiceId;
};
// Linux guest
// See include/uapi/linux/vm_sockets.h for more information.
struct sockaddr_vm {
__kernel_sa_family_t svm_family;
unsigned short svm_reserved1;
unsigned int svm_port;
unsigned int svm_cid;
unsigned char svm_zero[sizeof(struct sockaddr) -
sizeof(sa_family_t) -
sizeof(unsigned short) -
sizeof(unsigned int) - sizeof(unsigned int)];
};
In lieu of an IP or hostname, AF_HYPERV endpoints rely heavily on two GUIDs:
VM ID – this is the unique ID assigned per VM. A VM’s ID can be found using the following PowerShell snippet.
(Get-VM -Name $VMName).Id
Service ID – GUID, described above, with which the application is registered in the Hyper-V host registry.
There is also a set of VMID wildcards available when a connection isn't to a specific virtual machine.
VMID Wildcards
Name | GUID | Description |
---|---|---|
HV_GUID_ZERO | 00000000-0000-0000-0000-000000000000 | Listeners should bind to this VmId to accept connection from all partitions. |
HV_GUID_WILDCARD | 00000000-0000-0000-0000-000000000000 | Listeners should bind to this VmId to accept connection from all partitions. |
HV_GUID_BROADCAST | FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF | |
HV_GUID_CHILDREN | 90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd | Wildcard address for children. Listeners should bind to this VmId to accept connection from its children. |
HV_GUID_LOOPBACK | e0e16197-dd56-4a10-9195-5ee7a155a838 | Loopback address. Using this VmId connects to the same partition as the connector. |
HV_GUID_PARENT | a42e7cda-d03f-480c-9cc2-a4de20abb878 | Parent address. Using this VmId connects to the parent partition of the connector.* |
* HV_GUID_PARENT
The parent of a virtual machine is its host. The parent of a container is the container's host.
Connecting from a container running in a virtual machine will connect to the VM hosting the container.
Listening on this VmId accepts connection from:
(Inside containers): Container host.
(Inside VM: Container host/ no container): VM host.
(Not inside VM: Container host/ no container): Not supported.
Supported socket commands
Socket() Bind() Connect() Send() Listen() Accept()
HvSocket Socket Options
Name | Type | Description |
---|---|---|
HVSOCKET_CONNECTED_SUSPEND | ULONG | When this socket option is set to a non-zero value sockets do not disconnect when the virtual machine is paused. |