[libvirt] [PATCH] leasetime support for <dhcp>

Alberto Ruiz aruiz at gnome.org
Mon Jun 26 18:59:04 UTC 2017


Hey Laine,

Have some time to review this?

2017-06-23 1:44 GMT+01:00  <aruiz at gnome.org>:
> From: Alberto Ruiz <aruiz at gnome.org>
>
> Fixes #913446
>
> This patch addresses a few problems found by the initial reviews:
>
> * leaseTimeUnit RNG type renamed to timeUnit
> * virNetworkDHCPDefGetLeaseTime() renamed to virNetworkDHCPLeaseTimeParseXML()
> * consistent use of braces in if-else-if
> * use %lu instead of PRId64
> * use 0 as infinite lease
> * add a leasetime_defined field to struct _virNetworkIPDef to describe whether the value was set in the xml configuration or not
> * use uint32_t for the leasetime instead of int64_t
> * fail on all invalid leasetime values
> * squash all patches into one
>
> ---
>  docs/schemas/basictypes.rng                        |  16 +++
>  docs/schemas/network.rng                           |   8 ++
>  src/conf/network_conf.c                            |  93 +++++++++++++++-
>  src/conf/network_conf.h                            |   5 +-
>  src/libvirt_private.syms                           |   1 +
>  src/network/bridge_driver.c                        | 119 ++++++++++++++++-----
>  src/network/bridge_driver.h                        |   1 +
>  src/util/virdnsmasq.c                              | 106 +++++++++++-------
>  src/util/virdnsmasq.h                              |   2 +
>  .../dhcp6-nat-network.hostsfile                    |   7 ++
>  tests/networkxml2confdata/dhcp6-network.hostsfile  |   5 +
>  .../dhcp6host-routed-network.hostsfile             |   7 ++
>  tests/networkxml2confdata/leasetime-days.conf      |  18 ++++
>  tests/networkxml2confdata/leasetime-days.xml       |  18 ++++
>  tests/networkxml2confdata/leasetime-hours.conf     |  18 ++++
>  tests/networkxml2confdata/leasetime-hours.xml      |  18 ++++
>  tests/networkxml2confdata/leasetime-infinite.conf  |  18 ++++
>  tests/networkxml2confdata/leasetime-infinite.xml   |  18 ++++
>  tests/networkxml2confdata/leasetime-minutes.conf   |  18 ++++
>  tests/networkxml2confdata/leasetime-minutes.xml    |  18 ++++
>  tests/networkxml2confdata/leasetime-seconds.conf   |  18 ++++
>  tests/networkxml2confdata/leasetime-seconds.xml    |  18 ++++
>  tests/networkxml2confdata/leasetime.conf           |  18 ++++
>  tests/networkxml2confdata/leasetime.xml            |  18 ++++
>  .../nat-network-dns-srv-record-minimal.hostsfile   |   2 +
>  .../nat-network-dns-srv-record.hostsfile           |   2 +
>  .../nat-network-dns-txt-record.hostsfile           |   2 +
>  .../nat-network-name-with-quotes.hostsfile         |   2 +
>  tests/networkxml2confdata/nat-network.hostsfile    |   2 +
>  .../networkxml2confdata/ptr-domains-auto.hostsfile |   2 +
>  tests/networkxml2conftest.c                        |  45 ++++++--
>  31 files changed, 571 insertions(+), 72 deletions(-)
>  create mode 100644 tests/networkxml2confdata/dhcp6-nat-network.hostsfile
>  create mode 100644 tests/networkxml2confdata/dhcp6-network.hostsfile
>  create mode 100644 tests/networkxml2confdata/dhcp6host-routed-network.hostsfile
>  create mode 100644 tests/networkxml2confdata/leasetime-days.conf
>  create mode 100644 tests/networkxml2confdata/leasetime-days.xml
>  create mode 100644 tests/networkxml2confdata/leasetime-hours.conf
>  create mode 100644 tests/networkxml2confdata/leasetime-hours.xml
>  create mode 100644 tests/networkxml2confdata/leasetime-infinite.conf
>  create mode 100644 tests/networkxml2confdata/leasetime-infinite.xml
>  create mode 100644 tests/networkxml2confdata/leasetime-minutes.conf
>  create mode 100644 tests/networkxml2confdata/leasetime-minutes.xml
>  create mode 100644 tests/networkxml2confdata/leasetime-seconds.conf
>  create mode 100644 tests/networkxml2confdata/leasetime-seconds.xml
>  create mode 100644 tests/networkxml2confdata/leasetime.conf
>  create mode 100644 tests/networkxml2confdata/leasetime.xml
>  create mode 100644 tests/networkxml2confdata/nat-network-dns-srv-record-minimal.hostsfile
>  create mode 100644 tests/networkxml2confdata/nat-network-dns-srv-record.hostsfile
>  create mode 100644 tests/networkxml2confdata/nat-network-dns-txt-record.hostsfile
>  create mode 100644 tests/networkxml2confdata/nat-network-name-with-quotes.hostsfile
>  create mode 100644 tests/networkxml2confdata/nat-network.hostsfile
>  create mode 100644 tests/networkxml2confdata/ptr-domains-auto.hostsfile
>
> diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
> index 1ea667cdf..9db19c7f0 100644
> --- a/docs/schemas/basictypes.rng
> +++ b/docs/schemas/basictypes.rng
> @@ -564,4 +564,20 @@
>      </element>
>    </define>
>
> +  <define name="timeUnit">
> +    <choice>
> +      <value>seconds</value>
> +      <value>minutes</value>
> +      <value>hours</value>
> +      <value>days</value>
> +    </choice>
> +  </define>
> +
> +  <define name="leaseTime">
> +    <data type="long">
> +      <param name="minInclusive">-1</param>
> +      <param name="maxInclusive">4294967295</param>
> +    </data>
> +  </define>
> +
>  </grammar>
> diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
> index 1048dabf3..a0d878e4a 100644
> --- a/docs/schemas/network.rng
> +++ b/docs/schemas/network.rng
> @@ -357,6 +357,14 @@
>                  <!-- Define the range(s) of IP addresses that the DHCP
>                       server should hand out -->
>                  <element name="dhcp">
> +                <optional>
> +                  <element name="leasetime">
> +                    <optional>
> +                      <attribute name="unit"><ref name="timeUnit"/></attribute>
> +                    </optional>
> +                    <ref name="leaseTime"/>
> +                  </element>
> +                </optional>
>                    <interleave>
>                      <zeroOrMore>
>                        <element name="range">
> diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
> index 3ebf67ff5..8431ee806 100644
> --- a/src/conf/network_conf.c
> +++ b/src/conf/network_conf.c
> @@ -29,6 +29,8 @@
>  #include <sys/stat.h>
>  #include <fcntl.h>
>  #include <string.h>
> +#include <stdlib.h>
> +#include <inttypes.h>
>
>  #include "virerror.h"
>  #include "datatypes.h"
> @@ -514,8 +516,92 @@ virNetworkDHCPHostDefParseXML(const char *networkName,
>
>
>  static int
> +virNetworkDHCPLeaseTimeParseXML (xmlNodePtr node,
> +                                 xmlXPathContextPtr ctxt,
> +                                 uint32_t *lease,
> +                                 bool     *defined)
> +{
> +    int ret = 0;
> +    uint32_t multiplier;
> +    char *leaseString, *leaseUnit;
> +    xmlNodePtr save;
> +
> +    *defined = 0;
> +
> +    save = ctxt->node;
> +    ctxt->node = node;
> +
> +    leaseString = virXPathString ("string(./leasetime/text())", ctxt);
> +    leaseUnit   = virXPathString ("string(./leasetime/@unit)", ctxt);
> +
> +    /* If value is not present we set the value to -2 */
> +    if (leaseString == NULL) {
> +        goto cleanup;
> +    }
> +    if (leaseString[0] == '-') {
> +        virReportError(VIR_ERR_XML_ERROR,
> +                       _("<leasetime> value (%s) cannot be negative"),
> +                       leaseString);
> +    }
> +
> +    *defined = 1;
> +
> +    if (leaseUnit == NULL || strcmp (leaseUnit, "seconds") == 0) {
> +        multiplier = 1;
> +    }
> +    else if (strcmp (leaseUnit, "minutes") == 0) {
> +        multiplier = 60;
> +    }
> +    else if (strcmp (leaseUnit, "hours") == 0) {
> +        multiplier = 60 * 60;
> +    }
> +    else if (strcmp (leaseUnit, "days") == 0) {
> +        multiplier = 60 * 60 * 24;
> +    }
> +    else {
> +        virReportError(VIR_ERR_XML_ERROR,
> +                       _("invalid value for unit parameter in <leasetime> element"
> +                         "found in <dhcp> network, only 'seconds', 'minutes', "
> +                         "'hours' or 'days' are valid: %s"),
> +                       leaseUnit);
> +        ret = -1;
> +        goto cleanup;
> +    }
> +
> +    errno = 0;
> +    *lease = (uint32_t) strtoul((const char*)leaseString, NULL, 10);
> +
> +    /* Report any errors parsing the string */
> +    if (errno != 0) {
> +        virReportError(VIR_ERR_XML_ERROR,
> +                       _("<leasetime> value could not be converted to a signed integer: %s"),
> +                      leaseString);
> +        ret = -1;
> +        goto cleanup;
> +    }
> +
> +    if (*lease > (UINT32_MAX / multiplier)) {
> +      virReportError (VIR_ERR_XML_ERROR,
> +                      _("<leasetime> value %lu %s exceeds the maximum of %lu seconds"),
> +                      (unsigned long)*lease, leaseUnit, (unsigned long)UINT32_MAX);
> +      ret = -1;
> +      goto cleanup;
> +    }
> +
> +    *lease = *lease * multiplier;
> +
> +cleanup:
> +    VIR_FREE(leaseString);
> +    VIR_FREE(leaseUnit);
> +    ctxt->node = save;
> +    return ret;
> +}
> +
> +
> +static int
>  virNetworkDHCPDefParseXML(const char *networkName,
>                            xmlNodePtr node,
> +                          xmlXPathContextPtr ctxt,
>                            virNetworkIPDefPtr def)
>  {
>      int ret = -1;
> @@ -526,6 +612,11 @@ virNetworkDHCPDefParseXML(const char *networkName,
>      memset(&range, 0, sizeof(range));
>      memset(&host, 0, sizeof(host));
>
> +    if (virNetworkDHCPLeaseTimeParseXML (node, ctxt,
> +                                         &def->leasetime,
> +                                         &def->leasetime_defined))
> +        goto cleanup;
> +
>      cur = node->children;
>      while (cur != NULL) {
>          if (cur->type == XML_ELEMENT_NODE &&
> @@ -1104,7 +1195,7 @@ virNetworkIPDefParseXML(const char *networkName,
>      }
>
>      if ((dhcp = virXPathNode("./dhcp[1]", ctxt)) &&
> -        virNetworkDHCPDefParseXML(networkName, dhcp, def) < 0)
> +        virNetworkDHCPDefParseXML(networkName, dhcp, ctxt, def) < 0)
>          goto cleanup;
>
>      if (virXPathNode("./tftp[1]", ctxt)) {
> diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
> index e9a5baf5b..466220e81 100644
> --- a/src/conf/network_conf.h
> +++ b/src/conf/network_conf.h
> @@ -175,7 +175,10 @@ struct _virNetworkIPDef {
>      char *tftproot;
>      char *bootfile;
>      virSocketAddr bootserver;
> -   };
> +
> +    uint32_t leasetime;
> +    bool leasetime_defined;
> +};
>
>  typedef struct _virNetworkForwardIfDef virNetworkForwardIfDef;
>  typedef virNetworkForwardIfDef *virNetworkForwardIfDefPtr;
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index c1e9471c5..5ef33dcfe 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -1561,6 +1561,7 @@ dnsmasqCapsRefresh;
>  dnsmasqContextFree;
>  dnsmasqContextNew;
>  dnsmasqDelete;
> +dnsmasqDhcpHostsToString;
>  dnsmasqReload;
>  dnsmasqSave;
>
> diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
> index 3ba70180b..cdb0230ab 100644
> --- a/src/network/bridge_driver.c
> +++ b/src/network/bridge_driver.c
> @@ -41,6 +41,8 @@
>  #include <sys/ioctl.h>
>  #include <net/if.h>
>  #include <dirent.h>
> +#include <inttypes.h>
> +#include <stdint.h>
>  #if HAVE_SYS_SYSCTL_H
>  # include <sys/sysctl.h>
>  #endif
> @@ -948,6 +950,62 @@ networkKillDaemon(pid_t pid, const char *daemonName, const char *networkName)
>      return ret;
>  }
>
> +static int
> +networkBuildDnsmasqHostsList(dnsmasqContext *dctx,
> +                             virNetworkDNSDefPtr dnsdef)
> +{
> +    size_t i, j;
> +
> +    if (dnsdef) {
> +        for (i = 0; i < dnsdef->nhosts; i++) {
> +            virNetworkDNSHostDefPtr host = &(dnsdef->hosts[i]);
> +            if (VIR_SOCKET_ADDR_VALID(&host->ip)) {
> +                for (j = 0; j < host->nnames; j++)
> +                    if (dnsmasqAddHost(dctx, &host->ip, host->names[j]) < 0)
> +                        return -1;
> +            }
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +/* translates the leasetime value into a dnsmasq configuration string
> + * for dhcp-range/host */
> +static char *
> +networkDnsmasqConfLeaseValueToString (int64_t leasetime, bool defined)
> +{
> +    char *result = NULL;
> +    virBuffer leasebuf = VIR_BUFFER_INITIALIZER;
> +
> +    /* Leasetime parameter set on the XML */
> +
> +    /* defined = FALSE means we fallback to dnsmasq defaults*/
> +    if (defined == 0) {
> +        virBufferAsprintf(&leasebuf, "%s", "");
> +    }
> +    /* 0 means no expiration */
> +    else if (leasetime == 0) {
> +        virBufferAsprintf(&leasebuf, ",infinite");
> +    }
> +    /* DHCP value for lease time is a unsigned four octect integer */
> +    else if (leasetime <= UINT32_MAX) {
> +        virBufferAsprintf(&leasebuf, ",%lu", (unsigned long)leasetime);
> +    }
> +    else {
> +        if (leasetime < 120)
> +          virReportError (VIR_ERR_CONFIG_UNSUPPORTED,
> +                          _("lease time must be greater than 120 seconds"));
> +        goto cleanup;
> +    }
> +
> +    result = virBufferContentAndReset(&leasebuf);
> +
> +cleanup:
> +    virBufferFreeAndReset (&leasebuf);
> +    return result;
> +}
> +
>  /* the following does not build a file, it builds a list
>   * which is later saved into a file
>   */
> @@ -956,8 +1014,14 @@ static int
>  networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
>                                   virNetworkIPDefPtr ipdef)
>  {
> +    int ret = -1;
>      size_t i;
>      bool ipv6 = false;
> +    char *leasetime = networkDnsmasqConfLeaseValueToString(ipdef->leasetime,
> +                                                           ipdef->leasetime_defined);
> +
> +    if (!leasetime)
> +        goto cleanup;
>
>      if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
>          ipv6 = true;
> @@ -965,31 +1029,14 @@ networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
>          virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
>          if (VIR_SOCKET_ADDR_VALID(&host->ip))
>              if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
> -                                   host->name, host->id, ipv6) < 0)
> -                return -1;
> -    }
> -
> -    return 0;
> -}
> -
> -static int
> -networkBuildDnsmasqHostsList(dnsmasqContext *dctx,
> -                             virNetworkDNSDefPtr dnsdef)
> -{
> -    size_t i, j;
> -
> -    if (dnsdef) {
> -        for (i = 0; i < dnsdef->nhosts; i++) {
> -            virNetworkDNSHostDefPtr host = &(dnsdef->hosts[i]);
> -            if (VIR_SOCKET_ADDR_VALID(&host->ip)) {
> -                for (j = 0; j < host->nnames; j++)
> -                    if (dnsmasqAddHost(dctx, &host->ip, host->names[j]) < 0)
> -                        return -1;
> -            }
> -        }
> +                                   host->name, host->id, leasetime, ipv6) < 0)
> +                goto cleanup;
>      }
>
> -    return 0;
> +    ret = 0;
> +cleanup:
> +    VIR_FREE(leasetime);
> +    return ret;
>  }
>
>
> @@ -1034,6 +1081,7 @@ int
>  networkDnsmasqConfContents(virNetworkObjPtr network,
>                             const char *pidfile,
>                             char **configstr,
> +                           char **hostsfilestr,
>                             dnsmasqContext *dctx,
>                             dnsmasqCapsPtr caps ATTRIBUTE_UNUSED)
>  {
> @@ -1362,6 +1410,7 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
>          }
>          for (r = 0; r < ipdef->nranges; r++) {
>              int thisRange;
> +            char *leasestr;
>
>              if (!(saddr = virSocketAddrFormat(&ipdef->ranges[r].start)) ||
>                  !(eaddr = virSocketAddrFormat(&ipdef->ranges[r].end)))
> @@ -1369,12 +1418,23 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
>
>              virBufferAsprintf(&configbuf, "dhcp-range=%s,%s",
>                                saddr, eaddr);
> -            if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
> +
> +            /* Add ipv6 prefix length parameter if needed */
> +            if (ipdef == ipv6def)
>                  virBufferAsprintf(&configbuf, ",%d", prefix);
> +
> +            leasestr = networkDnsmasqConfLeaseValueToString (ipdef->leasetime,
> +                                                             ipdef->leasetime_defined);
> +            if (!leasestr)
> +                goto cleanup;
> +            virBufferAsprintf(&configbuf, "%s", leasestr);
> +
> +            /* Add the newline */
>              virBufferAddLit(&configbuf, "\n");
>
>              VIR_FREE(saddr);
>              VIR_FREE(eaddr);
> +            VIR_FREE(leasestr);
>              thisRange = virSocketAddrGetRange(&ipdef->ranges[r].start,
>                                                &ipdef->ranges[r].end,
>                                                &ipdef->address,
> @@ -1405,6 +1465,15 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
>          if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
>              goto cleanup;
>
> +        /* Return the contents of the hostsfile if requested */
> +        if (hostsfilestr) {
> +            *hostsfilestr = dnsmasqDhcpHostsToString (dctx->hostsfile->hosts,
> +                                                      dctx->hostsfile->nhosts);
> +
> +            if (!hostsfilestr)
> +                goto cleanup;
> +        }
> +
>          /* Note: the following is IPv4 only */
>          if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
>              if (ipdef->nranges || ipdef->nhosts) {
> @@ -1506,7 +1575,7 @@ networkBuildDhcpDaemonCommandLine(virNetworkDriverStatePtr driver,
>
>      network->dnsmasqPid = -1;
>
> -    if (networkDnsmasqConfContents(network, pidfile, &configstr,
> +    if (networkDnsmasqConfContents(network, pidfile, &configstr, NULL,
>                                     dctx, dnsmasq_caps) < 0)
>          goto cleanup;
>      if (!configstr)
> diff --git a/src/network/bridge_driver.h b/src/network/bridge_driver.h
> index 7832b6031..56329eb59 100644
> --- a/src/network/bridge_driver.h
> +++ b/src/network/bridge_driver.h
> @@ -53,6 +53,7 @@ int networkGetActualType(virDomainNetDefPtr iface)
>  int networkDnsmasqConfContents(virNetworkObjPtr network,
>                          const char *pidfile,
>                          char **configstr,
> +                        char **hostsfilestr,
>                          dnsmasqContext *dctx,
>                          dnsmasqCapsPtr caps);
>
> diff --git a/src/util/virdnsmasq.c b/src/util/virdnsmasq.c
> index 1b78c1fad..94c9a3bb1 100644
> --- a/src/util/virdnsmasq.c
> +++ b/src/util/virdnsmasq.c
> @@ -308,52 +308,47 @@ hostsfileAdd(dnsmasqHostsfile *hostsfile,
>               virSocketAddr *ip,
>               const char *name,
>               const char *id,
> +             const char *leasetime,
>               bool ipv6)
>  {
> +    int ret = -1;
>      char *ipstr = NULL;
> +    virBuffer hostbuf = VIR_BUFFER_INITIALIZER;
> +
>      if (VIR_REALLOC_N(hostsfile->hosts, hostsfile->nhosts + 1) < 0)
>          goto error;
>
>      if (!(ipstr = virSocketAddrFormat(ip)))
> -        return -1;
> +        goto error;
>
>      /* the first test determines if it is a dhcpv6 host */
>      if (ipv6) {
> -        if (name && id) {
> -            if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host,
> -                            "id:%s,%s,[%s]", id, name, ipstr) < 0)
> -                goto error;
> -        } else if (name && !id) {
> -            if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host,
> -                            "%s,[%s]", name, ipstr) < 0)
> -                goto error;
> -        } else if (!name && id) {
> -            if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host,
> -                            "id:%s,[%s]", id, ipstr) < 0)
> -                goto error;
> -        }
> +        if (name && id)
> +            virBufferAsprintf(&hostbuf, "id:%s,%s,[%s]", id, name, ipstr);
> +        else if (name && !id)
> +            virBufferAsprintf(&hostbuf, "%s,[%s]", name, ipstr);
> +        else if (!name && id)
> +            virBufferAsprintf(&hostbuf, "id:%s,[%s]", id, ipstr);
>      } else if (name && mac) {
> -        if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s,%s",
> -                        mac, ipstr, name) < 0)
> -            goto error;
> +        virBufferAsprintf(&hostbuf, "%s,%s,%s", mac, ipstr, name);
>      } else if (name && !mac) {
> -        if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s",
> -                        name, ipstr) < 0)
> -            goto error;
> +        virBufferAsprintf(&hostbuf, "%s,%s", name, ipstr);
>      } else {
> -        if (virAsprintf(&hostsfile->hosts[hostsfile->nhosts].host, "%s,%s",
> -                        mac, ipstr) < 0)
> -            goto error;
> +        virBufferAsprintf(&hostbuf, "%s,%s", mac, ipstr);
>      }
> -    VIR_FREE(ipstr);
>
> -    hostsfile->nhosts++;
> +    /* The leasetime string already includes comma if there's any value at all */
> +    virBufferAsprintf(&hostbuf, "%s", leasetime);
>
> -    return 0;
> +    if (!(hostsfile->hosts[hostsfile->nhosts].host = virBufferContentAndReset (&hostbuf)))
> +      goto error;
>
> +    hostsfile->nhosts++;
> +    ret = 0;
>   error:
> +    virBufferFreeAndReset(&hostbuf);
>      VIR_FREE(ipstr);
> -    return -1;
> +    return ret;
>  }
>
>  static dnsmasqHostsfile *
> @@ -391,10 +386,9 @@ hostsfileWrite(const char *path,
>                 dnsmasqDhcpHost *hosts,
>                 unsigned int nhosts)
>  {
> -    char *tmp;
> +    char *tmp, *content = NULL;
>      FILE *f;
>      bool istmp = true;
> -    size_t i;
>      int rc = 0;
>
>      /* even if there are 0 hosts, create a 0 length file, to allow
> @@ -412,17 +406,21 @@ hostsfileWrite(const char *path,
>          }
>      }
>
> -    for (i = 0; i < nhosts; i++) {
> -        if (fputs(hosts[i].host, f) == EOF || fputc('\n', f) == EOF) {
> -            rc = -errno;
> -            VIR_FORCE_FCLOSE(f);
> +    if (!(content = dnsmasqDhcpHostsToString(hosts, nhosts))) {
> +        rc = -ENOMEM;
> +        goto cleanup;
> +    }
>
> -            if (istmp)
> -                unlink(tmp);
> +    if (fputs(content, f) == EOF) {
> +        rc = -errno;
> +        VIR_FORCE_FCLOSE(f);
> +
> +        if (istmp)
> +            unlink(tmp);
> +
> +        goto cleanup;
> +     }
>
> -            goto cleanup;
> -        }
> -    }
>
>      if (VIR_FCLOSE(f) == EOF) {
>          rc = -errno;
> @@ -436,6 +434,7 @@ hostsfileWrite(const char *path,
>      }
>
>   cleanup:
> +    VIR_FREE(content);
>      VIR_FREE(tmp);
>
>      return rc;
> @@ -524,9 +523,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);
>  }
>
>  /*
> @@ -892,3 +892,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)
> +{
> +    int 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 f47bea3ab..1795bc83b 100644
> --- a/src/util/virdnsmasq.h
> +++ b/src/util/virdnsmasq.h
> @@ -88,6 +88,7 @@ int              dnsmasqAddDhcpHost(dnsmasqContext *ctx,
>                                      virSocketAddr *ip,
>                                      const char *name,
>                                      const char *id,
> +                                    const char *leastime,
>                                      bool ipv6);
>  int              dnsmasqAddHost(dnsmasqContext *ctx,
>                                  virSocketAddr *ip,
> @@ -105,6 +106,7 @@ 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/tests/networkxml2confdata/dhcp6-nat-network.hostsfile b/tests/networkxml2confdata/dhcp6-nat-network.hostsfile
> new file mode 100644
> index 000000000..de659b98c
> --- /dev/null
> +++ b/tests/networkxml2confdata/dhcp6-nat-network.hostsfile
> @@ -0,0 +1,7 @@
> +00:16:3e:77:e2:ed,192.168.122.10,a.example.com
> +00:16:3e:3e:a9:1a,192.168.122.11,b.example.com
> +id:0:4:7e:7d:f0:7d:a8:bc:c5:d2:13:32:11:ed:16:ea:84:63,[2001:db8:ac10:fd01::1:20]
> +paul,[2001:db8:ac10:fd01::1:21]
> +id:0:3:0:1:0:16:3e:11:22:33,peter.xyz,[2001:db8:ac10:fd01::1:22]
> +id:0:3:0:1:0:16:3e:44:55:33,[2001:db8:ac10:fd01::1:23]
> +id:0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66,badbob,[2001:db8:ac10:fd01::1:24]
> diff --git a/tests/networkxml2confdata/dhcp6-network.hostsfile b/tests/networkxml2confdata/dhcp6-network.hostsfile
> new file mode 100644
> index 000000000..9dfb172ce
> --- /dev/null
> +++ b/tests/networkxml2confdata/dhcp6-network.hostsfile
> @@ -0,0 +1,5 @@
> +id:0:4:7e:7d:f0:7d:a8:bc:c5:d2:13:32:11:ed:16:ea:84:63,[2001:db8:ac10:fd01::1:20]
> +paul,[2001:db8:ac10:fd01::1:21]
> +id:0:3:0:1:0:16:3e:11:22:33,peter.xyz,[2001:db8:ac10:fd01::1:22]
> +id:0:3:0:1:0:16:3e:44:55:33,[2001:db8:ac10:fd01::1:23]
> +id:0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66,badbob,[2001:db8:ac10:fd01::1:24]
> diff --git a/tests/networkxml2confdata/dhcp6host-routed-network.hostsfile b/tests/networkxml2confdata/dhcp6host-routed-network.hostsfile
> new file mode 100644
> index 000000000..de659b98c
> --- /dev/null
> +++ b/tests/networkxml2confdata/dhcp6host-routed-network.hostsfile
> @@ -0,0 +1,7 @@
> +00:16:3e:77:e2:ed,192.168.122.10,a.example.com
> +00:16:3e:3e:a9:1a,192.168.122.11,b.example.com
> +id:0:4:7e:7d:f0:7d:a8:bc:c5:d2:13:32:11:ed:16:ea:84:63,[2001:db8:ac10:fd01::1:20]
> +paul,[2001:db8:ac10:fd01::1:21]
> +id:0:3:0:1:0:16:3e:11:22:33,peter.xyz,[2001:db8:ac10:fd01::1:22]
> +id:0:3:0:1:0:16:3e:44:55:33,[2001:db8:ac10:fd01::1:23]
> +id:0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66,badbob,[2001:db8:ac10:fd01::1:24]
> diff --git a/tests/networkxml2confdata/leasetime-days.conf b/tests/networkxml2confdata/leasetime-days.conf
> new file mode 100644
> index 000000000..d227be67a
> --- /dev/null
> +++ b/tests/networkxml2confdata/leasetime-days.conf
> @@ -0,0 +1,18 @@
> +##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
> +##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:
> +##    virsh net-edit default
> +## or other application using the libvirt API.
> +##
> +## dnsmasq conf file created by libvirt
> +strict-order
> +except-interface=lo
> +bind-dynamic
> +interface=virbr0
> +dhcp-range=192.168.122.2,192.168.122.254,86400
> +dhcp-no-override
> +dhcp-authoritative
> +dhcp-range=2001:db8:ac10:fd01::1:10,2001:db8:ac10:fd01::1:ff,64,86400
> +dhcp-lease-max=493
> +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile
> +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts
> +enable-ra
> diff --git a/tests/networkxml2confdata/leasetime-days.xml b/tests/networkxml2confdata/leasetime-days.xml
> new file mode 100644
> index 000000000..b990b4d68
> --- /dev/null
> +++ b/tests/networkxml2confdata/leasetime-days.xml
> @@ -0,0 +1,18 @@
> +<network>
> +  <name>default</name>
> +  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
> +  <forward dev='eth1' mode='nat'/>
> +  <bridge name='virbr0' stp='on' delay='0'/>
> +  <ip address='192.168.122.1' netmask='255.255.255.0'>
> +    <dhcp>
> +      <leasetime unit="days">1</leasetime>
> +      <range start='192.168.122.2' end='192.168.122.254'/>
> +    </dhcp>
> +  </ip>
> +  <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
> +    <dhcp>
> +      <leasetime unit="days">1</leasetime>
> +      <range start='2001:db8:ac10:fd01::1:10' end='2001:db8:ac10:fd01::1:ff'/>
> +    </dhcp>
> +  </ip>
> +</network>
> diff --git a/tests/networkxml2confdata/leasetime-hours.conf b/tests/networkxml2confdata/leasetime-hours.conf
> new file mode 100644
> index 000000000..e5e8c19cd
> --- /dev/null
> +++ b/tests/networkxml2confdata/leasetime-hours.conf
> @@ -0,0 +1,18 @@
> +##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
> +##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:
> +##    virsh net-edit default
> +## or other application using the libvirt API.
> +##
> +## dnsmasq conf file created by libvirt
> +strict-order
> +except-interface=lo
> +bind-dynamic
> +interface=virbr0
> +dhcp-range=192.168.122.2,192.168.122.254,3600
> +dhcp-no-override
> +dhcp-authoritative
> +dhcp-range=2001:db8:ac10:fd01::1:10,2001:db8:ac10:fd01::1:ff,64,3600
> +dhcp-lease-max=493
> +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile
> +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts
> +enable-ra
> diff --git a/tests/networkxml2confdata/leasetime-hours.xml b/tests/networkxml2confdata/leasetime-hours.xml
> new file mode 100644
> index 000000000..3b9609601
> --- /dev/null
> +++ b/tests/networkxml2confdata/leasetime-hours.xml
> @@ -0,0 +1,18 @@
> +<network>
> +  <name>default</name>
> +  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
> +  <forward dev='eth1' mode='nat'/>
> +  <bridge name='virbr0' stp='on' delay='0'/>
> +  <ip address='192.168.122.1' netmask='255.255.255.0'>
> +    <dhcp>
> +      <leasetime unit="hours">1</leasetime>
> +      <range start='192.168.122.2' end='192.168.122.254'/>
> +    </dhcp>
> +  </ip>
> +  <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
> +    <dhcp>
> +      <leasetime unit="hours">1</leasetime>
> +      <range start='2001:db8:ac10:fd01::1:10' end='2001:db8:ac10:fd01::1:ff'/>
> +    </dhcp>
> +  </ip>
> +</network>
> diff --git a/tests/networkxml2confdata/leasetime-infinite.conf b/tests/networkxml2confdata/leasetime-infinite.conf
> new file mode 100644
> index 000000000..52f4798e5
> --- /dev/null
> +++ b/tests/networkxml2confdata/leasetime-infinite.conf
> @@ -0,0 +1,18 @@
> +##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
> +##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:
> +##    virsh net-edit default
> +## or other application using the libvirt API.
> +##
> +## dnsmasq conf file created by libvirt
> +strict-order
> +except-interface=lo
> +bind-dynamic
> +interface=virbr0
> +dhcp-range=192.168.122.2,192.168.122.254,infinite
> +dhcp-no-override
> +dhcp-authoritative
> +dhcp-range=2001:db8:ac10:fd01::1:10,2001:db8:ac10:fd01::1:ff,64,infinite
> +dhcp-lease-max=493
> +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile
> +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts
> +enable-ra
> diff --git a/tests/networkxml2confdata/leasetime-infinite.xml b/tests/networkxml2confdata/leasetime-infinite.xml
> new file mode 100644
> index 000000000..d855978a1
> --- /dev/null
> +++ b/tests/networkxml2confdata/leasetime-infinite.xml
> @@ -0,0 +1,18 @@
> +<network>
> +  <name>default</name>
> +  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
> +  <forward dev='eth1' mode='nat'/>
> +  <bridge name='virbr0' stp='on' delay='0'/>
> +  <ip address='192.168.122.1' netmask='255.255.255.0'>
> +    <dhcp>
> +      <leasetime>0</leasetime>
> +      <range start='192.168.122.2' end='192.168.122.254'/>
> +    </dhcp>
> +  </ip>
> +  <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
> +    <dhcp>
> +      <leasetime>0</leasetime>
> +      <range start='2001:db8:ac10:fd01::1:10' end='2001:db8:ac10:fd01::1:ff'/>
> +    </dhcp>
> +  </ip>
> +</network>
> diff --git a/tests/networkxml2confdata/leasetime-minutes.conf b/tests/networkxml2confdata/leasetime-minutes.conf
> new file mode 100644
> index 000000000..37da5702f
> --- /dev/null
> +++ b/tests/networkxml2confdata/leasetime-minutes.conf
> @@ -0,0 +1,18 @@
> +##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
> +##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:
> +##    virsh net-edit default
> +## or other application using the libvirt API.
> +##
> +## dnsmasq conf file created by libvirt
> +strict-order
> +except-interface=lo
> +bind-dynamic
> +interface=virbr0
> +dhcp-range=192.168.122.2,192.168.122.254,300
> +dhcp-no-override
> +dhcp-authoritative
> +dhcp-range=2001:db8:ac10:fd01::1:10,2001:db8:ac10:fd01::1:ff,64,300
> +dhcp-lease-max=493
> +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile
> +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts
> +enable-ra
> diff --git a/tests/networkxml2confdata/leasetime-minutes.xml b/tests/networkxml2confdata/leasetime-minutes.xml
> new file mode 100644
> index 000000000..e7a27afe6
> --- /dev/null
> +++ b/tests/networkxml2confdata/leasetime-minutes.xml
> @@ -0,0 +1,18 @@
> +<network>
> +  <name>default</name>
> +  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
> +  <forward dev='eth1' mode='nat'/>
> +  <bridge name='virbr0' stp='on' delay='0'/>
> +  <ip address='192.168.122.1' netmask='255.255.255.0'>
> +    <dhcp>
> +      <leasetime unit="minutes">5</leasetime>
> +      <range start='192.168.122.2' end='192.168.122.254'/>
> +    </dhcp>
> +  </ip>
> +  <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
> +    <dhcp>
> +      <leasetime unit="minutes">5</leasetime>
> +      <range start='2001:db8:ac10:fd01::1:10' end='2001:db8:ac10:fd01::1:ff'/>
> +    </dhcp>
> +  </ip>
> +</network>
> diff --git a/tests/networkxml2confdata/leasetime-seconds.conf b/tests/networkxml2confdata/leasetime-seconds.conf
> new file mode 100644
> index 000000000..ea0845e21
> --- /dev/null
> +++ b/tests/networkxml2confdata/leasetime-seconds.conf
> @@ -0,0 +1,18 @@
> +##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
> +##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:
> +##    virsh net-edit default
> +## or other application using the libvirt API.
> +##
> +## dnsmasq conf file created by libvirt
> +strict-order
> +except-interface=lo
> +bind-dynamic
> +interface=virbr0
> +dhcp-range=192.168.122.2,192.168.122.254,125
> +dhcp-no-override
> +dhcp-authoritative
> +dhcp-range=2001:db8:ac10:fd01::1:10,2001:db8:ac10:fd01::1:ff,64,125
> +dhcp-lease-max=493
> +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile
> +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts
> +enable-ra
> diff --git a/tests/networkxml2confdata/leasetime-seconds.xml b/tests/networkxml2confdata/leasetime-seconds.xml
> new file mode 100644
> index 000000000..56b07f8ae
> --- /dev/null
> +++ b/tests/networkxml2confdata/leasetime-seconds.xml
> @@ -0,0 +1,18 @@
> +<network>
> +  <name>default</name>
> +  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
> +  <forward dev='eth1' mode='nat'/>
> +  <bridge name='virbr0' stp='on' delay='0'/>
> +  <ip address='192.168.122.1' netmask='255.255.255.0'>
> +    <dhcp>
> +      <leasetime unit="seconds">125</leasetime>
> +      <range start='192.168.122.2' end='192.168.122.254'/>
> +    </dhcp>
> +  </ip>
> +  <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
> +    <dhcp>
> +      <leasetime unit="seconds">125</leasetime>
> +      <range start='2001:db8:ac10:fd01::1:10' end='2001:db8:ac10:fd01::1:ff'/>
> +    </dhcp>
> +  </ip>
> +</network>
> diff --git a/tests/networkxml2confdata/leasetime.conf b/tests/networkxml2confdata/leasetime.conf
> new file mode 100644
> index 000000000..b754c3ffb
> --- /dev/null
> +++ b/tests/networkxml2confdata/leasetime.conf
> @@ -0,0 +1,18 @@
> +##WARNING:  THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
> +##OVERWRITTEN AND LOST.  Changes to this configuration should be made using:
> +##    virsh net-edit default
> +## or other application using the libvirt API.
> +##
> +## dnsmasq conf file created by libvirt
> +strict-order
> +except-interface=lo
> +bind-dynamic
> +interface=virbr0
> +dhcp-range=192.168.122.2,192.168.122.254,122
> +dhcp-no-override
> +dhcp-authoritative
> +dhcp-range=2001:db8:ac10:fd01::1:10,2001:db8:ac10:fd01::1:ff,64,121
> +dhcp-lease-max=493
> +dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile
> +addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts
> +enable-ra
> diff --git a/tests/networkxml2confdata/leasetime.xml b/tests/networkxml2confdata/leasetime.xml
> new file mode 100644
> index 000000000..fdbb15fc0
> --- /dev/null
> +++ b/tests/networkxml2confdata/leasetime.xml
> @@ -0,0 +1,18 @@
> +<network>
> +  <name>default</name>
> +  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
> +  <forward dev='eth1' mode='nat'/>
> +  <bridge name='virbr0' stp='on' delay='0'/>
> +  <ip address='192.168.122.1' netmask='255.255.255.0'>
> +    <dhcp>
> +      <leasetime>122</leasetime>
> +      <range start='192.168.122.2' end='192.168.122.254'/>
> +    </dhcp>
> +  </ip>
> +  <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
> +    <dhcp>
> +      <leasetime>121</leasetime>
> +      <range start='2001:db8:ac10:fd01::1:10' end='2001:db8:ac10:fd01::1:ff'/>
> +    </dhcp>
> +  </ip>
> +</network>
> diff --git a/tests/networkxml2confdata/nat-network-dns-srv-record-minimal.hostsfile b/tests/networkxml2confdata/nat-network-dns-srv-record-minimal.hostsfile
> new file mode 100644
> index 000000000..deb3f00ac
> --- /dev/null
> +++ b/tests/networkxml2confdata/nat-network-dns-srv-record-minimal.hostsfile
> @@ -0,0 +1,2 @@
> +00:16:3e:77:e2:ed,192.168.122.10,a.example.com
> +00:16:3e:3e:a9:1a,192.168.122.11,b.example.com
> diff --git a/tests/networkxml2confdata/nat-network-dns-srv-record.hostsfile b/tests/networkxml2confdata/nat-network-dns-srv-record.hostsfile
> new file mode 100644
> index 000000000..deb3f00ac
> --- /dev/null
> +++ b/tests/networkxml2confdata/nat-network-dns-srv-record.hostsfile
> @@ -0,0 +1,2 @@
> +00:16:3e:77:e2:ed,192.168.122.10,a.example.com
> +00:16:3e:3e:a9:1a,192.168.122.11,b.example.com
> diff --git a/tests/networkxml2confdata/nat-network-dns-txt-record.hostsfile b/tests/networkxml2confdata/nat-network-dns-txt-record.hostsfile
> new file mode 100644
> index 000000000..deb3f00ac
> --- /dev/null
> +++ b/tests/networkxml2confdata/nat-network-dns-txt-record.hostsfile
> @@ -0,0 +1,2 @@
> +00:16:3e:77:e2:ed,192.168.122.10,a.example.com
> +00:16:3e:3e:a9:1a,192.168.122.11,b.example.com
> diff --git a/tests/networkxml2confdata/nat-network-name-with-quotes.hostsfile b/tests/networkxml2confdata/nat-network-name-with-quotes.hostsfile
> new file mode 100644
> index 000000000..deb3f00ac
> --- /dev/null
> +++ b/tests/networkxml2confdata/nat-network-name-with-quotes.hostsfile
> @@ -0,0 +1,2 @@
> +00:16:3e:77:e2:ed,192.168.122.10,a.example.com
> +00:16:3e:3e:a9:1a,192.168.122.11,b.example.com
> diff --git a/tests/networkxml2confdata/nat-network.hostsfile b/tests/networkxml2confdata/nat-network.hostsfile
> new file mode 100644
> index 000000000..deb3f00ac
> --- /dev/null
> +++ b/tests/networkxml2confdata/nat-network.hostsfile
> @@ -0,0 +1,2 @@
> +00:16:3e:77:e2:ed,192.168.122.10,a.example.com
> +00:16:3e:3e:a9:1a,192.168.122.11,b.example.com
> diff --git a/tests/networkxml2confdata/ptr-domains-auto.hostsfile b/tests/networkxml2confdata/ptr-domains-auto.hostsfile
> new file mode 100644
> index 000000000..deb3f00ac
> --- /dev/null
> +++ b/tests/networkxml2confdata/ptr-domains-auto.hostsfile
> @@ -0,0 +1,2 @@
> +00:16:3e:77:e2:ed,192.168.122.10,a.example.com
> +00:16:3e:3e:a9:1a,192.168.122.11,b.example.com
> diff --git a/tests/networkxml2conftest.c b/tests/networkxml2conftest.c
> index ab3c13aa0..15f783fb1 100644
> --- a/tests/networkxml2conftest.c
> +++ b/tests/networkxml2conftest.c
> @@ -19,9 +19,13 @@
>  #define VIR_FROM_THIS VIR_FROM_NONE
>
>  static int
> -testCompareXMLToConfFiles(const char *inxml, const char *outconf, dnsmasqCapsPtr caps)
> +testCompareXMLToConfFiles(const char *inxml,
> +                          const char *outconf,
> +                          const char *outhostsfile,
> +                          dnsmasqCapsPtr caps)
>  {
> -    char *actual = NULL;
> +    char *actualconf = NULL;
> +    char *actualhosts = NULL;
>      int ret = -1;
>      virNetworkDefPtr dev = NULL;
>      virNetworkObjPtr obj = NULL;
> @@ -41,7 +45,11 @@ testCompareXMLToConfFiles(const char *inxml, const char *outconf, dnsmasqCapsPtr
>      if (dctx == NULL)
>          goto fail;
>
> -    if (networkDnsmasqConfContents(obj, pidfile, &actual, dctx, caps) < 0)
> +    if (networkDnsmasqConfContents(obj, pidfile, &actualconf, &actualhosts,
> +                        dctx, caps) < 0)
> +        goto fail;
> +
> +    if (virTestCompareToFile(actualconf, outconf) < 0)
>          goto fail;
>
>      /* Any changes to this function ^^ should be reflected here too. */
> @@ -57,13 +65,27 @@ testCompareXMLToConfFiles(const char *inxml, const char *outconf, dnsmasqCapsPtr
>      tmp = NULL;
>  #endif
>
> -    if (virTestCompareToFile(actual, outconf) < 0)
> +    if (virFileExists(outhostsfile)) {
> +        if (!actualhosts) {
> +            fprintf(stderr,
> +                    "%s: hostsfile exists but the configuration did not specify any host",
> +                    outhostsfile);
> +            goto fail;
> +        } else if (virTestCompareToFile(actualhosts, outhostsfile) < 0) {
> +            goto fail;
> +        }
> +    } else if (actualhosts) {
> +        fprintf(stderr,
> +                "%s: file does not exist but actual data was expected",
> +                outhostsfile);
>          goto fail;
> +    }
>
>      ret = 0;
>
>   fail:
> -    VIR_FREE(actual);
> +    VIR_FREE(actualconf);
> +    VIR_FREE(actualhosts);
>      VIR_FREE(pidfile);
>      virCommandFree(cmd);
>      virObjectUnref(obj);
> @@ -83,19 +105,23 @@ testCompareXMLToConfHelper(const void *data)
>      const testInfo *info = data;
>      char *inxml = NULL;
>      char *outconf = NULL;
> +    char *outhostsfile = NULL;
>
>      if (virAsprintf(&inxml, "%s/networkxml2confdata/%s.xml",
>                      abs_srcdir, info->name) < 0 ||
>          virAsprintf(&outconf, "%s/networkxml2confdata/%s.conf",
> +                    abs_srcdir, info->name) < 0 ||
> +        virAsprintf(&outhostsfile, "%s/networkxml2confdata/%s.hostsfile",
>                      abs_srcdir, info->name) < 0) {
>          goto cleanup;
>      }
>
> -    result = testCompareXMLToConfFiles(inxml, outconf, info->caps);
> +    result = testCompareXMLToConfFiles(inxml, outconf, outhostsfile, info->caps);
>
>   cleanup:
>      VIR_FREE(inxml);
>      VIR_FREE(outconf);
> +    VIR_FREE(outhostsfile);
>
>      return result;
>  }
> @@ -143,6 +169,13 @@ mymain(void)
>      DO_TEST("dhcp6-nat-network", dhcpv6);
>      DO_TEST("dhcp6host-routed-network", dhcpv6);
>      DO_TEST("ptr-domains-auto", dhcpv6);
> +    DO_TEST("leasetime", dhcpv6);
> +    DO_TEST("leasetime-seconds", dhcpv6);
> +    DO_TEST("leasetime-hours", dhcpv6);
> +    DO_TEST("leasetime-minutes", dhcpv6);
> +    DO_TEST("leasetime-hours", dhcpv6);
> +    DO_TEST("leasetime-days", dhcpv6);
> +    DO_TEST("leasetime-infinite", dhcpv6);
>
>      virObjectUnref(dhcpv6);
>      virObjectUnref(full);
> --
> 2.13.0
>



-- 
Cheers,
Alberto Ruiz




More information about the libvir-list mailing list