[libvirt] [PATCH V1 1/6] Add QMP probing for TPM

Daniel P. Berrange berrange at redhat.com
Thu Mar 14 14:20:40 UTC 2013


On Wed, Mar 13, 2013 at 12:03:49PM -0400, Stefan Berger wrote:
> Probe for QEMU's QMP TPM support by querying the lists of
> supported TPM models (query-tpm-models) and backend types
> (query-tpm-types). 
> 
> The setting of the capability flags following the strings
> returned from the commands above is only provided in the
> patch where domain_conf.c gets TPM support due to dependencies
> on functions only introduced there. 
> 
> Signed-off-by: Stefan Berger <stefanb at linux.vnet.ibm.com>
> 
> ---
>  src/libvirt_private.syms     |    1 
>  src/qemu/qemu_capabilities.c |   61 ++++++++++++++++++++++++++++
>  src/qemu/qemu_capabilities.h |    3 +
>  src/qemu/qemu_monitor.c      |   44 ++++++++++++++++++++
>  src/qemu/qemu_monitor.h      |    6 ++
>  src/qemu/qemu_monitor_json.c |   91 +++++++++++++++++++++++++++++++++++++++++++
>  src/qemu/qemu_monitor_json.h |    8 +++
>  src/util/virutil.c           |   14 ++++++
>  src/util/virutil.h           |    3 +
>  9 files changed, 231 insertions(+)
> 
> Index: libvirt/src/qemu/qemu_capabilities.c
> ===================================================================
> --- libvirt.orig/src/qemu/qemu_capabilities.c
> +++ libvirt/src/qemu/qemu_capabilities.c
> @@ -210,6 +210,8 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAS
>  
>                "rng-random", /* 130 */
>                "rng-egd",
> +              "tpm-passthrough",
> +              "tpm-tis",
>      );
>  
>  struct _virQEMUCaps {
> Index: libvirt/src/qemu/qemu_capabilities.h
> ===================================================================
> --- libvirt.orig/src/qemu/qemu_capabilities.h
> +++ libvirt/src/qemu/qemu_capabilities.h
> @@ -171,6 +171,8 @@ enum virQEMUCapsFlags {
>      QEMU_CAPS_OBJECT_RNG_RANDOM  = 130, /* the rng-random backend for
>                                             virtio rng */
>      QEMU_CAPS_OBJECT_RNG_EGD     = 131, /* EGD protocol daemon for rng */
> +    QEMU_CAPS_DEVICE_TPM_PASSTHROUGH = 132, /* -tpmdev passthrough */
> +    QEMU_CAPS_DEVICE_TPM_TIS     = 133, /* -device tpm_tis */

I'm wondering whether we really need to spend 2 capability bits on
this. Is it possible to build QEMU such that we have one, but not
the other ? If not then one capability would suffice

> Index: libvirt/src/qemu/qemu_monitor.c
> ===================================================================
> --- libvirt.orig/src/qemu/qemu_monitor.c
> +++ libvirt/src/qemu/qemu_monitor.c
> @@ -3522,3 +3522,47 @@ int qemuMonitorNBDServerStop(qemuMonitor
>  
>      return qemuMonitorJSONNBDServerStop(mon);
>  }
> +
> +
> +int qemuMonitorGetTPMModels(qemuMonitorPtr mon,
> +                            char ***tpmmodels)
> +{
> +    VIR_DEBUG("mon=%p tpmmodels=%p",
> +              mon, tpmmodels);
> +
> +    if (!mon) {
> +        virReportError(VIR_ERR_INVALID_ARG, "%s",
> +                       _("monitor must not be NULL"));
> +        return -1;
> +    }
> +
> +    if (!mon->json) {
> +        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
> +                       _("JSON monitor is required"));
> +        return -1;
> +    }
> +
> +    return qemuMonitorJSONGetTPMModels(mon, tpmmodels);
> +}
> +
> +
> +int qemuMonitorGetTPMTypes(qemuMonitorPtr mon,
> +                           char ***tpmtypes)
> +{
> +    VIR_DEBUG("mon=%p tpmtypes=%p",
> +              mon, tpmtypes);
> +
> +    if (!mon) {
> +        virReportError(VIR_ERR_INVALID_ARG, "%s",
> +                       _("monitor must not be NULL"));
> +        return -1;
> +    }
> +
> +    if (!mon->json) {
> +        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
> +                       _("JSON monitor is required"));
> +        return -1;
> +    }
> +
> +    return qemuMonitorJSONGetTPMTypes(mon, tpmtypes);
> +}
> Index: libvirt/src/qemu/qemu_monitor.h
> ===================================================================
> --- libvirt.orig/src/qemu/qemu_monitor.h
> +++ libvirt/src/qemu/qemu_monitor.h
> @@ -683,6 +683,12 @@ int qemuMonitorNBDServerAdd(qemuMonitorP
>                              const char *deviceID,
>                              bool writable);
>  int qemuMonitorNBDServerStop(qemuMonitorPtr);
> +int qemuMonitorGetTPMModels(qemuMonitorPtr mon,
> +                            char ***tpmmodels);
> +
> +int qemuMonitorGetTPMTypes(qemuMonitorPtr mon,
> +                           char ***tpmtypes);
> +
>  /**
>   * When running two dd process and using <> redirection, we need a
>   * shell that will not truncate files.  These two strings serve that
> Index: libvirt/src/qemu/qemu_monitor_json.c
> ===================================================================
> --- libvirt.orig/src/qemu/qemu_monitor_json.c
> +++ libvirt/src/qemu/qemu_monitor_json.c
> @@ -4707,3 +4707,94 @@ qemuMonitorJSONNBDServerStop(qemuMonitor
>      virJSONValueFree(reply);
>      return ret;
>  }
> +
> +
> +static int
> +qemuMonitorJSONGetStringArray(qemuMonitorPtr mon, const char *qmpCmd,
> +                              char ***array)
> +{
> +    int ret;
> +    virJSONValuePtr cmd;
> +    virJSONValuePtr reply = NULL;
> +    virJSONValuePtr data;
> +    char **list = NULL;
> +    int n = 0;
> +    size_t i;
> +
> +    *array = NULL;
> +
> +    if (!(cmd = qemuMonitorJSONMakeCommand(qmpCmd, NULL)))
> +        return -1;
> +
> +    ret = qemuMonitorJSONCommand(mon, cmd, &reply);
> +
> +    if (ret == 0)
> +        ret = qemuMonitorJSONCheckError(cmd, reply);
> +
> +    if (ret < 0)
> +        goto cleanup;
> +
> +    ret = -1;
> +
> +    if (!(data = virJSONValueObjectGet(reply, "return"))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("%s reply was missing return data"),
> +                       qmpCmd);
> +        goto cleanup;
> +    }

I think everything above this point should be in the main monitor APIs,
and this method concern itself solely with converting the virJSONValuePtr
into a string array, not actually executing command. This makes the code
more portable for use in commands which need control over the command
execution to handle errors / pass arguments.


> +
> +    if ((n = virJSONValueArraySize(data)) < 0) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("%s reply data was not an array"),
> +                       qmpCmd);
> +        goto cleanup;
> +    }
> +
> +    if (VIR_ALLOC_N(list, n) < 0) {
> +        virReportOOMError();
> +        goto cleanup;
> +    }
> +
> +    for (i = 0 ; i < n ; i++) {
> +        virJSONValuePtr child = virJSONValueArrayGet(data, i);
> +        const char *tmp;
> +
> +        if (!(tmp = virJSONValueGetString(child))) {
> +            virReportError(VIR_ERR_INTERNAL_ERROR,
> +                           _("%s array element does not contain data"),
> +                           qmpCmd);
> +            goto cleanup;
> +        }
> +
> +        if (!(list[i] = strdup(tmp))) {
> +            virReportOOMError();
> +            goto cleanup;
> +        }
> +    }
> +
> +    ret = n;
> +    *array = list;
> +
> +cleanup:
> +    if (ret < 0 && list) {
> +        for (i = 0 ; i < n ; i++)
> +            VIR_FREE(list[i]);
> +        VIR_FREE(list);
> +    }
> +    virJSONValueFree(cmd);
> +    virJSONValueFree(reply);
> +    return ret;
> +}
> +
> +int qemuMonitorJSONGetTPMModels(qemuMonitorPtr mon,
> +                                char ***tpmmodels)
> +{
> +    return qemuMonitorJSONGetStringArray(mon, "query-tpm-models", tpmmodels);
> +}
> +
> +
> +int qemuMonitorJSONGetTPMTypes(qemuMonitorPtr mon,
> +                               char ***tpmtypes)
> +{
> +    return qemuMonitorJSONGetStringArray(mon, "query-tpm-types", tpmtypes);
> +}

> Index: libvirt/src/libvirt_private.syms
> ===================================================================
> --- libvirt.orig/src/libvirt_private.syms
> +++ libvirt/src/libvirt_private.syms
> @@ -1886,6 +1886,7 @@ virSetUIDGIDWithCaps;
>  virSkipSpaces;
>  virSkipSpacesAndBackslash;
>  virSkipSpacesBackwards;
> +virStrArrayHasString;
>  virStrcpy;
>  virStrIsPrint;
>  virStrncpy;
> Index: libvirt/src/util/virutil.c
> ===================================================================
> --- libvirt.orig/src/util/virutil.c
> +++ libvirt/src/util/virutil.c
> @@ -3379,3 +3379,17 @@ cleanup:
>      VIR_FREE(buf);
>      return ret;
>  }
> +
> +
> +bool
> +virStrArrayHasString(char **strings, size_t n_strings, const char *needle)
> +{
> +    size_t i;
> +
> +    for (i = 0; i < n_strings; i++) {
> +        if (STREQ(strings[i], needle))
> +            return true;
> +    }
> +
> +    return false;
> +}
> Index: libvirt/src/util/virutil.h
> ===================================================================
> --- libvirt.orig/src/util/virutil.h
> +++ libvirt/src/util/virutil.h
> @@ -297,4 +297,7 @@ int virGetDeviceUnprivSGIO(const char *p
>  char * virGetUnprivSGIOSysfsPath(const char *path,
>                                   const char *sysfs_dir);
>  
> +bool virStrArrayHasString(char **strings, size_t n_strings,
> +                          const char *needle);
> +
>  #endif /* __VIR_UTIL_H__ */

The virStrArrayHasString method doesn't appear to be used in this patch.
If some other patch needs this still, then it should be a separate patch
from the monitor code.

Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|




More information about the libvir-list mailing list