[libvirt] [PATCH v4 11/11] qemu: Add swtpm to emulator cgroup

Boris Fiuczynski fiuczy at linux.ibm.com
Tue May 15 08:51:14 UTC 2018


On 05/10/2018 11:57 PM, Stefan Berger wrote:
> Add the external swtpm to the emulator cgroup so that upper limits of CPU
> usage can be enforced on the emulated TPM.
> 
> To enable this we need to have the swtpm write its process id (pid) into a
> file. We then read it from the file to configure the emulator cgroup.
> 
> The PID file is created in /var/run/libvirt/qemu/swtpm:
> 
> [root at localhost swtpm]# ls -lZ /var/run/libvirt/qemu/swtpm/
> total 4
> -rw-r--r--. 1 tss  tss  system_u:object_r:qemu_var_run_t:s0          5 Apr 10 12:26 1-testvm-swtpm.pid
> srw-rw----. 1 qemu qemu system_u:object_r:svirt_image_t:s0:c597,c632 0 Apr 10 12:26 1-testvm-swtpm.sock
> 
> The swtpm command line now looks as follows:
> 
> root at localhost testvm]# ps auxZ | grep swtpm | grep socket | grep -v grep
> system_u:system_r:virtd_t:s0:c597,c632 tss 18697 0.0  0.0 28172 3892 ?       Ss   16:46   0:00 /usr/bin/swtpm socket --daemon --ctrl type=unixio,path=/var/run/libvirt/qemu/swtpm/1-testvm-swtpm.sock,mode=0600 --tpmstate dir=/var/lib/libvirt/swtpm/485d0004-a48f-436a-8457-8a3b73e28568/tpm1.2/ --log file=/var/log/swtpm/libvirt/qemu/testvm-swtpm.log --pid file=/var/run/libvirt/qemu/swtpm/1-testvm-swtpm.pid
> 
> Signed-off-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
> ---
>   src/qemu/qemu_cgroup.c    |  35 ++++++++++++
>   src/qemu/qemu_cgroup.h    |   2 +
>   src/qemu/qemu_extdevice.c |  23 ++++++++
>   src/qemu/qemu_extdevice.h |   6 +++
>   src/qemu/qemu_process.c   |   4 ++
>   src/qemu/qemu_tpm.c       | 134 +++++++++++++++++++++++++++++++++++++++++++++-
>   src/qemu/qemu_tpm.h       |   6 +++
>   7 files changed, 208 insertions(+), 2 deletions(-)
> 
> diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
> index 1a5adca..c51062d 100644
> --- a/src/qemu/qemu_cgroup.c
> +++ b/src/qemu/qemu_cgroup.c
> @@ -26,6 +26,7 @@
>   #include "qemu_cgroup.h"
>   #include "qemu_domain.h"
>   #include "qemu_process.h"
> +#include "qemu_extdevice.h"
>   #include "vircgroup.h"
>   #include "virlog.h"
>   #include "viralloc.h"
> @@ -1146,6 +1147,40 @@ qemuSetupCgroupCpusetCpus(virCgroupPtr cgroup,
>   
>   
>   int
> +qemuSetupCgroupForExtDevices(virDomainObjPtr vm,
> +                             virQEMUDriverPtr driver)
> +{
> +    qemuDomainObjPrivatePtr priv = vm->privateData;
> +    virCgroupPtr cgroup_temp = NULL;
> +    int ret = -1;
> +
> +    if (!qemuExtDevicesHasDevice(vm->def) ||
> +        priv->cgroup == NULL)
> +        return 0; /* Not supported, so claim success */
> +
> +    /*
> +     * If CPU cgroup controller is not initialized here, then we need
> +     * neither period nor quota settings.  And if CPUSET controller is
> +     * not initialized either, then there's nothing to do anyway.
> +     */
> +    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU) &&
> +        !virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET))
> +        return 0;
> +
> +    if (virCgroupNewThread(priv->cgroup, VIR_CGROUP_THREAD_EMULATOR, 0,
> +                           false, &cgroup_temp) < 0)
> +        goto cleanup;
> +
> +    ret = qemuExtDevicesSetupCgroup(driver, vm->def, cgroup_temp);
> +
> +cleanup:
make syntax-check wants a blank in front of the label

> +    virCgroupFree(&cgroup_temp);
> +
> +    return ret;
> +}
> +
> +
> +int
>   qemuSetupGlobalCpuCgroup(virDomainObjPtr vm)
>   {
>       qemuDomainObjPrivatePtr priv = vm->privateData;
> diff --git a/src/qemu/qemu_cgroup.h b/src/qemu/qemu_cgroup.h
> index 3b8ff60..c2fca7f 100644
> --- a/src/qemu/qemu_cgroup.h
> +++ b/src/qemu/qemu_cgroup.h
> @@ -69,6 +69,8 @@ int qemuSetupCgroupVcpuBW(virCgroupPtr cgroup,
>                             long long quota);
>   int qemuSetupCgroupCpusetCpus(virCgroupPtr cgroup, virBitmapPtr cpumask);
>   int qemuSetupGlobalCpuCgroup(virDomainObjPtr vm);
> +int qemuSetupCgroupForExtDevices(virDomainObjPtr vm,
> +                                 virQEMUDriverPtr driver);
>   int qemuRemoveCgroup(virDomainObjPtr vm);
>   
>   typedef struct _qemuCgroupEmulatorAllNodesData qemuCgroupEmulatorAllNodesData;
> diff --git a/src/qemu/qemu_extdevice.c b/src/qemu/qemu_extdevice.c
> index 790b19b..dd66420 100644
> --- a/src/qemu/qemu_extdevice.c
> +++ b/src/qemu/qemu_extdevice.c
> @@ -30,6 +30,8 @@
>   #include "virlog.h"
>   #include "virstring.h"
>   #include "virtime.h"
> +#include "virtpm.h"
> +#include "virpidfile.h"
>   
>   #define VIR_FROM_THIS VIR_FROM_QEMU
>   
> @@ -152,3 +154,24 @@ qemuExtDevicesStop(virQEMUDriverPtr driver,
>       if (def->tpm)
>           qemuExtTPMStop(driver, def);
>   }
> +
> +
> +bool
> +qemuExtDevicesHasDevice(virDomainDefPtr def)
> +{
> +    return def->tpm != NULL;
> +}
> +
> +
> +int
> +qemuExtDevicesSetupCgroup(virQEMUDriverPtr driver,
> +                          virDomainDefPtr def,
> +                          virCgroupPtr cgroup)
> +{
> +    int ret = 0;
> +
> +    if (def->tpm)
> +        ret = qemuExtTPMSetupCgroup(driver, def, cgroup);
> +
> +    return ret;
> +}
> diff --git a/src/qemu/qemu_extdevice.h b/src/qemu/qemu_extdevice.h
> index 6de858b..c557778 100644
> --- a/src/qemu/qemu_extdevice.h
> +++ b/src/qemu/qemu_extdevice.h
> @@ -50,4 +50,10 @@ void qemuExtDevicesStop(virQEMUDriverPtr driver,
>                           virDomainDefPtr def)
>       ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
>   
> +bool qemuExtDevicesHasDevice(virDomainDefPtr def);
> +
> +int qemuExtDevicesSetupCgroup(virQEMUDriverPtr driver,
> +                              virDomainDefPtr def,
> +                              virCgroupPtr cgroup);
> +
>   #endif /* __QEMU_EXTDEVICE_H__ */
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index 9370de3..35a78f3 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -6075,6 +6075,10 @@ qemuProcessLaunch(virConnectPtr conn,
>       if (qemuProcessSetupEmulator(vm) < 0)
>           goto cleanup;
>   
> +    VIR_DEBUG("Setting cgroup for external devices (if required)");
> +    if (qemuSetupCgroupForExtDevices(vm, driver) < 0)
> +        goto cleanup;
> +
>       VIR_DEBUG("Setting up resctrl");
>       if (qemuProcessResctrlCreate(driver, vm) < 0)
>           goto cleanup;
> diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c
> index 26cc572..da6acbf 100644
> --- a/src/qemu/qemu_tpm.c
> +++ b/src/qemu/qemu_tpm.c
> @@ -39,6 +39,7 @@
>   #include "viruuid.h"
>   #include "virfile.h"
>   #include "virstring.h"
> +#include "virpidfile.h"
>   #include "configmake.h"
>   #include "qemu_tpm.h"
>   
> @@ -346,6 +347,57 @@ qemuTPMEmulatorInitPaths(virDomainTPMDefPtr tpm,
>   
>   
>   /*
> + * qemuTPMCreatePidFilename
> + */
> +static char *
> +qemuTPMEmulatorCreatePidFilename(const char *swtpmStateDir,
> +                                 const char *shortName)
> +{
> +    char *pidfile = NULL;
> +    char *devicename = NULL;
> +
> +    if (virAsprintf(&devicename, "%s-swtpm", shortName) < 0)
> +        return NULL;
> +
> +    pidfile = virPidFileBuildPath(swtpmStateDir, devicename);
> +
> +    VIR_FREE(devicename);
> +
> +    return pidfile;
> +}
> +
> +
> +/*
> + * qemuTPMEmulatorGetPid
> + *
> + * @swtpmStateDir: the directory where swtpm writes the pidfile into
> + * @shortName: short name of the domain
> + * @pid: pointer to pid
> + *
> + * Return -errno upon error, or zero on successful reading of the pidfile.
> + * If the PID was not still alive, zero will be returned, and @pid will be
> + * set to -1;
> + */
> +static int
> +qemuTPMEmulatorGetPid(const char *swtpmStateDir,
> +                      const char *shortName,
> +                      pid_t *pid)
> +{
> +    int ret;
> +    char *pidfile = qemuTPMEmulatorCreatePidFilename(swtpmStateDir,
> +                                                     shortName);
> +    if (!pidfile)
> +        return -ENOMEM;
> +
> +    ret = virPidFileReadPathIfAlive(pidfile, pid, swtpm_path);
> +
> +    VIR_FREE(pidfile);
> +
> +    return ret;
> +}
> +
> +
> +/*
>    * qemuTPMEmulatorPrepareHost:
>    *
>    * @tpm: tpm definition
> @@ -514,6 +566,9 @@ qemuTPMEmulatorRunSetup(const char *storagepath,
>    * @privileged: whether we are running in privileged mode
>    * @swtpm_user: The uid for the swtpm to run as (drop privileges to from root)
>    * @swtpm_group: The gid for the swtpm to run as
> + * @swtpmStateDir: the directory where swtpm writes the pid file and creates the
> + *                 Unix socket
> + * @shortName: the short name of the VM
>    *
>    * Create the virCommand use for starting the emulator
>    * Do some initializations on the way, such as creation of storage
> @@ -525,10 +580,13 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDefPtr tpm,
>                               const unsigned char *vmuuid,
>                               bool privileged,
>                               uid_t swtpm_user,
> -                            gid_t swtpm_group)
> +                            gid_t swtpm_group,
> +                            const char *swtpmStateDir,
> +                            const char *shortName)
>   {
>       virCommandPtr cmd = NULL;
>       bool created = false;
> +    char *pidfile;
>   
>       if (qemuTPMCreateEmulatorStorage(tpm->data.emulator.storagepath,
>                                        &created, swtpm_user, swtpm_group) < 0)
> @@ -570,6 +628,13 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDefPtr tpm,
>           break;
>       }
>   
> +    if (!(pidfile = qemuTPMEmulatorCreatePidFilename(swtpmStateDir, shortName)))
> +        goto error;
> +
> +    virCommandAddArg(cmd, "--pid");
> +    virCommandAddArgFormat(cmd, "file=%s", pidfile);
> +    VIR_FREE(pidfile);
> +
>       return cmd;
>   
>    error:
> @@ -721,6 +786,8 @@ qemuExtTPMStartEmulator(virQEMUDriverPtr driver,
>       virQEMUDriverConfigPtr cfg;
>       virDomainTPMDefPtr tpm = def->tpm;
>       char *shortName = virDomainDefGetShortName(def);
> +    int timeout, rc;
> +    pid_t pid;
>   
>       if (!shortName)
>           return -1;
> @@ -733,7 +800,8 @@ qemuExtTPMStartEmulator(virQEMUDriverPtr driver,
>       if (!(cmd = qemuTPMEmulatorBuildCommand(tpm, def->name, def->uuid,
>                                               driver->privileged,
>                                               cfg->swtpm_user,
> -                                            cfg->swtpm_group)))
> +                                            cfg->swtpm_group,
> +                                            cfg->swtpmStateDir, shortName)))
>           goto cleanup;
>   
>       if (qemuExtDeviceLogCommand(logCtxt, cmd, "TPM Emulator") < 0)
> @@ -769,6 +837,22 @@ qemuExtTPMStartEmulator(virQEMUDriverPtr driver,
>           goto cleanup;
>       }
>   
> +    /* check that the swtpm has written its pid into the file */
> +    timeout = 1000; /* ms */
> +    while (timeout > 0) {
> +        rc = qemuTPMEmulatorGetPid(cfg->swtpmStateDir, shortName, &pid);
> +        if (rc < 0) {
> +            timeout -= 50;
> +            usleep(50 * 1000);
> +            continue;
> +        }
> +        if (rc == 0 && pid == (pid_t)-1)
> +             goto error;
> +        break;
> +    }
> +    if (timeout <= 0)
> +        goto error;
> +
>       ret = 0;
>   
>    cleanup:
> @@ -781,6 +865,11 @@ qemuExtTPMStartEmulator(virQEMUDriverPtr driver,
>       virObjectUnref(cfg);
>   
>       return ret;
> +
> + error:
> +    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                   _("swtpm failed to start"));
> +    goto cleanup;
>   }
>   
>   
> @@ -830,3 +919,44 @@ qemuExtTPMStop(virQEMUDriverPtr driver,
>       VIR_FREE(shortName);
>       virObjectUnref(cfg);
>   }
> +
> +
> +int
> +qemuExtTPMSetupCgroup(virQEMUDriverPtr driver,
> +                      virDomainDefPtr def,
> +                      virCgroupPtr cgroup)
> +{
> +    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
> +    char *pidfile = NULL;
> +    char *shortName = NULL;
> +    int ret = -1, rc;
> +    pid_t pid;
> +
> +    switch (def->tpm->type) {
> +    case VIR_DOMAIN_TPM_TYPE_EMULATOR:
> +        shortName = virDomainDefGetShortName(def);
> +        if (!shortName)
> +            goto cleanup;
> +        rc = qemuTPMEmulatorGetPid(cfg->swtpmStateDir, shortName, &pid);
> +        if (rc < 0 || (rc == 0 && pid == (pid_t)-1)) {
> +            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                           _("Could not get process id of swtpm"));
> +            goto cleanup;
> +        }
> +        if (virCgroupAddTask(cgroup, pid) < 0)
> +            goto cleanup;
> +        break;
> +    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
> +    case VIR_DOMAIN_TPM_TYPE_LAST:
> +        break;
> +    }
> +
> +    ret = 0;
> +
> + cleanup:
> +    VIR_FREE(pidfile);
> +    VIR_FREE(shortName);
> +    virObjectUnref(cfg);
> +
> +    return ret;
> +}
> diff --git a/src/qemu/qemu_tpm.h b/src/qemu/qemu_tpm.h
> index 20f3a9c..6eb1294 100644
> --- a/src/qemu/qemu_tpm.h
> +++ b/src/qemu/qemu_tpm.h
> @@ -47,4 +47,10 @@ void qemuExtTPMStop(virQEMUDriverPtr driver,
>                       virDomainDefPtr def)
>       ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
>   
> +int qemuExtTPMSetupCgroup(virQEMUDriverPtr driver,
> +                          virDomainDefPtr def,
> +                          virCgroupPtr cgroup)
> +    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
> +    ATTRIBUTE_RETURN_CHECK;
> +
>   #endif /* __QEMU_TPM_H__ */
> 


-- 
Mit freundlichen Grüßen/Kind regards
    Boris Fiuczynski

IBM Deutschland Research & Development GmbH
Vorsitzender des Aufsichtsrats: Martina Köderitz
Geschäftsführung: Dirk Wittkopp
Sitz der Gesellschaft: Böblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294




More information about the libvir-list mailing list