Define helper function virDomainInterfaceFree, which allows
the upper layer application to free the domain interface object
conveniently.
The API is going to provide multiple methods by flags, e.g.
* Query guest agent
* Parse lease file of dnsmasq
* DHCP snooping
At this stage, it will only work with guest agent. Passing other
flags will result in error: "Method hasn't been implemented yet"
include/libvirt/libvirt.h.in:
* Define virDomainInterfaceAddresses, virDomainInterfaceFree
* Define structs virDomainInterface, virDomainIPAddress
python/generator.py:
* Skip the auto-generation for virDomainInterfaceAddresses
and virDomainInterfaceFree
src/driver.h:
* Define domainInterfaceAddresses
src/libvirt.c:
* Implement virDomainInterfaceAddresses
* Implement virDomainInterfaceFree
src/libvirt_public.syms:
* Export the new symbols
---
include/libvirt/libvirt.h.in | 38 ++++++++++++
python/generator.py | 3 +
src/driver.h | 6 ++
src/libvirt.c | 135 +++++++++++++++++++++++++++++++++++++++++++
src/libvirt_public.syms | 6 ++
5 files changed, 188 insertions(+)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index a47e33c..0995080 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2044,6 +2044,44 @@ int virDomainGetInterfaceParameters
(virDomainPtr dom,
virTypedParameterPtr params,
int *nparams, unsigned int
flags);
+typedef enum {
+ VIR_DOMAIN_INTERFACE_ADDRESSES_SNOOP = (1 << 0), /* Snoop traffic */
+ VIR_DOMAIN_INTERFACE_ADDRESSES_LEASE = (1 << 1), /* Parse DHCP lease file */
+ VIR_DOMAIN_INTERFACE_ADDRESSES_AGENT = (1 << 2), /* Query qemu guest agent */
+} virDomainInterfaceAddressesFlags;
+
+typedef enum {
+ VIR_IP_ADDR_TYPE_IPV4 = 0,
+ VIR_IP_ADDR_TYPE_IPV6 = 1,
+
+#ifdef VIR_ENUM_SENTINELS
+ VIR_IP_ADDR_TYPE_LAST,
+#endif
+} virIPAddrType;
+
+typedef struct _virDomainInterfaceIPAddress virDomainIPAddress;
+typedef virDomainIPAddress *virDomainIPAddressPtr;
+struct _virDomainInterfaceIPAddress {
+ int type; /* virIPAddrType */
+ char *addr; /* IP address */
+ unsigned int prefix; /* IP address prefix */
+};
+
+typedef struct _virDomainInterface virDomainInterface;
+typedef virDomainInterface *virDomainInterfacePtr;
+struct _virDomainInterface {
+ char *name; /* interface name */
+ char *hwaddr; /* hardware address */
+ unsigned int naddrs; /* number of items in @addrs */
+ virDomainIPAddressPtr addrs; /* array of IP addresses */
+};
+
+int virDomainInterfaceAddresses(virDomainPtr dom,
+ virDomainInterfacePtr **ifaces,
+ unsigned int flags);
+
+void virDomainInterfaceFree(virDomainInterfacePtr iface);
+
/* Management of domain block devices */
int virDomainBlockPeek (virDomainPtr dom,
diff --git a/python/generator.py b/python/generator.py
index fb321c6..50f779b 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -458,6 +458,7 @@ skip_impl = (
'virNodeGetMemoryParameters',
'virNodeSetMemoryParameters',
'virNodeGetCPUMap',
+ 'virDomainInterfaceAddresses',
'virDomainMigrate3',
'virDomainMigrateToURI3',
)
@@ -560,6 +561,8 @@ skip_function = (
"virTypedParamsGetString",
"virTypedParamsGetUInt",
"virTypedParamsGetULLong",
+
+ "virDomainInterfaceFree", # Only useful in C
)
lxc_skip_function = (
diff --git a/src/driver.h b/src/driver.h
index be64333..210a910 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -518,6 +518,11 @@ typedef int
unsigned int flags);
typedef int
+(*virDrvDomainInterfaceAddresses)(virDomainPtr dom,
+ virDomainInterfacePtr **ifaces,
+ unsigned int flags);
+
+typedef int
(*virDrvDomainMemoryStats)(virDomainPtr domain,
struct _virDomainMemoryStat *stats,
unsigned int nr_stats,
@@ -1238,6 +1243,7 @@ struct _virDriver {
virDrvDomainInterfaceStats domainInterfaceStats;
virDrvDomainSetInterfaceParameters domainSetInterfaceParameters;
virDrvDomainGetInterfaceParameters domainGetInterfaceParameters;
+ virDrvDomainInterfaceAddresses domainInterfaceAddresses;
virDrvDomainMemoryStats domainMemoryStats;
virDrvDomainBlockPeek domainBlockPeek;
virDrvDomainMemoryPeek domainMemoryPeek;
diff --git a/src/libvirt.c b/src/libvirt.c
index 07a3fd5..7a5759b 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -8643,6 +8643,116 @@ error:
return -1;
}
+ /**
+ * virDomainInterfaceAddresses:
+ * @dom: domain object
+ * @ifaces: pointer to an array of pointers pointing to interface objects
+ * @flags: bitwise-OR of virDomainInterfaceAddressesFlags
+ *
+ * Return a pointer to the allocated array of pointers pointing to interfaces
+ * present in given domain along with their IP and MAC addresses. Note that
+ * single interface can have multiple or even 0 IP address.
+ *
+ * This API dynamically allocates the virDomainInterfacePtr struct based on
+ * how many interfaces domain @dom has, usually there's 1:1 correlation. The
+ * count of the interfaces is returned as the return value.
+ *
+ * In case @flags includes VIR_DOMAIN_INTERFACE_ADDRESSES_AGENT, a configured
+ * guest agent is needed for successful return from this API. Moreover, if
+ * guest agent is used then the interface name is the one seen by guest OS.
+ * To match such interface with the one from @dom XML use MAC address or IP
+ * range.
+ *
+ * Both the methods, pasrsing leases file and traffic snooping will return
+ * the interface name of the form "vnetN", which is different from what guest
+ * agent returns (like ethN or emN). And since the MAC address from guest agent
+ * might be different with what @dom XML specifies, we have no way to convert it
+ * into the names present in @dom config. Hence, it is not recommended to mix
+ * the flag ..._AGENT with ..._LEASE or ..._SNOOP as it may lead to ambiguous
+ * results because we cannot be sure if the name came from the agent or from
+ * the other method.
+ *
+ * If 0 is passed as @flags, libvirt will choose the best way, and won't
+ * include agent in it.
+ *
+ * @ifaces->name and @ifaces->hwaddr are never NULL.
+ *
+ * The caller *must* free @ifaces when no longer needed. Usual use case
+ * looks like this:
+ *
+ * virDomainInterfacePtr *ifaces = NULL;
+ * int ifaces_count = 0;
+ * size_t i, j;
+ * virDomainPtr dom = ... obtain a domain here ...;
+ *
+ * if ((ifaces_count = virDomainInterfaceAddresses(dom, &ifaces, 0)) < 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)
+ * 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)
+ * for (i = 0; i < ifaces_count; i++)
+ * virDomainInterfaceFree(ifaces[i]);
+ * free(ifaces);
+ *
+ * Returns the number of interfaces on success, -1 in case of error.
+ */
+int
+virDomainInterfaceAddresses(virDomainPtr dom,
+ virDomainInterfacePtr **ifaces,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(dom, "ifaces=%p, flags=%x", ifaces, flags);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_DOMAIN(dom)) {
+ virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+
+ conn = dom->conn;
+
+ virCheckNonNullArgGoto(ifaces, error);
+
+ if ((flags & VIR_DOMAIN_INTERFACE_ADDRESSES_AGENT)
+ && (conn->flags & VIR_CONNECT_RO)) {
+ virLibConnError(VIR_ERR_OPERATION_DENIED, "%s",
+ _("Cannot query guest agent in readonly mode"));
+ goto error;
+ }
+
+ if (conn->driver->domainInterfaceAddresses) {
+ int ret;
+ ret = conn->driver->domainInterfaceAddresses(dom, ifaces, flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(dom->conn);
+ return -1;
+}
+
/**
* virDomainMemoryStats:
* @dom: pointer to the domain object
@@ -21961,3 +22071,28 @@ error:
virDispatchError(dom->conn);
return -1;
}
+
+/**
+ * virDomainInterfaceFree:
+ * @iface: an interface object
+ *
+ * Free the interface object. The data structure is
+ * freed and should not be used thereafter.
+ */
+void
+virDomainInterfaceFree(virDomainInterfacePtr iface)
+{
+ size_t i;
+
+ if (!iface)
+ return;
+
+ VIR_FREE(iface->name);
+ VIR_FREE(iface->hwaddr);
+
+ for (i = 0; i < iface->naddrs; i++)
+ VIR_FREE(iface->addrs[i].addr);
+ VIR_FREE(iface->addrs);
+
+ VIR_FREE(iface);
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index bbdf78a..35f3a3e 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -634,4 +634,10 @@ LIBVIRT_1.1.1 {
virDomainSetMemoryStatsPeriod;
} LIBVIRT_1.1.0;
+LIBVIRT_1.1.3 {
+ global:
+ virDomainInterfaceAddresses;
+ virDomainInterfaceFree;
+} LIBVIRT_1.1.1;
+
# .... define new API here using predicted next version number ....
--
1.7.11.7