Создание собственных служб интеграции

Начиная с юбилейного обновления Windows 10, любой пользователь может сделать приложения, взаимодействующие между узлом Hyper-V и его виртуальными машинами с помощью Hyper-V сокетов — сокета Windows с новым семейством адресов и специализированной конечной точкой для целевых виртуальных машин. Весь обмен данными через сокеты Hyper-V выполняется без использования сети, а все данные остаются в одной и той же физической памяти. Приложения, использующие сокеты Hyper-V, похожи на службы интеграции Hyper-V.

В этом документе описывается создание простой программы, созданной на основе сокетов Hyper-V.

Поддерживаемая ОС хоста

  • Windows 10 и более поздних версий
  • Windows Server 2016 и более поздних версий

Поддерживаемая гостевая ОС

Замечание

Поддерживаемая гостевая версия Linux должна иметь поддержку ядра:

CONFIG_VSOCKET=y
CONFIG_HYPERV_VSOCKETS=y

Возможности и ограничения

  • Поддерживает действия режима ядра или режима пользователя
  • Только поток данных
  • Нет блочного памяти (не лучше всего для резервного копирования или видео)

Начало работы

Требования:

  • Компилятор C/C++. Если у вас его нет, ознакомьтесь с visual Studio Community
  • Пакет SDK для Windows — предварительно установлен в Visual Studio 2015 с обновлением 3 и более поздними версиями.
  • Компьютер под управлением одной из хостовых операционных систем, указанных по крайней мере с одной виртуальной машиной. — это для тестирования приложения.

Заметка: API для Hyper-V сокетов стал общедоступным в юбилейном обновлении Windows 10. Приложения, использующие HVSocket, будут работать на любом узле и гостях Windows 10, но могут быть разработаны только с помощью пакета SDK для Windows позже сборки 14290.

Регистрация нового приложения

Чтобы использовать сокеты Hyper-V, приложение должно быть зарегистрировано в реестре узла Hyper-V.

Зарегистрируя службу в реестре, вы получите:

  • Управление WMI для включения, отключения и перечисления доступных служб
  • Разрешение на обмен данными с виртуальными машинами напрямую

В следующем powerShell будет зарегистрировано новое приложение с именем HV Socket Demo. Это должно быть запущено от имени администратора. Инструкции для использования приведены ниже.

$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

Расположение реестра и сведения:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\GuestCommunicationServices\

В этом расположении реестра вы увидите несколько идентификаторов GUID. Это наши стандартные услуги.

Сведения в реестре для каждой службы:

  • Service GUID
    • ElementName (REG_SZ) -- это удобочитаемое имя службы.

Чтобы зарегистрировать свою собственную службу, создайте новый ключ реестра, используя свой GUID и осмысленное имя.

Понятное название будет ассоциироваться с вашим новым приложением. Он будет отображаться в счетчиках производительности и других местах, где GUID не подходит.

Запись реестра выглядит следующим образом:

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

Замечание

GUID службы для виртуального гостя Linux использует протокол VSOCK, который адресует через svm_cid и svm_port, а не через GUID. Чтобы устранить эту несогласованность с Windows, хорошо известный GUID используется в качестве шаблона службы на узле, который преобразуется в порт гостя. Чтобы настроить GUID службы, просто измените первый "000000000" на нужный номер порта. Например, "00000ac9" — порт 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
  */

Совет: Чтобы создать GUID в PowerShell и скопировать его в буфер обмена, выполните следующую команду:

(New-Guid).Guid | clip.exe

Создание сокета Hyper-V

В большинстве случаев для определения сокета требуется семейство адресов, тип подключения и протокол.

Вот простое определение сокета

// Windows
SOCKET WSAAPI socket(
  _In_ int af,
  _In_ int type,
  _In_ int protocol
);

// Linux guest
int socket(int domain, int type, int protocol);

Для сокета Hyper-V:

  • Семейство адресов - AF_HYPERV (Windows) или AF_VSOCK (гостевая система Linux)
  • тип- SOCK_STREAM
  • протокол — HV_PROTOCOL_RAW (Windows) или 0 (гость Linux)

Ниже приведен пример объявления или создания экземпляра:

// Windows
SOCKET sock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW);

// Linux guest
int sock = socket(AF_VSOCK, SOCK_STREAM, 0);

Привязка к сокету Hyper-V

Привязка связывает сокет с сведениями о подключении.

Определение функции приведено ниже для удобства, ознакомьтесь с дополнительными сведениями о привязке здесь.

// 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);

В отличие от адреса сокета (sockaddr) для стандартного семейства адресов протокола Интернета (AF_INET), который состоит из IP-адреса хост-компьютера и номера порта на этом узле, адрес сокета для AF_HYPERV использует идентификатор виртуальной машины и идентификатор приложения, определенный выше, для установления подключения. Если привязка в гостевой системе Linux AF_VSOCK использует svm_cid и svm_port.

Поскольку сокеты Hyper-V не зависят от сетевого стека, TCP/IP, DNS и т. д., конечная точка сокета должна быть в формате, который не использует ни IP-адрес, ни имя хоста, но всё же однозначно описывает подключение.

Вот определение адреса сокета Hyper-V:

// 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)];
};

Вместо IP-адреса или имени узла конечные точки AF_HYPERV в основном используют две GUID.

  • Идентификатор виртуальной машины — это уникальный идентификатор, назначенный для каждой виртуальной машины. Идентификатор виртуальной машины можно найти с помощью следующего фрагмента кода PowerShell.

    (Get-VM -Name $VMName).Id
    
  • Идентификатор службы — GUID, описанный выше, с помощью которого приложение зарегистрировано в реестре узлов Hyper-V.

Существует также набор подстановочных знаков VMID, доступных, если подключение не относится к определенной виртуальной машине.

Подстановочные знаки VMID

Имя GUID Description
HV_GUID_ZERO 00000000-0000-0000-0000-000000000000 Прослушиватели должны привязаться к этому VmId, чтобы принять подключение со всех партиций.
HV_GUID_WILDCARD 00000000-0000-0000-0000-000000000000 Прослушиватели должны привязаться к этому VmId, чтобы принять подключение со всех партиций.
HV_GUID_BROADCAST FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF
HV_GUID_CHILDREN 90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd Универсальный адрес для детей. Прослушиватели должны привязаться к этому VmId, чтобы принимать соединения от дочерних узлов.
HV_GUID_LOOPBACK e0e16197-dd56-4a10-9195-5ee7a155a838 Адрес обратной связи. Использование этого VmId подключает к тому же разделу, что и соединитель.
HV_GUID_PARENT a42e7cda-d03f-480c-9cc2-a4de20abb878 Родительский адрес. Использование этого VmId позволяет подключиться к родительскому разделу соединителя.*

* HV_GUID_PARENT Родитель виртуальной машины — это её хост. Родителем контейнера является хост контейнера. Подключение из контейнера, работающего на виртуальной машине, будет подключаться к виртуальной машине, на которой размещен контейнер. Прослушивание на этом vmId принимает подключения от: (внутри контейнеров): контейнерный хост. (Внутри виртуальной машины: хост контейнера/без контейнера): хост виртуальной машины. (Не внутри виртуальной машины: размещение контейнеров / отсутствие контейнера): не поддерживается.

Поддерживаемые команды сокета

Сокет() Привязка() Соединение() Отправка() Прослушивание() Принятие()

Параметры сокета HvSocket

Имя Тип Description
HVSOCKET_CONNECTED_SUSPEND ULONG Если этот параметр сокета установлен в значение, отличное от нуля, сокеты не отключаются при приостановке виртуальной машины.

Полный API WinSock

Справочник по службам Hyper-V Integration Services