From: Prakhar Bansal <prakharbansal0910@xxxxxxxxx> --- include/libvirt/virterror.h | 1 + po/POTFILES.in | 2 + src/jailhouse/Makefile.inc.am | 34 ++- src/jailhouse/jailhouse.conf | 10 + src/jailhouse/jailhouse_api.c | 372 ++++++++++++++++++++++++++++ src/jailhouse/jailhouse_api.h | 74 ++++++ src/jailhouse/jailhouse_driver.c | 302 +++++++++++++++++----- src/jailhouse/jailhouse_driver.h | 51 ++++ src/jailhouse/meson.build | 1 + src/libvirt.c | 10 - src/remote/remote_daemon.c | 4 + src/remote/remote_daemon_dispatch.c | 3 +- 12 files changed, 783 insertions(+), 81 deletions(-) create mode 100644 src/jailhouse/jailhouse.conf create mode 100644 src/jailhouse/jailhouse_api.c create mode 100644 src/jailhouse/jailhouse_api.h diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 97f2ac16d8..9f1bca2684 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -137,6 +137,7 @@ typedef enum { VIR_FROM_TPM = 70, /* Error from TPM */ VIR_FROM_BPF = 71, /* Error from BPF code */ VIR_FROM_JAILHOUSE = 72, /* Error from Jailhouse driver */ + # ifdef VIR_ENUM_SENTINELS VIR_ERR_DOMAIN_LAST # endif diff --git a/po/POTFILES.in b/po/POTFILES.in index 471af30b89..317db58a21 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -85,6 +85,8 @@ @SRCDIR@src/interface/interface_backend_netcf.c @SRCDIR@src/interface/interface_backend_udev.c @SRCDIR@src/internal.h +@SRCDIR@src/jailhouse/jailhouse_api.c +@SRCDIR@src/jailhouse/jailhouse_driver.c @SRCDIR@src/libvirt-domain-checkpoint.c @SRCDIR@src/libvirt-domain-snapshot.c @SRCDIR@src/libvirt-domain.c diff --git a/src/jailhouse/Makefile.inc.am b/src/jailhouse/Makefile.inc.am index 02822b2ea1..324c3b1b16 100644 --- a/src/jailhouse/Makefile.inc.am +++ b/src/jailhouse/Makefile.inc.am @@ -1,8 +1,11 @@ # vim: filetype=automake + JAILHOUSE_DRIVER_SOURCES = \ jailhouse/jailhouse_driver.c \ jailhouse/jailhouse_driver.h \ + jailhouse/jailhouse_api.c \ + jailhouse/jailhouse_api.h \ $(NULL) @@ -11,11 +14,34 @@ DRIVER_SOURCE_FILES += $(addprefix $(srcdir)/,$(JAILHOUSE_DRIVER_SOURCES)) EXTRA_DIST += $(JAILHOUSE_DRIVER_SOURCES) if WITH_JAILHOUSE -noinst_LTLIBRARIES += libvirt_driver_jailhouse.la -libvirt_la_BUILT_LIBADD += libvirt_driver_jailhouse.la -libvirt_driver_jailhouse_la_CFLAGS = \ + +noinst_LTLIBRARIES += libvirt_driver_jailhouse_impl.la +libvirt_driver_jailhouse_la_SOURCES = +libvirt_driver_jailhouse_la_LIBADD = \ + libvirt_driver_jailhouse_impl.la \ + libvirt.la \ + $(GLIB_LIBS) \ + $(NULL) +mod_LTLIBRARIES += libvirt_driver_jailhouse.la +libvirt_driver_jailhouse_la_LDFLAGS = $(AM_LDFLAGS_MOD_NOUNDEF) + +libvirt_driver_jailhouse_impl_la_CFLAGS = \ -I$(srcdir)/conf \ $(AM_CFLAGS) \ $(NULL) -libvirt_driver_jailhouse_la_SOURCES = $(JAILHOUSE_DRIVER_SOURCES) +libvirt_driver_jailhouse_impl_la_SOURCES = \ + $(JAILHOUSE_DRIVER_SOURCES) + +sbin_PROGRAMS += virtjailhoused + +virtjailhoused_SOURCES = $(REMOTE_DAEMON_SOURCES) +nodist_virtjailhoused_SOURCES = $(REMOTE_DAEMON_GENERATED) +virtjailhoused_CFLAGS = \ + $(REMOTE_DAEMON_CFLAGS) \ + -DDAEMON_NAME="\"virtjailhoused\"" \ + -DMODULE_NAME="\"jailhouse\"" \ + $(NULL) +virtjailhoused_LDFLAGS = $(REMOTE_DAEMON_LD_FLAGS) +virtjailhoused_LDADD = $(REMOTE_DAEMON_LD_ADD) + endif WITH_JAILHOUSE diff --git a/src/jailhouse/jailhouse.conf b/src/jailhouse/jailhouse.conf new file mode 100644 index 0000000000..587068b9d0 --- /dev/null +++ b/src/jailhouse/jailhouse.conf @@ -0,0 +1,10 @@ +# Configuration for the Jailhouse driver. + +# Jailhouse system configuration file to enable the Jailhouse hypervisor on the +# system. This is a required configuration parameter for the driver. +#system_config = "/etc/libvirt/jailhouse/qemu-x86.cell" + +# Specify a directory which contains all the non-root cell configurations which +# should be created by the driver at the startup. This is optional. Default +# value of "/etc/libvirt/jailhouse/cells/" will be used if left empty. +#non_root_cells_dir = "/etc/libvirt/jailhouse/cells/" diff --git a/src/jailhouse/jailhouse_api.c b/src/jailhouse/jailhouse_api.c new file mode 100644 index 0000000000..cda00b50e7 --- /dev/null +++ b/src/jailhouse/jailhouse_api.c @@ -0,0 +1,372 @@ +/* + * jailhouse_api.c: Jailhouse API + * + * Copyright (C) 2020 Prakhar Bansal + * + * 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/>. + * + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dirent.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <linux/types.h> + +#include "viralloc.h" +#include "virerror.h" +#include "virfile.h" +#include "virlog.h" +#include "virstring.h" +#include "jailhouse_api.h" + +#define JAILHOUSE_DEVICE "/dev/jailhouse" +#define JAILHOUSE_CELLS "/sys/devices/jailhouse/cells" +#define MAX_JAILHOUSE_SYS_CONFIG_FILE_SIZE 1024*1024 +#define MAX_JAILHOUSE_CELL_CONFIG_FILE_SIZE 1024 + + +#define JAILHOUSE_ENABLE _IOW(0, 0, void *) +#define JAILHOUSE_DISABLE _IO(0, 1) +#define JAILHOUSE_CELL_CREATE _IOW(0, 2, virJailhouseCellCreate) +#define JAILHOUSE_CELL_DESTROY _IOW(0, 5, virJailhouseCellId) + +#define VIR_FROM_THIS VIR_FROM_JAILHOUSE + +VIR_LOG_INIT("jailhouse.jailhouse_api"); + +#define JAILHOUSE_CELL_FILE_EXTENSION ".cell" + +/* Forward declarations */ + +/* Open the Jailhouse device for ioctl APIs */ +int openDev(void); + +/* Reads cell's property given by 'entry' using sysfs API */ +char *readSysfsCellString(const unsigned int id, const char *entry); + +int cell_match(const struct dirent *dirent); + +int createCell(const char *conf_file); + +int destroyCell(virJailhouseCellId cell_id); + +int getCellInfo(const unsigned int id, + virJailhouseCellInfoPtr * cell_info); + +int +jailhouseEnable(const char *sys_conf_file_path) +{ + int err = -1, len; + g_autofree char *buffer = NULL; + VIR_AUTOCLOSE fd = -1; + + if (!virFileExists(sys_conf_file_path)) + return 0; + + len = virFileReadAll(sys_conf_file_path, MAX_JAILHOUSE_SYS_CONFIG_FILE_SIZE, &buffer); + if (len < 0 || !buffer) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("Failed to read the system configuration file")); + return -1; + } + + fd = openDev(); + + err = ioctl(fd, JAILHOUSE_ENABLE, buffer); + if (err) { + virReportSystemError(errno, "%s", _("Failed to enable jailhouse")); + return err; + } + + VIR_DEBUG("Jailhouse hypervisor is enabled"); + + return 1; +} + +int +jailhouseDisable(void) +{ + int err = -1; + VIR_AUTOCLOSE fd = -1; + + fd = openDev(); + + err = ioctl(fd, JAILHOUSE_DISABLE); + if (err) + virReportSystemError(errno, + "%s", + _("Failed to disable jailhouse: %s")); + + VIR_DEBUG("Jailhouse hypervisor is disabled"); + + return err; +} + +int +cell_match(const struct dirent *dirent) +{ + char *ext = strrchr(dirent->d_name, '.'); + + return dirent->d_name[0] != '.' + && (STREQ(ext, JAILHOUSE_CELL_FILE_EXTENSION) == 0); +} + +int +createJailhouseCells(const char *dir_path) +{ + + struct dirent **namelist; + int num_entries, ret = -1; + size_t i; + + if (strlen(dir_path) == 0) + return ret; + + num_entries = scandir(dir_path, &namelist, cell_match, alphasort); + if (num_entries == -1) { + if (errno == ENOENT) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("No cells found in %s, scandir failed."), + dir_path); + goto fail; + } + + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Error reading cell configurations in %s."), + dir_path); + goto fail; + } + + + for (i = 0; i < num_entries; i++) { + g_autofree char *file_path = g_strdup_printf("%s/%s", dir_path, namelist[i]->d_name); + + if (createCell(file_path) != 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Cell creation failed with conf found in %s."), + namelist[i]->d_name); + goto fail; + } + } + + ret = 0; + + fail: + VIR_FREE(namelist); + return ret; +} + +int +openDev(void) +{ + int fd; + + fd = open(JAILHOUSE_DEVICE, O_RDWR); + if (fd < 0) { + virReportSystemError(errno, + _("Error opening jailhouse device %s"), + JAILHOUSE_DEVICE); + } + return fd; +} + +int +createCell(const char *conf_file) +{ + virJailhouseCellCreate cell_create; + int err = -1, len; + g_autofree char *buffer = NULL; + VIR_AUTOCLOSE fd = -1; + + if (strlen(conf_file) == 0) + return err; + + len = virFileReadAll(conf_file, MAX_JAILHOUSE_CELL_CONFIG_FILE_SIZE, &buffer); + if (len < 0 || !buffer) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("Failed to read the system configuration file")); + return err; + } + + cell_create.config_address = (unsigned long) buffer; + cell_create.config_size = len; + + fd = openDev(); + + err = ioctl(fd, JAILHOUSE_CELL_CREATE, &cell_create); + if (err) + virReportSystemError(errno, + "%s", + _("Cell creation failed: %s")); + + return err; +} + +void +cellInfoFree(virJailhouseCellInfoPtr cell_info) +{ + VIR_FREE(cell_info->state); + VIR_FREE(cell_info->cpus_assigned_list); + VIR_FREE(cell_info->cpus_failed_list); + VIR_FREE(cell_info); +} + +char * +readSysfsCellString(const unsigned int id, const char *entry) +{ + g_autofree char *buffer = NULL; + g_autofree char *file_path = NULL; + int len = -1; + + file_path = g_strdup_printf(JAILHOUSE_CELLS "%u/%s", id, entry); + + len = virFileReadAll(file_path, 1024, &buffer); + if (len < 0 || !buffer) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Error reading cell(%u) %s from %s failed"), + id, entry, file_path); + return NULL; + } + + virTrimSpaces(buffer, NULL); + + return buffer; +} + +int +getCellInfo(const unsigned int id, virJailhouseCellInfoPtr * cell_info_ptr) +{ + char *tmp; + + if (VIR_ALLOC(*cell_info_ptr) < 0) + return -1; + + virJailhouseCellInfoPtr cell_info = *cell_info_ptr; + + /* set cell id */ + cell_info->id.id = id; + + /* get cell name */ + tmp = readSysfsCellString(id, "name"); + if (virStrncpy(cell_info->id.name, tmp, JAILHOUSE_CELL_ID_NAMELEN, JAILHOUSE_CELL_ID_NAMELEN) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Cell ID %s too long to be copied to the cell info"), + tmp); + return -1; + } + + cell_info->id.name[JAILHOUSE_CELL_ID_NAMELEN] = 0; + VIR_FREE(tmp); + + /* get cell state */ + cell_info->state = readSysfsCellString(id, "state"); + + /* get assigned cpu list */ + cell_info->cpus_assigned_list = + readSysfsCellString(id, "cpus_assigned_list"); + + /* get failed cpu list */ + cell_info->cpus_failed_list = + readSysfsCellString(id, "cpus_failed_list"); + + return 0; +} + +virJailhouseCellInfoPtr * +getJailhouseCellsInfo(void) +{ + struct dirent **namelist; + virJailhouseCellInfoPtr *cell_info_list; + unsigned int id; + int num_entries; + size_t i; + + num_entries = + scandir(JAILHOUSE_CELLS, &namelist, cell_match, alphasort); + if (num_entries == -1) { + if (errno == ENOENT) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("No cells found in %s, scandir failed."), + JAILHOUSE_CELLS); + return NULL; + } + + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Error reading cell IDs in %s."), + JAILHOUSE_CELLS); + return NULL; + } + + /* Allocate memory for 1 more than num_entries and make the last entry NULL. */ + if (VIR_ALLOC_N(cell_info_list, num_entries + 1) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Insufficient memory for cells info list")); + } + + /* Set the last entry to NULL. */ + cell_info_list[num_entries] = NULL; + + for (i = 0; i < num_entries; i++) { + if (virStrToLong_ui(namelist[i]->d_name, NULL, 10, &id) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Cell ID %s could not be converted to a long"), + namelist[i]->d_name); + continue; + } + + /* get the cell's information(name, state etc.) using sysfs */ + getCellInfo(id, &cell_info_list[i]); + VIR_FREE(namelist[i]); + } + + VIR_FREE(namelist); + return cell_info_list; +} + +int +destroyCell(virJailhouseCellId cell_id) +{ + int err = -1; + VIR_AUTOCLOSE fd = -1; + + fd = openDev(); + + err = ioctl(fd, JAILHOUSE_CELL_DESTROY, &cell_id); + if (err) + virReportSystemError(errno, + _("Destroying cell %d failed"), + cell_id.id); + + return err; +} + +int +destroyJailhouseCells(virJailhouseCellInfoPtr *cell_info_list G_GNUC_UNUSED) +{ + + /* Iterate over all cells in cell_info_list and destroy each cell */ + // TODO: Not implemented yet. + + return 0; +} diff --git a/src/jailhouse/jailhouse_api.h b/src/jailhouse/jailhouse_api.h new file mode 100644 index 0000000000..8362cb3d0f --- /dev/null +++ b/src/jailhouse/jailhouse_api.h @@ -0,0 +1,74 @@ +/* + * jailhouse_api.h: Jailhouse hypervisor API implementation + * + * Copyright (C) 2020 Prakhar Bansal + * + * 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/>. + */ + +#pragma once + +#define JAILHOUSE_CELL_ID_NAMELEN 31 + +typedef struct _virJailhouseCellId virJailhouseCellId; + +struct _virJailhouseCellId { + __s32 id; + __u32 padding; + char name[JAILHOUSE_CELL_ID_NAMELEN + 1]; +}; + +typedef struct _virJailhouseCellInfo virJailhouseCellInfo; +typedef virJailhouseCellInfo *virJailhouseCellInfoPtr; + +struct _virJailhouseCellInfo { + struct _virJailhouseCellId id; + char *state; + char *cpus_assigned_list; + char *cpus_failed_list; +}; + +typedef struct _virJailhouseCellCreate virJailhouseCellCreate; + +struct _virJailhouseCellCreate { + __u64 config_address; + __u32 config_size; + __u32 padding; +}; + +// Enables the Jailhouse hypervisor by reading the hypervisor system +// configuration from the given file and calls the ioctl API to +// enable the hypervisor. +int jailhouseEnable(const char *sys_conf_file_path); + +// Disables the Jailhouse hypervisor. +int jailhouseDisable(void); + +/* Cell API methods */ + +// Creates Jailhouse cells using the cells configurations +// provided in the dir_name. +int createJailhouseCells(const char *dir_path); + +// Destroys Jailhouse cells using the cell IDs provided in +// the cell_info_list. +int destroyJailhouseCells(virJailhouseCellInfoPtr *cell_info_list); + +// Returns cell's information in a null-terminated array of +// virJailhouseCellInfoPtr for all the Jailhouse cells. +virJailhouseCellInfoPtr *getJailhouseCellsInfo(void); + +// Free the cell info object. +void cellInfoFree(virJailhouseCellInfoPtr cell_info); diff --git a/src/jailhouse/jailhouse_driver.c b/src/jailhouse/jailhouse_driver.c index 0175ba771b..ac9da4c85d 100644 --- a/src/jailhouse/jailhouse_driver.c +++ b/src/jailhouse/jailhouse_driver.c @@ -16,43 +16,228 @@ * 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/>. + * */ #include <config.h> +#include <string.h> +#include "configmake.h" +#include "datatypes.h" +#include "domain_conf.h" #include "jailhouse_driver.h" #include "virtypedparam.h" #include "virerror.h" #include "virstring.h" #include "viralloc.h" -#include "domain_conf.h" #include "virfile.h" -#include "datatypes.h" +#include "virlog.h" #include "vircommand.h" -#include <string.h> +#include "virpidfile.h" -#define UNUSED(x) (void)(x) +#define VIR_FROM_THIS VIR_FROM_JAILHOUSE + +VIR_LOG_INIT("jailhouse.jailhouse_driver"); + +static virClassPtr virJailhouseDriverConfigClass; +static void virJailhouseDriverConfigDispose(void *obj); + +static virJailhouseDriverPtr jailhouse_driver; + +static int virJailhouseConfigOnceInit(void) +{ + if (!VIR_CLASS_NEW(virJailhouseDriverConfig, virClassForObject())) + return -1; + + return 0; +} + +VIR_ONCE_GLOBAL_INIT(virJailhouseConfig); + + +static virJailhouseDriverConfigPtr +virJailhouseDriverConfigNew(void) +{ + virJailhouseDriverConfigPtr cfg; + + // TODO: Check if the following has to be uncommented. + if (virJailhouseConfigInitialize() < 0) + return NULL; + + if (!(cfg = virObjectNew(virJailhouseDriverConfigClass))) + return NULL; + + cfg->stateDir = g_strdup(JAILHOUSE_STATE_DIR); + + cfg->sys_config_file_path = g_strdup(DATADIR "/jailhouse/system.cell"); + + cfg->cell_config_dir = g_strdup(DATADIR "/jailhouse/cells"); + + return cfg; +} + +static void virJailhouseDriverConfigDispose(void *obj) +{ + + virJailhouseDriverConfigPtr cfg = obj; + + VIR_FREE(cfg->stateDir); + VIR_FREE(cfg->sys_config_file_path); + VIR_FREE(cfg->cell_config_dir); +} + +static int +jailhouseLoadConf(virJailhouseDriverConfigPtr config) +{ + g_autoptr(virConf) conf = NULL; + + if (!virFileExists(JAILHOUSE_CONFIG_FILE)) + return 0; + + if (!(conf = virConfReadFile(JAILHOUSE_CONFIG_FILE, 0))) + return -1; + + if (virConfGetValueString(conf, "system_config", + &config->sys_config_file_path) < 0) + return -1; + + if (virConfGetValueString(conf, "non_root_cells_dir", + &config->cell_config_dir) < 0) + return -1; + + return 1; +} + +static int +jailhouseCreateAndLoadCells(virJailhouseDriverPtr driver) +{ + if (!driver->config || + !driver->config->cell_config_dir || + strlen(driver->config->cell_config_dir) == 0) + return -1; + + // Create all cells in the hypervisor. + if (createJailhouseCells(driver->config->cell_config_dir) < 0) + return -1; + + // Get all cells created above. + driver->cell_info_list = getJailhouseCellsInfo(); + + return 0; +} + +static void +jailhouseFreeDriver(virJailhouseDriverPtr driver) +{ + if (!driver) + return; + + virMutexDestroy(&driver->lock); + virObjectUnref(driver->config); + VIR_FREE(driver); +} static virDrvOpenStatus jailhouseConnectOpen(virConnectPtr conn, - virConnectAuthPtr auth, - virConfPtr conf, - unsigned int flags) + virConnectAuthPtr auth G_GNUC_UNUSED, + virConfPtr conf G_GNUC_UNUSED, unsigned int flags) { - UNUSED(conn); - UNUSED(auth); - UNUSED(conf); - UNUSED(flags); - return 0; + uid_t uid = geteuid(); + + virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); + + if (!virConnectValidateURIPath(conn->uri->path, "jailhouse", uid == 0)) + return VIR_DRV_OPEN_ERROR; + + if (!jailhouse_driver) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Jailhouse driver state is not initialized.")); + return VIR_DRV_OPEN_ERROR; + } + + conn->privateData = jailhouse_driver; + + return VIR_DRV_OPEN_SUCCESS; } +#define UNUSED(x) (void)(x) + static int jailhouseConnectClose(virConnectPtr conn) { - UNUSED(conn); + conn->privateData = NULL; + + return 0; +} + +static int +jailhouseStateCleanup(void) +{ + if (!jailhouse_driver) + return -1; + + if (jailhouse_driver->lockFD != -1) + virPidFileRelease(jailhouse_driver->config->stateDir, + "driver", jailhouse_driver->lockFD); + + virMutexDestroy(&jailhouse_driver->lock); + + jailhouseFreeDriver(jailhouse_driver); return 0; } +static int +jailhouseStateInitialize(bool privileged G_GNUC_UNUSED, + const char *root G_GNUC_UNUSED, + virStateInhibitCallback callback G_GNUC_UNUSED, + void *opaque G_GNUC_UNUSED) +{ + virJailhouseDriverConfigPtr cfg = NULL; + int rc; + + jailhouse_driver = g_new0(virJailhouseDriver, 1); + jailhouse_driver->lockFD = -1; + + if (virMutexInit(&jailhouse_driver->lock) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("cannot initialize mutex")); + VIR_FREE(jailhouse_driver); + return VIR_DRV_STATE_INIT_ERROR; + } + + if (!(cfg = virJailhouseDriverConfigNew())) + goto error; + + jailhouse_driver->config = cfg; + + if (jailhouseLoadConf(cfg) < 0) + goto error; + + if (virFileMakePath(cfg->stateDir) < 0) { + virReportSystemError(errno, _("Failed to create state dir %s"), + cfg->stateDir); + goto error; + } + + if ((jailhouse_driver->lockFD = virPidFileAcquire(cfg->stateDir, + "driver", false, getpid())) < 0) + goto error; + + if ((rc = jailhouseEnable(cfg->sys_config_file_path)) < 0) + goto error; + else if (rc == 0) + return VIR_DRV_STATE_INIT_SKIPPED; + + if (jailhouseCreateAndLoadCells(jailhouse_driver) < 0) + goto error; + + return VIR_DRV_STATE_INIT_COMPLETE; + + error: + jailhouseStateCleanup(); + return VIR_DRV_STATE_INIT_ERROR; + +} static const char * jailhouseConnectGetType(virConnectPtr conn) { @@ -69,36 +254,16 @@ jailhouseConnectGetHostname(virConnectPtr conn) } static int -jailhouseNodeGetInfo(virConnectPtr conn, - virNodeInfoPtr info) +jailhouseNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) { UNUSED(conn); UNUSED(info); return -1; } -static int -jailhouseConnectListDomains(virConnectPtr conn, - int *ids, - int maxids) -{ - UNUSED(conn); - UNUSED(ids); - UNUSED(maxids); - return -1; -} - -static int -jailhouseConnectNumOfDomains(virConnectPtr conn) -{ - UNUSED(conn); - return -1; -} - static int jailhouseConnectListAllDomains(virConnectPtr conn, - virDomainPtr **domain, - unsigned int flags) + virDomainPtr ** domain, unsigned int flags) { UNUSED(conn); UNUSED(domain); @@ -107,8 +272,7 @@ jailhouseConnectListAllDomains(virConnectPtr conn, } static virDomainPtr -jailhouseDomainLookupByID(virConnectPtr conn, - int id) +jailhouseDomainLookupByID(virConnectPtr conn, int id) { UNUSED(conn); UNUSED(id); @@ -116,8 +280,7 @@ jailhouseDomainLookupByID(virConnectPtr conn, } static virDomainPtr -jailhouseDomainLookupByName(virConnectPtr conn, - const char *name) +jailhouseDomainLookupByName(virConnectPtr conn, const char *name) { UNUSED(conn); UNUSED(name); @@ -125,8 +288,7 @@ jailhouseDomainLookupByName(virConnectPtr conn, } static virDomainPtr -jailhouseDomainLookupByUUID(virConnectPtr conn, - const unsigned char *uuid) +jailhouseDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid) { UNUSED(conn); UNUSED(uuid); @@ -157,8 +319,7 @@ jailhouseDomainDestroy(virDomainPtr domain) } static int -jailhouseDomainGetInfo(virDomainPtr domain, - virDomainInfoPtr info) +jailhouseDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) { UNUSED(domain); UNUSED(info); @@ -167,9 +328,7 @@ jailhouseDomainGetInfo(virDomainPtr domain, static int jailhouseDomainGetState(virDomainPtr domain, - int *state, - int *reason, - unsigned int flags) + int *state, int *reason, unsigned int flags) { UNUSED(domain); UNUSED(state); @@ -179,8 +338,7 @@ jailhouseDomainGetState(virDomainPtr domain, } static char * -jailhouseDomainGetXMLDesc(virDomainPtr domain, - unsigned int flags) +jailhouseDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) { UNUSED(domain); UNUSED(flags); @@ -189,31 +347,43 @@ jailhouseDomainGetXMLDesc(virDomainPtr domain, static virHypervisorDriver jailhouseHypervisorDriver = { .name = "JAILHOUSE", - .connectOpen = jailhouseConnectOpen, /* 6.3.0 */ - .connectClose = jailhouseConnectClose, /* 6.3.0 */ - .connectListDomains = jailhouseConnectListDomains, /* 6.3.0 */ - .connectNumOfDomains = jailhouseConnectNumOfDomains, /* 6.3.0 */ - .connectListAllDomains = jailhouseConnectListAllDomains, /* 6.3.0 */ - .domainLookupByID = jailhouseDomainLookupByID, /* 6.3.0 */ - .domainLookupByUUID = jailhouseDomainLookupByUUID, /* 6.3.0 */ - .domainLookupByName = jailhouseDomainLookupByName, /* 6.3.0 */ - .domainGetXMLDesc = jailhouseDomainGetXMLDesc, /* 6.3.0 */ - .domainCreate = jailhouseDomainCreate, /* 6.3.0 */ - .connectGetType = jailhouseConnectGetType, /* 6.3.0 */ - .connectGetHostname = jailhouseConnectGetHostname, /* 6.3.0 */ - .nodeGetInfo = jailhouseNodeGetInfo, /* 6.3.0 */ - .domainShutdown = jailhouseDomainShutdown, /* 6.3.0 */ - .domainDestroy = jailhouseDomainDestroy, /* 6.3.0 */ - .domainGetInfo = jailhouseDomainGetInfo, /* 6.3.0 */ - .domainGetState = jailhouseDomainGetState, /* 6.3.0 */ + .connectOpen = jailhouseConnectOpen, /* 6.3.0 */ + .connectClose = jailhouseConnectClose, /* 6.3.0 */ + .connectListAllDomains = jailhouseConnectListAllDomains, /* 6.3.0 */ + .domainLookupByID = jailhouseDomainLookupByID, /* 6.3.0 */ + .domainLookupByUUID = jailhouseDomainLookupByUUID, /* 6.3.0 */ + .domainLookupByName = jailhouseDomainLookupByName, /* 6.3.0 */ + .domainGetXMLDesc = jailhouseDomainGetXMLDesc, /* 6.3.0 */ + .domainCreate = jailhouseDomainCreate, /* 6.3.0 */ + .connectGetType = jailhouseConnectGetType, /* 6.3.0 */ + .connectGetHostname = jailhouseConnectGetHostname, /* 6.3.0 */ + .nodeGetInfo = jailhouseNodeGetInfo, /* 6.3.0 */ + .domainShutdown = jailhouseDomainShutdown, /* 6.3.0 */ + .domainDestroy = jailhouseDomainDestroy, /* 6.3.0 */ + .domainGetInfo = jailhouseDomainGetInfo, /* 6.3.0 */ + .domainGetState = jailhouseDomainGetState, /* 6.3.0 */ }; + static virConnectDriver jailhouseConnectDriver = { + .localOnly = true, + .uriSchemes = (const char *[]){ "jailhouse", NULL }, .hypervisorDriver = &jailhouseHypervisorDriver, }; + +static virStateDriver jailhouseStateDriver = { + .name = "JAILHOUSE", + .stateInitialize = jailhouseStateInitialize, + .stateCleanup = jailhouseStateCleanup, +}; + int jailhouseRegister(void) { - return virRegisterConnectDriver(&jailhouseConnectDriver, false); + if (virRegisterConnectDriver(&jailhouseConnectDriver, false) < 0) + return -1; + if (virRegisterStateDriver(&jailhouseStateDriver) < 0) + return -1; + return 0; } diff --git a/src/jailhouse/jailhouse_driver.h b/src/jailhouse/jailhouse_driver.h index b0dbc8d033..8a0e111676 100644 --- a/src/jailhouse/jailhouse_driver.h +++ b/src/jailhouse/jailhouse_driver.h @@ -20,4 +20,55 @@ #pragma once +#include <linux/types.h> + +#include "jailhouse_api.h" + int jailhouseRegister(void); + +#define JAILHOUSE_CONFIG_FILE SYSCONFDIR "/libvirt/jailhouse/jailhouse.conf" +#define JAILHOUSE_STATE_DIR RUNSTATEDIR "/libvirt/jailhouse" + +#define JAILHOUSE_DEV "/dev/jailhouse" + +#define JAILHOUSE_SYSFS_DEV "/sys/devices/jailhouse/" + +typedef struct _virJailhouseDriver virJailhouseDriver; +typedef virJailhouseDriver *virJailhouseDriverPtr; + +typedef struct _virJailhouseDriverConfig virJailhouseDriverConfig; +typedef virJailhouseDriverConfig *virJailhouseDriverConfigPtr; + +struct _virJailhouseDriverConfig { + virObject parent; + + char *stateDir; + + // File path of the jailhouse system configuration + // for jailhouse enable/disable. + char *sys_config_file_path; + + // Config directory where all jailhouse cell configurations + // are stored. + char *cell_config_dir; +}; + +struct _virJailhouseDriver { + virMutex lock; + + // Jailhouse configuration read from the jailhouse.conf + virJailhouseDriverConfigPtr config; + + /* pid file FD, ensures two copies of the driver can't use the same root */ + int lockFD; + + // All the cells created during connect open on the hypervisor. + virJailhouseCellInfoPtr *cell_info_list; +}; + +struct _jailhouseCell { + __s32 id; + char *state; + char *cpus_assigned_list; + char *cpus_failed_list; +}; diff --git a/src/jailhouse/meson.build b/src/jailhouse/meson.build index 45ceeecca3..a706985169 100644 --- a/src/jailhouse/meson.build +++ b/src/jailhouse/meson.build @@ -1,5 +1,6 @@ jailhouse_sources = files( 'jailhouse_driver.c', + 'jailhouse_api.c', ) driver_source_files += jailhouse_sources diff --git a/src/libvirt.c b/src/libvirt.c index 8a78cbcf3a..0748eb2352 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -75,9 +75,6 @@ #ifdef WITH_BHYVE # include "bhyve/bhyve_driver.h" #endif -#ifdef WITH_JAILHOUSE -# include "jailhouse/jailhouse_driver.h" -#endif #include "access/viraccessmanager.h" #define VIR_FROM_THIS VIR_FROM_NONE @@ -274,10 +271,6 @@ virGlobalInit(void) if (hypervRegister() == -1) goto error; #endif -#ifdef WITH_JAILHOUSE - if (jailhouseRegister() == -1) - goto error; -#endif #ifdef WITH_REMOTE if (remoteRegister() == -1) goto error; @@ -1052,9 +1045,6 @@ virConnectOpenInternal(const char *name, #endif #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, diff --git a/src/remote/remote_daemon.c b/src/remote/remote_daemon.c index 2ac4f6cd2e..cbfdebfd7a 100644 --- a/src/remote/remote_daemon.c +++ b/src/remote/remote_daemon.c @@ -145,6 +145,10 @@ static int daemonInitialize(void) if (virDriverLoadModule("interface", "interfaceRegister", false) < 0) return -1; # endif +# ifdef WITH_JAILHOUSE + if (virDriverLoadModule("jailhouse", "jailhouseRegister", false) < 0) + return -1; +# endif # ifdef WITH_SECRETS if (virDriverLoadModule("secret", "secretRegister", false) < 0) return -1; diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c index 53d17a8f4a..06d8fe6098 100644 --- a/src/remote/remote_daemon_dispatch.c +++ b/src/remote/remote_daemon_dispatch.c @@ -2115,7 +2115,8 @@ remoteDispatchConnectOpen(virNetServerPtr server G_GNUC_UNUSED, STREQ(type, "VBOX") || STREQ(type, "bhyve") || STREQ(type, "vz") || - STREQ(type, "Parallels")) { + STREQ(type, "Parallels") || + STREQ(type, "JAILHOUSE")) { VIR_DEBUG("Hypervisor driver found, setting URIs for secondary drivers"); if (getuid() == 0) { priv->interfaceURI = "interface:///system"; -- 2.26.2