[libvirt] [PATCH v3 09/14] qemu: Implement a layer for external devices like tpm-emulator
John Ferlan
jferlan at redhat.com
Tue May 8 20:50:41 UTC 2018
On 05/04/2018 04:21 PM, Stefan Berger wrote:
> Implement a layer for starting and stopping of external devices.
> The tpm-emulator is the only user of this layer.
>
> Signed-off-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
> ---
> src/qemu/Makefile.inc.am | 2 +
> src/qemu/qemu_extdevice.c | 300 ++++++++++++++++++++++++++++++++++++++++++++++
> src/qemu/qemu_extdevice.h | 43 +++++++
> src/qemu/qemu_process.c | 13 ++
> 4 files changed, 358 insertions(+)
> create mode 100644 src/qemu/qemu_extdevice.c
> create mode 100644 src/qemu/qemu_extdevice.h
>
> diff --git a/src/qemu/Makefile.inc.am b/src/qemu/Makefile.inc.am
> index 63e7c87..d16e880 100644
> --- a/src/qemu/Makefile.inc.am
> +++ b/src/qemu/Makefile.inc.am
> @@ -19,6 +19,8 @@ QEMU_DRIVER_SOURCES = \
> qemu/qemu_domain_address.h \
> qemu/qemu_cgroup.c \
> qemu/qemu_cgroup.h \
> + qemu/qemu_extdevice.c \
> + qemu/qemu_extdevice.h \
> qemu/qemu_hostdev.c \
> qemu/qemu_hostdev.h \
> qemu/qemu_hotplug.c \
> diff --git a/src/qemu/qemu_extdevice.c b/src/qemu/qemu_extdevice.c
> new file mode 100644
> index 0000000..f3f337d
> --- /dev/null
> +++ b/src/qemu/qemu_extdevice.c
> @@ -0,0 +1,300 @@
> +/*
> + * qemu_extdevice.c: QEMU external devices support
> + *
> + * Copyright (C) 2014, 2018 IBM Corporation
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library. If not, see
> + * <http://www.gnu.org/licenses/>.
> + *
> + * Author: Stefan Berger <stefanb at linux.vnet.ibm.com>
> + */
> +
> +#include <config.h>
> +
> +#include "qemu_extdevice.h"
> +#include "qemu_domain.h"
> +
> +#include "viralloc.h"
> +#include "virlog.h"
> +#include "virstring.h"
> +#include "virtime.h"
> +#include "virtpm.h"
> +
> +#define VIR_FROM_THIS VIR_FROM_QEMU
> +
> +VIR_LOG_INIT("qemu.qemu_extdevice")
> +
> +static int
> +qemuExtDeviceLogCommand(qemuDomainLogContextPtr logCtxt,
> + virCommandPtr cmd,
> + const char *info)
> +{
> + int ret = -1;
> + char *timestamp = NULL;
> + char *logline = NULL;
> + int logFD;
> +
> + logFD = qemuDomainLogContextGetWriteFD(logCtxt);
> +
> + if ((timestamp = virTimeStringNow()) == NULL)
> + goto cleanup;
> +
> + if (virAsprintf(&logline, "%s: Starting external device: %s\n",
> + timestamp, info) < 0)
> + goto cleanup;
> +
> + if (safewrite(logFD, logline, strlen(logline)) < 0)
> + goto cleanup;
> +
> + virCommandWriteArgLog(cmd, logFD);
> +
> + ret = 0;
> +
> + cleanup:
> + VIR_FREE(timestamp);
> + VIR_FREE(logline);
> +
> + return ret;
> +}
> +
> +
> +static int
> +qemuExtTPMInitPaths(virQEMUDriverPtr driver,
> + virDomainDefPtr def)
> +{
> + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
> + int ret = 0;
> +
> + switch (def->tpm->type) {
> + case VIR_DOMAIN_TPM_TYPE_EMULATOR:
> + ret = virTPMEmulatorInitPaths(def->tpm, cfg->swtpmStorageDir,
> + def->uuid);
> + break;
> + case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
> + case VIR_DOMAIN_TPM_TYPE_LAST:
> + break;
> + }
> +
> + virObjectUnref(cfg);
> +
> + return ret;
> +}
> +
> +
> +static int
> +qemuExtTPMPrepareHost(virQEMUDriverPtr driver,
> + virDomainDefPtr def)
> +{
> + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
> + int ret = 0;
> + char *shortName = NULL;
> +
> + switch (def->tpm->type) {
> + case VIR_DOMAIN_TPM_TYPE_EMULATOR:
> + shortName = virDomainDefGetShortName(def);
> + if (!shortName)
> + goto cleanup;
> +
> + ret = virTPMEmulatorPrepareHost(def->tpm, cfg->swtpmLogDir,
> + def->name, cfg->swtpm_user,
> + cfg->swtpm_group,
> + cfg->swtpmStateDir, cfg->user,
> + shortName);
> + break;
> + case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
> + case VIR_DOMAIN_TPM_TYPE_LAST:
> + break;
> + }
> +
> +cleanup:
> + VIR_FREE(shortName);
> + virObjectUnref(cfg);
> +
> + return ret;
> +}
> +
> +
> +/*
> + * qemuExtTPMStartEmulator:
> + *
> + * @driver: QEMU driver
> + * @def: domain definition
> + * @logCtxt: log context
> + *
> + * Start the external TPM Emulator:
> + * - have the command line built
> + * - start the external TPM Emulator and sync with it before QEMU start
> + */
> +static int
> +qemuExtTPMStartEmulator(virQEMUDriverPtr driver,
> + virDomainDefPtr def,
> + qemuDomainLogContextPtr logCtxt)
> +{
> + int ret = -1;
> + virCommandPtr cmd = NULL;
> + int exitstatus;
> + char *errbuf = NULL;
> + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
> + virDomainTPMDefPtr tpm = def->tpm;
> + char *shortName = virDomainDefGetShortName(def);
> +
> + if (!shortName)
> + return -1;
Leaking @cfg (repeats often)
> +
> + /* stop any left-over TPM emulator for this VM */
> + virTPMEmulatorStop(cfg->swtpmStateDir, shortName);
> +
> + if (!(cmd = virTPMEmulatorBuildCommand(tpm, def->name, def->uuid,
> + driver->privileged,
> + cfg->swtpm_user,
> + cfg->swtpm_group)))
> + goto cleanup;
> +
> + if (qemuExtDeviceLogCommand(logCtxt, cmd, "TPM Emulator") < 0)
> + goto cleanup;
> +
> + virCommandSetErrorBuffer(cmd, &errbuf);
> +
> + if (virCommandRun(cmd, &exitstatus) < 0 || exitstatus != 0) {
> + VIR_ERROR("Could not start 'swtpm'. exitstatus: %d\n"
> + "stderr: %s\n", exitstatus, errbuf);
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Could not start 'swtpm'. exitstatus: %d, "
> + "error: %s"), exitstatus, errbuf);
> + goto error;
> + }
> +
> + ret = 0;
> +
> + cleanup:
> + VIR_FREE(shortName);
> + VIR_FREE(errbuf);
> + virCommandFree(cmd);
> +
> + virObjectUnref(cfg);
> +
> + return ret;
> +
> + error:
> + VIR_FREE(tpm->data.emulator.source.data.nix.path);
Still not clear why VIR_FREE here since virDomainTPMDefFree does it.
> +
> + goto cleanup;
> +}
> +
Right about here you went back to single blank line between functions.
> +static int
> +qemuExtTPMStart(virQEMUDriverPtr driver,
> + virDomainDefPtr def,
> + qemuDomainLogContextPtr logCtxt)
> +{
> + int ret = 0;
> + virDomainTPMDefPtr tpm = def->tpm;
> +
> + switch (tpm->type) {
> + case VIR_DOMAIN_TPM_TYPE_EMULATOR:
> + ret = qemuExtTPMStartEmulator(driver, def, logCtxt);
> + break;
> + case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
> + case VIR_DOMAIN_TPM_TYPE_LAST:
> + break;
> + }
> +
> + return ret;
> +}
> +
> +static void
> +qemuExtTPMStop(virQEMUDriverPtr driver, virDomainDefPtr def)
> +{
> + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
> + char *shortName = NULL;
> +
> + switch (def->tpm->type) {
> + case VIR_DOMAIN_TPM_TYPE_EMULATOR:
> + shortName = virDomainDefGetShortName(def);
> + if (!shortName)
> + goto cleanup;
> +
> + virTPMEmulatorStop(cfg->swtpmStateDir, shortName);
> + break;
> + case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
> + case VIR_DOMAIN_TPM_TYPE_LAST:
> + break;
> + }
> +
> +cleanup:
> + VIR_FREE(shortName);
> + virObjectUnref(cfg);
> +}
> +
> +/*
> + * qemuExtDevicesInitPaths:
> + *
> + * @driver: QEMU driver
> + * @def: domain definition
> + *
> + * Initialize paths of external devices so that it is known where state is
> + * stored and we can remove directories and files in case of domain XML
> + * changes.
> + */
> +int
> +qemuExtDevicesInitPaths(virQEMUDriverPtr driver,
> + virDomainDefPtr def)
> +{
> + int ret = 0;
> +
> + if (def->tpm)
> + ret = qemuExtTPMInitPaths(driver, def);
> +
> + return ret;
> +}
> +
> +/*
> + * qemuExtDevicesPrepareHost:
> + *
> + * @driver: QEMU driver
> + * @def: domain definition
> + *
> + * Prepare host storage paths for external devices.
> + */
> +int
> +qemuExtDevicesPrepareHost(virQEMUDriverPtr driver,
> + virDomainDefPtr def)
> +{
> + int ret = 0;
> +
> + if (def->tpm)
> + ret = qemuExtTPMPrepareHost(driver, def);
> +
> + return ret;
> +}
> +
> +int
> +qemuExtDevicesStart(virQEMUDriverPtr driver,
> + virDomainDefPtr def,
> + qemuDomainLogContextPtr logCtxt)
> +{
> + int ret = 0;
> +
> + if (def->tpm)
> + ret = qemuExtTPMStart(driver, def, logCtxt);
> +
> + return ret;
> +}
> +
> +void
> +qemuExtDevicesStop(virQEMUDriverPtr driver,
> + virDomainDefPtr def)
> +{
> + if (def->tpm)
> + qemuExtTPMStop(driver, def);
> +}
> diff --git a/src/qemu/qemu_extdevice.h b/src/qemu/qemu_extdevice.h
> new file mode 100644
> index 0000000..fd6b630
> --- /dev/null
> +++ b/src/qemu/qemu_extdevice.h
> @@ -0,0 +1,43 @@
> +/*
> + * qemu_extdevice.h: QEMU external devices support
> + *
> + * Copyright (C) 2014, 2018 IBM Corporation
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library. If not, see
> + * <http://www.gnu.org/licenses/>.
> + *
> + * Author: Stefan Berger <stefanb at linux.vnet.ibm.com>
> + */
> +#ifndef __QEMU_EXTDEVICE_H__
> +# define __QEMU_EXTDEVICE_H__
> +
> +# include "qemu_conf.h"
> +# include "qemu_domain.h"
> +
> +int qemuExtDevicesInitPaths(virQEMUDriverPtr driver,
> + virDomainDefPtr def)
> + ATTRIBUTE_RETURN_CHECK;
> +
> +int qemuExtDevicesPrepareHost(virQEMUDriverPtr driver,
> + virDomainDefPtr def)
> + ATTRIBUTE_RETURN_CHECK;
> +
> +int qemuExtDevicesStart(virQEMUDriverPtr driver,
> + virDomainDefPtr def,
> + qemuDomainLogContextPtr logCtxt)
> + ATTRIBUTE_RETURN_CHECK;
> +
> +void qemuExtDevicesStop(virQEMUDriverPtr driver, virDomainDefPtr def);
> +
> +#endif /* __QEMU_EXTDEVICE_H__ */
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index 9233d26..2b07530 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -48,6 +48,7 @@
> #include "qemu_migration_params.h"
> #include "qemu_interface.h"
> #include "qemu_security.h"
> +#include "qemu_extdevice.h"
>
> #include "cpu/cpu.h"
> #include "datatypes.h"
> @@ -5872,6 +5873,10 @@ qemuProcessPrepareHost(virQEMUDriverPtr driver,
> if (qemuProcessPrepareHostStorage(driver, vm, flags) < 0)
> goto cleanup;
>
> + VIR_DEBUG("Preparing external devices");
> + if (qemuExtDevicesPrepareHost(driver, vm->def) < 0)
> + goto cleanup;
> +
> ret = 0;
> cleanup:
> virObjectUnref(cfg);
> @@ -5955,6 +5960,10 @@ qemuProcessLaunch(virConnectPtr conn,
> goto cleanup;
> logfile = qemuDomainLogContextGetWriteFD(logCtxt);
>
> + if (qemuExtDevicesInitPaths(driver, vm->def) < 0 ||
> + qemuExtDevicesStart(driver, vm->def, logCtxt) < 0)
> + goto cleanup;
> +
> VIR_DEBUG("Building emulator command line");
> if (!(cmd = qemuBuildCommandLine(driver,
> qemuDomainLogContextGetManager(logCtxt),
> @@ -6194,6 +6203,8 @@ qemuProcessLaunch(virConnectPtr conn,
> ret = 0;
>
> cleanup:
> + if (ret)
> + qemuExtDevicesStop(driver, vm->def);
> qemuDomainSecretDestroy(vm);
> virCommandFree(cmd);
> virObjectUnref(logCtxt);
> @@ -6614,6 +6625,8 @@ void qemuProcessStop(virQEMUDriverPtr driver,
>
> qemuDomainCleanupRun(driver, vm);
>
> + qemuExtDevicesStop(driver, vm->def);
> +
> /* Stop autodestroy in case guest is restarted */
> qemuProcessAutoDestroyRemove(driver, vm);
>
>
Anything need to be done during qemuProcessReconnect?
John
More information about the libvir-list
mailing list