Tornar seus próprios serviços de integração

A partir da Atualização de Aniversário do Windows 10, qualquer pessoa pode criar aplicativos que se comuniquem entre o host do Hyper-V e suas máquinas virtuais usando soquetes do Hyper-V – um soquete do Windows com uma nova família de endereços e um ponto de extremidade especializado para direcionamento de máquinas virtuais. Todas as comunicações por meio de soquetes do Hyper-V funcionam sem o uso de rede e todos os dados permanecem na mesma memória física. Os aplicativos que usam soquetes do Hyper-V são semelhantes aos serviços de integração do Hyper-V.

Este documento explica como criar um programa simples baseado em soquetes do Hyper-V.

Sistema operacional do host com suporte

  • Windows 10 e posterior
  • Windows Server 2016 e posterior

Sistema operacional convidado com suporte

Observação: um convidado Linux com suporte deve ter suporte de kernel para:

CONFIG_VSOCKET=y
CONFIG_HYPERV_VSOCKETS=y

Funcionalidades e Limitações

  • Dá suporte a ações de modo de usuário ou modo de kernel
  • Somente o fluxo de dados
  • Nenhuma memória de bloco (não é a melhor para backup/vídeo)

Introdução

Requisitos:

  • Compilador C/C++. Se você não tiver um, confira Visual Studio Community
  • SDK do Windows 10 – pré-instalado no Visual Studio 2015 com Atualização 3 e posterior.
  • Um computador com um dos sistemas operacionais host acima com pelo menos uma máquina virtual. – isso é para testar seu aplicativo.

Observação: a API para soquetes do Hyper-V se tornou publicamente disponível na Atualização de Aniversário do Windows 10. Os aplicativos que usam o HVSocket funcionarão em qualquer host e convidado do Windows 10, mas só podem ser desenvolvidos com um SDK do Windows posterior ao build 14290.

Registrar um novo aplicativo

Para usar soquetes do Hyper-V, o aplicativo deve ser registrado com o Registro de Host do Hyper-V.

Ao registrar o serviço no Registro, você obtém:

  • Gerenciamento de WMI para habilitar, desabilitar e listar os serviços disponíveis
  • Permissão para se comunicar diretamente com máquinas virtuais

O PowerShell a seguir registrará um novo aplicativo chamado "Demonstração de Soquete do HV". Ele deve ser executado como administrador. Instruções manuais abaixo.

$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

Localização e informações do Registro:

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

No local do Registro, você verá vários GUIDs. Esses são nossos serviços nativos.

Informações no Registro por serviço:

  • Service GUID
    • ElementName (REG_SZ) — este é o nome amigável do serviço

Para registrar seu próprio serviço, crie uma nova chave de registro usando seu próprio GUID e o nome amigável.

O nome amigável será associado ao seu novo aplicativo. Ele aparecerá nos contadores de desempenho e em outros lugares onde um GUID não é apropriado.

A entrada do Registro será assim:

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

Observação: o GUID de Serviço de um convidado Linux usa o protocolo VSOCK, que endereça por meio de um svm_cid e svm_port em vez de um guids. Para criar uma ponte entre essa inconsistência e o Windows, o GUID bem conhecido é usado como o modelo de serviço no host, que traduz para uma porta no convidado. Para personalizar o GUID de Serviço, simplesmente altere os primeiros "00000000" para o número da porta desejado. Por exemplo: "00000ac9" é a porta 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
  */

Dica: para gerar um GUID no PowerShell e copiá-lo para a área de transferência, execute:

(New-Guid).Guid | clip.exe

Criar um soquete do Hyper-V

No caso mais básico, definir um soquete requer uma família de endereços, um tipo de conexão e um protocolo.

Segue uma definição simples de soquete

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

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

Para um soquete do Hyper-V:

  • Família de endereços - AF_HYPERV (Windows) ou AF_VSOCK (convidado Linux)
  • tipo - SOCK_STREAM
  • protocolo - HV_PROTOCOL_RAW (Windows) ou 0 (convidado Linux)

Segue um exemplo de declaração/instanciação:

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

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

Associar a um soquete do Hyper-V

A associação vincula um soquete às informações de conexão.

A definição da função é copiada abaixo para conveniência, leia mais sobre a associação aqui.

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

Em contraste com o endereço de soquete (sockaddr) para uma família de endereços do protocolo de internet padrão (AF_INET) que consiste no endereço IP e um número da porta no computador host, o endereço de soquete para AF_HYPERV usa a ID da máquina virtual e a ID do aplicativo definida acima para estabelecer uma conexão. Se estiver associando de um convidado Linux, AF_VSOCK usará o svm_cid e a svm_port.

Como soquetes do Hyper-V não dependem de uma pilha de rede, TCP/IP, DNS, etc., o ponto de extremidade de soquete necessita de um formato sem IP e sem nome do host que ainda descreve a conexão sem ambiguidade.

Esta é a definição para o endereço de soquete de um soquete do 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)];
};

Em vez de um IP ou nome de host, pontos de extremidade AF_HYPERV dependem fortemente de dois GUIDs:

  • ID da VM – essa é a ID exclusiva atribuída por VM. Uma ID da VM pode ser encontrada usando o seguinte snippet do PowerShell.
    (Get-VM -Name $VMName).Id
    
  • ID de Serviço – GUID, descrito acima, com que o aplicativo está registrado no registro do host do Hyper-V.

Há também um conjunto de caracteres curinga de VMID disponível quando uma conexão não for específica para a máquina virtual.

Caracteres curinga de VMID

Nome GUID Descrição
HV_GUID_ZERO 00000000-0000-0000-0000-000000000000 Ouvintes devem ser vinculados a essa VmId para aceitar conexão de todas as partições.
HV_GUID_WILDCARD 00000000-0000-0000-0000-000000000000 Ouvintes devem ser vinculados a essa VmId para aceitar conexão de todas as partições.
HV_GUID_BROADCAST FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF
HV_GUID_CHILDREN 90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd Endereço de curinga para os filhos. Os ouvintes devem ser associados a essa VmId para aceitar a conexão de todos os filhos.
HV_GUID_LOOPBACK e0e16197-dd56-4a10-9195-5ee7a155a838 Endereço de loopback. Usar essa VmId conecta à mesma partição que o conector.
HV_GUID_PARENT a42e7cda-d03f-480c-9cc2-a4de20abb878 Endereço do pai. Usar essa VmId conecta à partição pai do connector.*

* HV_GUID_PARENT O pai de uma máquina virtual é seu host. O pai de um contêiner é o host do contêiner. Conectar-se de um contêiner em execução em uma máquina virtual se conectará à VM que hospeda o contêiner. A escuta nessa VmId aceita a conexão de: (dentro de contêineres): host do contêiner. (Dentro da VM: host do contêiner / nenhum contêiner): host da VM. (Fora da VM: host do contêiner / nenhum contêiner): sem suporte.

Comandos de soquete com suporte

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

Concluir a API do WinSock

Referência dos serviços de integração do Hyper-V