On Wed, Mar 13, 2013 at 12:03:50PM -0400, Stefan Berger wrote: > Parse the domain XML with TPM support. > > Convert the strings from QEMU's QMP TPM commands into > capability flags. > > Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxxxxxxxxxx> > > --- > docs/schemas/domaincommon.rng | 43 ++++++ > src/conf/domain_conf.c | 268 ++++++++++++++++++++++++++++++++++++++++++ > src/conf/domain_conf.h | 34 +++++ > src/libvirt_private.syms | 5 > src/qemu/qemu_capabilities.c | 59 +++++++++ > 5 files changed, 409 insertions(+) The QEMU changes should be a separate patch from any XML schema changes. > @@ -1515,6 +1522,24 @@ void virDomainHostdevDefClear(virDomainH > } > } > > +void virDomainTPMDefFree(virDomainTPMDefPtr def) > +{ > + if (!def) > + return; > + > + switch (def->type) { > + case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH: > + VIR_FREE(def->data.passthrough.path); > + VIR_FREE(def->data.passthrough.cancel_path); > + break; > + case VIR_DOMAIN_TPM_TYPE_LAST: > + break; > + } > + > + virDomainDeviceInfoClear(&def->info); > + VIR_FREE(def); > +} > + > void virDomainHostdevDefFree(virDomainHostdevDefPtr def) > { > if (!def) > @@ -1776,6 +1801,8 @@ void virDomainDefFree(virDomainDefPtr de > > virDomainRNGDefFree(def->rng); > > + virDomainTPMDefFree(def->tpm); > + > VIR_FREE(def->os.type); > VIR_FREE(def->os.machine); > VIR_FREE(def->os.init); > @@ -6312,6 +6339,192 @@ error: > goto cleanup; > } > > +/* > + * Check whether the given base path, e.g., /sys/class/misc/tpm0/device, > + * is the sysfs entry of a TPM. A TPM sysfs entry should be uniquely > + * recognizable by the file entries 'pcrs' and 'cancel'. > + * Upon success 'true' is returned and the basebath buffer has '/cancel' > + * appended. > + */ > +static bool > +virDomainTPMCheckSysfsCancel(char *basepath, size_t bufsz) > +{ > + char *path = NULL; > + struct stat statbuf; > + > + if (virAsprintf(&path, "%s/pcrs", basepath) < 0) { > + virReportOOMError(); > + goto error; > + } > + if (stat(path, &statbuf) == -1 || !S_ISREG(statbuf.st_mode)) > + goto error; > + > + VIR_FREE(path); > + > + if (virAsprintf(&path, "%s/cancel", basepath) < 0) { > + virReportOOMError(); > + goto error; > + } > + > + if (stat(path, &statbuf) == -1 || !S_ISREG(statbuf.st_mode)) > + goto error; > + > + if (!virStrncpy(basepath, path, strlen(path) + 1, bufsz)) { > + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", > + _("Basepath buffer is too small")); > + goto error; > + } > + > + VIR_FREE(path); > + > + return true; > + > +error: > + VIR_FREE(path); > + return false; > +} > + > + > +static char * > +virDomainTPMFindCancelPath(void) > +{ > + unsigned int idx; > + int len; > + DIR *pnp_dir; > + char path[100], *p; > + struct dirent entry, *result; > + bool found = false; > + > + snprintf(path, sizeof(path), "/sys/class/misc"); > + pnp_dir = opendir(path); > + if (pnp_dir != NULL) { > + while (readdir_r(pnp_dir, &entry, &result) == 0 && > + result != NULL) { > + if (sscanf(entry.d_name, "tpm%u%n", &idx, &len) < 1 || > + len <= strlen("tpm") || > + len != strlen(entry.d_name)) { > + continue; > + } > + snprintf(path, sizeof(path), "/sys/class/misc/%s/device", > + entry.d_name); > + if (!virDomainTPMCheckSysfsCancel(path, sizeof(path))) { > + continue; > + } > + > + found = true; > + break; > + } > + closedir(pnp_dir); > + } > + > + if (found) { > + if (!(p = strdup(path))) > + virReportOOMError(); > + return p; > + } > + > + return NULL; > +} These two funtions have nothing todo with the XML schema so should not be in this file. Either some helper file in src/util or in the QEMU code. > + switch (def->type) { > + case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH: > + path = virXPathString("string(./backend/device/@path)", ctxt); > + if (!path && !(path = strdup(VIR_DOMAIN_TPM_DEFAULT_DEVICE))) { > + virReportOOMError(); > + goto error; > + } > + def->data.passthrough.path = path; > + path = NULL; > + /* cancel_path is read-only */ > + def->data.passthrough.cancel_path = virDomainTPMFindCancelPath(); This data is driver specific state so should not be in the XML schema structs - it should be in QEMU code where needed > +# define VIR_DOMAIN_TPM_DEFAULT_DEVICE "/dev/tpm0" > + > +typedef struct _virDomainTPMDef virDomainTPMDef; > +typedef virDomainTPMDef *virDomainTPMDefPtr; > +struct _virDomainTPMDef { > + enum virDomainTPMBackendType type; > + virDomainDeviceInfo info; > + enum virDomainTPMModel model; > + union { > + struct { > + char *path; > + char *cancel_path; Per previous comments 'cancel_path' should not be in this struct. > + } passthrough; > + } data; > +}; > + > Index: libvirt/src/qemu/qemu_capabilities.c > =================================================================== > --- libvirt.orig/src/qemu/qemu_capabilities.c > +++ libvirt/src/qemu/qemu_capabilities.c > @@ -2110,6 +2110,63 @@ virQEMUCapsProbeQMPCPUDefinitions(virQEM > > > static int > +virQEMUCapsProbeQMPTPM(virQEMUCapsPtr qemuCaps, > + qemuMonitorPtr mon) > +{ > + int nentries, i; > + char **entries = NULL; > + struct typeToCaps { > + int type; > + enum virQEMUCapsFlags caps; > + }; > + const struct typeToCaps tpmTypesToCaps[] = { > + { > + .type = VIR_DOMAIN_TPM_TYPE_PASSTHROUGH, > + .caps = QEMU_CAPS_DEVICE_TPM_PASSTHROUGH, > + }, > + }; > + const struct typeToCaps tpmModelsToCaps[] = { > + { > + .type = VIR_DOMAIN_TPM_MODEL_TIS, > + .caps = QEMU_CAPS_DEVICE_TPM_TIS, > + }, > + }; > + > + if ((nentries = qemuMonitorGetTPMModels(mon, &entries)) < 0) > + return -1; > + > + if (nentries > 0) { > + for (i = 0; i < ARRAY_CARDINALITY(tpmModelsToCaps); i++) { > + const char *needle = virDomainTPMModelTypeToString( > + tpmModelsToCaps[i].type); > + if (virStrArrayHasString(entries, nentries, needle)) > + virQEMUCapsSet(qemuCaps, tpmModelsToCaps[i].caps); > + } > + for (i = 0; i < nentries; i++) > + VIR_FREE(entries[i]); If you make the monitor commands return a NULL terminated list, you can just use virStringFreeList. This also avoids the need to pass around 'nentries'; to virStrArrayHasString. 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 :| -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list