Udostępnij za pośrednictwem


Utwórz własne usługi integracji

Począwszy od rocznicowej aktualizacji systemu Windows 10 każdy może tworzyć aplikacje komunikujące się między hostem Hyper-V a maszynami wirtualnymi przy użyciu gniazd Hyper-V — gniazda systemu Windows z nową rodziną adresów i wyspecjalizowanym punktem końcowym przeznaczonym dla maszyn wirtualnych. Cała komunikacja przez gniazda Hyper-V działa bez korzystania z sieci, a wszystkie dane pozostają w tej samej pamięci fizycznej. Aplikacje korzystające z gniazd Hyper-V są podobne do usług integracji funkcji Hyper-V.

W tym dokumencie opisano tworzenie prostego programu opartego na gniazdach Hyper-V.

Obsługiwany system operacyjny hosta

  • Windows 10 lub nowszy
  • Windows Server 2016 i nowsze

Obsługiwany system operacyjny gościa

Uwaga / Notatka

Obsługiwany gość systemu Linux musi mieć obsługę jądra dla:

CONFIG_VSOCKET=y
CONFIG_HYPERV_VSOCKETS=y

Możliwości i ograniczenia

  • Obsługuje akcje trybu jądra lub trybu użytkownika
  • Tylko strumień danych
  • Brak pamięci blokowej (nie jest to najlepsze rozwiązanie do tworzenia kopii zapasowej/wideo)

Wprowadzenie

Wymagania:

  • Kompilator C/C++. Jeśli go nie masz, sprawdź Visual Studio Community
  • Zestaw Windows SDK — wstępnie zainstalowany w programie Visual Studio 2015 z aktualizacją Update 3 lub nowszą.
  • Komputer z jednym z określonych systemów operacyjnych hosta z co najmniej jedną maszyną wirtualną. — jest to przeznaczone do testowania aplikacji.

Nuta: Interfejs API dla gniazd Hyper-V stał się publicznie dostępny w rocznicowej aktualizacji systemu Windows 10. Aplikacje korzystające z protokołu HVSocket będą działać na dowolnym hoście i gościu systemu Windows 10, ale mogą być opracowywane tylko przy użyciu zestawu Windows SDK później niż kompilacja 14290.

Rejestrowanie nowej aplikacji

Aby można było używać gniazd Hyper-V, aplikacja musi być zarejestrowana w rejestrze hosta Hyper-V.

Rejestrując usługę w rejestrze, uzyskujesz następujące informacje:

  • Zarządzanie usługami WMI na potrzeby włączania, wyłączania i wyświetlania dostępnych usług
  • Uprawnienie do bezpośredniej komunikacji z maszynami wirtualnymi

Poniższy skrypt PowerShell zarejestruje nową aplikację pod nazwą "HV Socket Demo". Musi to być uruchomione jako administrator. Instrukcje ręczne poniżej.

$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

Lokalizacja rejestru i informacje:

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

W tej lokalizacji rejestru zobaczysz kilka identyfikatorów GUID (Global Unique Identifier). Są to nasze usługi w pakiecie.

Informacje w rejestrze dla każdej usługi:

  • Service GUID
    • ElementName (REG_SZ) — jest to przyjazna nazwa usługi

Aby zarejestrować własną usługę, utwórz nowy klucz rejestru przy użyciu własnego identyfikatora GUID i przyjaznej nazwy.

Przyjazna nazwa zostanie skojarzona z nową aplikacją. Pojawi się on w licznikach wydajności i innych miejscach, w których identyfikator GUID nie jest odpowiedni.

Wpis rejestru wygląda następująco:

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

Uwaga / Notatka

Identyfikator GUID usługi dla gościa systemu Linux używa protokołu VSOCK, który adresuje się za pośrednictwem elementu svm_cid i svm_port zamiast identyfikatorów GUID. W celu pokonania tej niespójności z systemem Windows, znany identyfikator GUID jest używany jako szablon usługi na hoście, co przekłada się na port w maszynie wirtualnej. Aby dostosować identyfikator GUID usługi, wystarczy zamienić pierwszą część "00000000" na żądany numer portu. Przykładowo, "00000ac9" jest portem 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
  */

Porada: Aby wygenerować identyfikator GUID w PowerShell i skopiować go do schowka, uruchom:

(New-Guid).Guid | clip.exe

Utwórz gniazdo Hyper-V

W najbardziej podstawowym przypadku definiowanie gniazda wymaga rodziny adresów, typu połączenia i protokołu.

Oto prosta definicja gniazda

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

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

W przypadku gniazda Hyper-V:

  • Rodzina adresów — AF_HYPERV (Windows) lub AF_VSOCK (gość systemu Linux)
  • typ - SOCK_STREAM
  • protocol — HV_PROTOCOL_RAW (Windows) lub 0 (gość systemu Linux)

Oto przykładowa deklaracja/wystąpienie:

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

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

Powiązanie do gniazda Hyper-V

Powiązanie kojarzy gniazdo z informacjami o połączeniu.

Definicja funkcji jest kopiowana poniżej w celu uzyskania zbieżności, przeczytaj więcej na temat powiązania tutaj.

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

W przeciwieństwie do adresu gniazda (sockaddr) dla standardowej rodziny adresów internetowych (AF_INET), który składa się z adresu IP maszyny hosta i numeru portu na tym hoście, adres gniazda dla AF_HYPERV używa identyfikatora maszyny wirtualnej oraz identyfikatora aplikacji zdefiniowanych powyżej w celu nawiązania połączenia. Jeśli powiązanie z gościa AF_VSOCK systemu Linux używa elementu svm_cid i svm_port.

Ponieważ gniazda Hyper-V nie zależą od stosu sieciowego, protokołu TCP/IP, serwera DNS itp., punkt końcowy gniazda potrzebuje formatu, który nie jest ani adresem IP, ani nazwą hosta, ale wciąż jednoznacznie opisuje połączenie.

Oto definicja adresu gniazda 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)];
};

Zamiast adresu IP lub nazwy hosta punkty końcowe AF_HYPERV w dużym stopniu polegają na dwóch identyfikatorach GUID.

  • Identyfikator maszyny wirtualnej — jest to unikatowy identyfikator przypisany na maszynę wirtualną. Identyfikator maszyny wirtualnej można znaleźć przy użyciu następującego fragmentu kodu programu PowerShell.

    (Get-VM -Name $VMName).Id
    
  • Identyfikator usługi — identyfikator GUID opisany powyżej, z którym aplikacja jest zarejestrowana w rejestrze hostów Hyper-V.

Istnieje również zestaw symboli wieloznacznych VMID dostępnych, gdy połączenie nie dotyczy określonej maszyny wirtualnej.

Symbole wieloznaczne VMID

Nazwa GUID (Globalny Unikalny Identyfikator) Opis
HV_GUID_ZERO 00000000-0000-0000-0000-000000000000 Odbiorniki powinny być powiązane z tym identyfikatorem VmId, aby akceptowały połączenie ze wszystkich partycji.
HV_GUID_WILDCARD 00000000-0000-0000-0000-000000000000 Odbiorniki powinny być powiązane z tym identyfikatorem VmId, aby akceptowały połączenie ze wszystkich partycji.
HV_GUID_BROADCAST FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF
HV_GUID_CHILDREN 90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd Adres ogólny dla dzieci. Słuchacze powinni wiązać się z tym identyfikatorem VmId, aby akceptować połączenia od jego elementów podrzędnych.
HV_GUID_LOOPBACK e0e16197-dd56-4a10-9195-5ee7a15a838 Adres pętli zwrotnej. Za pomocą tego VmId nawiązuje się połączenie z tą samą partycją co łącznik.
HV_GUID_PARENT a42e7cda-d03f-480c-9cc2-a4de20abb878 Adres rodzica. Użycie tego VmId łączy z partycją nadrzędną łącznika.*

* HV_GUID_PARENT Rodzic maszyny wirtualnej to jej host. Elementem nadrzędnym kontenera jest host kontenera. Nawiązywanie połączenia z kontenera uruchomionego na maszynie wirtualnej spowoduje nawiązanie połączenia z maszyną wirtualną hostująca kontener. Nasłuchiwanie na tym identyfikatorze VM akceptuje połączenia z: (wewnątrz kontenerów): Host kontenera. (Wewnątrz maszyny wirtualnej: host kontenera/ brak kontenera): host maszyny wirtualnej. (Nie wewnątrz maszyny wirtualnej: host kontenera/ brak kontenera): nieobsługiwane.

Obsługiwane polecenia gniazda

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

Opcje gniazda HvSocket

Nazwa Typ Opis
HVSOCKET_CONNECTED_SUSPEND ULONG Gdy ta opcja gniazda jest ustawiona na wartość inną niż zero, gniazda nie rozłączają się po wstrzymaniu maszyny wirtualnej.

Kompletny interfejs API WinSock

Dokumentacja usługHyper-V Integration Services