Hey Laine, Have some time to review this? 2017-06-23 1:44 GMT+01:00 <aruiz@xxxxxxxxx>: > From: Alberto Ruiz <aruiz@xxxxxxxxx> > > 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list