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

Nehal J Wani nehaljw.kkd1 at gmail.com
Mon Nov 25 21:06:00 UTC 2013


By querying the driver for the path of the custom 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 | 248 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 248 insertions(+)

diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 83dc931..1aedf86 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -109,6 +109,20 @@ 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 6
 
 static virNetworkDriverStatePtr driverState = NULL;
 
@@ -147,6 +161,16 @@ networkDnsmasqLeaseFileNameFunc networkDnsmasqLeaseFileName =
     networkDnsmasqLeaseFileNameDefault;
 
 static char *
+networkDnsmasqLeaseFileNameCustom(const char *bridge)
+{
+    char *leasefile;
+
+    ignore_value(virAsprintf(&leasefile, "%s/%s.status",
+                             driverState->dnsmasqStateDir, bridge));
+    return leasefile;
+}
+
+static char *
 networkDnsmasqConfigFileName(const char *netname)
 {
     char *conffile;
@@ -182,6 +206,7 @@ networkRemoveInactive(virNetworkDriverStatePtr driver,
                       virNetworkObjPtr net)
 {
     char *leasefile = NULL;
+    char *customleasefile = NULL;
     char *radvdconfigfile = NULL;
     char *configfile = NULL;
     char *radvdpidbase = NULL;
@@ -200,6 +225,9 @@ networkRemoveInactive(virNetworkDriverStatePtr driver,
     if (!(leasefile = networkDnsmasqLeaseFileName(def->name)))
         goto cleanup;
 
+    if (!(customleasefile = networkDnsmasqLeaseFileNameCustom(def->bridge)))
+        goto cleanup;
+
     if (!(radvdconfigfile = networkRadvdConfigFileName(def->name)))
         goto cleanup;
 
@@ -216,6 +244,7 @@ networkRemoveInactive(virNetworkDriverStatePtr driver,
     /* dnsmasq */
     dnsmasqDelete(dctx);
     unlink(leasefile);
+    unlink(customleasefile);
     unlink(configfile);
 
     /* radvd */
@@ -1058,6 +1087,9 @@ networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network,
 
     cmd = virCommandNew(dnsmasqCapsGetBinaryPath(caps));
     virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
+
+    /* This helper is used to create cutom leases file for libvirt */
+    virCommandAddArgFormat(cmd, "--dhcp-script=%s", LIBEXECDIR "/libvirt_leaseshelper");
     *cmdout = cmd;
     ret = 0;
 cleanup:
@@ -2991,6 +3023,220 @@ cleanup:
     return ret;
 }
 
+/* This function parses the leases file of dnsmasq.
+ *
+ * An example of custom leases file content:
+ *
+ * 1385245780 52:54:00:2f:ba:76 * 192.168.150.153 * *
+ * 1385245781 52:54:00:2f:ba:76 3127926 2001:db8:ca2:2:1::6c * 00:04:76:00:cf:ae:b3:0b:fc:cd:0e:22:2e:97:76:65:74:ec
+ * 1385245964 52:54:00:44:7c:d7 * 192.168.150.219 iiit-ad885e4aa1 01:52:54:00:44:7c:d7
+ * 1385245964 52:54:00:44:7c:d7 * 192.168.150.219 * 01:52:54:00:44:7c:d7
+ * 1385246016 52:54:00:5d:99:92 * 192.168.150.212 iiit-ad885e4aa1 01:52:54:00:5d:99:92
+ * 1385246041 52:54:00:3b:16:e0 * 192.168.150.207 * *
+ * 1385246081 52:54:00:db:dd:98 * 192.168.150.234 * *
+ * 1385246088 52:54:00:db:dd:98 14409112 2001:db8:ca2:2:1::6d * 00:04:76:00:cf:ae:b3:0b:fc:cd:0e:22:2e:97:76:65:74:ec
+ *
+ */
+static int
+networkGetDHCPLeasesHelper(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 custom leases file location */
+    lease_file = networkDnsmasqLeaseFileNameCustom(obj->def->bridge);
+
+    if ((lease_file_len = virFileReadAll(lease_file,
+                                        VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX,
+                                        &lease_entries)) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("No leases available for network: %s"), obj->def->name);
+        goto cleanup;
+    }
+
+    lease_entry = lease_entries[0] == '\0' ? NULL : lease_entries;
+
+    while (lease_entry) {
+        int nfields = 0;
+        ipv6 = false;
+
+        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;
+
+        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;
+            }
+
+            /* Unlike IPv4, IPv6 uses ':' instead of '.' as separator */
+            ipv6 = strchr(lease_fields[3], ':') ? true : false;
+
+            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->mac, lease_fields[1]) < 0) ||
+                (VIR_STRDUP(lease->ipaddr, lease_fields[3]) < 0) ||
+                (VIR_STRDUP(lease->interface, obj->def->bridge) < 0))
+                goto error;
+
+            /* IAID is NULL in case of ipv4 */
+            if (STREQ(lease_fields[2], "*"))
+                lease->iaid = NULL;
+            else if (VIR_STRDUP(lease->iaid, 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[4], "*"))
+                lease->hostname = NULL;
+            else if (VIR_STRDUP(lease->hostname, lease_fields[4]) < 0)
+                goto error;
+
+            if (STREQ(lease_fields[5], "*"))
+                lease->clientid = NULL;
+            else if (VIR_STRDUP(lease->clientid, lease_fields[5]) < 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:
+    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(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(obj, mac, leases);
+
+cleanup:
+    if (obj)
+        virNetworkObjUnlock(obj);
+    return rv;
+}
 
 static virNetworkDriver networkDriver = {
     "Network",
@@ -3015,6 +3261,8 @@ static virNetworkDriver networkDriver = {
     .networkSetAutostart = networkSetAutostart, /* 0.2.1 */
     .networkIsActive = networkIsActive, /* 0.7.3 */
     .networkIsPersistent = networkIsPersistent, /* 0.7.3 */
+    .networkGetDHCPLeases = networkGetDHCPLeases, /* 1.1.4 */
+    .networkGetDHCPLeasesForMAC = networkGetDHCPLeasesForMAC, /* 1.1.4 */
 };
 
 static virStateDriver networkStateDriver = {
-- 
1.8.1.4




More information about the libvir-list mailing list