[PATCH v3 4/6] qemu: tpm: Pass --migration option to swtpm if supported and needed

Michal Prívozník mprivozn at redhat.com
Fri Oct 21 10:55:45 UTC 2022


On 10/18/22 19:04, Stefan Berger wrote:
> Pass the --migration option to swtpm if swptm supports it (starting
> with v0.8) and if the TPM's state is written on shared storage. If this
> is the case apply the 'release-lock-outgoing' parameter with this
> option and apply the 'incoming' parameter for incoming migration so that
> swtpm releases the file lock on the source side when the state is migrated
> and locks the file on the destination side when the state is received.
> 
> If a started swtpm instance is running with the necessary options of
> migrating with share storage then remember this with a flag in the
> virDomainTPMPrivateDef.
> 
> Report an error if swtpm does not support the --migration option and an
> incoming migration across shared storage is requested.
> 
> Signed-off-by: Stefan Berger <stefanb at linux.ibm.com>
> ---
>  src/qemu/qemu_migration.c |  8 +++++
>  src/qemu/qemu_tpm.c       | 66 ++++++++++++++++++++++++++++++++++++++-
>  src/qemu/qemu_tpm.h       |  6 ++++
>  3 files changed, 79 insertions(+), 1 deletion(-)
> 
> diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
> index 33105cf07b..5b4f4615ee 100644
> --- a/src/qemu/qemu_migration.c
> +++ b/src/qemu/qemu_migration.c
> @@ -38,6 +38,7 @@
>  #include "qemu_security.h"
>  #include "qemu_slirp.h"
>  #include "qemu_block.h"
> +#include "qemu_tpm.h"
>  
>  #include "domain_audit.h"
>  #include "virlog.h"
> @@ -2789,6 +2790,13 @@ qemuMigrationSrcBegin(virConnectPtr conn,
>          goto cleanup;
>      }
>  
> +    if (qemuTPMHasSharedStorage(vm->def) &&
> +        !qemuTPMCanMigrateSharedStorage(vm->def)) {

This works, but only because qemuValidateDomainDefTPMs() denies two
emulated TPMs. I think we can call just qemuTPMCanMigrateSharedStorage()
since it already iterates over all TPMs and checks each one individually.

> +        virReportError(VIR_ERR_NO_SUPPORT, "%s",
> +                       _("the running swtpm does not support migration with shared storage"));
> +        goto cleanup;
> +    }
> +
>      if (flags & VIR_MIGRATE_POSTCOPY_RESUME) {
>          ret = qemuMigrationSrcBeginResumePhase(conn, driver, vm, xmlin,
>                                                 cookieout, cookieoutlen, flags);
> diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c
> index a45ad599aa..7b0afe94ec 100644
> --- a/src/qemu/qemu_tpm.c
> +++ b/src/qemu/qemu_tpm.c
> @@ -557,6 +557,7 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm,
>      int migpwdfile_fd = -1;
>      const unsigned char *secretuuid = NULL;
>      bool create_storage = true;
> +    bool on_shared_storage;
>  
>      if (!swtpm)
>          return NULL;
> @@ -564,7 +565,8 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm,
>      /* Do not create storage and run swtpm_setup on incoming migration over
>       * shared storage
>       */
> -    if (incomingMigration && virFileIsSharedFS(tpm->data.emulator.storagepath))
> +    on_shared_storage = virFileIsSharedFS(tpm->data.emulator.storagepath);
> +    if (incomingMigration && on_shared_storage)
>          create_storage = false;
>  
>      if (create_storage &&
> @@ -642,6 +644,31 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm,
>          virCommandAddArgFormat(cmd, "pwdfd=%d,mode=aes-256-cbc", migpwdfile_fd);
>      }
>  
> +    /* If swtpm supports it and the TPM state is stored on shared storage,
> +     * start swtpm with --migration release-lock-outgoing so it can migrate
> +     * across shared storage if needed.
> +     */
> +    QEMU_DOMAIN_TPM_PRIVATE(tpm)->swtpm.can_migrate_shared_storage = false;

If we don't introduce private data, then this line should be deleted.

> +    if (on_shared_storage &&
> +        virTPMSwtpmCapsGet(VIR_TPM_SWTPM_FEATURE_CMDARG_MIGRATION)) {
> +
> +        virCommandAddArg(cmd, "--migration");
> +        virCommandAddArgFormat(cmd, "release-lock-outgoing%s",
> +                               incomingMigration ? ",incoming": "");
> +        QEMU_DOMAIN_TPM_PRIVATE(tpm)->swtpm.can_migrate_shared_storage = true;
> +    } else {
> +        /* Report an error if there's an incoming migration across shared
> +         * storage and swtpm does not support the --migration option.
> +         */
> +        if (incomingMigration && on_shared_storage) {
> +            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
> +                _("%s (on destination side) does not support the --migration option "
> +                  "needed for migration with shared storage"),

Don't hesitate to put whole error message onto one line. It's way easier
to grep then.

> +                   swtpm);
> +            goto error;
> +        }
> +    }
> +
>      return g_steal_pointer(&cmd);
>  
>   error:
> @@ -962,6 +989,43 @@ qemuTPMEmulatorStart(virQEMUDriver *driver,
>  }
>  
>  
> +bool
> +qemuTPMHasSharedStorage(virDomainDef *def)
> +{
> +    size_t i;
> +
> +    for (i = 0; i < def->ntpms; i++) {
> +        virDomainTPMDef *tpm = def->tpms[i];
> +        switch (tpm->type) {
> +        case VIR_DOMAIN_TPM_TYPE_EMULATOR:
> +            return virFileIsSharedFS(tpm->data.emulator.storagepath);
> +        case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
> +        case VIR_DOMAIN_TPM_TYPE_LAST:
> +        }
> +    }
> +
> +    return false;
> +}
> +
> +
> +bool
> +qemuTPMCanMigrateSharedStorage(virDomainDef *def)
> +{
> +    size_t i;
> +
> +    for (i = 0; i < def->ntpms; i++) {
> +        virDomainTPMDef *tpm = def->tpms[i];
> +        switch (tpm->type) {
> +        case VIR_DOMAIN_TPM_TYPE_EMULATOR:
> +            return QEMU_DOMAIN_TPM_PRIVATE(tpm)->swtpm.can_migrate_shared_storage;

If we don't introduce private data, then how about just:

if (virFileIsSharedFS(tpm->data.emulator.storagepath) == 1 &&
    !virTPMSwtpmCapsGet(VIR_TPM_SWTPM_FEATURE_CMDARG_MIGRATION))
     return false;

> +        case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
> +        case VIR_DOMAIN_TPM_TYPE_LAST:
> +        }
> +    }
> +    return true;
> +}
> +
> +
>  /* ---------------------
>   *  Module entry points
>   * ---------------------
> diff --git a/src/qemu/qemu_tpm.h b/src/qemu/qemu_tpm.h
> index f068f3ca5a..9daa3e14df 100644
> --- a/src/qemu/qemu_tpm.h
> +++ b/src/qemu/qemu_tpm.h
> @@ -56,3 +56,9 @@ int qemuExtTPMSetupCgroup(virQEMUDriver *driver,
>                            virCgroup *cgroup)
>      ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
>      G_GNUC_WARN_UNUSED_RESULT;
> +
> +bool qemuTPMHasSharedStorage(virDomainDef *def)
> +    ATTRIBUTE_NONNULL(1);
> +
> +bool qemuTPMCanMigrateSharedStorage(virDomainDef *def)
> +    ATTRIBUTE_NONNULL(1);

Michal



More information about the libvir-list mailing list