Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Scambio di dati è un servizio di integrazione (noto anche come scambio di coppie chiave-valore o KVP) che può essere usato per condividere piccole informazioni tra una macchina virtuale (guest) e il relativo host Hyper-V. Le informazioni generali sulla macchina virtuale e sull'host vengono create e archiviate automaticamente come coppie chiave-valore. È anche possibile creare coppie personalizzate per condividere dati personalizzati.
Le coppie chiave-valore sono costituite da una "chiave" e da un "valore". Entrambe sono stringhe; non sono supportati altri tipi di dati. Quando viene creata o modificata una coppia chiave-valore, diventa visibile sia al guest che all'host. I dati KVP passano attraverso la Hyper-V VMbus e non richiedono alcuna connettività di rete tra il guest e l'host.
Una volta create, le coppie chiave-valore rimangono fino a quando non vengono eliminate. Tutte le applicazioni che creano coppie chiave-valore devono eliminarle quando non sono più necessarie. Le coppie chiave-valore si spostano con la macchina virtuale durante la migrazione in tempo reale.
Utenti guest di Windows
Nei guest di Windows i dati KVP vengono archiviati nel Registro di sistema in:
HKLM\SOFTWARE\Microsoft\Virtual Machine
I dati sono organizzati in queste sottochiavi:
- Macchina virtuale\Auto : dati che descrivono il guest. Creato dai driver del servizio di integrazione dopo il caricamento. Visibile all'host come dati intrinseci.
- Macchina virtuale\Esterna – i dati inviati al guest dall'host da un utente.
- Macchina virtuale\Ospite – dati creati sull'ospite. Visibile all'host come dati non intrinseci.
- Macchina virtuale\Guest\Parameter : dati trasferiti nel guest dall'host che descrivono l'host.
L'aggiunta di valori dall'interno del guest è facile quanto creare un nuovo valore stringa in HKLM\SOFTWARE\Microsoft\Virtual Machine\Guest. Per modificare questo percorso, è necessario essere un amministratore del sistema operativo guest. È possibile usare WMI (PowerShell o altri strumenti) dall'host o da un computer remoto (con autorizzazioni) per recuperare il valore.
Per informazioni sui limiti delle dimensioni del Registro di sistema, vedere l'articolo (legacy) Limiti delle dimensioni degli elementi del Registro di sistema.
Aggiungere una nuova coppia chiave-valore nel guest
In questo esempio il valore di Status è impostato su Ready:
$regPath = "HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest"
Set-ItemProperty -Path $regPath -Name "Status" -Value "Ready" -Type String
È possibile usare la stessa sintassi per modificare il valore.
Eseguire query sulle coppie chiave-valore nel guest
Per interrogare il valore della sottochiave Esterna (dati trasmessi al guest dall'host):
$regPath = "HKLM:\SOFTWARE\Microsoft\Virtual Machine\External"
Get-ItemProperty -Path $regPath -Name "Name"
Ospiti Linux
Linux non dispone di un registro, quindi gli elementi KVP vengono archiviati nel file system. Un processo daemon, hv_kvp_daemon, deve essere in esecuzione per gestire l'elaborazione. Per la maggior parte delle distribuzioni con Linux Integration Services (LIS) o driver in kernel installati, questo daemon viene avviato automaticamente. In alcuni casi, potrebbero essere necessari passaggi aggiuntivi per installare e avviare il daemon.
I servizi di integrazione Linux implementano lo scambio di dati con i pool KVP. Un pool KVP è un file archiviato in un percorso specifico. Sono disponibili quattro file del pool:
/var/lib/hyperv/.kvp_pool_0
/var/lib/hyperv/.kvp_pool_1
/var/lib/hyperv/.kvp_pool_2
/var/lib/hyperv/.kvp_pool_3
Questi file del pool vengono mappati ai set di chiavi del Registro di sistema di Windows seguenti:
- Pool 0:
Virtual Machine\External - Pool 1:
Virtual Machine\Guest - Pool 2:
Virtual Machine\Auto - Pool 3:
Virtual Machine\Guest\Parameter
Annotazioni
Per altre informazioni sul supporto KVP di Linux, vedere Macchine virtuali Linux e FreeBSD in Hyper-V.
L'infrastruttura della coppia chiave-valore potrebbe non funzionare correttamente senza un aggiornamento software Linux. Se si verificano problemi, contattare il fornitore di distribuzione per un aggiornamento.
Struttura del pool
Ogni file del pool contiene record con questa struttura:
struct kvp_record
{
unsigned char key[ HV_KVP_EXCHANGE_MAK_KEY_SIZE ];
unsigned char value[ HV_KVP_EXCHANGE_MAX_VALUE_SIZE ];
};
Tali costanti di dimensioni sono definite in hyperv.h (un'intestazione del kernel distribuita con le origini del kernel Linux).
Leggere e visualizzare i valori del pool 0
Questo esempio legge i valori KVP dal pool 0 e li visualizza.
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include "../include/linux/hyperv.h"
typedef struct kvp_record
{
unsigned char key [HV_KVP_EXCHANGE_MAX_KEY_SIZE];
unsigned char value [HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
} KVP_RECORD;
KVP_RECORD myRecords[200];
void KVPAcquireLock(int fd)
{
struct flock fl = {F_RDLCK, SEEK_SET, 0, 0, 0};
fl.l_pid = getpid();
if (-1 == fcntl(fd, F_SETLKW, &fl))
{
perror("fcntl lock");
exit (-10);
}
}
void KVPReleaseLock(int fd)
{
struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
fl.l_pid = getpid();
if (-1 == fcntl(fd, F_SETLK, &fl))
{
perror("fcntl unlock");
exit (-20);
}
}
int main (int argc, char **argv)
{
char poolName[] = "/var/lib/hyperv/.kvp_pool_0";
int i;
int fd;
int bytesRead;
int numRecords;
fd = open(poolName, O_RDONLY);
if (-1 == fd)
{
printf("Error: Unable to open pool file %s\n", poolName);
exit (-30);
}
KVPAcquireLock(fd);
bytesRead = read(fd, myRecords, sizeof(myRecords));
KVPReleaseLock(fd);
numRecords = bytesRead / sizeof(struct kvp_record);
printf("Number of records : %d\n", numRecords);
for (i = 0; i < numRecords; i++)
{
printf(" Key : %s\n Value: %s\n\n", myRecords[i].key, myRecords[i].value);
}
close(fd);
return 0;
}
Creare un elemento KVP nel pool 1
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include "../include/linux/hyperv.h"
typedef struct kvp_record
{
unsigned char key [HV_KVP_EXCHANGE_MAX_KEY_SIZE];
unsigned char value [HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
} KVP_RECORD;
void KVPAcquireWriteLock(int fd)
{
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
fl.l_pid = getpid();
if (-1 == fcntl(fd, F_SETLKW, &fl))
{
perror("fcntl lock");
exit (-10);
}
}
void KVPReleaseLock(int fd)
{
struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
fl.l_pid = getpid();
if (-1 == fcntl(fd, F_SETLK, &fl))
{
perror("fcntl unlock");
exit (-20);
}
}
int main (int argc, char **argv)
{
char poolName[] = "/var/lib/hyperv/.kvp_pool_1";
int fd;
KVP_RECORD newKvp;
if (3 != argc)
{
printf("Usage: WritePool keyName valueString\n\n");
exit (-5);
}
fd = open(poolName, O_WRONLY);
if (-1 == fd)
{
printf("Error: Unable to open pool file %s\n", poolName);
exit (-30);
}
memset((void *)&newKvp, 0, sizeof(KVP_RECORD));
memcpy(newKvp.key, argv[1], strlen(argv[1]));
memcpy(newKvp.value, argv[2], strlen(argv[2]));
KVPAcquireWriteLock(fd);
write(fd, (void *)&newKvp, sizeof(KVP_RECORD));
KVPReleaseLock(fd);
close(fd);
return 0;
}
Eliminare un elemento KVP dal pool 1
In questo esempio viene eliminato un elemento.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <uapi/linux/hyperv.h>
typedef struct kvp_record
{
unsigned char key [HV_KVP_EXCHANGE_MAX_KEY_SIZE];
unsigned char value [HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
} KVP_RECORD;
void KVPAcquireWriteLock(int fd)
{
struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
fl.l_pid = getpid();
if (-1 == fcntl(fd, F_SETLKW, &fl))
{
perror("fcntl lock");
exit (-10);
}
}
void KVPReleaseLock(int fd)
{
struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
fl.l_pid = getpid();
if (-1 == fcntl(fd, F_SETLK, &fl))
{
perror("fcntl unlock");
exit (-20);
}
}
int find_record_offset(int fd, char *key)
{
int bytesRead;
int offset = 0;
int retval = -1;
KVP_RECORD kvpRec;
while (1)
{
lseek(fd, offset, SEEK_SET);
bytesRead = read(fd, &kvpRec, sizeof(KVP_RECORD));
if (0 == bytesRead)
{
break;
}
if (0 == strcmp(key, (const char *) kvpRec.key))
{
retval = offset;
break;
}
offset += sizeof(KVP_RECORD);
}
return retval;
}
int main (int argc, char **argv)
{
char poolName[] = "/var/lib/hyperv/.kvp_pool_1";
int fd;
int exitVal = -1;
int bytesRead;
int bytesWritten;
int offset_to_delete;
int offset_last_record;
KVP_RECORD kvpRec;
if (2 != argc)
{
printf("Usage: WritePool keyName valueString\n\n");
exit (-5);
}
fd = open(poolName, O_RDWR, 0644);
if (-1 == fd)
{
printf("Error: Unable to open pool file %s\n", poolName);
exit (-10);
}
KVPAcquireWriteLock(fd);
offset_to_delete = find_record_offset(fd, argv[1]);
if (offset_to_delete < 0)
{
exitVal = -15;
goto cleanup2;
}
offset_last_record = lseek(fd, -sizeof(KVP_RECORD), SEEK_END);
if (offset_last_record < 0)
{
exitVal = -20;
goto cleanup2;
}
if (offset_last_record != offset_to_delete)
{
lseek(fd, offset_last_record, SEEK_SET);
bytesRead = read(fd, &kvpRec, sizeof(KVP_RECORD));
lseek(fd, offset_to_delete, SEEK_SET);
bytesWritten = write(fd, &kvpRec, sizeof(KVP_RECORD));
}
ftruncate(fd, offset_last_record);
exitVal = 0;
cleanup2:
KVPReleaseLock(fd);
cleanup1:
close(fd);
return exitVal;
}
Lavorare con coppie di chiavi e valori dall'host utilizzando WMI
Negli esempi seguenti viene usato lo spazio dei nomi WMI v2. Per WMI v1 (versioni precedenti), rimuovere il \v2 segmento dal percorso dello spazio dei nomi.
Annotazioni
Se utilizzi Windows 8 o Windows 8.1, installa Client Hyper-V per ottenere i namespaces.
Leggere il valore dall'host
Questo esempio ottiene il valore della chiave Status da una macchina virtuale denominata Vm1:
$vm = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_ComputerSystem -Filter {ElementName = 'Vm1'}
$vm.GetRelated("Msvm_KvpExchangeComponent").GuestExchangeItems | % { \
$GuestExchangeItemXml = ([XML]$_).SelectSingleNode(\
"/INSTANCE/PROPERTY[@NAME='Name']/VALUE[child::text() = 'Status']")
if ($GuestExchangeItemXml -ne $null)
{
$GuestExchangeItemXml.SelectSingleNode(\
"/INSTANCE/PROPERTY[@NAME='Data']/VALUE/child::text()" ).Value
}
}
Aggiungi o modifica le coppie chiave-valore dall'host
Per aggiungere una coppia chiave-valore dall'host, accedi alle istanze del servizio di gestione e della macchina virtuale e crea una nuova istanza di Msvm_KvpExchangeDataItem. Quando si crea la nuova istanza, specificare Name, Datae Source (deve essere 0). Quindi chiamare AddKvpItems.
L'esecuzione di query per le coppie chiave-valore create dall'host è simile alle query guest, ma richiede un hop di associazione aggiuntivo a Msvm_KvpExchangeComponentSettingData. La modifica e l'eliminazione di valori funzionano allo stesso modo: specificare lo stesso nome di chiave e chiamare il metodo appropriato Modify o Remove.
Importante
Gli esempi seguenti usano lo spazio dei nomi v2. Se si usa Windows Server 2008 o Windows Server 2008 R2, rimuovere il \v2 segmento.
Aggiungere una nuova coppia chiave-valore
$VmMgmt = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_VirtualSystemManagementService
$vm = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_ComputerSystem -Filter {ElementName='VM1'}
$kvpDataItem = ([WMIClass][String]::Format("\\{0}\\{1}:{2}", \
$VmMgmt.ClassPath.Server, \
$VmMgmt.ClassPath.NamespacePath, \
"Msvm_KvpExchangeDataItem")).CreateInstance()
$kvpDataItem.Name = "Name"
$kvpDataItem.Data = "Data"
$kvpDataItem.Source = 0
$VmMgmt.AddKvpItems($Vm, $kvpDataItem.PSBase.GetText(1))
Eseguire query sulle coppie chiave-valore nell'host
$VmMgmt = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_VirtualSystemManagementService
$vm = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_ComputerSystem -Filter {ElementName='VM1'}
($vm.GetRelated("Msvm_KvpExchangeComponent")[0] ).GetRelated("Msvm_KvpExchangeComponentSettingData").HostExchangeItems | % { \
$GuestExchangeItemXml = ([XML]$_).SelectSingleNode(\
"/INSTANCE/PROPERTY[@NAME='Name']/VALUE[child::text() = 'Name2']")
if ($GuestExchangeItemXml -ne $null)
{
$GuestExchangeItemXml.SelectSingleNode(\
"/INSTANCE/PROPERTY[@NAME='Data']/VALUE/child::text()" ).Value
}
}
Modificare una coppia chiave-valore
$VmMgmt = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_VirtualSystemManagementService
$vm = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_ComputerSystem -Filter {ElementName='VM1'}
$kvpDataItem = ([WMIClass][String]::Format("\\{0}\\{1}:{2}", \
$VmMgmt.ClassPath.Server, \
$VmMgmt.ClassPath.NamespacePath, \
"Msvm_KvpExchangeDataItem")).CreateInstance()
$kvpDataItem.Name = "Name"
$kvpDataItem.Data = "Data2"
$kvpDataItem.Source = 0
$VmMgmt.ModifyKvpItems($Vm, $kvpDataItem.PSBase.GetText(1))
Rimuovere una coppia chiave-valore
$VmMgmt = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_VirtualSystemManagementService
$vm = Get-WmiObject -Namespace root\virtualization\v2 -Class \
Msvm_ComputerSystem -Filter {ElementName='VM1'}
$kvpDataItem = ([WMIClass][String]::Format("\\{0}\\{1}:{2}", \
$VmMgmt.ClassPath.Server, \
$VmMgmt.ClassPath.NamespacePath, \
"Msvm_KvpExchangeDataItem")).CreateInstance()
$kvpDataItem.Name = "Name"
$kvpDataItem.Data = [String]::Empty
$kvpDataItem.Source = 0
$VmMgmt.RemoveKvpItems($Vm, $kvpDataItem.PSBase.GetText(1))