Поделиться через


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

Начиная с юбилейного обновления 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, будут работать на любом хосте и гостевом узле с Widnows 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 службы измените первое значение "00000000" на необходимый номер порта. Например, "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-FFFFFFFFFFFFFFFF
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 принимает подключение: (внутри контейнеров): узел контейнера. (Внутри виртуальной машины: узел контейнера или нет контейнера): узел виртуальной машины. (Не внутри виртуальной машины: узел контейнера/ нет контейнера): не поддерживается.

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

Socket() Bind() Connect() Send() Listen() Accept()

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

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

Полный API WinSock

Справочник по службам интеграции Hyper-V