[libvirt] [PATCH] hypervisor driver for Jailhouse
by Christian Loehle
>From README:
The jailhouse hypervisor driver for the libvirt project aims to provide
rudimentary support for managing jailhouse with the libvirt library. The
main advantage of this is the possibility to use virt-manager as a GUI
to manage Jailhouse cells. Thus the driver is mainly built around the
API calls that virt-manager uses and needs.
Due to the concept of Jailhouse a lot of libvirt functions can't be
realized, so this driver isn't as full-featured as upstream drivers of
the libvirt project.
Currently the driver relies on the Jailhouse binary, which has to be
passed when connecting a libvirt client to it(e.g. virt-manager -c
jailhouse:///path/to/jailhouse/tools/jailhouse). This has the advantage
that remote support can be easily done by not passing the original
Jailhouse binary, but an executable that redirects its parameters
through ssh to the real Jailhouse binary and outputs that output. Be
aware though that the driver doesn't store any information about cells,
so most API calls use "jailhouse cell list" every time they're called to
get the current state.
I would like to get Jailhouse support upstream, any feedback is greatly
appreciated.
--
Christian Loehle
diff --git a/configure.ac b/configure.ac
index f481c50..8b68828 100644
--- a/configure.ac
+++ b/configure.ac
@@ -563,6 +563,10 @@ AC_ARG_WITH([hyperv],
[AS_HELP_STRING([--with-hyperv],
[add Hyper-V support @<:@default=check@:>@])])
m4_divert_text([DEFAULTS], [with_hyperv=check])
+AC_ARG_WITH([jailhouse],
+ [AS_HELP_STRING([--with-jailhouse],
+ [add Jailhouse support @<:@default=yes@:>@])])
+m4_divert_text([DEFAULTS], [with_jailhouse=yes])
AC_ARG_WITH([test],
[AS_HELP_STRING([--with-test],
[add test driver support @<:@default=yes@:>@])])
@@ -722,6 +726,16 @@ AM_CONDITIONAL([WITH_VMWARE], [test "$with_vmware"
= "yes"])
dnl
+dnl Checks for the Jailhouse driver
+dnl
+
+if test "$with_jailhouse" = "yes"; then
+ AC_DEFINE_UNQUOTED([WITH_JAILHOUSE], 1, [whether Jailhouse driver
is enabled])
+fi
+AM_CONDITIONAL([WITH_JAILHOUSE], [test "$with_jailhouse" = "yes"])
+
+
+dnl
dnl check for XDR
dnl
@@ -1087,6 +1101,12 @@ dnl
LIBVIRT_DRIVER_CHECK_BHYVE
dnl
+dnl Checks for Jailhouse driver
+dnl
+
+AM_CONDITIONAL([WITH_JAILHOUSE], [test "$with_jailhouse" = "yes"])
+
+dnl
dnl check for shell that understands <> redirection without truncation,
dnl needed by src/qemu/qemu_monitor_{text,json}.c.
dnl
@@ -2830,6 +2850,7 @@ AC_MSG_NOTICE([ ESX: $with_esx])
AC_MSG_NOTICE([ Hyper-V: $with_hyperv])
LIBVIRT_DRIVER_RESULT_VZ
LIBVIRT_DRIVER_RESULT_BHYVE
+AC_MSG_NOTICE([Jailhouse: $with_jailhouse])
AC_MSG_NOTICE([ Test: $with_test])
AC_MSG_NOTICE([ Remote: $with_remote])
AC_MSG_NOTICE([ Network: $with_network])
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index f716cb9..c8fe2d3 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -127,6 +127,7 @@ typedef enum {
VIR_FROM_POLKIT = 60, /* Error from polkit code */
VIR_FROM_THREAD = 61, /* Error from thread utils */
VIR_FROM_ADMIN = 62, /* Error from admin backend */
+ VIR_FROM_JAILHOUSE = 63, /* Error from Jailhouse driver */
# ifdef VIR_ENUM_SENTINELS
VIR_ERR_DOMAIN_LAST
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0cc5b99..2b144bf 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -59,6 +59,7 @@ src/hyperv/hyperv_wmi.c
src/interface/interface_backend_netcf.c
src/interface/interface_backend_udev.c
src/internal.h
+src/jailhouse/jailhouse_driver.c
src/libvirt.c
src/libvirt-admin.c
src/libvirt-domain.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 99b4993..10d59de 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -578,6 +578,7 @@ DRIVER_SOURCE_FILES = \
$(VMWARE_DRIVER_SOURCES) \
$(XEN_DRIVER_SOURCES) \
$(XENAPI_DRIVER_SOURCES) \
+ $(JAILHOUSE_DRIVER_SOURCES) \
$(NULL)
STATEFUL_DRIVER_SOURCE_FILES = \
@@ -860,6 +861,11 @@ BHYVE_DRIVER_SOURCES = \
bhyve/bhyve_utils.h \
$(NULL)
+JAILHOUSE_DRIVER_SOURCES = \
+ jailhouse/jailhouse_driver.c \
+ jailhouse/jailhouse_driver.h \
+ $(NULL)
+
NETWORK_DRIVER_SOURCES = \
network/bridge_driver.h network/bridge_driver.c \
network/bridge_driver_platform.h \
@@ -1436,6 +1442,14 @@ libvirt_driver_vz_la_LIBADD =
$(PARALLELS_SDK_LIBS) $(LIBNL_LIBS)
libvirt_driver_vz_la_SOURCES = $(VZ_DRIVER_SOURCES)
endif WITH_VZ
+if WITH_JAILHOUSE
+noinst_LTLIBRARIES += libvirt_driver_jailhouse.la
+libvirt_la_BUILT_LIBADD += libvirt_driver_jailhouse.la
+libvirt_driver_jailhouse_la_CFLAGS = \
+ -I$(srcdir)/conf $(AM_CFLAGS)
+libvirt_driver_jailhouse_la_SOURCES = $(JAILHOUSE_DRIVER_SOURCES)
+endif WITH_JAILHOUSE
+
if WITH_BHYVE
noinst_LTLIBRARIES += libvirt_driver_bhyve_impl.la
libvirt_driver_bhyve_la_SOURCES =
@@ -1801,6 +1815,7 @@ EXTRA_DIST += \
$(HYPERV_DRIVER_EXTRA_DIST) \
$(VZ_DRIVER_SOURCES) \
$(BHYVE_DRIVER_SOURCES) \
+ $(JAILHOUSE_DRIVER_SOURCES) \
$(NETWORK_DRIVER_SOURCES) \
$(INTERFACE_DRIVER_SOURCES) \
$(STORAGE_DRIVER_SOURCES) \
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 2edf123..00d17e9 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -121,7 +121,8 @@ VIR_ENUM_IMPL(virDomainVirt, VIR_DOMAIN_VIRT_LAST,
"phyp",
"parallels",
"bhyve",
- "vz")
+ "vz",
+ "jailhouse")
VIR_ENUM_IMPL(virDomainOS, VIR_DOMAIN_OSTYPE_LAST,
"hvm",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index f10b534..27beef0 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -225,6 +225,7 @@ typedef enum {
VIR_DOMAIN_VIRT_PARALLELS,
VIR_DOMAIN_VIRT_BHYVE,
VIR_DOMAIN_VIRT_VZ,
+ VIR_DOMAIN_VIRT_JAILHOUSE,
VIR_DOMAIN_VIRT_LAST
} virDomainVirtType;
diff --git a/src/jailhouse/README b/src/jailhouse/README
new file mode 100644
index 0000000..564cfbd
--- /dev/null
+++ b/src/jailhouse/README
@@ -0,0 +1,3 @@
+The jailhouse hypervisor driver for the libvirt project aims to provide
rudimentary support for managing jailhouse with the libvirt library. The
main advantage of this is the possibility to use virt-manager as a GUI
to manage Jailhouse cells. Thus the driver is mainly built around the
API calls that virt-manager uses and needs.
+Due to the concept of Jailhouse a lot of libvirt functions can't be
realized, so this driver isn't as full-featured as upstream drivers of
the libvirt project.
+Currently the driver relies on the Jailhouse binary, which has to be
passed when connecting a libvirt client to it(e.g. virt-manager -c
jailhouse:///path/to/jailhouse/tools/jailhouse). This has the advantage
that remote support can be easily done by not passing the original
Jailhouse binary, but an executable that redirects its parameters
through ssh to the real Jailhouse binary and outputs that output. Be
aware though that the driver doesn't store any information about cells,
so most API calls use "jailhouse cell list" every time they're called to
get the current state.
diff --git a/src/jailhouse/jailhouse_driver.c
b/src/jailhouse/jailhouse_driver.c
new file mode 100644
index 0000000..21acbba
--- /dev/null
+++ b/src/jailhouse/jailhouse_driver.c
@@ -0,0 +1,614 @@
+/*
+ * jailhouse_driver.c: hypervisor driver for managing Jailhouse cells
+ *
+ * Copyright (C) 2015 Linutronix 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, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Christian Loehle
+ */
+
+#include <config.h>
+#include <string.h>
+#include "jailhouse_driver.h"
+#include "datatypes.h"
+#include "virerror.h"
+#include "viralloc.h"
+#include "virlog.h"
+#include "vircommand.h"
+#include "virxml.h"
+#include "configmake.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virstring.h"
+#include "nodeinfo.h"
+
+#define VIR_FROM_THIS VIR_FROM_JAILHOUSE
+
+#define IDLENGTH 8
+#define NAMELENGTH 24
+#define STATELENGTH 16
+#define CPULENGTH 24
+#define STATERUNNING 0
+#define STATERUNNINGSTRING "running "
+#define STATERUNNINGLOCKED 1
+#define STATERUNNINGLOCKEDSTRING "running/locked "
+#define STATESHUTDOWN 2
+#define STATESHUTDOWNSTRING "shut down "
+#define STATEFAILED 3
+#define STATEFAILEDSTRING "failed "
+#define JAILHOUSEVERSIONOUTPUT "Jailhouse management tool"
+
+/*
+ * The driver requeries the cells on most calls, it stores the result
of the last query, so it can copy the UUIDs in the new query if the cell
is the same(otherwise it just generates a new one)
+ * not preserving the UUID results in a lot of bugs in libvirts clients.
+ */
+struct jailhouse_driver {
+ char *binary;
+ size_t lastQueryCellsCount;
+ struct jailhouse_cell* lastQueryCells;
+};
+
+/*
+ * CPUs are currently unused but this might change
+ */
+struct jailhouse_cell {
+ int id;
+ char name[NAMELENGTH+1];
+ int state;
+ int *assignedCPUs; //Don't use cpumask because remote system might
have different # of cpus
+ int assignedCPUsLength;
+ int *failedCPUs;
+ int failedCPUsLength;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+};
+
+/*
+ * helper function that returns the number as an integer and sets i to
be the first char after the number
+ */
+static int
+charsToInt(char* chars, size_t *i)
+{
+ int result = 0;
+ while (chars[*i] != ',' && chars[*i] != '-' && chars[*i] != ' ') {
+ result *= 10;
+ result += chars[*i] - '0';
+ (*i)++;
+ }
+ return result;
+}
+
+/*
+ * Takes a string in the format of "jailhouse cell list" as input,
+ * allocates an int array in which every CPU is explicitly listed and
saves a pointer in cpusptr
+ */
+static size_t
+parseCPUs(char* output, int **cpusptr)
+{
+ size_t i;
+ size_t count = 1;
+ int number;
+ int* cpus;
+ if (output[0] == ' ') {
+ *cpusptr = NULL;
+ return 0;
+ }
+ for (i = 0; i<CPULENGTH; i++) {
+ number = charsToInt(output, &i);
+ if (output[i] == ',') {
+ count++;
+ } else if (output[i] == '-') {
+ i++;
+ count += charsToInt(output, &i) - number;
+ }
+ }
+ if (VIR_ALLOC_N(cpus, count)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to allocate CPUs array of size %zu"), count);
+ return 0;
+ }
+ size_t j = 0;
+ i = 0;
+ while (output[i] != ' ') {
+ number = charsToInt(output, &i);
+ if (output[i] == ',' || output[i] == ' ') {
+ cpus[j++] = number;
+ } else if (output[i] == '-') {
+ i++;
+ int nextNumber = charsToInt(output, &i);
+ for (; number <= nextNumber; number++) cpus[j++] = number;
+ }
+ i++;
+ }
+ *cpusptr = cpus;
+ return count;
+}
+
+/*
+ * calls "jailhouse cell list" and parses the output in an array of
jailhouse_cell
+ */
+static size_t
+parseListOutput(virConnectPtr conn, struct jailhouse_cell **parsedOutput)
+{
+ virCommandPtr cmd = virCommandNew(((struct jailhouse_driver
*)conn->privateData)->binary);
+ virCommandAddArg(cmd, "cell");
+ virCommandAddArg(cmd, "list");
+ virCommandAddEnvPassCommon(cmd);
+ char *output;
+ virCommandSetOutputBuffer(cmd, &output);
+ size_t count = -1; // Don't count table header line
+ size_t i = 0;
+ if (virCommandRun(cmd, NULL) < 0)
+ goto error;
+ while (output[i] != '\0') {
+ if (output[i] == '\n') count++;
+ i++;
+ }
+ if (VIR_ALLOC_N(*parsedOutput, count)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to allocate jailhouse_cell array of size
%zu"), count);
+ goto error;
+ }
+ if (*parsedOutput == NULL)
+ goto error;
+ i = 0;
+ size_t j;
+ while (output[i++] != '\n'); // Skip table header line
+ for (j = 0; j < count; j++) {
+ size_t k;
+ for (k = 0; k <= IDLENGTH; k++) // char after number needs to
be NUL for virStrToLong
+ if (output[i+k] == ' ') {
+ output[i+k] = '\0';
+ break;
+ }
+ char c = output[i+IDLENGTH];
+ output[i+IDLENGTH] = '\0'; // in case ID is 8 chars long, so
beginning of name won't get parsed
+ if (virStrToLong_i(output+i, NULL, 0, &(*parsedOutput)[j].id))
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to parse id to long: %s"), output+i);
+ output[i+IDLENGTH] = c;
+ i += IDLENGTH;
+ if (virStrncpy((*parsedOutput)[j].name, output+i, NAMELENGTH,
NAMELENGTH+1) == NULL)
+ // should never happen
+ goto error;
+ (*parsedOutput)[j].name[NAMELENGTH] = '\0';
+ for (k = 0; k < NAMELENGTH; k++)
+ if ((*parsedOutput)[j].name[k] == ' ')
+ break;
+ (*parsedOutput)[j].name[k] = '\0';
+ i += NAMELENGTH;
+ if (STREQLEN(output+i, STATERUNNINGSTRING, STATELENGTH))
(*parsedOutput)[j].state = STATERUNNING;
+ else if (STREQLEN(output+i, STATESHUTDOWNSTRING, STATELENGTH))
(*parsedOutput)[j].state = STATESHUTDOWN;
+ else if (STREQLEN(output+i, STATEFAILEDSTRING, STATELENGTH))
(*parsedOutput)[j].state = STATEFAILED;
+ else if (STREQLEN(output+i, STATERUNNINGLOCKEDSTRING,
STATELENGTH)) (*parsedOutput)[j].state = STATERUNNINGLOCKED;
+ i += STATELENGTH;
+ (*parsedOutput)[j].assignedCPUsLength = parseCPUs(output+i,
&((*parsedOutput)[j].assignedCPUs));
+ i += CPULENGTH;
+ (*parsedOutput)[j].failedCPUsLength = parseCPUs(output+i,
&((*parsedOutput)[j].failedCPUs));
+ i += CPULENGTH;
+ i++; // skip \n
+ }
+ VIR_FREE(output);
+ return count;
+ error:
+ for (i = 0; i < count; i++) {
+ VIR_FREE((*parsedOutput)[i].assignedCPUs);
+ VIR_FREE((*parsedOutput)[i].failedCPUs);
+ }
+ VIR_FREE(*parsedOutput);
+ *parsedOutput = NULL;
+ VIR_FREE(output);
+ output = NULL;
+ return -1;
+}
+
+/*
+ * Returns the libvirts equivalent of the cell state passed to it
+ */
+static virDomainState
+cellToVirDomainState(struct jailhouse_cell *cell)
+{
+ switch (cell->state) {
+ case STATERUNNING: return VIR_DOMAIN_RUNNING;
+ case STATERUNNINGLOCKED: return VIR_DOMAIN_RUNNING;
+ case STATESHUTDOWN: return VIR_DOMAIN_SHUTOFF;
+ case STATEFAILED: return VIR_DOMAIN_CRASHED;
+ default: return VIR_DOMAIN_NOSTATE;
+ }
+}
+
+/*
+ * Returns a new virDomainPtr filled with the data of the jailhouse_cell
+ */
+static virDomainPtr
+cellToVirDomainPtr(virConnectPtr conn, struct jailhouse_cell *cell)
+{
+ virDomainPtr dom = virGetDomain(conn, cell->name, cell->uuid);
+ dom->id = cell->id;
+ return dom;
+}
+
+/*
+ * Check cells for cell and copies UUID if found, otherwise generates
a new one, this is to preserve UUID in libvirt
+ */
+static void setUUID(struct jailhouse_cell *cells, size_t count, struct
jailhouse_cell* cell) {
+ size_t i;
+ for (i = 0; i < count; i++) {
+ if (strncmp(cells[i].name, cell->name, NAMELENGTH+1))
+ continue;
+ memcpy(cell->uuid, cells[i].uuid, VIR_UUID_BUFLEN);
+ return;
+ }
+ virUUIDGenerate(cell->uuid);
+}
+
+/*
+ * Frees the old list of cells, gets the new one and preserves UUID if
cells were present in the old
+ */
+static void
+getCurrentCellList(virConnectPtr conn)
+{
+ size_t lastCount = ((struct jailhouse_driver
*)conn->privateData)->lastQueryCellsCount;
+ struct jailhouse_cell *lastCells = ((struct jailhouse_driver
*)conn->privateData)->lastQueryCells;
+ struct jailhouse_cell *cells = NULL;
+ size_t i;
+ size_t count = parseListOutput(conn, &cells);
+ for (i = 0; i < count; i++)
+ setUUID(lastCells, lastCount, cells+i);
+ for (i = 0; i < lastCount; i++) {
+ VIR_FREE(lastCells[i].assignedCPUs);
+ VIR_FREE(lastCells[i].failedCPUs);
+ }
+ VIR_FREE(lastCells);
+ ((struct jailhouse_driver *)conn->privateData)->lastQueryCells = cells;
+ ((struct jailhouse_driver *)conn->privateData)->lastQueryCellsCount
= count;
+}
+
+/*
+ * Converts libvirts virDomainPtr to the internal jailhouse_cell by
parsing the "jailhouse cell list" output
+ * and looking up the name of the virDomainPtr, returns NULL if cell
is no longer present
+ */
+static struct jailhouse_cell *
+virDomainPtrToCell(virDomainPtr dom)
+{
+ getCurrentCellList(dom->conn);
+ size_t cellsCount = ((struct jailhouse_driver
*)dom->conn->privateData)->lastQueryCellsCount;
+ struct jailhouse_cell *cells = ((struct jailhouse_driver
*)dom->conn->privateData)->lastQueryCells;
+ size_t i;
+ for (i = 0; i < cellsCount; i++)
+ if (dom->id == cells[i].id)
+ return cells+i;
+ return NULL;
+}
+
+static virDrvOpenStatus
+jailhouseConnectOpen(virConnectPtr conn, virConnectAuthPtr auth
ATTRIBUTE_UNUSED, unsigned int flags)
+{
+ virCheckFlags(0, VIR_DRV_OPEN_ERROR);
+ if (conn->uri->scheme == NULL ||
+ STRNEQ(conn->uri->scheme, "jailhouse"))
+ return VIR_DRV_OPEN_DECLINED;
+ char* binary;
+ if (conn->uri->path == NULL) {
+ if (VIR_STRDUP(binary, "jailhouse") != 1)
+ return VIR_DRV_OPEN_ERROR;
+ } else {
+ if (!virFileIsExecutable(conn->uri->path)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Path '%s', is not a valid executable file."),
+ conn->uri->path);
+ return VIR_DRV_OPEN_ERROR;
+ }
+ if (VIR_STRDUP(binary, conn->uri->path) != 1)
+ return VIR_DRV_OPEN_ERROR;
+ }
+ virCommandPtr cmd = virCommandNew(binary);
+ virCommandAddArg(cmd, "--version");
+ virCommandAddEnvPassCommon(cmd);
+ char *output;
+ virCommandSetOutputBuffer(cmd, &output);
+ if (virCommandRun(cmd, NULL) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Executing '%s --version' failed."),
+ conn->uri->path);
+ VIR_FREE(output);
+ return VIR_DRV_OPEN_ERROR;
+ }
+ if (STRNEQLEN(JAILHOUSEVERSIONOUTPUT, output,
strlen(JAILHOUSEVERSIONOUTPUT))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("%s doesn't seem to be a correct Jailhouse
binary."),
+ conn->uri->path);
+ VIR_FREE(output);
+ return VIR_DRV_OPEN_ERROR;
+ }
+ VIR_FREE(output);
+ struct jailhouse_driver *driver;
+ if (VIR_ALLOC(driver))
+ return VIR_DRV_OPEN_ERROR;
+ driver->binary = binary;
+ driver->lastQueryCells = NULL;
+ driver->lastQueryCellsCount = 0;
+ conn->privateData = driver;
+ return VIR_DRV_OPEN_SUCCESS;
+}
+
+static int
+jailhouseConnectClose(virConnectPtr conn)
+{
+ size_t i;
+ size_t cellsCount = ((struct jailhouse_driver
*)conn->privateData)->lastQueryCellsCount;
+ struct jailhouse_cell *cells = ((struct jailhouse_driver
*)conn->privateData)->lastQueryCells;
+ for (i = 0; i < cellsCount; i++) {
+ VIR_FREE(cells[i].assignedCPUs);
+ VIR_FREE(cells[i].failedCPUs);
+ }
+ VIR_FREE(cells);
+ VIR_FREE(((struct jailhouse_driver *)conn->privateData)->binary);
+ VIR_FREE(conn->privateData);
+ conn->privateData = NULL;
+ return 0;
+}
+
+static int
+jailhouseConnectNumOfDomains(virConnectPtr conn)
+{
+ getCurrentCellList(conn);
+ return ((struct jailhouse_driver
*)conn->privateData)->lastQueryCellsCount;
+}
+
+static int
+jailhouseConnectListDomains(virConnectPtr conn, int * ids, int maxids)
+{
+ getCurrentCellList(conn);
+ size_t cellsCount = ((struct jailhouse_driver
*)conn->privateData)->lastQueryCellsCount;
+ struct jailhouse_cell *cells = ((struct jailhouse_driver
*)conn->privateData)->lastQueryCells;
+ size_t i;
+ for (i = 0; i < maxids && i < cellsCount; i++)
+ ids[i] = cells[i].id;
+ return i;
+}
+
+static int
+jailhouseConnectListAllDomains(virConnectPtr conn, virDomainPtr **
domains, unsigned int flags)
+{
+ virCheckFlags(VIR_CONNECT_LIST_DOMAINS_ACTIVE, 0);
+ getCurrentCellList(conn);
+ size_t cellsCount = ((struct jailhouse_driver
*)conn->privateData)->lastQueryCellsCount;
+ struct jailhouse_cell *cells = ((struct jailhouse_driver
*)conn->privateData)->lastQueryCells;
+ if (cellsCount == -1)
+ goto error;
+ if (VIR_ALLOC_N(*domains, cellsCount+1)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Failed to allocate virDomainPtr array of size
%zu"), cellsCount+1);
+ goto error;
+ }
+ size_t i;
+ for (i = 0; i < cellsCount; i++)
+ (*domains)[i] = cellToVirDomainPtr(conn, cells+i);
+ (*domains)[cellsCount] = NULL;
+ return cellsCount;
+ error:
+ *domains = NULL;
+ return -1;
+}
+
+static virDomainPtr
+jailhouseDomainLookupByID(virConnectPtr conn, int id)
+{
+ getCurrentCellList(conn);
+ size_t cellsCount = ((struct jailhouse_driver
*)conn->privateData)->lastQueryCellsCount;
+ if (cellsCount == -1)
+ return NULL;
+ struct jailhouse_cell *cells = ((struct jailhouse_driver
*)conn->privateData)->lastQueryCells;
+ size_t i;
+ for (i = 0; i < cellsCount; i++)
+ if (cells[i].id == id)
+ return cellToVirDomainPtr(conn, cells+i);
+ virReportError(VIR_ERR_NO_DOMAIN, NULL);
+ return NULL;
+}
+
+static virDomainPtr
+jailhouseDomainLookupByName(virConnectPtr conn, const char *lookupName)
+{
+ getCurrentCellList(conn);
+ size_t cellsCount = ((struct jailhouse_driver
*)conn->privateData)->lastQueryCellsCount;
+ if (cellsCount == -1)
+ return NULL;
+ struct jailhouse_cell *cells = ((struct jailhouse_driver
*)conn->privateData)->lastQueryCells;
+ size_t i;
+ for (i = 0; i < cellsCount; i++)
+ if (STREQ(cells[i].name, lookupName))
+ return cellToVirDomainPtr(conn, cells+i);
+ virReportError(VIR_ERR_NO_DOMAIN, NULL);
+ return NULL;
+}
+
+static virDomainPtr
+jailhouseDomainLookupByUUID(virConnectPtr conn, const unsigned char * uuid)
+{
+ getCurrentCellList(conn);
+ size_t cellsCount = ((struct jailhouse_driver
*)conn->privateData)->lastQueryCellsCount;
+ if (cellsCount == -1)
+ return NULL;
+ struct jailhouse_cell *cells = ((struct jailhouse_driver
*)conn->privateData)->lastQueryCells;
+ size_t i;
+ for (i = 0; i < cellsCount; i++)
+ if (memcmp(cells[i].uuid, (const char*)uuid, VIR_UUID_BUFLEN) == 0)
+ return cellToVirDomainPtr(conn, cells+i);
+ virReportError(VIR_ERR_NO_DOMAIN, NULL);
+ return NULL;
+}
+
+/*
+ * There currently is no straightforward way for the driver to
retrieve those,
+ * so maxMem, memory and cpuTime have dummy values
+ */
+static int
+jailhouseDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
+{
+ struct jailhouse_cell *cell = virDomainPtrToCell(domain);
+ if (cell == NULL)
+ return -1;
+ info->state = cellToVirDomainState(cell);
+ info->maxMem = 1;
+ info->memory = 1;
+ info->nrVirtCpu = cell->assignedCPUsLength;
+ info->cpuTime = 1;
+ return 0;
+}
+
+static int
+jailhouseDomainGetState(virDomainPtr domain, int *state,
+ int *reason ATTRIBUTE_UNUSED, unsigned int flags)
+{
+ virCheckFlags(0, 0);
+ struct jailhouse_cell *cell = virDomainPtrToCell(domain);
+ if (cell == NULL)
+ return -1;
+ *state = cellToVirDomainState(cell);
+ return 0;
+}
+
+static int
+jailhouseDomainShutdown(virDomainPtr domain)
+{
+ virCommandPtr cmd = virCommandNew(((struct jailhouse_driver
*)domain->conn->privateData)->binary);
+ virCommandAddArg(cmd, "cell");
+ virCommandAddArg(cmd, "shutdown");
+ char buf[IDLENGTH+1];
+ snprintf(buf, IDLENGTH+1, "%d", domain->id);
+ virCommandAddArg(cmd, buf);
+ virCommandAddEnvPassCommon(cmd);
+ int resultcode = virCommandRun(cmd, NULL);
+ if (resultcode < 0)
+ return -1;
+ return 0;
+}
+
+/*
+ * CAREFUL, this is the Jailhouse destroy, not the libvirt destroy,
cell will be deleted and would need to be created and loaded again.
+ * This is implemented anyway, so libvirt clients have an option to
use jailhouse destroy too.
+ */
+static int
+jailhouseDomainDestroy(virDomainPtr domain)
+{
+ virCommandPtr cmd = virCommandNew(((struct jailhouse_driver
*)domain->conn->privateData)->binary);
+ virCommandAddArg(cmd, "cell");
+ virCommandAddArg(cmd, "destroy");
+ char buf[IDLENGTH+1];
+ snprintf(buf, IDLENGTH+1, "%d", domain->id);
+ virCommandAddArg(cmd, buf);
+ virCommandAddEnvPassCommon(cmd);
+ int resultcode = virCommandRun(cmd, NULL);
+ if (resultcode < 0)
+ return -1;
+ return 0;
+}
+
+static int
+jailhouseDomainCreate(virDomainPtr domain)
+{
+ virCommandPtr cmd = virCommandNew(((struct jailhouse_driver
*)domain->conn->privateData)->binary);
+ virCommandAddArg(cmd, "cell");
+ virCommandAddArg(cmd, "start");
+ char buf[IDLENGTH+1];
+ snprintf(buf, IDLENGTH+1, "%d", domain->id);
+ virCommandAddArg(cmd, buf);
+ virCommandAddEnvPassCommon(cmd);
+ int resultcode = virCommandRun(cmd, NULL);
+ if (resultcode < 0)
+ return -1;
+ return 0;
+}
+
+/*
+ * There currently is no reason why it shouldn't be
+ */
+static int
+jailhouseConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ return 1;
+}
+
+static int
+jailhouseNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED,
virNodeInfoPtr info)
+{
+ return nodeGetInfo(NULL, info);
+}
+
+/*
+ * Returns a dummy capabilities XML for virt-manager
+ */
+static char *
+jailhouseConnectGetCapabilities(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+ char* caps;
+ if (VIR_STRDUP(caps, "<capabilities></capabilities>") != 1)
+ return NULL;
+ return caps;
+}
+
+/*
+ * Returns a dummy XML for virt-manager
+ */
+static char *
+jailhouseDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
+{
+ virCheckFlags(0, NULL);
+ char buf[200];
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ virDomainGetUUIDString(domain, uuid);
+ snprintf(buf, 200, "<domain type =\"jailhouse\">\n\
+ <name>%s</name>\n\
+ <uuid>%s</uuid>\n\
+ </domain>", domain->name, uuid);
+ char* result;
+ if (VIR_STRDUP(result, buf) != 1)
+ return NULL;
+ return result;
+}
+
+static virHypervisorDriver jailhouseHypervisorDriver = {
+ .name = "jailhouse",
+ .connectOpen = jailhouseConnectOpen, /* 1.2.22 */
+ .connectClose = jailhouseConnectClose, /* 1.2.22 */
+ .connectGetCapabilities = jailhouseConnectGetCapabilities, /* 1.2.22 */
+ .connectNumOfDomains = jailhouseConnectNumOfDomains, /* 1.2.22 */
+ .connectListDomains = jailhouseConnectListDomains, /* 1.2.22 */
+ .connectIsAlive = jailhouseConnectIsAlive, /* 1.2.22 */
+ .connectListAllDomains = jailhouseConnectListAllDomains, /* 1.2.22 */
+ .domainLookupByID = jailhouseDomainLookupByID, /* 1.2.22 */
+ .domainLookupByName = jailhouseDomainLookupByName, /* 1.2.22 */
+ .domainLookupByUUID = jailhouseDomainLookupByUUID, /* 1.2.22 */
+ .domainGetInfo = jailhouseDomainGetInfo, /* 1.2.22 */
+ .domainGetState = jailhouseDomainGetState, /* 1.2.22 */
+ .domainGetXMLDesc = jailhouseDomainGetXMLDesc, /* 1.2.22 */
+ .domainShutdown = jailhouseDomainShutdown, /* 1.2.22 */
+ .domainDestroy = jailhouseDomainDestroy, /* 1.2.22 */
+ .domainCreate = jailhouseDomainCreate, /* 1.2.22 */
+ .nodeGetInfo = jailhouseNodeGetInfo /* 1.2.22 */
+};
+
+static virConnectDriver jailhouseConnectDriver = {
+ .hypervisorDriver = &jailhouseHypervisorDriver,
+};
+
+int
+jailhouseRegister(void)
+{
+ return virRegisterConnectDriver(&jailhouseConnectDriver,
+ false);
+}
diff --git a/src/jailhouse/jailhouse_driver.h
b/src/jailhouse/jailhouse_driver.h
new file mode 100644
index 0000000..47c17e7
--- /dev/null
+++ b/src/jailhouse/jailhouse_driver.h
@@ -0,0 +1,28 @@
+/*
+ * jailhouse_driver.h: hypervisor driver for managing Jailhouse cells
+ *
+ * Copyright (C) 2015 Linutronix 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, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Christian Loehle
+ */
+
+#ifndef JAILHOUSE_DRIVER_H
+# define JAILHOUSE_DRIVER_H
+
+int jailhouseRegister(void);
+
+#endif
diff --git a/src/libvirt.c b/src/libvirt.c
index 25a0040..7626353 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -98,6 +98,9 @@
#ifdef WITH_BHYVE
# include "bhyve/bhyve_driver.h"
#endif
+#ifdef WITH_JAILHOUSE
+# include "jailhouse/jailhouse_driver.h"
+#endif
#define VIR_FROM_THIS VIR_FROM_NONE
@@ -437,12 +440,17 @@ virGlobalInit(void)
if (vzRegister() == -1)
goto error;
# endif
+#ifdef WITH_JAILHOUSE
+ if (jailhouseRegister() == -1)
+ goto error;
+#endif
#endif
#ifdef WITH_REMOTE
if (remoteRegister() == -1)
goto error;
#endif
+
return;
error:
@@ -1167,6 +1175,9 @@ do_open(const char *name,
#ifndef WITH_VZ
STRCASEEQ(ret->uri->scheme, "parallels") ||
#endif
+#ifndef WITH_JAILHOUSE
+ STRCASEEQ(ret->uri->scheme, "jailhouse") ||
+#endif
false)) {
virReportErrorHelper(VIR_FROM_NONE, VIR_ERR_CONFIG_UNSUPPORTED,
__FILE__, __FUNCTION__, __LINE__,
diff --git a/src/util/virerror.c b/src/util/virerror.c
index 6dc05f4..0d480c0 100644
--- a/src/util/virerror.c
+++ b/src/util/virerror.c
@@ -134,6 +134,7 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST,
"Polkit", /* 60 */
"Thread jobs",
"Admin Interface",
+ "Jailhouse Driver",
)
9 years
[libvirt] [PATCH v4 00/10] Few VFIO related fixes
by Shivaprasad G Bhat
The series fixes few VFIO related host crash issues. The patches 3, 4, 9 and 10
are actual fixes. Patch 7 and 8 are test changes to allow testing patch 9.
Rest of the patches are mostly code movements except for patch 2.
---
Changes from v3 -> v4
- Andrea's suggestion not to overload the usage of stubDriver to set it in
virPCINew is addressed. Not setting it any more. Fetch it fresh from
sysfs.
- The test case added in old P7 is improvised
- Old P7 is split into 3 patches where I have moved the virpcimock
changes to support iommu into a new patch.
Shivaprasad G Bhat (10):
Implement virPCIIsKnownStub function
Add iommu group number info to virPCIDevice
Refuse to reattach from vfio if the iommu group is in use by any domain
Wait for vfio-pci device cleanups before reassinging the device to host driver
Split reprobe action from the virPCIUnbindFromStub into a new function
Pass activeDevs and inactiveDevs to virPCIDeviceUnbindFromStub and virPCIDeviceBindToStub
Change the negative test case to try pciback instead of vfio-pci
Add iommu info for pci on mocked sysfs
Postpone reprobing till all the devices in iommu group are unbound from vfio
Wait for iommmu device to go away before reprobing the host driver
src/util/virhostdev.c | 28 ++++-
src/util/virpci.c | 297 +++++++++++++++++++++++++++++++++++++++++--------
tests/virpcimock.c | 193 +++++++++++++++++++++++++++++---
tests/virpcitest.c | 117 +++++++++++++++++++
4 files changed, 566 insertions(+), 69 deletions(-)
--
Signature
9 years
[libvirt] [PATCH v3] storage sheepdog: allow to specify redundancy level
by Vasiliy Tolstov
Completely fix tests and check that all works on production env
Vasiliy Tolstov (1):
storage sheepdog: allow to specify redundancy level
docs/schemas/storagevol.rng | 3 +
src/conf/storage_conf.c | 2 +
src/storage/storage_backend_sheepdog.c | 143 +++++++++++++++++-----------
src/util/virstoragefile.c | 4 +-
src/util/virstoragefile.h | 2 +
tests/storagebackendsheepdogtest.c | 104 ++++++++++----------
tests/storagevolxml2xmlin/vol-sheepdog.xml | 1 +
tests/storagevolxml2xmlout/vol-sheepdog.xml | 1 +
8 files changed, 153 insertions(+), 107 deletions(-)
--
2.5.0
9 years
[libvirt] [PATCH] vz: Allow to create container based on template
by Mikhail Feoktistov
We shouldn't delete disk from default config if we create container based on template,
because we don't have the new disk from XML, only template name.
And don't add template section from XML as new filesystem,
we use PrlVmCfg_SetOsTemplate function to set template name.
---
src/vz/vz_sdk.c | 33 +++++++++++++++++++++++++++++----
1 file changed, 29 insertions(+), 4 deletions(-)
diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c
index 89c9e89..865cabe 100644
--- a/src/vz/vz_sdk.c
+++ b/src/vz/vz_sdk.c
@@ -2096,12 +2096,14 @@ prlsdkCheckUnsupportedParams(PRL_HANDLE sdkdom, virDomainDefPtr def)
return 0;
}
-static int prlsdkClearDevices(PRL_HANDLE sdkdom)
+static int prlsdkClearDevices(PRL_HANDLE sdkdom, bool skipdisk)
{
PRL_RESULT pret;
PRL_UINT32 n, i;
PRL_HANDLE devList;
PRL_HANDLE dev;
+ PRL_DEVICE_TYPE devType;
+ PRL_VM_DEV_EMULATION_TYPE emul;
int ret = -1;
pret = PrlVmCfg_SetVNCMode(sdkdom, PRD_DISABLED);
@@ -2117,6 +2119,18 @@ static int prlsdkClearDevices(PRL_HANDLE sdkdom)
pret = PrlHndlList_GetItem(devList, i, &dev);
prlsdkCheckRetGoto(pret, cleanup);
+ if (skipdisk) {
+ pret = PrlVmDev_GetType(dev, &devType);
+ prlsdkCheckRetGoto(pret, cleanup);
+
+ pret = PrlVmDev_GetEmulatedType(dev, &emul);
+ prlsdkCheckRetGoto(pret, cleanup);
+
+ if (devType == PDE_HARD_DISK) {
+ PrlHandle_Free(dev);
+ continue;
+ }
+ }
pret = PrlVmDev_Remove(dev);
PrlHandle_Free(dev);
}
@@ -3465,6 +3479,7 @@ prlsdkDoApplyConfig(virConnectPtr conn,
char uuidstr[VIR_UUID_STRING_BUFLEN + 2];
bool needBoot = true;
char *mask = NULL;
+ bool skipdisk = false;
if (prlsdkCheckUnsupportedParams(sdkdom, def) < 0)
return -1;
@@ -3514,7 +3529,11 @@ prlsdkDoApplyConfig(virConnectPtr conn,
}
prlsdkCheckRetGoto(pret, error);
- if (prlsdkClearDevices(sdkdom) < 0)
+ if (def->nfss == 1 &&
+ def->fss[0]->type == VIR_DOMAIN_FS_TYPE_TEMPLATE)
+ skipdisk = true;
+
+ if (prlsdkClearDevices(sdkdom, skipdisk) < 0)
goto error;
if (prlsdkRemoveBootDevices(sdkdom) < 0)
@@ -3544,6 +3563,8 @@ prlsdkDoApplyConfig(virConnectPtr conn,
for (i = 0; i < def->nfss; i++) {
if (STREQ(def->fss[i]->dst, "/"))
needBoot = false;
+ if (def->fss[i]->type == VIR_DOMAIN_FS_TYPE_TEMPLATE)
+ continue;
if (prlsdkAddFS(sdkdom, def->fss[i]) < 0)
goto error;
}
@@ -3655,6 +3676,7 @@ prlsdkCreateCt(virConnectPtr conn, virDomainDefPtr def)
int ret = -1;
int useTemplate = 0;
size_t i;
+ PRL_UINT32 flags = 0;
if (def->nfss > 1) {
/* Check all filesystems */
@@ -3696,8 +3718,11 @@ prlsdkCreateCt(virConnectPtr conn, virDomainDefPtr def)
if (ret)
goto cleanup;
- job = PrlVm_RegEx(sdkdom, "",
- PACF_NON_INTERACTIVE_MODE | PRNVM_PRESERVE_DISK);
+ flags = PACF_NON_INTERACTIVE_MODE;
+ if (!useTemplate)
+ flags = flags | PRNVM_PRESERVE_DISK;
+
+ job = PrlVm_RegEx(sdkdom, "", flags);
if (PRL_FAILED(waitJob(job)))
ret = -1;
--
1.8.3.1
9 years
[libvirt] [PATCH v2 00/27] Prepare for specific vcpu hot(un)plug - part 1
by Peter Krempa
This series is getting rather big. The target is to refactor the way libvirt
stores info about vCPUs into a single structure (okay, two structures for the
qemu driver. Part 1 is not yet completely there, well, not even halfway.
Future work will involve fully allocating priv->vcpupids to the maxcpus size
and moving around few other bits of data in cputune and other parts to the new
structure. Yet another follow up work is then to add new APIs for vCPU hotplug,
which will enable adding vCPUs sparsely (useful if you have NUMA).
Since this refactor will result in tracking all vcpu-related data in one struct,
the result will automagically fix a few bugs where we'd end up with invalid
config after vcpu unplug or other operations.
Version 2 does not contain already pushed patches and incorporates feedback from
John's review. Since I've changed quite a few things I'm reposting this.
Peter Krempa (27):
conf: Replace writes to def->maxvcpus with accessor
conf: Use local copy of maxvcpus in virDomainVcpuParse
conf: Extract update of vcpu count if maxvcpus is decreased
conf: Add helper to check whether domain has offline vCPUs
conf: Replace read access to def->maxvcpus with accessor
conf: Replace writes to def->vcpus with accessor
conf: Move vcpu count check into helper
conf: Replace read accesses to def->vcpus with accessor
conf: Turn def->maxvcpus into size_t
qemu: domain: Add helper to access vm->privateData->agent
qemu: Extract vCPU onlining/offlining via agent into a separate
function
qemu: qemuDomainSetVcpusAgent: re-check agent before calling it the
again
qemu: Split up vCPU hotplug and hotunplug
qemu: cpu hotplug: Fix error handling logic
qemu: monitor: Remove weird return values from qemuMonitorSetCPU
qemu: cpu hotplug: Move loops to qemuDomainSetVcpusFlags
qemu: Refactor qemuDomainHotplugVcpus
qemu: refactor qemuDomainHotunplugVcpus
conf: turn def->vcpus into a structure
conf: ABI: Split up and improve vcpu info ABI checking
conf: Add helper to get pointer to a certain vCPU definition
qemu: cgroup: Remove now unreachable check
qemu: Drop checking vcpu threads in emulator bandwidth getter/setter
qemu: Replace checking for vcpu<->pid mapping availability with a
helper
qemu: Add helper to retrieve vCPU pid
qemu: driver: Refactor qemuDomainHelperGetVcpus
qemu: cgroup: Don't use priv->ncpupids to iterate domain vCPUs
src/bhyve/bhyve_command.c | 2 +-
src/bhyve/bhyve_driver.c | 2 +-
src/conf/domain_audit.c | 2 +-
src/conf/domain_conf.c | 190 ++++++++++++---
src/conf/domain_conf.h | 20 +-
src/hyperv/hyperv_driver.c | 10 +-
src/libvirt_private.syms | 6 +
src/libxl/libxl_conf.c | 6 +-
src/libxl/libxl_driver.c | 40 ++--
src/lxc/lxc_controller.c | 2 +-
src/lxc/lxc_driver.c | 2 +-
src/lxc/lxc_native.c | 7 +-
src/openvz/openvz_conf.c | 7 +-
src/openvz/openvz_driver.c | 19 +-
src/phyp/phyp_driver.c | 12 +-
src/qemu/qemu_cgroup.c | 42 ++--
src/qemu/qemu_command.c | 29 ++-
src/qemu/qemu_domain.c | 47 ++++
src/qemu/qemu_domain.h | 4 +
src/qemu/qemu_driver.c | 542 ++++++++++++++++++++++---------------------
src/qemu/qemu_monitor.c | 3 +
src/qemu/qemu_monitor_json.c | 8 -
src/qemu/qemu_monitor_text.c | 23 +-
src/qemu/qemu_process.c | 22 +-
src/test/test_driver.c | 38 +--
src/uml/uml_driver.c | 2 +-
src/vbox/vbox_common.c | 19 +-
src/vmware/vmware_driver.c | 2 +-
src/vmx/vmx.c | 38 +--
src/vz/vz_driver.c | 8 +-
src/vz/vz_sdk.c | 13 +-
src/xen/xm_internal.c | 19 +-
src/xenapi/xenapi_driver.c | 7 +-
src/xenapi/xenapi_utils.c | 6 +-
src/xenconfig/xen_common.c | 16 +-
src/xenconfig/xen_sxpr.c | 27 ++-
36 files changed, 767 insertions(+), 475 deletions(-)
--
2.6.2
9 years
[libvirt] [PATCH v2] guest-agent-socket: don't generate default path to config XML
by Pavel Hrdina
While we started using for all unix sockets as default one common
directory based on a guest name it introduced several issues, for example
with renaming the guest or cloning it. In general it's not entirely
bad, but in this case it would be best to hide the auto-generated socket
path from user and don't export it in the config XML.
Signed-off-by: Pavel Hrdina <phrdina(a)redhat.com>
---
Version 2:
- removed unnecessary changes
src/qemu/qemu_command.c | 28 ++++++++++++++++++++++++++++
src/qemu/qemu_command.h | 1 +
src/qemu/qemu_domain.c | 16 ----------------
src/qemu/qemu_driver.c | 3 +++
src/qemu/qemu_process.c | 3 +++
tests/qemuhotplugtest.c | 5 +++++
tests/qemuxml2argvtest.c | 5 +++++
7 files changed, 45 insertions(+), 16 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 2a9fab5..f1bb621 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1262,6 +1262,34 @@ qemuAssignDeviceAliases(virDomainDefPtr def, virQEMUCapsPtr qemuCaps)
}
+int
+qemuUnixSocketGenerate(virDomainDefPtr def,
+ virQEMUDriverConfigPtr cfg)
+{
+ size_t i;
+
+ for (i = 0; i < def->nchannels; i++) {
+ virDomainChrDefPtr channel = def->channels[i];
+
+ if (channel->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
+ channel->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO &&
+ channel->source.type == VIR_DOMAIN_CHR_TYPE_UNIX &&
+ !channel->source.data.nix.path) {
+ if (virAsprintf(&channel->source.data.nix.path,
+ "%s/domain-%s/%s",
+ cfg->channelTargetDir, def->name,
+ channel->target.name ? channel->target.name
+ : "unknown.sock") < 0)
+ return -1;
+
+ channel->source.data.nix.listen = true;
+ }
+ }
+
+ return 0;
+}
+
+
static void
qemuDomainPrimeVirtioDeviceAddresses(virDomainDefPtr def,
virDomainDeviceAddressType type)
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index bebdd27..0512a23 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -283,6 +283,7 @@ int qemuAssignDevicePCISlots(virDomainDefPtr def,
virDomainPCIAddressSetPtr addrs);
int qemuAssignDeviceAliases(virDomainDefPtr def, virQEMUCapsPtr qemuCaps);
+int qemuUnixSocketGenerate(virDomainDefPtr def, virQEMUDriverConfigPtr cfg);
int qemuDomainNetVLAN(virDomainNetDefPtr def);
int qemuAssignDeviceNetAlias(virDomainDefPtr def, virDomainNetDefPtr net, int idx);
int qemuAssignDeviceDiskAlias(virDomainDefPtr vmdef,
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index ed21245..7e05289 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -1329,22 +1329,6 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
ARCH_IS_S390(def->os.arch))
dev->data.controller->model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI;
- /* auto generate unix socket path */
- if (dev->type == VIR_DOMAIN_DEVICE_CHR &&
- dev->data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL &&
- dev->data.chr->targetType == VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO &&
- dev->data.chr->source.type == VIR_DOMAIN_CHR_TYPE_UNIX &&
- !dev->data.chr->source.data.nix.path) {
- if (virAsprintf(&dev->data.chr->source.data.nix.path,
- "%s/domain-%s/%s",
- cfg->channelTargetDir, def->name,
- dev->data.chr->target.name ? dev->data.chr->target.name
- : "unknown.sock") < 0)
- goto cleanup;
-
- dev->data.chr->source.data.nix.listen = true;
- }
-
/* forbid capabilities mode hostdev in this kind of hypervisor */
if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&
dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES) {
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index ae1d8e7..39f2f03 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7254,6 +7254,9 @@ static char *qemuConnectDomainXMLToNative(virConnectPtr conn,
if (qemuAssignDeviceAliases(def, qemuCaps) < 0)
goto cleanup;
+ if (qemuUnixSocketGenerate(def, cfg) < 0)
+ goto cleanup;
+
if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
goto cleanup;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 192730c..29cf965 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4663,6 +4663,9 @@ qemuProcessLaunch(virConnectPtr conn,
if (qemuAssignDeviceAliases(vm->def, priv->qemuCaps) < 0)
goto cleanup;
+ if (qemuUnixSocketGenerate(vm->def, cfg) < 0)
+ goto cleanup;
+
/* Get the advisory nodeset from numad if 'placement' of
* either <vcpu> or <numatune> is 'auto'.
*/
diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c
index 102e052..b17cca2 100644
--- a/tests/qemuhotplugtest.c
+++ b/tests/qemuhotplugtest.c
@@ -61,6 +61,7 @@ qemuHotplugCreateObjects(virDomainXMLOptionPtr xmlopt,
{
int ret = -1;
qemuDomainObjPrivatePtr priv = NULL;
+ virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(&driver);
if (!(*vm = virDomainObjNew(xmlopt)))
goto cleanup;
@@ -94,10 +95,14 @@ qemuHotplugCreateObjects(virDomainXMLOptionPtr xmlopt,
if (qemuAssignDeviceAliases((*vm)->def, priv->qemuCaps) < 0)
goto cleanup;
+ if (qemuUnixSocketGenerate((*vm)->def, cfg) < 0)
+ goto cleanup;
+
(*vm)->def->id = QEMU_HOTPLUG_TEST_DOMAIN_ID;
ret = 0;
cleanup:
+ virObjectUnref(cfg);
return ret;
}
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index f7596a0..f6083db 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -262,6 +262,7 @@ static int testCompareXMLToArgvFiles(const char *xml,
virCommandPtr cmd = NULL;
size_t i;
virBitmapPtr nodeset = NULL;
+ virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(&driver);
if (!(conn = virGetConnect()))
goto out;
@@ -324,6 +325,9 @@ static int testCompareXMLToArgvFiles(const char *xml,
if (qemuAssignDeviceAliases(vmdef, extraFlags) < 0)
goto out;
+ if (qemuUnixSocketGenerate(vmdef, cfg) < 0)
+ goto out;
+
for (i = 0; i < vmdef->nhostdevs; i++) {
virDomainHostdevDefPtr hostdev = vmdef->hostdevs[i];
@@ -387,6 +391,7 @@ static int testCompareXMLToArgvFiles(const char *xml,
virCommandFree(cmd);
virDomainDefFree(vmdef);
virObjectUnref(conn);
+ virObjectUnref(cfg);
virBitmapFree(nodeset);
return ret;
}
--
2.6.3
9 years
[libvirt] libvirt-php 0.5.1 uneeded files
by Remi Collet
Installing the new 0.5.1 version:
libvirt-php.la
libvirt-php.so -> libvirt-php.so.0.0.0
libvirt-php.so.0 -> libvirt-php.so.0.0.0
libvirt-php.so.0.0.0
This is not a versioned library but a PHP extension so having those
have no sense.
Only libvirt-php.so is needed.
Notice: I think it will be simpler to switch to the standard PHP
extension build system (phpize; configure; make)
Especially, this will allow to use the --with-php-config option (an
thus, build for not standard PHP, e.g. TS build or SCL build)
Remi.
9 years
[libvirt] [PATCH] doc: extend virDomainSetMemory semantics
by Nikolay Shirokovskiy
virDomainSetMemory is documented to change only runtime configuration of
running domain. This can't be implemented for vz driver as it always change
persistent state too. Let's extend semantics of this function for changes to be
hyperviror specific. As a result 'virsh setmem' without parameters (which ends
up in virDomainSetMemory call) would be possible for a vz domain. By the way,
virsh documentation for this case states that behaviour is hypervisor specific
already.
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy(a)virtuozzo.com>
---
src/libvirt-domain.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
index de7eb04..56ab907 100644
--- a/src/libvirt-domain.c
+++ b/src/libvirt-domain.c
@@ -1882,8 +1882,9 @@ virDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
* to Domain0 i.e. the domain where the application runs.
* This function may require privileged access to the hypervisor.
*
- * This command only changes the runtime configuration of the domain,
- * so can only be called on an active domain.
+ * This command is hypervisor-specific for whether active, persistent,
+ * or both configurations are changed; for more control, use
+ * virDomainSetMemoryFlags().
*
* Returns 0 in case of success and -1 in case of failure.
*/
--
1.7.1
9 years
[libvirt] [PATCH 0/3] libvirt: Fix automatic SCSI controller create in hotplug
by Boris Fiuczynski
Trying to hotplug a SCSI device to a domain without the required SCSI
controller fails.
For hostdev SCSI device hotplug commits 0d8b24f6 and 0785966d rearranged
the automatic creation of the required SCSI controllers from the parsing
xml code into the post parsing code section of virDomainDefParseXML. In
doing so the code will create but not hotplug the missing SCSI controller
and on the hotplug path thru the same code the SCSI controller will not get
hotplugged since it already exits. Then the SCSI hostdev device is
hotplugged and runs into the following internal error
error: Failed to attach device from scsidev.xml
error: internal error: Device alias was not set for scsi controller with index 0
For disk SCSI device hotplug commit 0260506c added in method
qemuBuildDriveDevStr a lookup of the controller alias. The internal error
error: Failed to attach device from scsi_disk.xml
error: internal error: Could not find scsi controller with index 0 required for device
occurs because in method qemuDomainAttachSCSIDisk the automatic creation
of the missing SCSI controller occurs after calling qemuBuildDriveDevStr.
Boris Fiuczynski (3):
conf: Reposition adding SCSI controller for SCSI hostdev hotplug
Revert "conf: Try controller add when searching hostdev bus for unit"
Automatic SCSI controller creation in SCSI disk hotplug broken
src/conf/domain_conf.c | 16 ++++------------
src/qemu/qemu_hotplug.c | 12 ++++++------
2 files changed, 10 insertions(+), 18 deletions(-)
--
2.3.0
9 years
[libvirt] [PATCH v2] libxl: add p2p migration
by Joao Martins
Introduce support for VIR_MIGRATE_PEER2PEER in libxl driver
for supporting migration in Openstack. Most of the changes
occur at the source and no modifications at the receiver.
In P2P mode there is only the Perform phase so we must handle
the connection with the destination and actually perform the
migration. libxlDomainPerformP2P implements the connection to
the destination and let libxlDoMigrateP2P implements the actual
migration logic with virConnectPtr. In this function we do
the migration steps in the destination similar to
virDomainMigrateVersion3Full. We appropriately save the last
error reported in each of the phases to provide proper
reporting. We don't yet support VIR_MIGRATE_TUNNELED and
we always use V3 with extensible params, making the
implementation simpler.
It is worth noting that the receiver didn't have any changes,
and because it's still the v3 sequence thus it is possible to
migrate from a P2P to non-P2P host.
Signed-off-by: Joao Martins <joao.m.martins(a)oracle.com>
---
Changes since v1:
- Move Begin step to libxlDoMigrateP2P to have all 4 steps
together.
- Remove if before VIR_FREE(dom_xml)
---
src/libxl/libxl_driver.c | 13 ++-
src/libxl/libxl_migration.c | 220 ++++++++++++++++++++++++++++++++++++++++++++
src/libxl/libxl_migration.h | 11 +++
3 files changed, 241 insertions(+), 3 deletions(-)
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index fcdcbdb..da98265 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -4713,6 +4713,7 @@ libxlConnectSupportsFeature(virConnectPtr conn, int feature)
switch (feature) {
case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
case VIR_DRV_FEATURE_MIGRATION_PARAMS:
+ case VIR_DRV_FEATURE_MIGRATION_P2P:
return 1;
default:
return 0;
@@ -5039,9 +5040,15 @@ libxlDomainMigratePerform3Params(virDomainPtr dom,
if (virDomainMigratePerform3ParamsEnsureACL(dom->conn, vm->def) < 0)
goto cleanup;
- if (libxlDomainMigrationPerform(driver, vm, dom_xml, dconnuri,
- uri, dname, flags) < 0)
- goto cleanup;
+ if (flags & VIR_MIGRATE_PEER2PEER) {
+ if (libxlDomainMigrationPerformP2P(driver, vm, dom->conn, dom_xml,
+ dconnuri, uri, dname, flags) < 0)
+ goto cleanup;
+ } else {
+ if (libxlDomainMigrationPerform(driver, vm, dom_xml, dconnuri,
+ uri, dname, flags) < 0)
+ goto cleanup;
+ }
ret = 0;
diff --git a/src/libxl/libxl_migration.c b/src/libxl/libxl_migration.c
index 0d23e5f..a1c7b55 100644
--- a/src/libxl/libxl_migration.c
+++ b/src/libxl/libxl_migration.c
@@ -42,6 +42,7 @@
#include "libxl_conf.h"
#include "libxl_migration.h"
#include "locking/domain_lock.h"
+#include "virtypedparam.h"
#define VIR_FROM_THIS VIR_FROM_LIBXL
@@ -456,6 +457,225 @@ libxlDomainMigrationPrepare(virConnectPtr dconn,
return ret;
}
+/* This function is a simplification of virDomainMigrateVersion3Full
+ * excluding tunnel support and restricting it to migration v3
+ * with params since it was the first to be introduced in libxl.
+ */
+static int
+libxlDoMigrateP2P(libxlDriverPrivatePtr driver,
+ virDomainObjPtr vm,
+ virConnectPtr sconn,
+ const char *xmlin,
+ virConnectPtr dconn,
+ const char *dconnuri ATTRIBUTE_UNUSED,
+ const char *dname,
+ const char *uri,
+ unsigned int flags)
+{
+ virDomainPtr ddomain = NULL;
+ virTypedParameterPtr params = NULL;
+ int nparams = 0;
+ int maxparams = 0;
+ char *uri_out = NULL;
+ char *dom_xml = NULL;
+ unsigned long destflags;
+ bool cancelled = true;
+ virErrorPtr orig_err = NULL;
+ int ret = -1;
+
+ dom_xml = libxlDomainMigrationBegin(sconn, vm, xmlin);
+ if (!dom_xml)
+ goto cleanup;
+
+ if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
+ VIR_MIGRATE_PARAM_DEST_XML, dom_xml) < 0)
+ goto cleanup;
+
+ if (dname &&
+ virTypedParamsAddString(¶ms, &nparams, &maxparams,
+ VIR_MIGRATE_PARAM_DEST_NAME, dname) < 0)
+ goto cleanup;
+
+ if (uri &&
+ virTypedParamsAddString(¶ms, &nparams, &maxparams,
+ VIR_MIGRATE_PARAM_URI, uri) < 0)
+ goto cleanup;
+
+ /* We don't require the destination to have P2P support
+ * as it looks to be normal migration from the receiver perpective.
+ */
+ destflags = flags & ~(VIR_MIGRATE_PEER2PEER);
+
+ VIR_DEBUG("Prepare3");
+ virObjectUnlock(vm);
+ ret = dconn->driver->domainMigratePrepare3Params
+ (dconn, params, nparams, NULL, 0, NULL, NULL, &uri_out, destflags);
+ virObjectLock(vm);
+
+ if (ret == -1)
+ goto cleanup;
+
+ if (uri_out) {
+ if (virTypedParamsReplaceString(¶ms, &nparams,
+ VIR_MIGRATE_PARAM_URI, uri_out) < 0) {
+ orig_err = virSaveLastError();
+ goto finish;
+ }
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("domainMigratePrepare3 did not set uri"));
+ goto finish;
+ }
+
+ VIR_DEBUG("Perform3 uri=%s", NULLSTR(uri_out));
+ ret = libxlDomainMigrationPerform(driver, vm, NULL, NULL,
+ uri_out, NULL, flags);
+
+ if (ret < 0)
+ orig_err = virSaveLastError();
+
+ cancelled = (ret < 0);
+
+ finish:
+ VIR_DEBUG("Finish3 ret=%d", ret);
+ if (virTypedParamsGetString(params, nparams,
+ VIR_MIGRATE_PARAM_DEST_NAME, NULL) <= 0 &&
+ virTypedParamsReplaceString(¶ms, &nparams,
+ VIR_MIGRATE_PARAM_DEST_NAME,
+ vm->def->name) < 0) {
+ ddomain = NULL;
+ } else {
+ virObjectUnlock(vm);
+ ddomain = dconn->driver->domainMigrateFinish3Params
+ (dconn, params, nparams, NULL, 0, NULL, NULL,
+ destflags, cancelled);
+ virObjectLock(vm);
+ }
+
+ cancelled = (ddomain == NULL);
+
+ /* If Finish3Params set an error, and we don't have an earlier
+ * one we need to preserve it in case confirm3 overwrites
+ */
+ if (!orig_err)
+ orig_err = virSaveLastError();
+
+ VIR_DEBUG("Confirm3 cancelled=%d vm=%p", cancelled, vm);
+ ret = libxlDomainMigrationConfirm(driver, vm, flags, cancelled);
+
+ if (ret < 0)
+ VIR_WARN("Guest %s probably left in 'paused' state on source",
+ vm->def->name);
+
+ cleanup:
+ if (ddomain) {
+ virObjectUnref(ddomain);
+ ret = 0;
+ } else {
+ ret = -1;
+ }
+
+ if (orig_err) {
+ virSetError(orig_err);
+ virFreeError(orig_err);
+ }
+
+ VIR_FREE(dom_xml);
+ VIR_FREE(uri_out);
+ virTypedParamsFree(params, nparams);
+ return ret;
+}
+
+static int virConnectCredType[] = {
+ VIR_CRED_AUTHNAME,
+ VIR_CRED_PASSPHRASE,
+};
+
+static virConnectAuth virConnectAuthConfig = {
+ .credtype = virConnectCredType,
+ .ncredtype = ARRAY_CARDINALITY(virConnectCredType),
+};
+
+static void
+libxlMigrationConnectionClosed(virConnectPtr conn,
+ int reason,
+ void *opaque)
+{
+ virDomainObjPtr vm = opaque;
+
+ VIR_DEBUG("conn=%p, reason=%d, vm=%s", conn, reason, vm->def->name);
+ virDomainObjBroadcast(vm);
+}
+
+/* On P2P mode there is only the Perform3 phase and we need to handle
+ * the connection with the destination libvirtd and perform the migration.
+ * Here we first tackle the first part of it, and libxlDoMigrationP2P handles
+ * the migration process with an established virConnectPtr to the destination.
+ */
+int
+libxlDomainMigrationPerformP2P(libxlDriverPrivatePtr driver,
+ virDomainObjPtr vm,
+ virConnectPtr sconn,
+ const char *xmlin,
+ const char *dconnuri,
+ const char *uri_str ATTRIBUTE_UNUSED,
+ const char *dname,
+ unsigned int flags)
+{
+ int ret = -1;
+ int keepAliveInterval = 5;
+ int keepAliveCount = 5;
+ bool useParams;
+ virConnectPtr dconn = NULL;
+ virErrorPtr orig_err = NULL;
+
+ virObjectUnlock(vm);
+ dconn = virConnectOpenAuth(dconnuri, &virConnectAuthConfig, 0);
+ virObjectLock(vm);
+
+ if (dconn == NULL) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to connect to remote libvirt URI %s: %s"),
+ dconnuri, virGetLastErrorMessage());
+ return ret;
+ }
+
+ if (virConnectSetKeepAlive(dconn, keepAliveInterval,
+ keepAliveCount) < 0)
+ goto cleanup;
+
+ if (virConnectRegisterCloseCallback(dconn, libxlMigrationConnectionClosed,
+ vm, NULL) < 0) {
+ goto cleanup;
+ }
+
+ virObjectUnlock(vm);
+ useParams = VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
+ VIR_DRV_FEATURE_MIGRATION_PARAMS);
+ virObjectLock(vm);
+
+ if (!useParams) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("Destination libvirt does not support migration with extensible parameters"));
+ goto cleanup;
+ }
+
+ ret = libxlDoMigrateP2P(driver, vm, sconn, xmlin, dconn, dconnuri,
+ dname, uri_str, flags);
+
+ cleanup:
+ orig_err = virSaveLastError();
+ virObjectUnlock(vm);
+ virConnectUnregisterCloseCallback(dconn, libxlMigrationConnectionClosed);
+ virObjectUnref(dconn);
+ virObjectLock(vm);
+ if (orig_err) {
+ virSetError(orig_err);
+ virFreeError(orig_err);
+ }
+ return ret;
+}
+
int
libxlDomainMigrationPerform(libxlDriverPrivatePtr driver,
virDomainObjPtr vm,
diff --git a/src/libxl/libxl_migration.h b/src/libxl/libxl_migration.h
index 20b45d8..0f83bb4 100644
--- a/src/libxl/libxl_migration.h
+++ b/src/libxl/libxl_migration.h
@@ -28,6 +28,7 @@
# define LIBXL_MIGRATION_FLAGS \
(VIR_MIGRATE_LIVE | \
+ VIR_MIGRATE_PEER2PEER | \
VIR_MIGRATE_UNDEFINE_SOURCE | \
VIR_MIGRATE_PAUSED)
@@ -56,6 +57,16 @@ libxlDomainMigrationPrepare(virConnectPtr dconn,
unsigned int flags);
int
+libxlDomainMigrationPerformP2P(libxlDriverPrivatePtr driver,
+ virDomainObjPtr vm,
+ virConnectPtr sconn,
+ const char *dom_xml,
+ const char *dconnuri,
+ const char *uri_str,
+ const char *dname,
+ unsigned int flags);
+
+int
libxlDomainMigrationPerform(libxlDriverPrivatePtr driver,
virDomainObjPtr vm,
const char *dom_xml,
--
2.1.4
9 years