<div dir="ltr"><div>Support for custom dhcp wide and per host leasetime.<br></div><div><br></div><div>It is specified as a child tag for <dhcp>:</div><div><dhcp></div><div>  <leasetime>24h</leasetime></div><div>  ...</div><div></dhcp></div><div><br></div><div>And as an attribute for <host>:</div><div><dhcp></div><div>  <host leasetime="7d" .../></div><div></dhcp></div><div><br></div><div>These are the different notations:</div><div><br></div><div>-1   (infinite/unlimited lease)</div><div>120  (seconds are the default unit, 120 seconds is the minimum, if less is specified it will use 120)</div><div>300s (seconds)</div><div>5m   (minutes)</div><div>24h  (hours)</div><div>7d   (days)</div><div>---</div><div> docs/schemas/basictypes.rng                        |   5 +</div><div> docs/schemas/network.rng                           |   8 ++</div><div> src/conf/network_conf.c                            |  86 +++++++++++++-</div><div> src/conf/network_conf.h                            |   4 +-</div><div> src/libvirt_private.syms                           |   1 +</div><div> src/network/bridge_driver.c                        | 132 +++++++++++++++++----</div><div> src/network/bridge_driver.h                        |   1 +</div><div> src/util/virdnsmasq.c                              | 106 +++++++++++------</div><div> src/util/virdnsmasq.h                              |   2 +</div><div> .../dhcp6-nat-network.<wbr>hostsfile                    |   7 ++</div><div> tests/networkxml2confdata/<wbr>dhcp6-network.hostsfile  |   5 +</div><div> .../dhcp6host-routed-network.<wbr>hostsfile             |   7 ++</div><div> tests/networkxml2confdata/<wbr>leasetime-days.conf      |  17 +++</div><div> tests/networkxml2confdata/<wbr>leasetime-days.xml       |  18 +++</div><div> tests/networkxml2confdata/<wbr>leasetime-host.conf      |  16 +++</div><div> tests/networkxml2confdata/<wbr>leasetime-host.hostsfile |   6 +</div><div> tests/networkxml2confdata/<wbr>leasetime-host.xml       |  22 ++++</div><div> tests/networkxml2confdata/<wbr>leasetime-hours.conf     |  17 +++</div><div> tests/networkxml2confdata/<wbr>leasetime-hours.xml      |  18 +++</div><div> tests/networkxml2confdata/<wbr>leasetime-infinite.conf  |  17 +++</div><div> tests/networkxml2confdata/<wbr>leasetime-infinite.xml   |  18 +++</div><div> tests/networkxml2confdata/<wbr>leasetime-minutes.conf   |  17 +++</div><div> tests/networkxml2confdata/<wbr>leasetime-minutes.xml    |  18 +++</div><div> tests/networkxml2confdata/<wbr>leasetime-seconds.conf   |  17 +++</div><div> tests/networkxml2confdata/<wbr>leasetime-seconds.xml    |  18 +++</div><div> tests/networkxml2confdata/<wbr>leasetime.conf           |  17 +++</div><div> tests/networkxml2confdata/<wbr>leasetime.xml            |  18 +++</div><div> .../nat-network-dns-srv-<wbr>record-minimal.hostsfile   |   2 +</div><div> .../nat-network-dns-srv-<wbr>record.hostsfile           |   2 +</div><div> .../nat-network-dns-txt-<wbr>record.hostsfile           |   2 +</div><div> .../nat-network-name-with-<wbr>quotes.hostsfile         |   2 +</div><div> tests/networkxml2confdata/<wbr>nat-network.hostsfile    |   2 +</div><div> tests/networkxml2conftest.c                        |  47 ++++++--</div><div> 33 files changed, 597 insertions(+), 78 deletions(-)</div><div> create mode 100644 tests/networkxml2confdata/<wbr>dhcp6-nat-network.hostsfile</div><div> create mode 100644 tests/networkxml2confdata/<wbr>dhcp6-network.hostsfile</div><div> create mode 100644 tests/networkxml2confdata/<wbr>dhcp6host-routed-network.<wbr>hostsfile</div><div> create mode 100644 tests/networkxml2confdata/<wbr>leasetime-days.conf</div><div> create mode 100644 tests/networkxml2confdata/<wbr>leasetime-days.xml</div><div> create mode 100644 tests/networkxml2confdata/<wbr>leasetime-host.conf</div><div> create mode 100644 tests/networkxml2confdata/<wbr>leasetime-host.hostsfile</div><div> create mode 100644 tests/networkxml2confdata/<wbr>leasetime-host.xml</div><div> create mode 100644 tests/networkxml2confdata/<wbr>leasetime-hours.conf</div><div> create mode 100644 tests/networkxml2confdata/<wbr>leasetime-hours.xml</div><div> create mode 100644 tests/networkxml2confdata/<wbr>leasetime-infinite.conf</div><div> create mode 100644 tests/networkxml2confdata/<wbr>leasetime-infinite.xml</div><div> create mode 100644 tests/networkxml2confdata/<wbr>leasetime-minutes.conf</div><div> create mode 100644 tests/networkxml2confdata/<wbr>leasetime-minutes.xml</div><div> create mode 100644 tests/networkxml2confdata/<wbr>leasetime-seconds.conf</div><div> create mode 100644 tests/networkxml2confdata/<wbr>leasetime-seconds.xml</div><div> create mode 100644 tests/networkxml2confdata/<wbr>leasetime.conf</div><div> create mode 100644 tests/networkxml2confdata/<wbr>leasetime.xml</div><div> create mode 100644 tests/networkxml2confdata/nat-<wbr>network-dns-srv-record-<wbr>minimal.hostsfile</div><div> create mode 100644 tests/networkxml2confdata/nat-<wbr>network-dns-srv-record.<wbr>hostsfile</div><div> create mode 100644 tests/networkxml2confdata/nat-<wbr>network-dns-txt-record.<wbr>hostsfile</div><div> create mode 100644 tests/networkxml2confdata/nat-<wbr>network-name-with-quotes.<wbr>hostsfile</div><div> create mode 100644 tests/networkxml2confdata/nat-<wbr>network.hostsfile</div><div><br></div><div>diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng</div><div>index 1b4f980..11fbe2b 100644</div><div>--- a/docs/schemas/basictypes.rng</div><div>+++ b/docs/schemas/basictypes.rng</div><div>@@ -518,4 +518,9 @@</div><div>     </element></div><div>   </define></div><div> </div><div>+  <define name="leaseTime"></div><div>+    <data type="string"></div><div>+      <param name="pattern">-?[0-9]*[smhd]?<wbr></param></div><div>+    </data></div><div>+  </define></div><div> </grammar></div><div>diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng</div><div>index 1a18e64..e6ddb63 100644</div><div>--- a/docs/schemas/network.rng</div><div>+++ b/docs/schemas/network.rng</div><div>@@ -340,6 +340,11 @@</div><div>               <!-- Define the range(s) of IP addresses that the DHCP</div><div>                    server should hand out --></div><div>               <element name="dhcp"></div><div>+                <optional></div><div>+                  <element name="leasetime"></div><div>+                    <ref name="leaseTime"/></div><div>+                  </element></div><div>+                </optional></div><div>                 <zeroOrMore></div><div>                   <element name="range"></div><div>                     <attribute name="start"><ref name="ipAddr"/></attribute></div><div>@@ -361,6 +366,9 @@</div><div>                       <attribute name="name"><text/></<wbr>attribute></div><div>                     </choice></div><div>                     <attribute name="ip"><ref name="ipAddr"/></attribute></div><div>+                    <optional></div><div>+                      <attribute name="leasetime"><ref name="leaseTime"/></attribute></div><div>+                    </optional></div><div>                   </element></div><div>                 </zeroOrMore></div><div>                 <optional></div><div>diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c</div><div>index aa39776..bcc4bbb 100644</div><div>--- a/src/conf/network_conf.c</div><div>+++ b/src/conf/network_conf.c</div><div>@@ -30,6 +30,8 @@</div><div> #include <fcntl.h></div><div> #include <string.h></div><div> #include <dirent.h></div><div>+#include <stdlib.h></div><div>+#include <inttypes.h></div><div> </div><div> #include "virerror.h"</div><div> #include "datatypes.h"</div><div>@@ -911,16 +913,83 @@ virSocketAddrRangeParseXML(<wbr>const char *networkName,</div><div>     return ret;</div><div> }</div><div> </div><div>+static int64_t</div><div>+virNetworkDHCPDefGetLeaseTime (xmlNodePtr node,</div><div>+                               xmlXPathContextPtr ctxt,</div><div>+                               const char* query,</div><div>+                               bool *error)</div><div>+{</div><div>+    int64_t multiplier = 1, result = -1;</div><div>+    char *leaseString;</div><div>+    xmlNodePtr save;</div><div>+    size_t len;</div><div>+</div><div>+    *error = 0;</div><div>+</div><div>+    save = ctxt->node;</div><div>+    ctxt->node = node;</div><div>+</div><div>+    leaseString = virXPathString (query, ctxt);</div><div>+</div><div>+    /* If value is not present we set the value to -2 */</div><div>+    if (leaseString == NULL) {</div><div>+        result = -2;</div><div>+        goto cleanup;</div><div>+    }</div><div>+</div><div>+    len = strlen (leaseString) - 1;</div><div>+</div><div>+    if (leaseString[len] == 'm')</div><div>+        multiplier = 60;</div><div>+    else if (leaseString[len] == 'h')</div><div>+        multiplier = 60 * 60;</div><div>+    else if (leaseString[len] == 'd')</div><div>+        multiplier = 60 * 60 * 24;</div><div>+</div><div>+    /* Remove the time unit suffix */</div><div>+    if (leaseString[len] < 48 || leaseString[len] > 57)</div><div>+        leaseString[len] = '\0';</div><div>+</div><div>+    errno = 0;</div><div>+    result = (int64_t) strtoll((const char*)leaseString, NULL, 10);</div><div>+</div><div>+    /* Report any errors parsing the string */</div><div>+    if (errno != 0) {</div><div>+        virReportError(VIR_ERR_XML_<wbr>ERROR,</div><div>+                       _("<leasetime> value could not be converted to a signed integer: %s"),</div><div>+                      leaseString);</div><div>+        *error = 1;</div><div>+        goto cleanup;</div><div>+    }</div><div>+</div><div>+    result = result * multiplier;</div><div>+</div><div>+    if (result > UINT32_MAX || result < -1) {</div><div>+        virReportError(VIR_ERR_XML_<wbr>ERROR,</div><div>+                       _("<leasetime> value cannot be greater than the equivalent of %" PRIo32 " seconds or less than -1: %" PRId64),</div><div>+                       UINT32_MAX, result);</div><div>+        *error = 1;</div><div>+    }</div><div>+</div><div>+cleanup:</div><div>+    VIR_FREE(leaseString);</div><div>+    ctxt->node = save;</div><div>+    return result;</div><div>+}</div><div>+</div><div> static int</div><div> <wbr>virNetworkDHCPHostDefParseXML(<wbr>const char *networkName,</div><div>                               virNetworkIPDefPtr def,</div><div>                               xmlNodePtr node,</div><div>+                              xmlXPathContextPtr ctxt,</div><div>                               virNetworkDHCPHostDefPtr host,</div><div>                               bool partialOkay)</div><div> {</div><div>     char *mac = NULL, *name = NULL, *ip = NULL, *id = NULL;</div><div>     virMacAddr addr;</div><div>     virSocketAddr inaddr;</div><div>+    int64_t leasetime;</div><div>+    bool error;</div><div>     int ret = -1;</div><div> </div><div>     mac = virXMLPropString(node, "mac");</div><div>@@ -1013,6 +1082,10 @@ virNetworkDHCPHostDefParseXML(<wbr>const char *networkName,</div><div>         }</div><div>     }</div><div> </div><div>+    leasetime = virNetworkDHCPDefGetLeaseTime (node, ctxt, "string(./@leasetime)", &error);</div><div>+    if (error)</div><div>+        goto cleanup;</div><div>+</div><div>     host->mac = mac;</div><div>     mac = NULL;</div><div>     host->id = id;</div><div>@@ -1021,6 +1094,7 @@ virNetworkDHCPHostDefParseXML(<wbr>const char *networkName,</div><div>     name = NULL;</div><div>     if (ip)</div><div>         host->ip = inaddr;</div><div>+    host->leasetime = leasetime;</div><div>     ret = 0;</div><div> </div><div>  cleanup:</div><div>@@ -1034,9 +1108,11 @@ virNetworkDHCPHostDefParseXML(<wbr>const char *networkName,</div><div> static int</div><div> virNetworkDHCPDefParseXML(<wbr>const char *networkName,</div><div>                           xmlNodePtr node,</div><div>+                          xmlXPathContextPtr ctxt,</div><div>                           virNetworkIPDefPtr def)</div><div> {</div><div>     int ret = -1;</div><div>+    bool error;</div><div>     xmlNodePtr cur;</div><div>     virSocketAddrRange range;</div><div>     virNetworkDHCPHostDef host;</div><div>@@ -1044,6 +1120,10 @@ virNetworkDHCPDefParseXML(<wbr>const char *networkName,</div><div>     memset(&range, 0, sizeof(range));</div><div>     memset(&host, 0, sizeof(host));</div><div> </div><div>+    def->leasetime = virNetworkDHCPDefGetLeaseTime (node, ctxt, "string(./leasetime/text())", &error);</div><div>+    if (error)</div><div>+        goto cleanup;</div><div>+</div><div>     cur = node->children;</div><div>     while (cur != NULL) {</div><div>         if (cur->type == XML_ELEMENT_NODE &&</div><div>@@ -1057,7 +1137,7 @@ virNetworkDHCPDefParseXML(<wbr>const char *networkName,</div><div>         } else if (cur->type == XML_ELEMENT_NODE &&</div><div>             xmlStrEqual(cur->name, BAD_CAST "host")) {</div><div> </div><div>-            if (<wbr>virNetworkDHCPHostDefParseXML(<wbr>networkName, def, cur,</div><div>+            if (<wbr>virNetworkDHCPHostDefParseXML(<wbr>networkName, def, cur, ctxt,</div><div>                                               &host, false) < 0)</div><div>                 goto cleanup;</div><div>             if (VIR_APPEND_ELEMENT(def-><wbr>hosts, def->nhosts, host) < 0)</div><div>@@ -1607,7 +1687,7 @@ virNetworkIPDefParseXML(const char *networkName,</div><div>     while (cur != NULL) {</div><div>         if (cur->type == XML_ELEMENT_NODE &&</div><div>             xmlStrEqual(cur->name, BAD_CAST "dhcp")) {</div><div>-            if (virNetworkDHCPDefParseXML(<wbr>networkName, cur, def) < 0)</div><div>+            if (virNetworkDHCPDefParseXML(<wbr>networkName, cur, ctxt, def) < 0)</div><div>                 goto cleanup;</div><div>         } else if (cur->type == XML_ELEMENT_NODE &&</div><div>                    xmlStrEqual(cur->name, BAD_CAST "tftp")) {</div><div>@@ -3659,7 +3739,7 @@ virNetworkDefUpdateIPDHCPHost(<wbr>virNetworkDefPtr def,</div><div>     if (!ipdef)</div><div>         goto cleanup;</div><div> </div><div>-    if (<wbr>virNetworkDHCPHostDefParseXML(<wbr>def->name, ipdef, ctxt->node,</div><div>+    if (<wbr>virNetworkDHCPHostDefParseXML(<wbr>def->name, ipdef, ctxt->node, ctxt,</div><div>                                       &host, partialOkay) < 0)</div><div>         goto cleanup;</div><div> </div><div>diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h</div><div>index 3b227db..df687df 100644</div><div>--- a/src/conf/network_conf.h</div><div>+++ b/src/conf/network_conf.h</div><div>@@ -96,6 +96,7 @@ struct _virNetworkDHCPHostDef {</div><div>     char *id;</div><div>     char *name;</div><div>     virSocketAddr ip;</div><div>+    int64_t leasetime;</div><div> };</div><div> </div><div> typedef struct _virNetworkDNSTxtDef virNetworkDNSTxtDef;</div><div>@@ -170,7 +171,8 @@ struct _virNetworkIPDef {</div><div>     char *tftproot;</div><div>     char *bootfile;</div><div>     virSocketAddr bootserver;</div><div>-   };</div><div>+    int64_t leasetime;</div><div>+};</div><div> </div><div> typedef struct _virNetworkForwardIfDef virNetworkForwardIfDef;</div><div> typedef virNetworkForwardIfDef *virNetworkForwardIfDefPtr;</div><div>diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms</div><div>index b88e903..84fb62e 100644</div><div>--- a/src/libvirt_private.syms</div><div>+++ b/src/libvirt_private.syms</div><div>@@ -1497,6 +1497,7 @@ dnsmasqCapsRefresh;</div><div> dnsmasqContextFree;</div><div> dnsmasqContextNew;</div><div> dnsmasqDelete;</div><div>+dnsmasqDhcpHostsToString;</div><div> dnsmasqReload;</div><div> dnsmasqSave;</div><div> </div><div>diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c</div><div>index 7b99aca..dccf743 100644</div><div>--- a/src/network/bridge_driver.c</div><div>+++ b/src/network/bridge_driver.c</div><div>@@ -41,6 +41,8 @@</div><div> #include <sys/ioctl.h></div><div> #include <net/if.h></div><div> #include <dirent.h></div><div>+#include <inttypes.h></div><div>+#include <stdint.h></div><div> #if HAVE_SYS_SYSCTL_H</div><div> # include <sys/sysctl.h></div><div> #endif</div><div>@@ -859,30 +861,6 @@ networkKillDaemon(pid_t pid, const char *daemonName, const char *networkName)</div><div>     return ret;</div><div> }</div><div> </div><div>-/* the following does not build a file, it builds a list</div><div>- * which is later saved into a file</div><div>- */</div><div>-</div><div>-static int</div><div>-<wbr>networkBuildDnsmasqDhcpHostsLi<wbr>st(dnsmasqContext *dctx,</div><div>-                                 virNetworkIPDefPtr ipdef)</div><div>-{</div><div>-    size_t i;</div><div>-    bool ipv6 = false;</div><div>-</div><div>-    if (VIR_SOCKET_ADDR_IS_FAMILY(&<wbr>ipdef->address, AF_INET6))</div><div>-        ipv6 = true;</div><div>-    for (i = 0; i < ipdef->nhosts; i++) {</div><div>-        virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);</div><div>-        if (VIR_SOCKET_ADDR_VALID(&host-><wbr>ip))</div><div>-            if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,</div><div>-                                   host->name, host->id, ipv6) < 0)</div><div>-                return -1;</div><div>-    }</div><div>-</div><div>-    return 0;</div><div>-}</div><div>-</div><div> static int</div><div> networkBuildDnsmasqHostsList(<wbr>dnsmasqContext *dctx,</div><div>                              virNetworkDNSDefPtr dnsdef)</div><div>@@ -903,11 +881,93 @@ networkBuildDnsmasqHostsList(<wbr>dnsmasqContext *dctx,</div><div>     return 0;</div><div> }</div><div> </div><div>+/* translates the leasetime value into a dnsmasq configuration string for dhcp-range/host */</div><div>+static char *</div><div>+<wbr>networkDnsmasqConfLeaseValueTo<wbr>String (int64_t leasetime)</div><div>+{</div><div>+    char *result = NULL;</div><div>+    virBuffer leasebuf = VIR_BUFFER_INITIALIZER;</div><div>+</div><div>+    /* Leasetime parameter set on the XML */</div><div>+    /* Less than -1 means there was no value set */</div><div>+    if (leasetime < -1) {</div><div>+        virBufferAsprintf(&leasebuf, "%s", "");</div><div>+    }</div><div>+    /* -1 means no expiration */</div><div>+    else if (leasetime == -1)</div><div>+        virBufferAsprintf(&leasebuf, ",infinite");</div><div>+    /* Minimum expiry value is 120 */</div><div>+    /* TODO: Discuss if we should up as we do here or just forward whatever value to dnsmasq */</div><div>+    else if (leasetime < 120)</div><div>+        virBufferAsprintf(&leasebuf, ",120");</div><div>+    /* DHCP value for lease time is a unsigned four octect integer */</div><div>+    else if (leasetime <= UINT32_MAX)</div><div>+        virBufferAsprintf(&leasebuf, ",%" PRId64, leasetime);</div><div>+    /* TODO: Discuss the use of "deprecated" for ipv6*/</div><div>+    /* TODO: Discuss what is the default value that we want as dnsmasq's is 1 hour */</div><div>+    /* TODO: Discuss what to do if value exceeds maximum, use default value for now */</div><div>+    else {</div><div>+        virBufferAsprintf(&leasebuf, "%s", "");</div><div>+    }</div><div>+</div><div>+    result = virBufferContentAndReset(&<wbr>leasebuf);</div><div>+    virBufferFreeAndReset (&leasebuf);</div><div>+</div><div>+    return result;</div><div>+}</div><div>+</div><div>+/* the following does not build a file, it builds a list</div><div>+ * which is later saved into a file</div><div>+ */</div><div>+</div><div>+static int</div><div>+<wbr>networkBuildDnsmasqDhcpHostsLi<wbr>st(dnsmasqContext *dctx,</div><div>+                                 virNetworkIPDefPtr ipdef)</div><div>+{</div><div>+    int ret = -1;</div><div>+    size_t i;</div><div>+    bool ipv6 = false;</div><div>+    char *leasetime = networkDnsmasqConfLeaseValueTo<wbr>String(ipdef->leasetime);</div><div>+</div><div>+    if (!leasetime)</div><div>+        goto cleanup;</div><div>+</div><div>+    if (VIR_SOCKET_ADDR_IS_FAMILY(&<wbr>ipdef->address, AF_INET6))</div><div>+        ipv6 = true;</div><div>+    for (i = 0; i < ipdef->nhosts; i++) {</div><div>+        virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);</div><div>+        if (VIR_SOCKET_ADDR_VALID(&host-><wbr>ip)) {</div><div>+            /* If the host has its own leasetime we get its specific string */</div><div>+            if (host->leasetime > -2) {</div><div>+                char *hostlease = networkDnsmasqConfLeaseValueTo<wbr>String(host->leasetime);</div><div>+                if (!hostlease)</div><div>+                    goto cleanup;</div><div>+                if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,</div><div>+                                       host->name, host->id, hostlease, ipv6) < 0) {</div><div>+                    VIR_FREE(hostlease);</div><div>+                    goto cleanup;</div><div>+                }</div><div>+                VIR_FREE(hostlease);</div><div>+            } else {</div><div>+            /* Otherwise we use the leasetime from dhcp */</div><div>+                if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,</div><div>+                                       host->name, host->id, leasetime, ipv6) < 0)</div><div>+                    goto cleanup;</div><div>+            }</div><div>+        }</div><div>+    }</div><div>+</div><div>+    ret = 0;</div><div>+cleanup:</div><div>+    VIR_FREE(leasetime);</div><div>+    return ret;</div><div>+}</div><div> </div><div> int</div><div> networkDnsmasqConfContents(<wbr>virNetworkObjPtr network,</div><div>                            const char *pidfile,</div><div>                            char **configstr,</div><div>+                           char **hostsfilestr,</div><div>                            dnsmasqContext *dctx,</div><div>                            dnsmasqCapsPtr caps ATTRIBUTE_UNUSED)</div><div> {</div><div>@@ -1213,6 +1273,7 @@ networkDnsmasqConfContents(<wbr>virNetworkObjPtr network,</div><div>         }</div><div>         for (r = 0; r < ipdef->nranges; r++) {</div><div>             int thisRange;</div><div>+            char *leasestr;</div><div> </div><div>             if (!(saddr = virSocketAddrFormat(&ipdef-><wbr>ranges[r].start)) ||</div><div>                 !(eaddr = virSocketAddrFormat(&ipdef-><wbr>ranges[r].end)))</div><div>@@ -1220,12 +1281,22 @@ networkDnsmasqConfContents(<wbr>virNetworkObjPtr network,</div><div> </div><div>             virBufferAsprintf(&configbuf, "dhcp-range=%s,%s",</div><div>                               saddr, eaddr);</div><div>-            if (VIR_SOCKET_ADDR_IS_FAMILY(&<wbr>ipdef->address, AF_INET6))</div><div>+</div><div>+            /* Add ipv6 prefix length parameter if needed */</div><div>+            if (ipdef == ipv6def)</div><div>                 virBufferAsprintf(&configbuf, ",%d", prefix);</div><div>+</div><div>+            leasestr = networkDnsmasqConfLeaseValueTo<wbr>String (ipdef->leasetime);</div><div>+            if (!leasestr)</div><div>+                goto cleanup;</div><div>+            virBufferAsprintf(&configbuf, "%s", leasestr);</div><div>+</div><div>+            /* Add the newline */</div><div>             virBufferAddLit(&configbuf, "\n");</div><div> </div><div>             VIR_FREE(saddr);</div><div>             VIR_FREE(eaddr);</div><div>+            VIR_FREE(leasestr);</div><div>             thisRange = virSocketAddrGetRange(&ipdef-><wbr>ranges[r].start,</div><div>                                               &ipdef->ranges[r].end,</div><div>                                               &ipdef->address,</div><div>@@ -1256,6 +1327,15 @@ networkDnsmasqConfContents(<wbr>virNetworkObjPtr network,</div><div>         if (<wbr>networkBuildDnsmasqDhcpHostsLi<wbr>st(dctx, ipdef) < 0)</div><div>             goto cleanup;</div><div> </div><div>+        /* Return the contents of the hostsfile if requested */</div><div>+        if (hostsfilestr) {</div><div>+            *hostsfilestr = dnsmasqDhcpHostsToString (dctx->hostsfile->hosts,</div><div>+                                                      dctx->hostsfile->nhosts);</div><div>+</div><div>+            if (!hostsfilestr)</div><div>+                goto cleanup;</div><div>+        }</div><div>+</div><div>         /* Note: the following is IPv4 only */</div><div>         if (VIR_SOCKET_ADDR_IS_FAMILY(&<wbr>ipdef->address, AF_INET)) {</div><div>             if (ipdef->nranges || ipdef->nhosts)</div><div>@@ -1355,7 +1435,7 @@ networkBuildDhcpDaemonCommandL<wbr>ine(virNetworkDriverStatePtr driver,</div><div> </div><div>     network->dnsmasqPid = -1;</div><div> </div><div>-    if (networkDnsmasqConfContents(<wbr>network, pidfile, &configstr,</div><div>+    if (networkDnsmasqConfContents(<wbr>network, pidfile, &configstr, NULL,</div><div>                                    dctx, dnsmasq_caps) < 0)</div><div>         goto cleanup;</div><div>     if (!configstr)</div><div>diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h</div><div>index ff7f921..c653c50 100644</div><div>--- a/src/network/bridge_driver.h</div><div>+++ b/src/network/bridge_driver.h</div><div>@@ -53,6 +53,7 @@ int networkGetActualType(<wbr>virDomainNetDefPtr iface)</div><div> int networkDnsmasqConfContents(<wbr>virNetworkObjPtr network,</div><div>                         const char *pidfile,</div><div>                         char **configstr,</div><div>+                        char **hostsfilestr,</div><div>                         dnsmasqContext *dctx,</div><div>                         dnsmasqCapsPtr caps);</div><div> </div><div>diff --git a/src/util/virdnsmasq.c b/src/util/virdnsmasq.c</div><div>index 1b78c1f..94c9a3b 100644</div><div>--- a/src/util/virdnsmasq.c</div><div>+++ b/src/util/virdnsmasq.c</div><div>@@ -308,52 +308,47 @@ hostsfileAdd(dnsmasqHostsfile *hostsfile,</div><div>              virSocketAddr *ip,</div><div>              const char *name,</div><div>              const char *id,</div><div>+             const char *leasetime,</div><div>              bool ipv6)</div><div> {</div><div>+    int ret = -1;</div><div>     char *ipstr = NULL;</div><div>+    virBuffer hostbuf = VIR_BUFFER_INITIALIZER;</div><div>+</div><div>     if (VIR_REALLOC_N(hostsfile-><wbr>hosts, hostsfile->nhosts + 1) < 0)</div><div>         goto error;</div><div> </div><div>     if (!(ipstr = virSocketAddrFormat(ip)))</div><div>-        return -1;</div><div>+        goto error;</div><div> </div><div>     /* the first test determines if it is a dhcpv6 host */</div><div>     if (ipv6) {</div><div>-        if (name && id) {</div><div>-            if (virAsprintf(&hostsfile-><wbr>hosts[hostsfile->nhosts].host,</div><div>-                            "id:%s,%s,[%s]", id, name, ipstr) < 0)</div><div>-                goto error;</div><div>-        } else if (name && !id) {</div><div>-            if (virAsprintf(&hostsfile-><wbr>hosts[hostsfile->nhosts].host,</div><div>-                            "%s,[%s]", name, ipstr) < 0)</div><div>-                goto error;</div><div>-        } else if (!name && id) {</div><div>-            if (virAsprintf(&hostsfile-><wbr>hosts[hostsfile->nhosts].host,</div><div>-                            "id:%s,[%s]", id, ipstr) < 0)</div><div>-                goto error;</div><div>-        }</div><div>+        if (name && id)</div><div>+            virBufferAsprintf(&hostbuf, "id:%s,%s,[%s]", id, name, ipstr);</div><div>+        else if (name && !id)</div><div>+            virBufferAsprintf(&hostbuf, "%s,[%s]", name, ipstr);</div><div>+        else if (!name && id)</div><div>+            virBufferAsprintf(&hostbuf, "id:%s,[%s]", id, ipstr);</div><div>     } else if (name && mac) {</div><div>-        if (virAsprintf(&hostsfile-><wbr>hosts[hostsfile->nhosts].host, "%s,%s,%s",</div><div>-                        mac, ipstr, name) < 0)</div><div>-            goto error;</div><div>+        virBufferAsprintf(&hostbuf, "%s,%s,%s", mac, ipstr, name);</div><div>     } else if (name && !mac) {</div><div>-        if (virAsprintf(&hostsfile-><wbr>hosts[hostsfile->nhosts].host, "%s,%s",</div><div>-                        name, ipstr) < 0)</div><div>-            goto error;</div><div>+        virBufferAsprintf(&hostbuf, "%s,%s", name, ipstr);</div><div>     } else {</div><div>-        if (virAsprintf(&hostsfile-><wbr>hosts[hostsfile->nhosts].host, "%s,%s",</div><div>-                        mac, ipstr) < 0)</div><div>-            goto error;</div><div>+        virBufferAsprintf(&hostbuf, "%s,%s", mac, ipstr);</div><div>     }</div><div>-    VIR_FREE(ipstr);</div><div> </div><div>-    hostsfile->nhosts++;</div><div>+    /* The leasetime string already includes comma if there's any value at all */</div><div>+    virBufferAsprintf(&hostbuf, "%s", leasetime);</div><div> </div><div>-    return 0;</div><div>+    if (!(hostsfile->hosts[hostsfile-<wbr>>nhosts].host = virBufferContentAndReset (&hostbuf)))</div><div>+      goto error;</div><div> </div><div>+    hostsfile->nhosts++;</div><div>+    ret = 0;</div><div>  error:</div><div>+    virBufferFreeAndReset(&<wbr>hostbuf);</div><div>     VIR_FREE(ipstr);</div><div>-    return -1;</div><div>+    return ret;</div><div> }</div><div> </div><div> static dnsmasqHostsfile *</div><div>@@ -391,10 +386,9 @@ hostsfileWrite(const char *path,</div><div>                dnsmasqDhcpHost *hosts,</div><div>                unsigned int nhosts)</div><div> {</div><div>-    char *tmp;</div><div>+    char *tmp, *content = NULL;</div><div>     FILE *f;</div><div>     bool istmp = true;</div><div>-    size_t i;</div><div>     int rc = 0;</div><div> </div><div>     /* even if there are 0 hosts, create a 0 length file, to allow</div><div>@@ -412,17 +406,21 @@ hostsfileWrite(const char *path,</div><div>         }</div><div>     }</div><div> </div><div>-    for (i = 0; i < nhosts; i++) {</div><div>-        if (fputs(hosts[i].host, f) == EOF || fputc('\n', f) == EOF) {</div><div>-            rc = -errno;</div><div>-            VIR_FORCE_FCLOSE(f);</div><div>+    if (!(content = dnsmasqDhcpHostsToString(<wbr>hosts, nhosts))) {</div><div>+        rc = -ENOMEM;</div><div>+        goto cleanup;</div><div>+    }</div><div> </div><div>-            if (istmp)</div><div>-                unlink(tmp);</div><div>+    if (fputs(content, f) == EOF) {</div><div>+        rc = -errno;</div><div>+        VIR_FORCE_FCLOSE(f);</div><div>+</div><div>+        if (istmp)</div><div>+            unlink(tmp);</div><div>+</div><div>+        goto cleanup;</div><div>+     }</div><div> </div><div>-            goto cleanup;</div><div>-        }</div><div>-    }</div><div> </div><div>     if (VIR_FCLOSE(f) == EOF) {</div><div>         rc = -errno;</div><div>@@ -436,6 +434,7 @@ hostsfileWrite(const char *path,</div><div>     }</div><div> </div><div>  cleanup:</div><div>+    VIR_FREE(content);</div><div>     VIR_FREE(tmp);</div><div> </div><div>     return rc;</div><div>@@ -524,9 +523,10 @@ dnsmasqAddDhcpHost(<wbr>dnsmasqContext *ctx,</div><div>                    virSocketAddr *ip,</div><div>                    const char *name,</div><div>                    const char *id,</div><div>+                   const char *leasetime,</div><div>                    bool ipv6)</div><div> {</div><div>-    return hostsfileAdd(ctx->hostsfile, mac, ip, name, id, ipv6);</div><div>+    return hostsfileAdd(ctx->hostsfile, mac, ip, name, id, leasetime, ipv6);</div><div> }</div><div> </div><div> /*</div><div>@@ -892,3 +892,31 @@ dnsmasqCapsGet(dnsmasqCapsPtr caps, dnsmasqCapsFlags flag)</div><div> </div><div>     return caps && virBitmapIsBitSet(caps->flags, flag);</div><div> }</div><div>+</div><div>+/** dnsmasqDhcpHostsToString:</div><div>+ *</div><div>+ *   Turns a vector of dnsmasqDhcpHost into the string that is ought to be</div><div>+ *   stored in the hostsfile, this functionality is split to make hostsfiles</div><div>+ *   testable. Returs NULL if nhosts is 0.</div><div>+ */</div><div>+char *</div><div>+dnsmasqDhcpHostsToString (dnsmasqDhcpHost *hosts,</div><div>+                          unsigned int nhosts)</div><div>+{</div><div>+    int i;</div><div>+    char *result = NULL;</div><div>+    virBuffer hostsfilebuf = VIR_BUFFER_INITIALIZER;</div><div>+</div><div>+    if (nhosts == 0)</div><div>+       goto cleanup;</div><div>+</div><div>+    for (i = 0; i < nhosts; i++) {</div><div>+        virBufferAsprintf(&<wbr>hostsfilebuf, "%s\n", hosts[i].host);</div><div>+    }</div><div>+</div><div>+    result = virBufferContentAndReset(&<wbr>hostsfilebuf);</div><div>+</div><div>+cleanup:</div><div>+    virBufferFreeAndReset(&<wbr>hostsfilebuf);</div><div>+    return result;</div><div>+}</div><div>diff --git a/src/util/virdnsmasq.h b/src/util/virdnsmasq.h</div><div>index f47bea3..1795bc8 100644</div><div>--- a/src/util/virdnsmasq.h</div><div>+++ b/src/util/virdnsmasq.h</div><div>@@ -88,6 +88,7 @@ int              dnsmasqAddDhcpHost(<wbr>dnsmasqContext *ctx,</div><div>                                     virSocketAddr *ip,</div><div>                                     const char *name,</div><div>                                     const char *id,</div><div>+                                    const char *leastime,</div><div>                                     bool ipv6);</div><div> int              dnsmasqAddHost(dnsmasqContext *ctx,</div><div>                                 virSocketAddr *ip,</div><div>@@ -105,6 +106,7 @@ int dnsmasqCapsRefresh(<wbr>dnsmasqCapsPtr *caps, const char *binaryPath);</div><div> bool dnsmasqCapsGet(dnsmasqCapsPtr caps, dnsmasqCapsFlags flag);</div><div> const char *dnsmasqCapsGetBinaryPath(<wbr>dnsmasqCapsPtr caps);</div><div> unsigned long dnsmasqCapsGetVersion(<wbr>dnsmasqCapsPtr caps);</div><div>+char *dnsmasqDhcpHostsToString(<wbr>dnsmasqDhcpHost *hosts, unsigned int nhosts);</div><div> </div><div> # define DNSMASQ_DHCPv6_MAJOR_REQD 2</div><div> # define DNSMASQ_DHCPv6_MINOR_REQD 64</div><div>diff --git a/tests/networkxml2confdata/<wbr>dhcp6-nat-network.hostsfile b/tests/networkxml2confdata/<wbr>dhcp6-nat-network.hostsfile</div><div>new file mode 100644</div><div>index 0000000..de659b9</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>dhcp6-nat-network.hostsfile</div><div>@@ -0,0 +1,7 @@</div><div>+00:16:3e:77:e2:ed,192.168.<wbr>122.10,<a href="http://a.example.com/" target="_blank">a.example.com</a></div><div>+00:16:3e:3e:a9:1a,192.168.<wbr>122.11,<a href="http://b.example.com/" target="_blank">b.example.com</a></div><div>+id:0:4:7e:7d:f0:7d:a8:bc:c5:<wbr>d2:13:32:11:ed:16:ea:84:63,[<wbr>2001:db8:ac10:fd01::1:20]</div><div>+paul,[2001:db8:ac10:fd01::1:<wbr>21]</div><div>+id:0:3:0:1:0:16:3e:11:22:33,<a href="http://peter.xyz/" target="_blank">p<wbr>eter.xyz</a>,[2001:db8:ac10:fd01::<wbr>1:22]</div><div>+id:0:3:0:1:0:16:3e:44:55:33,[<wbr>2001:db8:ac10:fd01::1:23]</div><div>+id:0:1:0:1:18:aa:62:fe:0:16:<wbr>3e:44:55:66,badbob,[2001:db8:<wbr>ac10:fd01::1:24]</div><div>diff --git a/tests/networkxml2confdata/<wbr>dhcp6-network.hostsfile b/tests/networkxml2confdata/<wbr>dhcp6-network.hostsfile</div><div>new file mode 100644</div><div>index 0000000..9dfb172</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>dhcp6-network.hostsfile</div><div>@@ -0,0 +1,5 @@</div><div>+id:0:4:7e:7d:f0:7d:a8:bc:c5:<wbr>d2:13:32:11:ed:16:ea:84:63,[<wbr>2001:db8:ac10:fd01::1:20]</div><div>+paul,[2001:db8:ac10:fd01::1:<wbr>21]</div><div>+id:0:3:0:1:0:16:3e:11:22:33,<a href="http://peter.xyz/" target="_blank">p<wbr>eter.xyz</a>,[2001:db8:ac10:fd01::<wbr>1:22]</div><div>+id:0:3:0:1:0:16:3e:44:55:33,[<wbr>2001:db8:ac10:fd01::1:23]</div><div>+id:0:1:0:1:18:aa:62:fe:0:16:<wbr>3e:44:55:66,badbob,[2001:db8:<wbr>ac10:fd01::1:24]</div><div>diff --git a/tests/networkxml2confdata/<wbr>dhcp6host-routed-network.<wbr>hostsfile b/tests/networkxml2confdata/<wbr>dhcp6host-routed-network.<wbr>hostsfile</div><div>new file mode 100644</div><div>index 0000000..de659b9</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>dhcp6host-routed-network.<wbr>hostsfile</div><div>@@ -0,0 +1,7 @@</div><div>+00:16:3e:77:e2:ed,192.168.<wbr>122.10,<a href="http://a.example.com/" target="_blank">a.example.com</a></div><div>+00:16:3e:3e:a9:1a,192.168.<wbr>122.11,<a href="http://b.example.com/" target="_blank">b.example.com</a></div><div>+id:0:4:7e:7d:f0:7d:a8:bc:c5:<wbr>d2:13:32:11:ed:16:ea:84:63,[<wbr>2001:db8:ac10:fd01::1:20]</div><div>+paul,[2001:db8:ac10:fd01::1:<wbr>21]</div><div>+id:0:3:0:1:0:16:3e:11:22:33,<a href="http://peter.xyz/" target="_blank">p<wbr>eter.xyz</a>,[2001:db8:ac10:fd01::<wbr>1:22]</div><div>+id:0:3:0:1:0:16:3e:44:55:33,[<wbr>2001:db8:ac10:fd01::1:23]</div><div>+id:0:1:0:1:18:aa:62:fe:0:16:<wbr>3e:44:55:66,badbob,[2001:db8:<wbr>ac10:fd01::1:24]</div><div>diff --git a/tests/networkxml2confdata/<wbr>leasetime-days.conf b/tests/networkxml2confdata/<wbr>leasetime-days.conf</div><div>new file mode 100644</div><div>index 0000000..9501e2f</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>leasetime-days.conf</div><div>@@ -0,0 +1,17 @@</div><div>+##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE</div><div>+##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:</div><div>+##    virsh net-edit default</div><div>+## or other application using the libvirt API.</div><div>+##</div><div>+## dnsmasq conf file created by libvirt</div><div>+strict-order</div><div>+except-interface=lo</div><div>+bind-dynamic</div><div>+interface=virbr0</div><div>+dhcp-range=192.168.122.2,192.<wbr>168.122.254,86400</div><div>+dhcp-no-override</div><div>+dhcp-range=2001:db8:ac10:<wbr>fd01::1:10,2001:db8:ac10:fd01:<wbr>:1:ff,64,86400</div><div>+dhcp-lease-max=493</div><div>+dhcp-hostsfile=/var/lib/<wbr>libvirt/dnsmasq/default.<wbr>hostsfile</div><div>+addn-hosts=/var/lib/libvirt/<wbr>dnsmasq/default.addnhosts</div><div>+enable-ra</div><div>diff --git a/tests/networkxml2confdata/<wbr>leasetime-days.xml b/tests/networkxml2confdata/<wbr>leasetime-days.xml</div><div>new file mode 100644</div><div>index 0000000..1a507d5</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>leasetime-days.xml</div><div>@@ -0,0 +1,18 @@</div><div>+<network></div><div>+  <name>default</name></div><div>+  <uuid>81ff0d90-c91e-6742-<wbr>64da-4a736edb9a9b</uuid></div><div>+  <forward dev='eth1' mode='nat'/></div><div>+  <bridge name='virbr0' stp='on' delay='0'/></div><div>+  <ip address='192.168.122.1' netmask='255.255.255.0'></div><div>+    <dhcp></div><div>+      <leasetime>1d</leasetime></div><div>+      <range start='192.168.122.2' end='192.168.122.254'/></div><div>+    </dhcp></div><div>+  </ip></div><div>+  <ip family='ipv6' address='2001:db8:ac10:fd01::<wbr>1' prefix='64'></div><div>+    <dhcp></div><div>+      <leasetime>1d</leasetime></div><div>+      <range start='2001:db8:ac10:fd01::1:<wbr>10' end='2001:db8:ac10:fd01::1:ff'<wbr>/></div><div>+    </dhcp></div><div>+  </ip></div><div>+</network></div><div>diff --git a/tests/networkxml2confdata/<wbr>leasetime-host.conf b/tests/networkxml2confdata/<wbr>leasetime-host.conf</div><div>new file mode 100644</div><div>index 0000000..7bd2054</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>leasetime-host.conf</div><div>@@ -0,0 +1,16 @@</div><div>+##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE</div><div>+##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:</div><div>+##    virsh net-edit default</div><div>+## or other application using the libvirt API.</div><div>+##</div><div>+## dnsmasq conf file created by libvirt</div><div>+strict-order</div><div>+except-interface=lo</div><div>+bind-dynamic</div><div>+interface=virbr0</div><div>+srv-host=_name._tcp</div><div>+dhcp-range=192.168.122.2,192.<wbr>168.122.254</div><div>+dhcp-no-override</div><div>+dhcp-lease-max=253</div><div>+dhcp-hostsfile=/var/lib/<wbr>libvirt/dnsmasq/default.<wbr>hostsfile</div><div>+addn-hosts=/var/lib/libvirt/<wbr>dnsmasq/default.addnhosts</div><div>diff --git a/tests/networkxml2confdata/<wbr>leasetime-host.hostsfile b/tests/networkxml2confdata/<wbr>leasetime-host.hostsfile</div><div>new file mode 100644</div><div>index 0000000..fd20ca2</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>leasetime-host.hostsfile</div><div>@@ -0,0 +1,6 @@</div><div>+00:16:3e:3e:a9:01,192.168.<wbr>122.11,<a href="http://a.example.com/" target="_blank">a.example.com</a>,3600</div><div>+00:16:3e:3e:a9:02,192.168.<wbr>122.12,<a href="http://b.example.com/" target="_blank">b.example.com</a>,3600</div><div>+00:16:3e:3e:a9:03,192.168.<wbr>122.13,<a href="http://c.example.com/" target="_blank">c.example.com</a>,3600</div><div>+00:16:3e:3e:a9:04,192.168.<wbr>122.14,<a href="http://d.example.com/" target="_blank">d.example.com</a>,86400</div><div>+00:16:3e:3e:a9:05,192.168.<wbr>122.15,<a href="http://e.example.com/" target="_blank">e.example.com</a>,3600</div><div>+00:16:3e:3e:a9:06,192.168.<wbr>122.16,<a href="http://f.example.com/" target="_blank">f.example.com</a>,infinite</div><div>diff --git a/tests/networkxml2confdata/<wbr>leasetime-host.xml b/tests/networkxml2confdata/<wbr>leasetime-host.xml</div><div>new file mode 100644</div><div>index 0000000..276d3e5</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>leasetime-host.xml</div><div>@@ -0,0 +1,22 @@</div><div>+<network></div><div>+  <name>default</name></div><div>+  <uuid>81ff0d90-c91e-6742-<wbr>64da-4a736edb9a9b</uuid></div><div>+  <forward dev='eth1' mode='nat'></div><div>+    <interface dev='eth1'/></div><div>+  </forward></div><div>+  <bridge name='virbr0' stp='on' delay='0'/></div><div>+  <dns></div><div>+    <srv service='name' protocol='tcp'/></div><div>+  </dns></div><div>+  <ip address='192.168.122.1' netmask='255.255.255.0'></div><div>+    <dhcp></div><div>+      <range start='192.168.122.2' end='192.168.122.254'/></div><div>+      <host mac='00:16:3e:3e:a9:1a' name='<a href="http://a.example.com/" target="_blank">a.example.com</a>' ip='192.168.122.11' leasetime="3600s"/></div><div>+      <host mac='00:16:3e:3e:a9:1b' name='<a href="http://b.example.com/" target="_blank">b.example.com</a>' ip='192.168.122.12' leasetime="60m"/></div><div>+      <host mac='00:16:3e:3e:a9:1c' name='<a href="http://c.example.com/" target="_blank">c.example.com</a>' ip='192.168.122.13' leasetime="1h"/></div><div>+      <host mac='00:16:3e:3e:a9:1d' name='<a href="http://d.example.com/" target="_blank">d.example.com</a>' ip='192.168.122.14' leasetime="1d"/></div><div>+      <host mac='00:16:3e:3e:a9:1e' name='<a href="http://e.example.com/" target="_blank">e.example.com</a>' ip='192.168.122.15' leasetime="3600"/></div><div>+      <host mac='00:16:3e:3e:a9:1f' name='<a href="http://f.example.com/" target="_blank">f.example.com</a>' ip='192.168.122.16' leasetime="-1"/></div><div>+    </dhcp></div><div>+  </ip></div><div>+</network></div><div>diff --git a/tests/networkxml2confdata/<wbr>leasetime-hours.conf b/tests/networkxml2confdata/<wbr>leasetime-hours.conf</div><div>new file mode 100644</div><div>index 0000000..021a769</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>leasetime-hours.conf</div><div>@@ -0,0 +1,17 @@</div><div>+##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE</div><div>+##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:</div><div>+##    virsh net-edit default</div><div>+## or other application using the libvirt API.</div><div>+##</div><div>+## dnsmasq conf file created by libvirt</div><div>+strict-order</div><div>+except-interface=lo</div><div>+bind-dynamic</div><div>+interface=virbr0</div><div>+dhcp-range=192.168.122.2,192.<wbr>168.122.254,3600</div><div>+dhcp-no-override</div><div>+dhcp-range=2001:db8:ac10:<wbr>fd01::1:10,2001:db8:ac10:fd01:<wbr>:1:ff,64,3600</div><div>+dhcp-lease-max=493</div><div>+dhcp-hostsfile=/var/lib/<wbr>libvirt/dnsmasq/default.<wbr>hostsfile</div><div>+addn-hosts=/var/lib/libvirt/<wbr>dnsmasq/default.addnhosts</div><div>+enable-ra</div><div>diff --git a/tests/networkxml2confdata/<wbr>leasetime-hours.xml b/tests/networkxml2confdata/<wbr>leasetime-hours.xml</div><div>new file mode 100644</div><div>index 0000000..36dc600</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>leasetime-hours.xml</div><div>@@ -0,0 +1,18 @@</div><div>+<network></div><div>+  <name>default</name></div><div>+  <uuid>81ff0d90-c91e-6742-<wbr>64da-4a736edb9a9b</uuid></div><div>+  <forward dev='eth1' mode='nat'/></div><div>+  <bridge name='virbr0' stp='on' delay='0'/></div><div>+  <ip address='192.168.122.1' netmask='255.255.255.0'></div><div>+    <dhcp></div><div>+      <leasetime>1h</leasetime></div><div>+      <range start='192.168.122.2' end='192.168.122.254'/></div><div>+    </dhcp></div><div>+  </ip></div><div>+  <ip family='ipv6' address='2001:db8:ac10:fd01::<wbr>1' prefix='64'></div><div>+    <dhcp></div><div>+      <leasetime>1h</leasetime></div><div>+      <range start='2001:db8:ac10:fd01::1:<wbr>10' end='2001:db8:ac10:fd01::1:ff'<wbr>/></div><div>+    </dhcp></div><div>+  </ip></div><div>+</network></div><div>diff --git a/tests/networkxml2confdata/<wbr>leasetime-infinite.conf b/tests/networkxml2confdata/<wbr>leasetime-infinite.conf</div><div>new file mode 100644</div><div>index 0000000..cc21135</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>leasetime-infinite.conf</div><div>@@ -0,0 +1,17 @@</div><div>+##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE</div><div>+##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:</div><div>+##    virsh net-edit default</div><div>+## or other application using the libvirt API.</div><div>+##</div><div>+## dnsmasq conf file created by libvirt</div><div>+strict-order</div><div>+except-interface=lo</div><div>+bind-dynamic</div><div>+interface=virbr0</div><div>+dhcp-range=192.168.122.2,192.<wbr>168.122.254,infinite</div><div>+dhcp-no-override</div><div>+dhcp-range=2001:db8:ac10:<wbr>fd01::1:10,2001:db8:ac10:fd01:<wbr>:1:ff,64,infinite</div><div>+dhcp-lease-max=493</div><div>+dhcp-hostsfile=/var/lib/<wbr>libvirt/dnsmasq/default.<wbr>hostsfile</div><div>+addn-hosts=/var/lib/libvirt/<wbr>dnsmasq/default.addnhosts</div><div>+enable-ra</div><div>diff --git a/tests/networkxml2confdata/<wbr>leasetime-infinite.xml b/tests/networkxml2confdata/<wbr>leasetime-infinite.xml</div><div>new file mode 100644</div><div>index 0000000..bc8740e</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>leasetime-infinite.xml</div><div>@@ -0,0 +1,18 @@</div><div>+<network></div><div>+  <name>default</name></div><div>+  <uuid>81ff0d90-c91e-6742-<wbr>64da-4a736edb9a9b</uuid></div><div>+  <forward dev='eth1' mode='nat'/></div><div>+  <bridge name='virbr0' stp='on' delay='0'/></div><div>+  <ip address='192.168.122.1' netmask='255.255.255.0'></div><div>+    <dhcp></div><div>+      <leasetime>-1</leasetime></div><div>+      <range start='192.168.122.2' end='192.168.122.254'/></div><div>+    </dhcp></div><div>+  </ip></div><div>+  <ip family='ipv6' address='2001:db8:ac10:fd01::<wbr>1' prefix='64'></div><div>+    <dhcp></div><div>+      <leasetime>-1</leasetime></div><div>+      <range start='2001:db8:ac10:fd01::1:<wbr>10' end='2001:db8:ac10:fd01::1:ff'<wbr>/></div><div>+    </dhcp></div><div>+  </ip></div><div>+</network></div><div>diff --git a/tests/networkxml2confdata/<wbr>leasetime-minutes.conf b/tests/networkxml2confdata/<wbr>leasetime-minutes.conf</div><div>new file mode 100644</div><div>index 0000000..db68895</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>leasetime-minutes.conf</div><div>@@ -0,0 +1,17 @@</div><div>+##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE</div><div>+##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:</div><div>+##    virsh net-edit default</div><div>+## or other application using the libvirt API.</div><div>+##</div><div>+## dnsmasq conf file created by libvirt</div><div>+strict-order</div><div>+except-interface=lo</div><div>+bind-dynamic</div><div>+interface=virbr0</div><div>+dhcp-range=192.168.122.2,192.<wbr>168.122.254,300</div><div>+dhcp-no-override</div><div>+dhcp-range=2001:db8:ac10:<wbr>fd01::1:10,2001:db8:ac10:fd01:<wbr>:1:ff,64,300</div><div>+dhcp-lease-max=493</div><div>+dhcp-hostsfile=/var/lib/<wbr>libvirt/dnsmasq/default.<wbr>hostsfile</div><div>+addn-hosts=/var/lib/libvirt/<wbr>dnsmasq/default.addnhosts</div><div>+enable-ra</div><div>diff --git a/tests/networkxml2confdata/<wbr>leasetime-minutes.xml b/tests/networkxml2confdata/<wbr>leasetime-minutes.xml</div><div>new file mode 100644</div><div>index 0000000..7c1df25</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>leasetime-minutes.xml</div><div>@@ -0,0 +1,18 @@</div><div>+<network></div><div>+  <name>default</name></div><div>+  <uuid>81ff0d90-c91e-6742-<wbr>64da-4a736edb9a9b</uuid></div><div>+  <forward dev='eth1' mode='nat'/></div><div>+  <bridge name='virbr0' stp='on' delay='0'/></div><div>+  <ip address='192.168.122.1' netmask='255.255.255.0'></div><div>+    <dhcp></div><div>+      <leasetime>5m</leasetime></div><div>+      <range start='192.168.122.2' end='192.168.122.254'/></div><div>+    </dhcp></div><div>+  </ip></div><div>+  <ip family='ipv6' address='2001:db8:ac10:fd01::<wbr>1' prefix='64'></div><div>+    <dhcp></div><div>+      <leasetime>5m</leasetime></div><div>+      <range start='2001:db8:ac10:fd01::1:<wbr>10' end='2001:db8:ac10:fd01::1:ff'<wbr>/></div><div>+    </dhcp></div><div>+  </ip></div><div>+</network></div><div>diff --git a/tests/networkxml2confdata/<wbr>leasetime-seconds.conf b/tests/networkxml2confdata/<wbr>leasetime-seconds.conf</div><div>new file mode 100644</div><div>index 0000000..635896b</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>leasetime-seconds.conf</div><div>@@ -0,0 +1,17 @@</div><div>+##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE</div><div>+##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:</div><div>+##    virsh net-edit default</div><div>+## or other application using the libvirt API.</div><div>+##</div><div>+## dnsmasq conf file created by libvirt</div><div>+strict-order</div><div>+except-interface=lo</div><div>+bind-dynamic</div><div>+interface=virbr0</div><div>+dhcp-range=192.168.122.2,192.<wbr>168.122.254,125</div><div>+dhcp-no-override</div><div>+dhcp-range=2001:db8:ac10:<wbr>fd01::1:10,2001:db8:ac10:fd01:<wbr>:1:ff,64,125</div><div>+dhcp-lease-max=493</div><div>+dhcp-hostsfile=/var/lib/<wbr>libvirt/dnsmasq/default.<wbr>hostsfile</div><div>+addn-hosts=/var/lib/libvirt/<wbr>dnsmasq/default.addnhosts</div><div>+enable-ra</div><div>diff --git a/tests/networkxml2confdata/<wbr>leasetime-seconds.xml b/tests/networkxml2confdata/<wbr>leasetime-seconds.xml</div><div>new file mode 100644</div><div>index 0000000..dcb3f91</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>leasetime-seconds.xml</div><div>@@ -0,0 +1,18 @@</div><div>+<network></div><div>+  <name>default</name></div><div>+  <uuid>81ff0d90-c91e-6742-<wbr>64da-4a736edb9a9b</uuid></div><div>+  <forward dev='eth1' mode='nat'/></div><div>+  <bridge name='virbr0' stp='on' delay='0'/></div><div>+  <ip address='192.168.122.1' netmask='255.255.255.0'></div><div>+    <dhcp></div><div>+      <leasetime>125s</leasetime></div><div>+      <range start='192.168.122.2' end='192.168.122.254'/></div><div>+    </dhcp></div><div>+  </ip></div><div>+  <ip family='ipv6' address='2001:db8:ac10:fd01::<wbr>1' prefix='64'></div><div>+    <dhcp></div><div>+      <leasetime>125s</leasetime></div><div>+      <range start='2001:db8:ac10:fd01::1:<wbr>10' end='2001:db8:ac10:fd01::1:ff'<wbr>/></div><div>+    </dhcp></div><div>+  </ip></div><div>+</network></div><div>diff --git a/tests/networkxml2confdata/<wbr>leasetime.conf b/tests/networkxml2confdata/<wbr>leasetime.conf</div><div>new file mode 100644</div><div>index 0000000..72a2f69</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>leasetime.conf</div><div>@@ -0,0 +1,17 @@</div><div>+##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE</div><div>+##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:</div><div>+##    virsh net-edit default</div><div>+## or other application using the libvirt API.</div><div>+##</div><div>+## dnsmasq conf file created by libvirt</div><div>+strict-order</div><div>+except-interface=lo</div><div>+bind-dynamic</div><div>+interface=virbr0</div><div>+dhcp-range=192.168.122.2,192.<wbr>168.122.254,122</div><div>+dhcp-no-override</div><div>+dhcp-range=2001:db8:ac10:<wbr>fd01::1:10,2001:db8:ac10:fd01:<wbr>:1:ff,64,121</div><div>+dhcp-lease-max=493</div><div>+dhcp-hostsfile=/var/lib/<wbr>libvirt/dnsmasq/default.<wbr>hostsfile</div><div>+addn-hosts=/var/lib/libvirt/<wbr>dnsmasq/default.addnhosts</div><div>+enable-ra</div><div>diff --git a/tests/networkxml2confdata/<wbr>leasetime.xml b/tests/networkxml2confdata/<wbr>leasetime.xml</div><div>new file mode 100644</div><div>index 0000000..fdbb15f</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>leasetime.xml</div><div>@@ -0,0 +1,18 @@</div><div>+<network></div><div>+  <name>default</name></div><div>+  <uuid>81ff0d90-c91e-6742-<wbr>64da-4a736edb9a9b</uuid></div><div>+  <forward dev='eth1' mode='nat'/></div><div>+  <bridge name='virbr0' stp='on' delay='0'/></div><div>+  <ip address='192.168.122.1' netmask='255.255.255.0'></div><div>+    <dhcp></div><div>+      <leasetime>122</leasetime></div><div>+      <range start='192.168.122.2' end='192.168.122.254'/></div><div>+    </dhcp></div><div>+  </ip></div><div>+  <ip family='ipv6' address='2001:db8:ac10:fd01::<wbr>1' prefix='64'></div><div>+    <dhcp></div><div>+      <leasetime>121</leasetime></div><div>+      <range start='2001:db8:ac10:fd01::1:<wbr>10' end='2001:db8:ac10:fd01::1:ff'<wbr>/></div><div>+    </dhcp></div><div>+  </ip></div><div>+</network></div><div>diff --git a/tests/networkxml2confdata/<wbr>nat-network-dns-srv-record-<wbr>minimal.hostsfile b/tests/networkxml2confdata/<wbr>nat-network-dns-srv-record-<wbr>minimal.hostsfile</div><div>new file mode 100644</div><div>index 0000000..deb3f00</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>nat-network-dns-srv-record-<wbr>minimal.hostsfile</div><div>@@ -0,0 +1,2 @@</div><div>+00:16:3e:77:e2:ed,192.168.<wbr>122.10,<a href="http://a.example.com/" target="_blank">a.example.com</a></div><div>+00:16:3e:3e:a9:1a,192.168.<wbr>122.11,<a href="http://b.example.com/" target="_blank">b.example.com</a></div><div>diff --git a/tests/networkxml2confdata/<wbr>nat-network-dns-srv-record.<wbr>hostsfile b/tests/networkxml2confdata/<wbr>nat-network-dns-srv-record.<wbr>hostsfile</div><div>new file mode 100644</div><div>index 0000000..deb3f00</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>nat-network-dns-srv-record.<wbr>hostsfile</div><div>@@ -0,0 +1,2 @@</div><div>+00:16:3e:77:e2:ed,192.168.<wbr>122.10,<a href="http://a.example.com/" target="_blank">a.example.com</a></div><div>+00:16:3e:3e:a9:1a,192.168.<wbr>122.11,<a href="http://b.example.com/" target="_blank">b.example.com</a></div><div>diff --git a/tests/networkxml2confdata/<wbr>nat-network-dns-txt-record.<wbr>hostsfile b/tests/networkxml2confdata/<wbr>nat-network-dns-txt-record.<wbr>hostsfile</div><div>new file mode 100644</div><div>index 0000000..deb3f00</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>nat-network-dns-txt-record.<wbr>hostsfile</div><div>@@ -0,0 +1,2 @@</div><div>+00:16:3e:77:e2:ed,192.168.<wbr>122.10,<a href="http://a.example.com/" target="_blank">a.example.com</a></div><div>+00:16:3e:3e:a9:1a,192.168.<wbr>122.11,<a href="http://b.example.com/" target="_blank">b.example.com</a></div><div>diff --git a/tests/networkxml2confdata/<wbr>nat-network-name-with-quotes.<wbr>hostsfile b/tests/networkxml2confdata/<wbr>nat-network-name-with-quotes.<wbr>hostsfile</div><div>new file mode 100644</div><div>index 0000000..deb3f00</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>nat-network-name-with-quotes.<wbr>hostsfile</div><div>@@ -0,0 +1,2 @@</div><div>+00:16:3e:77:e2:ed,192.168.<wbr>122.10,<a href="http://a.example.com/" target="_blank">a.example.com</a></div><div>+00:16:3e:3e:a9:1a,192.168.<wbr>122.11,<a href="http://b.example.com/" target="_blank">b.example.com</a></div><div>diff --git a/tests/networkxml2confdata/<wbr>nat-network.hostsfile b/tests/networkxml2confdata/<wbr>nat-network.hostsfile</div><div>new file mode 100644</div><div>index 0000000..deb3f00</div><div>--- /dev/null</div><div>+++ b/tests/networkxml2confdata/<wbr>nat-network.hostsfile</div><div>@@ -0,0 +1,2 @@</div><div>+00:16:3e:77:e2:ed,192.168.<wbr>122.10,<a href="http://a.example.com/" target="_blank">a.example.com</a></div><div>+00:16:3e:3e:a9:1a,192.168.<wbr>122.11,<a href="http://b.example.com/" target="_blank">b.example.com</a></div><div>diff --git a/tests/networkxml2conftest.c b/tests/networkxml2conftest.c</div><div>index 65a0e32..8e1f8be 100644</div><div>--- a/tests/networkxml2conftest.c</div><div>+++ b/tests/networkxml2conftest.c</div><div>@@ -19,9 +19,13 @@</div><div> #define VIR_FROM_THIS VIR_FROM_NONE</div><div> </div><div> static int</div><div>-testCompareXMLToConfFiles(<wbr>const char *inxml, const char *outconf, dnsmasqCapsPtr caps)</div><div>+testCompareXMLToConfFiles(<wbr>const char *inxml,</div><div>+                          const char *outconf,</div><div>+                          const char *outhostsfile,</div><div>+                          dnsmasqCapsPtr caps)</div><div> {</div><div>-    char *actual = NULL;</div><div>+    char *actualconf = NULL;</div><div>+    char *actualhosts = NULL;</div><div>     int ret = -1;</div><div>     virNetworkDefPtr dev = NULL;</div><div>     virNetworkObjPtr obj = NULL;</div><div>@@ -41,17 +45,30 @@ testCompareXMLToConfFiles(<wbr>const char *inxml, const char *outconf, dnsmasqCapsPtr</div><div>     if (dctx == NULL)</div><div>         goto fail;</div><div> </div><div>-    if (networkDnsmasqConfContents(<wbr>obj, pidfile, &actual,</div><div>+    if (networkDnsmasqConfContents(<wbr>obj, pidfile, &actualconf, &actualhosts,</div><div>                         dctx, caps) < 0)</div><div>         goto fail;</div><div> </div><div>-    if (virTestCompareToFile(actual, outconf) < 0)</div><div>+    if (virTestCompareToFile(<wbr>actualconf, outconf) < 0)</div><div>         goto fail;</div><div> </div><div>+    if (virFileExists(outhostsfile)) {</div><div>+        if (!actualhosts) {</div><div>+            fprintf(stderr, "%s: hostsfile exists but the configuration did not specify any host", outhostsfile);</div><div>+            goto fail;</div><div>+        } else if (virTestCompareToFile(<wbr>actualhosts, outhostsfile) < 0) {</div><div>+            goto fail;</div><div>+        }</div><div>+    } else if (actualhosts) {</div><div>+        fprintf(stderr, "%s: file does not exist but actual data was expected", outhostsfile);</div><div>+        goto fail;</div><div>+    }</div><div>+</div><div>     ret = 0;</div><div> </div><div>  fail:</div><div>-    VIR_FREE(actual);</div><div>+    VIR_FREE(actualconf);</div><div>+    VIR_FREE(actualhosts);</div><div>     VIR_FREE(pidfile);</div><div>     virCommandFree(cmd);</div><div>     virObjectUnref(obj);</div><div>@@ -70,20 +87,24 @@ testCompareXMLToConfHelper(<wbr>const void *data)</div><div>     int result = -1;</div><div>     const testInfo *info = data;</div><div>     char *inxml = NULL;</div><div>-    char *outxml = NULL;</div><div>+    char *outconf = NULL;</div><div>+    char *outhostsfile = NULL;</div><div> </div><div>     if (virAsprintf(&inxml, "%s/networkxml2confdata/%s.<wbr>xml",</div><div>                     abs_srcdir, info->name) < 0 ||</div><div>-        virAsprintf(&outxml, "%s/networkxml2confdata/%s.<wbr>conf",</div><div>+        virAsprintf(&outconf, "%s/networkxml2confdata/%s.<wbr>conf",</div><div>+                    abs_srcdir, info->name) < 0 ||</div><div>+        virAsprintf(&outhostsfile, "%s/networkxml2confdata/%s.<wbr>hostsfile",</div><div>                     abs_srcdir, info->name) < 0) {</div><div>         goto cleanup;</div><div>     }</div><div> </div><div>-    result = testCompareXMLToConfFiles(<wbr>inxml, outxml, info->caps);</div><div>+    result = testCompareXMLToConfFiles(<wbr>inxml, outconf, outhostsfile, info->caps);</div><div> </div><div>  cleanup:</div><div>     VIR_FREE(inxml);</div><div>-    VIR_FREE(outxml);</div><div>+    VIR_FREE(outconf);</div><div>+    VIR_FREE(outhostsfile);</div><div> </div><div>     return result;</div><div> }</div><div>@@ -129,6 +150,14 @@ mymain(void)</div><div>     DO_TEST("dhcp6-network", dhcpv6);</div><div>     DO_TEST("dhcp6-nat-network", dhcpv6);</div><div>     DO_TEST("dhcp6host-routed-<wbr>network", dhcpv6);</div><div>+    DO_TEST("leasetime", dhcpv6);</div><div>+    DO_TEST("leasetime-seconds", dhcpv6);</div><div>+    DO_TEST("leasetime-hours", dhcpv6);</div><div>+    DO_TEST("leasetime-minutes", dhcpv6);</div><div>+    DO_TEST("leasetime-hours", dhcpv6);</div><div>+    DO_TEST("leasetime-days", dhcpv6);</div><div>+    DO_TEST("leasetime-infinite", dhcpv6);</div><div>+    DO_TEST("leasetime-host", dhcpv6);</div><div> </div><div>     virObjectUnref(dhcpv6);</div><div>     virObjectUnref(full);</div><div class="gmail-yj6qo gmail-ajU" style="margin:2px 0px 0px"><div id="gmail-:nr" class="gmail-ajR" tabindex="0"><img class="gmail-ajT" src="https://ssl.gstatic.com/ui/v1/icons/mail/images/cleardot.gif"></div></div><span class="gmail-HOEnZb gmail-adL"><font color="#888888"><div style="font-size:12.8px">-- </div><div style="font-size:12.8px">2.9.3</div><div><br></div></font></span><div><br></div>-- <br><div class="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div><div>Alberto Ruiz<br></div><span>Associate </span>Engineering Manager - Desktop Management Tools<br></div>Red Hat<br></div></div></div></div>
</div>