[libvirt] [PATCH] Fix compile error for stable 1.2.9
by Yang hongyang
Seems a backport miss. An extra member is passed to struct
virLXCBasicMountInfo.
Signed-off-by: Yang hongyang <hongyang.yang(a)easystack.cn>
---
src/lxc/lxc_container.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index 28dabec..1c65fa9 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -760,7 +760,7 @@ typedef struct {
static const virLXCBasicMountInfo lxcBasicMounts[] = {
{ "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false },
- { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
+ { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false },
{ "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false },
{ "securityfs", "/sys/kernel/security", "securityfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, true, true },
#if WITH_SELINUX
--
1.7.1
1 year, 1 month
[libvirt] Supporting vhost-net and macvtap in libvirt for QEMU
by Anthony Liguori
Disclaimer: I am neither an SR-IOV nor a vhost-net expert, but I've CC'd
people that are who can throw tomatoes at me for getting bits wrong :-)
I wanted to start a discussion about supporting vhost-net in libvirt.
vhost-net has not yet been merged into qemu but I expect it will be soon
so it's a good time to start this discussion.
There are two modes worth supporting for vhost-net in libvirt. The
first mode is where vhost-net backs to a tun/tap device. This is
behaves in very much the same way that -net tap behaves in qemu today.
Basically, the difference is that the virtio backend is in the kernel
instead of in qemu so there should be some performance improvement.
Current, libvirt invokes qemu with -net tap,fd=X where X is an already
open fd to a tun/tap device. I suspect that after we merge vhost-net,
libvirt could support vhost-net in this mode by just doing -net
vhost,fd=X. I think the only real question for libvirt is whether to
provide a user visible switch to use vhost or to just always use vhost
when it's available and it makes sense. Personally, I think the later
makes sense.
The more interesting invocation of vhost-net though is one where the
vhost-net device backs directly to a physical network card. In this
mode, vhost should get considerably better performance than the current
implementation. I don't know the syntax yet, but I think it's
reasonable to assume that it will look something like -net
tap,dev=eth0. The effect will be that eth0 is dedicated to the guest.
On most modern systems, there is a small number of network devices so
this model is not all that useful except when dealing with SR-IOV
adapters. In that case, each physical device can be exposed as many
virtual devices (VFs). There are a few restrictions here though. The
biggest is that currently, you can only change the number of VFs by
reloading a kernel module so it's really a parameter that must be set at
startup time.
I think there are a few ways libvirt could support vhost-net in this
second mode. The simplest would be to introduce a new tag similar to
<source network='br0'>. In fact, if you probed the device type for the
network parameter, you could probably do something like <source
network='eth0'> and have it Just Work.
Another model would be to have libvirt see an SR-IOV adapter as a
network pool whereas it handled all of the VF management. Considering
how inflexible SR-IOV is today, I'm not sure whether this is the best model.
Has anyone put any more thought into this problem or how this should be
modeled in libvirt? Michael, could you share your current thinking for
-net syntax?
--
Regards,
Anthony Liguori
1 year, 1 month
[libvirt] [PATCH] leasetime support per <dhcp> and <host>
by Alberto Ruiz
Support for custom dhcp wide and per host leasetime.
It is specified as a child tag for <dhcp>:
<dhcp>
<leasetime>24h</leasetime>
...
</dhcp>
And as an attribute for <host>:
<dhcp>
<host leasetime="7d" .../>
</dhcp>
These are the different notations:
-1 (infinite/unlimited lease)
120 (seconds are the default unit, 120 seconds is the minimum, if less is
specified it will use 120)
300s (seconds)
5m (minutes)
24h (hours)
7d (days)
---
docs/schemas/basictypes.rng | 5 +
docs/schemas/network.rng | 8 ++
src/conf/network_conf.c | 86 +++++++++++++-
src/conf/network_conf.h | 4 +-
src/libvirt_private.syms | 1 +
src/network/bridge_driver.c | 132
+++++++++++++++++----
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 | 17 +++
tests/networkxml2confdata/leasetime-days.xml | 18 +++
tests/networkxml2confdata/leasetime-host.conf | 16 +++
tests/networkxml2confdata/leasetime-host.hostsfile | 6 +
tests/networkxml2confdata/leasetime-host.xml | 22 ++++
tests/networkxml2confdata/leasetime-hours.conf | 17 +++
tests/networkxml2confdata/leasetime-hours.xml | 18 +++
tests/networkxml2confdata/leasetime-infinite.conf | 17 +++
tests/networkxml2confdata/leasetime-infinite.xml | 18 +++
tests/networkxml2confdata/leasetime-minutes.conf | 17 +++
tests/networkxml2confdata/leasetime-minutes.xml | 18 +++
tests/networkxml2confdata/leasetime-seconds.conf | 17 +++
tests/networkxml2confdata/leasetime-seconds.xml | 18 +++
tests/networkxml2confdata/leasetime.conf | 17 +++
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 +
tests/networkxml2conftest.c | 47 ++++++--
33 files changed, 597 insertions(+), 78 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-host.conf
create mode 100644 tests/networkxml2confdata/leasetime-host.hostsfile
create mode 100644 tests/networkxml2confdata/leasetime-host.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
diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
index 1b4f980..11fbe2b 100644
--- a/docs/schemas/basictypes.rng
+++ b/docs/schemas/basictypes.rng
@@ -518,4 +518,9 @@
</element>
</define>
+ <define name="leaseTime">
+ <data type="string">
+ <param name="pattern">-?[0-9]*[smhd]?</param>
+ </data>
+ </define>
</grammar>
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index 1a18e64..e6ddb63 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -340,6 +340,11 @@
<!-- Define the range(s) of IP addresses that the DHCP
server should hand out -->
<element name="dhcp">
+ <optional>
+ <element name="leasetime">
+ <ref name="leaseTime"/>
+ </element>
+ </optional>
<zeroOrMore>
<element name="range">
<attribute name="start"><ref
name="ipAddr"/></attribute>
@@ -361,6 +366,9 @@
<attribute name="name"><text/></attribute>
</choice>
<attribute name="ip"><ref name="ipAddr"/></attribute>
+ <optional>
+ <attribute name="leasetime"><ref
name="leaseTime"/></attribute>
+ </optional>
</element>
</zeroOrMore>
<optional>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index aa39776..bcc4bbb 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -30,6 +30,8 @@
#include <fcntl.h>
#include <string.h>
#include <dirent.h>
+#include <stdlib.h>
+#include <inttypes.h>
#include "virerror.h"
#include "datatypes.h"
@@ -911,16 +913,83 @@ virSocketAddrRangeParseXML(const char *networkName,
return ret;
}
+static int64_t
+virNetworkDHCPDefGetLeaseTime (xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
+ const char* query,
+ bool *error)
+{
+ int64_t multiplier = 1, result = -1;
+ char *leaseString;
+ xmlNodePtr save;
+ size_t len;
+
+ *error = 0;
+
+ save = ctxt->node;
+ ctxt->node = node;
+
+ leaseString = virXPathString (query, ctxt);
+
+ /* If value is not present we set the value to -2 */
+ if (leaseString == NULL) {
+ result = -2;
+ goto cleanup;
+ }
+
+ len = strlen (leaseString) - 1;
+
+ if (leaseString[len] == 'm')
+ multiplier = 60;
+ else if (leaseString[len] == 'h')
+ multiplier = 60 * 60;
+ else if (leaseString[len] == 'd')
+ multiplier = 60 * 60 * 24;
+
+ /* Remove the time unit suffix */
+ if (leaseString[len] < 48 || leaseString[len] > 57)
+ leaseString[len] = '\0';
+
+ errno = 0;
+ result = (int64_t) strtoll((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);
+ *error = 1;
+ goto cleanup;
+ }
+
+ result = result * multiplier;
+
+ if (result > UINT32_MAX || result < -1) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("<leasetime> value cannot be greater than the
equivalent of %" PRIo32 " seconds or less than -1: %" PRId64),
+ UINT32_MAX, result);
+ *error = 1;
+ }
+
+cleanup:
+ VIR_FREE(leaseString);
+ ctxt->node = save;
+ return result;
+}
+
static int
virNetworkDHCPHostDefParseXML(const char *networkName,
virNetworkIPDefPtr def,
xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
virNetworkDHCPHostDefPtr host,
bool partialOkay)
{
char *mac = NULL, *name = NULL, *ip = NULL, *id = NULL;
virMacAddr addr;
virSocketAddr inaddr;
+ int64_t leasetime;
+ bool error;
int ret = -1;
mac = virXMLPropString(node, "mac");
@@ -1013,6 +1082,10 @@ virNetworkDHCPHostDefParseXML(const char
*networkName,
}
}
+ leasetime = virNetworkDHCPDefGetLeaseTime (node, ctxt,
"string(./@leasetime)", &error);
+ if (error)
+ goto cleanup;
+
host->mac = mac;
mac = NULL;
host->id = id;
@@ -1021,6 +1094,7 @@ virNetworkDHCPHostDefParseXML(const char *networkName,
name = NULL;
if (ip)
host->ip = inaddr;
+ host->leasetime = leasetime;
ret = 0;
cleanup:
@@ -1034,9 +1108,11 @@ virNetworkDHCPHostDefParseXML(const char
*networkName,
static int
virNetworkDHCPDefParseXML(const char *networkName,
xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
virNetworkIPDefPtr def)
{
int ret = -1;
+ bool error;
xmlNodePtr cur;
virSocketAddrRange range;
virNetworkDHCPHostDef host;
@@ -1044,6 +1120,10 @@ virNetworkDHCPDefParseXML(const char *networkName,
memset(&range, 0, sizeof(range));
memset(&host, 0, sizeof(host));
+ def->leasetime = virNetworkDHCPDefGetLeaseTime (node, ctxt,
"string(./leasetime/text())", &error);
+ if (error)
+ goto cleanup;
+
cur = node->children;
while (cur != NULL) {
if (cur->type == XML_ELEMENT_NODE &&
@@ -1057,7 +1137,7 @@ virNetworkDHCPDefParseXML(const char *networkName,
} else if (cur->type == XML_ELEMENT_NODE &&
xmlStrEqual(cur->name, BAD_CAST "host")) {
- if (virNetworkDHCPHostDefParseXML(networkName, def, cur,
+ if (virNetworkDHCPHostDefParseXML(networkName, def, cur, ctxt,
&host, false) < 0)
goto cleanup;
if (VIR_APPEND_ELEMENT(def->hosts, def->nhosts, host) < 0)
@@ -1607,7 +1687,7 @@ virNetworkIPDefParseXML(const char *networkName,
while (cur != NULL) {
if (cur->type == XML_ELEMENT_NODE &&
xmlStrEqual(cur->name, BAD_CAST "dhcp")) {
- if (virNetworkDHCPDefParseXML(networkName, cur, def) < 0)
+ if (virNetworkDHCPDefParseXML(networkName, cur, ctxt, def) < 0)
goto cleanup;
} else if (cur->type == XML_ELEMENT_NODE &&
xmlStrEqual(cur->name, BAD_CAST "tftp")) {
@@ -3659,7 +3739,7 @@ virNetworkDefUpdateIPDHCPHost(virNetworkDefPtr def,
if (!ipdef)
goto cleanup;
- if (virNetworkDHCPHostDefParseXML(def->name, ipdef, ctxt->node,
+ if (virNetworkDHCPHostDefParseXML(def->name, ipdef, ctxt->node, ctxt,
&host, partialOkay) < 0)
goto cleanup;
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 3b227db..df687df 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -96,6 +96,7 @@ struct _virNetworkDHCPHostDef {
char *id;
char *name;
virSocketAddr ip;
+ int64_t leasetime;
};
typedef struct _virNetworkDNSTxtDef virNetworkDNSTxtDef;
@@ -170,7 +171,8 @@ struct _virNetworkIPDef {
char *tftproot;
char *bootfile;
virSocketAddr bootserver;
- };
+ int64_t leasetime;
+};
typedef struct _virNetworkForwardIfDef virNetworkForwardIfDef;
typedef virNetworkForwardIfDef *virNetworkForwardIfDefPtr;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index b88e903..84fb62e 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1497,6 +1497,7 @@ dnsmasqCapsRefresh;
dnsmasqContextFree;
dnsmasqContextNew;
dnsmasqDelete;
+dnsmasqDhcpHostsToString;
dnsmasqReload;
dnsmasqSave;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 7b99aca..dccf743 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
@@ -859,30 +861,6 @@ networkKillDaemon(pid_t pid, const char *daemonName,
const char *networkName)
return ret;
}
-/* the following does not build a file, it builds a list
- * which is later saved into a file
- */
-
-static int
-networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
- virNetworkIPDefPtr ipdef)
-{
- size_t i;
- bool ipv6 = false;
-
- if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
- ipv6 = true;
- for (i = 0; i < ipdef->nhosts; i++) {
- 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)
@@ -903,11 +881,93 @@ networkBuildDnsmasqHostsList(dnsmasqContext *dctx,
return 0;
}
+/* translates the leasetime value into a dnsmasq configuration string for
dhcp-range/host */
+static char *
+networkDnsmasqConfLeaseValueToString (int64_t leasetime)
+{
+ char *result = NULL;
+ virBuffer leasebuf = VIR_BUFFER_INITIALIZER;
+
+ /* Leasetime parameter set on the XML */
+ /* Less than -1 means there was no value set */
+ if (leasetime < -1) {
+ virBufferAsprintf(&leasebuf, "%s", "");
+ }
+ /* -1 means no expiration */
+ else if (leasetime == -1)
+ virBufferAsprintf(&leasebuf, ",infinite");
+ /* Minimum expiry value is 120 */
+ /* TODO: Discuss if we should up as we do here or just forward
whatever value to dnsmasq */
+ else if (leasetime < 120)
+ virBufferAsprintf(&leasebuf, ",120");
+ /* DHCP value for lease time is a unsigned four octect integer */
+ else if (leasetime <= UINT32_MAX)
+ virBufferAsprintf(&leasebuf, ",%" PRId64, leasetime);
+ /* TODO: Discuss the use of "deprecated" for ipv6*/
+ /* TODO: Discuss what is the default value that we want as dnsmasq's
is 1 hour */
+ /* TODO: Discuss what to do if value exceeds maximum, use default
value for now */
+ else {
+ virBufferAsprintf(&leasebuf, "%s", "");
+ }
+
+ result = virBufferContentAndReset(&leasebuf);
+ virBufferFreeAndReset (&leasebuf);
+
+ return result;
+}
+
+/* the following does not build a file, it builds a list
+ * which is later saved into a file
+ */
+
+static int
+networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
+ virNetworkIPDefPtr ipdef)
+{
+ int ret = -1;
+ size_t i;
+ bool ipv6 = false;
+ char *leasetime = networkDnsmasqConfLeaseValueTo
String(ipdef->leasetime);
+
+ if (!leasetime)
+ goto cleanup;
+
+ if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
+ ipv6 = true;
+ for (i = 0; i < ipdef->nhosts; i++) {
+ virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
+ if (VIR_SOCKET_ADDR_VALID(&host->ip)) {
+ /* If the host has its own leasetime we get its specific
string */
+ if (host->leasetime > -2) {
+ char *hostlease = networkDnsmasqConfLeaseValueTo
String(host->leasetime);
+ if (!hostlease)
+ goto cleanup;
+ if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
+ host->name, host->id, hostlease,
ipv6) < 0) {
+ VIR_FREE(hostlease);
+ goto cleanup;
+ }
+ VIR_FREE(hostlease);
+ } else {
+ /* Otherwise we use the leasetime from dhcp */
+ if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
+ host->name, host->id, leasetime,
ipv6) < 0)
+ goto cleanup;
+ }
+ }
+ }
+
+ ret = 0;
+cleanup:
+ VIR_FREE(leasetime);
+ return ret;
+}
int
networkDnsmasqConfContents(virNetworkObjPtr network,
const char *pidfile,
char **configstr,
+ char **hostsfilestr,
dnsmasqContext *dctx,
dnsmasqCapsPtr caps ATTRIBUTE_UNUSED)
{
@@ -1213,6 +1273,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)))
@@ -1220,12 +1281,22 @@ 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);
+ 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,
@@ -1256,6 +1327,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)
@@ -1355,7 +1435,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 ff7f921..c653c50 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 1b78c1f..94c9a3b 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 f47bea3..1795bc8 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 0000000..de659b9
--- /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 0000000..9dfb172
--- /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 0000000..de659b9
--- /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 0000000..9501e2f
--- /dev/null
+++ b/tests/networkxml2confdata/leasetime-days.conf
@@ -0,0 +1,17 @@
+##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-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 0000000..1a507d5
--- /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>1d</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>1d</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-host.conf
b/tests/networkxml2confdata/leasetime-host.conf
new file mode 100644
index 0000000..7bd2054
--- /dev/null
+++ b/tests/networkxml2confdata/leasetime-host.conf
@@ -0,0 +1,16 @@
+##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
+srv-host=_name._tcp
+dhcp-range=192.168.122.2,192.168.122.254
+dhcp-no-override
+dhcp-lease-max=253
+dhcp-hostsfile=/var/lib/libvirt/dnsmasq/default.hostsfile
+addn-hosts=/var/lib/libvirt/dnsmasq/default.addnhosts
diff --git a/tests/networkxml2confdata/leasetime-host.hostsfile
b/tests/networkxml2confdata/leasetime-host.hostsfile
new file mode 100644
index 0000000..fd20ca2
--- /dev/null
+++ b/tests/networkxml2confdata/leasetime-host.hostsfile
@@ -0,0 +1,6 @@
+00:16:3e:3e:a9:01,192.168.122.11,a.example.com,3600
+00:16:3e:3e:a9:02,192.168.122.12,b.example.com,3600
+00:16:3e:3e:a9:03,192.168.122.13,c.example.com,3600
+00:16:3e:3e:a9:04,192.168.122.14,d.example.com,86400
+00:16:3e:3e:a9:05,192.168.122.15,e.example.com,3600
+00:16:3e:3e:a9:06,192.168.122.16,f.example.com,infinite
diff --git a/tests/networkxml2confdata/leasetime-host.xml
b/tests/networkxml2confdata/leasetime-host.xml
new file mode 100644
index 0000000..276d3e5
--- /dev/null
+++ b/tests/networkxml2confdata/leasetime-host.xml
@@ -0,0 +1,22 @@
+<network>
+ <name>default</name>
+ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+ <forward dev='eth1' mode='nat'>
+ <interface dev='eth1'/>
+ </forward>
+ <bridge name='virbr0' stp='on' delay='0'/>
+ <dns>
+ <srv service='name' protocol='tcp'/>
+ </dns>
+ <ip address='192.168.122.1' netmask='255.255.255.0'>
+ <dhcp>
+ <range start='192.168.122.2' end='192.168.122.254'/>
+ <host mac='00:16:3e:3e:a9:1a' name='a.example.com'
ip='192.168.122.11' leasetime="3600s"/>
+ <host mac='00:16:3e:3e:a9:1b' name='b.example.com'
ip='192.168.122.12' leasetime="60m"/>
+ <host mac='00:16:3e:3e:a9:1c' name='c.example.com'
ip='192.168.122.13' leasetime="1h"/>
+ <host mac='00:16:3e:3e:a9:1d' name='d.example.com'
ip='192.168.122.14' leasetime="1d"/>
+ <host mac='00:16:3e:3e:a9:1e' name='e.example.com'
ip='192.168.122.15' leasetime="3600"/>
+ <host mac='00:16:3e:3e:a9:1f' name='f.example.com'
ip='192.168.122.16' leasetime="-1"/>
+ </dhcp>
+ </ip>
+</network>
diff --git a/tests/networkxml2confdata/leasetime-hours.conf
b/tests/networkxml2confdata/leasetime-hours.conf
new file mode 100644
index 0000000..021a769
--- /dev/null
+++ b/tests/networkxml2confdata/leasetime-hours.conf
@@ -0,0 +1,17 @@
+##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-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 0000000..36dc600
--- /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>1h</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>1h</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 0000000..cc21135
--- /dev/null
+++ b/tests/networkxml2confdata/leasetime-infinite.conf
@@ -0,0 +1,17 @@
+##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-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 0000000..bc8740e
--- /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>-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>-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-minutes.conf
b/tests/networkxml2confdata/leasetime-minutes.conf
new file mode 100644
index 0000000..db68895
--- /dev/null
+++ b/tests/networkxml2confdata/leasetime-minutes.conf
@@ -0,0 +1,17 @@
+##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-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 0000000..7c1df25
--- /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>5m</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>5m</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 0000000..635896b
--- /dev/null
+++ b/tests/networkxml2confdata/leasetime-seconds.conf
@@ -0,0 +1,17 @@
+##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-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 0000000..dcb3f91
--- /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>125s</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>125s</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 0000000..72a2f69
--- /dev/null
+++ b/tests/networkxml2confdata/leasetime.conf
@@ -0,0 +1,17 @@
+##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-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 0000000..fdbb15f
--- /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 0000000..deb3f00
--- /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 0000000..deb3f00
--- /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 0000000..deb3f00
--- /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 0000000..deb3f00
--- /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 0000000..deb3f00
--- /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/networkxml2conftest.c b/tests/networkxml2conftest.c
index 65a0e32..8e1f8be 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,17 +45,30 @@ testCompareXMLToConfFiles(const char *inxml, const char
*outconf, dnsmasqCapsPtr
if (dctx == NULL)
goto fail;
- if (networkDnsmasqConfContents(obj, pidfile, &actual,
+ if (networkDnsmasqConfContents(obj, pidfile, &actualconf, &actualhosts,
dctx, caps) < 0)
goto fail;
- if (virTestCompareToFile(actual, outconf) < 0)
+ if (virTestCompareToFile(actualconf, outconf) < 0)
goto fail;
+ 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);
@@ -70,20 +87,24 @@ testCompareXMLToConfHelper(const void *data)
int result = -1;
const testInfo *info = data;
char *inxml = NULL;
- char *outxml = NULL;
+ char *outconf = NULL;
+ char *outhostsfile = NULL;
if (virAsprintf(&inxml, "%s/networkxml2confdata/%s.xml",
abs_srcdir, info->name) < 0 ||
- virAsprintf(&outxml, "%s/networkxml2confdata/%s.conf",
+ 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, outxml, info->caps);
+ result = testCompareXMLToConfFiles(inxml, outconf, outhostsfile,
info->caps);
cleanup:
VIR_FREE(inxml);
- VIR_FREE(outxml);
+ VIR_FREE(outconf);
+ VIR_FREE(outhostsfile);
return result;
}
@@ -129,6 +150,14 @@ mymain(void)
DO_TEST("dhcp6-network", dhcpv6);
DO_TEST("dhcp6-nat-network", dhcpv6);
DO_TEST("dhcp6host-routed-network", 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);
+ DO_TEST("leasetime-host", dhcpv6);
virObjectUnref(dhcpv6);
virObjectUnref(full);
--
2.9.3
--
Alberto Ruiz
Associate Engineering Manager - Desktop Management Tools
Red Hat
7 years, 8 months
[libvirt] [PATCH] node_device: Check return value for udev_new()
by Marc Hartmayer
The comment was actually wrong as
https://www.freedesktop.org/software/systemd/man/udev_new.html
mentions that on failure NULL is returned.
Signed-off-by: Marc Hartmayer <mhartmay(a)linux.vnet.ibm.com>
Reviewed-by: Bjoern Walk <bwalk(a)linux.vnet.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy(a)linux.vnet.ibm.com>
---
src/node_device/node_device_udev.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/src/node_device/node_device_udev.c b/src/node_device/node_device_udev.c
index 4b81312..4b0a875 100644
--- a/src/node_device/node_device_udev.c
+++ b/src/node_device/node_device_udev.c
@@ -1491,13 +1491,11 @@ static int nodeStateInitialize(bool privileged,
if (udevPCITranslateInit(privileged) < 0)
goto cleanup;
- /*
- * http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/libudev-udev...
- *
- * indicates no return value other than success, so we don't check
- * its return value.
- */
udev = udev_new();
+ if (!udev) {
+ virReportOOMError();
+ goto cleanup;
+ }
#if HAVE_UDEV_LOGGING
/* cast to get rid of missing-format-attribute warning */
udev_set_log_fn(udev, (udevLogFunctionPtr) udevLogFunction);
--
2.5.5
7 years, 10 months
[libvirt] [RFC PATCH 00/10] introduce push backups
by Nikolay Shirokovskiy
Push backup is a backup when hypervisor itself copy backup
data to destination in contrast to pull backup when hypervisor
exports backup data thru some interface and mgmt itself make
a copy.
This patch series basically adds API and remote/qemu implementation
of backup creation and correspondent backup xml description definition.
Just like other blockjobs backup creation is asynchronous. That
is creation is merely a backup start and client should track
backup error/completion thru blockjob events. Another option
is to make backup synchronus operation. AFAIU on this way we
have to make backup asynchronus job and thus make all modifying
commands unavailable during backup. This makes backup rather
obtrusive operation which is not convinient.
Backup xml desription follows closely snapshot one and
is described in more details in definition patch [1].
Nikolay Shirokovskiy (10):
api: add API to create backup
add driver based implementation of backup API
remote: add backup API
qemu: monitor: add backup command
misc: add backup block job type
conf: add backup definition [1]
qemu: add qemuDomainBackupCreateXML implementation
qemu: check backup destination before start
qemu: prepare backup destination
virsh: add create backup command
daemon/remote.c | 8 +
examples/object-events/event-test.c | 3 +
include/libvirt/libvirt-domain-backup.h | 59 +++++++
include/libvirt/libvirt-domain.h | 3 +
include/libvirt/libvirt.h | 1 +
include/libvirt/virterror.h | 2 +
po/POTFILES.in | 2 +
src/Makefile.am | 3 +
src/access/viraccessperm.c | 3 +-
src/access/viraccessperm.h | 6 +
src/conf/backup_conf.c | 294 ++++++++++++++++++++++++++++++++
src/conf/backup_conf.h | 69 ++++++++
src/conf/domain_conf.c | 2 +-
src/datatypes.c | 60 +++++++
src/datatypes.h | 29 ++++
src/driver-hypervisor.h | 6 +
src/libvirt-domain-backup.c | 203 ++++++++++++++++++++++
src/libvirt_private.syms | 9 +
src/libvirt_public.syms | 10 ++
src/qemu/qemu_conf.h | 1 +
src/qemu/qemu_domain.c | 14 ++
src/qemu/qemu_domain.h | 2 +
src/qemu/qemu_driver.c | 249 +++++++++++++++++++++++++++
src/qemu/qemu_monitor.c | 13 ++
src/qemu/qemu_monitor.h | 5 +
src/qemu/qemu_monitor_json.c | 36 ++++
src/qemu/qemu_monitor_json.h | 6 +
src/remote/remote_driver.c | 7 +
src/remote/remote_protocol.x | 24 ++-
src/rpc/gendispatch.pl | 29 +++-
src/util/virerror.c | 6 +
tools/Makefile.am | 1 +
tools/virsh-backup.c | 101 +++++++++++
tools/virsh-backup.h | 29 ++++
tools/virsh-domain.c | 3 +-
tools/virsh.c | 2 +
tools/virsh.h | 1 +
37 files changed, 1290 insertions(+), 11 deletions(-)
create mode 100644 include/libvirt/libvirt-domain-backup.h
create mode 100644 src/conf/backup_conf.c
create mode 100644 src/conf/backup_conf.h
create mode 100644 src/libvirt-domain-backup.c
create mode 100644 tools/virsh-backup.c
create mode 100644 tools/virsh-backup.h
--
1.8.3.1
7 years, 10 months
[libvirt] [PATCH] qemu: Filter ARAT CPU feature from host-model
by Jiri Denemark
ARAT feature was first introduced in QEMU 2.4.0, which means host-model
CPU mode is unusable with QEMU < 2.4.0 on any host CPU which supports
ARAT. Let's not include this feature in host-model CPUs unless a user
explicitly asks for it.
Signed-off-by: Jiri Denemark <jdenemar(a)redhat.com>
---
Notes:
We will do this properly in the future since we will ask QEMU what CPU
features it understands and what it thinks about host CPU. However, the
required QMP interface is not upstream yet.
src/qemu/qemu_capabilities.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index cfd090c3f..2da4c76ab 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -2959,7 +2959,8 @@ virQEMUCapsCPUFilterFeatures(const char *name,
{
if (STREQ(name, "cmt") ||
STREQ(name, "mbm_total") ||
- STREQ(name, "mbm_local"))
+ STREQ(name, "mbm_local") ||
+ STREQ(name, "arat"))
return false;
return true;
--
2.11.0.rc2
7 years, 10 months
[libvirt] [PATCHv2] qemu: Emit domain events for all virtio-serial channels
by Matt Broadstone
Presently domain events are emitted for the "agent lifecycle" which
is a specialization on virtio-serial events specific to the channel
named "org.qemu.guest_agent.0". This patch adds a generic event for
"channel lifecycles", which emit state change events for all
attached channels.
---
daemon/remote.c | 42 +++++++++++++++++
examples/object-events/event-test.c | 57 ++++++++++++++++++++++++
include/libvirt/libvirt-domain.h | 44 ++++++++++++++++++
src/conf/domain_event.c | 89 +++++++++++++++++++++++++++++++++++++
src/conf/domain_event.h | 12 +++++
src/libvirt_private.syms | 2 +
src/qemu/qemu_driver.c | 5 +++
src/qemu/qemu_process.c | 6 +++
src/remote/remote_driver.c | 32 +++++++++++++
src/remote/remote_protocol.x | 17 ++++++-
src/remote_protocol-structs | 7 +++
tools/virsh-domain.c | 35 +++++++++++++++
12 files changed, 347 insertions(+), 1 deletion(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index e414f92..25b32f2 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -1086,6 +1086,47 @@ remoteRelayDomainEventAgentLifecycle(virConnectPtr conn,
static int
+remoteRelayDomainEventChannelLifecycle(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *channelName,
+ int state,
+ int reason,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_domain_event_callback_channel_lifecycle_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelayDomainEventCheckACL(callback->client, conn, dom))
+ return -1;
+
+ VIR_DEBUG("Relaying domain channel lifecycle event %s %d, callback %d, "
+ " name: %s, state %d, reason %d",
+ dom->name, dom->id, callback->callbackID, channelName, state, reason);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ data.callbackID = callback->callbackID;
+ make_nonnull_domain(&data.dom, dom);
+
+ if (VIR_STRDUP(data.channelName, channelName) < 0)
+ goto error;
+ data.state = state;
+ data.reason = reason;
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CHANNEL_LIFECYCLE,
+ (xdrproc_t)xdr_remote_domain_event_callback_channel_lifecycle_msg,
+ &data);
+
+ return 0;
+ error:
+ VIR_FREE(data.channelName);
+ return -1;
+}
+
+
+static int
remoteRelayDomainEventDeviceAdded(virConnectPtr conn,
virDomainPtr dom,
const char *devAlias,
@@ -1248,6 +1289,7 @@ static virConnectDomainEventGenericCallback domainEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventMigrationIteration),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventJobCompleted),
VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventDeviceRemovalFailed),
+ VIR_DOMAIN_EVENT_CALLBACK(remoteRelayDomainEventChannelLifecycle)
};
verify(ARRAY_CARDINALITY(domainEventCallbacks) == VIR_DOMAIN_EVENT_ID_LAST);
diff --git a/examples/object-events/event-test.c b/examples/object-events/event-test.c
index 730cb8b..da023eb 100644
--- a/examples/object-events/event-test.c
+++ b/examples/object-events/event-test.c
@@ -337,6 +337,46 @@ guestAgentLifecycleEventReasonToString(int event)
return "unknown";
}
+
+static const char *
+guestChannelLifecycleEventStateToString(int event)
+{
+ switch ((virConnectDomainEventChannelLifecycleState) event) {
+ case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_DISCONNECTED:
+ return "Disconnected";
+
+ case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_CONNECTED:
+ return "Connected";
+
+ case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_LAST:
+ break;
+ }
+
+ return "unknown";
+}
+
+
+static const char *
+guestChannelLifecycleEventReasonToString(int event)
+{
+ switch ((virConnectDomainEventChannelLifecycleReason) event) {
+ case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_UNKNOWN:
+ return "Unknown";
+
+ case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_DOMAIN_STARTED:
+ return "Domain started";
+
+ case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_CHANNEL:
+ return "Channel event";
+
+ case VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_LAST:
+ break;
+ }
+
+ return "unknown";
+}
+
+
static const char *
storagePoolEventToString(int event)
{
@@ -797,6 +837,22 @@ myDomainEventAgentLifecycleCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
return 0;
}
+static int
+myDomainEventChannelLifecycleCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *channelName,
+ int state,
+ int reason,
+ void *opaque ATTRIBUTE_UNUSED)
+{
+ printf("%s EVENT: Domain %s(%d) guest channel(%s) state changed: %s reason: %s\n",
+ __func__, virDomainGetName(dom), virDomainGetID(dom), channelName,
+ guestChannelLifecycleEventStateToString(state),
+ guestChannelLifecycleEventReasonToString(reason));
+
+ return 0;
+}
+
static int
myDomainEventDeviceAddedCallback(virConnectPtr conn ATTRIBUTE_UNUSED,
@@ -971,6 +1027,7 @@ struct domainEventData domainEvents[] = {
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_MIGRATION_ITERATION, myDomainEventMigrationIterationCallback),
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_JOB_COMPLETED, myDomainEventJobCompletedCallback),
DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED, myDomainEventDeviceRemovalFailedCallback),
+ DOMAIN_EVENT(VIR_DOMAIN_EVENT_ID_CHANNEL_LIFECYCLE, myDomainEventChannelLifecycleCallback)
};
struct storagePoolEventData {
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 5f50660..9a5c664 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -3965,6 +3965,49 @@ typedef void (*virConnectDomainEventAgentLifecycleCallback)(virConnectPtr conn,
int reason,
void *opaque);
+typedef enum {
+ VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_CONNECTED = 1, /* channel connected */
+ VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_DISCONNECTED = 2, /* channel disconnected */
+
+# ifdef VIR_ENUM_SENTINELS
+ VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_LAST
+# endif
+} virConnectDomainEventChannelLifecycleState;
+
+typedef enum {
+ VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_UNKNOWN = 0, /* unknown state change reason */
+ VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_DOMAIN_STARTED =
+ VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_DOMAIN_STARTED, /* state changed due to domain start */
+ VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_CHANNEL =
+ VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_CHANNEL, /* channel state changed */
+
+# ifdef VIR_ENUM_SENTINELS
+ VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_LAST
+# endif
+} virConnectDomainEventChannelLifecycleReason;
+
+/**
+ * virConnectDomainEventChannelLifecycleCallback:
+ * @conn: connection object
+ * @dom: domain on which the event occurred
+ * @channelName: the name of the channel on which the event occurred
+ * @state: new state of the guest channel, one of virConnectDomainEventChannelLifecycleState
+ * @reason: reason for state change; one of virConnectDomainEventChannelLifecycleReason
+ * @opaque: application specified data
+ *
+ * This callback occurs when libvirt detects a change in the state of a guest
+ * serial channel. The hypervisor must support serial notification, and this is
+ * currently limited to modern versions of qemu.
+ *
+ * The callback signature to use when registering for an event of type
+ * VIR_DOMAIN_EVENT_ID_CHANNEL_LIFECYCLE with virConnectDomainEventRegisterAny()
+ */
+typedef void (*virConnectDomainEventChannelLifecycleCallback)(virConnectPtr conn,
+ virDomainPtr dom,
+ const char *channelName,
+ int state,
+ int reason,
+ void *opaque);
/**
* VIR_DOMAIN_EVENT_CALLBACK:
@@ -4006,6 +4049,7 @@ typedef enum {
VIR_DOMAIN_EVENT_ID_MIGRATION_ITERATION = 20, /* virConnectDomainEventMigrationIterationCallback */
VIR_DOMAIN_EVENT_ID_JOB_COMPLETED = 21, /* virConnectDomainEventJobCompletedCallback */
VIR_DOMAIN_EVENT_ID_DEVICE_REMOVAL_FAILED = 22, /* virConnectDomainEventDeviceRemovalFailedCallback */
+ VIR_DOMAIN_EVENT_ID_CHANNEL_LIFECYCLE = 23, /* virConnectDomainEventChannelLifecycleCallback */
# ifdef VIR_ENUM_SENTINELS
VIR_DOMAIN_EVENT_ID_LAST
diff --git a/src/conf/domain_event.c b/src/conf/domain_event.c
index 63ae9e1..f971a0d 100644
--- a/src/conf/domain_event.c
+++ b/src/conf/domain_event.c
@@ -55,6 +55,7 @@ static virClassPtr virDomainEventPMClass;
static virClassPtr virDomainQemuMonitorEventClass;
static virClassPtr virDomainEventTunableClass;
static virClassPtr virDomainEventAgentLifecycleClass;
+static virClassPtr virDomainEventChannelLifecycleClass;
static virClassPtr virDomainEventDeviceAddedClass;
static virClassPtr virDomainEventMigrationIterationClass;
static virClassPtr virDomainEventJobCompletedClass;
@@ -75,6 +76,7 @@ static void virDomainEventPMDispose(void *obj);
static void virDomainQemuMonitorEventDispose(void *obj);
static void virDomainEventTunableDispose(void *obj);
static void virDomainEventAgentLifecycleDispose(void *obj);
+static void virDomainEventChannelLifecycleDispose(void *obj);
static void virDomainEventDeviceAddedDispose(void *obj);
static void virDomainEventMigrationIterationDispose(void *obj);
static void virDomainEventJobCompletedDispose(void *obj);
@@ -241,6 +243,16 @@ struct _virDomainEventAgentLifecycle {
typedef struct _virDomainEventAgentLifecycle virDomainEventAgentLifecycle;
typedef virDomainEventAgentLifecycle *virDomainEventAgentLifecyclePtr;
+struct _virDomainEventChannelLifecycle {
+ virDomainEvent parent;
+
+ char *channelName;
+ int state;
+ int reason;
+};
+typedef struct _virDomainEventChannelLifecycle virDomainEventChannelLifecycle;
+typedef virDomainEventChannelLifecycle *virDomainEventChannelLifecyclePtr;
+
struct _virDomainEventMigrationIteration {
virDomainEvent parent;
@@ -367,6 +379,12 @@ virDomainEventsOnceInit(void)
sizeof(virDomainEventAgentLifecycle),
virDomainEventAgentLifecycleDispose)))
return -1;
+ if (!(virDomainEventChannelLifecycleClass =
+ virClassNew(virDomainEventClass,
+ "virDomainEventChannelLifecycle",
+ sizeof(virDomainEventChannelLifecycle),
+ virDomainEventChannelLifecycleDispose)))
+ return -1;
if (!(virDomainEventMigrationIterationClass =
virClassNew(virDomainEventClass,
"virDomainEventMigrationIteration",
@@ -557,6 +575,15 @@ virDomainEventAgentLifecycleDispose(void *obj)
};
static void
+virDomainEventChannelLifecycleDispose(void *obj)
+{
+ virDomainEventChannelLifecyclePtr event = obj;
+ VIR_DEBUG("obj=%p", event);
+
+ VIR_FREE(event->channelName);
+};
+
+static void
virDomainEventMigrationIterationDispose(void *obj)
{
virDomainEventMigrationIterationPtr event = obj;
@@ -1460,6 +1487,56 @@ virDomainEventAgentLifecycleNewFromDom(virDomainPtr dom,
}
static virObjectEventPtr
+virDomainEventChannelLifecycleNew(int id,
+ const char *name,
+ const unsigned char *uuid,
+ const char *channelName,
+ int state,
+ int reason)
+{
+ virDomainEventChannelLifecyclePtr ev;
+
+ if (virDomainEventsInitialize() < 0)
+ return NULL;
+
+ if (!(ev = virDomainEventNew(virDomainEventChannelLifecycleClass,
+ VIR_DOMAIN_EVENT_ID_CHANNEL_LIFECYCLE,
+ id, name, uuid)))
+ return NULL;
+
+ if (VIR_STRDUP(ev->channelName, channelName) < 0) {
+ virObjectUnref(ev);
+ return NULL;
+ }
+
+ ev->state = state;
+ ev->reason = reason;
+
+ return (virObjectEventPtr)ev;
+}
+
+virObjectEventPtr
+virDomainEventChannelLifecycleNewFromObj(virDomainObjPtr obj,
+ const char *channelName,
+ int state,
+ int reason)
+{
+ return virDomainEventChannelLifecycleNew(obj->def->id, obj->def->name,
+ obj->def->uuid, channelName, state, reason);
+}
+
+virObjectEventPtr
+virDomainEventChannelLifecycleNewFromDom(virDomainPtr dom,
+ const char *channelName,
+ int state,
+ int reason)
+{
+ return virDomainEventChannelLifecycleNew(dom->id, dom->name, dom->uuid,
+ channelName, state, reason);
+}
+
+
+static virObjectEventPtr
virDomainEventMigrationIterationNew(int id,
const char *name,
const unsigned char *uuid,
@@ -1812,6 +1889,18 @@ virDomainEventDispatchDefaultFunc(virConnectPtr conn,
goto cleanup;
}
+ case VIR_DOMAIN_EVENT_ID_CHANNEL_LIFECYCLE:
+ {
+ virDomainEventChannelLifecyclePtr channelLifecycleEvent;
+ channelLifecycleEvent = (virDomainEventChannelLifecyclePtr)event;
+ ((virConnectDomainEventChannelLifecycleCallback)cb)(conn, dom,
+ channelLifecycleEvent->channelName,
+ channelLifecycleEvent->state,
+ channelLifecycleEvent->reason,
+ cbopaque);
+ goto cleanup;
+ }
+
case VIR_DOMAIN_EVENT_ID_DEVICE_ADDED:
{
virDomainEventDeviceAddedPtr deviceAddedEvent;
diff --git a/src/conf/domain_event.h b/src/conf/domain_event.h
index 54fa879..3a689b3 100644
--- a/src/conf/domain_event.h
+++ b/src/conf/domain_event.h
@@ -217,6 +217,18 @@ virDomainEventAgentLifecycleNewFromDom(virDomainPtr dom,
int reason);
virObjectEventPtr
+virDomainEventChannelLifecycleNewFromObj(virDomainObjPtr obj,
+ const char *channelName,
+ int state,
+ int reason);
+
+virObjectEventPtr
+virDomainEventChannelLifecycleNewFromDom(virDomainPtr dom,
+ const char *channelName,
+ int state,
+ int reason);
+
+virObjectEventPtr
virDomainEventMigrationIterationNewFromObj(virDomainObjPtr obj,
int iteration);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 74dd527..e259687 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -535,6 +535,8 @@ virDomainEventBlockJob2NewFromDom;
virDomainEventBlockJob2NewFromObj;
virDomainEventBlockJobNewFromDom;
virDomainEventBlockJobNewFromObj;
+virDomainEventChannelLifecycleNewFromDom;
+virDomainEventChannelLifecycleNewFromObj;
virDomainEventControlErrorNewFromDom;
virDomainEventControlErrorNewFromObj;
virDomainEventDeviceAddedNewFromDom;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 38c8414..b464412 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4407,6 +4407,7 @@ processSerialChangedEvent(virQEMUDriverPtr driver,
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
virDomainChrDeviceState newstate;
virObjectEventPtr event = NULL;
+ virObjectEventPtr channelEvent = NULL;
virDomainDeviceDef dev;
qemuDomainObjPrivatePtr priv = vm->privateData;
int rc;
@@ -4482,6 +4483,10 @@ processSerialChangedEvent(virQEMUDriverPtr driver,
qemuDomainEventQueue(driver, event);
}
+ channelEvent = virDomainEventChannelLifecycleNewFromObj(vm, dev.data.chr->target.name, newstate,
+ VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_CHANNEL);
+ qemuDomainEventQueue(driver, channelEvent);
+
endjob:
qemuDomainObjEndJob(driver, vm);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 1b67aee..31b5028 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1931,6 +1931,7 @@ qemuProcessRefreshChannelVirtioState(virQEMUDriverPtr driver,
int agentReason = VIR_CONNECT_DOMAIN_EVENT_AGENT_LIFECYCLE_REASON_CHANNEL;
qemuMonitorChardevInfoPtr entry;
virObjectEventPtr event = NULL;
+ virObjectEventPtr channelEvent = NULL;
char id[32];
if (booted)
@@ -1958,6 +1959,11 @@ qemuProcessRefreshChannelVirtioState(virQEMUDriverPtr driver,
agentReason)))
qemuDomainEventQueue(driver, event);
+
+ channelEvent =
+ virDomainEventChannelLifecycleNewFromObj(vm, chr->target.name, entry->state, agentReason);
+ qemuDomainEventQueue(driver, channelEvent);
+
chr->state = entry->state;
}
}
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index a3cd7cd..eb783cb 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -345,6 +345,11 @@ remoteDomainBuildEventCallbackAgentLifecycle(virNetClientProgramPtr prog,
void *evdata, void *opaque);
static void
+remoteDomainBuildEventCallbackChannelLifecycle(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
+
+static void
remoteDomainBuildEventCallbackMigrationIteration(virNetClientProgramPtr prog,
virNetClientPtr client,
void *evdata, void *opaque);
@@ -574,6 +579,10 @@ static virNetClientProgramEvent remoteEvents[] = {
remoteNodeDeviceBuildEventUpdate,
sizeof(remote_node_device_event_update_msg),
(xdrproc_t)xdr_remote_node_device_event_update_msg },
+ { REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CHANNEL_LIFECYCLE,
+ remoteDomainBuildEventCallbackChannelLifecycle,
+ sizeof(remote_domain_event_callback_channel_lifecycle_msg),
+ (xdrproc_t)xdr_remote_domain_event_callback_channel_lifecycle_msg },
};
static void
@@ -5152,6 +5161,29 @@ remoteDomainBuildEventCallbackAgentLifecycle(virNetClientProgramPtr prog ATTRIBU
static void
+remoteDomainBuildEventCallbackChannelLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
+{
+ virConnectPtr conn = opaque;
+ remote_domain_event_callback_channel_lifecycle_msg *msg = evdata;
+ struct private_data *priv = conn->privateData;
+ virDomainPtr dom;
+ virObjectEventPtr event = NULL;
+
+ if (!(dom = get_nonnull_domain(conn, msg->dom)))
+ return;
+
+ event = virDomainEventChannelLifecycleNewFromDom(dom, msg->channelName, msg->state,
+ msg->reason);
+
+ virObjectUnref(dom);
+
+ remoteEventQueue(priv, event, msg->callbackID);
+}
+
+
+static void
remoteDomainBuildEventCallbackMigrationIteration(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
void *evdata,
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index e8382dc..e5227c4 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -3242,6 +3242,15 @@ struct remote_domain_event_callback_agent_lifecycle_msg {
int reason;
};
+struct remote_domain_event_callback_channel_lifecycle_msg {
+ int callbackID;
+ remote_nonnull_domain dom;
+
+ char *channelName;
+ int state;
+ int reason;
+};
+
struct remote_connect_get_all_domain_stats_ret {
remote_domain_stats_record retStats<REMOTE_DOMAIN_LIST_MAX>;
};
@@ -5934,5 +5943,11 @@ enum remote_procedure {
* @generate: both
* @acl: none
*/
- REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE = 377
+ REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE = 377,
+
+ /**
+ * @generate: both
+ * @acl: none
+ */
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_CHANNEL_LIFECYCLE = 378
};
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index b71accc..7921016 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -2689,6 +2689,13 @@ struct remote_domain_event_callback_agent_lifecycle_msg {
int state;
int reason;
};
+struct remote_domain_event_callback_channel_lifecycle_msg {
+ int callbackID;
+ remote_nonnull_domain dom;
+ remote_string channelName;
+ int state;
+ int reason;
+};
struct remote_connect_get_all_domain_stats_ret {
struct {
u_int retStats_len;
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 184f64d..e085358 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -12637,6 +12637,20 @@ VIR_ENUM_IMPL(virshEventAgentLifecycleReason,
N_("domain started"),
N_("channel event"))
+VIR_ENUM_DECL(virshEventChannelLifecycleState)
+VIR_ENUM_IMPL(virshEventChannelLifecycleState,
+ VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_STATE_LAST,
+ N_("unknown"),
+ N_("connected"),
+ N_("disconnected"))
+
+VIR_ENUM_DECL(virshEventChannelLifecycleReason)
+VIR_ENUM_IMPL(virshEventChannelLifecycleReason,
+ VIR_CONNECT_DOMAIN_EVENT_CHANNEL_LIFECYCLE_REASON_LAST,
+ N_("unknown"),
+ N_("domain started"),
+ N_("channel event"))
+
#define UNKNOWNSTR(str) (str ? str : N_("unsupported value"))
static void
virshEventAgentLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
@@ -12656,6 +12670,25 @@ virshEventAgentLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
}
static void
+virshEventChannelLifecyclePrint(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainPtr dom,
+ const char *channelName,
+ int state,
+ int reason,
+ void *opaque)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAsprintf(&buf, _("event 'channel-lifecycle' for domain %s: name: '%s', "
+ "state: '%s' reason: '%s'\n"),
+ virDomainGetName(dom),
+ channelName,
+ UNKNOWNSTR(virshEventChannelLifecycleStateTypeToString(state)),
+ UNKNOWNSTR(virshEventChannelLifecycleReasonTypeToString(reason)));
+ virshEventPrint(opaque, &buf);
+}
+
+static void
virshEventMigrationIterationPrint(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainPtr dom,
int iteration,
@@ -12755,6 +12788,8 @@ static vshEventCallback vshEventCallbacks[] = {
VIR_DOMAIN_EVENT_CALLBACK(virshEventJobCompletedPrint), },
{ "device-removal-failed",
VIR_DOMAIN_EVENT_CALLBACK(virshEventDeviceRemovalFailedPrint), },
+ { "channel-lifecycle",
+ VIR_DOMAIN_EVENT_CALLBACK(virshEventChannelLifecyclePrint), },
};
verify(VIR_DOMAIN_EVENT_ID_LAST == ARRAY_CARDINALITY(vshEventCallbacks));
--
2.7.4 (Apple Git-66)
7 years, 10 months
[libvirt] [PATCH] disk: Fixup error handling path for devmapper when part_separator='yes'
by John Ferlan
https://bugzilla.redhat.com/show_bug.cgi?id=1346566
If libvirt_parthelper is erroneously told to append the partition
separator 'p' onto the generated output for a disk pool using device
mapper that has 'user_friendly_names' set to true, then the error
recovery path will fail to find volume resulting in the pool being
in an unusable state.
So, augment the documentation to provide the better hint that the
part_separator='yes' should be set when user_friendly_names are not
being used. Additionally, once we're in the error path where the
returned name doesn't match the expected partition name try to see
if the reason is because the 'p' was erroneosly added. If so alter
the about to be removed vol->target.path so that the DiskDeleteVol
code can find the partition that was created and remove it.
Signed-off-by: John Ferlan <jferlan(a)redhat.com>
---
docs/formatstorage.html.in | 5 ++++-
src/storage/storage_backend_disk.c | 23 +++++++++++++++++++++++
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/docs/formatstorage.html.in b/docs/formatstorage.html.in
index ed1f0d1..7690114 100644
--- a/docs/formatstorage.html.in
+++ b/docs/formatstorage.html.in
@@ -138,7 +138,10 @@
causes libvirt to attempt to generate and find target volume path's
using a "p" separator. The default algorithm used by device mapper
is to add the "p" separator only when the source device path ends
- with a number.
+ with a number; however, it's possible to configure the devmapper
+ device to not use 'user_friendly_names' thus creating partitions
+ with the "p" separator even when the device source path does not
+ end with a number.
<span class="since">Since 1.3.1</span></p></dd>
<dt><code>dir</code></dt>
<dd>Provides the source for pools backed by directories (pool
diff --git a/src/storage/storage_backend_disk.c b/src/storage/storage_backend_disk.c
index 666ad03..07a04f1 100644
--- a/src/storage/storage_backend_disk.c
+++ b/src/storage/storage_backend_disk.c
@@ -95,6 +95,29 @@ virStorageBackendDiskMakeDataVol(virStoragePoolObjPtr pool,
virReportError(VIR_ERR_INVALID_ARG,
_("invalid partition name '%s', expected '%s'"),
vol->name, partname);
+
+ /* Let's see if we by chance parthelper created a name that won't be
+ * found later when we try to delete. We tell parthelper to add a 'p'
+ * to the output via the part_separator flag, but if devmapper has
+ * user_friendly_names set, the creation won't happen that way, thus
+ * our deletion will fail because the name we generated is wrong.
+ * Check for our conditions and see if the generated name is the
+ * same as StablePath returns and has the 'p' in it */
+ if (pool->def->source.devices[0].part_separator ==
+ VIR_TRISTATE_BOOL_YES &&
+ !virIsDevMapperDevice(vol->target.path) &&
+ STREQ(groups[0], vol->target.path) &&
+ (tmp = strrchr(groups[0], 'p'))) {
+
+ /* If we remove the 'p' from groups[0] and the resulting
+ * device is a devmapper device, then we know parthelper
+ * was told to create the wrong name based on the results.
+ * So just remove the 'p' from the vol->target.path too. */
+ memmove(tmp, tmp + 1, strlen(tmp));
+ if (virIsDevMapperDevice(groups[0]) &&
+ (tmp = strrchr(vol->target.path, 'p')))
+ memmove(tmp, tmp + 1, strlen(tmp));
+ }
return -1;
}
--
2.7.4
7 years, 11 months
[libvirt] [PATCH] util: fix domain object leaks on closecallbacks
by Wang King
From: wangjing <king.wang(a)huawei.com>
The virCloseCallbacksSet method increase object reference for
VM, and decrease object reference in virCloseCallbacksUnset.
But VM UUID will be deleted from closecallbacks list in
virCloseCallbacksRun when connection disconnected, and then
object reference cannot be decreased by virCloseCallbacksUnset
in callback functions.
Signed-off-by: Wang King <king.wang(a)huawei.com>
---
src/util/virclosecallbacks.c | 29 +++++++++++++++++------------
1 file changed, 17 insertions(+), 12 deletions(-)
diff --git a/src/util/virclosecallbacks.c b/src/util/virclosecallbacks.c
index 891a92b..26d5075 100644
--- a/src/util/virclosecallbacks.c
+++ b/src/util/virclosecallbacks.c
@@ -300,7 +300,9 @@ virCloseCallbacksGetForConn(virCloseCallbacksPtr closeCallbacks,
data.list = list;
data.oom = false;
+ virObjectLock(closeCallbacks);
virHashForEach(closeCallbacks->list, virCloseCallbacksGetOne, &data);
+ virObjectUnlock(closeCallbacks);
if (data.oom) {
VIR_FREE(list->entries);
@@ -329,22 +331,15 @@ virCloseCallbacksRun(virCloseCallbacksPtr closeCallbacks,
* them all from the hash. At that point we can release
* the lock and run the callbacks safely. */
- virObjectLock(closeCallbacks);
list = virCloseCallbacksGetForConn(closeCallbacks, conn);
if (!list)
return;
for (i = 0; i < list->nentries; i++) {
- char uuidstr[VIR_UUID_STRING_BUFLEN];
- virUUIDFormat(list->entries[i].uuid, uuidstr);
- virHashRemoveEntry(closeCallbacks->list, uuidstr);
- }
- virObjectUnlock(closeCallbacks);
-
- for (i = 0; i < list->nentries; i++) {
virDomainObjPtr vm;
+ virDomainObjPtr dom;
- if (!(vm = virDomainObjListFindByUUID(domains,
+ if (!(vm = virDomainObjListFindByUUIDRef(domains,
list->entries[i].uuid))) {
char uuidstr[VIR_UUID_STRING_BUFLEN];
virUUIDFormat(list->entries[i].uuid, uuidstr);
@@ -352,10 +347,20 @@ virCloseCallbacksRun(virCloseCallbacksPtr closeCallbacks,
continue;
}
- vm = list->entries[i].callback(vm, conn, opaque);
- if (vm)
- virObjectUnlock(vm);
+ dom = list->entries[i].callback(vm, conn, opaque);
+ if (dom)
+ virObjectUnlock(dom);
+ virObjectUnref(vm);
}
+
+ virObjectLock(closeCallbacks);
+ for (i = 0; i < list->nentries; i++) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(list->entries[i].uuid, uuidstr);
+ virHashRemoveEntry(closeCallbacks->list, uuidstr);
+ }
+ virObjectUnlock(closeCallbacks);
+
VIR_FREE(list->entries);
VIR_FREE(list);
}
--
2.8.3
7 years, 11 months