Creare servizi di integrazione personalizzati

A partire dall'aggiornamento dell'anniversario di Windows 10, chiunque può creare applicazioni che comunicano tra l'host Hyper-V e le relative macchine virtuali usando i socket Hyper-V, ovvero un Windows Socket con una nuova famiglia di indirizzi e un endpoint specializzato per le macchine virtuali di destinazione. Tutte le comunicazioni sui socket Hyper-V vengono eseguite senza usare la rete e tutti i dati rimangono nella stessa memoria fisica. Le applicazioni che usano socket Hyper-V sono simili ai servizi di integrazione di Hyper-V.

Questo documento illustra come creare un semplice programma basato su socket Hyper-V.

Sistema operativo host supportato

  • Windows 10 e versioni successive
  • Windows Server 2016 e versioni successive

Sistema operativo guest supportato

Nota

un guest Linux supportato deve disporre del supporto kernel per:

CONFIG_VSOCKET=y
CONFIG_HYPERV_VSOCKETS=y

Funzionalità e limitazioni

  • Supporta azioni in modalità kernel o in modalità utente
  • Solo flusso di dati
  • Nessuna memoria a blocchi (non ottimale per il backup/video)

Introduzione

Requisiti:

  • Compilatore C/C++. Se non è disponibile, vedere Visual Studio Community
  • Windows SDK : preinstallato in Visual Studio 2015 con Update 3 e versioni successive.
  • Un computer che esegue uno dei sistemi operativi host specificati con almeno un computer vitual. - Questo è per il test dell'applicazione.

Nota: l'API per i socket Hyper-V è diventata disponibile pubblicamente nell'aggiornamento dell'anniversario di Windows 10. Le applicazioni che usano HVSocket verranno eseguite in qualsiasi host e guest Windows 10, ma possono essere sviluppate solo con una versione di Windows SDK successiva alla build 14290.

Registrare una nuova applicazione

Per usare i socket Hyper-V, l'applicazione deve essere registrata nel Registro di sistema dell'host Hyper-V.

Registrando il servizio nel Registro di sistema, si ottiene:

  • Gestione WMI per abilitare, disabilitare ed elencare i servizi disponibili
  • Autorizzazione per comunicare direttamente con le macchine virtuali

PowerShell seguente registrerà una nuova applicazione denominata "HV Socket Demo". Deve essere eseguito come amministratore. Istruzioni manuali riportate di seguito.

$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

Percorso del Registro di sistema e informazioni correlate:

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

In questo percorso del Registro di sistema verranno visualizzati diversi GUID. Questi sono i nostri servizi in scatola.

Informazioni nel Registro di sistema per servizio:

  • Service GUID
    • ElementName (REG_SZ) - questo è il nome descrittivo del servizio

Per registrare il proprio servizio, creare una nuova chiave del Registro di sistema usando il proprio GUID e il nome descrittivo.

Il nome descrittivo verrà associato alla nuova applicazione. Verrà visualizzato nei contatori delle prestazioni e in altre posizioni in cui un GUID non è appropriato.

La voce del Registro di sistema è simile alla seguente:

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

Nota

il GUID del servizio per un guest Linux usa il protocollo VSOCK usato tramite svm_cide svm_port invece di un GUID. Per ovviare al problema di incoerenza con Windows si usa il GUID noto come modello di servizio nell'host che viene convertito in una porta nel guest. Per personalizzare il GUID del servizio è sufficiente modificare il primo "00000000" per il numero di porta desiderato. Ad esempio: "00000ac9" è la 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
  */

Suggerimento: per generare un GUID in PowerShell e copiarlo negli Appunti, eseguire:

(New-Guid).Guid | clip.exe

Creare un socket Hyper-V

Nel caso più semplice, la definizione di un socket richiede una famiglia di indirizzi, un tipo di connessione e un protocollo.

Ecco una definizione di socket semplice

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

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

Per un socket Hyper-V:

  • Famiglia di indirizzi: AF_HYPERV (Windows) o AF_VSOCK (guest Linux)
  • tipo - SOCK_STREAM
  • Protocollo: HV_PROTOCOL_RAW (Windows) o 0 (guest Linux)

Di seguito è riportato un esempio di dichiarazione/creazione di istanze:

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

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

Eseguire l'associazione a un socket Hyper-V

Bind associa un socket alle informazioni di connessione.

La definizione della funzione viene copiata di seguito per la convinzione. Per altre informazioni sull'associazione , vedere qui.

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

A differenza dell'indirizzo socket (sockaddr) per una famiglia di indirizzi Internet Protocol standard (AF_INET) costituita dall'indirizzo IP del computer host e da un numero di porta in tale host, l'indirizzo del socket per AF_HYPERV usa l'ID della macchina virtuale e l'ID applicazione definiti in precedenza per stabilire una connessione. In caso di associazione da un guest Linux, AF_VSOCK usa svm_cid e svm_port.

Poiché i socket Hyper-V non dipendono da uno stack di rete, TCP/IP, DNS e così via. L'endpoint socket richiedeva un formato non IP, non hostname, che descrive comunque in modo non ambiguo la connessione.

Ecco la definizione per l'indirizzo socket di un socket 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)];
};

Al posto di un IP o di un nome host, AF_HYPERV endpoint si basano principalmente su due GUID:

  • ID macchina virtuale: id univoco assegnato per ogni macchina virtuale. L'ID di una macchina virtuale è reperibile usando il frammento di codice di PowerShell seguente.

    (Get-VM -Name $VMName).Id
    
  • ID servizio: GUID, descritto in precedenza, con cui l'applicazione è registrata nel Registro di sistema host Hyper-V.

È disponibile anche un set di caratteri jolly VMID quando una connessione non è a una macchina virtuale specifica.

Caratteri jolly VMID

Nome GUID Descrizione
HV_GUID_ZERO 00000000-0000-0000-0000-000000000000 I listener devono essere associati a questo VMId per accettare la connessione da tutte le partizioni.
HV_GUID_WILDCARD 00000000-0000-0000-0000-000000000000 I listener devono essere associati a questo VMId per accettare la connessione da tutte le partizioni.
HV_GUID_BROADCAST FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFFFF
HV_GUID_CHILDREN 90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd Indirizzo con caratteri jolly per gli elementi figlio. I listener devono essere associati a questo ID vm per accettare la connessione dai relativi elementi figlio.
HV_GUID_LOOPBACK e0e16197-dd56-4a10-9195-5ee7a155a838 Indirizzo di loopback. L'uso di questo ID vm si connette alla stessa partizione del connettore.
HV_GUID_PARENT a42e7cda-d03f-480c-9cc2-a4de20abb878 Indirizzo padre. L'uso di questo ID vm si connette alla partizione padre del connettore.*

* HV_GUID_PARENT L'elemento padre di una macchina virtuale è il relativo host. L'elemento padre di un contenitore è l'host del contenitore. La connessione da un contenitore in esecuzione in una macchina virtuale si connetterà alla macchina virtuale che ospita il contenitore. L'ascolto su questo VMId accetta la connessione da: (All'interno dei contenitori): host contenitore. (All'interno della macchina virtuale: host contenitore/ nessun contenitore): host della macchina virtuale. (Non all'interno della macchina virtuale: host contenitore/ nessun contenitore): non supportato.

Comandi socket supportati

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

Opzioni socket HvSocket

Nome Tipo Descrizione
HVSOCKET_CONNECTED_SUSPEND ULONG Quando questa opzione socket è impostata su un socket senza valore zero, non disconnettersi quando la macchina virtuale viene sospesa.

Completare l'API WinSock

Riferimento per i servizi di integrazione Hyper-V