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@xxxxxxxxxxxxx> --- 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