Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
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 automaticamente criadas e armazenadas 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". Ambas são cadeias de caracteres; não há suporte para outros tipos de dados. Quando um par chave-valor é criado ou alterado, ele fica visível tanto para o convidado quanto para o host. Os dados do KVP viajam pelo Hyper-V VMbus e não exigem nenhuma conectividade de rede entre o convidado e o host.
Depois de criados, os pares chave-valor permanecem até serem excluídos. Qualquer aplicativo que crie pares chave-valor deve excluí-los quando eles não forem mais necessários. Os pares chave-valor se movem com a máquina virtual durante a Migração Dinâmica.
Convidados do Windows
Em convidados do Windows, os dados do KVP são armazenados no registro em:
HKLM\SOFTWARE\Microsoft\Virtual Machine
Os dados são organizados nestas subchaves:
- Máquina Virtual\Auto – Dados que descrevem o convidado. Criado por drivers de serviço de integração após serem carregados. Visível para o host como dados intrínsecos.
- Máquina Virtual\Externa – Dados enviados ao convidado do host 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.
- Máquina Virtual\Máquina Convidada\Parâmetro – Dados transmitidos para a máquina convidada a partir do host, que descrevem as características do host.
Adicionar valores de dentro do ambiente convidado é tão simples quanto criar um novo valor de string em HKLM\SOFTWARE\Microsoft\Virtual Machine\Guest. Você deve ser um administrador do sistema convidado para modificar essa localização. Você pode usar o WMI (PowerShell ou outras ferramentas) do host ou de um computador remoto (com permissões) para recuperar o valor.
Para obter informações sobre os limites de tamanho do Registro, consulte o artigo ( herdado) Limites de tamanho do elemento do Registro.
Adicionar um novo par chave-valor ao convidado
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.
Consultar pares chave-valor no convidado
Para consultar o valor da subchave External (dados transferidos para o convidado a partir do host):
$regPath = "HKLM:\SOFTWARE\Microsoft\Virtual Machine\External"
Get-ItemProperty -Path $regPath -Name "Name"
Convidados do Linux
O Linux não tem um registro, portanto, os itens de KVP são armazenados no sistema de arquivos. Um processo de daemon deve hv_kvp_daemonestar em execução para lidar com o processamento. Para a maioria das distribuições com LIS (Linux Integration Services) ou drivers no kernel instalados, esse daemon é iniciado automaticamente. Em alguns casos, etapas extras podem ser necessárias para instalar e iniciar o daemon.
Os serviços de integração do Linux implementam a troca de dados com pools de KVP. Um pool de 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 associados aos seguintes conjuntos de chaves do Registro do Windows:
- Pool 0:
Virtual Machine\External - Pool 1:
Virtual Machine\Guest - Pool 2:
Virtual Machine\Auto - Pool 3:
Virtual Machine\Guest\Parameter
Observação
Para obter mais informações sobre o suporte ao KVP do Linux, consulte Máquinas Virtuais Linux e FreeBSD no Hyper-V.
A infraestrutura de par chave-valor pode não funcionar corretamente sem uma atualização de software do Linux. Entre em contato com o fornecedor de distribuição para obter uma atualização se você encontrar problemas.
Estrutura do pool
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 um cabeçalho de kernel (distribuído com os códigos-fonte do kernel do Linux).
Ler e exibir valores do pool 0
Este exemplo lê os valores de 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 segmento \v2 do caminho do namespace.
Observação
Se você estiver usando o Windows 8 ou o Windows 8.1, instale o Cliente Hyper-V para obter os namespaces.
Ler o valor do sistema 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 instâncias tanto do serviço de gerenciamento quanto da VM e crie uma nova instância de Msvm_KvpExchangeDataItem. Ao criar a nova instância, especifique o Name, Datae Source (deve ser 0). Em seguida, chame AddKvpItems.
A consulta para 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 funciona da mesma maneira—especifique o mesmo nome de chave e chame o método Modify ou Remove apropriado.
Importante
Os exemplos a seguir 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))
Consulte 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 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))