By querying the driver for the path of the leases file for the given virtual
network and parsing it to retrieve info.
src/network/bridge_driver.c:
* Implement networkGetDHCPLeases
* Implement networkGetDHCPLeasesForMAC
* Implement networkGetDHCPLeasesHelper
---
src/network/bridge_driver.c | 240 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 240 insertions(+)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 8787bdb..e1c97c7 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -109,6 +109,29 @@ static int networkPlugBandwidth(virNetworkObjPtr net,
virDomainNetDefPtr iface);
static int networkUnplugBandwidth(virNetworkObjPtr net,
virDomainNetDefPtr iface);
+/**
+ * VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX:
+ *
+ * Macro providing the upper limit on the size of leases file
+ */
+#define VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX 2097152
+
+/**
+ * VIR_NETWORK_DHCP_LEASE_FIELDS:
+ *
+ * Macro providing the maximum number of fields in an entry in
+ * the leases file
+ */
+#define VIR_NETWORK_DHCP_LEASE_FIELDS 5
+
+/**
+ * VIR_NETWORK_DHCP_LEASE_SEPARATOR_FIELDS:
+ *
+ * Macro providing the maximum number of fields in the separator
+ * line in the DHCPv6 leases file
+ */
+#define VIR_NETWORK_DHCP_LEASE_SEPARATOR_FIELDS 2
+
static virNetworkDriverStatePtr driverState = NULL;
@@ -2988,6 +3011,221 @@ cleanup:
return ret;
}
+/* This function parses the leases file of dnsmasq.
+ *
+ * An example of DHCPv4 leases file content:
+ *
+ * 1379024255 52:54:00:20:70:3d 192.168.105.240 * *
+ * 1379023351 52:54:00:b1:70:19 192.168.105.201 * *
+ *
+ * An example of DHCPv6 leases file content:
+ *
+ * 1380150262 52:54:00:2e:1d:22 192.168.122.80 * *
+ * 1380152517 52:54:00:72:0f:1e 192.168.122.119 * *
+ * duid 00:01:00:01:19:d3:ec:62:f0:4d:a2:8c:14:51
+ * 1380152445 3022114 2001:db8:ca2:2:1::92 * 00:01:00:01:19:d6:0c:59:52:54:00:2e:1d:22
+ * 1380152453 7474974 2001:db8:ca2:2:1::4e * 00:01:00:01:19:d5:e0:86:52:54:00:72:0f:1e
+ *
+ */
+static int
+networkGetDHCPLeasesHelper(virNetworkPtr network,
+ virNetworkObjPtr obj,
+ const char *mac,
+ virNetworkDHCPLeasesPtr **leases)
+{
+ int rv = -1;
+ size_t i = 0;
+ size_t nleases = 0;
+ char *lease_file = NULL;
+ char **lease_fields = NULL;
+ char *lease_entries = NULL;
+ char *lease_entry = NULL;
+ virNetworkDHCPLeasesPtr *leases_ret = NULL;
+ virNetworkDHCPLeasesPtr lease = NULL;
+ int lease_file_len = 0;
+ bool ipv6 = false;
+ bool need_results = !!leases;
+
+ /* Retrieve leases file location */
+ lease_file = networkDnsmasqLeaseFileNameDefault(network->name);
+
+ if ((lease_file_len = virFileReadAll(lease_file,
+ VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX,
+ &lease_entries)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to read leases file: %s"), lease_file);
+ goto cleanup;
+ }
+
+ lease_entry = lease_entries[0] == '\0' ? NULL : lease_entries;
+
+ while (lease_entry) {
+ int nfields = 0;
+
+ char *eol = strchr(lease_entry, '\n');
+ *eol = '\0';
+
+ /* Split the lease line */
+ if (!(lease_fields = virStringSplit(lease_entry, " ",
+ VIR_NETWORK_DHCP_LEASE_FIELDS)))
+ goto error;
+
+ nfields = virStringListLength(lease_fields);
+
+ /* Forward lease_entry to the next lease */
+ lease_entry = strchr(lease_entry, '\0');
+ if (lease_entry - lease_entries + 1 < lease_file_len)
+ lease_entry++;
+ else
+ lease_entry = NULL;
+
+ /* Ignore the separator line in case of DHCPv6 */
+ if (nfields == VIR_NETWORK_DHCP_LEASE_SEPARATOR_FIELDS
+ && STREQ(lease_fields[0], "duid")) {
+ ipv6 = true;
+ virStringFreeList(lease_fields);
+ continue;
+ }
+
+ if (nfields != VIR_NETWORK_DHCP_LEASE_FIELDS) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Number of lease params aren't equal to:
%d"),
+ VIR_NETWORK_DHCP_LEASE_FIELDS);
+ goto error;
+ }
+
+ if (mac && virMacAddrCompare(mac, lease_fields[1])) {
+ virStringFreeList(lease_fields);
+ continue;
+ }
+
+ if (need_results) {
+ if (VIR_ALLOC(lease) < 0)
+ goto error;
+
+ /* Convert expirytime here */
+ if (virStrToLong_ll(lease_fields[0], NULL, 10, &(lease->expirytime))
< 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to convert lease expiry time to integer:
%s"),
+ lease_fields[0]);
+ goto error;
+ }
+
+ lease->type = ipv6 ? VIR_IP_ADDR_TYPE_IPV6 : VIR_IP_ADDR_TYPE_IPV4;
+ lease->prefix =
virSocketAddrGetIpPrefix(&obj->def->ips->address,
+
&obj->def->ips->netmask,
+ obj->def->ips->prefix);
+
+ if ((VIR_STRDUP(lease->id.mac, lease_fields[1]) < 0) ||
+ (VIR_STRDUP(lease->ipaddr, lease_fields[2]) < 0))
+ goto error;
+
+ /* Only two fields, hostname and clientid can be NULL
+ * Refer:
http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2013q3/007544.html
+ */
+ if (STREQ(lease_fields[3], "*"))
+ lease->hostname = NULL;
+ else if (VIR_STRDUP(lease->hostname, lease_fields[3]) < 0)
+ goto error;
+
+ if (STREQ(lease_fields[4], "*"))
+ lease->clientid = NULL;
+ else if (VIR_STRDUP(lease->clientid, lease_fields[4]) < 0)
+ goto error;
+
+ if (VIR_INSERT_ELEMENT(leases_ret, nleases, nleases, lease) < 0)
+ goto error;
+ }
+ else
+ nleases++;
+
+ VIR_FREE(lease);
+ virStringFreeList(lease_fields);
+ }
+
+ lease_fields = NULL;
+
+ if (need_results && mac && !leases_ret) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("no lease with matching MAC address: %s"), mac);
+ goto error;
+ }
+
+ if (leases_ret) {
+ /* NULL terminated array */
+ ignore_value(VIR_REALLOC_N(leases_ret, nleases + 1));
+ *leases = leases_ret;
+ leases_ret = NULL;
+ }
+
+ rv = nleases;
+
+cleanup:
+ if (lease)
+ VIR_FREE(lease);
+ VIR_FREE(lease_file);
+ VIR_FREE(lease_entries);
+ if (lease_fields)
+ virStringFreeList(lease_fields);
+ return rv;
+
+error:
+ if (leases_ret) {
+ for (i = 0; i < nleases; i++)
+ virNetworkDHCPLeaseFree(leases_ret[i]);
+ VIR_FREE(leases_ret);
+ }
+ goto cleanup;
+}
+
+static int
+networkGetDHCPLeases(virNetworkPtr network,
+ virNetworkDHCPLeasesPtr **leases,
+ unsigned int flags)
+{
+ int rv = -1;
+ virNetworkObjPtr obj;
+
+ virCheckFlags(0, -1);
+
+ if (!(obj = networkObjFromNetwork(network)))
+ return rv;
+
+ if (virNetworkGetDHCPLeasesEnsureACL(network->conn, obj->def) < 0)
+ goto cleanup;
+
+ rv = networkGetDHCPLeasesHelper(network, obj, NULL, leases);
+
+cleanup:
+ if (obj)
+ virNetworkObjUnlock(obj);
+ return rv;
+}
+
+static int
+networkGetDHCPLeasesForMAC(virNetworkPtr network,
+ const char *mac,
+ virNetworkDHCPLeasesPtr **leases,
+ unsigned int flags)
+{
+ int rv = -1;
+ virNetworkObjPtr obj;
+
+ virCheckFlags(0, -1);
+
+ if (!(obj = networkObjFromNetwork(network)))
+ return rv;
+
+ if (virNetworkGetDHCPLeasesForMACEnsureACL(network->conn, obj->def) < 0)
+ goto cleanup;
+
+ rv = networkGetDHCPLeasesHelper(network, obj, mac, leases);
+
+cleanup:
+ if (obj)
+ virNetworkObjUnlock(obj);
+ return rv;
+}
static virNetworkDriver networkDriver = {
"Network",
@@ -3012,6 +3250,8 @@ static virNetworkDriver networkDriver = {
.networkSetAutostart = networkSetAutostart, /* 0.2.1 */
.networkIsActive = networkIsActive, /* 0.7.3 */
.networkIsPersistent = networkIsPersistent, /* 0.7.3 */
+ .networkGetDHCPLeases = networkGetDHCPLeases, /* 1.1.3 */
+ .networkGetDHCPLeasesForMAC = networkGetDHCPLeasesForMAC, /* 1.1.3 */
};
static virStateDriver networkStateDriver = {
--
1.7.11.7