[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, 3 months
[libvirt] How should libvirt apps enable virtio-pci for aarch64?
by Cole Robinson
Hi all,
I'm trying to figure out how apps should request virtio-pci for libvirt + qemu
+ arm/aarch64. Let me provide some background.
qemu's arm/aarch64 original virtio support is via virtio-mmio, libvirt XML
<address type='virtio-mmio'/>. Currently this is what libvirt sets as the
address default for all arm/aarch64 virtio devices in the XML. Long term
though all arm virt will likely be using virtio-pci: it's faster, enables
hotplug, is more x86 like, etc.
Support for virtio-pci is newer and not as widespread. qemu has had the
necessary support since 2.4 at least, but the guest side isn't well
distributed yet. For example, Fedora 23 and earlier don't work out of the box
with virtio-pci. Internal RHELSA (RHEL Server for Aarch64) builds have it
recently working AFAIK.
Libvirt has some support for enabling virtio-pci with aarch64, commits added
by Pavel Fedin in v1.2.19. (See e8d55172544c1fafe31a9e09346bdebca4f0d6f9). The
patches add a PCIe controller automatically to the XML (and qemu commandline)
if qemu-system-aarch64 supports it. However virtio-mmio is still used as the
default virtio address, given the current lack of OS support.
So we are at the point where libvirt apps want to enable this, but presently
there isn't a good solution; the only option is to fully allocate <address
type='pci' ...> for each virtio device in the XML. This is suboptimal for 2
reasons:
#1) apps need to duplicate libvirt's non-trivial address type=pci allocation logic
#2) apps have to add an <address> block for every virtio device, which is less
friendly than the x86 case where this is rarely required. Any XML device
snippets that work for x86 likely won't give the desired result for aarch64,
since they will default to virtio-mmio. Think virsh attach-device/attach-disk
commands
Here are some possible solutions:
* Drop the current behavior of adding a PCIe controller unconditionally, and
instead require apps to specify it in the XML. Then, if libvirt sees a PCIe
controller in the XML, default the virtio address type to pci. Apps will know
if the OS they are installing supports virtio-pci (eventually via libosinfo),
so this is the way we can implicitly ask libvirt 'allocate us pci addresses'
Upsides:
- Solves both the stated problems.
- Simplest addition for applications IMO
Downsides:
- Requires a libvirt behavior change, no longer adding the PCIe controller by
default. But in practice I don't think it will really affect anyone, since
there isn't really any OS support for virtio-pci yet, and no apps support it
either AFAIK.
- The PCIe controller is not strictly about virtio-pci, it's for enabling
plain emulated PCI devices as well. So there is a use case for using the PCIe
controller for a graphics card even while your OS doesn't yet support
virtio-pci. In the big picture though this is a small time window with current
OS, and users can work around it by manually requesting <address
type='virtio-mmio'/>, so medium/long term this isn't a big deal IMO
- The PCIe controller XML is:
<controller type='pci' index='0' model='pcie-root'/>
<controller type='pci' index='1' model='dmi-to-pci-bridge'/>
<controller type='pci' index='2' model='pci-bridge'/>
I have no idea if that's always going to be the expected XML, maybe it's not
wise to hardcode that in apps. Laine?
* Next idea: Users specify something like like <address type='pci'/> and
libvirt fills in the address for us.
Upsides:
- We can stick with the current PCIe controller default and avoid some of the
problems mentioned above.
- An auto address feature may be useful in other contexts as well.
Downsides:
- Seems potentially tricky to implement in libvirt code. There's many places
that check type=pci and key off that, seems like it would be easy to miss
updating a check and cause regressions. Maybe we could add a new type like
auto-pci to make it explicit. There's probably some implementation trick to
make this safe, but at first glance it looked a little dicey.
- Doesn't really solve problem #2 mentioned up above... maybe we could change
the address allocation logic to default to virtio-pci if there's already a
virtio-pci device in the XML. But it's more work.
- More work for apps, but nothing horrible.
* Change the default address type from virtio-mmio to pci, if qemu supports
it. I'm listing this for completeness. In the short term this doesn't make
sense as there isn't any OS releases that will work with this default. However
it might be worth considering for the future, maybe keying off a particular
qemu version or machine type. I suspect 2 years from now no one is going to be
using virtio-mmio so long term it's not an ideal default.
I think the first option is best (keying off the PCIe controller specified by
the user), with a longer term plan to change the default from mmio to pci. But
I'm not really sold on anything either way. So I'm interested if anyone else
has ideas.
Thanks,
Cole
9 years, 3 months
[libvirt] [PATCH] util: Fixup virnetdevmacvlan.h ATTRIBUTE_NONNULL's
by John Ferlan
Commit id '56e2171c6' removed a variable from the argument list, but
neglected to update the ATTRIBUTE_NONNULL values, so when commit id
'08da97bfb' added a couple of arguments, the values were off.
Signed-off-by: John Ferlan <jferlan(a)redhat.com>
---
Pushed as build breaker (coverity) and trivial.
src/util/virnetdevmacvlan.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/util/virnetdevmacvlan.h b/src/util/virnetdevmacvlan.h
index 2844a44..70e3b01 100644
--- a/src/util/virnetdevmacvlan.h
+++ b/src/util/virnetdevmacvlan.h
@@ -74,8 +74,8 @@ int virNetDevMacVLanCreateWithVPortProfile(const char *ifname,
int *tapfd,
size_t tapfdSize,
unsigned int flags)
- ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(6)
- ATTRIBUTE_NONNULL(8) ATTRIBUTE_NONNULL(12) ATTRIBUTE_RETURN_CHECK;
+ ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(5)
+ ATTRIBUTE_NONNULL(7) ATTRIBUTE_NONNULL(9) ATTRIBUTE_RETURN_CHECK;
int virNetDevMacVLanDeleteWithVPortProfile(const char *ifname,
const virMacAddr *macaddress,
--
2.5.0
9 years, 3 months
[libvirt] [PATCH v2 00/10] Make loading domains with invalid XML possible
by Martin Kletzander
We always had to deal with new parsing errors in a weird way. All of
them needed to go into functions starting the domains. That messes up
the code, it's confusing to newcomers and so on.
I once had an idea that we can handle this stuff. We know what
failed, we have the XML that failed parsing and if the problem is not
in the domain name nor UUID, we can create a domain object out of that
as well. This way we are able to do something we weren't with this
series applied. Example follows.
Assume "dummy" is a domain with invalid XML (I just modified the
file). Now, just for the purpose of this silly example, let's say we
allowed domains with archtecture x86_*, but now we've realized that
x86_64 is the only one we want to allow, but there already is a domain
defined that has <type arch='x86_256' .../>. With the current master,
the domain would be lost, so we would need to modify the funstion
starting the domain (e.g. qemuProcessStart for qemu domain). However,
with this series, it behaves like this:
# virsh list --all --reason
Id Name State Reason
---------------------------------------------------------------
- dummy shut off invalid XML
# virsh domstate --reason dummy
shut off (invalid XML)
# virsh start dummy
error: Failed to start domain dummy
error: XML error: domain 'dummy' was not loaded due to an XML error
(unsupported configuration: Unknown architecture x86_256), please
redefine it
# VISUAL='sed -i s/x86_256/x86_64/' virsh edit dummy
Domain dummy XML configuration edited.
# virsh domstate --reason dummy
shut off (unknown)
# virsh start dummy
Domain dummy started
This is a logical next step for us to clean and separate parsing and
starting, getting rid of some old code without sacrifying compatibility
and maybe generating parser code in the future.
v2:
- rebased on top of current master (with virdomainobjlist.c)
- only disallow starting domains with invalid definitions (change
done in v1), but allow re-defining them
- add support for "virsh list --reason" to better excercise the
feature added in this patchset
v1:
- rebase
- don't allow starting domains with invalid state
- https://www.redhat.com/archives/libvir-list/2015-November/msg01127.html
RFC: https://www.redhat.com/archives/libvir-list/2015-September/msg00698.html
Martin Kletzander (10):
conf, virsh: Add new domain shutoff reason
virsh: Refactor the table output of the list command
virsh: Add support for list -reason
qemu: Few whitespace cleanups
conf: Extract name-parsing into its own function
conf: Extract UUID parsing into its own function
conf: Optionally keep domains with invalid XML, but don't allow
starting them
qemu: Don't lookup invalid domains unless specified otherwise
qemu: Prepare basic APIs to handle invalid defs
qemu: Load domains with invalid XML on start
include/libvirt/libvirt-domain.h | 2 +
src/bhyve/bhyve_driver.c | 2 +
src/conf/domain_conf.c | 121 +++++++++++++++++++++++++++++++--------
src/conf/domain_conf.h | 7 +++
src/conf/virdomainobjlist.c | 71 +++++++++++++++++++++--
src/conf/virdomainobjlist.h | 1 +
src/libvirt_private.syms | 1 +
src/libxl/libxl_driver.c | 3 +
src/lxc/lxc_driver.c | 3 +
src/qemu/qemu_driver.c | 64 +++++++++++++++++----
src/uml/uml_driver.c | 2 +
tests/virshtest.c | 30 +++++++---
tools/virsh-domain-monitor.c | 60 ++++++++++++-------
tools/virsh.pod | 5 +-
14 files changed, 303 insertions(+), 69 deletions(-)
--
2.6.3
9 years, 3 months
[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, 3 months
[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, 3 months
[libvirt] [PATCH] test: qemuxml2argv: Mock virMemoryMaxValue to remove 32/64 bit difference
by Peter Krempa
Always return LLONG_MAX even on 32 bit systems. The limitation
originates from our use of "unsigned long" in several APIs. The internal
data type is unsigned long long. Make the test suite deterministic by
removing the architecture difference.
Flaw was introduced in 645881139b3d2c86acf9d644c3a1471520bc9e57 where
I've added a test that uses too large numbers.
---
I've tested this by changing the mock value to the number returned on 32-bit
systems and got the same error. I didn't test it on an actual 32 bit system
though.
src/util/virutil.c | 2 ++
tests/qemuxml2argvmock.c | 10 ++++++++++
2 files changed, 12 insertions(+)
diff --git a/src/util/virutil.c b/src/util/virutil.c
index fe65faf..9d56d66 100644
--- a/src/util/virutil.c
+++ b/src/util/virutil.c
@@ -2639,6 +2639,8 @@ virMemoryLimitIsSet(unsigned long long value)
* @capped: whether the value must fit into unsigned long
* (long long is assumed otherwise)
*
+ * Note: This function is mocked in tests/qemuxml2argvmock.c for test stability
+ *
* Returns the maximum possible memory value in bytes.
*/
unsigned long long
diff --git a/tests/qemuxml2argvmock.c b/tests/qemuxml2argvmock.c
index e58b8ce..8426108 100644
--- a/tests/qemuxml2argvmock.c
+++ b/tests/qemuxml2argvmock.c
@@ -74,3 +74,13 @@ virTPMCreateCancelPath(const char *devpath)
return path;
}
+
+/**
+ * Large values for memory would fail on 32 bit systems, despite having
+ * variables that support it.
+ */
+unsigned long long
+virMemoryMaxValue(bool capped ATTRIBUTE_UNUSED)
+{
+ return LLONG_MAX;
+}
--
2.6.2
9 years, 3 months
[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, 3 months
[libvirt] [PATCH 0/7] cleanup the input device code
by Pavel Hrdina
This patch series is an attempt to make the code for input devices cleaner and
readable and also follow some good practices whit rule that one function should
do only one thing. We are really bad at this and our code is sometimes really
hard to follow.
Pavel Hrdina (7):
vmware/vmx: use virDomainDefPostParse after parsing vmx config
lxc: use virDomainDefPostParse for parsing LXC config string
xen: use virDomainDefPostParse for parsing XM/XL/SEXPR cofings
xen: fix timer bug found by updated test
libxl: copy persistent domain definition while starting a guest
device: cleanup input device code
qemu_domain: cleanup default input device code
src/Makefile.am | 2 +-
src/conf/domain_conf.c | 77 +---------------------
src/esx/esx_driver.c | 4 +-
src/libxl/libxl_domain.c | 8 +++
src/libxl/libxl_driver.c | 8 ++-
src/lxc/lxc_driver.c | 5 +-
src/lxc/lxc_native.c | 8 ++-
src/lxc/lxc_native.h | 4 +-
src/qemu/qemu_domain.c | 47 ++++++++-----
src/qemu/qemu_domain.h | 1 +
src/qemu/qemu_process.c | 3 +
src/vmware/vmware_conf.c | 3 +-
src/vmware/vmware_driver.c | 2 +-
src/vmx/vmx.c | 5 ++
src/vmx/vmx.h | 1 +
src/xen/xen_driver.c | 5 +-
src/xen/xend_internal.c | 10 +++
src/xen/xm_internal.c | 2 +-
src/xenapi/xenapi_driver.c | 8 +++
src/xenconfig/xen_common.c | 24 +++++++
src/xenconfig/xen_common.h | 2 +
src/xenconfig/xen_sxpr.c | 18 ++++-
src/xenconfig/xen_sxpr.h | 8 ++-
src/xenconfig/xen_xl.c | 9 ++-
src/xenconfig/xen_xl.h | 4 +-
src/xenconfig/xen_xm.c | 7 +-
src/xenconfig/xen_xm.h | 2 +-
tests/Makefile.am | 2 +-
tests/lxcconf2xmldata/lxcconf2xml-blkiotune.xml | 3 +-
tests/lxcconf2xmldata/lxcconf2xml-cpusettune.xml | 3 +-
tests/lxcconf2xmldata/lxcconf2xml-cputune.xml | 3 +-
tests/lxcconf2xmldata/lxcconf2xml-idmap.xml | 3 +-
.../lxcconf2xmldata/lxcconf2xml-macvlannetwork.xml | 3 +-
tests/lxcconf2xmldata/lxcconf2xml-memtune.xml | 3 +-
tests/lxcconf2xmldata/lxcconf2xml-nonenetwork.xml | 3 +-
tests/lxcconf2xmldata/lxcconf2xml-nonetwork.xml | 3 +-
tests/lxcconf2xmldata/lxcconf2xml-physnetwork.xml | 3 +-
tests/lxcconf2xmldata/lxcconf2xml-simple.xml | 3 +-
tests/lxcconf2xmldata/lxcconf2xml-vlannetwork.xml | 3 +-
tests/lxcconf2xmltest.c | 18 ++++-
.../qemuxml2argv-graphics-listen-network.xml | 2 -
.../qemuxml2argv-graphics-listen-network2.xml | 2 -
.../qemuxml2argv-graphics-sdl-fullscreen.xml | 2 -
.../qemuxml2argvdata/qemuxml2argv-graphics-sdl.xml | 2 -
...qemuxml2argv-graphics-spice-agent-file-xfer.xml | 1 -
.../qemuxml2argv-graphics-spice-compression.xml | 2 -
.../qemuxml2argv-graphics-spice-listen-network.xml | 1 -
.../qemuxml2argv-graphics-spice-qxl-vga.xml | 2 -
.../qemuxml2argv-graphics-spice-sasl.xml | 1 -
.../qemuxml2argv-graphics-spice-timeout.xml | 2 -
.../qemuxml2argv-graphics-spice.xml | 2 -
.../qemuxml2argv-graphics-vnc-policy.xml | 2 -
.../qemuxml2argv-graphics-vnc-sasl.xml | 2 -
.../qemuxml2argv-graphics-vnc-socket.xml | 2 -
.../qemuxml2argv-graphics-vnc-tls.xml | 2 -
.../qemuxml2argv-graphics-vnc-websocket.xml | 2 -
.../qemuxml2argvdata/qemuxml2argv-graphics-vnc.xml | 2 -
.../qemuxml2argv-pci-autoadd-addr.xml | 1 -
.../qemuxml2argv-pci-autoadd-idx.xml | 1 -
.../qemuxml2argvdata/qemuxml2argv-pseries-disk.xml | 2 +-
.../qemuxml2xmlout-graphics-listen-network2.xml | 2 -
.../qemuxml2xmlout-graphics-spice-timeout.xml | 2 -
tests/sexpr2xmldata/sexpr2xml-boot-grub.xml | 1 +
tests/sexpr2xmldata/sexpr2xml-bridge-ipaddr.xml | 1 +
tests/sexpr2xmldata/sexpr2xml-curmem.xml | 3 +-
.../sexpr2xml-disk-block-shareable.xml | 1 +
tests/sexpr2xmldata/sexpr2xml-disk-block.xml | 1 +
.../sexpr2xml-disk-drv-blktap-qcow.xml | 1 +
.../sexpr2xml-disk-drv-blktap-raw.xml | 1 +
.../sexpr2xml-disk-drv-blktap2-raw.xml | 1 +
tests/sexpr2xmldata/sexpr2xml-disk-file.xml | 1 +
tests/sexpr2xmldata/sexpr2xml-fv-autoport.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-empty-kernel.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-force-hpet.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-force-nohpet.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-kernel.xml | 1 +
tests/sexpr2xmldata/sexpr2xml-fv-legacy-vfb.xml | 2 +
tests/sexpr2xmldata/sexpr2xml-fv-localtime.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-net-ioemu.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-net-netfront.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-parallel-tcp.xml | 5 +-
.../sexpr2xml-fv-serial-dev-2-ports.xml | 5 +-
.../sexpr2xml-fv-serial-dev-2nd-port.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-serial-file.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-serial-null.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-serial-pipe.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-serial-pty.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-serial-stdio.xml | 5 +-
.../sexpr2xml-fv-serial-tcp-telnet.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-serial-tcp.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-serial-udp.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-serial-unix.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-sound-all.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-sound.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-usbmouse.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-usbtablet.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-utc.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv-v2.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-fv.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-net-bridged.xml | 1 +
tests/sexpr2xmldata/sexpr2xml-net-e1000.xml | 1 +
tests/sexpr2xmldata/sexpr2xml-net-routed.xml | 1 +
tests/sexpr2xmldata/sexpr2xml-no-source-cdrom.xml | 5 +-
tests/sexpr2xmldata/sexpr2xml-pci-devs.xml | 1 +
.../sexpr2xml-pv-bootloader-cmdline.xml | 1 +
tests/sexpr2xmldata/sexpr2xml-pv-bootloader.xml | 1 +
tests/sexpr2xmldata/sexpr2xml-pv-localtime.xml | 1 +
tests/sexpr2xmldata/sexpr2xml-pv-vcpus.xml | 1 +
.../sexpr2xml-pv-vfb-new-vncdisplay.xml | 3 +-
tests/sexpr2xmldata/sexpr2xml-pv-vfb-new.xml | 3 +-
tests/sexpr2xmldata/sexpr2xml-pv-vfb-orig.xml | 3 +-
.../sexpr2xmldata/sexpr2xml-pv-vfb-type-crash.xml | 3 +-
tests/sexpr2xmldata/sexpr2xml-pv.xml | 1 +
tests/sexpr2xmltest.c | 10 ++-
tests/vmx2xmldata/vmx2xml-graphics-vnc.xml | 2 -
tests/vmx2xmltest.c | 2 +-
.../test-fullvirt-direct-kernel-boot.xml | 4 +-
tests/xlconfigdata/test-fullvirt-multiusb.xml | 4 +-
tests/xlconfigdata/test-new-disk.xml | 5 +-
tests/xlconfigdata/test-spice-features.xml | 4 +-
tests/xlconfigdata/test-spice.xml | 4 +-
tests/xlconfigtest.c | 2 +-
tests/xmconfigdata/test-escape-paths.xml | 6 +-
.../xmconfigdata/test-fullvirt-default-feature.xml | 5 +-
tests/xmconfigdata/test-fullvirt-force-hpet.xml | 5 +-
tests/xmconfigdata/test-fullvirt-force-nohpet.xml | 5 +-
tests/xmconfigdata/test-fullvirt-localtime.xml | 5 +-
tests/xmconfigdata/test-fullvirt-net-ioemu.xml | 5 +-
tests/xmconfigdata/test-fullvirt-net-netfront.xml | 5 +-
tests/xmconfigdata/test-fullvirt-new-cdrom.xml | 5 +-
tests/xmconfigdata/test-fullvirt-old-cdrom.xml | 5 +-
tests/xmconfigdata/test-fullvirt-parallel-tcp.xml | 5 +-
.../test-fullvirt-serial-dev-2-ports.xml | 5 +-
.../test-fullvirt-serial-dev-2nd-port.xml | 5 +-
tests/xmconfigdata/test-fullvirt-serial-file.xml | 5 +-
tests/xmconfigdata/test-fullvirt-serial-null.xml | 5 +-
tests/xmconfigdata/test-fullvirt-serial-pipe.xml | 5 +-
tests/xmconfigdata/test-fullvirt-serial-pty.xml | 5 +-
tests/xmconfigdata/test-fullvirt-serial-stdio.xml | 5 +-
.../test-fullvirt-serial-tcp-telnet.xml | 5 +-
tests/xmconfigdata/test-fullvirt-serial-tcp.xml | 5 +-
tests/xmconfigdata/test-fullvirt-serial-udp.xml | 5 +-
tests/xmconfigdata/test-fullvirt-serial-unix.xml | 5 +-
tests/xmconfigdata/test-fullvirt-sound.xml | 5 +-
tests/xmconfigdata/test-fullvirt-usbmouse.xml | 5 +-
.../test-fullvirt-usbtablet-no-bus.xml | 4 +-
tests/xmconfigdata/test-fullvirt-usbtablet.xml | 5 +-
tests/xmconfigdata/test-fullvirt-utc.xml | 5 +-
tests/xmconfigdata/test-no-source-cdrom.xml | 5 +-
tests/xmconfigdata/test-paravirt-net-e1000.xml | 3 +-
tests/xmconfigdata/test-paravirt-net-vifname.xml | 3 +-
.../test-paravirt-new-pvfb-vncdisplay.xml | 3 +-
tests/xmconfigdata/test-paravirt-new-pvfb.xml | 3 +-
.../test-paravirt-old-pvfb-vncdisplay.xml | 3 +-
tests/xmconfigdata/test-paravirt-old-pvfb.xml | 3 +-
tests/xmconfigdata/test-paravirt-vcpu.xml | 1 +
tests/xmconfigdata/test-pci-devs.xml | 5 +-
tests/xmconfigtest.c | 3 +-
158 files changed, 429 insertions(+), 309 deletions(-)
--
2.6.3
9 years, 3 months
[libvirt] [PATCH 0/7] tests: Always fake root directory
by Andrea Bolognani
When mocking filesystem access in the test suite, we have always
assumed it to be some subdirectory of /sys depending on the needs
of the specific test case.
This limits our flexibility, and will be a problem once we need
to start mocking eg. /dev as well, or simply two different parts
of the /sys filesystem at the same time[1].
Solve the issue by always using the temporary directory as the
root directory for the mocked filesystem.
The series is organized as follows:
1-2: Tiny cleanups
3-4: Change the mock libraries so that they build the proper
directory structure
5: Change the name of the environment variable used to pass
the temporary directory name to the mock libraries
6: Make it so we'll be able to mock different parts of the
/sys filesystem at the same time
7: Update scsihosttest to use the same directory structure
Cheers.
[1] https://www.redhat.com/archives/libvir-list/2015-November/msg00532.html
is an example of why we would need to do that
Andrea Bolognani (7):
tests: scsihost: Don't set LIBVIRT_FAKE_SYSFS_DIR
tests: pcimock: Remove check for fakesysfsdir
tests: pcimock: Use the temporary directory as fake root
tests: cgroupmock: Use the temporary directory as fake root
tests: Rename LIBVIRT_FAKE_SYSFS_DIR to LIBVIRT_FAKE_ROOT_DIR
tests: Use more specific names for variables
tests: scsihost: Use fakerootdir instead of fakesysfsdir
tests/scsihosttest.c | 17 ++++++---
tests/vircgroupmock.c | 99 ++++++++++++++++++++++++++++----------------------
tests/vircgrouptest.c | 16 ++++----
tests/virhostdevtest.c | 16 ++++----
tests/virpcimock.c | 69 +++++++++++++++++++----------------
tests/virpcitest.c | 16 ++++----
6 files changed, 129 insertions(+), 104 deletions(-)
--
2.5.0
9 years, 3 months