Parse TPM passthrough XML in the domain XML

Parse the domain XML with TPM passthrough support.
The TPM passthrough XML may look like this:

    <tpm model='tpm-tis'>
      <backend type='passthrough'>
        <device path='/dev/tpm0'/>
      </backend>
    </tpm>


Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Tested-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
This commit is contained in:
Stefan Berger 2013-04-12 16:55:45 -04:00 committed by Stefan Berger
parent 06ba4bff91
commit 6ecff413e1
3 changed files with 215 additions and 0 deletions

View File

@ -51,6 +51,7 @@
#include "netdev_bandwidth_conf.h"
#include "netdev_vlan_conf.h"
#include "device_conf.h"
#include "virtpm.h"
#define VIR_FROM_THIS VIR_FROM_DOMAIN
@ -721,6 +722,13 @@ VIR_ENUM_IMPL(virDomainRNGBackend,
"random",
"egd");
VIR_ENUM_IMPL(virDomainTPMModel, VIR_DOMAIN_TPM_MODEL_LAST,
"tpm-tis")
VIR_ENUM_IMPL(virDomainTPMBackend, VIR_DOMAIN_TPM_TYPE_LAST,
"passthrough")
#define VIR_DOMAIN_XML_WRITE_FLAGS VIR_DOMAIN_XML_SECURE
#define VIR_DOMAIN_XML_READ_FLAGS VIR_DOMAIN_XML_INACTIVE
@ -1619,6 +1627,23 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
}
}
void virDomainTPMDefFree(virDomainTPMDefPtr def)
{
if (!def)
return;
switch (def->type) {
case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
VIR_FREE(def->data.passthrough.source.data.file.path);
break;
case VIR_DOMAIN_TPM_TYPE_LAST:
break;
}
virDomainDeviceInfoClear(&def->info);
VIR_FREE(def);
}
void virDomainHostdevDefFree(virDomainHostdevDefPtr def)
{
if (!def)
@ -1880,6 +1905,8 @@ void virDomainDefFree(virDomainDefPtr def)
virDomainRNGDefFree(def->rng);
virDomainTPMDefFree(def->tpm);
VIR_FREE(def->os.type);
VIR_FREE(def->os.machine);
VIR_FREE(def->os.init);
@ -6771,6 +6798,103 @@ error:
goto cleanup;
}
/* Parse the XML definition for a TPM device
*
* The XML looks like this:
*
* <tpm model='tpm-tis'>
* <backend type='passthrough'>
* <device path='/dev/tpm0'/>
* </backend>
* </tpm>
*
*/
static virDomainTPMDefPtr
virDomainTPMDefParseXML(const xmlNodePtr node,
xmlXPathContextPtr ctxt,
unsigned int flags)
{
char *type = NULL;
char *path = NULL;
char *model = NULL;
char *backend = NULL;
virDomainTPMDefPtr def;
xmlNodePtr save = ctxt->node;
xmlNodePtr *backends = NULL;
int nbackends;
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
return NULL;
}
model = virXMLPropString(node, "model");
if (model != NULL &&
(int)(def->model = virDomainTPMModelTypeFromString(model)) < 0) {
virReportError(VIR_ERR_INVALID_ARG,
_("Unknown TPM frontend model '%s'"), model);
goto error;
} else {
def->model = VIR_DOMAIN_TPM_MODEL_TIS;
}
ctxt->node = node;
if ((nbackends = virXPathNodeSet("./backend", ctxt, &backends)) < 0)
goto error;
if (nbackends > 1) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("only one TPM backend is supported"));
goto error;
}
if (!(backend = virXMLPropString(backends[0], "type"))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("missing TPM device backend type"));
goto error;
}
if ((int)(def->type = virDomainTPMBackendTypeFromString(backend)) < 0) {
virReportError(VIR_ERR_XML_ERROR,
_("Unknown TPM backend type '%s'"),
backend);
goto error;
}
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.source.data.file.path = path;
def->data.passthrough.source.type = VIR_DOMAIN_CHR_TYPE_DEV;
path = NULL;
break;
case VIR_DOMAIN_TPM_TYPE_LAST:
goto error;
}
if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
goto error;
cleanup:
VIR_FREE(type);
VIR_FREE(path);
VIR_FREE(model);
VIR_FREE(backend);
VIR_FREE(backends);
ctxt->node = save;
return def;
error:
virDomainTPMDefFree(def);
def = NULL;
goto cleanup;
}
/* Parse the XML definition for an input device */
static virDomainInputDefPtr
virDomainInputDefParseXML(const char *ostype,
@ -11099,6 +11223,23 @@ virDomainDefParseXML(xmlDocPtr xml,
goto error;
VIR_FREE(nodes);
}
VIR_FREE(nodes);
/* Parse the TPM devices */
if ((n = virXPathNodeSet("./devices/tpm", ctxt, &nodes)) < 0)
goto error;
if (n > 1) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("only a single TPM device is supported"));
goto error;
}
if (n > 0) {
if (!(def->tpm = virDomainTPMDefParseXML(nodes[0], ctxt, flags)))
goto error;
}
VIR_FREE(nodes);
/* analysis of the hub devices */
if ((n = virXPathNodeSet("./devices/hub", ctxt, &nodes)) < 0) {
@ -14082,6 +14223,39 @@ virDomainSoundCodecDefFormat(virBufferPtr buf,
return 0;
}
static int
virDomainTPMDefFormat(virBufferPtr buf,
virDomainTPMDefPtr def,
unsigned int flags)
{
virBufferAsprintf(buf, " <tpm model='%s'>\n",
virDomainTPMModelTypeToString(def->model));
virBufferAsprintf(buf, " <backend type='%s'>\n",
virDomainTPMBackendTypeToString(def->type));
switch (def->type) {
case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
virBufferEscapeString(buf, " <device path='%s'/>\n",
def->data.passthrough.source.data.file.path);
break;
case VIR_DOMAIN_TPM_TYPE_LAST:
break;
}
virBufferAddLit(buf, " </backend>\n");
if (virDomainDeviceInfoIsSet(&def->info, flags)) {
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
return -1;
}
virBufferAddLit(buf, " </tpm>\n");
return 0;
}
static int
virDomainSoundDefFormat(virBufferPtr buf,
virDomainSoundDefPtr def,
@ -15408,6 +15582,11 @@ virDomainDefFormatInternal(virDomainDefPtr def,
virDomainInputDefFormat(buf, def->inputs[n], flags) < 0)
goto error;
if (def->tpm) {
if (virDomainTPMDefFormat(buf, def->tpm, flags) < 0)
goto error;
}
if (def->ngraphics > 0) {
/* If graphics is enabled, add the implicit mouse */
virDomainInputDef autoInput = {

View File

@ -1097,6 +1097,33 @@ struct _virDomainHubDef {
virDomainDeviceInfo info;
};
enum virDomainTPMModel {
VIR_DOMAIN_TPM_MODEL_TIS,
VIR_DOMAIN_TPM_MODEL_LAST
};
enum virDomainTPMBackendType {
VIR_DOMAIN_TPM_TYPE_PASSTHROUGH,
VIR_DOMAIN_TPM_TYPE_LAST
};
# 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 {
virDomainChrSourceDef source;
} passthrough;
} data;
};
enum virDomainInputType {
VIR_DOMAIN_INPUT_TYPE_MOUSE,
VIR_DOMAIN_INPUT_TYPE_TABLET,
@ -1883,6 +1910,7 @@ struct _virDomainDef {
/* Only 1 */
virDomainWatchdogDefPtr watchdog;
virDomainMemballoonDefPtr memballoon;
virDomainTPMDefPtr tpm;
virCPUDefPtr cpu;
virSysinfoDefPtr sysinfo;
virDomainRedirFilterDefPtr redirfilter;
@ -2062,6 +2090,7 @@ void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info);
void virDomainDefClearPCIAddresses(virDomainDefPtr def);
void virDomainDefClearCCWAddresses(virDomainDefPtr def);
void virDomainDefClearDeviceAliases(virDomainDefPtr def);
void virDomainTPMDefFree(virDomainTPMDefPtr def);
typedef int (*virDomainDeviceInfoCallback)(virDomainDefPtr def,
virDomainDeviceDefPtr dev,
@ -2433,6 +2462,8 @@ VIR_ENUM_DECL(virDomainGraphicsSpiceMouseMode)
VIR_ENUM_DECL(virDomainHyperv)
VIR_ENUM_DECL(virDomainRNGModel)
VIR_ENUM_DECL(virDomainRNGBackend)
VIR_ENUM_DECL(virDomainTPMModel)
VIR_ENUM_DECL(virDomainTPMBackend)
/* from libvirt.h */
VIR_ENUM_DECL(virDomainState)
VIR_ENUM_DECL(virDomainNostateReason)

View File

@ -320,6 +320,11 @@ virDomainTimerTickpolicyTypeFromString;
virDomainTimerTickpolicyTypeToString;
virDomainTimerTrackTypeFromString;
virDomainTimerTrackTypeToString;
virDomainTPMBackendTypeFromString;
virDomainTPMBackendTypeToString;
virDomainTPMDefFree;
virDomainTPMModelTypeFromString;
virDomainTPMModelTypeToString;
virDomainVcpuPinAdd;
virDomainVcpuPinDefArrayFree;
virDomainVcpuPinDefCopy;