Query the network driver for the path of the custom leases file for the given
virtual network and parse it to retrieve info.
src/network/bridge_driver.c:
* Implement networkGetDHCPLeases
* Implement networkGetDHCPLeasesForMAC
* Implement networkGetDHCPLeasesHelper
---
src/network/bridge_driver.c | 232 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 232 insertions(+)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 8de7a59..d5577e0 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -73,9 +73,17 @@
#include "viraccessapicheck.h"
#include "network_event.h"
#include "virhook.h"
+#include "virjson.h"
#define VIR_FROM_THIS VIR_FROM_NETWORK
+/**
+ * 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 (32 * 1024 * 1024)
+
VIR_LOG_INIT("network.bridge_driver");
static void networkDriverLock(virNetworkDriverStatePtr driver)
@@ -3360,6 +3368,228 @@ static int networkSetAutostart(virNetworkPtr net,
return ret;
}
+static int
+networkGetDHCPLeasesHelper(virNetworkObjPtr obj,
+ const char *mac,
+ virNetworkDHCPLeasePtr **leases)
+{
+ size_t i, j;
+ size_t nleases = 0;
+ int rv = -1;
+ int size = 0;
+ int custom_lease_file_len = 0;
+ bool need_results = !!leases;
+ long long currtime = 0;
+ long long expirytime_tmp = -1;
+ bool ipv6 = false;
+ char *lease_entries = NULL;
+ char *custom_lease_file = NULL;
+ const char *ip_tmp = NULL;
+ const char *mac_tmp = NULL;
+ virJSONValuePtr lease_tmp = NULL;
+ virJSONValuePtr leases_array = NULL;
+ virNetworkIpDefPtr ipdef_tmp = NULL;
+ virNetworkDHCPLeasePtr lease = NULL;
+ virNetworkDHCPLeasePtr *leases_ret = NULL;
+
+ /* Retrieve custom leases file location */
+ custom_lease_file = networkDnsmasqLeaseFileNameCustom(obj->def->bridge);
+
+ /* Read entire contents */
+ if ((custom_lease_file_len = virFileReadAll(custom_lease_file,
+ VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX,
+ &lease_entries)) < 0) {
+ /* Even though src/network/leaseshelper.c guarantees the existence of
+ * leases file (even if no leases are present), and the control reaches
+ * here, instead of reporting error, return 0 leases */
+ rv = 0;
+ goto error;
+ }
+
+ if (custom_lease_file_len) {
+ if (!(leases_array = virJSONValueFromString(lease_entries))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("invalid json in file: %s"), custom_lease_file);
+ goto error;
+ }
+
+ if ((size = virJSONValueArraySize(leases_array)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("couldn't fetch array of leases"));
+ goto error;
+ }
+ }
+
+ currtime = (long long) time(NULL);
+
+ for (i = 0; i < size; i++) {
+ if (!(lease_tmp = virJSONValueArrayGet(leases_array, i))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to parse json"));
+ goto error;
+ }
+
+ if (!(mac_tmp = virJSONValueObjectGetString(lease_tmp, "mac-address")))
{
+ /* leaseshelper program guarantees that lease will be stored only if
+ * mac-address is known otherwise not */
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("found lease without mac-address"));
+ goto error;
+ }
+
+ if (mac && virMacAddrCompare(mac, mac_tmp)) {
+ virJSONValueFree(lease_tmp);
+ continue;
+ }
+
+ if (virJSONValueObjectGetNumberLong(lease_tmp, "expiry-time",
&expirytime_tmp) < 0) {
+ /* A lease cannot be present without expiry-time */
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("found lease without expiry-time"));
+ goto error;
+ }
+
+ /* Do not report expired lease */
+ if (expirytime_tmp < currtime)
+ continue;
+
+ if (need_results) {
+ if (VIR_ALLOC(lease) < 0)
+ goto error;
+
+ lease->expirytime = expirytime_tmp;
+
+ if (!(ip_tmp = virJSONValueObjectGetString(lease_tmp,
"ip-address"))) {
+ /* A lease without ip-address makes no sense */
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("found lease without ip-address"));
+ goto error;
+ }
+
+ /* Unlike IPv4, IPv6 uses ':' instead of '.' as separator */
+ ipv6 = strchr(ip_tmp, ':') ? true : false;
+ lease->type = ipv6 ? VIR_IP_ADDR_TYPE_IPV6 : VIR_IP_ADDR_TYPE_IPV4;
+
+ /* Obtain prefix */
+ for (j = 0; j < obj->def->nips; j++) {
+ ipdef_tmp = &obj->def->ips[j];
+
+ if (ipv6 &&
VIR_SOCKET_ADDR_IS_FAMILY(&ipdef_tmp->address,
+ AF_INET6)) {
+ lease->prefix = ipdef_tmp->prefix;
+ break;
+ }
+ if (!ipv6 &&
VIR_SOCKET_ADDR_IS_FAMILY(&ipdef_tmp->address,
+ AF_INET)) {
+ lease->prefix =
virSocketAddrGetIpPrefix(&ipdef_tmp->address,
+ &ipdef_tmp->netmask,
+ ipdef_tmp->prefix);
+ break;
+ }
+ }
+
+ if ((VIR_STRDUP(lease->mac, mac_tmp) < 0) ||
+ (VIR_STRDUP(lease->ipaddr, ip_tmp) < 0) ||
+ (VIR_STRDUP(lease->interface, obj->def->bridge) < 0))
+ goto error;
+
+ /* Fields that can be NULL */
+ if ((VIR_STRDUP(lease->iaid,
+ virJSONValueObjectGetString(lease_tmp, "iaid"))
< 0) ||
+ (VIR_STRDUP(lease->clientid,
+ virJSONValueObjectGetString(lease_tmp,
"client-id")) < 0) ||
+ (VIR_STRDUP(lease->hostname,
+ virJSONValueObjectGetString(lease_tmp, "hostname"))
< 0))
+ goto error;
+
+ if (VIR_INSERT_ELEMENT(leases_ret, nleases, nleases, lease) < 0)
+ goto error;
+
+ } else {
+ nleases++;
+ }
+
+ VIR_FREE(lease);
+ }
+
+ 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:
+ VIR_FREE(lease);
+ VIR_FREE(custom_lease_file);
+ virJSONValueFree(leases_array);
+ 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,
+ virNetworkDHCPLeasePtr **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(obj, NULL, leases);
+
+ cleanup:
+ if (obj)
+ virNetworkObjUnlock(obj);
+ return rv;
+}
+
+static int
+networkGetDHCPLeasesForMAC(virNetworkPtr network,
+ const char *mac,
+ virNetworkDHCPLeasePtr **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(obj, mac, leases);
+
+ cleanup:
+ if (obj)
+ virNetworkObjUnlock(obj);
+ return rv;
+}
static virNetworkDriver networkDriver = {
"Network",
@@ -3386,6 +3616,8 @@ static virNetworkDriver networkDriver = {
.networkSetAutostart = networkSetAutostart, /* 0.2.1 */
.networkIsActive = networkIsActive, /* 0.7.3 */
.networkIsPersistent = networkIsPersistent, /* 0.7.3 */
+ .networkGetDHCPLeases = networkGetDHCPLeases, /* 1.2.6 */
+ .networkGetDHCPLeasesForMAC = networkGetDHCPLeasesForMAC, /* 1.2.6 */
};
static virStateDriver networkStateDriver = {
--
1.9.3