[libvirt] [PATCH] hypervisor driver for Jailhouse
Christian Loehle
cloehle at linutronix.de
Tue Nov 10 14:46:26 UTC 2015
I'm sorry, I completely forgot the virCommandFree calls:
diff --git a/src/jailhouse/jailhouse_driver.c
b/src/jailhouse/jailhouse_driver.c
index 21acbba..9f1ed70 100644
--- a/src/jailhouse/jailhouse_driver.c
+++ b/src/jailhouse/jailhouse_driver.c
@@ -201,6 +201,7 @@ parseListOutput(virConnectPtr conn, struct
jailhouse_cell **parsedOutput)
i++; // skip \n
}
VIR_FREE(output);
+ virCommandFree(cmd);
return count;
error:
for (i = 0; i < count; i++) {
@@ -211,6 +212,7 @@ parseListOutput(virConnectPtr conn, struct
jailhouse_cell **parsedOutput)
*parsedOutput = NULL;
VIR_FREE(output);
output = NULL;
+ virCommandFree(cmd);
return -1;
}
@@ -323,17 +325,16 @@ jailhouseConnectOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Executing '%s --version' failed."),
conn->uri->path);
- VIR_FREE(output);
- return VIR_DRV_OPEN_ERROR;
+ goto 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;
+ goto error;
}
VIR_FREE(output);
+ virCommandFree(cmd);
struct jailhouse_driver *driver;
if (VIR_ALLOC(driver))
return VIR_DRV_OPEN_ERROR;
@@ -342,6 +343,10 @@ jailhouseConnectOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED
driver->lastQueryCellsCount = 0;
conn->privateData = driver;
return VIR_DRV_OPEN_SUCCESS;
+ error:
+ VIR_FREE(output);
+ virCommandFree(cmd);
+ return VIR_DRV_OPEN_ERROR;
}
static int
@@ -493,6 +498,7 @@ jailhouseDomainShutdown(virDomainPtr domain)
virCommandAddArg(cmd, buf);
virCommandAddEnvPassCommon(cmd);
int resultcode = virCommandRun(cmd, NULL);
+ virCommandFree(cmd);
if (resultcode < 0)
return -1;
return 0;
@@ -513,6 +519,7 @@ jailhouseDomainDestroy(virDomainPtr domain)
virCommandAddArg(cmd, buf);
virCommandAddEnvPassCommon(cmd);
int resultcode = virCommandRun(cmd, NULL);
+ virCommandFree(cmd);
if (resultcode < 0)
return -1;
return 0;
@@ -529,6 +536,7 @@ jailhouseDomainCreate(virDomainPtr domain)
virCommandAddArg(cmd, buf);
virCommandAddEnvPassCommon(cmd);
int resultcode = virCommandRun(cmd, NULL);
+ virCommandFree(cmd);
if (resultcode < 0)
return -1;
return 0;
On 11/10/2015 01:17 PM, Christian Loehle wrote:
> >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",
> )
>
>
>
> --
> libvir-list mailing list
> libvir-list at redhat.com
> https://www.redhat.com/mailman/listinfo/libvir-list
More information about the libvir-list
mailing list