Implemented Jailhouse hypervisor APIs for cell load/start/shutdown/destroy. --- src/jailhouse/jailhouse_api.c | 100 ++++++++++++-- src/jailhouse/jailhouse_api.h | 29 +++++ src/jailhouse/jailhouse_driver.c | 217 +++++++++++++++++++++++++++++-- src/jailhouse/jailhouse_driver.h | 8 ++ 4 files changed, 335 insertions(+), 19 deletions(-) diff --git a/src/jailhouse/jailhouse_api.c b/src/jailhouse/jailhouse_api.c index cda00b50e7..783903e939 100644 --- a/src/jailhouse/jailhouse_api.c +++ b/src/jailhouse/jailhouse_api.c @@ -43,11 +43,14 @@ #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 MAX_JAILHOUSE_CELL_IMAGE_FILE_SIZE 64*1024*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_LOAD _IOW(0, 3, virJailhouseCellLoad) +#define JAILHOUSE_CELL_START _IOW(0, 4, virJailhouseCellId) #define JAILHOUSE_CELL_DESTROY _IOW(0, 5, virJailhouseCellId) #define VIR_FROM_THIS VIR_FROM_JAILHOUSE @@ -68,8 +71,6 @@ 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); @@ -254,7 +255,7 @@ readSysfsCellString(const unsigned int id, const char *entry) } int -getCellInfo(const unsigned int id, virJailhouseCellInfoPtr * cell_info_ptr) +getCellInfo(const unsigned int id, virJailhouseCellInfoPtr *cell_info_ptr) { char *tmp; @@ -345,28 +346,105 @@ getJailhouseCellsInfo(void) } int -destroyCell(virJailhouseCellId cell_id) +loadImagesInCell(virJailhouseCellId cell_id, char **images, int num_images) +{ + virJailhousePreloadImagePtr image; + virJailhouseCellLoadPtr cell_load; + g_autofree char *buffer = NULL; + unsigned int n; + int len = -1, err = -1; + VIR_AUTOCLOSE fd = -1; + + + if (VIR_ALLOC(cell_load) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Insufficient memory for cell load")); + return -1; + } + + + if (VIR_ALLOC_N(cell_load->image, num_images) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "%s", + _("Insufficient memory for cell load images")); + return -1; + } + + cell_load->id = cell_id; + cell_load->num_preload_images = num_images; + + for (n = 0, image = cell_load->image; n < num_images; n++, image++) { + len = virFileReadAll(images[n], MAX_JAILHOUSE_CELL_IMAGE_FILE_SIZE, &buffer); + if (len < 0 || !buffer) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Failed to read the image file %s"), + images[n]); + return -1; + } + + image->source_address = (unsigned long)buffer; + image->size = len; + + // TODO(Prakhar): Add support for target address. + image->target_address = 0; + } + + fd = openDev(); + + err = ioctl(fd, JAILHOUSE_CELL_LOAD, cell_load); + if (err) { + virReportSystemError(errno, + _("Loading cell images for %d failed"), + cell_id.id); + return -1; + } + + return 0; +} + +int +shutdownCell(virJailhouseCellId cell_id) +{ + // Loading 0 images in the cell causes cell to shutdown. + return loadImagesInCell(cell_id, NULL, 0); +} + +int +startCell(virJailhouseCellId cell_id) { int err = -1; VIR_AUTOCLOSE fd = -1; fd = openDev(); - err = ioctl(fd, JAILHOUSE_CELL_DESTROY, &cell_id); - if (err) + err = ioctl(fd, JAILHOUSE_CELL_START, &cell_id); + if (err) { virReportSystemError(errno, - _("Destroying cell %d failed"), + _("Start cell %d failed"), cell_id.id); + return -1; + } - return err; + return 0; } int -destroyJailhouseCells(virJailhouseCellInfoPtr *cell_info_list G_GNUC_UNUSED) +destroyCell(virJailhouseCellId cell_id) { + int err = -1; + VIR_AUTOCLOSE fd = -1; + + fd = openDev(); - /* Iterate over all cells in cell_info_list and destroy each cell */ - // TODO: Not implemented yet. + err = ioctl(fd, JAILHOUSE_CELL_DESTROY, &cell_id); + if (err) { + virReportSystemError(errno, + _("Destroying cell %d failed"), + cell_id.id); + + return -1; + } return 0; } diff --git a/src/jailhouse/jailhouse_api.h b/src/jailhouse/jailhouse_api.h index 8362cb3d0f..ba39a4c8b7 100644 --- a/src/jailhouse/jailhouse_api.h +++ b/src/jailhouse/jailhouse_api.h @@ -48,6 +48,27 @@ struct _virJailhouseCellCreate { __u32 padding; }; +typedef struct _virJailhousePreloadImage virJailhousePreloadImage; +typedef virJailhousePreloadImage *virJailhousePreloadImagePtr; + +struct _virJailhousePreloadImage { + __u64 source_address; + __u64 size; + __u64 target_address; + __u64 padding; +}; + +typedef struct _virJailhouseCellLoad virJailhouseCellLoad; +typedef virJailhouseCellLoad *virJailhouseCellLoadPtr; + +struct _virJailhouseCellLoad { + struct _virJailhouseCellId id; + __u32 num_preload_images; + __u32 padding; + struct _virJailhousePreloadImage image[]; +}; + + // Enables the Jailhouse hypervisor by reading the hypervisor system // configuration from the given file and calls the ioctl API to // enable the hypervisor. @@ -62,6 +83,14 @@ int jailhouseDisable(void); // provided in the dir_name. int createJailhouseCells(const char *dir_path); +int loadImagesInCell(virJailhouseCellId cell_id, char **images, int num_images); + +int startCell(virJailhouseCellId cell_id); + +int shutdownCell(virJailhouseCellId cell_id); + +int destroyCell(virJailhouseCellId cell_id); + // Destroys Jailhouse cells using the cell IDs provided in // the cell_info_list. int destroyJailhouseCells(virJailhouseCellInfoPtr *cell_info_list); diff --git a/src/jailhouse/jailhouse_driver.c b/src/jailhouse/jailhouse_driver.c index 75bf41fc11..5b7bdc92d8 100644 --- a/src/jailhouse/jailhouse_driver.c +++ b/src/jailhouse/jailhouse_driver.c @@ -25,7 +25,6 @@ #include "configmake.h" #include "datatypes.h" #include "domain_conf.h" -#include "jailhouse_driver.h" #include "virtypedparam.h" #include "virerror.h" #include "virstring.h" @@ -36,6 +35,9 @@ #include "vircommand.h" #include "virpidfile.h" #include "access/viraccessapicheck.h" +#include "virdomainobjlist.h" + +#include "jailhouse_driver.h" #define VIR_FROM_THIS VIR_FROM_JAILHOUSE @@ -62,7 +64,6 @@ virJailhouseDriverConfigNew(void) { virJailhouseDriverConfigPtr cfg; - // TODO: Check if the following has to be uncommented. if (virJailhouseConfigInitialize() < 0) return NULL; @@ -135,6 +136,7 @@ jailhouseFreeDriver(virJailhouseDriverPtr driver) return; virMutexDestroy(&driver->lock); + virObjectUnref(driver->domains); virObjectUnref(driver->config); VIR_FREE(driver); } @@ -207,6 +209,9 @@ jailhouseStateInitialize(bool privileged G_GNUC_UNUSED, return VIR_DRV_STATE_INIT_ERROR; } + if (!(jailhouse_driver->domains = virDomainObjListNew())) + goto error; + if (!(cfg = virJailhouseDriverConfigNew())) goto error; @@ -259,10 +264,11 @@ jailhouseConnectGetHostname(virConnectPtr conn) } static int -jailhouseNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) +jailhouseNodeGetInfo(virConnectPtr conn, + virNodeInfoPtr nodeinfo) { UNUSED(conn); - UNUSED(info); + UNUSED(nodeinfo); return -1; } @@ -300,11 +306,205 @@ jailhouseDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid) return NULL; } +static virDomainObjPtr +virJailhouseDomObjFromDomain(virDomainPtr domain) +{ + virDomainObjPtr cell; + virJailhouseDriverPtr driver = domain->conn->privateData; + char uuidstr[VIR_UUID_STRING_BUFLEN]; + + cell = virDomainObjListFindByUUID(driver->domains, domain->uuid); + if (!cell) { + virUUIDFormat(domain->uuid, uuidstr); + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s' (%s)"), + uuidstr, domain->name); + return NULL; + } + + return cell; +} + + + +static virJailhouseCellInfoPtr +virJailhouseFindCellByName(virJailhouseDriverPtr driver, + char* name) +{ + virJailhouseCellInfoPtr *cell = driver->cell_info_list; + + while (*cell) { + if (STRCASEEQ((*cell)->id.name, name)) + return *cell; + cell++; + } + + return NULL; +} + +static int +jailhouseDomainCreateWithFlags(virDomainPtr domain, + unsigned int flags) +{ + virJailhouseDriverPtr driver = domain->conn->privateData; + virDomainObjPtr cell; + virJailhouseCellInfoPtr cell_info; + int ret = -1; + + virCheckFlags(VIR_DOMAIN_NONE, -1); + + if (!domain->name) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Error while reading the domain name")); + goto cleanup; + } + + if (!domain->id) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Error while reading the domain ID")); + goto cleanup; + } + + if (!(cell = virJailhouseDomObjFromDomain(domain))) + goto cleanup; + + if (virDomainCreateWithFlagsEnsureACL(domain->conn, cell->def) < 0) + goto cleanup; + + if (!(cell_info = virJailhouseFindCellByName(driver, cell->def->name))) { + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching name %s and ID %d)"), + cell->def->name, cell->def->id); + virDomainObjListRemove(driver->domains, cell); + goto cleanup; + } + + ret = 0; + + cleanup: + virDomainObjEndAPI(&cell); + return ret; + +} + static int jailhouseDomainCreate(virDomainPtr domain) { - UNUSED(domain); - return -1; + return jailhouseDomainCreateWithFlags(domain, 0); +} + +static virDomainPtr +jailhouseDomainCreateXML(virConnectPtr conn, + const char *xml, + unsigned int flags) +{ + virJailhouseDriverPtr driver = conn->privateData; + virJailhouseCellInfoPtr cell_info; + virDomainPtr dom = NULL; + virDomainDefPtr def = NULL; + virDomainObjPtr cell = NULL; + virDomainDiskDefPtr disk = NULL; + virJailhouseCellId cell_id; + char **images = NULL; + int num_images = 0, i = 0; + unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE; + + if (flags & VIR_DOMAIN_START_VALIDATE) + parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA; + + if ((def = virDomainDefParseString(xml, NULL, + NULL, parse_flags)) == NULL) + goto cleanup; + + if ((cell = virDomainObjListFindByUUID(driver->domains, def->uuid))) + goto cleanup; + + if (virDomainCreateXMLEnsureACL(conn, def) < 0) + goto cleanup; + + if (!(cell_info = virJailhouseFindCellByName(driver, def->name))) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("cell info for %s not found"), + def->name); + goto cleanup; + } + + // Assign cell Id to the domain. + def->id = cell_info->id.id; + + if (!(cell = virDomainObjListAdd(driver->domains, def, + NULL, + VIR_DOMAIN_OBJ_LIST_ADD_LIVE | + VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE, NULL))) + goto cleanup; + + def = NULL; + + if (cell->def->ndisks < 1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Domain XML doesn't contain any disk images")); + goto cleanup; + } + + if (VIR_ALLOC_N(images, cell->def->ndisks) < 0) + goto cleanup; + + for (i = 0; i < cell->def->ndisks; ++i) { + images[i] = NULL; + + if (cell->def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK && + virDomainDiskGetType(cell->def->disks[i]) == VIR_STORAGE_TYPE_FILE) { + disk = cell->def->disks[i]; + const char *src = virDomainDiskGetSource(disk); + if (!src) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("First file-based harddisk has no source")); + goto cleanup; + } + + images[i] = (char *)src; + num_images++; + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("A Jailhouse doamin(cell) can ONLY have FILE type disks")); + goto cleanup; + } + } + + // Initialize the cell_id. + cell_id.id = cell->def->id; + cell_id.padding = 0; + if (virStrncpy(cell_id.name, cell->def->name, JAILHOUSE_CELL_ID_NAMELEN, JAILHOUSE_CELL_ID_NAMELEN) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Cell name %s length exceeded the limit"), + cell->def->name); + goto cleanup; + } + + if (loadImagesInCell(cell_id, images, num_images) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to load images in the Cell %s"), + cell->def->name); + goto cleanup; + } + + VIR_DEBUG("Starting the domain..."); + + if (startCell(cell_id) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to start the Cell %s"), + cell->def->name); + goto cleanup; + } + + virDomainObjSetState(cell, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED); + + dom = virGetDomain(conn, cell->def->name, cell->def->uuid, cell->def->id); + + cleanup: + virDomainDefFree(def); + virDomainObjEndAPI(&cell); + return dom; } static int @@ -314,7 +514,6 @@ jailhouseDomainShutdown(virDomainPtr domain) return -1; } - static int jailhouseDomainDestroy(virDomainPtr domain) { @@ -356,7 +555,9 @@ static virHypervisorDriver jailhouseHypervisorDriver = { .connectListAllDomains = jailhouseConnectListAllDomains, /* 6.3.0 */ .connectGetType = jailhouseConnectGetType, /* 6.3.0 */ .connectGetHostname = jailhouseConnectGetHostname, /* 6.3.0 */ - .domainCreate = jailhouseDomainCreate, /* 6.3.0 */ + .domainCreate = jailhouseDomainCreate, /*6.3.0 */ + .domainCreateWithFlags = jailhouseDomainCreateWithFlags, /* 6.3.0 */ + .domainCreateXML = jailhouseDomainCreateXML, /* 6.3.0 */ .domainShutdown = jailhouseDomainShutdown, /* 6.3.0 */ .domainDestroy = jailhouseDomainDestroy, /* 6.3.0 */ .domainGetInfo = jailhouseDomainGetInfo, /* 6.3.0 */ diff --git a/src/jailhouse/jailhouse_driver.h b/src/jailhouse/jailhouse_driver.h index 8a0e111676..8fc99fe7d2 100644 --- a/src/jailhouse/jailhouse_driver.h +++ b/src/jailhouse/jailhouse_driver.h @@ -22,7 +22,9 @@ #include <linux/types.h> +#include "domain_event.h" #include "jailhouse_api.h" +#include "virdomainobjlist.h" int jailhouseRegister(void); @@ -64,6 +66,12 @@ struct _virJailhouseDriver { // All the cells created during connect open on the hypervisor. virJailhouseCellInfoPtr *cell_info_list; + + // XML options for domain XMLs. + virDomainXMLOptionPtr xmlopt; + virDomainObjListPtr domains; + + virObjectEventStatePtr domainEventState; }; struct _jailhouseCell { -- 2.17.1