目前找到两种方案。方案一:libvirt命令获取。 方案二:调用libvirt-api获取。
相关命令如下:
virsh #进入virsh 命令模式
list --all # 查看所有在线的虚拟机列表
虚拟机列表输出结果如下:
Id Name State
----------------------------------------------------
1 151 running
- 170 shut off
- win10 shut off
可以看出正在运行的虚拟机 为 151
查看151支持的相关命令
qemu-agent-command 151 '{"execute":"guest-info"}'
输出结果如下:
{"return":{"version":"0.12.1","supported_commands":[{"enabled":true,"name":"guest-set-user-password"},{"enabled":true,"name":"guest-get-vcpus"},{"enabled":true,"name":"guest-suspend-ram"},{"enabled":true,"name":"guest-suspend-disk"},{"enabled":true,"name":"guest-fsfreeze-thaw"},{"enabled":true,"name":"guest-fsfreeze-freeze"},{"enabled":true,"name":"guest-fsfreeze-status"},{"enabled":true,"name":"guest-shutdown"},{"enabled":true,"name":"guest-info"},{"enabled":true,"name":"guest-set-time"},{"enabled":true,"name":"guest-get-time"},{"enabled":true,"name":"guest-ping"},{"enabled":true,"name":"guest-sync"},{"enabled":true,"name":"guest-sync-delimited"}]}}
获取虚拟机IP的主要命令如下:
qemu-agent-command 151 '{"execute":"guest-network-get-interfaces"}'
输出结果如下:
{"return":[{"name":"��̫��e","ip-addresses":[{"ip-address-type":"ipv6","ip-address":"fe80::9ded:74ad:cbc9:7ec2%5","prefix":64},{"ip-address-type":"ipv4","ip-address":"172.26.106.102","prefix":24}],"statistics":{"tx-packets":183723,"tx-errs":0,"rx-bytes":482140384,"rx-dropped":4781392,"rx-packets":329018,"rx-errs":0,"tx-bytes":12037307,"tx-dropped":0},"hardware-address":"52:54:00:89:0e:2b"},{"name":"Loopback Pseudo-Interface 1","ip-addresses":[{"ip-address-type":"ipv6","ip-address":"::1","prefix":128},{"ip-address-type":"ipv4","ip-address":"127.0.0.1","prefix":8}],"statistics":{"tx-packets":0,"tx-errs":0,"rx-bytes":0,"rx-dropped":0,"rx-packets":0,"rx-errs":0,"tx-bytes":0,"tx-dropped":0}},{"name":"Teredo Tunneling Pseudo-Interface","ip-addresses":[{"ip-address-type":"ipv6","ip-address":"2001:0:348b:fb58:28bf:26c3:2ca1:2326","prefix":64},{"ip-address-type":"ipv6","ip-address":"fe80::28bf:26c3:2ca1:2326%3","prefix":64}],"statistics":{"tx-packets":165,"tx-errs":0,"rx-bytes":18504,"rx-dropped":0,"rx-packets":191,"rx-errs":0,"tx-bytes":18780,"tx-dropped":0},"hardware-address":"00:00:00:00:00:00"}]}
所有相关的ip信息如下: ip地址类型,ip地址,硬件地址
官方接口地址:https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainIPAddress
相关结构体如下:
struct virDomainIPAddress { //ip信息结构体
int type; //virIPAddrType
char * addr; //IP address
unsigned int prefix; //IP address prefix
}
struct virDomainInterface { //接口信息结构体
char * name; //interface name
char * hwaddr; //hardware address, may be NULL
unsigned int naddrs; //number of items in @addrs
virDomainIPAddressPtr addrs; //array of IP addresses
}
/*
Return a pointer to the allocated array of pointers to interfaces present in given domain along with their IP and MAC addresses. Note that single interface can have multiple or even 0 IP addresses
*/
int virDomainInterfaceAddresses (virDomainPtr dom,
virDomainInterfacePtr ** ifaces,
unsigned int source,
unsigned int flags) //interface接口地址获取方法
enum virDomainInterfaceAddressesSource { //ip地址的枚举类型
VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE = 0 (0x0) ,//Parse DHCP lease file
VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT = 1 (0x1) ,//Query qemu guest agent
VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP = 2 (0x2) ,//Query ARP tables
VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LAST = 3 (0x3)
}
目前笔者用的 类型为 VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT ,获取指定虚拟机IP。 VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE为获取 DHCP 方式的虚拟机IP。VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP,VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LAST这两种类型,笔者的libvirt版本不支持也就没有测试。
官方Demo样例如下:
virDomainInterfacePtr *ifaces = NULL; //接口指针初始化 --网卡
int ifaces_count = 0; //接口个数
size_t i, j;
virDomainPtr dom = /*... obtain a domain here ...*/;
if ((ifaces_count = virDomainInterfaceAddresses(dom, &ifaces,
VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE)) < 0)
goto cleanup;
//... do something with returned values, for example:
for (i = 0; i < ifaces_count; i++) {
printf("name: %s", ifaces[i]->name);
if (ifaces[i]->hwaddr) //网卡个数,硬件地址 MAC
printf(" hwaddr: %s", ifaces[i]->hwaddr);
for (j = 0; j < ifaces[i]->naddrs; j++) {
virDomainIPAddressPtr ip_addr = ifaces[i]->addrs + j;
printf("[addr: %s prefix: %d type: %d]",
ip_addr->addr, ip_addr->prefix, ip_addr->type);
}
printf("\n");
}
cleanup:
if (ifaces && ifaces_count > 0)
for (i = 0; i < ifaces_count; i++)
virDomainInterfaceFree(ifaces[i]);
free(ifaces);//释放接口指针内存
/*参数说明
dom: domain object
ifaces: pointer to an array of pointers pointing to interface objects
source: one of the virDomainInterfaceAddressesSource constants
flags: currently unused, pass zero
Returns: the number of interfaces on success, -1 in case of error.
*/
测试代码如下:
#include
#include
#include
#include
#include
#include
#define MAX_LEN (1024*10)
int main(int argc, char** argv)
{
virConnectPtr conn;
virDomainInterfacePtr* ifaces = NULL;
int ret = -1;
int ifaces_count = 0;
int i,j;
conn = virConnectOpen("qemu:///system");
if(conn == NULL){
printf("failed to open connection to qemu\n");
return 1;
}
printf("success to open connection to qemu\n");
char* xml = malloc(MAX_LEN);
memset(xml,0,MAX_LEN);
FILE* fp = NULL;
//filename 作者写为了固定地址。也可以利用 argv参数进行传参
char filename[128] = {"/etc/libvirt/qemu/151.xml"};
fp = fopen(filename,"r");
if(fp != NULL){
int len = fread(xml,1,MAX_LEN,fp);
printf("len = %d\n",len);
}
else{
printf("fp is null!\n");
}
if(fp != NULL){
fclose(fp);
}
virDomainPtr dom;
dom = virDomainDefineXML(conn,xml);
if(!dom){
printf("domain definition failed\n");
}
if((ifaces_count = virDomainInterfaceAddresses(dom,&ifaces,VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT ,0))<0)
{
goto cleanup;
}
for( i=0;i<ifaces_count;i++)
{
printf("name:%s \n",ifaces[i]->name);
if(ifaces[i]->hwaddr) printf("hwaddr:%s\n",ifaces[i]->hwaddr);
for( j = 0;j < ifaces[i]->naddrs;j++)
{
virDomainIPAddressPtr ip_addr = ifaces[i]->addrs + j;
printf("[addr: %s prefix: %d type: %d]\n",
ip_addr->addr, ip_addr->prefix, ip_addr->type);
}
}
cleanup:
if (ifaces && ifaces_count > 0)
for (i = 0; i < ifaces_count; i++)
virDomainInterfaceFree(ifaces[i]);
free(ifaces);
return ret;
}
编译:
gcc add.c -lvirt -o add
输出结果如下:
success to open connection to qemu
len = 4214
name:��̫��e
hwaddr:52:54:00:89:0e:2b
[addr: fe80::9ded:74ad:cbc9:7ec2%5 prefix: 64 type: 1]
[addr: 172.26.106.102 prefix: 24 type: 0]
name:Loopback Pseudo-Interface 1
[addr: ::1 prefix: 128 type: 1]
[addr: 127.0.0.1 prefix: 8 type: 0]
name:Teredo Tunneling Pseudo-Interface
hwaddr:00:00:00:00:00:00
[addr: fe80::ffff:ffff:fffe%3 prefix: 64 type: 1]
错误一:
libvirt: QEMU Driver error : internal error: unable to execute QEMU agent command 'guest-network-get-interfaces': The command guest-network-get-interfaces has been disabled for this instance
解决方法:
1.查看命令是否启用。网络上黑白名单,但是作者是 ubuntu 系统,并没有找到相关的json文件。查看命令是否被禁用,如果被禁用,则启用。
2.利用 qemu-agent-command 151 '{"execute":"guest-info"}' 命令查看libvirt支持命令,打印信息并没有 guest-network-get-interfaces 命令。原因为;在虚拟机,里边没有安装 qga 即 qemu-ga-x86_64.msi
错误二:
libvirt: QEMU Driver error : argument unsupported: QEMU guest agent is not configured
解决方法:
错误原因:在对应xml文件中,没有增加对应的接口通道 unix 接口 传输信息。接口如下:
<channel type='unix'>
<target type='virtio' name='org.qemu.guest_agent.0'/>
<address type='virtio-serial' controller='0' bus='0' port='2'/>
channel>
其实两个方案本质上都是调用libvirt底层API。只不过命令方式,只是自己封了一层调用命令。