Created
July 23, 2013 11:42
-
-
Save nehaljwani/6061745 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
daemon/remote.c | 73 +++++++++++++++++ | |
include/libvirt/libvirt.h.in | 23 ++++++ | |
python/generator.py | 1 + | |
python/libvirt-override-api.xml | 6 ++ | |
src/driver.h | 6 ++ | |
src/libvirt.c | 52 ++++++++++++ | |
src/libvirt_public.syms | 1 + | |
src/qemu/qemu_agent.c | 175 ++++++++++++++++++++++++++++++++++++++++ | |
src/qemu/qemu_agent.h | 3 + | |
src/qemu/qemu_driver.c | 64 +++++++++++++++ | |
src/remote/remote_driver.c | 62 +++++++++++++- | |
src/remote/remote_protocol.x | 33 +++++++- | |
tools/virsh-domain-monitor.c | 107 ++++++++++++++++++++++++ | |
13 files changed, 604 insertions(+), 2 deletions(-) | |
diff --git a/daemon/remote.c b/daemon/remote.c | |
index cb362da..ab14ef4 100644 | |
--- a/daemon/remote.c | |
+++ b/daemon/remote.c | |
@@ -5005,6 +5005,79 @@ cleanup: | |
return rv; | |
} | |
+ static int | |
+remoteDispatchDomainInterfacesAddresses( | |
+ virNetServerPtr server ATTRIBUTE_UNUSED, | |
+ virNetServerClientPtr client, | |
+ virNetMessagePtr msg ATTRIBUTE_UNUSED, | |
+ virNetMessageErrorPtr rerr, | |
+ remote_domain_interfaces_addresses_args *args, | |
+ remote_domain_interfaces_addresses_ret *ret) | |
+{ | |
+ virTypedParameterPtr *params = NULL; | |
+ virDomainPtr dom = NULL; | |
+ int nparams; | |
+ unsigned int flags = 0; | |
+ int rv = -1, i; | |
+ struct daemonClientPrivate *priv = | |
+ virNetServerClientGetPrivateData(client); | |
+ | |
+ if (!priv->conn) { | |
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); | |
+ goto cleanup; | |
+ } | |
+ | |
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom))) | |
+ goto cleanup; | |
+ flags = args->flags; | |
+ | |
+ if (args->nparams > REMOTE_DOMAIN_INTERFACES_MAX) { | |
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large")); | |
+ goto cleanup; | |
+ } | |
+ if (args->nparams && VIR_ALLOC_N(params, args->nparams) < 0) { | |
+ virReportOOMError(); | |
+ goto cleanup; | |
+ } | |
+ nparams = args->nparams; | |
+ | |
+ if (nparams && VIR_ALLOC_N(params, nparams) < 0) { | |
+ virReportOOMError(); | |
+ goto cleanup; | |
+ } | |
+ | |
+ if (virDomainInterfacesAddresses(dom, params, &nparams, flags) < 0) | |
+ goto cleanup; | |
+ | |
+ ret->ifaces.ifaces_len = nparams; | |
+ if (VIR_ALLOC_N(ret->ifaces.ifaces_val, nparams) < 0) { | |
+ virReportOOMError(); | |
+ goto cleanup; | |
+ } | |
+ | |
+ if (args->nparams == 0) | |
+ goto success; | |
+ | |
+ for (i = 0; i < nparams; i++) { | |
+ int temp_nparams = (¶ms[i][0])->value.i; | |
+ if (remoteSerializeTypedParameters(params[i], temp_nparams, | |
+ &ret->ifaces.ifaces_val[i].params.params_val, | |
+ &ret->ifaces.ifaces_val[i].params.params_len, | |
+ args->flags) < 0) | |
+ goto cleanup; | |
+ } | |
+ | |
+success: | |
+ rv = 0; | |
+ | |
+cleanup: | |
+ if (rv < 0) | |
+ virNetMessageSaveError(rerr); | |
+ /* I am unable to use virTypedParamsFree to free params*/ | |
+ if (dom) | |
+ virDomainFree(dom); | |
+ return rv; | |
+} | |
/*----- Helpers. -----*/ | |
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in | |
index b791125..a624431 100644 | |
--- a/include/libvirt/libvirt.h.in | |
+++ b/include/libvirt/libvirt.h.in | |
@@ -2033,6 +2033,29 @@ int virDomainGetInterfaceParameters (virDomainPtr dom, | |
virTypedParameterPtr params, | |
int *nparams, unsigned int flags); | |
+# define VIR_DOMAIN_INTERFACE_NAME "iface-name" | |
+# define VIR_DOMAIN_INTERFACE_HWADDR "iface-hwaddr" | |
+# define VIR_DOMAIN_INTERFACES_PARAMS_COUNT "iface-count" | |
+# define VIR_DOMAIN_IPADDR_TYPE "ipaddr-type" | |
+# define VIR_DOMAIN_IPADDR_ADDR "ipaddr-addr" | |
+# define VIR_DOMAIN_IPADDR_PREFIX "ipaddr-prefix" | |
+# define VIR_DOMAIN_PARAMS_PER_IPADDR 3 | |
+# define VIR_DOMAIN_NECESSARY_PARAMS_COUNT 3 | |
+ | |
+typedef enum { | |
+ VIR_IP_ADDR_TYPE_IPV4, | |
+ VIR_IP_ADDR_TYPE_IPV6, | |
+ | |
+#ifdef VIR_ENUM_SENTINELS | |
+ VIR_IP_ADDR_TYPE_LAST | |
+#endif | |
+} virIPAddrType; | |
+ | |
+int virDomainInterfacesAddresses (virDomainPtr dom, | |
+ virTypedParameterPtr *params, | |
+ int *nparams, | |
+ unsigned int flags); | |
+ | |
/* Management of domain block devices */ | |
int virDomainBlockPeek (virDomainPtr dom, | |
diff --git a/python/generator.py b/python/generator.py | |
index da642eb..3f7bbae 100755 | |
--- a/python/generator.py | |
+++ b/python/generator.py | |
@@ -460,6 +460,7 @@ skip_impl = ( | |
'virNodeGetCPUMap', | |
'virDomainMigrate3', | |
'virDomainMigrateToURI3', | |
+ 'virDomainInterfacesAddresses', | |
) | |
lxc_skip_impl = ( | |
diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml | |
index 9a88215..9b310d8 100644 | |
--- a/python/libvirt-override-api.xml | |
+++ b/python/libvirt-override-api.xml | |
@@ -602,5 +602,11 @@ | |
<arg name='conn' type='virConnectPtr' info='pointer to the hypervisor connection'/> | |
<arg name='flags' type='int' info='unused, pass 0'/> | |
</function> | |
+ <function name='virDomainInterfacesAddresses' file='python'> | |
+ <info>returns array of IP addresses for all domain interfaces</info> | |
+ <arg name='dom' type='virDomainPtr' info='pointer to the domain'/> | |
+ <arg name='flags' type='unsigned int' info='extra flags; not used yet, so callers should always pass 0'/> | |
+ <return type='virDomainInterfacePtr' info="dictionary of domain interfaces among with their HW and IP addresses"/> | |
+ </function> | |
</symbols> | |
</api> | |
diff --git a/src/driver.h b/src/driver.h | |
index 31851cb..5d7d242 100644 | |
--- a/src/driver.h | |
+++ b/src/driver.h | |
@@ -500,6 +500,11 @@ typedef int | |
virTypedParameterPtr params, | |
int *nparams, | |
unsigned int flags); | |
+typedef int | |
+(*virDrvDomainInterfacesAddresses) (virDomainPtr dom, | |
+ virTypedParameterPtr *params, | |
+ int *nparams, | |
+ unsigned int flags); | |
typedef int | |
(*virDrvDomainMemoryStats)(virDomainPtr domain, | |
@@ -1219,6 +1224,7 @@ struct _virDriver { | |
virDrvDomainInterfaceStats domainInterfaceStats; | |
virDrvDomainSetInterfaceParameters domainSetInterfaceParameters; | |
virDrvDomainGetInterfaceParameters domainGetInterfaceParameters; | |
+ virDrvDomainInterfacesAddresses domainInterfacesAddresses; | |
virDrvDomainMemoryStats domainMemoryStats; | |
virDrvDomainBlockPeek domainBlockPeek; | |
virDrvDomainMemoryPeek domainMemoryPeek; | |
diff --git a/src/libvirt.c b/src/libvirt.c | |
index bc1694a..1919573 100644 | |
--- a/src/libvirt.c | |
+++ b/src/libvirt.c | |
@@ -7511,6 +7511,58 @@ error: | |
} | |
/** | |
+* virDomainInterfacesAddresses: | |
+* @dom: domain object | |
+* @flags: extra flags; not used yet, so callers should always pass 0 | |
+* @params: pointer to interface parameter objects | |
+* @nparams: number of interface parameter (this value can be the same or | |
+* | |
+* ToDO | |
+* | |
+* Returns -1 in case of error, 0 in case of success. | |
+**/ | |
+ | |
+int | |
+virDomainInterfacesAddresses(virDomainPtr dom, | |
+ virTypedParameterPtr *params, | |
+ int *nparams, | |
+ unsigned int flags) | |
+{ | |
+ virConnectPtr conn; | |
+ | |
+ VIR_DOMAIN_DEBUG(dom, "params=%p, nparams=%d, flags=%x", | |
+ params, *nparams, flags); | |
+ | |
+ virResetLastError(); | |
+ | |
+ if (!VIR_IS_CONNECTED_DOMAIN(dom)) { | |
+ virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); | |
+ goto error; | |
+ } | |
+ | |
+ conn = dom->conn; | |
+ | |
+ if (VIR_DRV_SUPPORTS_FEATURE(dom->conn->driver, dom->conn, | |
+ VIR_DRV_FEATURE_TYPED_PARAM_STRING)) | |
+ flags |= VIR_TYPED_PARAM_STRING_OKAY; | |
+ | |
+ if (conn->driver->domainInterfacesAddresses) { | |
+ int ret; | |
+ ret = conn->driver->domainInterfacesAddresses(dom, params, | |
+ nparams, flags); | |
+ if (ret < 0) | |
+ goto error; | |
+ return ret; | |
+ } | |
+ | |
+ virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); | |
+ | |
+error: | |
+ virDispatchError(dom ? dom->conn : NULL); | |
+ return -1; | |
+} | |
+ | |
+/** | |
* virNodeGetMemoryStats: | |
* @conn: pointer to the hypervisor connection. | |
* @cellNum: number of node cell. (VIR_NODE_MEMORY_STATS_ALL_CELLS means total | |
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms | |
index 7c6edf6..ddbbb79 100644 | |
--- a/src/libvirt_public.syms | |
+++ b/src/libvirt_public.syms | |
@@ -542,6 +542,7 @@ LIBVIRT_0.9.13 { | |
virDomainSnapshotIsCurrent; | |
virDomainSnapshotListAllChildren; | |
virDomainSnapshotRef; | |
+ virDomainInterfacesAddresses; | |
} LIBVIRT_0.9.11; | |
LIBVIRT_0.10.0 { | |
diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c | |
index 9914521..d2a0d28 100644 | |
--- a/src/qemu/qemu_agent.c | |
+++ b/src/qemu/qemu_agent.c | |
@@ -42,6 +42,7 @@ | |
#include "virtime.h" | |
#include "virobject.h" | |
#include "virstring.h" | |
+#include "virtypedparam.h" | |
#define VIR_FROM_THIS VIR_FROM_QEMU | |
@@ -1330,6 +1331,180 @@ cleanup: | |
return ret; | |
} | |
+int | |
+qemuAgentGetInterfaces(qemuAgentPtr mon, | |
+ virTypedParameterPtr *params, | |
+ int *nparams) | |
+{ | |
+ int ret = -1; | |
+ int size = -1; | |
+ int i, j; | |
+ virJSONValuePtr cmd; | |
+ virJSONValuePtr reply = NULL; | |
+ virJSONValuePtr ret_array = NULL; | |
+ | |
+ cmd = qemuAgentMakeCommand("guest-network-get-interfaces", NULL); | |
+ | |
+ if (!cmd) | |
+ return -1; | |
+ | |
+ if (qemuAgentCommand(mon, cmd, &reply, 1) < 0 || | |
+ qemuAgentCheckError(cmd, reply) < 0) | |
+ goto cleanup; | |
+ | |
+ /*Count number of interfaces*/ | |
+ if (!(ret_array = virJSONValueObjectGet(reply, "return"))) { | |
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", | |
+ _("qemu agent didn't provide 'return' field")); | |
+ goto cleanup; | |
+ } | |
+ | |
+ if ((size = virJSONValueArraySize(ret_array)) < 0) { | |
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", | |
+ _("qemu agent didn't return an array of interfaces")); | |
+ goto cleanup; | |
+ } | |
+ if (*nparams == 0){ | |
+ *nparams = (int) size; | |
+ ret = 0; | |
+ goto cleanup; | |
+ } | |
+ | |
+ for (i = 0; i < size; i++) { | |
+ | |
+ virJSONValuePtr tmp_iface = virJSONValueArrayGet(ret_array, i); | |
+ virJSONValuePtr ip_addr_arr = NULL; | |
+ char *name, *hwaddr; | |
+ int ip_addr_arr_size, params_count; | |
+ | |
+ /* Shouldn't happen but doesn't hurt to check neither */ | |
+ if (!tmp_iface) { | |
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", | |
+ _("something has went really wrong")); | |
+ goto cleanup; | |
+ } | |
+ | |
+ /* interface name is required to be presented */ | |
+ if (VIR_STRDUP(name, virJSONValueObjectGetString(tmp_iface, "name")) < 0) | |
+ goto cleanup; | |
+ | |
+ if (!name) { | |
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", | |
+ _("qemu agent didn't provide 'name' field")); | |
+ goto cleanup; | |
+ } | |
+ | |
+ ip_addr_arr = virJSONValueObjectGet(tmp_iface, "ip-addresses"); | |
+ if (!ip_addr_arr) | |
+ continue; | |
+ | |
+ if ((ip_addr_arr_size = virJSONValueArraySize(ip_addr_arr)) < 0) { | |
+ /* Mmm, empty 'ip-address'? */ | |
+ continue; | |
+ } | |
+ | |
+ params_count = VIR_DOMAIN_PARAMS_PER_IPADDR * ip_addr_arr_size | |
+ + VIR_DOMAIN_NECESSARY_PARAMS_COUNT; | |
+ /*Allocate memory to params*/ | |
+ if (VIR_ALLOC_N(params[i], params_count) < 0) { | |
+ virReportOOMError(); | |
+ goto cleanup; | |
+ } | |
+ | |
+ /*Store total number of parameters per interface */ | |
+ if (virTypedParameterAssign(¶ms[i][0], VIR_DOMAIN_INTERFACES_PARAMS_COUNT, | |
+ VIR_TYPED_PARAM_INT, params_count) < 0) | |
+ goto cleanup; | |
+ | |
+ /*Store interface name*/ | |
+ if (virTypedParameterAssign(¶ms[i][1], VIR_DOMAIN_INTERFACE_NAME, | |
+ VIR_TYPED_PARAM_STRING, name) < 0) | |
+ goto cleanup; | |
+ | |
+ /* hwaddr might be omitted */ | |
+ if (VIR_STRDUP(hwaddr, virJSONValueObjectGetString(tmp_iface, "hardware-address")) < 0) | |
+ goto cleanup; | |
+ | |
+ if (hwaddr && virTypedParameterAssign(¶ms[i][2], VIR_DOMAIN_INTERFACE_HWADDR, | |
+ VIR_TYPED_PARAM_STRING, hwaddr) < 0) | |
+ goto cleanup; | |
+ | |
+ /*Enumerate though each ip */ | |
+ for (j = 0; j < ip_addr_arr_size; j++) { | |
+ virJSONValuePtr ip_addr_obj = virJSONValueArrayGet(ip_addr_arr, j); | |
+ virTypedParameterPtr ip_type = ¶ms[i][VIR_DOMAIN_PARAMS_PER_IPADDR * j + 3]; | |
+ virTypedParameterPtr ip_addr = ¶ms[i][VIR_DOMAIN_PARAMS_PER_IPADDR * j + 4]; | |
+ virTypedParameterPtr ip_prefix = ¶ms[i][VIR_DOMAIN_PARAMS_PER_IPADDR * j + 5]; | |
+ char *type, *addr; | |
+ int addrType, prefix; | |
+ | |
+ /* Shouldn't happen but doesn't hurt to check neither */ | |
+ if (!ip_addr_obj) { | |
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", | |
+ _("something has went really wrong")); | |
+ goto cleanup; | |
+ } | |
+ | |
+ /* Getting the ip address type */ | |
+ if (VIR_STRDUP(type, virJSONValueObjectGetString(ip_addr_obj, "ip-address-type")) < 0) | |
+ goto cleanup; | |
+ if (!type) { | |
+ virReportError(VIR_ERR_INTERNAL_ERROR, | |
+ _("qemu agent didn't provide 'ip-address-type'" | |
+ " field for interface '%s'"), name); | |
+ goto cleanup; | |
+ } else if (STREQ(type, "ipv4")) { | |
+ addrType = VIR_IP_ADDR_TYPE_IPV4; | |
+ } else if (STREQ(type, "ipv6")) { | |
+ addrType = VIR_IP_ADDR_TYPE_IPV6; | |
+ } else { | |
+ virReportError(VIR_ERR_INTERNAL_ERROR, | |
+ _("unknown ip address type '%s'"), | |
+ type); | |
+ goto cleanup; | |
+ } | |
+ if (virTypedParameterAssign(ip_type, VIR_DOMAIN_IPADDR_TYPE, | |
+ VIR_TYPED_PARAM_INT, addrType) < 0) | |
+ goto cleanup; | |
+ | |
+ /* Getting the ip address value */ | |
+ if (VIR_STRDUP(addr, virJSONValueObjectGetString(ip_addr_obj, "ip-address")) < 0) | |
+ goto cleanup; | |
+ if (!addr) { | |
+ virReportError(VIR_ERR_INTERNAL_ERROR, | |
+ _("qemu agent didn't provide 'ip-address'" | |
+ " field for interface '%s'"), name); | |
+ goto cleanup; | |
+ } | |
+ if (virTypedParameterAssign(ip_addr, VIR_DOMAIN_IPADDR_ADDR, | |
+ VIR_TYPED_PARAM_STRING, addr) < 0) | |
+ goto cleanup; | |
+ | |
+ /* Getting the ip address prefix */ | |
+ if (virJSONValueObjectGetNumberInt(ip_addr_obj, "prefix", | |
+ &prefix) < 0) { | |
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", | |
+ _("malformed 'prefix' field")); | |
+ goto cleanup; | |
+ } | |
+ | |
+ if (virTypedParameterAssign(ip_prefix, VIR_DOMAIN_IPADDR_PREFIX, | |
+ VIR_TYPED_PARAM_INT, prefix) < 0) { | |
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", | |
+ _("malformed 'prefix' field")); | |
+ goto cleanup; | |
+ } | |
+ } | |
+ } | |
+ | |
+ ret = 0; | |
+ | |
+cleanup: | |
+ virJSONValueFree(cmd); | |
+ virJSONValueFree(reply); | |
+ return ret; | |
+} | |
+ | |
/* | |
* qemuAgentFSThaw: | |
* @mon: Agent | |
diff --git a/src/qemu/qemu_agent.h b/src/qemu/qemu_agent.h | |
index cf70653..fabdda3 100644 | |
--- a/src/qemu/qemu_agent.h | |
+++ b/src/qemu/qemu_agent.h | |
@@ -83,6 +83,9 @@ int qemuAgentArbitraryCommand(qemuAgentPtr mon, | |
int qemuAgentFSTrim(qemuAgentPtr mon, | |
unsigned long long minimum); | |
+int qemuAgentGetInterfaces(qemuAgentPtr mon, | |
+ virTypedParameterPtr *params, | |
+ int *nparams); | |
typedef struct _qemuAgentCPUInfo qemuAgentCPUInfo; | |
typedef qemuAgentCPUInfo *qemuAgentCPUInfoPtr; | |
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c | |
index 4856f37..91b49f2 100644 | |
--- a/src/qemu/qemu_driver.c | |
+++ b/src/qemu/qemu_driver.c | |
@@ -15869,6 +15869,69 @@ qemuNodeSuspendForDuration(virConnectPtr conn, | |
return nodeSuspendForDuration(target, duration, flags); | |
} | |
+static int | |
+qemuDomainInterfacesAddresses(virDomainPtr dom, | |
+ virTypedParameterPtr *params, | |
+ int *nparams, | |
+ unsigned int flags) | |
+{ | |
+ virQEMUDriverPtr driver = dom->conn->privateData; | |
+ qemuDomainObjPrivatePtr priv = NULL; | |
+ virDomainObjPtr vm = NULL; | |
+ unsigned long long ret = -1; | |
+ | |
+ virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); | |
+ | |
+ if (!(vm = qemuDomObjFromDomain(dom))) | |
+ goto cleanup; | |
+ | |
+ priv = vm->privateData; | |
+ | |
+ if (virDomainInterfacesAddressesEnsureACL(dom->conn, vm->def) < 0) | |
+ goto cleanup; | |
+ | |
+ if (!virDomainObjIsActive(vm)) { | |
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s", | |
+ _("domain is not running")); | |
+ goto cleanup; | |
+ } | |
+ | |
+ | |
+ if (priv->agentError) { | |
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", | |
+ _("QEMU guest agent is not " | |
+ "available due to an error")); | |
+ goto cleanup; | |
+ } | |
+ | |
+ if (!priv->agent) { | |
+ virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", | |
+ _("QEMU guest agent is not configured")); | |
+ goto cleanup; | |
+ } | |
+ | |
+ if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0) | |
+ goto cleanup; | |
+ | |
+ if (!virDomainObjIsActive(vm)) { | |
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s", | |
+ _("domain is not running")); | |
+ goto endjob; | |
+ } | |
+ | |
+ qemuDomainObjEnterAgent(vm); | |
+ ret = qemuAgentGetInterfaces(priv->agent, params, nparams); | |
+ qemuDomainObjExitAgent(vm); | |
+ | |
+endjob: | |
+ if (qemuDomainObjEndJob(driver, vm) == 0) | |
+ vm = NULL; | |
+ | |
+cleanup: | |
+ if (vm) | |
+ virObjectUnlock(vm); | |
+ return ret; | |
+} | |
static virDriver qemuDriver = { | |
.no = VIR_DRV_QEMU, | |
@@ -15907,6 +15970,7 @@ static virDriver qemuDriver = { | |
.domainGetMemoryParameters = qemuDomainGetMemoryParameters, /* 0.8.5 */ | |
.domainSetBlkioParameters = qemuDomainSetBlkioParameters, /* 0.9.0 */ | |
.domainGetBlkioParameters = qemuDomainGetBlkioParameters, /* 0.9.0 */ | |
+ .domainInterfacesAddresses = qemuDomainInterfacesAddresses, /* 0.9.13 */ | |
.domainGetInfo = qemuDomainGetInfo, /* 0.2.0 */ | |
.domainGetState = qemuDomainGetState, /* 0.9.2 */ | |
.domainGetControlInfo = qemuDomainGetControlInfo, /* 0.9.3 */ | |
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c | |
index 7f3e833..74fd13e 100644 | |
--- a/src/remote/remote_driver.c | |
+++ b/src/remote/remote_driver.c | |
@@ -2729,6 +2729,66 @@ done: | |
return rv; | |
} | |
+static int | |
+remoteDomainInterfacesAddresses(virDomainPtr dom, | |
+ virTypedParameterPtr *params, | |
+ int *nparams, | |
+ unsigned int flags) | |
+{ | |
+ int rv = -1, i; | |
+ remote_domain_interfaces_addresses_args args; | |
+ remote_domain_interfaces_addresses_ret ret; | |
+ struct private_data *priv = dom->conn->privateData; | |
+ | |
+ memset(&ret, 0, sizeof(ret)); | |
+ args.flags = flags; | |
+ args.nparams = *nparams; | |
+ make_nonnull_domain(&args.dom, dom); | |
+ | |
+ remoteDriverLock(priv); | |
+ | |
+ if (call(dom->conn, priv, 0, REMOTE_PROC_DOMAIN_INTERFACES_ADDRESSES, | |
+ (xdrproc_t)xdr_remote_domain_interfaces_addresses_args, | |
+ (char *)&args, | |
+ (xdrproc_t)xdr_remote_domain_interfaces_addresses_ret, | |
+ (char *)&ret) == -1) { | |
+ goto done; | |
+ } | |
+ | |
+ /* Handle the case when the caller does not know the number of stats | |
+ * and is asking for the number of stats supported | |
+ */ | |
+ if (*nparams == 0) { | |
+ rv = ret.ifaces.ifaces_len; | |
+ goto cleanup; | |
+ } | |
+ | |
+ /*Deserialize the ret structure and fill params*/ | |
+ for (i = 0; i < ret.ifaces.ifaces_len; i++) { | |
+ int size = ret.ifaces.ifaces_val[i].params.params_val | |
+ ->value.remote_typed_param_value_u.i; | |
+ if (VIR_ALLOC_N(params[i], size) < 0) { | |
+ virReportOOMError(); | |
+ goto cleanup; | |
+ } | |
+ if (remoteDeserializeTypedParameters(ret.ifaces.ifaces_val[i].params.params_val, | |
+ ret.ifaces.ifaces_val[i].params.params_len, | |
+ REMOTE_DOMAIN_INTERFACE_ADDRESSES_MAX, | |
+ ¶ms[i], | |
+ &size) < 0) | |
+ goto cleanup; | |
+ } | |
+ rv = 0; | |
+ | |
+cleanup: | |
+ xdr_free((xdrproc_t)xdr_remote_domain_interfaces_addresses_ret, | |
+ (char *) &ret); | |
+done: | |
+ remoteDriverUnlock(priv); | |
+ return rv; | |
+} | |
+ | |
+ | |
static int remoteDomainGetCPUStats(virDomainPtr domain, | |
virTypedParameterPtr params, | |
unsigned int nparams, | |
@@ -6434,7 +6494,6 @@ cleanup: | |
return rv; | |
} | |
- | |
static void | |
remoteDomainEventQueue(struct private_data *priv, virDomainEventPtr event) | |
{ | |
@@ -6674,6 +6733,7 @@ static virDriver remote_driver = { | |
.domainMemoryPeek = remoteDomainMemoryPeek, /* 0.4.2 */ | |
.domainGetBlockInfo = remoteDomainGetBlockInfo, /* 0.8.1 */ | |
.nodeGetCPUStats = remoteNodeGetCPUStats, /* 0.9.3 */ | |
+ .domainInterfacesAddresses = remoteDomainInterfacesAddresses, /* 0.9.13 */ | |
.nodeGetMemoryStats = remoteNodeGetMemoryStats, /* 0.9.3 */ | |
.nodeGetCellsFreeMemory = remoteNodeGetCellsFreeMemory, /* 0.3.3 */ | |
.nodeGetFreeMemory = remoteNodeGetFreeMemory, /* 0.3.3 */ | |
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x | |
index 2e9dc1d..1d91b0e 100644 | |
--- a/src/remote/remote_protocol.x | |
+++ b/src/remote/remote_protocol.x | |
@@ -236,6 +236,15 @@ const REMOTE_NODE_MEMORY_PARAMETERS_MAX = 64; | |
/* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ | |
typedef opaque remote_uuid[VIR_UUID_BUFLEN]; | |
+/* | |
+ + * Upper limit on number of interfaces per domain | |
+ + */ | |
+const REMOTE_DOMAIN_INTERFACES_MAX = 64; | |
+ | |
+/* | |
+ + * Upper limit on number of ip addresses per interface | |
+ + */ | |
+const REMOTE_DOMAIN_INTERFACE_ADDRESSES_MAX = 64; | |
/* A domain which may not be NULL. */ | |
struct remote_nonnull_domain { | |
@@ -1272,6 +1281,23 @@ struct remote_domain_get_cpu_stats_ret { | |
int nparams; | |
}; | |
+struct remote_domain_interfaces_addresses_args { | |
+ remote_nonnull_domain dom; | |
+ int nparams; | |
+ unsigned int flags; | |
+}; | |
+ | |
+struct remote_domain_interfaces_addresses_ret_ { | |
+ remote_typed_param params<REMOTE_DOMAIN_INTERFACE_ADDRESSES_MAX>; | |
+}; | |
+ | |
+struct remote_domain_interfaces_addresses_ret { | |
+ remote_domain_interfaces_addresses_ret_ ifaces<REMOTE_DOMAIN_INTERFACES_MAX>; | |
+ int ifaces_len; | |
+}; | |
+ | |
+ | |
+ | |
struct remote_domain_get_hostname_args { | |
remote_nonnull_domain dom; | |
unsigned int flags; | |
@@ -4944,6 +4970,11 @@ enum remote_procedure { | |
* @generate: none | |
* @acl: domain:migrate | |
*/ | |
- REMOTE_PROC_DOMAIN_MIGRATE_CONFIRM3_PARAMS = 307 | |
+ REMOTE_PROC_DOMAIN_MIGRATE_CONFIRM3_PARAMS = 307, | |
+ /** | |
+ * @generate: none | |
+ * @acl: domain:read | |
+ */ | |
+ REMOTE_PROC_DOMAIN_INTERFACES_ADDRESSES = 308 | |
}; | |
diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c | |
index 3ba829c..0c5591e 100644 | |
--- a/tools/virsh-domain-monitor.c | |
+++ b/tools/virsh-domain-monitor.c | |
@@ -1317,6 +1317,107 @@ cleanup: | |
return ret; | |
} | |
+/* "domifaddr" command | |
+ */ | |
+static const vshCmdInfo info_domifaddr[] = { | |
+ {"help", N_("get network interfaces addresses for a domain")}, | |
+ {"desc", N_("Get network interfaces addresses for a running domain")}, | |
+ {NULL, NULL} | |
+}; | |
+ | |
+static const vshCmdOptDef opts_domifaddr[] = { | |
+ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, | |
+ {"interface", VSH_OT_DATA, VSH_OFLAG_NONE, N_("network interface name")}, | |
+ {NULL, 0, 0, NULL} | |
+}; | |
+static bool | |
+cmdDomIfAddr(vshControl *ctl, const vshCmd *cmd) | |
+{ | |
+ virDomainPtr dom = NULL; | |
+ const char *device = NULL; | |
+ | |
+ virTypedParameterPtr *params = NULL; | |
+ int nparams = 0; | |
+ unsigned int flags = 0; | |
+ int i, j; | |
+ | |
+ bool ret = false; | |
+ | |
+ if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) | |
+ return false; | |
+ | |
+ if (vshCommandOptString(cmd, "interface", &device) < 0) { | |
+ goto cleanup; | |
+ } | |
+ | |
+ /*Find how many interfaces exist*/ | |
+ if ((nparams = virDomainInterfacesAddresses(dom, params, &nparams, flags)) < 0) { | |
+ vshError(ctl, _("Failed to query for interfaces addresses")); | |
+ goto cleanup; | |
+ } | |
+ | |
+ /*Allocate Memory Accordingly*/ | |
+ if (VIR_ALLOC_N(params, nparams) < 0) { | |
+ virReportOOMError(); | |
+ goto cleanup; | |
+ } | |
+ | |
+ /*Send request for all interfaces*/ | |
+ if (virDomainInterfacesAddresses(dom, params, &nparams, flags) < 0) { | |
+ vshError(ctl, _("Failed to query for interfaces addresses")); | |
+ goto cleanup; | |
+ } | |
+ | |
+ /*Lets print to stdout*/ | |
+ vshPrintExtra(ctl, " %-10s %-17s %s\n%s\n", | |
+ _("Name"), _("HW address"), _("IP address"), | |
+ "---------------------------------------------------"); | |
+ ret = true; | |
+ for (i = 0; i < nparams; i++) { | |
+ virTypedParameterPtr iface = params[i]; | |
+ virBuffer buf = VIR_BUFFER_INITIALIZER; | |
+ const char *hwaddr = ""; | |
+ const char *ip_addr_str = NULL; | |
+ virTypedParameterPtr iface_count = &iface[0]; | |
+ virTypedParameterPtr iface_name = &iface[1]; | |
+ virTypedParameterPtr iface_hwaddr = &iface[2]; | |
+ | |
+ if (device && STRNEQ(device, iface_name->value.s)) | |
+ continue; | |
+ | |
+ if (iface_hwaddr) | |
+ hwaddr = iface_hwaddr->value.s; | |
+ | |
+ int ip_addr_count = (iface_count->value.i - | |
+ VIR_DOMAIN_NECESSARY_PARAMS_COUNT) / VIR_DOMAIN_PARAMS_PER_IPADDR; | |
+ for (j = 0; j < ip_addr_count; j++) { | |
+ virTypedParameterPtr ip_addr = &iface[3*j+4]; | |
+ virTypedParameterPtr ip_prefix = &iface[3*j+5]; | |
+ if (j) | |
+ virBufferAddChar(&buf, ' '); | |
+ virBufferAsprintf(&buf, "%s/%d", | |
+ ip_addr->value.s, | |
+ ip_prefix->value.i); | |
+ } | |
+ | |
+ ip_addr_str = virBufferContentAndReset(&buf); | |
+ | |
+ if (!ip_addr_str) | |
+ ip_addr_str = ""; | |
+ | |
+ vshPrintExtra(ctl, " %-10s %-17s %s\n", | |
+ iface_name->value.s, hwaddr, ip_addr_str); | |
+ | |
+ virBufferFreeAndReset(&buf); | |
+ } | |
+ | |
+cleanup: | |
+ | |
+ if (dom) | |
+ virDomainFree(dom); | |
+ return ret; | |
+} | |
+ | |
/* | |
* "list" command | |
*/ | |
@@ -1855,6 +1956,12 @@ const vshCmdDef domMonitoringCmds[] = { | |
.info = info_domifstat, | |
.flags = 0 | |
}, | |
+ {.name = "domifaddr", | |
+ .handler = cmdDomIfAddr, | |
+ .opts = opts_domifaddr, | |
+ .info = info_domifaddr, | |
+ .flags = 0 | |
+ }, | |
{.name = "dominfo", | |
.handler = cmdDominfo, | |
.opts = opts_dominfo, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment