Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
O Data Exchange é um serviço de integração (também conhecido como troca de pares chave-valor ou KVP) que pode ser usado para compartilhar pequenas informações entre uma máquina virtual (convidado) e seu host Hyper-V. Informações gerais sobre a máquina virtual e o host são criadas e armazenadas automaticamente como pares chave-valor. Você também pode criar seus próprios pares para compartilhar dados personalizados.
Os pares chave-valor consistem em uma "chave" e um "valor". Ambos são sequências; Não são suportados outros tipos de dados. Quando um par chave-valor é criado ou alterado, torna-se visível para o convidado e para o anfitrião. Os dados KVP viajam pelo VMbus Hyper-V e não exigem nenhuma conectividade de rede entre o convidado e o host.
Uma vez criados, os pares chave-valor permanecem até serem excluídos. Qualquer aplicativo que crie pares chave-valor deve excluí-los quando não forem mais necessários. Os pares chave-valor são movidos com a máquina virtual durante a Migração ao Vivo.
Convidados do Windows
Nos computadores Windows, os dados KVP são armazenados no registo em:
HKLM\SOFTWARE\Microsoft\Virtual Machine
Os dados estão organizados nestas subchaves:
- Virtual Machine\Auto – Dados que descrevem o convidado. Criado por controladores de serviço de integração após o carregamento. Visível para o host como dados intrínsecos.
- Máquina Virtual\Externa – Dados enviados do host para o convidado por um usuário.
- Máquina Virtual\Hóspede – Dados criados no hóspede. Visível para o host como dados não intrínsecos.
- Virtual Machine\Guest\Parameter – Dados transferidos para o convidado a partir do host que descrevem o host.
Adicionar valores no ambiente do guest é tão simples quanto criar um novo valor de string em HKLM\SOFTWARE\Microsoft\Virtual Machine\Guest. Você deve ser um administrador no sistema convidado para modificar este local. Você pode usar WMI (PowerShell ou outras ferramentas) do host ou de uma máquina remota (com permissões) para recuperar o valor.
Para obter informações sobre limites de tamanho do Registro, consulte o artigo (legado) Limites de tamanho do elemento do Registro.
Adicionar um novo par chave-valor ao sistema guest
Neste exemplo, o valor de Status é definido como Ready:
$regPath = "HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest"
Set-ItemProperty -Path $regPath -Name "Status" -Value "Ready" -Type String
Você pode usar a mesma sintaxe para alterar o valor.
Interrogar pares chave-valor no sistema convidado
Para consultar o valor da subchave externa (dados enviados do host para o convidado):
$regPath = "HKLM:\SOFTWARE\Microsoft\Virtual Machine\External"
Get-ItemProperty -Path $regPath -Name "Name"
Convidados Linux
O Linux não tem um registro, então os itens KVP são armazenados no sistema de arquivos. Um processo de daemon, hv_kvp_daemon, deve estar em execução para lidar com o processamento. Para a maioria das distribuições com Linux Integration Services (LIS) ou drivers no kernel instalados, este daemon é iniciado automaticamente. Em alguns casos, etapas extras podem ser necessárias para instalar e iniciar o daemon.
Os serviços de integração Linux implementam a troca de dados com pools KVP. Um pool KVP é um arquivo armazenado em um caminho específico. Há quatro arquivos de 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
Esses arquivos de pool são mapeados para os seguintes conjuntos de chaves do Registro do Windows:
- Piscina 0:
Virtual Machine\External - Piscina 1:
Virtual Machine\Guest - Piscina 2:
Virtual Machine\Auto - Piscina 3:
Virtual Machine\Guest\Parameter
Observação
Para obter mais informações sobre o suporte ao Linux KVP, consulte Máquinas virtuais Linux e FreeBSD no Hyper-V.
A infraestrutura do par chave-valor pode não funcionar corretamente sem uma atualização de software Linux. Entre em contato com seu fornecedor de distribuição para obter uma atualização se encontrar problemas.
Estrutura da piscina
Cada arquivo de pool contém registros com esta estrutura:
struct kvp_record
{
unsigned char key[ HV_KVP_EXCHANGE_MAK_KEY_SIZE ];
unsigned char value[ HV_KVP_EXCHANGE_MAX_VALUE_SIZE ];
};
Essas constantes de tamanho são definidas em hyperv.h (um cabeçalho do kernel distribuído com os códigos-fonte do kernel Linux).
Ler e exibir valores do pool 0
Este exemplo lê valores KVP do pool 0 e os exibe.
```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;
}
Criar um item KVP no 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;
}
Excluir um item KVP do pool 1
Este exemplo exclui um item.
#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;
}
Trabalhando com pares chave-valor do host usando WMI
Os exemplos a seguir usam o namespace WMI v2. Para WMI v1 (versões mais antigas), remova o \v2 segmento do caminho do namespace.
Observação
Se você estiver usando o Windows 8 ou o Windows 8.1, instale o Client Hyper-V para obter os namespaces.
Leia o valor do host
Este exemplo obtém o valor da chave Status de uma VM chamada 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
}
}
Adicionar ou modificar pares chave-valor do host
Para adicionar um par chave-valor do host, obtenha as instâncias tanto do serviço de gestão como da VM e crie uma nova instância do Msvm_KvpExchangeDataItem. Ao criar a nova instância, especifique o Name, Datae Source (deve ser 0). Em seguida, ligue para AddKvpItems.
A consulta de pares chave-valor criados pelo host é semelhante às consultas de convidado, mas requer um salto de associação adicional para Msvm_KvpExchangeComponentSettingData. Modificar e excluir valores funcionam da mesma maneira: especifique o mesmo nome de chave e chame o método Modify ou Remove apropriado.
Importante
Os exemplos abaixo usam o namespace v2. Se você estiver usando o Windows Server 2008 ou o Windows Server 2008 R2, remova o \v2 segmento.
Adicionar um novo par chave-valor
$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))
Interrogar pares chave-valor no 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
}
}
Modificar um par de chave-valor
$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))
Remover um par chave-valor
$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))