[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