[PATCH 1/2] conf: Add <leasetime/> option for <dhcp/> settings

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If an user is trying to configure a dhcp neetwork settings, it is not
possible to change the leasetime of a range or a host entry. This is
available using dnsmasq extra options, but they are associated with
dhcp-range or dhcp-hosts fields. This patch implements a default
leasetime for both. If this XML entry is defined, it applies leasetime
for each range or host defined under DHCP scope.

Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=913446

Signed-off-by: Julio Faracco <jcfaracco@xxxxxxxxx>
---
 docs/schemas/basictypes.rng |  9 ++++++
 docs/schemas/network.rng    | 11 +++++++
 src/conf/network_conf.c     | 62 ++++++++++++++++++++++++++++++++++++-
 src/conf/network_conf.h     | 14 +++++++++
 src/libvirt_private.syms    |  2 ++
 src/network/bridge_driver.c | 37 ++++++++++++++++++++--
 src/util/virdnsmasq.c       | 40 ++++++++++++------------
 src/util/virdnsmasq.h       |  1 +
 8 files changed, 152 insertions(+), 24 deletions(-)

diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
index 81465273c8..12f085c101 100644
--- a/docs/schemas/basictypes.rng
+++ b/docs/schemas/basictypes.rng
@@ -607,4 +607,13 @@
     </element>
   </define>
 
+  <define name="leaseUnit">
+    <choice>
+      <value>seconds</value>
+      <value>minutes</value>
+      <value>hours</value>
+      <value>infinite</value>
+    </choice>
+  </define>
+
 </grammar>
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index 60453225d6..9a93529d52 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -398,6 +398,17 @@
                         </optional>
                       </element>
                     </optional>
+                    <optional>
+                      <element name="leasetime">
+                        <optional>
+                          <attribute name="unit"><ref name="leaseUnit"/></attribute>
+                        </optional>
+                        <choice>
+                          <data type="unsignedLong"/>
+                          <empty/>
+                        </choice>
+                      </element>
+                    </optional>
                   </interleave>
                 </element>
               </optional>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 819b645df7..e6e82ee9fc 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -70,6 +70,14 @@ VIR_ENUM_IMPL(virNetworkTaint,
               "hook-script",
 );
 
+VIR_ENUM_IMPL(virNetworkDHCPLeaseTimeUnit,
+              VIR_NETWORK_DHCP_LEASETIME_UNIT_LAST,
+              "seconds",
+              "minutes",
+              "hours",
+              "infinite",
+);
+
 static virClassPtr virNetworkXMLOptionClass;
 
 static void
@@ -552,9 +560,50 @@ virNetworkDHCPHostDefParseXML(const char *networkName,
 }
 
 
+static int
+virNetworkDHCPLeaseTimeDefParseXML(virNetworkIPDefPtr def,
+                                   xmlNodePtr node,
+                                   xmlXPathContextPtr ctxt)
+{
+    g_autofree char *leasetime = NULL, *leaseunit = NULL;
+
+    if (!(leaseunit = virXMLPropString(node, "unit")))
+        def->leaseunit = VIR_NETWORK_DHCP_LEASETIME_UNIT_SECONDS;
+    else
+        def->leaseunit = virNetworkDHCPLeaseTimeUnitTypeFromString(leaseunit);
+
+    if (def->leaseunit == VIR_NETWORK_DHCP_LEASETIME_UNIT_INFINITE)
+        return 0;
+
+    if (!(leasetime = virXPathString("string(./dhcp/leasetime)", ctxt)))
+        return -1;
+
+    if (virStrToLong_ul(leasetime, NULL, 10, &def->leasetime) < 0)
+        return -1;
+
+    /* This boundary check is related to dnsmasq man page settings:
+     * "The minimum lease time is two minutes." */
+    if ((def->leaseunit == VIR_NETWORK_DHCP_LEASETIME_UNIT_SECONDS &&
+         def->leasetime < 120) ||
+        (def->leaseunit == VIR_NETWORK_DHCP_LEASETIME_UNIT_MINUTES &&
+         def->leasetime < 2)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("The minimum lease time should be greater "
+                         "than 2 minutes"));
+        return -1;
+    }
+
+    if (def->leasetime > 0)
+        return 0;
+
+    return -1;
+}
+
+
 static int
 virNetworkDHCPDefParseXML(const char *networkName,
                           xmlNodePtr node,
+                          xmlXPathContextPtr ctxt,
                           virNetworkIPDefPtr def)
 {
     int ret = -1;
@@ -583,7 +632,11 @@ virNetworkDHCPDefParseXML(const char *networkName,
                 goto cleanup;
             if (VIR_APPEND_ELEMENT(def->hosts, def->nhosts, host) < 0)
                 goto cleanup;
+        } else if (cur->type == XML_ELEMENT_NODE &&
+            virXMLNodeNameEqual(cur, "leasetime")) {
 
+            if (virNetworkDHCPLeaseTimeDefParseXML(def, cur, ctxt) < 0)
+                goto cleanup;
         } else if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET) &&
                    cur->type == XML_ELEMENT_NODE &&
                    virXMLNodeNameEqual(cur, "bootp")) {
@@ -1143,7 +1196,7 @@ virNetworkIPDefParseXML(const char *networkName,
     }
 
     if ((dhcp = virXPathNode("./dhcp[1]", ctxt)) &&
-        virNetworkDHCPDefParseXML(networkName, dhcp, def) < 0)
+        virNetworkDHCPDefParseXML(networkName, dhcp, ctxt, def) < 0)
         goto cleanup;
 
     if (virXPathNode("./tftp[1]", ctxt)) {
@@ -2343,6 +2396,13 @@ virNetworkIPDefFormat(virBufferPtr buf,
             virBufferAddLit(buf, "/>\n");
 
         }
+        if (def->leaseunit == VIR_NETWORK_DHCP_LEASETIME_UNIT_INFINITE) {
+            virBufferAddLit(buf, "<leasetime unit='infinite'/>\n");
+        } else if (def->leasetime) {
+            virBufferAsprintf(buf, "<leasetime unit='%s'>%lu</leasetime>\n",
+                              virNetworkDHCPLeaseTimeUnitTypeToString(def->leaseunit),
+                              def->leasetime);
+        }
 
         virBufferAdjustIndent(buf, -2);
         virBufferAddLit(buf, "</dhcp>\n");
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index db7243eef5..66a5e1ad4f 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -80,6 +80,17 @@ typedef enum {
     VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_LAST,
 } virNetworkForwardHostdevDeviceType;
 
+typedef enum {
+    VIR_NETWORK_DHCP_LEASETIME_UNIT_SECONDS = 0,
+    VIR_NETWORK_DHCP_LEASETIME_UNIT_MINUTES,
+    VIR_NETWORK_DHCP_LEASETIME_UNIT_HOURS,
+    VIR_NETWORK_DHCP_LEASETIME_UNIT_INFINITE,
+
+    VIR_NETWORK_DHCP_LEASETIME_UNIT_LAST,
+} virNetworkDHCPLeaseTimeUnitType;
+
+VIR_ENUM_DECL(virNetworkDHCPLeaseTimeUnit);
+
 /* The backend driver used for devices from the pool. Currently used
  * only for PCI devices (vfio vs. kvm), but could be used for other
  * device types in the future.
@@ -176,6 +187,9 @@ struct _virNetworkIPDef {
     size_t nhosts;              /* Zero or more dhcp hosts */
     virNetworkDHCPHostDefPtr hosts;
 
+    unsigned long leasetime;
+    virNetworkDHCPLeaseTimeUnitType leaseunit;
+
     char *tftproot;
     char *bootfile;
     virSocketAddr bootserver;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index ec367653d5..79bb5cc160 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -770,6 +770,8 @@ virNetworkDefParseNode;
 virNetworkDefParseString;
 virNetworkDefParseXML;
 virNetworkDefUpdateSection;
+virNetworkDHCPLeaseTimeUnitTypeFromString;
+virNetworkDHCPLeaseTimeUnitTypeToString;
 virNetworkForwardTypeToString;
 virNetworkIPDefNetmask;
 virNetworkIPDefPrefix;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index f06099297a..d587e266de 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -966,6 +966,27 @@ static int networkConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)
 }
 
 
+static char *
+networkBuildDnsmasqLeaseTime(virNetworkIPDefPtr ipdef)
+{
+    char *leasetime = NULL;
+    const char *unit;
+    g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+    if (ipdef->leaseunit == VIR_NETWORK_DHCP_LEASETIME_UNIT_INFINITE) {
+        virBufferAddLit(&buf, "infinite");
+    } else if (ipdef->leasetime) {
+        unit = virNetworkDHCPLeaseTimeUnitTypeToString(ipdef->leaseunit);
+        /* We get only first compatible char from string: 's', 'm' or 'h' */
+        virBufferAsprintf(&buf, "%lu%c", ipdef->leasetime, unit[0]);
+    }
+
+    leasetime = virBufferContentAndReset(&buf);
+
+    return leasetime;
+}
+
+
 /* the following does not build a file, it builds a list
  * which is later saved into a file
  */
@@ -975,6 +996,9 @@ networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
 {
     size_t i;
     bool ipv6 = false;
+    g_autofree char *leasetime = NULL;
+
+    leasetime = networkBuildDnsmasqLeaseTime(ipdef);
 
     if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
         ipv6 = true;
@@ -982,7 +1006,8 @@ networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
         virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
         if (VIR_SOCKET_ADDR_VALID(&host->ip))
             if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
-                                   host->name, host->id, ipv6) < 0)
+                                   host->name, host->id, leasetime,
+                                   ipv6) < 0)
                 return -1;
     }
 
@@ -1381,13 +1406,14 @@ networkDnsmasqConfContents(virNetworkObjPtr obj,
         }
         for (r = 0; r < ipdef->nranges; r++) {
             int thisRange;
+            g_autofree char *leasetime = NULL;
 
             if (!(saddr = virSocketAddrFormat(&ipdef->ranges[r].start)) ||
                 !(eaddr = virSocketAddrFormat(&ipdef->ranges[r].end)))
                 goto cleanup;
 
             if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) {
-               virBufferAsprintf(&configbuf, "dhcp-range=%s,%s,%d\n",
+               virBufferAsprintf(&configbuf, "dhcp-range=%s,%s,%d",
                                  saddr, eaddr, prefix);
             } else {
                 /* IPv4 - dnsmasq requires a netmask rather than prefix */
@@ -1404,10 +1430,15 @@ networkDnsmasqConfContents(virNetworkObjPtr obj,
 
                 if (!(netmaskStr = virSocketAddrFormat(&netmask)))
                     goto cleanup;
-                virBufferAsprintf(&configbuf, "dhcp-range=%s,%s,%s\n",
+                virBufferAsprintf(&configbuf, "dhcp-range=%s,%s,%s",
                                   saddr, eaddr, netmaskStr);
             }
 
+            if ((leasetime = networkBuildDnsmasqLeaseTime(ipdef)))
+                virBufferAsprintf(&configbuf, ",%s", leasetime);
+
+            virBufferAddLit(&configbuf, "\n");
+
             VIR_FREE(saddr);
             VIR_FREE(eaddr);
             thisRange = virSocketAddrGetRange(&ipdef->ranges[r].start,
diff --git a/src/util/virdnsmasq.c b/src/util/virdnsmasq.c
index adc6f96bb6..fc977a47f5 100644
--- a/src/util/virdnsmasq.c
+++ b/src/util/virdnsmasq.c
@@ -296,11 +296,14 @@ hostsfileAdd(dnsmasqHostsfile *hostsfile,
              virSocketAddr *ip,
              const char *name,
              const char *id,
+             const char *leasetime,
              bool ipv6)
 {
-    char *ipstr = NULL;
+    g_autofree char *ipstr = NULL;
+    g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
     if (VIR_REALLOC_N(hostsfile->hosts, hostsfile->nhosts + 1) < 0)
-        goto error;
+        return -1;
 
     if (!(ipstr = virSocketAddrFormat(ip)))
         return -1;
@@ -308,34 +311,30 @@ hostsfileAdd(dnsmasqHostsfile *hostsfile,
     /* the first test determines if it is a dhcpv6 host */
     if (ipv6) {
         if (name && id) {
-            hostsfile->hosts[hostsfile->nhosts].host = g_strdup_printf("id:%s,%s,[%s]",
-                                                                       id, name, ipstr);
+            virBufferAsprintf(&buf, "id:%s,%s", id, name);
         } else if (name && !id) {
-            hostsfile->hosts[hostsfile->nhosts].host = g_strdup_printf("%s,[%s]",
-                                                                       name, ipstr);
+            virBufferAsprintf(&buf, "%s", name);
         } else if (!name && id) {
-            hostsfile->hosts[hostsfile->nhosts].host = g_strdup_printf("id:%s,[%s]",
-                                                                       id, ipstr);
+            virBufferAsprintf(&buf, "id:%s", id);
         }
+        virBufferAsprintf(&buf, ",[%s]", ipstr);
     } else if (name && mac) {
-        hostsfile->hosts[hostsfile->nhosts].host = g_strdup_printf("%s,%s,%s",
-                                                                   mac, ipstr, name);
+        virBufferAsprintf(&buf, "%s,%s,%s", mac, ipstr, name);
     } else if (name && !mac) {
-        hostsfile->hosts[hostsfile->nhosts].host = g_strdup_printf("%s,%s", name,
-                                                                   ipstr);
+        virBufferAsprintf(&buf, "%s,%s", name, ipstr);
     } else {
-        hostsfile->hosts[hostsfile->nhosts].host = g_strdup_printf("%s,%s", mac,
-                                                                   ipstr);
+        virBufferAsprintf(&buf, "%s,%s", mac, ipstr);
     }
-    VIR_FREE(ipstr);
+
+    if (leasetime)
+        virBufferAsprintf(&buf, ",%s", leasetime);
+
+    if (!(hostsfile->hosts[hostsfile->nhosts].host = virBufferContentAndReset(&buf)))
+        return -1;
 
     hostsfile->nhosts++;
 
     return 0;
-
- error:
-    VIR_FREE(ipstr);
-    return -1;
 }
 
 static dnsmasqHostsfile *
@@ -501,9 +500,10 @@ dnsmasqAddDhcpHost(dnsmasqContext *ctx,
                    virSocketAddr *ip,
                    const char *name,
                    const char *id,
+                   const char *leasetime,
                    bool ipv6)
 {
-    return hostsfileAdd(ctx->hostsfile, mac, ip, name, id, ipv6);
+    return hostsfileAdd(ctx->hostsfile, mac, ip, name, id, leasetime, ipv6);
 }
 
 /*
diff --git a/src/util/virdnsmasq.h b/src/util/virdnsmasq.h
index ff0e56d635..6fbc101e64 100644
--- a/src/util/virdnsmasq.h
+++ b/src/util/virdnsmasq.h
@@ -87,6 +87,7 @@ int              dnsmasqAddDhcpHost(dnsmasqContext *ctx,
                                     virSocketAddr *ip,
                                     const char *name,
                                     const char *id,
+                                    const char *leasetime,
                                     bool ipv6);
 int              dnsmasqAddHost(dnsmasqContext *ctx,
                                 virSocketAddr *ip,
-- 
2.24.1






[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux