[libvirt] [PATCH v6 3/4] net-dhcp-leases: Private implementation inside network

Nehal J Wani nehaljw.kkd1 at gmail.com
Sun Jun 15 22:14:55 UTC 2014


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 4fc4c9a..361f36f 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




More information about the libvir-list mailing list