Implemented Jailhouse hypervisor APIs for cell
load/start/shutdown/destroy.
Signed-off-by:Prakhar Bansal<prakharbansal0910(a)gmail.com>
---
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