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

Julio Faracco jcfaracco at gmail.com
Tue Apr 21 04:03:54 UTC 2020


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 leasetime for
range and hosts tags. They can be defined under that settings:

    <dhcp>
      <range ...>
        <lease/>
      </range>
      <host ...>
        <lease/>
      </host>
    </dhcp>

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

Signed-off-by: Julio Faracco <jcfaracco at gmail.com>
---
 docs/schemas/basictypes.rng |   8 ++
 docs/schemas/network.rng    |  20 +++++
 src/conf/network_conf.c     | 159 +++++++++++++++++++++++++++++++-----
 src/conf/network_conf.h     |  27 +++++-
 src/libvirt_private.syms    |   3 +
 src/network/bridge_driver.c |  56 +++++++++++--
 src/network/bridge_driver.h |   1 +
 src/test/test_driver.c      |   2 +-
 src/util/virdnsmasq.c       |  68 ++++++++++-----
 src/util/virdnsmasq.h       |   3 +
 src/vbox/vbox_network.c     |  16 ++--
 11 files changed, 305 insertions(+), 58 deletions(-)

diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
index 81465273c8..271ed18afb 100644
--- a/docs/schemas/basictypes.rng
+++ b/docs/schemas/basictypes.rng
@@ -607,4 +607,12 @@
     </element>
   </define>
 
+  <define name="leaseUnit">
+    <choice>
+      <value>seconds</value>
+      <value>mins</value>
+      <value>hours</value>
+    </choice>
+  </define>
+
 </grammar>
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index 60453225d6..88b6f4dfdd 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -371,6 +371,16 @@
                       <element name="range">
                         <attribute name="start"><ref name="ipAddr"/></attribute>
                         <attribute name="end"><ref name="ipAddr"/></attribute>
+                        <interleave>
+                          <optional>
+                            <element name="lease">
+                              <attribute name="expiry"><ref name="unsignedLong"/></attribute>
+                              <optional>
+                                <attribute name="unit"><ref name="leaseUnit"/></attribute>
+                              </optional>
+                            </element>
+                          </optional>
+                        </interleave>
                       </element>
                     </zeroOrMore>
                     <zeroOrMore>
@@ -388,6 +398,16 @@
                           <attribute name="name"><text/></attribute>
                         </choice>
                         <attribute name="ip"><ref name="ipAddr"/></attribute>
+                        <interleave>
+                          <optional>
+                            <element name="lease">
+                              <attribute name="expiry"><ref name="unsignedLong"/></attribute>
+                              <optional>
+                                <attribute name="unit"><ref name="leaseUnit"/></attribute>
+                              </optional>
+                            </element>
+                          </optional>
+                        </interleave>
                       </element>
                     </zeroOrMore>
                     <optional>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 819b645df7..286a0edb7c 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -70,6 +70,13 @@ VIR_ENUM_IMPL(virNetworkTaint,
               "hook-script",
 );
 
+VIR_ENUM_IMPL(virNetworkDHCPLeaseTimeUnit,
+              VIR_NETWORK_DHCP_LEASETIME_UNIT_LAST,
+              "seconds",
+              "mins",
+              "hours",
+);
+
 static virClassPtr virNetworkXMLOptionClass;
 
 static void
@@ -132,12 +139,20 @@ virNetworkForwardPfDefClear(virNetworkForwardPfDefPtr def)
 }
 
 
+static void
+virNetworkDHCPLeaseTimeDefClear(virNetworkDHCPLeaseTimeDefPtr lease)
+{
+    VIR_FREE(lease);
+}
+
+
 static void
 virNetworkDHCPHostDefClear(virNetworkDHCPHostDefPtr def)
 {
     VIR_FREE(def->mac);
     VIR_FREE(def->id);
     VIR_FREE(def->name);
+    VIR_FREE(def->lease);
 }
 
 
@@ -145,6 +160,9 @@ static void
 virNetworkIPDefClear(virNetworkIPDefPtr def)
 {
     VIR_FREE(def->family);
+
+    while (def->nranges)
+        virNetworkDHCPLeaseTimeDefClear(def->ranges[--def->nranges].lease);
     VIR_FREE(def->ranges);
 
     while (def->nhosts)
@@ -391,11 +409,55 @@ int virNetworkIPDefNetmask(const virNetworkIPDef *def,
 
 
 static int
-virSocketAddrRangeParseXML(const char *networkName,
-                           virNetworkIPDefPtr ipdef,
-                           xmlNodePtr node,
-                           virSocketAddrRangePtr range)
+virNetworkDHCPLeaseTimeDefParseXML(virNetworkDHCPLeaseTimeDefPtr *lease,
+                                   xmlNodePtr node)
+{
+    virNetworkDHCPLeaseTimeDefPtr new_lease = *lease;
+    g_autofree char *expiry = NULL, *unit = NULL;
+
+    if (!(expiry = virXMLPropString(node, "expiry")))
+        return 0;
+
+    if (VIR_ALLOC(new_lease) < 0)
+        return -1;
+
+    if (virStrToLong_ul(expiry, NULL, 10, &new_lease->expiry) < 0)
+        return -1;
+
+    if (!(unit = virXMLPropString(node, "unit")))
+        new_lease->unit = VIR_NETWORK_DHCP_LEASETIME_UNIT_MINUTES;
+    else
+        new_lease->unit = virNetworkDHCPLeaseTimeUnitTypeFromString(unit);
+
+    /* infinite */
+    if (new_lease->expiry > 0) {
+        /* This boundary check is related to dnsmasq man page settings:
+         * "The minimum lease time is two minutes." */
+        if ((new_lease->unit == VIR_NETWORK_DHCP_LEASETIME_UNIT_SECONDS &&
+             new_lease->expiry < 120) ||
+            (new_lease->unit == VIR_NETWORK_DHCP_LEASETIME_UNIT_MINUTES &&
+             new_lease->expiry < 2)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("The minimum lease time should be greater "
+                             "than 2 minutes"));
+            return -1;
+        }
+    }
+
+    *lease = new_lease;
+
+    return 0;
+}
+
+
+static int
+virNetworkDHCPRangeDefParseXML(const char *networkName,
+                               virNetworkIPDefPtr ipdef,
+                               xmlNodePtr node,
+                               virNetworkDHCPRangeDefPtr range)
 {
+    virSocketAddrRangePtr addr = &range->addr;
+    xmlNodePtr cur = node->children;
     char *start = NULL, *end = NULL;
     int ret = -1;
 
@@ -405,7 +467,7 @@ virSocketAddrRangeParseXML(const char *networkName,
                        networkName);
         goto cleanup;
     }
-    if (virSocketAddrParse(&range->start, start, AF_UNSPEC) < 0)
+    if (virSocketAddrParse(&addr->start, start, AF_UNSPEC) < 0)
         goto cleanup;
 
     if (!(end = virXMLPropString(node, "end"))) {
@@ -414,14 +476,24 @@ virSocketAddrRangeParseXML(const char *networkName,
                        networkName);
         goto cleanup;
     }
-    if (virSocketAddrParse(&range->end, end, AF_UNSPEC) < 0)
+    if (virSocketAddrParse(&addr->end, end, AF_UNSPEC) < 0)
         goto cleanup;
 
     /* do a sanity check of the range */
-    if (virSocketAddrGetRange(&range->start, &range->end, &ipdef->address,
+    if (virSocketAddrGetRange(&addr->start, &addr->end, &ipdef->address,
                               virNetworkIPDefPrefix(ipdef)) < 0)
         goto cleanup;
 
+    while (cur != NULL) {
+        if (cur->type == XML_ELEMENT_NODE &&
+            virXMLNodeNameEqual(cur, "lease")) {
+
+            if (virNetworkDHCPLeaseTimeDefParseXML(&range->lease, cur) < 0)
+                goto cleanup;
+        }
+        cur = cur->next;
+    }
+
     ret = 0;
 
  cleanup:
@@ -441,6 +513,7 @@ virNetworkDHCPHostDefParseXML(const char *networkName,
     char *mac = NULL, *name = NULL, *ip = NULL, *id = NULL;
     virMacAddr addr;
     virSocketAddr inaddr;
+    xmlNodePtr cur = node->children;
     int ret = -1;
 
     mac = virXMLPropString(node, "mac");
@@ -533,6 +606,16 @@ virNetworkDHCPHostDefParseXML(const char *networkName,
         }
     }
 
+    while (cur != NULL) {
+        if (cur->type == XML_ELEMENT_NODE &&
+            virXMLNodeNameEqual(cur, "lease")) {
+
+            if (virNetworkDHCPLeaseTimeDefParseXML(&host->lease, cur) < 0)
+                goto cleanup;
+        }
+        cur = cur->next;
+    }
+
     host->mac = mac;
     mac = NULL;
     host->id = id;
@@ -559,7 +642,7 @@ virNetworkDHCPDefParseXML(const char *networkName,
 {
     int ret = -1;
     xmlNodePtr cur;
-    virSocketAddrRange range;
+    virNetworkDHCPRangeDef range;
     virNetworkDHCPHostDef host;
 
     memset(&range, 0, sizeof(range));
@@ -570,7 +653,7 @@ virNetworkDHCPDefParseXML(const char *networkName,
         if (cur->type == XML_ELEMENT_NODE &&
             virXMLNodeNameEqual(cur, "range")) {
 
-            if (virSocketAddrRangeParseXML(networkName, def, cur, &range) < 0)
+            if (virNetworkDHCPRangeDefParseXML(networkName, def, cur, &range) < 0)
                 goto cleanup;
             if (VIR_APPEND_ELEMENT(def->ranges, def->nranges, range) < 0)
                 goto cleanup;
@@ -583,7 +666,6 @@ virNetworkDHCPDefParseXML(const char *networkName,
                 goto cleanup;
             if (VIR_APPEND_ELEMENT(def->hosts, def->nhosts, host) < 0)
                 goto cleanup;
-
         } else if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET) &&
                    cur->type == XML_ELEMENT_NODE &&
                    virXMLNodeNameEqual(cur, "bootp")) {
@@ -2300,20 +2382,39 @@ virNetworkIPDefFormat(virBufferPtr buf,
         virBufferAdjustIndent(buf, 2);
 
         for (i = 0; i < def->nranges; i++) {
-            char *saddr = virSocketAddrFormat(&def->ranges[i].start);
+            virSocketAddrRange addr = def->ranges[i].addr;
+            virNetworkDHCPLeaseTimeDefPtr lease = def->ranges[i].lease;
+
+            char *saddr = virSocketAddrFormat(&addr.start);
             if (!saddr)
                 return -1;
-            char *eaddr = virSocketAddrFormat(&def->ranges[i].end);
+            char *eaddr = virSocketAddrFormat(&addr.end);
             if (!eaddr) {
                 VIR_FREE(saddr);
                 return -1;
             }
-            virBufferAsprintf(buf, "<range start='%s' end='%s'/>\n",
+            virBufferAsprintf(buf, "<range start='%s' end='%s'",
                               saddr, eaddr);
+            if (lease) {
+                virBufferAddLit(buf, ">\n");
+                virBufferAdjustIndent(buf, 2);
+                if (!lease->expiry) {
+                    virBufferAddLit(buf, "<lease expiry='0'/>\n");
+                } else {
+                    virBufferAsprintf(buf, "<lease expiry='%lu' unit='%s'/>\n",
+                                      lease->expiry,
+                                      virNetworkDHCPLeaseTimeUnitTypeToString(lease->unit));
+                }
+                virBufferAdjustIndent(buf, -2);
+                virBufferAddLit(buf, "</range>\n");
+            } else {
+                virBufferAddLit(buf, "/>\n");
+            }
             VIR_FREE(saddr);
             VIR_FREE(eaddr);
         }
         for (i = 0; i < def->nhosts; i++) {
+            virNetworkDHCPLeaseTimeDefPtr lease = def->hosts[i].lease;
             virBufferAddLit(buf, "<host");
             if (def->hosts[i].mac)
                 virBufferAsprintf(buf, " mac='%s'", def->hosts[i].mac);
@@ -2328,7 +2429,21 @@ virNetworkIPDefFormat(virBufferPtr buf,
                 virBufferAsprintf(buf, " ip='%s'", ipaddr);
                 VIR_FREE(ipaddr);
             }
-            virBufferAddLit(buf, "/>\n");
+            if (lease) {
+                virBufferAddLit(buf, ">\n");
+                virBufferAdjustIndent(buf, 2);
+                if (!lease->expiry) {
+                    virBufferAddLit(buf, "<lease expiry='0'/>\n");
+                } else {
+                    virBufferAsprintf(buf, "<lease expiry='%lu' unit='%s'/>\n",
+                                      lease->expiry,
+                                      virNetworkDHCPLeaseTimeUnitTypeToString(lease->unit));
+                }
+                virBufferAdjustIndent(buf, -2);
+                virBufferAddLit(buf, "</host>\n");
+            } else {
+                virBufferAddLit(buf, "/>\n");
+            }
         }
         if (def->bootfile) {
             virBufferEscapeString(buf, "<bootp file='%s'",
@@ -2343,7 +2458,6 @@ virNetworkIPDefFormat(virBufferPtr buf,
             virBufferAddLit(buf, "/>\n");
 
         }
-
         virBufferAdjustIndent(buf, -2);
         virBufferAddLit(buf, "</dhcp>\n");
     }
@@ -3080,7 +3194,7 @@ virNetworkDefUpdateIPDHCPRange(virNetworkDefPtr def,
 {
     size_t i;
     virNetworkIPDefPtr ipdef = virNetworkIPDefByIndex(def, parentIndex);
-    virSocketAddrRange range;
+    virNetworkDHCPRangeDef range;
 
     memset(&range, 0, sizeof(range));
 
@@ -3100,11 +3214,11 @@ virNetworkDefUpdateIPDHCPRange(virNetworkDefPtr def,
         return -1;
     }
 
-    if (virSocketAddrRangeParseXML(def->name, ipdef, ctxt->node, &range) < 0)
+    if (virNetworkDHCPRangeDefParseXML(def->name, ipdef, ctxt->node, &range) < 0)
         return -1;
 
     if (VIR_SOCKET_ADDR_FAMILY(&ipdef->address)
-        != VIR_SOCKET_ADDR_FAMILY(&range.start)) {
+        != VIR_SOCKET_ADDR_FAMILY(&range.addr.start)) {
         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("the address family of a dhcp range must match "
                          "the address family of the dhcp element's parent"));
@@ -3113,8 +3227,9 @@ virNetworkDefUpdateIPDHCPRange(virNetworkDefPtr def,
 
     /* check if an entry with same name/address/ip already exists */
     for (i = 0; i < ipdef->nranges; i++) {
-        if (virSocketAddrEqual(&range.start, &ipdef->ranges[i].start) &&
-            virSocketAddrEqual(&range.end, &ipdef->ranges[i].end)) {
+        virSocketAddrRange addr = ipdef->ranges[i].addr;
+        if (virSocketAddrEqual(&range.addr.start, &addr.start) &&
+            virSocketAddrEqual(&range.addr.end, &addr.end)) {
             break;
         }
     }
@@ -3126,8 +3241,8 @@ virNetworkDefUpdateIPDHCPRange(virNetworkDefPtr def,
             return -1;
 
         if (i < ipdef->nranges) {
-            char *startip = virSocketAddrFormat(&range.start);
-            char *endip = virSocketAddrFormat(&range.end);
+            char *startip = virSocketAddrFormat(&range.addr.start);
+            char *endip = virSocketAddrFormat(&range.addr.end);
 
             virReportError(VIR_ERR_OPERATION_INVALID,
                            _("there is an existing dhcp range entry in "
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index db7243eef5..f2dc388ef0 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -80,6 +80,16 @@ 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_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.
@@ -94,6 +104,20 @@ typedef enum {
 
 VIR_ENUM_DECL(virNetworkForwardDriverName);
 
+typedef struct _virNetworkDHCPLeaseTimeDef virNetworkDHCPLeaseTimeDef;
+typedef virNetworkDHCPLeaseTimeDef *virNetworkDHCPLeaseTimeDefPtr;
+struct _virNetworkDHCPLeaseTimeDef {
+    unsigned long expiry;
+    virNetworkDHCPLeaseTimeUnitType unit;
+};
+
+typedef struct _virNetworkDHCPRangeDef virNetworkDHCPRangeDef;
+typedef virNetworkDHCPRangeDef *virNetworkDHCPRangeDefPtr;
+struct _virNetworkDHCPRangeDef {
+    virSocketAddrRange addr;
+    virNetworkDHCPLeaseTimeDefPtr lease;
+};
+
 typedef struct _virNetworkDHCPHostDef virNetworkDHCPHostDef;
 typedef virNetworkDHCPHostDef *virNetworkDHCPHostDefPtr;
 struct _virNetworkDHCPHostDef {
@@ -101,6 +125,7 @@ struct _virNetworkDHCPHostDef {
     char *id;
     char *name;
     virSocketAddr ip;
+    virNetworkDHCPLeaseTimeDefPtr lease;
 };
 
 typedef struct _virNetworkDNSTxtDef virNetworkDNSTxtDef;
@@ -171,7 +196,7 @@ struct _virNetworkIPDef {
     int localPTR; /* virTristateBool */
 
     size_t nranges;             /* Zero or more dhcp ranges */
-    virSocketAddrRangePtr ranges;
+    virNetworkDHCPRangeDefPtr ranges;
 
     size_t nhosts;              /* Zero or more dhcp hosts */
     virNetworkDHCPHostDefPtr hosts;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 182a570382..b7e18c146d 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -770,6 +770,8 @@ virNetworkDefParseNode;
 virNetworkDefParseString;
 virNetworkDefParseXML;
 virNetworkDefUpdateSection;
+virNetworkDHCPLeaseTimeUnitTypeFromString;
+virNetworkDHCPLeaseTimeUnitTypeToString;
 virNetworkForwardTypeToString;
 virNetworkIPDefNetmask;
 virNetworkIPDefPrefix;
@@ -1948,6 +1950,7 @@ dnsmasqCapsRefresh;
 dnsmasqContextFree;
 dnsmasqContextNew;
 dnsmasqDelete;
+dnsmasqDhcpHostsToString;
 dnsmasqReload;
 dnsmasqSave;
 
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index f06099297a..db17e6b2fd 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -966,6 +966,30 @@ static int networkConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)
 }
 
 
+static char *
+networkBuildDnsmasqLeaseTime(virNetworkDHCPLeaseTimeDefPtr lease)
+{
+    char *leasetime = NULL;
+    const char *unit;
+    g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+
+    if (!lease)
+        return NULL;
+
+    if (lease->expiry == 0) {
+        virBufferAddLit(&buf, "infinite");
+    } else {
+        unit = virNetworkDHCPLeaseTimeUnitTypeToString(lease->unit);
+        /* We get only first compatible char from string: 's', 'm' or 'h' */
+        virBufferAsprintf(&buf, "%lu%c", lease->expiry, 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,14 +999,18 @@ networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
 {
     size_t i;
     bool ipv6 = false;
+    g_autofree char *leasetime = NULL;
 
     if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
         ipv6 = true;
     for (i = 0; i < ipdef->nhosts; i++) {
         virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
+
+        leasetime = networkBuildDnsmasqLeaseTime(host->lease);
         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;
     }
 
@@ -1052,6 +1080,7 @@ int
 networkDnsmasqConfContents(virNetworkObjPtr obj,
                            const char *pidfile,
                            char **configstr,
+                           char **hostsfilestr,
                            dnsmasqContext *dctx,
                            dnsmasqCapsPtr caps G_GNUC_UNUSED)
 {
@@ -1381,13 +1410,15 @@ networkDnsmasqConfContents(virNetworkObjPtr obj,
         }
         for (r = 0; r < ipdef->nranges; r++) {
             int thisRange;
+            virNetworkDHCPRangeDef range = ipdef->ranges[r];
+            g_autofree char *leasetime = NULL;
 
-            if (!(saddr = virSocketAddrFormat(&ipdef->ranges[r].start)) ||
-                !(eaddr = virSocketAddrFormat(&ipdef->ranges[r].end)))
+            if (!(saddr = virSocketAddrFormat(&range.addr.start)) ||
+                !(eaddr = virSocketAddrFormat(&range.addr.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,14 +1435,19 @@ 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(range.lease)))
+                virBufferAsprintf(&configbuf, ",%s", leasetime);
+
+            virBufferAddLit(&configbuf, "\n");
+
             VIR_FREE(saddr);
             VIR_FREE(eaddr);
-            thisRange = virSocketAddrGetRange(&ipdef->ranges[r].start,
-                                              &ipdef->ranges[r].end,
+            thisRange = virSocketAddrGetRange(&range.addr.start,
+                                              &range.addr.end,
                                               &ipdef->address,
                                               virNetworkIPDefPrefix(ipdef));
             if (thisRange < 0)
@@ -1440,6 +1476,9 @@ networkDnsmasqConfContents(virNetworkObjPtr obj,
         if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
             goto cleanup;
 
+        *hostsfilestr = dnsmasqDhcpHostsToString(dctx->hostsfile->hosts,
+                                                 dctx->hostsfile->nhosts);
+
         /* Note: the following is IPv4 only */
         if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
             if (ipdef->nranges || ipdef->nhosts) {
@@ -1549,11 +1588,12 @@ networkBuildDhcpDaemonCommandLine(virNetworkDriverStatePtr driver,
     int ret = -1;
     char *configfile = NULL;
     char *configstr = NULL;
+    char *hostsfilestr = NULL;
     char *leaseshelper_path = NULL;
 
     virNetworkObjSetDnsmasqPid(obj, -1);
 
-    if (networkDnsmasqConfContents(obj, pidfile, &configstr,
+    if (networkDnsmasqConfContents(obj, pidfile, &configstr, &hostsfilestr,
                                    dctx, dnsmasq_caps) < 0)
         goto cleanup;
     if (!configstr)
diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h
index d35850d293..fb0ccad4b1 100644
--- a/src/network/bridge_driver.h
+++ b/src/network/bridge_driver.h
@@ -46,5 +46,6 @@ int
 networkDnsmasqConfContents(virNetworkObjPtr obj,
                            const char *pidfile,
                            char **configstr,
+                           char **hostsfilestr,
                            dnsmasqContext *dctx,
                            dnsmasqCapsPtr caps);
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index 7759847c2d..0506147888 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -5025,7 +5025,7 @@ testDomainInterfaceAddressFromNet(testDriverPtr driver,
                                                       net_def->ips->prefix);
 
     if (net_def->ips->nranges > 0)
-        addr = net_def->ips->ranges[0].start;
+        addr = net_def->ips->ranges[0].addr.start;
     else
         addr = net_def->ips->address;
 
diff --git a/src/util/virdnsmasq.c b/src/util/virdnsmasq.c
index adc6f96bb6..ee4c458290 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);
 }
 
 /*
@@ -862,3 +862,31 @@ dnsmasqCapsGet(dnsmasqCapsPtr caps, dnsmasqCapsFlags flag)
 {
     return caps && virBitmapIsBitSet(caps->flags, flag);
 }
+
+
+/** dnsmasqDhcpHostsToString:
+ *
+ *   Turns a vector of dnsmasqDhcpHost into the string that is ought to be
+ *   stored in the hostsfile, this functionality is split to make hostsfiles
+ *   testable. Returs NULL if nhosts is 0.
+ */
+char *
+dnsmasqDhcpHostsToString(dnsmasqDhcpHost *hosts,
+                         unsigned int nhosts)
+{
+    size_t i;
+    char *result = NULL;
+    virBuffer hostsfilebuf = VIR_BUFFER_INITIALIZER;
+
+    if (nhosts == 0)
+       goto cleanup;
+
+    for (i = 0; i < nhosts; i++)
+        virBufferAsprintf(&hostsfilebuf, "%s\n", hosts[i].host);
+
+    result = virBufferContentAndReset(&hostsfilebuf);
+
+ cleanup:
+    virBufferFreeAndReset(&hostsfilebuf);
+    return result;
+}
diff --git a/src/util/virdnsmasq.h b/src/util/virdnsmasq.h
index ff0e56d635..4c14bc6ca7 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,
@@ -104,6 +105,8 @@ int dnsmasqCapsRefresh(dnsmasqCapsPtr *caps, const char *binaryPath);
 bool dnsmasqCapsGet(dnsmasqCapsPtr caps, dnsmasqCapsFlags flag);
 const char *dnsmasqCapsGetBinaryPath(dnsmasqCapsPtr caps);
 unsigned long dnsmasqCapsGetVersion(dnsmasqCapsPtr caps);
+char *dnsmasqDhcpHostsToString(dnsmasqDhcpHost *hosts,
+                               unsigned int nhosts);
 
 #define DNSMASQ_DHCPv6_MAJOR_REQD 2
 #define DNSMASQ_DHCPv6_MINOR_REQD 64
diff --git a/src/vbox/vbox_network.c b/src/vbox/vbox_network.c
index 19b4d23ed8..cf273b9a48 100644
--- a/src/vbox/vbox_network.c
+++ b/src/vbox/vbox_network.c
@@ -379,6 +379,7 @@ vboxNetworkDefineCreateXML(virConnectPtr conn, const char *xml, bool start)
     virNetworkIPDefPtr ipdef = NULL;
     unsigned char uuid[VIR_UUID_BUFLEN];
     vboxIID vboxnetiid;
+    virSocketAddrRange addr;
     virSocketAddr netmask;
     IHost *host = NULL;
     virNetworkPtr ret = NULL;
@@ -440,9 +441,10 @@ vboxNetworkDefineCreateXML(virConnectPtr conn, const char *xml, bool start)
     /* Currently support only one dhcp server per network
      * with contigious address space from start to end
      */
+    addr = ipdef->ranges[0].addr;
     if ((ipdef->nranges >= 1) &&
-        VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].start) &&
-        VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].end)) {
+        VIR_SOCKET_ADDR_VALID(&addr.start) &&
+        VIR_SOCKET_ADDR_VALID(&addr.end)) {
         IDHCPServer *dhcpServer = NULL;
 
         gVBoxAPI.UIVirtualBox.FindDHCPServerByNetworkName(data->vboxObj,
@@ -464,8 +466,8 @@ vboxNetworkDefineCreateXML(virConnectPtr conn, const char *xml, bool start)
 
             ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->address);
             networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
-            fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].start);
-            toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].end);
+            fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &addr.start);
+            toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &addr.end);
 
             if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL ||
                 fromIPAddressUtf16 == NULL || toIPAddressUtf16 == NULL) {
@@ -770,6 +772,7 @@ static char *vboxNetworkGetXMLDesc(virNetworkPtr network, unsigned int flags)
     vboxIID vboxnet0IID;
     IHost *host = NULL;
     char *ret = NULL;
+    virSocketAddrRange addr;
     nsresult rc;
 
     if (!data->vboxObj)
@@ -833,14 +836,15 @@ static char *vboxNetworkGetXMLDesc(virNetworkPtr network, unsigned int flags)
             /* Currently virtualbox supports only one dhcp server per network
              * with contigious address space from start to end
              */
+            addr = ipdef->ranges[0].addr;
             if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
                                          &ipdef->address) < 0 ||
                 vboxSocketParseAddrUtf16(data, networkMaskUtf16,
                                          &ipdef->netmask) < 0 ||
                 vboxSocketParseAddrUtf16(data, fromIPAddressUtf16,
-                                         &ipdef->ranges[0].start) < 0 ||
+                                         &addr.start) < 0 ||
                 vboxSocketParseAddrUtf16(data, toIPAddressUtf16,
-                                         &ipdef->ranges[0].end) < 0) {
+                                         &addr.end) < 0) {
                 errorOccurred = true;
             }
 
-- 
2.24.1





More information about the libvir-list mailing list