[PATCH v4 4/7] qemu: tpm: Add support for storing private TPM-related data

Stefan Berger stefanb at linux.ibm.com
Mon Oct 24 10:28:45 UTC 2022


Add support for storing private TPM-related data. The first private data
will be related to the capability of the started swtpm indicating whether
it is capable of migration with a shared storage setup since that requires
support for certain command line flags that were only becoming available
in v0.8.

Signed-off-by: Stefan Berger <stefanb at linux.ibm.com>
---
 src/conf/domain_conf.c | 63 +++++++++++++++++++++++++++++++++---
 src/conf/domain_conf.h |  9 ++++++
 src/qemu/qemu_domain.c | 73 ++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_domain.h | 14 ++++++++
 4 files changed, 154 insertions(+), 5 deletions(-)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 7dba65cfeb..4178583950 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -3276,6 +3276,22 @@ void virDomainHostdevDefClear(virDomainHostdevDef *def)
     }
 }
 
+static virDomainTPMDef *
+virDomainTPMDefNew(virDomainXMLOption *xmlopt)
+{
+    virDomainTPMDef *def;
+
+    def = g_new0(virDomainTPMDef, 1);
+
+    if (xmlopt && xmlopt->privateData.tpmNew &&
+        !(def->privateData = xmlopt->privateData.tpmNew())) {
+        VIR_FREE(def);
+        return NULL;
+    }
+
+    return def;
+}
+
 void virDomainTPMDefFree(virDomainTPMDef *def)
 {
     if (!def)
@@ -3296,6 +3312,7 @@ void virDomainTPMDefFree(virDomainTPMDef *def)
     }
 
     virDomainDeviceInfoClear(&def->info);
+    virObjectUnref(def->privateData);
     g_free(def);
 }
 
@@ -10238,7 +10255,8 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt,
     g_autofree xmlNodePtr *nodes = NULL;
     int bank;
 
-    def = g_new0(virDomainTPMDef, 1);
+    if (!(def = virDomainTPMDefNew(xmlopt)))
+        return NULL;
 
     if (virXMLPropEnum(node, "model",
                        virDomainTPMModelTypeFromString,
@@ -10329,6 +10347,14 @@ virDomainTPMDefParseXML(virDomainXMLOption *xmlopt,
     if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt, &def->info, flags) < 0)
         goto error;
 
+    if (flags & VIR_DOMAIN_DEF_PARSE_STATUS &&
+        xmlopt && xmlopt->privateData.tpmParse) {
+        if ((ctxt->node = virXPathNode("./privateData", ctxt))) {
+            if (xmlopt->privateData.tpmParse(ctxt, def) < 0)
+                goto error;
+        }
+    }
+
     return def;
 
  error:
@@ -24049,10 +24075,32 @@ virDomainSoundCodecDefFormat(virBuffer *buf,
     return 0;
 }
 
-static void
+static int
+virDomainTPMDefFormatPrivateData(virBuffer *buf,
+                                 const virDomainTPMDef *tpm,
+                                 unsigned int flags,
+                                 virDomainXMLOption *xmlopt)
+{
+    g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
+
+    if (!(flags & VIR_DOMAIN_DEF_FORMAT_STATUS) ||
+        !xmlopt ||
+        !xmlopt->privateData.tpmFormat)
+        return 0;
+
+    if (xmlopt->privateData.tpmFormat(tpm, &childBuf) < 0)
+        return -1;
+
+    virXMLFormatElement(buf, "privateData", NULL, &childBuf);
+    return 0;
+}
+
+
+static int
 virDomainTPMDefFormat(virBuffer *buf,
                       const virDomainTPMDef *def,
-                      unsigned int flags)
+                      unsigned int flags,
+                      virDomainXMLOption *xmlopt)
 {
     g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
     g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
@@ -24101,8 +24149,12 @@ virDomainTPMDefFormat(virBuffer *buf,
 
     virXMLFormatElement(&childBuf, "backend", &backendAttrBuf, &backendChildBuf);
     virDomainDeviceInfoFormat(&childBuf, &def->info, flags);
+    if (virDomainTPMDefFormatPrivateData(&childBuf, def, flags, xmlopt) < 0)
+        return -1;
 
     virXMLFormatElement(buf, "tpm", &attrBuf, &childBuf);
+
+    return 0;
 }
 
 
@@ -27188,7 +27240,8 @@ virDomainDefFormatInternalSetRootName(virDomainDef *def,
     }
 
     for (n = 0; n < def->ntpms; n++) {
-        virDomainTPMDefFormat(buf, def->tpms[n], flags);
+        if (virDomainTPMDefFormat(buf, def->tpms[n], flags, xmlopt) < 0)
+            return -1;
     }
 
     for (n = 0; n < def->ngraphics; n++) {
@@ -28454,7 +28507,7 @@ virDomainDeviceDefCopy(virDomainDeviceDef *src,
         rc = virDomainChrDefFormat(&buf, src->data.chr, flags);
         break;
     case VIR_DOMAIN_DEVICE_TPM:
-        virDomainTPMDefFormat(&buf, src->data.tpm, flags);
+        virDomainTPMDefFormat(&buf, src->data.tpm, flags, xmlopt);
         rc = 0;
         break;
     case VIR_DOMAIN_DEVICE_PANIC:
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 8f8a54bc41..82f71f8853 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1445,6 +1445,8 @@ typedef enum {
 #define VIR_DOMAIN_TPM_DEFAULT_DEVICE "/dev/tpm0"
 
 struct _virDomainTPMDef {
+    virObject *privateData;
+
     virDomainTPMModel model;
     virDomainTPMBackendType type;
     virDomainDeviceInfo info;
@@ -3248,6 +3250,10 @@ typedef int (*virDomainXMLPrivateDataStorageSourceParseFunc)(xmlXPathContextPtr
 typedef int (*virDomainXMLPrivateDataStorageSourceFormatFunc)(virStorageSource *src,
                                                               virBuffer *buf);
 
+typedef int (*virDomainXMLPrivateDataTPMParseFunc)(xmlXPathContextPtr ctxt,
+                                                   virDomainTPMDef *disk);
+typedef int (*virDomainXMLPrivateDataTPMFormatFunc)(const virDomainTPMDef *tpm,
+                                                    virBuffer *buf);
 
 struct _virDomainXMLPrivateDataCallbacks {
     virDomainXMLPrivateDataAllocFunc  alloc;
@@ -3264,6 +3270,9 @@ struct _virDomainXMLPrivateDataCallbacks {
     virDomainXMLPrivateDataNewFunc    networkNew;
     virDomainXMLPrivateDataNewFunc    videoNew;
     virDomainXMLPrivateDataNewFunc    fsNew;
+    virDomainXMLPrivateDataTPMParseFunc tpmParse;
+    virDomainXMLPrivateDataTPMFormatFunc tpmFormat;
+    virDomainXMLPrivateDataNewFunc    tpmNew;
     virDomainXMLPrivateDataFormatFunc format;
     virDomainXMLPrivateDataParseFunc  parse;
     /* following function shall return a pointer which will be used as the
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 9ef6c8bb64..41333f1725 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -1139,6 +1139,76 @@ qemuDomainVideoPrivateDispose(void *obj)
 }
 
 
+static virClass *qemuDomainTPMPrivateClass;
+static void qemuDomainTPMPrivateDispose(void *obj);
+
+
+static int
+qemuDomainTPMPrivateOnceInit(void)
+{
+    if (!VIR_CLASS_NEW(qemuDomainTPMPrivate, virClassForObject()))
+        return -1;
+
+    return 0;
+}
+
+VIR_ONCE_GLOBAL_INIT(qemuDomainTPMPrivate);
+
+
+static virObject *
+qemuDomainTPMPrivateNew(void)
+{
+    qemuDomainTPMPrivate *priv;
+
+    if (qemuDomainTPMPrivateInitialize() < 0)
+        return NULL;
+
+    if (!(priv = virObjectNew(qemuDomainTPMPrivateClass)))
+        return NULL;
+
+    return (virObject *) priv;
+}
+
+
+static void
+qemuDomainTPMPrivateDispose(void *obj G_GNUC_UNUSED)
+{
+}
+
+
+static int
+qemuDomainTPMPrivateParse(xmlXPathContextPtr ctxt,
+                          virDomainTPMDef *tpm)
+{
+    qemuDomainTPMPrivate *priv = QEMU_DOMAIN_TPM_PRIVATE(tpm);
+
+    priv->swtpm.can_migrate_shared_storage =
+        virXPathBoolean("string(./swtpm/@can_migrate_shared_storage)", ctxt);
+
+    return 0;
+}
+
+
+static int
+qemuDomainTPMPrivateFormat(const virDomainTPMDef *tpm,
+                           virBuffer *buf)
+{
+    qemuDomainTPMPrivate *priv = QEMU_DOMAIN_TPM_PRIVATE(tpm);
+
+    switch (tpm->type) {
+    case VIR_DOMAIN_TPM_TYPE_EMULATOR:
+        if (priv->swtpm.can_migrate_shared_storage)
+            virBufferAddLit(buf, "<swtpm can_migrate_shared_storage='yes'/>\n");
+        break;
+
+    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
+    case VIR_DOMAIN_TPM_TYPE_LAST:
+    }
+
+    return 0;
+}
+
+
 /* qemuDomainSecretInfoSetup:
  * @priv: pointer to domain private object
  * @alias: alias of the secret
@@ -3215,6 +3285,9 @@ virDomainXMLPrivateDataCallbacks virQEMUDriverPrivateDataCallbacks = {
     .graphicsNew = qemuDomainGraphicsPrivateNew,
     .networkNew = qemuDomainNetworkPrivateNew,
     .videoNew = qemuDomainVideoPrivateNew,
+    .tpmNew = qemuDomainTPMPrivateNew,
+    .tpmParse = qemuDomainTPMPrivateParse,
+    .tpmFormat = qemuDomainTPMPrivateFormat,
     .parse = qemuDomainObjPrivateXMLParse,
     .format = qemuDomainObjPrivateXMLFormat,
     .getParseOpaque = qemuDomainObjPrivateXMLGetParseOpaque,
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 2bbd492d62..919ce16097 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -414,6 +414,20 @@ struct _qemuDomainNetworkPrivate {
     qemuFDPass *vdpafd;
 };
 
+
+#define QEMU_DOMAIN_TPM_PRIVATE(dev) \
+    ((qemuDomainTPMPrivate *) (dev)->privateData)
+
+typedef struct _qemuDomainTPMPrivate qemuDomainTPMPrivate;
+struct _qemuDomainTPMPrivate {
+    virObject parent;
+
+    struct {
+        bool can_migrate_shared_storage;
+    } swtpm;
+};
+
+
 void
 qemuDomainNetworkPrivateClearFDs(qemuDomainNetworkPrivate *priv);
 
-- 
2.37.3



More information about the libvir-list mailing list