[libvirt] [PATCH] network driver: log error and abort network startup when radvd isn't found
by Laine Stump
This is detailed in:
https://bugzilla.redhat.com/show_bug.cgi?id=688957
Since radvd is executed by daemonizing it, the attempt to exec the
radvd binary doesn't happen until after libvirtd has already received
an exit code from the intermediate forked process, so no error is
detected or logged by __virExec().
We can't require radvd as a prerequisit for the libvirt package (many
installations don't use IPv6, so they don't need it), so instead we
add in a check to verify there is an executable radvd binary prior to
trying to exec it.
---
src/network/bridge_driver.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 6a02df1..c30620a 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -689,6 +689,14 @@ networkStartRadvd(virNetworkObjPtr network)
network->radvdPid = -1;
+ if (access(RADVD, X_OK) < 0) {
+ virReportSystemError(errno,
+ _("Cannot find %s - "
+ "Possibly the package isn't installed"),
+ RADVD);
+ goto cleanup;
+ }
+
if ((err = virFileMakePath(NETWORK_PID_DIR)) != 0) {
virReportSystemError(err,
_("cannot create directory %s"),
--
1.7.3.4
14 years
[libvirt] [PATCH] remote: fix memory leak
by Eric Blake
Detected in this valgrind run:
https://bugzilla.redhat.com/show_bug.cgi?id=690734
==13864== 10 bytes in 1 blocks are definitely lost in loss record 10 of 34
==13864== at 0x4A05FDE: malloc (vg_replace_malloc.c:236)
==13864== by 0x308587FD91: strdup (in /lib64/libc-2.12.so)
==13864== by 0x3BB68BA0A3: doRemoteOpen (remote_driver.c:451)
==13864== by 0x3BB68BCFCF: remoteOpen (remote_driver.c:1111)
==13864== by 0x3BB689A0FF: do_open (libvirt.c:1290)
==13864== by 0x3BB689ADD5: virConnectOpenAuth (libvirt.c:1545)
==13864== by 0x41F659: main (virsh.c:11613)
* src/remote/remote_driver.c (doRemoteClose): Move up.
(remoteOpenSecondaryDriver, remoteOpen): Avoid leak on failure.
---
src/remote/remote_driver.c | 120 +++++++++++++++++++++++---------------------
1 files changed, 62 insertions(+), 58 deletions(-)
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index b05bbcb..4c7df17 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -998,6 +998,64 @@ retry:
goto cleanup;
}
+static int
+doRemoteClose (virConnectPtr conn, struct private_data *priv)
+{
+ if (priv->eventFlushTimer >= 0) {
+ /* Remove timeout */
+ virEventRemoveTimeout(priv->eventFlushTimer);
+ /* Remove handle for remote events */
+ virEventRemoveHandle(priv->watch);
+ priv->watch = -1;
+ }
+
+ if (call (conn, priv, 0, REMOTE_PROC_CLOSE,
+ (xdrproc_t) xdr_void, (char *) NULL,
+ (xdrproc_t) xdr_void, (char *) NULL) == -1)
+ return -1;
+
+ /* Close socket. */
+ if (priv->uses_tls && priv->session) {
+ gnutls_bye (priv->session, GNUTLS_SHUT_RDWR);
+ gnutls_deinit (priv->session);
+ }
+#if HAVE_SASL
+ if (priv->saslconn)
+ sasl_dispose (&priv->saslconn);
+#endif
+ VIR_FORCE_CLOSE(priv->sock);
+ VIR_FORCE_CLOSE(priv->errfd);
+
+#ifndef WIN32
+ if (priv->pid > 0) {
+ pid_t reap;
+ do {
+retry:
+ reap = waitpid(priv->pid, NULL, 0);
+ if (reap == -1 && errno == EINTR)
+ goto retry;
+ } while (reap != -1 && reap != priv->pid);
+ }
+#endif
+ VIR_FORCE_CLOSE(priv->wakeupReadFD);
+ VIR_FORCE_CLOSE(priv->wakeupSendFD);
+
+
+ /* Free hostname copy */
+ VIR_FREE(priv->hostname);
+
+ /* See comment for remoteType. */
+ VIR_FREE(priv->type);
+
+ /* Free callback list */
+ virDomainEventCallbackListFree(priv->callbackList);
+
+ /* Free queued events */
+ virDomainEventQueueFree(priv->domainEvents);
+
+ return 0;
+}
+
static struct private_data *
remoteAllocPrivateData(void)
{
@@ -1039,7 +1097,9 @@ remoteOpenSecondaryDriver(virConnectPtr conn,
ret = doRemoteOpen(conn, *priv, auth, rflags);
if (ret != VIR_DRV_OPEN_SUCCESS) {
+ doRemoteClose(conn, *priv);
remoteDriverUnlock(*priv);
+ virMutexDestroy(&(*priv)->lock);
VIR_FREE(*priv);
} else {
(*priv)->localUses = 1;
@@ -1111,7 +1171,9 @@ remoteOpen (virConnectPtr conn,
ret = doRemoteOpen(conn, priv, auth, rflags);
if (ret != VIR_DRV_OPEN_SUCCESS) {
conn->privateData = NULL;
+ doRemoteClose(conn, priv);
remoteDriverUnlock(priv);
+ virMutexDestroy(&priv->lock);
VIR_FREE(priv);
} else {
conn->privateData = priv;
@@ -1538,64 +1600,6 @@ verify_certificate (virConnectPtr conn ATTRIBUTE_UNUSED,
static int
-doRemoteClose (virConnectPtr conn, struct private_data *priv)
-{
- if (priv->eventFlushTimer >= 0) {
- /* Remove timeout */
- virEventRemoveTimeout(priv->eventFlushTimer);
- /* Remove handle for remote events */
- virEventRemoveHandle(priv->watch);
- priv->watch = -1;
- }
-
- if (call (conn, priv, 0, REMOTE_PROC_CLOSE,
- (xdrproc_t) xdr_void, (char *) NULL,
- (xdrproc_t) xdr_void, (char *) NULL) == -1)
- return -1;
-
- /* Close socket. */
- if (priv->uses_tls && priv->session) {
- gnutls_bye (priv->session, GNUTLS_SHUT_RDWR);
- gnutls_deinit (priv->session);
- }
-#if HAVE_SASL
- if (priv->saslconn)
- sasl_dispose (&priv->saslconn);
-#endif
- VIR_FORCE_CLOSE(priv->sock);
- VIR_FORCE_CLOSE(priv->errfd);
-
-#ifndef WIN32
- if (priv->pid > 0) {
- pid_t reap;
- do {
-retry:
- reap = waitpid(priv->pid, NULL, 0);
- if (reap == -1 && errno == EINTR)
- goto retry;
- } while (reap != -1 && reap != priv->pid);
- }
-#endif
- VIR_FORCE_CLOSE(priv->wakeupReadFD);
- VIR_FORCE_CLOSE(priv->wakeupSendFD);
-
-
- /* Free hostname copy */
- VIR_FREE(priv->hostname);
-
- /* See comment for remoteType. */
- VIR_FREE(priv->type);
-
- /* Free callback list */
- virDomainEventCallbackListFree(priv->callbackList);
-
- /* Free queued events */
- virDomainEventQueueFree(priv->domainEvents);
-
- return 0;
-}
-
-static int
remoteClose (virConnectPtr conn)
{
int ret = 0;
--
1.7.4
14 years
[libvirt] [PATCH V5] Add libxenlight driver
by Jim Fehlig
Add a new xen driver based on libxenlight [1], which is the primary
toolstack starting with Xen 4.1.0. The driver is stateful, runs
privileged only, and is accessed with libxl:/// URI.
V5:
- Ensure events are unregistered when domain private data
is destroyed. Discovered and fixed by Markus Gross.
V4:
- Handle restart of libvirtd, reconnecting to previously
started domains
- Rebased to current master
- Tested against Xen 4.1 RC7-pre (c/s 22961:c5d121fd35c0)
V3:
- Reserve vnc port within driver when autoport=yes
V2:
- Update to Xen 4.1 RC6-pre (c/s 22940:5a4710640f81)
- Rebased to current master
- Plug memory leaks found by Stefano Stabellini and valgrind
- Handle SHUTDOWN_crash domain death event
[1] http://lists.xensource.com/archives/html/xen-devel/2009-11/msg00436.html
---
cfg.mk | 1 +
configure.ac | 48 ++
daemon/Makefile.am | 4 +
daemon/libvirtd.c | 6 +
docs/drivers.html.in | 3 +-
docs/drvxen.html.in | 6 +-
docs/drvxenlight.html.in | 53 ++
docs/sitemap.html.in | 6 +-
include/libvirt/virterror.h | 1 +
po/POTFILES.in | 2 +
src/Makefile.am | 32 +
src/driver.h | 3 +-
src/libvirt.c | 4 +
src/libxl/libxl_conf.c | 896 +++++++++++++++++++++++++++
src/libxl/libxl_conf.h | 91 +++
src/libxl/libxl_driver.c | 1420 +++++++++++++++++++++++++++++++++++++++++++
src/libxl/libxl_driver.h | 27 +
src/util/virterror.c | 3 +
18 files changed, 2602 insertions(+), 4 deletions(-)
diff --git a/cfg.mk b/cfg.mk
index 5cb2ead..ef71cd5 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -402,6 +402,7 @@ msg_gen_function += virXenStoreError
msg_gen_function += virXendError
msg_gen_function += vmwareError
msg_gen_function += xenapiSessionErrorHandler
+msg_gen_function += libxlError
msg_gen_function += xenUnifiedError
msg_gen_function += xenXMError
msg_gen_function += VIR_ERROR
diff --git a/configure.ac b/configure.ac
index a58ee4e..0ef90e1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -263,6 +263,8 @@ AC_ARG_WITH([phyp],
AC_HELP_STRING([--with-phyp], [add PHYP support @<:@default=check@:>@]),[],[with_phyp=check])
AC_ARG_WITH([xenapi],
AC_HELP_STRING([--with-xenapi], [add XenAPI support @<:@default=check@:>@]),[],[with_xenapi=check])
+AC_ARG_WITH([libxl],
+ AC_HELP_STRING([--with-libxl], [add libxenlight support @<:@default=check@:>@]),[],[with_libxl=check])
AC_ARG_WITH([vbox],
AC_HELP_STRING([--with-vbox=@<:@PFX@:>@],
[VirtualBox XPCOMC location @<:@default=yes@:>@]),[],
@@ -497,6 +499,46 @@ fi
AC_SUBST([LIBXENSERVER_CFLAGS])
AC_SUBST([LIBXENSERVER_LIBS])
+old_LIBS="$LIBS"
+old_CFLAGS="$CFLAGS"
+LIBXL_LIBS=""
+LIBXL_CFLAGS=""
+dnl search for libxl, aka libxenlight
+fail=0
+if test "$with_libxl" != "no" ; then
+ if test "$with_libxl" != "yes" && test "$with_libxl" != "check" ; then
+ LIBXL_CFLAGS="-I$with_libxl/include"
+ LIBXL_LIBS="-L$with_libxl"
+ fi
+ CFLAGS="$CFLAGS $LIBXL_CFLAGS"
+ LIBS="$LIBS $LIBXL_LIBS"
+ AC_CHECK_LIB([xenlight], [libxl_ctx_init], [
+ with_libxl=yes
+ LIBXL_LIBS="$LIBXL_LIBS -lxenlight -lxenstore -lxenctrl -lxenguest -luuid -lutil -lblktapctl"
+ ],[
+ if test "$with_libxl" = "yes"; then
+ fail=1
+ fi
+ with_libxl=no
+ ],[
+ -lxenstore -lxenctrl -lxenguest -luuid -lutil -lblktapctl
+ ])
+fi
+
+LIBS="$old_LIBS"
+CFLAGS="$old_CFLAGS"
+
+if test $fail = 1; then
+ AC_MSG_ERROR([You must install the libxl Library to compile libxenlight driver with -lxl])
+fi
+
+if test "$with_libxl" = "yes"; then
+ AC_DEFINE_UNQUOTED([WITH_LIBXL], 1, [whether libxenlight driver is enabled])
+fi
+AM_CONDITIONAL([WITH_LIBXL], [test "$with_libxl" = "yes"])
+
+AC_SUBST([LIBXL_CFLAGS])
+AC_SUBST([LIBXL_LIBS])
old_LIBS="$LIBS"
old_CFLAGS="$CFLAGS"
@@ -2370,6 +2412,7 @@ AC_MSG_NOTICE([ OpenVZ: $with_openvz])
AC_MSG_NOTICE([ VMware: $with_vmware])
AC_MSG_NOTICE([ VBox: $with_vbox])
AC_MSG_NOTICE([ XenAPI: $with_xenapi])
+AC_MSG_NOTICE([libxenlight: $with_libxl])
AC_MSG_NOTICE([ LXC: $with_lxc])
AC_MSG_NOTICE([ PHYP: $with_phyp])
AC_MSG_NOTICE([ ONE: $with_one])
@@ -2479,6 +2522,11 @@ AC_MSG_NOTICE([ xenapi: $LIBXENSERVER_CFLAGS $LIBXENSERVER_LIBS])
else
AC_MSG_NOTICE([ xenapi: no])
fi
+if test "$with_libxl" = "yes" ; then
+AC_MSG_NOTICE([ libxenlight: $LIBXL_CFLAGS $LIBXL_LIBS])
+else
+AC_MSG_NOTICE([ libxenlight: no])
+fi
if test "$with_hal" = "yes" ; then
AC_MSG_NOTICE([ hal: $HAL_CFLAGS $HAL_LIBS])
else
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 15e8129..9e3a557 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -106,6 +106,10 @@ if WITH_LXC
libvirtd_LDADD += ../src/libvirt_driver_lxc.la
endif
+if WITH_LIBXL
+ libvirtd_LDADD += ../src/libvirt_driver_libxl.la
+endif
+
if WITH_UML
libvirtd_LDADD += ../src/libvirt_driver_uml.la
endif
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 9a5a53e..c7fcb46 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -81,6 +81,9 @@
# ifdef WITH_LXC
# include "lxc/lxc_driver.h"
# endif
+# ifdef WITH_LIBXL
+# include "libxl/libxl_driver.h"
+# endif
# ifdef WITH_UML
# include "uml/uml_driver.h"
# endif
@@ -948,6 +951,9 @@ static struct qemud_server *qemudInitialize(void) {
# ifdef WITH_LXC
lxcRegister();
# endif
+# ifdef WITH_LIBXL
+ libxlRegister();
+# endif
# ifdef WITH_UML
umlRegister();
# endif
diff --git a/docs/drivers.html.in b/docs/drivers.html.in
index ecad03a..368664e 100644
--- a/docs/drivers.html.in
+++ b/docs/drivers.html.in
@@ -28,7 +28,8 @@
<li><strong><a href="drvvbox.html">VirtualBox</a></strong></li>
<li><strong><a href="drvesx.html">VMware ESX</a></strong></li>
<li><strong><a href="drvvmware.html">VMware Workstation/Player</a></strong></li>
- <li><strong><a href="drvxen.html">Xen</a></strong></li>
+ <li><strong><a href="drvxen.html">Xen 3.0.1 - 4.0.x</a></strong></li>
+ <li><strong><a href="drvxenlight.html">Xen 4.1.0 onwards</a></strong></li>
</ul>
<h2><a name="stroage">Storage drivers</a></h2>
diff --git a/docs/drvxen.html.in b/docs/drvxen.html.in
index 4e35afa..4b88a7d 100644
--- a/docs/drvxen.html.in
+++ b/docs/drvxen.html.in
@@ -6,7 +6,11 @@
<p>
The libvirt Xen driver provides the ability to manage virtual machines
- on any Xen release from 3.0.1 onwards.
+ on any Xen release from 3.0.1 to 4.0.x. Starting with Xen 4.1.0,
+ the traditional xm/xend toolstack is replaced with a new toolstack
+ based on libxenlight. Consult the
+ <a href="drvxenlight.html">libxenlight driver</a> if your Xen host is
+ configured to use the new toolstack.
</p>
<h2><a name="prereq">Deployment pre-requisites</a></h2>
diff --git a/docs/drvxenlight.html.in b/docs/drvxenlight.html.in
new file mode 100644
index 0000000..fe60786
--- /dev/null
+++ b/docs/drvxenlight.html.in
@@ -0,0 +1,53 @@
+<html>
+ <body>
+ <h1>libxenlight hypervisor driver</h1>
+
+ <ul id="toc"></ul>
+
+ <p>
+ The libvirt libxenlight driver provides the ability to manage virtual
+ machines on any Xen release from 4.1.0 onwards.
+ </p>
+
+ <h2><a name="prereq">Deployment pre-requisites</a></h2>
+
+ <p>
+ This driver uses Xen's libxenlight toolstack, which is the default
+ toolstack configuration starting with Xen 4.1.0. The traditional
+ xm/xend toolstack is still provided, but it is no longer maintained
+ and may be removed in a future Xen release.
+ </p>
+
+ <p>
+ The libxenlight toolstack uses xenstored and blktap2. Ensure
+ xenstored is running, or use the xencommons init script provided.
+ Ensure your kernel supports the blktap2 module and it is loaded.
+ </p>
+
+ <h2><a name="uri">Connections to libxenlight driver</a></h2>
+
+ <p>
+ The libvirt libxenlight driver is a stateful, privileged driver,
+ with a driver name of 'libxl'. Some example conection URIs for
+ the libxenlight driver are:
+ </p>
+
+<pre>
+libxl:/// (local access, direct)
+libxl://example.com/ (remote access, TLS/x509)
+libxl+tcp://example.com/ (remote access, SASl/Kerberos)
+libxl+ssh://root@example.com/ (remote access, SSH tunnelled)
+</pre>
+
+ <h2><a name="xmlconfig">Example domain XML config</a></h2>
+
+ <p>
+ The libxenlight toolstack attempts to be compatible with the
+ legacy xm/xend toolstack, supporting the traditional python
+ configuration files (xen-xm). Fortunately, the libvirt XML
+ syntax is unchanged with the libxenlight driver. Consult
+ the <a href="drvxen.html#xmlconfig">Xen driver examples</a>.
+ </p>
+
+ </body>
+</html>
diff --git a/docs/sitemap.html.in b/docs/sitemap.html.in
index ac0af71..538f227 100644
--- a/docs/sitemap.html.in
+++ b/docs/sitemap.html.in
@@ -156,7 +156,11 @@
<ul>
<li>
<a href="drvxen.html">Xen</a>
- <span>Driver the Xen hypervisor</span>
+ <span>Driver the Xen hypervisor, versions 3.0.1 - 4.0.x</span>
+ </li>
+ <li>
+ <a href="drvxenlight.html">libxenlight</a>
+ <span>Driver the Xen hypervisor, version 4.1.0 onwards</span>
</li>
<li>
<a href="drvqemu.html">QEMU / KVM</a>
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 6b8c789..1d8275b 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -80,6 +80,7 @@ typedef enum {
VIR_FROM_STREAMS = 38, /* Error from I/O streams */
VIR_FROM_VMWARE = 39, /* Error from VMware driver */
VIR_FROM_EVENT = 40, /* Error from event loop impl */
+ VIR_FROM_LIBXL = 41, /* Error from libxenlight driver */
} virErrorDomain;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1ed2765..4bd2b13 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -34,6 +34,8 @@ src/lxc/lxc_conf.c
src/lxc/lxc_controller.c
src/lxc/lxc_driver.c
src/lxc/veth.c
+src/libxl/libxl_driver.c
+src/libxl/libxl_conf.c
src/network/bridge_driver.c
src/node_device/node_device_driver.c
src/node_device/node_device_hal.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 645119e..c3729a6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -298,6 +298,10 @@ XENAPI_DRIVER_SOURCES = \
xenapi/xenapi_driver_private.h \
xenapi/xenapi_utils.c xenapi/xenapi_utils.h
+LIBXL_DRIVER_SOURCES = \
+ libxl/libxl_conf.c libxl/libxl_conf.h \
+ libxl/libxl_driver.c libxl/libxl_driver.h
+
UML_DRIVER_SOURCES = \
uml/uml_conf.c uml/uml_conf.h \
uml/uml_driver.c uml/uml_driver.h
@@ -692,6 +696,25 @@ endif
libvirt_driver_xenapi_la_SOURCES = $(XENAPI_DRIVER_SOURCES)
endif
+if WITH_LIBXL
+if WITH_DRIVER_MODULES
+mod_LTLIBRARIES += libvirt_driver_libxl.la
+else
+noinst_LTLIBRARIES += libvirt_driver_libxl.la
+# Stateful, so linked to daemon instead
+#libvirt_la_BUILT_LIBADD += libvirt_driver_libxl.la
+endif
+libvirt_driver_libxl_la_CFLAGS = $(LIBXL_CFLAGS) \
+ -I@top_srcdir@/src/conf $(AM_CFLAGS)
+libvirt_driver_libxl_la_LDFLAGS = $(AM_LDFLAGS)
+libvirt_driver_libxl_la_LIBADD = $(LIBXL_LIBS)
+if WITH_DRIVER_MODULES
+libvirt_driver_libxl_la_LIBADD += ../gnulib/lib/libgnu.la
+libvirt_driver_libxl_la_LDFLAGS += -module -avoid-version
+endif
+libvirt_driver_libxl_la_SOURCES = $(LIBXL_DRIVER_SOURCES)
+endif
+
if WITH_QEMU
if WITH_DRIVER_MODULES
mod_LTLIBRARIES += libvirt_driver_qemu.la
@@ -1005,6 +1028,7 @@ EXTRA_DIST += \
$(PHYP_DRIVER_SOURCES) \
$(VBOX_DRIVER_SOURCES) \
$(XENAPI_DRIVER_SOURCES) \
+ $(LIBXL_DRIVER_SOURCES) \
$(ESX_DRIVER_SOURCES) \
$(ESX_DRIVER_EXTRA_DIST) \
$(NETWORK_DRIVER_SOURCES) \
@@ -1259,6 +1283,10 @@ if WITH_LXC
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/lxc"
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/run/libvirt/lxc"
endif
+if WITH_LIBXL
+ $(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/libxl"
+ $(MKDIR_P) "$(DESTDIR)$(localstatedir)/run/libvirt/libxl"
+endif
if WITH_UML
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/uml"
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/run/libvirt/uml"
@@ -1296,6 +1324,10 @@ if WITH_LXC
rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/lxc" ||:
rmdir "$(DESTDIR)$(localstatedir)/run/libvirt/lxc" ||:
endif
+if WITH_LIBXL
+ rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/libxl" ||:
+ rmdir "$(DESTDIR)$(localstatedir)/run/libvirt/libxl" ||:
+endif
if WITH_UML
rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/uml" ||:
rmdir "$(DESTDIR)$(localstatedir)/run/libvirt/uml" ||:
diff --git a/src/driver.h b/src/driver.h
index c65a4b9..c8c9624 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -27,7 +27,8 @@ typedef enum {
VIR_DRV_ESX = 10,
VIR_DRV_PHYP = 11,
VIR_DRV_XENAPI = 12,
- VIR_DRV_VMWARE = 13
+ VIR_DRV_VMWARE = 13,
+ VIR_DRV_LIBXL = 14,
} virDrvNo;
diff --git a/src/libvirt.c b/src/libvirt.c
index e4b451e..5e2876b 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -912,6 +912,10 @@ virGetVersion(unsigned long *libVer, const char *type,
if (STRCASEEQ(type, "LXC"))
*typeVer = LIBVIR_VERSION_NUMBER;
# endif
+# if WITH_LIBXL
+ if (STRCASEEQ(type, "libxl"))
+ *typeVer = LIBVIR_VERSION_NUMBER;
+# endif
# if WITH_PHYP
if (STRCASEEQ(type, "phyp"))
*typeVer = LIBVIR_VERSION_NUMBER;
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c
new file mode 100644
index 0000000..a48eea3
--- /dev/null
+++ b/src/libxl/libxl_conf.c
@@ -0,0 +1,896 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*---------------------------------------------------------------------------*/
+
+#include <config.h>
+
+#include <regex.h>
+#include <libxl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+
+#include "internal.h"
+#include "logging.h"
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "files.h"
+#include "memory.h"
+#include "uuid.h"
+#include "capabilities.h"
+#include "libxl_driver.h"
+#include "libxl_conf.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_LIBXL
+
+
+struct guest_arch {
+ const char *model;
+ int bits;
+ int hvm;
+ int pae;
+ int nonpae;
+ int ia64_be;
+};
+
+static const char *xen_cap_re = "(xen|hvm)-[[:digit:]]+\\.[[:digit:]]+-(x86_32|x86_64|ia64|powerpc64)(p|be)?";
+static regex_t xen_cap_rec;
+
+
+static int
+libxlNextFreeVncPort(libxlDriverPrivatePtr driver, int startPort)
+{
+ int i;
+
+ for (i = startPort ; i < LIBXL_VNC_PORT_MAX; i++) {
+ int fd;
+ int reuse = 1;
+ struct sockaddr_in addr;
+ bool used = false;
+
+ if (virBitmapGetBit(driver->reservedVNCPorts,
+ i - LIBXL_VNC_PORT_MIN, &used) < 0)
+ VIR_DEBUG("virBitmapGetBit failed on bit %d", i - LIBXL_VNC_PORT_MIN);
+
+ if (used)
+ continue;
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(i);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ fd = socket(PF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ return -1;
+
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&reuse, sizeof(reuse)) < 0) {
+ VIR_FORCE_CLOSE(fd);
+ break;
+ }
+
+ if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
+ /* Not in use, lets grab it */
+ VIR_FORCE_CLOSE(fd);
+ /* Add port to bitmap of reserved ports */
+ if (virBitmapSetBit(driver->reservedVNCPorts,
+ i - LIBXL_VNC_PORT_MIN) < 0) {
+ VIR_DEBUG("virBitmapSetBit failed on bit %d",
+ i - LIBXL_VNC_PORT_MIN);
+ }
+ return i;
+ }
+ VIR_FORCE_CLOSE(fd);
+
+ if (errno == EADDRINUSE) {
+ /* In use, try next */
+ continue;
+ }
+ /* Some other bad failure, get out.. */
+ break;
+ }
+ return -1;
+}
+
+static virCapsPtr
+libxlBuildCapabilities(const char *hostmachine,
+ int host_pae,
+ struct guest_arch *guest_archs,
+ int nr_guest_archs)
+{
+ virCapsPtr caps;
+ int i;
+
+ if ((caps = virCapabilitiesNew(hostmachine, 1, 1)) == NULL)
+ goto no_memory;
+
+ virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x00, 0x16, 0x3e });
+
+ if (host_pae &&
+ virCapabilitiesAddHostFeature(caps, "pae") < 0)
+ goto no_memory;
+
+ for (i = 0; i < nr_guest_archs; ++i) {
+ virCapsGuestPtr guest;
+ char const *const xen_machines[] = {guest_archs[i].hvm ? "xenfv" : "xenpv"};
+ virCapsGuestMachinePtr *machines;
+
+ if ((machines = virCapabilitiesAllocMachines(xen_machines, 1)) == NULL)
+ goto no_memory;
+
+ if ((guest = virCapabilitiesAddGuest(caps,
+ guest_archs[i].hvm ? "hvm" : "xen",
+ guest_archs[i].model,
+ guest_archs[i].bits,
+ (STREQ(hostmachine, "x86_64") ?
+ "/usr/lib64/xen/bin/qemu-dm" :
+ "/usr/lib/xen/bin/qemu-dm"),
+ (guest_archs[i].hvm ?
+ "/usr/lib/xen/boot/hvmloader" :
+ NULL),
+ 1,
+ machines)) == NULL) {
+ virCapabilitiesFreeMachines(machines, 1);
+ goto no_memory;
+ }
+ machines = NULL;
+
+ if (virCapabilitiesAddGuestDomain(guest,
+ "xen",
+ NULL,
+ NULL,
+ 0,
+ NULL) == NULL)
+ goto no_memory;
+
+ if (guest_archs[i].pae &&
+ virCapabilitiesAddGuestFeature(guest,
+ "pae",
+ 1,
+ 0) == NULL)
+ goto no_memory;
+
+ if (guest_archs[i].nonpae &&
+ virCapabilitiesAddGuestFeature(guest,
+ "nonpae",
+ 1,
+ 0) == NULL)
+ goto no_memory;
+
+ if (guest_archs[i].ia64_be &&
+ virCapabilitiesAddGuestFeature(guest,
+ "ia64_be",
+ 1,
+ 0) == NULL)
+ goto no_memory;
+
+ if (guest_archs[i].hvm) {
+ if (virCapabilitiesAddGuestFeature(guest,
+ "acpi",
+ 1,
+ 1) == NULL)
+ goto no_memory;
+
+ if (virCapabilitiesAddGuestFeature(guest, "apic",
+ 1,
+ 0) == NULL)
+ goto no_memory;
+
+ if (virCapabilitiesAddGuestFeature(guest,
+ "hap",
+ 0,
+ 1) == NULL)
+ goto no_memory;
+ }
+ }
+
+ caps->defaultConsoleTargetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
+
+ return caps;
+
+ no_memory:
+ virCapabilitiesFree(caps);
+ return NULL;
+}
+
+static virCapsPtr
+libxlMakeCapabilitiesInternal(const char *hostmachine,
+ libxl_physinfo *phy_info,
+ char *capabilities)
+{
+ char *str, *token;
+ regmatch_t subs[4];
+ char *saveptr = NULL;
+ int i;
+
+ int host_pae = 0;
+ struct guest_arch guest_archs[32];
+ int nr_guest_archs = 0;
+ virCapsPtr caps = NULL;
+
+ memset(guest_archs, 0, sizeof(guest_archs));
+
+ // TODO: extract pae from phy_info->phys_cap
+ // for now, better default is 1
+ (void)phy_info;
+ host_pae = 1;
+
+ /* Format of capabilities string is documented in the code in
+ * xen-unstable.hg/xen/arch/.../setup.c.
+ *
+ * It is a space-separated list of supported guest architectures.
+ *
+ * For x86:
+ * TYP-VER-ARCH[p]
+ * ^ ^ ^ ^
+ * | | | +-- PAE supported
+ * | | +------- x86_32 or x86_64
+ * | +----------- the version of Xen, eg. "3.0"
+ * +--------------- "xen" or "hvm" for para or full virt respectively
+ *
+ * For IA64:
+ * TYP-VER-ARCH[be]
+ * ^ ^ ^ ^
+ * | | | +-- Big-endian supported
+ * | | +------- always "ia64"
+ * | +----------- the version of Xen, eg. "3.0"
+ * +--------------- "xen" or "hvm" for para or full virt respectively
+ */
+
+ /* Split capabilities string into tokens. strtok_r is OK here because
+ * we "own" the buffer. Parse out the features from each token.
+ */
+ for (str = capabilities, nr_guest_archs = 0;
+ nr_guest_archs < sizeof guest_archs / sizeof guest_archs[0]
+ && (token = strtok_r (str, " ", &saveptr)) != NULL;
+ str = NULL) {
+ if (regexec(&xen_cap_rec, token, sizeof subs / sizeof subs[0],
+ subs, 0) == 0) {
+ int hvm = STRPREFIX(&token[subs[1].rm_so], "hvm");
+ const char *model;
+ int bits, pae = 0, nonpae = 0, ia64_be = 0;
+
+ if (STRPREFIX(&token[subs[2].rm_so], "x86_32")) {
+ model = "i686";
+ bits = 32;
+ if (subs[3].rm_so != -1 &&
+ STRPREFIX(&token[subs[3].rm_so], "p"))
+ pae = 1;
+ else
+ nonpae = 1;
+ }
+ else if (STRPREFIX(&token[subs[2].rm_so], "x86_64")) {
+ model = "x86_64";
+ bits = 64;
+ }
+ else if (STRPREFIX(&token[subs[2].rm_so], "ia64")) {
+ model = "ia64";
+ bits = 64;
+ if (subs[3].rm_so != -1 &&
+ STRPREFIX(&token[subs[3].rm_so], "be"))
+ ia64_be = 1;
+ }
+ else if (STRPREFIX(&token[subs[2].rm_so], "powerpc64")) {
+ model = "ppc64";
+ bits = 64;
+ } else {
+ continue;
+ }
+
+ /* Search for existing matching (model,hvm) tuple */
+ for (i = 0 ; i < nr_guest_archs ; i++) {
+ if (STREQ(guest_archs[i].model, model) &&
+ guest_archs[i].hvm == hvm) {
+ break;
+ }
+ }
+
+ /* Too many arch flavours - highly unlikely ! */
+ if (i >= ARRAY_CARDINALITY(guest_archs))
+ continue;
+ /* Didn't find a match, so create a new one */
+ if (i == nr_guest_archs)
+ nr_guest_archs++;
+
+ guest_archs[i].model = model;
+ guest_archs[i].bits = bits;
+ guest_archs[i].hvm = hvm;
+
+ /* Careful not to overwrite a previous positive
+ setting with a negative one here - some archs
+ can do both pae & non-pae, but Xen reports
+ separately capabilities so we're merging archs */
+ if (pae)
+ guest_archs[i].pae = pae;
+ if (nonpae)
+ guest_archs[i].nonpae = nonpae;
+ if (ia64_be)
+ guest_archs[i].ia64_be = ia64_be;
+ }
+ }
+
+ if ((caps = libxlBuildCapabilities(hostmachine,
+ host_pae,
+ guest_archs,
+ nr_guest_archs)) == NULL)
+ goto no_memory;
+
+ return caps;
+
+ no_memory:
+ virReportOOMError();
+ virCapabilitiesFree(caps);
+ return NULL;
+}
+
+static int
+libxlMakeDomCreateInfo(virDomainDefPtr def, libxl_domain_create_info *c_info)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ libxl_init_create_info(c_info);
+
+ c_info->hvm = STREQ(def->os.type, "hvm");
+ if ((c_info->name = strdup(def->name)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+
+ virUUIDFormat(def->uuid, uuidstr);
+ if (libxl_uuid_from_string(&c_info->uuid, uuidstr) ) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("libxenlight failed to parse UUID '%s'"), uuidstr);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ libxl_domain_create_info_destroy(c_info);
+ return -1;
+}
+
+static int
+libxlMakeDomBuildInfo(virDomainDefPtr def, libxl_domain_config *d_config)
+{
+ libxl_domain_build_info *b_info = &d_config->b_info;
+ int hvm = STREQ(def->os.type, "hvm");
+
+ libxl_init_build_info(b_info, &d_config->c_info);
+
+ b_info->hvm = hvm;
+ b_info->max_vcpus = def->maxvcpus;
+ b_info->cur_vcpus = def->vcpus;
+ if (def->clock.ntimers > 0 &&
+ def->clock.timers[0]->name == VIR_DOMAIN_TIMER_NAME_TSC) {
+ switch (def->clock.timers[0]->mode) {
+ case VIR_DOMAIN_TIMER_MODE_NATIVE:
+ b_info->tsc_mode = 2;
+ break;
+ case VIR_DOMAIN_TIMER_MODE_PARAVIRT:
+ b_info->tsc_mode = 3;
+ break;
+ default:
+ b_info->tsc_mode = 1;
+ }
+ }
+ b_info->max_memkb = def->mem.max_balloon;
+ b_info->target_memkb = def->mem.cur_balloon;
+ if (hvm) {
+ b_info->u.hvm.pae = def->features & (1 << VIR_DOMAIN_FEATURE_PAE);
+ b_info->u.hvm.apic = def->features & (1 << VIR_DOMAIN_FEATURE_APIC);
+ b_info->u.hvm.acpi = def->features & (1 << VIR_DOMAIN_FEATURE_ACPI);
+ /*
+ * The following comment and calculation were taken directly from
+ * libxenlight's internal function libxl_get_required_shadow_memory():
+ *
+ * 256 pages (1MB) per vcpu, plus 1 page per MiB of RAM for the P2M map,
+ * plus 1 page per MiB of RAM to shadow the resident processes.
+ */
+ b_info->shadow_memkb = 4 * (256 * b_info->cur_vcpus +
+ 2 * (b_info->max_memkb / 1024));
+ } else {
+ if (def->os.bootloader) {
+ if ((b_info->u.pv.bootloader = strdup(def->os.bootloader)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ if (def->os.bootloaderArgs) {
+ if ((b_info->u.pv.bootloader_args = strdup(def->os.bootloaderArgs)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ if (def->os.cmdline) {
+ if ((b_info->u.pv.cmdline = strdup(def->os.cmdline)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ if (def->os.kernel) {
+ /* libxl_init_build_info() sets kernel.path = strdup("hvmloader") */
+ free(b_info->kernel.path);
+ if ((b_info->kernel.path = strdup(def->os.kernel)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ if (def->os.initrd) {
+ if ((b_info->u.pv.ramdisk.path = strdup(def->os.initrd)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ }
+
+ return 0;
+
+error:
+ libxl_domain_build_info_destroy(b_info);
+ return -1;
+}
+
+static int
+libxlMakeDiskList(virDomainDefPtr def, libxl_domain_config *d_config)
+{
+ virDomainDiskDefPtr *l_disks = def->disks;
+ int ndisks = def->ndisks;
+ libxl_device_disk *x_disks;
+ int i;
+
+ if (VIR_ALLOC_N(x_disks, ndisks) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ for (i = 0; i < ndisks; i++) {
+ if (l_disks[i]->src &&
+ (x_disks[i].pdev_path = strdup(l_disks[i]->src)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+
+ if (l_disks[i]->dst &&
+ (x_disks[i].vdev = strdup(l_disks[i]->dst)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+
+ if (l_disks[i]->driverName) {
+ if (STREQ(l_disks[i]->driverName, "tap") ||
+ STREQ(l_disks[i]->driverName, "tap2")) {
+ if (l_disks[i]->driverType) {
+ if (STREQ(l_disks[i]->driverType, "qcow")) {
+ x_disks[i].format = DISK_FORMAT_QCOW;
+ x_disks[i].backend = DISK_BACKEND_QDISK;
+ } else if (STREQ(l_disks[i]->driverType, "qcow2")) {
+ x_disks[i].format = DISK_FORMAT_QCOW2;
+ x_disks[i].backend = DISK_BACKEND_QDISK;
+ } else if (STREQ(l_disks[i]->driverType, "vhd")) {
+ x_disks[i].format = DISK_FORMAT_VHD;
+ x_disks[i].backend = DISK_BACKEND_TAP;
+ } else if (STREQ(l_disks[i]->driverType, "aio") ||
+ STREQ(l_disks[i]->driverType, "raw")) {
+ x_disks[i].format = DISK_FORMAT_RAW;
+ x_disks[i].backend = DISK_BACKEND_TAP;
+ }
+ } else {
+ /* No subtype specified, default to raw/tap */
+ x_disks[i].format = DISK_FORMAT_RAW;
+ x_disks[i].backend = DISK_BACKEND_TAP;
+ }
+ } else if (STREQ(l_disks[i]->driverName, "file")) {
+ x_disks[i].format = DISK_FORMAT_RAW;
+ x_disks[i].backend = DISK_BACKEND_TAP;
+ } else if (STREQ(l_disks[i]->driverName, "phy")) {
+ x_disks[i].format = DISK_FORMAT_RAW;
+ x_disks[i].backend = DISK_BACKEND_PHY;
+ } else {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("libxenlight does not support disk driver %s"),
+ l_disks[i]->driverName);
+ goto error;
+ }
+ } else {
+ /* No driverName - default to raw/tap?? */
+ x_disks[i].format = DISK_FORMAT_RAW;
+ x_disks[i].backend = DISK_BACKEND_TAP;
+ }
+
+ /* How to set unpluggable? */
+ x_disks[i].unpluggable = 1;
+ x_disks[i].readwrite = !l_disks[i]->readonly;
+ x_disks[i].is_cdrom =
+ l_disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM ? 1 : 0;
+ }
+
+ d_config->disks = x_disks;
+ d_config->num_disks = ndisks;
+
+ return 0;
+
+error:
+ for (i = 0; i < ndisks; i++)
+ libxl_device_disk_destroy(&x_disks[i]);
+ VIR_FREE(x_disks);
+ return -1;
+}
+
+static int
+libxlMakeNicList(virDomainDefPtr def, libxl_domain_config *d_config)
+{
+ virDomainNetDefPtr *l_nics = def->nets;
+ int nnics = def->nnets;
+ libxl_device_nic *x_nics;
+ int i;
+
+ if (VIR_ALLOC_N(x_nics, nnics) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ for (i = 0; i < nnics; i++) {
+ x_nics[i].devid = i;
+
+ // TODO: Where is mtu stored?
+ x_nics[i].mtu = 1492;
+
+ memcpy(x_nics[i].mac, l_nics[i]->mac, sizeof(libxl_mac));
+
+ if (l_nics[i]->model && !STREQ(l_nics[i]->model, "netfront")) {
+ if ((x_nics[i].model = strdup(l_nics[i]->model)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ x_nics[i].nictype = NICTYPE_IOEMU;
+ } else {
+ x_nics[i].nictype = NICTYPE_VIF;
+ }
+
+ if (l_nics[i]->ifname &&
+ (x_nics[i].ifname = strdup(l_nics[i]->ifname)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+
+ if (l_nics[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
+ if (l_nics[i]->data.bridge.brname &&
+ (x_nics[i].bridge =
+ strdup(l_nics[i]->data.bridge.brname)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ if (l_nics[i]->data.bridge.script &&
+ (x_nics[i].script =
+ strdup(l_nics[i]->data.bridge.script)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+
+ //TODO
+ //x_nics[i].ip = ;
+ }
+
+ d_config->vifs = x_nics;
+ d_config->num_vifs = nnics;
+
+ return 0;
+
+error:
+ for (i = 0; i < nnics; i++)
+ libxl_device_nic_destroy(&x_nics[i]);
+ VIR_FREE(x_nics);
+ return -1;
+}
+
+static int
+libxlMakeVfbList(libxlDriverPrivatePtr driver,
+ virDomainDefPtr def, libxl_domain_config *d_config)
+{
+ virDomainGraphicsDefPtr *l_vfbs = def->graphics;
+ int nvfbs = def->ngraphics;
+ libxl_device_vfb *x_vfbs;
+ libxl_device_vkb *x_vkbs;
+ int i;
+ int port;
+
+ if (nvfbs == 0)
+ return 0;
+
+ if (VIR_ALLOC_N(x_vfbs, nvfbs) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ if (VIR_ALLOC_N(x_vkbs, nvfbs) < 0) {
+ virReportOOMError();
+ VIR_FREE(x_vfbs);
+ return -1;
+ }
+
+ for (i = 0; i < nvfbs; i++) {
+ libxl_device_vfb_init(&x_vfbs[i], i);
+ libxl_device_vkb_init(&x_vkbs[i], i);
+
+ switch (l_vfbs[i]->type) {
+ case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
+ x_vfbs[i].sdl = 1;
+ if (l_vfbs[i]->data.sdl.display &&
+ (x_vfbs[i].display =
+ strdup(l_vfbs[i]->data.sdl.display)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ if (l_vfbs[i]->data.sdl.xauth &&
+ (x_vfbs[i].xauthority =
+ strdup(l_vfbs[i]->data.sdl.xauth)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ break;
+ case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
+ x_vfbs[i].vnc = 1;
+ /* driver handles selection of free port */
+ x_vfbs[i].vncunused = 0;
+ if (l_vfbs[i]->data.vnc.autoport) {
+ port = libxlNextFreeVncPort(driver, LIBXL_VNC_PORT_MIN);
+ if (port < 0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Unable to find an unused VNC port"));
+ goto error;
+ }
+ l_vfbs[i]->data.vnc.port = port;
+ }
+ x_vfbs[i].vncdisplay = l_vfbs[i]->data.vnc.port -
+ LIBXL_VNC_PORT_MIN;
+
+ if (l_vfbs[i]->data.vnc.listenAddr) {
+ /* libxl_device_vfb_init() does strdup("127.0.0.1") */
+ free(x_vfbs[i].vnclisten);
+ if ((x_vfbs[i].vnclisten =
+ strdup(l_vfbs[i]->data.vnc.listenAddr)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ if (l_vfbs[i]->data.vnc.keymap &&
+ (x_vfbs[i].keymap =
+ strdup(l_vfbs[i]->data.vnc.keymap)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ break;
+ }
+ }
+
+ d_config->vfbs = x_vfbs;
+ d_config->vkbs = x_vkbs;
+ d_config->num_vfbs = d_config->num_vkbs = nvfbs;
+
+ return 0;
+
+error:
+ for (i = 0; i < nvfbs; i++) {
+ libxl_device_vfb_destroy(&x_vfbs[i]);
+ libxl_device_vkb_destroy(&x_vkbs[i]);
+ }
+ VIR_FREE(x_vfbs);
+ VIR_FREE(x_vkbs);
+ return -1;
+}
+
+static int
+libxlMakeChrdevStr(virDomainChrDefPtr def, char **buf)
+{
+ const char *type = virDomainChrTypeToString(def->source.type);
+
+ if (!type) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("unexpected chr device type"));
+ return -1;
+ }
+
+ switch (def->source.type) {
+ case VIR_DOMAIN_CHR_TYPE_NULL:
+ case VIR_DOMAIN_CHR_TYPE_STDIO:
+ case VIR_DOMAIN_CHR_TYPE_VC:
+ case VIR_DOMAIN_CHR_TYPE_PTY:
+ if (virAsprintf(buf, "%s", type) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_FILE:
+ case VIR_DOMAIN_CHR_TYPE_PIPE:
+ if (virAsprintf(buf, "%s:%s", type,
+ def->source.data.file.path) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_DEV:
+ if (virAsprintf(buf, "%s", def->source.data.file.path) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static int
+libxlMakeDeviceModelInfo(virDomainDefPtr def, libxl_domain_config *d_config)
+{
+ libxl_device_model_info *dm_info = &d_config->dm_info;
+ int i;
+ char b_order[VIR_DOMAIN_BOOT_LAST+1];
+
+ libxl_init_dm_info(dm_info, &d_config->c_info, &d_config->b_info);
+
+ if (d_config->b_info.hvm) {
+ /* HVM-specific device model info */
+ dm_info->type = XENFV;
+ if (def->os.nBootDevs > 0) {
+ free(dm_info->boot);
+ for (i = 0; i < def->os.nBootDevs; i++) {
+ switch (def->os.bootDevs[i]) {
+ case VIR_DOMAIN_BOOT_FLOPPY:
+ b_order[i] = 'a';
+ break;
+ default:
+ case VIR_DOMAIN_BOOT_DISK:
+ b_order[i] = 'c';
+ break;
+ case VIR_DOMAIN_BOOT_CDROM:
+ b_order[i] = 'd';
+ break;
+ case VIR_DOMAIN_BOOT_NET:
+ b_order[i] = 'n';
+ break;
+ }
+ }
+ b_order[def->os.nBootDevs] = '\0';
+ if ((dm_info->boot = strdup(b_order)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ if (def->serials &&
+ (libxlMakeChrdevStr(def->serials[0], &dm_info->serial) < 0))
+ goto error;
+ } else {
+ /* PV-specific device model info */
+ dm_info->type = XENPV;
+ }
+
+ /* Build qemu graphics options from previously parsed vfb */
+ if (d_config->num_vfbs > 0) {
+ if (d_config->vfbs[0].vnc) {
+ dm_info->vnc = 1;
+ /* driver handles selection of free port */
+ dm_info->vncunused = 0;
+ if (d_config->vfbs[0].vnclisten) {
+ free(dm_info->vnclisten);
+ if ((dm_info->vnclisten =
+ strdup(d_config->vfbs[0].vnclisten)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ }
+ if (d_config->vfbs[0].keymap &&
+ (dm_info->keymap = strdup(d_config->vfbs[0].keymap)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ dm_info->vncdisplay = d_config->vfbs[0].vncdisplay;
+ if (d_config->vfbs[0].vncpasswd &&
+ (dm_info->vncpasswd =
+ strdup(d_config->vfbs[0].vncpasswd)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+ } else if (d_config->vfbs[0].sdl) {
+ dm_info->sdl = 1;
+ dm_info->vnc = 0;
+ }
+ } else if (d_config->num_vfbs == 0) {
+ dm_info->nographic = 1;
+ dm_info->vnc = 0;
+ }
+
+ // TODO
+ //dm_info->usb = ;
+ //dm_info->usbdevice = ;
+ //dm_info->soundhw = ;
+
+ return 0;
+
+error:
+ libxl_device_model_info_destroy(dm_info);
+ return -1;
+}
+
+virCapsPtr
+libxlMakeCapabilities(libxl_ctx *ctx)
+{
+ libxl_physinfo phy_info;
+ const libxl_version_info *ver_info;
+ struct utsname utsname;
+
+ regcomp (&xen_cap_rec, xen_cap_re, REG_EXTENDED);
+
+ if (libxl_get_physinfo(ctx, &phy_info) != 0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to get node physical info from libxenlight"));
+ return NULL;
+ }
+
+ if ((ver_info = libxl_get_version_info(ctx)) == NULL) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to get version info from libxenlight"));
+ return NULL;
+ }
+
+ uname(&utsname);
+
+ return libxlMakeCapabilitiesInternal(utsname.machine,
+ &phy_info,
+ ver_info->capabilities);
+}
+
+int
+libxlBuildDomainConfig(libxlDriverPrivatePtr driver,
+ virDomainDefPtr def, libxl_domain_config *d_config)
+{
+
+ if (libxlMakeDomCreateInfo(def, &d_config->c_info) < 0)
+ return -1;
+
+ if (libxlMakeDomBuildInfo(def, d_config) < 0) {
+ goto error;
+ }
+
+ if (libxlMakeDiskList(def, d_config) < 0) {
+ goto error;
+ }
+
+ if (libxlMakeNicList(def, d_config) < 0) {
+ goto error;
+ }
+
+ if (libxlMakeVfbList(driver, def, d_config) < 0) {
+ goto error;
+ }
+
+ if (libxlMakeDeviceModelInfo(def, d_config) < 0) {
+ goto error;
+ }
+
+ d_config->on_reboot = def->onReboot;
+ d_config->on_poweroff = def->onPoweroff;
+ d_config->on_crash = def->onCrash;
+
+ return 0;
+
+error:
+ libxl_domain_config_destroy(d_config);
+ return -1;
+}
diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h
new file mode 100644
index 0000000..bb49d35
--- /dev/null
+++ b/src/libxl/libxl_conf.h
@@ -0,0 +1,91 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*---------------------------------------------------------------------------*/
+
+#ifndef LIBXL_CONF_H
+# define LIBXL_CONF_H
+
+# include <config.h>
+
+# include <libxl.h>
+
+# include "internal.h"
+# include "domain_conf.h"
+# include "capabilities.h"
+# include "configmake.h"
+# include "bitmap.h"
+
+
+# define LIBXL_VNC_PORT_MIN 5900
+# define LIBXL_VNC_PORT_MAX 65535
+
+# define LIBXL_CONFIG_DIR SYSCONFDIR "/libvirt/libxl"
+# define LIBXL_AUTOSTART_DIR LIBXL_CONFIG_DIR "/autostart"
+# define LIBXL_STATE_DIR LOCALSTATEDIR "/run/libvirt/libxl"
+# define LIBXL_LOG_DIR LOCALSTATEDIR "/log/libvirt/libxl"
+# define LIBXL_LIB_DIR LOCALSTATEDIR "/lib/libvirt/libxl"
+# define LIBXL_SAVE_DIR LIBXL_LIB_DIR "/save"
+
+
+typedef struct _libxlDriverPrivate libxlDriverPrivate;
+typedef libxlDriverPrivate *libxlDriverPrivatePtr;
+struct _libxlDriverPrivate {
+ virMutex lock;
+ virCapsPtr caps;
+ unsigned int version;
+
+ FILE *logger_file;
+ xentoollog_logger *logger;
+ /* libxl ctx for driver wide ops; getVersion, getNodeInfo, ... */
+ libxl_ctx ctx;
+
+ virBitmapPtr reservedVNCPorts;
+ virDomainObjList domains;
+
+ char *configDir;
+ char *autostartDir;
+ char *logDir;
+ char *stateDir;
+ char *libDir;
+ char *saveDir;
+};
+
+typedef struct _libxlDomainObjPrivate libxlDomainObjPrivate;
+typedef libxlDomainObjPrivate *libxlDomainObjPrivatePtr;
+struct _libxlDomainObjPrivate {
+ /* per domain libxl ctx */
+ libxl_ctx ctx;
+ libxl_waiter *dWaiter;
+ int waiterFD;
+ int eventHdl;
+};
+
+
+# define libxlError(code, ...) \
+ virReportErrorHelper(NULL, VIR_FROM_LIBXL, code, __FILE__, \
+ __FUNCTION__, __LINE__, __VA_ARGS__)
+
+virCapsPtr
+libxlMakeCapabilities(libxl_ctx *ctx);
+
+int
+libxlBuildDomainConfig(libxlDriverPrivatePtr driver,
+ virDomainDefPtr def, libxl_domain_config *d_config);
+
+
+#endif /* LIBXL_CONF_H */
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
new file mode 100644
index 0000000..7559949
--- /dev/null
+++ b/src/libxl/libxl_driver.c
@@ -0,0 +1,1420 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany.
+ * Copyright (C) 2011 Univention GmbH.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*---------------------------------------------------------------------------*/
+
+#include <config.h>
+
+#include <sys/utsname.h>
+#include <libxl.h>
+
+#include "internal.h"
+#include "logging.h"
+#include "virterror_internal.h"
+#include "datatypes.h"
+#include "files.h"
+#include "memory.h"
+#include "event.h"
+#include "uuid.h"
+#include "libxl_driver.h"
+#include "libxl_conf.h"
+
+
+#define VIR_FROM_THIS VIR_FROM_LIBXL
+
+#define LIBXL_DOM_REQ_POWEROFF 0
+#define LIBXL_DOM_REQ_REBOOT 1
+#define LIBXL_DOM_REQ_SUSPEND 2
+#define LIBXL_DOM_REQ_CRASH 3
+#define LIBXL_DOM_REQ_HALT 4
+
+static libxlDriverPrivatePtr libxl_driver = NULL;
+
+
+/* Function declarations */
+static int
+libxlVmStart(libxlDriverPrivatePtr driver,
+ virDomainObjPtr vm, bool start_paused);
+
+
+/* Function definitions */
+static void
+libxlDriverLock(libxlDriverPrivatePtr driver)
+{
+ virMutexLock(&driver->lock);
+}
+
+static void
+libxlDriverUnlock(libxlDriverPrivatePtr driver)
+{
+ virMutexUnlock(&driver->lock);
+}
+
+static void *
+libxlDomainObjPrivateAlloc(void)
+{
+ libxlDomainObjPrivatePtr priv;
+
+ if (VIR_ALLOC(priv) < 0)
+ return NULL;
+
+ libxl_ctx_init(&priv->ctx, LIBXL_VERSION, libxl_driver->logger);
+ priv->waiterFD = -1;
+ priv->eventHdl = -1;
+
+ return priv;
+}
+
+static void
+libxlDomainObjPrivateFree(void *data)
+{
+ libxlDomainObjPrivatePtr priv = data;
+
+ if (priv->eventHdl >= 0)
+ virEventRemoveHandle(priv->eventHdl);
+
+ if (priv->dWaiter) {
+ libxl_stop_waiting(&priv->ctx, priv->dWaiter);
+ libxl_free_waiter(priv->dWaiter);
+ VIR_FREE(priv->dWaiter);
+ }
+
+ libxl_ctx_free(&priv->ctx);
+ VIR_FREE(priv);
+}
+
+/*
+ * Cleanup function for domain that has reached shutoff state.
+ *
+ * virDomainObjPtr should be locked on invocation
+ */
+static void
+libxlVmCleanup(libxlDriverPrivatePtr driver, virDomainObjPtr vm)
+{
+ libxlDomainObjPrivatePtr priv = vm->privateData;
+ int vnc_port;
+ char *file;
+
+ if (priv->eventHdl >= 0) {
+ virEventRemoveHandle(priv->eventHdl);
+ priv->eventHdl = -1;
+ }
+
+ if (priv->dWaiter) {
+ libxl_stop_waiting(&priv->ctx, priv->dWaiter);
+ libxl_free_waiter(priv->dWaiter);
+ VIR_FREE(priv->dWaiter);
+ }
+
+ if (vm->persistent) {
+ vm->def->id = -1;
+ vm->state = VIR_DOMAIN_SHUTOFF;
+ }
+
+ if ((vm->def->ngraphics == 1) &&
+ vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
+ vm->def->graphics[0]->data.vnc.autoport) {
+ vnc_port = vm->def->graphics[0]->data.vnc.port;
+ if (vnc_port >= LIBXL_VNC_PORT_MIN) {
+ if (virBitmapClearBit(driver->reservedVNCPorts,
+ vnc_port - LIBXL_VNC_PORT_MIN) < 0)
+ VIR_DEBUG("Could not mark port %d as unused", vnc_port);
+ }
+ }
+
+ if (virAsprintf(&file, "%s/%s.xml", driver->stateDir, vm->def->name) > 0) {
+ if (unlink(file) < 0 && errno != ENOENT && errno != ENOTDIR)
+ VIR_DEBUG("Failed to remove domain XML for %s", vm->def->name);
+ VIR_FREE(file);
+ }
+}
+
+/*
+ * Reap a domain from libxenlight.
+ *
+ * virDomainObjPtr should be locked on invocation
+ */
+static int
+libxlVmReap(libxlDriverPrivatePtr driver, virDomainObjPtr vm, int force)
+{
+ libxlDomainObjPrivatePtr priv = vm->privateData;
+
+ if (libxl_domain_destroy(&priv->ctx, vm->def->id, force) < 0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to cleanup domain %d"), vm->def->id);
+ return -1;
+ }
+
+ libxlVmCleanup(driver, vm);
+ return 0;
+}
+
+/*
+ * Handle previously registered event notification from libxenlight
+ */
+static void libxlEventHandler(int watch,
+ int fd,
+ int events,
+ void *data)
+{
+ libxlDriverPrivatePtr driver = libxl_driver;
+ virDomainObjPtr vm = data;
+ libxlDomainObjPrivatePtr priv;
+ libxl_event event;
+ libxl_dominfo info;
+
+ libxlDriverLock(driver);
+ virDomainObjLock(vm);
+ libxlDriverUnlock(driver);
+
+ priv = vm->privateData;
+
+ memset(&event, 0, sizeof(event));
+ memset(&info, 0, sizeof(info));
+
+ if (priv->waiterFD != fd || priv->eventHdl != watch) {
+ virEventRemoveHandle(watch);
+ priv->eventHdl = -1;
+ goto cleanup;
+ }
+
+ if (!(events & VIR_EVENT_HANDLE_READABLE))
+ goto cleanup;
+
+ if (libxl_get_event(&priv->ctx, &event))
+ goto cleanup;
+
+ if (event.type == LIBXL_EVENT_DOMAIN_DEATH) {
+ /* libxl_event_get_domain_death_info returns 1 if death
+ * event was for this domid */
+ if (libxl_event_get_domain_death_info(&priv->ctx,
+ vm->def->id,
+ &event,
+ &info) != 1)
+ goto cleanup;
+
+ virEventRemoveHandle(watch);
+ priv->eventHdl = -1;
+ switch (info.shutdown_reason) {
+ case SHUTDOWN_poweroff:
+ case SHUTDOWN_crash:
+ libxlVmReap(driver, vm, 0);
+ if (!vm->persistent) {
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ }
+ break;
+ case SHUTDOWN_reboot:
+ libxlVmReap(driver, vm, 0);
+ libxlVmStart(driver, vm, 0);
+ break;
+ default:
+ VIR_INFO("Unhandled shutdown_reason %d", info.shutdown_reason);
+ break;
+ }
+ }
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxl_free_event(&event);
+}
+
+/*
+ * Register domain events with libxenlight and insert event handles
+ * in libvirt's event loop.
+ */
+static int
+libxlCreateDomEvents(virDomainObjPtr vm)
+{
+ libxlDomainObjPrivatePtr priv = vm->privateData;
+ int fd;
+
+ if (VIR_ALLOC(priv->dWaiter) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if (libxl_wait_for_domain_death(&priv->ctx, vm->def->id, priv->dWaiter))
+ goto error;
+
+ libxl_get_wait_fd(&priv->ctx, &fd);
+ if (fd < 0)
+ goto error;
+
+ priv->waiterFD = fd;
+ if ((priv->eventHdl = virEventAddHandle(
+ fd,
+ VIR_EVENT_HANDLE_READABLE | VIR_EVENT_HANDLE_ERROR,
+ libxlEventHandler,
+ vm, NULL)) < 0)
+ goto error;
+
+ return 0;
+
+error:
+ libxl_free_waiter(priv->dWaiter);
+ VIR_FREE(priv->dWaiter);
+ priv->eventHdl = -1;
+ return -1;
+}
+
+/*
+ * Start a domain through libxenlight.
+ *
+ * virDomainObjPtr should be locked on invocation
+ */
+static int
+libxlVmStart(libxlDriverPrivatePtr driver,
+ virDomainObjPtr vm, bool start_paused)
+{
+ libxl_domain_config d_config;
+ virDomainDefPtr def = vm->def;
+ int ret;
+ uint32_t domid = 0;
+ char *dom_xml = NULL;
+ pid_t child_console_pid = -1;
+ libxlDomainObjPrivatePtr priv = vm->privateData;
+
+ memset(&d_config, 0, sizeof(d_config));
+
+ if (libxlBuildDomainConfig(driver, def, &d_config) < 0 )
+ return -1;
+
+ //TODO: Balloon dom0 ??
+ //ret = freemem(&d_config->b_info, &d_config->dm_info);
+
+ ret = libxl_domain_create_new(&priv->ctx, &d_config,
+ NULL, &child_console_pid, &domid);
+ if (ret) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("libxenlight failed to create new domain '%s'"),
+ d_config.c_info.name);
+ goto error;
+ }
+
+ def->id = domid;
+ if ((dom_xml = virDomainDefFormat(def, 0)) == NULL)
+ goto error;
+
+ if(libxl_userdata_store(&priv->ctx, domid, "libvirt-xml",
+ (uint8_t *)dom_xml, strlen(dom_xml) + 1)) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("libxenlight failed to store userdata"));
+ goto error;
+ }
+
+ if (libxlCreateDomEvents(vm) < 0)
+ goto error;
+
+ if (!start_paused) {
+ libxl_domain_unpause(&priv->ctx, domid);
+ vm->state = VIR_DOMAIN_RUNNING;
+ } else {
+ vm->state = VIR_DOMAIN_PAUSED;
+ }
+
+ if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
+ goto error;
+
+ libxl_domain_config_destroy(&d_config);
+ VIR_FREE(dom_xml);
+ return 0;
+
+error:
+ if (domid > 0) {
+ libxl_domain_destroy(&priv->ctx, domid, 0);
+ def->id = -1;
+ vm->state = VIR_DOMAIN_SHUTOFF;
+ }
+ libxl_domain_config_destroy(&d_config);
+ VIR_FREE(dom_xml);
+ return -1;
+}
+
+
+/*
+ * Reconnect to running domains that were previously started/created
+ * with libxenlight driver.
+ */
+static void
+libxlReconnectDomain(void *payload,
+ const void *name ATTRIBUTE_UNUSED,
+ void *opaque)
+{
+ virDomainObjPtr vm = payload;
+ libxlDriverPrivatePtr driver = opaque;
+ int rc;
+ libxl_dominfo d_info;
+ int len;
+ uint8_t *data = NULL;
+
+ virDomainObjLock(vm);
+
+ /* Does domain still exist? */
+ rc = libxl_domain_info(&driver->ctx, &d_info, vm->def->id);
+ if (rc == ERROR_INVAL) {
+ goto out;
+ } else if (rc != 0) {
+ VIR_DEBUG("libxl_domain_info failed (code %d), ignoring domain %d",
+ rc, vm->def->id);
+ goto out;
+ }
+
+ /* Is this a domain that was under libvirt control? */
+ if (libxl_userdata_retrieve(&driver->ctx, vm->def->id,
+ "libvirt-xml", &data, &len)) {
+ VIR_DEBUG("libxl_userdata_retrieve failed, ignoring domain %d", vm->def->id);
+ goto out;
+ }
+
+ /* Update domid in case it changed (e.g. reboot) while we were gone? */
+ vm->def->id = d_info.domid;
+ vm->state = VIR_DOMAIN_RUNNING;
+
+ /* Recreate domain death et. al. events */
+ libxlCreateDomEvents(vm);
+ virDomainObjUnlock(vm);
+ return;
+
+out:
+ libxlVmCleanup(driver, vm);
+ if (!vm->persistent)
+ virDomainRemoveInactive(&driver->domains, vm);
+ else
+ virDomainObjUnlock(vm);
+}
+
+static void
+libxlReconnectDomains(libxlDriverPrivatePtr driver)
+{
+ virHashForEach(driver->domains.objs, libxlReconnectDomain, driver);
+}
+
+static int
+libxlShutdown(void)
+{
+ if (!libxl_driver)
+ return -1;
+
+ libxlDriverLock(libxl_driver);
+ virCapabilitiesFree(libxl_driver->caps);
+ virDomainObjListDeinit(&libxl_driver->domains);
+ libxl_ctx_free(&libxl_driver->ctx);
+ xtl_logger_destroy(libxl_driver->logger);
+ if (libxl_driver->logger_file)
+ VIR_FORCE_FCLOSE(libxl_driver->logger_file);
+
+ virBitmapFree(libxl_driver->reservedVNCPorts);
+
+ VIR_FREE(libxl_driver->configDir);
+ VIR_FREE(libxl_driver->autostartDir);
+ VIR_FREE(libxl_driver->logDir);
+ VIR_FREE(libxl_driver->stateDir);
+ VIR_FREE(libxl_driver->libDir);
+ VIR_FREE(libxl_driver->saveDir);
+
+ libxlDriverUnlock(libxl_driver);
+ virMutexDestroy(&libxl_driver->lock);
+ VIR_FREE(libxl_driver);
+
+ return 0;
+}
+
+static int
+libxlStartup(int privileged) {
+ const libxl_version_info *ver_info;
+ char *log_file = NULL;
+
+ /* Check that the user is root, silently disable if not */
+ if (!privileged) {
+ VIR_INFO0("Not running privileged, disabling libxenlight driver");
+ return 0;
+ }
+
+ if (VIR_ALLOC(libxl_driver) < 0)
+ return -1;
+
+ if (virMutexInit(&libxl_driver->lock) < 0) {
+ VIR_ERROR0(_("cannot initialize mutex"));
+ VIR_FREE(libxl_driver);
+ return -1;
+ }
+ libxlDriverLock(libxl_driver);
+
+ /* Allocate bitmap for vnc port reservation */
+ if ((libxl_driver->reservedVNCPorts =
+ virBitmapAlloc(LIBXL_VNC_PORT_MAX - LIBXL_VNC_PORT_MIN)) == NULL)
+ goto out_of_memory;
+
+ if (virDomainObjListInit(&libxl_driver->domains) < 0)
+ goto out_of_memory;
+
+ if (virAsprintf(&libxl_driver->configDir,
+ "%s", LIBXL_CONFIG_DIR) == -1)
+ goto out_of_memory;
+
+ if (virAsprintf(&libxl_driver->autostartDir,
+ "%s", LIBXL_AUTOSTART_DIR) == -1)
+ goto out_of_memory;
+
+ if (virAsprintf(&libxl_driver->logDir,
+ "%s", LIBXL_LOG_DIR) == -1)
+ goto out_of_memory;
+
+ if (virAsprintf(&libxl_driver->stateDir,
+ "%s", LIBXL_STATE_DIR) == -1)
+ goto out_of_memory;
+
+ if (virAsprintf(&libxl_driver->libDir,
+ "%s", LIBXL_LIB_DIR) == -1)
+ goto out_of_memory;
+
+ if (virAsprintf(&libxl_driver->saveDir,
+ "%s", LIBXL_SAVE_DIR) == -1)
+ goto out_of_memory;
+
+ if (virFileMakePath(libxl_driver->logDir) != 0) {
+ char ebuf[1024];
+ VIR_ERROR(_("Failed to create log dir '%s': %s"),
+ libxl_driver->logDir, virStrerror(errno, ebuf, sizeof ebuf));
+ goto error;
+ }
+ if (virFileMakePath(libxl_driver->stateDir) != 0) {
+ char ebuf[1024];
+ VIR_ERROR(_("Failed to create state dir '%s': %s"),
+ libxl_driver->stateDir, virStrerror(errno, ebuf, sizeof ebuf));
+ goto error;
+ }
+ if (virFileMakePath(libxl_driver->libDir) != 0) {
+ char ebuf[1024];
+ VIR_ERROR(_("Failed to create lib dir '%s': %s"),
+ libxl_driver->libDir, virStrerror(errno, ebuf, sizeof ebuf));
+ goto error;
+ }
+ if (virFileMakePath(libxl_driver->saveDir) != 0) {
+ char ebuf[1024];
+ VIR_ERROR(_("Failed to create save dir '%s': %s"),
+ libxl_driver->saveDir, virStrerror(errno, ebuf, sizeof ebuf));
+ goto error;
+ }
+
+ if (virAsprintf(&log_file, "%s/libxl.log", libxl_driver->logDir) < 0) {
+ goto out_of_memory;
+ }
+
+ if ((libxl_driver->logger_file = fopen(log_file, "a")) == NULL) {
+ virReportSystemError(errno,
+ _("failed to create logfile %s"),
+ log_file);
+ goto error;
+ }
+ VIR_FREE(log_file);
+
+ libxl_driver->logger =
+ (xentoollog_logger *)xtl_createlogger_stdiostream(libxl_driver->logger_file, XTL_DEBUG, 0);
+ if (!libxl_driver->logger) {
+ VIR_ERROR0(_("cannot create logger for libxenlight"));
+ goto error;
+ }
+
+ if (libxl_ctx_init(&libxl_driver->ctx,
+ LIBXL_VERSION,
+ libxl_driver->logger)) {
+ VIR_ERROR0(_("cannot initialize libxenlight context"));
+ goto error;
+ }
+
+ if ((ver_info = libxl_get_version_info(&libxl_driver->ctx)) == NULL) {
+ VIR_ERROR0(_("cannot version information from libxenlight"));
+ goto error;
+ }
+ libxl_driver->version = (ver_info->xen_version_major * 1000000) +
+ (ver_info->xen_version_minor * 1000);
+
+ if ((libxl_driver->caps =
+ libxlMakeCapabilities(&libxl_driver->ctx)) == NULL) {
+ VIR_ERROR0(_("cannot create capabilities for libxenlight"));
+ goto error;
+ }
+
+ libxl_driver->caps->privateDataAllocFunc = libxlDomainObjPrivateAlloc;
+ libxl_driver->caps->privateDataFreeFunc = libxlDomainObjPrivateFree;
+
+ /* Load running domains first. */
+ if (virDomainLoadAllConfigs(libxl_driver->caps,
+ &libxl_driver->domains,
+ libxl_driver->stateDir,
+ libxl_driver->autostartDir,
+ 1, NULL, NULL) < 0)
+ goto error;
+
+ libxlReconnectDomains(libxl_driver);
+
+ /* Then inactive persistent configs */
+ if (virDomainLoadAllConfigs(libxl_driver->caps,
+ &libxl_driver->domains,
+ libxl_driver->configDir,
+ libxl_driver->autostartDir,
+ 0, NULL, NULL) < 0)
+ goto error;
+
+ libxlDriverUnlock(libxl_driver);
+
+ // TODO: autostart domains
+ //libxlAutostartConfigs(libxl_driver);
+
+ return 0;
+
+out_of_memory:
+ virReportOOMError();
+error:
+ VIR_FREE(log_file);
+ if (libxl_driver)
+ libxlDriverUnlock(libxl_driver);
+ libxlShutdown();
+ return -1;
+}
+
+static int
+libxlReload(void)
+{
+ if (!libxl_driver)
+ return 0;
+
+ libxlDriverLock(libxl_driver);
+ virDomainLoadAllConfigs(libxl_driver->caps,
+ &libxl_driver->domains,
+ libxl_driver->configDir,
+ libxl_driver->autostartDir,
+ 0, NULL, libxl_driver);
+ libxlDriverUnlock(libxl_driver);
+
+ // TODO
+ //libxlAutostartConfigs(libxl_driver);
+
+ return 0;
+}
+
+static int
+libxlActive(void)
+{
+ if (!libxl_driver)
+ return 0;
+
+ return 1;
+}
+
+static virDrvOpenStatus
+libxlOpen(virConnectPtr conn,
+ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED)
+{
+ if (conn->uri == NULL) {
+ if (libxl_driver == NULL)
+ return VIR_DRV_OPEN_DECLINED;
+
+ conn->uri = xmlParseURI("libxl:///");
+ if (!conn->uri) {
+ virReportOOMError();
+ return VIR_DRV_OPEN_ERROR;
+ }
+ } else {
+ if (conn->uri->scheme == NULL || STRNEQ(conn->uri->scheme, "libxl"))
+ return VIR_DRV_OPEN_DECLINED;
+
+ /* If server name is given, its for remote driver */
+ if (conn->uri->server != NULL)
+ return VIR_DRV_OPEN_DECLINED;
+
+ if (libxl_driver == NULL) {
+ libxlError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("libxenlight state driver is not active"));
+ return VIR_DRV_OPEN_ERROR;
+ }
+
+ /* /session isn't supported in libxenlight */
+ if (conn->uri->path &&
+ STRNEQ(conn->uri->path, "") &&
+ STRNEQ(conn->uri->path, "/") &&
+ STRNEQ(conn->uri->path, "/system")) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("unexpected Xen URI path '%s', try libxl:///"),
+ NULLSTR(conn->uri->path));
+ return VIR_DRV_OPEN_ERROR;
+ }
+ }
+
+ conn->privateData = libxl_driver;
+
+ return VIR_DRV_OPEN_SUCCESS;
+};
+
+static int
+libxlClose(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ conn->privateData = NULL;
+ return 0;
+}
+
+static const char *
+libxlGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return "libxl";
+}
+
+static int
+libxlGetVersion(virConnectPtr conn, unsigned long *version)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+
+ libxlDriverLock(driver);
+ *version = driver->version;
+ libxlDriverUnlock(driver);
+ return 0;
+}
+
+static int
+libxlGetMaxVcpus(virConnectPtr conn, const char *type ATTRIBUTE_UNUSED)
+{
+ int ret;
+ libxlDriverPrivatePtr driver = conn->privateData;
+
+ ret = libxl_get_max_cpus(&driver->ctx);
+ /* libxl_get_max_cpus() will return 0 if there were any failures,
+ e.g. xc_physinfo() failing */
+ if (ret == 0)
+ return -1;
+
+ return ret;
+}
+
+static int
+libxlNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
+{
+ libxl_physinfo phy_info;
+ const libxl_version_info* ver_info;
+ libxlDriverPrivatePtr driver = conn->privateData;
+ struct utsname utsname;
+
+ if (libxl_get_physinfo(&driver->ctx, &phy_info)) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("libxl_get_physinfo_info failed"));
+ return -1;
+ }
+
+ if ((ver_info = libxl_get_version_info(&driver->ctx)) == NULL) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("libxl_get_version_info failed"));
+ return -1;
+ }
+
+ uname(&utsname);
+ if (virStrncpy(info->model,
+ utsname.machine,
+ strlen(utsname.machine),
+ sizeof(info->model)) == NULL) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("machine type %s too big for destination"),
+ utsname.machine);
+ return -1;
+ }
+
+ info->memory = phy_info.total_pages * (ver_info->pagesize / 1024);
+ info->cpus = phy_info.nr_cpus;
+ info->nodes = phy_info.nr_nodes;
+ info->cores = phy_info.cores_per_socket;
+ info->threads = phy_info.threads_per_core;
+ info->sockets = 1;
+ info->mhz = phy_info.cpu_khz / 1000;
+ return 0;
+}
+
+static char *
+libxlGetCapabilities(virConnectPtr conn)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ char *xml;
+
+ libxlDriverLock(driver);
+ if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
+ virReportOOMError();
+ libxlDriverUnlock(driver);
+
+ return xml;
+}
+
+static int
+libxlListDomains(virConnectPtr conn, int *ids, int nids)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ int n;
+
+ libxlDriverLock(driver);
+ n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
+ libxlDriverUnlock(driver);
+
+ return n;
+}
+
+static int
+libxlNumDomains(virConnectPtr conn)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ int n;
+
+ libxlDriverLock(driver);
+ n = virDomainObjListNumOfDomains(&driver->domains, 1);
+ libxlDriverUnlock(driver);
+
+ return n;
+}
+
+static virDomainPtr
+libxlDomainCreateXML(virConnectPtr conn, const char *xml,
+ unsigned int flags)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ virDomainDefPtr def;
+ virDomainObjPtr vm = NULL;
+ virDomainPtr dom = NULL;
+
+ virCheckFlags(VIR_DOMAIN_START_PAUSED, NULL);
+
+ libxlDriverLock(driver);
+ if (!(def = virDomainDefParseString(driver->caps, xml,
+ VIR_DOMAIN_XML_INACTIVE)))
+ goto cleanup;
+
+ if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
+ goto cleanup;
+
+ if (!(vm = virDomainAssignDef(driver->caps,
+ &driver->domains, def, false)))
+ goto cleanup;
+ def = NULL;
+
+ if (libxlVmStart(driver, vm, (flags & VIR_DOMAIN_START_PAUSED) != 0) < 0) {
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ goto cleanup;
+ }
+
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = vm->def->id;
+
+cleanup:
+ virDomainDefFree(def);
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return dom;
+}
+
+static virDomainPtr
+libxlDomainLookupByID(virConnectPtr conn, int id)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ virDomainObjPtr vm;
+ virDomainPtr dom = NULL;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByID(&driver->domains, id);
+ libxlDriverUnlock(driver);
+
+ if (!vm) {
+ libxlError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = vm->def->id;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return dom;
+}
+
+static virDomainPtr
+libxlDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ virDomainObjPtr vm;
+ virDomainPtr dom = NULL;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, uuid);
+ libxlDriverUnlock(driver);
+
+ if (!vm) {
+ libxlError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = vm->def->id;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return dom;
+}
+
+static virDomainPtr
+libxlDomainLookupByName(virConnectPtr conn, const char *name)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ virDomainObjPtr vm;
+ virDomainPtr dom = NULL;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByName(&driver->domains, name);
+ libxlDriverUnlock(driver);
+
+ if (!vm) {
+ libxlError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = vm->def->id;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return dom;
+}
+
+static int
+libxlDomainShutdown(virDomainPtr dom)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+ libxlDomainObjPrivatePtr priv;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ libxlError(VIR_ERR_NO_DOMAIN,
+ _("No domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (!virDomainObjIsActive(vm)) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("Domain is not running"));
+ goto cleanup;
+ }
+
+ priv = vm->privateData;
+ if (libxl_domain_shutdown(&priv->ctx, dom->id, LIBXL_DOM_REQ_POWEROFF) != 0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to shutdown domain '%d' with libxenlight"),
+ dom->id);
+ goto cleanup;
+ }
+
+ /* vm is marked shutoff (or removed from domains list if not persistent)
+ * in shutdown event handler.
+ */
+ ret = 0;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return ret;
+}
+
+static int
+libxlDomainReboot(virDomainPtr dom, unsigned int flags ATTRIBUTE_UNUSED)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+ libxlDomainObjPrivatePtr priv;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ libxlError(VIR_ERR_NO_DOMAIN,
+ _("No domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (!virDomainObjIsActive(vm)) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("Domain is not running"));
+ goto cleanup;
+ }
+
+ priv = vm->privateData;
+ if (libxl_domain_shutdown(&priv->ctx, dom->id, LIBXL_DOM_REQ_REBOOT) != 0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to reboot domain '%d' with libxenlight"),
+ dom->id);
+ goto cleanup;
+ }
+ ret = 0;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return ret;
+}
+
+static int
+libxlDomainDestroy(virDomainPtr dom)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+ libxlDomainObjPrivatePtr priv;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ libxlError(VIR_ERR_NO_DOMAIN,
+ _("No domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (!virDomainObjIsActive(vm)) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("Domain is not running"));
+ goto cleanup;
+ }
+
+ priv = vm->privateData;
+ if (libxlVmReap(driver, vm, 1) != 0) {
+ libxlError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to destroy domain '%d'"), dom->id);
+ goto cleanup;
+ }
+
+ if (!vm->persistent) {
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ }
+
+ ret = 0;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return ret;
+}
+
+static int
+libxlDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ libxlDriverUnlock(driver);
+
+ if (!vm) {
+ libxlError(VIR_ERR_NO_DOMAIN, "%s",
+ _("no domain with matching uuid"));
+ goto cleanup;
+ }
+
+ info->state = vm->state;
+ info->cpuTime = 0;
+ info->maxMem = vm->def->mem.max_balloon;
+ info->memory = vm->def->mem.cur_balloon;
+ info->nrVirtCpu = vm->def->vcpus;
+ ret = 0;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+static char *
+libxlDomainDumpXML(virDomainPtr dom, int flags)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ char *ret = NULL;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ libxlDriverUnlock(driver);
+
+ if (!vm) {
+ libxlError(VIR_ERR_NO_DOMAIN, "%s",
+ _("no domain with matching uuid"));
+ goto cleanup;
+ }
+
+ ret = virDomainDefFormat(vm->def, flags);
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+static int
+libxlListDefinedDomains(virConnectPtr conn,
+ char **const names, int nnames)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ int n;
+
+ libxlDriverLock(driver);
+ n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
+ libxlDriverUnlock(driver);
+ return n;
+}
+
+static int
+libxlNumDefinedDomains(virConnectPtr conn)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ int n;
+
+ libxlDriverLock(driver);
+ n = virDomainObjListNumOfDomains(&driver->domains, 0);
+ libxlDriverUnlock(driver);
+
+ return n;
+}
+
+static int
+libxlDomainCreateWithFlags(virDomainPtr dom,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+
+ virCheckFlags(VIR_DOMAIN_START_PAUSED, -1);
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ libxlError(VIR_ERR_NO_DOMAIN,
+ _("No domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (virDomainObjIsActive(vm)) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("Domain is already running"));
+ goto cleanup;
+ }
+
+ ret = libxlVmStart(driver, vm, (flags & VIR_DOMAIN_START_PAUSED) != 0);
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return ret;
+}
+
+static int
+libxlDomainCreate(virDomainPtr dom)
+{
+ return libxlDomainCreateWithFlags(dom, 0);
+}
+
+static virDomainPtr
+libxlDomainDefineXML(virConnectPtr conn, const char *xml)
+{
+ libxlDriverPrivatePtr driver = conn->privateData;
+ virDomainDefPtr def = NULL;
+ virDomainObjPtr vm = NULL;
+ virDomainPtr dom = NULL;
+ int dupVM;
+
+ libxlDriverLock(driver);
+ if (!(def = virDomainDefParseString(driver->caps, xml,
+ VIR_DOMAIN_XML_INACTIVE)))
+ goto cleanup;
+
+ if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
+ goto cleanup;
+
+ if (!(vm = virDomainAssignDef(driver->caps,
+ &driver->domains, def, false)))
+ goto cleanup;
+ def = NULL;
+ vm->persistent = 1;
+
+ if (virDomainSaveConfig(driver->configDir,
+ vm->newDef ? vm->newDef : vm->def) < 0) {
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ goto cleanup;
+ }
+
+ dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+ if (dom)
+ dom->id = vm->def->id;
+
+cleanup:
+ virDomainDefFree(def);
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return dom;
+}
+
+static int
+libxlDomainUndefine(virDomainPtr dom)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+
+ libxlDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ virUUIDFormat(dom->uuid, uuidstr);
+ libxlError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (virDomainObjIsActive(vm)) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("cannot undefine active domain"));
+ goto cleanup;
+ }
+
+ if (!vm->persistent) {
+ libxlError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("cannot undefine transient domain"));
+ goto cleanup;
+ }
+
+ if (virDomainDeleteConfig(driver->configDir,
+ driver->autostartDir,
+ vm) < 0)
+ goto cleanup;
+
+ virDomainRemoveInactive(&driver->domains, vm);
+ vm = NULL;
+ ret = 0;
+
+ cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ libxlDriverUnlock(driver);
+ return ret;
+}
+
+static int
+libxlDomainIsActive(virDomainPtr dom)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr obj;
+ int ret = -1;
+
+ libxlDriverLock(driver);
+ obj = virDomainFindByUUID(&driver->domains, dom->uuid);
+ libxlDriverUnlock(driver);
+ if (!obj) {
+ libxlError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+ ret = virDomainObjIsActive(obj);
+
+ cleanup:
+ if (obj)
+ virDomainObjUnlock(obj);
+ return ret;
+}
+
+static int
+libxlDomainIsPersistent(virDomainPtr dom)
+{
+ libxlDriverPrivatePtr driver = dom->conn->privateData;
+ virDomainObjPtr obj;
+ int ret = -1;
+
+ libxlDriverLock(driver);
+ obj = virDomainFindByUUID(&driver->domains, dom->uuid);
+ libxlDriverUnlock(driver);
+ if (!obj) {
+ libxlError(VIR_ERR_NO_DOMAIN, NULL);
+ goto cleanup;
+ }
+ ret = obj->persistent;
+
+ cleanup:
+ if (obj)
+ virDomainObjUnlock(obj);
+ return ret;
+}
+
+
+static virDriver libxlDriver = {
+ VIR_DRV_LIBXL,
+ "libxenlight",
+ libxlOpen, /* open */
+ libxlClose, /* close */
+ NULL, /* supports_feature */
+ libxlGetType, /* type */
+ libxlGetVersion, /* version */
+ NULL, /* libvirtVersion (impl. in libvirt.c) */
+ virGetHostname, /* getHostname */
+ NULL, /* getSysinfo */
+ libxlGetMaxVcpus, /* getMaxVcpus */
+ libxlNodeGetInfo, /* nodeGetInfo */
+ libxlGetCapabilities, /* getCapabilities */
+ libxlListDomains, /* listDomains */
+ libxlNumDomains, /* numOfDomains */
+ libxlDomainCreateXML, /* domainCreateXML */
+ libxlDomainLookupByID, /* domainLookupByID */
+ libxlDomainLookupByUUID, /* domainLookupByUUID */
+ libxlDomainLookupByName, /* domainLookupByName */
+ NULL, /* domainSuspend */
+ NULL, /* domainResume */
+ libxlDomainShutdown, /* domainShutdown */
+ libxlDomainReboot, /* domainReboot */
+ libxlDomainDestroy, /* domainDestroy */
+ NULL, /* domainGetOSType */
+ NULL, /* domainGetMaxMemory */
+ NULL, /* domainSetMaxMemory */
+ NULL, /* domainSetMemory */
+ libxlDomainGetInfo, /* domainGetInfo */
+ NULL, /* domainSave */
+ NULL, /* domainRestore */
+ NULL, /* domainCoreDump */
+ NULL, /* domainSetVcpus */
+ NULL, /* domainSetVcpusFlags */
+ NULL, /* domainGetVcpusFlags */
+ NULL, /* domainPinVcpu */
+ NULL, /* domainGetVcpus */
+ NULL, /* domainGetMaxVcpus */
+ NULL, /* domainGetSecurityLabel */
+ NULL, /* nodeGetSecurityModel */
+ libxlDomainDumpXML, /* domainDumpXML */
+ NULL, /* domainXmlFromNative */
+ NULL, /* domainXmlToNative */
+ libxlListDefinedDomains, /* listDefinedDomains */
+ libxlNumDefinedDomains, /* numOfDefinedDomains */
+ libxlDomainCreate, /* domainCreate */
+ libxlDomainCreateWithFlags, /* domainCreateWithFlags */
+ libxlDomainDefineXML, /* domainDefineXML */
+ libxlDomainUndefine, /* domainUndefine */
+ NULL, /* domainAttachDevice */
+ NULL, /* domainAttachDeviceFlags */
+ NULL, /* domainDetachDevice */
+ NULL, /* domainDetachDeviceFlags */
+ NULL, /* domainUpdateDeviceFlags */
+ NULL, /* domainGetAutostart */
+ NULL, /* domainSetAutostart */
+ NULL, /* domainGetSchedulerType */
+ NULL, /* domainGetSchedulerParameters */
+ NULL, /* domainSetSchedulerParameters */
+ NULL, /* domainMigratePrepare */
+ NULL, /* domainMigratePerform */
+ NULL, /* domainMigrateFinish */
+ NULL, /* domainBlockStats */
+ NULL, /* domainInterfaceStats */
+ NULL, /* domainMemoryStats */
+ NULL, /* domainBlockPeek */
+ NULL, /* domainMemoryPeek */
+ NULL, /* domainGetBlockInfo */
+ NULL, /* nodeGetCellsFreeMemory */
+ NULL, /* getFreeMemory */
+ NULL, /* domainEventRegister */
+ NULL, /* domainEventDeregister */
+ NULL, /* domainMigratePrepare2 */
+ NULL, /* domainMigrateFinish2 */
+ NULL, /* nodeDeviceDettach */
+ NULL, /* nodeDeviceReAttach */
+ NULL, /* nodeDeviceReset */
+ NULL, /* domainMigratePrepareTunnel */
+ NULL, /* IsEncrypted */
+ NULL, /* IsSecure */
+ libxlDomainIsActive, /* DomainIsActive */
+ libxlDomainIsPersistent, /* DomainIsPersistent */
+ NULL, /* domainIsUpdated */
+ NULL, /* cpuCompare */
+ NULL, /* cpuBaseline */
+ NULL, /* domainGetJobInfo */
+ NULL, /* domainAbortJob */
+ NULL, /* domainMigrateSetMaxDowntime */
+ NULL, /* domainEventRegisterAny */
+ NULL, /* domainEventDeregisterAny */
+ NULL, /* domainManagedSave */
+ NULL, /* domainHasManagedSaveImage */
+ NULL, /* domainManagedSaveRemove */
+ NULL, /* domainSnapshotCreateXML */
+ NULL, /* domainSnapshotDumpXML */
+ NULL, /* domainSnapshotNum */
+ NULL, /* domainSnapshotListNames */
+ NULL, /* domainSnapshotLookupByName */
+ NULL, /* domainHasCurrentSnapshot */
+ NULL, /* domainSnapshotCurrent */
+ NULL, /* domainRevertToSnapshot */
+ NULL, /* domainSnapshotDelete */
+ NULL, /* qemuDomainMonitorCommand */
+ NULL, /* domainSetMemoryParameters */
+ NULL, /* domainGetMemoryParameters */
+ NULL, /* domainOpenConsole */
+};
+
+static virStateDriver libxlStateDriver = {
+ .name = "LIBXL",
+ .initialize = libxlStartup,
+ .cleanup = libxlShutdown,
+ .reload = libxlReload,
+ .active = libxlActive,
+};
+
+
+int
+libxlRegister(void)
+{
+ if (virRegisterDriver(&libxlDriver) < 0)
+ return -1;
+ if (virRegisterStateDriver(&libxlStateDriver) < 0)
+ return -1;
+
+ return 0;
+}
diff --git a/src/libxl/libxl_driver.h b/src/libxl/libxl_driver.h
new file mode 100644
index 0000000..e047552
--- /dev/null
+++ b/src/libxl/libxl_driver.h
@@ -0,0 +1,27 @@
+/*---------------------------------------------------------------------------*/
+/* Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/*---------------------------------------------------------------------------*/
+
+#ifndef LIBXL_DRIVER_H
+# define LIBXL_DRIVER_H
+
+# include <config.h>
+
+int libxlRegister(void);
+
+#endif /* LIBXL_DRIVER_H */
diff --git a/src/util/virterror.c b/src/util/virterror.c
index f136054..39f0788 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -89,6 +89,9 @@ static const char *virErrorDomainName(virErrorDomain domain) {
case VIR_FROM_XENAPI:
dom = "XenAPI ";
break;
+ case VIR_FROM_LIBXL:
+ dom = "libxenlight ";
+ break;
case VIR_FROM_XML:
dom = "XML ";
break;
--
1.7.3.1
14 years
[libvirt] [PATCH] Add missing { for qemudDomainInterfaceStats
by Philipp Hahn
Add missing open curly brace between function declaration of non-linux
variant of qemudDomainInterfaceStats() and its body.
Signed-off-by: Philipp Hahn <hahn(a)univention.de>
---
src/qemu/qemu_driver.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index dac2bf2..4481261 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -5118,6 +5118,7 @@ static int
qemudDomainInterfaceStats (virDomainPtr dom,
const char *path ATTRIBUTE_UNUSED,
struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
+{
qemuReportError(VIR_ERR_NO_SUPPORT,
"%s", __FUNCTION__);
return -1;
--
1.7.1
14 years
[libvirt] [PATCH] daemon: Avoid resetting errors before they are reported
by Jiri Denemark
Commit f44bfb7 was supposed to make sure no additional libvirt API (esp.
*Free) is called before remoteDispatchConnError() is called on error.
However, the patch missed two instances.
---
daemon/remote.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index 7520df3..7d0016c 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -5105,12 +5105,13 @@ remoteDispatchStoragePoolListVolumes (struct qemud_server *server ATTRIBUTE_UNUS
ret->names.names_len =
virStoragePoolListVolumes (pool,
ret->names.names_val, args->maxnames);
- virStoragePoolFree(pool);
if (ret->names.names_len == -1) {
VIR_FREE(ret->names.names_val);
remoteDispatchConnError(rerr, conn);
+ virStoragePoolFree(pool);
return -1;
}
+ virStoragePoolFree(pool);
return 0;
}
@@ -5134,11 +5135,12 @@ remoteDispatchStoragePoolNumOfVolumes (struct qemud_server *server ATTRIBUTE_UNU
}
ret->num = virStoragePoolNumOfVolumes (pool);
- virStoragePoolFree(pool);
if (ret->num == -1) {
remoteDispatchConnError(rerr, conn);
+ virStoragePoolFree(pool);
return -1;
}
+ virStoragePoolFree(pool);
return 0;
}
--
1.7.4.1
14 years
[libvirt] CPU compare and baseline
by Edouard Thuleau
Hi,
I try to understand the compare and baseline CPU commands with libvirt.
This functions are useful for the migration ? Before migrate a domain to
other host, libvirt verifies the CPU compatibility, that's right ?
I've got two 64bits hosts, one with an Intel CPU :
> *<cpu>*
* **<arch>x86_64</arch>*
* **<model>Penryn</model>*
* **<vendor>Intel</vendor>*
* **<topology sockets='1' cores='2' threads='1'/>*
* **<feature name='xtpr'/>*
* **<feature name='tm2'/>*
* **<feature name='est'/>*
* **<feature name='vmx'/>*
* **<feature name='ds_cpl'/>*
* **<feature name='monitor'/>*
* **<feature name='pbe'/>*
* **<feature name='tm'/>*
* **<feature name='ht'/>*
* **<feature name='ss'/>*
* **<feature name='acpi'/>*
* **<feature name='ds'/>*
* **<feature name='vme'/>*
*</cpu>*
and one with an AMD CPU
> *<cpu>*
* **<arch>x86_64</arch>*
* **<model>Opteron_G2</model>*
* **<vendor>AMD</vendor>*
* **<topology sockets='1' cores='2' threads='1'/>*
* **<feature name='3dnowprefetch'/>*
* **<feature name='cr8legacy'/>*
* **<feature name='extapic'/>*
* **<feature name='cmp_legacy'/>*
* **<feature name='3dnow'/>*
* **<feature name='3dnowext'/>*
* **<feature name='fxsr_opt'/>*
* **<feature name='mmxext'/>*
* **<feature name='ht'/>*
* **<feature name='vme'/>*
*</cpu>*
Baseline output :
AMD to intel:
> *$ virsh cpu-baseline cpu_gargamel.xml *
*<cpu match='exact'>*
* <model>Opteron_G2</model>*
* <vendor>AMD</vendor>*
* <feature policy='require' name='3dnowprefetch'/>*
* <feature policy='require' name='cr8legacy'/>*
* <feature policy='require' name='extapic'/>*
* <feature policy='require' name='cmp_legacy'/>*
* <feature policy='require' name='3dnow'/>*
* <feature policy='require' name='3dnowext'/>*
* <feature policy='require' name='fxsr_opt'/>*
* <feature policy='require' name='mmxext'/>*
* <feature policy='require' name='ht'/>*
* <feature policy='require' name='vme'/>*
*</cpu>*
Intel to AMD:
> *$ virsh cpu-baseline cpu_azrael.xml *
*<cpu match='exact'>*
* <model>Penryn</model>*
* <vendor>Intel</vendor>*
* <feature policy='require' name='xtpr'/>*
* <feature policy='require' name='tm2'/>*
* <feature policy='require' name='est'/>*
* <feature policy='require' name='vmx'/>*
* <feature policy='require' name='ds_cpl'/>*
* <feature policy='require' name='monitor'/>*
* <feature policy='require' name='pbe'/>*
* <feature policy='require' name='tm'/>*
* <feature policy='require' name='ht'/>*
* <feature policy='require' name='ss'/>*
* <feature policy='require' name='acpi'/>*
* <feature policy='require' name='ds'/>*
* <feature policy='require' name='vme'/>*
*</cpu>*
But if I try to migrate a domain from a host to another, the CPU compare
says there are incompatible.
I don't understand, I've done live migration manually (*migrate -d tcp:
192.168.1.10:4444*) with KVM and it's works nicely. Why it's not possible
trough libvirt ?
I use libvirt 0.7.5 with KVM on an Ubuntu LTS 10.04.
Regards,
Doude.
14 years
[libvirt] [PATCH] command: properly diagnose process exit via signal
by Eric Blake
Child processes don't always reach _exit(); if they die from a
signal, then any messages should still be accurate. Most users
either expect a 0 status (thankfully, if status==0, then
WIFEXITED(status) is true and WEXITSTATUS(status)==0 for all
known platforms) or were filtering on WIFEXITED before printing
a status, but a few were missing this check. Additionally,
nwfilter_ebiptables_driver was making an assumption that works
on Linux (where WEXITSTATUS shifts and WTERMSIG just masks)
but fails on other platforms (where WEXITSTATUS just masks and
WTERMSIG shifts).
* src/util/command.h (virCommandTranslateStatus): New helper.
* src/libvirt_private.syms (command.h): Export it.
* src/util/command.c (virCommandTranslateStatus): New function.
(virCommandWait): Use it to also diagnose status from signals.
* src/security/security_apparmor.c (load_profile): Likewise.
* src/storage/storage_backend.c
(virStorageBackendQEMUImgBackingFormat): Likewise.
* src/util/util.c (virExecDaemonize, virRunWithHook)
(virFileOperation, virDirCreate): Likewise.
* daemon/remote.c (remoteDispatchAuthPolkit): Likewise.
* src/nwfilter/nwfilter_ebiptables_driver.c (ebiptablesExecCLI):
Likewise.
---
In response to my finding here:
https://www.redhat.com/archives/libvir-list/2011-March/msg01029.html
> status includes normal exit and signals. This should probably use
> WIFEXITED and WEXITSTATUS to avoid printing values shifted by 8. For
> that matter, I just noticed that virCommandWait should probably be more
> careful in how it interprets status.
daemon/remote.c | 11 +++++++-
src/libvirt_private.syms | 1 +
src/nwfilter/nwfilter_ebiptables_driver.c | 16 ++++++++++---
src/security/security_apparmor.c | 22 ++++++++++++------
src/storage/storage_backend.c | 18 ++++++---------
src/util/command.c | 34 ++++++++++++++++++++++++++--
src/util/command.h | 7 +++++-
src/util/util.c | 27 ++++++++++------------
8 files changed, 92 insertions(+), 44 deletions(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index f410982..2c54721 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -60,6 +60,7 @@
#include "uuid.h"
#include "network.h"
#include "libvirt/libvirt-qemu.h"
+#include "command.h"
#define VIR_FROM_THIS VIR_FROM_REMOTE
#define REMOTE_DEBUG(fmt, ...) VIR_DEBUG(fmt, __VA_ARGS__)
@@ -4363,8 +4364,14 @@ remoteDispatchAuthPolkit (struct qemud_server *server,
goto authfail;
}
if (status != 0) {
- VIR_ERROR(_("Policy kit denied action %s from pid %d, uid %d, result: %d"),
- action, callerPid, callerUid, status);
+ char *tmp = virCommandTranslateStatus(status);
+ if (!tmp) {
+ virReportOOMError();
+ goto authfail;
+ }
+ VIR_ERROR(_("Policy kit denied action %s from pid %d, uid %d: %s"),
+ action, callerPid, callerUid, tmp);
+ VIR_FREE(tmp);
goto authdeny;
}
PROBE(CLIENT_AUTH_ALLOW, "fd=%d, auth=%d, username=%s",
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 55be36e..d2f98fc 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -123,6 +123,7 @@ virCommandSetPreExecHook;
virCommandSetWorkingDirectory;
virCommandToString;
virCommandTransferFD;
+virCommandTranslateStatus;
virCommandWait;
virCommandWriteArgLog;
diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c
index 2ec5b02..75fddfb 100644
--- a/src/nwfilter/nwfilter_ebiptables_driver.c
+++ b/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -1,6 +1,7 @@
/*
* nwfilter_ebiptables_driver.c: driver for ebtables/iptables on tap devices
*
+ * Copyright (C) 2011 Red Hat, Inc.
* Copyright (C) 2010 IBM Corp.
* Copyright (C) 2010 Stefan Berger
*
@@ -2558,7 +2559,7 @@ err_exit:
* ebiptablesExecCLI:
* @buf : pointer to virBuffer containing the string with the commands to
* execute.
- * @status: Pointer to an integer for returning the status of the
+ * @status: Pointer to an integer for returning the WEXITSTATUS of the
* commands executed via the script the was run.
*
* Returns 0 in case of success, != 0 in case of an error. The returned
@@ -2587,7 +2588,7 @@ ebiptablesExecCLI(virBufferPtr buf,
cmds = virBufferContentAndReset(buf);
- VIR_DEBUG("%s", cmds);
+ VIR_DEBUG("%s", NULLSTR(cmds));
if (!cmds)
return 0;
@@ -2606,9 +2607,16 @@ ebiptablesExecCLI(virBufferPtr buf,
virMutexUnlock(&execCLIMutex);
- *status >>= 8;
+ if (rc == 0) {
+ if (WIFEXITED(*status)) {
+ *status = WEXITSTATUS(*status);
+ } else {
+ rc = -1;
+ *status = 1;
+ }
+ }
- VIR_DEBUG("rc = %d, status = %d",rc, *status);
+ VIR_DEBUG("rc = %d, status = %d", rc, *status);
unlink(filename);
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
index deb4181..3edc680 100644
--- a/src/security/security_apparmor.c
+++ b/src/security/security_apparmor.c
@@ -1,5 +1,6 @@
/*
* AppArmor security driver for libvirt
+ * Copyright (C) 2011 Red Hat, Inc.
* Copyright (C) 2009-2010 Canonical Ltd.
*
* This library is free software; you can redistribute it and/or
@@ -36,6 +37,7 @@
#include "hostusb.h"
#include "files.h"
#include "configmake.h"
+#include "command.h"
#define VIR_FROM_THIS VIR_FROM_SECURITY
#define SECURITY_APPARMOR_VOID_DOI "0"
@@ -217,15 +219,19 @@ load_profile(virSecurityManagerPtr mgr,
VIR_FORCE_CLOSE(pipefd[1]);
rc = 0;
- rewait:
- if (waitpid(child, &status, 0) != child) {
- if (errno == EINTR)
- goto rewait;
-
+ while ((ret = waitpid(child, &status, 0)) < 0 && errno == EINTR);
+ if (ret < 0) {
+ virReportSystemError(errno,
+ _("Failed to reap virt-aa-helper pid %lu"),
+ (unsigned long)child);
+ rc = -1;
+ } else if (status) {
+ char *str = virCommandTranslateStatus(status);
virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unexpected exit status from virt-aa-helper "
- "%d pid %lu"),
- WEXITSTATUS(status), (unsigned long)child);
+ _("Unexpected status from virt-aa-helper "
+ "pid %lu: %s"),
+ (unsigned long)child, NULLSTR(str));
+ VIR_FREE(str);
rc = -1;
}
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index fc08c68..c6c16c8 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -56,6 +56,7 @@
#include "storage_backend.h"
#include "logging.h"
#include "files.h"
+#include "command.h"
#if WITH_STORAGE_LVM
# include "storage_backend_logical.h"
@@ -631,18 +632,13 @@ static int virStorageBackendQEMUImgBackingFormat(const char *qemuimg)
cleanup:
VIR_FREE(help);
VIR_FORCE_CLOSE(newstdout);
-rewait:
if (child) {
- if (waitpid(child, &status, 0) != child) {
- if (errno == EINTR)
- goto rewait;
-
- VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
- WEXITSTATUS(status), (unsigned long)child);
- }
- if (WEXITSTATUS(status) != 0) {
- VIR_WARN("Unexpected exit status '%d', qemu probably failed",
- WEXITSTATUS(status));
+ while (waitpid(child, &status, 0) == -1 && errno == EINTR);
+ if (status) {
+ tmp = virCommandTranslateStatus(status);
+ VIR_WARN("Unexpected status, qemu probably failed: %s",
+ NULLSTR(tmp));
+ VIR_FREE(tmp);
}
}
diff --git a/src/util/command.c b/src/util/command.c
index 22f350b..89f82c7 100644
--- a/src/util/command.c
+++ b/src/util/command.c
@@ -798,6 +798,26 @@ virCommandToString(virCommandPtr cmd)
/*
+ * Translate an exit status into a malloc'd string. Generic helper
+ * for virCommandRun and virCommandWait status argument, as well as
+ * raw waitpid and older virRun status.
+ */
+char *
+virCommandTranslateStatus(int status)
+{
+ char *buf;
+ if (WIFEXITED(status)) {
+ virAsprintf(&buf, _("exit status %d"), WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ virAsprintf(&buf, _("fatal signal %d"), WTERMSIG(status));
+ } else {
+ virAsprintf(&buf, _("invalid value %d"), status);
+ }
+ return buf;
+}
+
+
+/*
* Manage input and output to the child process.
*/
static int
@@ -958,6 +978,7 @@ virCommandRun(virCommandPtr cmd, int *exitstatus)
struct stat st;
bool string_io;
bool async_io = false;
+ char *str;
if (!cmd ||cmd->has_error == ENOMEM) {
virReportOOMError();
@@ -1048,9 +1069,14 @@ virCommandRun(virCommandPtr cmd, int *exitstatus)
if (virCommandWait(cmd, exitstatus) < 0)
ret = -1;
- VIR_DEBUG("Result stdout: '%s' stderr: '%s'",
+ str = (exitstatus ? virCommandTranslateStatus(*exitstatus)
+ : (char *) "status 0");
+ VIR_DEBUG("Result %s, stdout: '%s' stderr: '%s'",
+ NULLSTR(str),
cmd->outbuf ? NULLSTR(*cmd->outbuf) : "(null)",
cmd->errbuf ? NULLSTR(*cmd->errbuf) : "(null)");
+ if (exitstatus)
+ VIR_FREE(str);
/* Reset any capturing, in case caller runs
* this identical command again */
@@ -1226,10 +1252,12 @@ virCommandWait(virCommandPtr cmd, int *exitstatus)
if (exitstatus == NULL) {
if (status != 0) {
char *str = virCommandToString(cmd);
+ char *st = virCommandTranslateStatus(status);
virCommandError(VIR_ERR_INTERNAL_ERROR,
- _("Child process (%s) exited with status %d."),
- str ? str : cmd->args[0], WEXITSTATUS(status));
+ _("Child process (%s) status unexpected: %s"),
+ str ? str : cmd->args[0], NULLSTR(st));
VIR_FREE(str);
+ VIR_FREE(st);
return -1;
}
} else {
diff --git a/src/util/command.h b/src/util/command.h
index 59d0ee3..0e890d0 100644
--- a/src/util/command.h
+++ b/src/util/command.h
@@ -1,7 +1,7 @@
/*
* command.h: Child command execution
*
- * Copyright (C) 2010 Red Hat, Inc.
+ * Copyright (C) 2010-2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -273,5 +273,10 @@ int virCommandWait(virCommandPtr cmd,
*/
void virCommandFree(virCommandPtr cmd);
+/*
+ * Translate an exit status into a malloc'd string.
+ */
+char *virCommandTranslateStatus(int exitstatus) ATTRIBUTE_RETURN_CHECK;
+
#endif /* __VIR_COMMAND_H__ */
diff --git a/src/util/util.c b/src/util/util.c
index 1e4e2ab..4301b00 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -76,6 +76,7 @@
#include "threads.h"
#include "verify.h"
#include "files.h"
+#include "command.h"
#ifndef NSIG
# define NSIG 32
@@ -832,9 +833,11 @@ int virExecDaemonize(const char *const*argv,
errno == EINTR);
if (childstat != 0) {
+ char *str = virCommandTranslateStatus(childstat);
virUtilError(VIR_ERR_INTERNAL_ERROR,
- _("Intermediate daemon process exited with status %d."),
- WEXITSTATUS(childstat));
+ _("Intermediate daemon process status unexpected: %s"),
+ NULLSTR(str));
+ VIR_FREE(str);
ret = -2;
}
@@ -903,13 +906,12 @@ virRunWithHook(const char *const*argv,
if (status == NULL) {
errno = EINVAL;
- if (WIFEXITED(exitstatus) && WEXITSTATUS(exitstatus) != 0) {
+ if (exitstatus) {
+ char *str = virCommandTranslateStatus(exitstatus);
virUtilError(VIR_ERR_INTERNAL_ERROR,
- _("'%s' exited with non-zero status %d and "
- "signal %d: %s"), argv_str,
- WIFEXITED(exitstatus) ? WEXITSTATUS(exitstatus) : 0,
- WIFSIGNALED(exitstatus) ? WTERMSIG(exitstatus) : 0,
- (errbuf ? errbuf : ""));
+ _("'%s' exited unexpectedly: %s"),
+ argv_str, NULLSTR(str));
+ VIR_FREE(str);
goto error;
}
} else {
@@ -1510,8 +1512,7 @@ int virFileOperation(const char *path, int openflags, mode_t mode,
path);
goto parenterror;
}
- ret = -WEXITSTATUS(status);
- if (!WIFEXITED(status) || (ret == -EACCES)) {
+ if (!WIFEXITED(status) || (ret = -WEXITSTATUS(status)) == -EACCES) {
/* fall back to the simpler method, which works better in
* some cases */
return virFileOperationNoFork(path, openflags, mode, uid, gid,
@@ -1630,15 +1631,11 @@ int virDirCreate(const char *path, mode_t mode,
path);
goto parenterror;
}
- ret = -WEXITSTATUS(status);
- if (!WIFEXITED(status) || (ret == -EACCES)) {
+ if (!WIFEXITED(status) || (ret = -WEXITSTATUS(status)) == -EACCES) {
/* fall back to the simpler method, which works better in
* some cases */
return virDirCreateNoFork(path, mode, uid, gid, flags);
}
- if (ret < 0) {
- goto parenterror;
- }
parenterror:
return ret;
}
--
1.7.4
14 years
[libvirt] About to enter freeze for 0.9.0, on Monday
by Daniel Veillard
As posted previously I was thinking of entering freeze today, but
we have a number of patchsets which are relatively advanced but
don't have a final version, like Dan's patches and support of persistent
device by Kame.
So I suggest to extend the development Friday and over the week-end
if needed but we will enter Freeze Monday morning.
Then depending on feedback on release candidate, I will either push
0.9.0 on the 1st April or following Monday,
Daniel
--
Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/
daniel(a)veillard.com | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library http://libvirt.org/
14 years
[libvirt] [PATCH] fix the check of the output of monitor command 'device_add'
by Wen Congyang
Hotpluging host usb device by text mode will fail, because the monitor
command 'device_add' outputs 'husb: using...' if it succeeds, but we
think the command should not output anything.
Signed-off-by: Wen Congyang <wency(a)cn.fujitsu.com>
---
src/qemu/qemu_monitor_text.c | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 91ecc8b..75b2995 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -2283,7 +2283,15 @@ int qemuMonitorTextAddDevice(qemuMonitorPtr mon,
goto cleanup;
}
- /* If the command succeeds, no output is sent. So
+ /* If the host device is hotpluged first time, qemu will output
+ * husb: using %s file-system with %s if the command succeeds.
+ */
+ if (STRPREFIX(reply, "husb: using")) {
+ ret = 0;
+ goto cleanup;
+ }
+
+ /* Otherwise, if the command succeeds, no output is sent. So
* any non-empty string shows an error */
if (STRNEQ(reply, "")) {
qemuReportError(VIR_ERR_OPERATION_FAILED,
--
1.7.1
14 years
[libvirt] cgroup memoryinfo handling
by Zvi Dubitzky
Hi
1) Daniel Smith of IBM wrote (2008) code for implementing 'virsh
schedinfo' in src/util/cgroup.c
He also added some code for cgroup memory subsystem (util/cgroup.c/
virCgroupSetMemoryHardLimit () etc.),
I see also src/qemu_driver.c/qemuDomainSetMemoryParameters()
But that seems not being invoked . I am looking at libvirt-0.8.8
2) Is anybody handling/completing this piece of code and are you libvirt
guys interested in us completing it
because we might find usage for that kind of 'virsh meminfo' command
using cgroups .
thanks
Zvi Dubitzky
Email:dubi@il.ibm.com
14 years