[GSoC PATCH 4/9] Jailhouse driver: Implementation of DomainCreate* callbacks

Prakhar Bansal itsprakhar at gmail.com
Mon Aug 31 08:21:24 UTC 2020


From: Prakhar Bansal <itsprakhar at gmail.com>

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




More information about the libvir-list mailing list