Add element "quoteGenerationService" to tdx launch security type.
Currently it contains only one sub-element "SocketAddress".
"SocketAddress" is modelized according to QEMU QAPI, supporting
inet, unix, vsock and fd type and variant attributes depending
on type.
XML example:
<launchSecurity type='tdx'>
<policy>0x0</policy>
<mrConfigId>xxx</mrConfigId>
<mrOwner>xxx</mrOwner>
<mrOwnerConfig>xxx</mrOwnerConfig>
<quoteGenerationService>
<SocketAddress type='vsock' cid='xxx' port='xxx'/>
</quoteGenerationService>
</launchSecurity>
QEMU command line example:
qemu-system-x86_64 \
-object
'{"qom-type":"tdx-guest","id":"lsec0","sept-ve-disable":false,"mrconfigid":"xxx","mrowner":"xxx","mrownerconfig":"xxx","quote-generation-socket":{"type":"vsock","cid":"xxx","port":"xxx"}}'
\
-machine pc-q35-6.0,confidential-guest-support=lsec0
Signed-off-by: Zhenzhong Duan <zhenzhong.duan(a)intel.com>
---
src/conf/domain_conf.c | 272 +++++++++++++++++++++++++++++-
src/conf/domain_conf.h | 61 +++++++
src/conf/schemas/domaincommon.rng | 106 ++++++++++++
src/qemu/qemu_command.c | 106 ++++++++++++
4 files changed, 544 insertions(+), 1 deletion(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index c557da0c65..e1ae8295e5 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1511,6 +1511,15 @@ VIR_ENUM_IMPL(virDomainLaunchSecurity,
"tdx",
);
+VIR_ENUM_IMPL(virDomainSocketAddress,
+ VIR_DOMAIN_SOCKET_ADDRESS_LAST,
+ "",
+ "inet",
+ "unix",
+ "vsock",
+ "fd",
+);
+
typedef enum {
VIR_DOMAIN_NET_VHOSTUSER_MODE_NONE,
VIR_DOMAIN_NET_VHOSTUSER_MODE_CLIENT,
@@ -13654,6 +13663,190 @@ virDomainSEVDefParseXML(virDomainSEVDef *def,
}
+static int
+virDomainInetSocketAddressDefParseXML(InetSocketAddress *inet,
+ xmlNodePtr node)
+{
+ int ret;
+
+ if (!(inet->host = virXMLPropString(node, "host"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing host for inet socket address"));
+ return -1;
+ }
+
+ if (!(inet->port = virXMLPropString(node, "port"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing port for inet socket address"));
+ return -1;
+ }
+
+ if (virXMLPropTristateBool(node, "numeric", VIR_XML_PROP_NONE,
+ &inet->numeric) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("wrong attribute numeric for inet socket address"));
+ return -1;
+ }
+
+ if ((ret = virXMLPropUInt(node, "to", 10, VIR_XML_PROP_NONE,
+ &inet->to)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("wrong attribute to for inet socket address"));
+ return -1;
+ }
+ if (!ret)
+ inet->has_to = true;
+
+ if (virXMLPropTristateBool(node, "ipv4", VIR_XML_PROP_NONE,
+ &inet->ipv4) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("wrong attribute ipv4 for inet socket address"));
+ return -1;
+ }
+
+ if (virXMLPropTristateBool(node, "ipv6", VIR_XML_PROP_NONE,
+ &inet->ipv6) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("wrong attribute ipv6 for inet socket address"));
+ return -1;
+ }
+
+ if (virXMLPropTristateBool(node, "keep_alive", VIR_XML_PROP_NONE,
+ &inet->keep_alive) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("wrong attribute keep_alive for inet socket
address"));
+ return -1;
+ }
+
+ if (virXMLPropTristateBool(node, "mptcp", VIR_XML_PROP_NONE,
+ &inet->mptcp) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("wrong attribute mptcp for inet socket address"));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+virDomainUnixSocketAddressDefParseXML(UnixSocketAddress *Unix,
+ xmlNodePtr node)
+{
+ if (!(Unix->path = virXMLPropString(node, "path"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing path for unix socket address"));
+ return -1;
+ }
+
+ if (virXMLPropTristateBool(node, "abstract", VIR_XML_PROP_NONE,
+ &Unix->abstract) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("wrong attribute abstract for unix socket address"));
+ return -1;
+ }
+
+ if (virXMLPropTristateBool(node, "tight", VIR_XML_PROP_NONE,
+ &Unix->tight) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("wrong attribute tight for unix socket address"));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+virDomainVsockSocketAddressDefParseXML(VsockSocketAddress *vsock,
+ xmlNodePtr node)
+{
+ if (!(vsock->cid = virXMLPropString(node, "cid"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing cid for vsock socket address"));
+ return -1;
+ }
+
+ if (!(vsock->port = virXMLPropString(node, "port"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing port for vsock socket address"));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+virDomainFdSocketAddressDefParseXML(FdSocketAddress *fd,
+ xmlNodePtr node)
+{
+ if (!(fd->str = virXMLPropString(node, "str"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing fd for fd socket address"));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+virDomainTDXQGSDefParseXML(virDomainTDXDef *def, xmlXPathContextPtr ctxt)
+{
+ g_autofree xmlNodePtr *nodes = NULL;
+ SocketAddress *sa = &def->qgs_sa;
+ xmlNodePtr node;
+ int n;
+
+ if ((n = virXPathNodeSet("./quoteGenerationService/SocketAddress",
+ ctxt, &nodes)) < 0)
+ return -1;
+
+ if (!n)
+ return 0;
+
+ if (n > 1) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("only a single QGS element is supported"));
+ return -1;
+ }
+ node = nodes[0];
+
+ if (virXMLPropEnum(node, "type", virDomainSocketAddressTypeFromString,
+ VIR_XML_PROP_REQUIRED, &sa->type) < 0)
+ return -1;
+
+ switch ((virDomainSocketAddress) def->qgs_sa.type) {
+ case VIR_DOMAIN_SOCKET_ADDRESS_INET:
+ if (virDomainInetSocketAddressDefParseXML(&sa->u.inet, node) < 0)
+ return -1;
+ break;
+ case VIR_DOMAIN_SOCKET_ADDRESS_UNIX:
+ if (virDomainUnixSocketAddressDefParseXML(&sa->u.Unix, node) < 0)
+ return -1;
+ break;
+ case VIR_DOMAIN_SOCKET_ADDRESS_VSOCK:
+ if (virDomainVsockSocketAddressDefParseXML(&sa->u.vsock, node) < 0)
+ return -1;
+ break;
+ case VIR_DOMAIN_SOCKET_ADDRESS_FD:
+ if (virDomainFdSocketAddressDefParseXML(&sa->u.fd, node) < 0)
+ return -1;
+ break;
+ case VIR_DOMAIN_SOCKET_ADDRESS_NONE:
+ case VIR_DOMAIN_SOCKET_ADDRESS_LAST:
+ default:
+ virReportError(VIR_ERR_XML_ERROR,
+ _("unsupported socket address type '%1$s'"),
+ virDomainSocketAddressTypeToString(def->qgs_sa.type));
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int
virDomainTDXDefParseXML(virDomainTDXDef *def,
xmlXPathContextPtr ctxt)
@@ -13668,7 +13861,7 @@ virDomainTDXDefParseXML(virDomainTDXDef *def,
def->mrowner = virXPathString("string(./mrOwner)", ctxt);
def->mrownerconfig = virXPathString("string(./mrOwnerConfig)", ctxt);
- return 0;
+ return virDomainTDXQGSDefParseXML(def, ctxt);
}
@@ -26652,6 +26845,82 @@ virDomainKeyWrapDefFormat(virBuffer *buf, virDomainKeyWrapDef
*keywrap)
}
+static void
+virDomainTDXQGSDefFormat(virBuffer *buf, virDomainTDXDef *tdx)
+{
+ SocketAddress *sa = &tdx->qgs_sa;
+
+ if (sa->type == VIR_DOMAIN_SOCKET_ADDRESS_NONE)
+ return;
+
+ virBufferAddLit(buf, "<quoteGenerationService>\n");
+ virBufferAdjustIndent(buf, 2);
+ virBufferAsprintf(buf, "<SocketAddress type='%s'",
+ virDomainSocketAddressTypeToString(sa->type));
+
+ switch ((virDomainSocketAddress) sa->type) {
+ case VIR_DOMAIN_SOCKET_ADDRESS_INET:
+ {
+ InetSocketAddress *inet = &sa->u.inet;
+
+ virBufferAsprintf(buf, " host='%s' port='%s'",
inet->host, inet->port);
+ if (inet->numeric != VIR_TRISTATE_BOOL_ABSENT)
+ virBufferAsprintf(buf, " numeric='%s'",
+ virTristateBoolTypeToString(inet->numeric));
+ if (inet->to)
+ virBufferAsprintf(buf, " to='%d'", inet->to);
+ if (inet->ipv4 != VIR_TRISTATE_BOOL_ABSENT)
+ virBufferAsprintf(buf, " ipv4='%s'",
+ virTristateBoolTypeToString(inet->ipv4));
+ if (inet->ipv6 != VIR_TRISTATE_BOOL_ABSENT)
+ virBufferAsprintf(buf, " ipv6='%s'",
+ virTristateBoolTypeToString(inet->ipv6));
+ if (inet->keep_alive != VIR_TRISTATE_BOOL_ABSENT)
+ virBufferAsprintf(buf, " keep_alive='%s'",
+ virTristateBoolTypeToString(inet->keep_alive));
+ if (inet->mptcp != VIR_TRISTATE_BOOL_ABSENT)
+ virBufferAsprintf(buf, " mptcp='%s'",
+ virTristateBoolTypeToString(inet->mptcp));
+ break;
+ }
+ case VIR_DOMAIN_SOCKET_ADDRESS_UNIX:
+ {
+ UnixSocketAddress *Unix = &sa->u.Unix;
+
+ virBufferAsprintf(buf, " path='%s'", Unix->path);
+ if (Unix->abstract != VIR_TRISTATE_BOOL_ABSENT)
+ virBufferAsprintf(buf, " abstract='%s'",
+ virTristateBoolTypeToString(Unix->abstract));
+ if (Unix->tight != VIR_TRISTATE_BOOL_ABSENT)
+ virBufferAsprintf(buf, " tight='%s'",
+ virTristateBoolTypeToString(Unix->tight));
+ break;
+ }
+ case VIR_DOMAIN_SOCKET_ADDRESS_VSOCK:
+ {
+ VsockSocketAddress *vsock = &sa->u.vsock;
+
+ virBufferAsprintf(buf, " cid='%s' port='%s'",
vsock->cid, vsock->port);
+ break;
+ }
+ case VIR_DOMAIN_SOCKET_ADDRESS_FD:
+ {
+ FdSocketAddress *fd = &sa->u.fd;
+
+ virBufferAsprintf(buf, " str='%s'", fd->str);
+ break;
+ }
+ case VIR_DOMAIN_SOCKET_ADDRESS_NONE:
+ case VIR_DOMAIN_SOCKET_ADDRESS_LAST:
+ default:
+ break;
+ }
+ virBufferAddLit(buf, "/>\n");
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</quoteGenerationService>\n");
+}
+
+
static void
virDomainSecDefFormat(virBuffer *buf, virDomainSecDef *sec)
{
@@ -26699,6 +26968,7 @@ virDomainSecDefFormat(virBuffer *buf, virDomainSecDef *sec)
virBufferEscapeString(&childBuf,
"<mrOwner>%s</mrOwner>\n", tdx->mrowner);
if (tdx->mrownerconfig)
virBufferEscapeString(&childBuf,
"<mrOwnerConfig>%s</mrOwnerConfig>\n", tdx->mrownerconfig);
+ virDomainTDXQGSDefFormat(&childBuf, tdx);
break;
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index bb4973fce8..15cdb3e0e6 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2852,6 +2852,55 @@ struct _virDomainKeyWrapDef {
virTristateSwitch dea;
};
+typedef enum {
+ VIR_DOMAIN_SOCKET_ADDRESS_NONE,
+ VIR_DOMAIN_SOCKET_ADDRESS_INET,
+ VIR_DOMAIN_SOCKET_ADDRESS_UNIX,
+ VIR_DOMAIN_SOCKET_ADDRESS_VSOCK,
+ VIR_DOMAIN_SOCKET_ADDRESS_FD,
+
+ VIR_DOMAIN_SOCKET_ADDRESS_LAST
+} virDomainSocketAddress;
+
+typedef struct _InetSocketAddress InetSocketAddress;
+typedef struct _UnixSocketAddress UnixSocketAddress;
+typedef struct _VsockSocketAddress VsockSocketAddress;
+typedef struct _FdSocketAddress FdSocketAddress;
+
+struct _InetSocketAddress {
+ char *host;
+ char *port;
+ bool has_numeric;
+ virTristateBool numeric;
+ bool has_to;
+ unsigned int to;
+ bool has_ipv4;
+ virTristateBool ipv4;
+ bool has_ipv6;
+ virTristateBool ipv6;
+ bool has_keep_alive;
+ virTristateBool keep_alive;
+ bool has_mptcp;
+ virTristateBool mptcp;
+};
+
+struct _UnixSocketAddress {
+ char *path;
+ bool has_abstract;
+ virTristateBool abstract;
+ bool has_tight;
+ virTristateBool tight;
+};
+
+struct _VsockSocketAddress {
+ char *cid;
+ char *port;
+};
+
+struct _FdSocketAddress {
+ char *str;
+};
+
typedef enum {
VIR_DOMAIN_LAUNCH_SECURITY_NONE,
VIR_DOMAIN_LAUNCH_SECURITY_SEV,
@@ -2873,11 +2922,22 @@ struct _virDomainSEVDef {
virTristateBool kernel_hashes;
};
+typedef struct SocketAddress {
+ virDomainSocketAddress type;
+ union {
+ InetSocketAddress inet;
+ UnixSocketAddress Unix;
+ VsockSocketAddress vsock;
+ FdSocketAddress fd;
+ } u;
+} SocketAddress;
+
struct _virDomainTDXDef {
unsigned long long policy;
char *mrconfigid;
char *mrowner;
char *mrownerconfig;
+ SocketAddress qgs_sa;
};
#define VIR_DOMAIN_TDX_POLICY_DEBUG 0x1
@@ -4258,6 +4318,7 @@ VIR_ENUM_DECL(virDomainCryptoBackend);
VIR_ENUM_DECL(virDomainShmemModel);
VIR_ENUM_DECL(virDomainShmemRole);
VIR_ENUM_DECL(virDomainLaunchSecurity);
+VIR_ENUM_DECL(virDomainSocketAddress);
/* from libvirt.h */
VIR_ENUM_DECL(virDomainState);
VIR_ENUM_DECL(virDomainNostateReason);
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
index f6e1782b33..e8cc78992a 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -591,9 +591,115 @@
<data type="string"/>
</element>
</optional>
+ <optional>
+ <element name="quoteGenerationService">
+ <ref name="SocketAddress"/>
+ </element>
+ </optional>
</interleave>
</define>
+ <define name="SocketAddress">
+ <element name="SocketAddress">
+ <choice>
+ <group>
+ <ref name="InetSocketAddress"/>
+ </group>
+ <group>
+ <ref name="UnixSocketAddress"/>
+ </group>
+ <group>
+ <ref name="VsockSocketAddress"/>
+ </group>
+ <group>
+ <ref name="FdSocketAddress"/>
+ </group>
+ </choice>
+ </element>
+ </define>
+
+ <define name="InetSocketAddress">
+ <attribute name="type">
+ <value>inet</value>
+ </attribute>
+ <attribute name="host">
+ <data type="string"/>
+ </attribute>
+ <attribute name="port">
+ <data type="string"/>
+ </attribute>
+ <optional>
+ <attribute name="numeric">
+ <ref name="virYesNo"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="to">
+ <ref name="uint16"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="ipv4">
+ <ref name="virYesNo"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="ipv6">
+ <ref name="virYesNo"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="keep_alive">
+ <ref name="virYesNo"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="mptcp">
+ <ref name="virYesNo"/>
+ </attribute>
+ </optional>
+ </define>
+
+ <define name="UnixSocketAddress">
+ <attribute name="type">
+ <value>unix</value>
+ </attribute>
+ <attribute name="path">
+ <data type="string"/>
+ </attribute>
+ <optional>
+ <attribute name="abstract">
+ <ref name="virYesNo"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="tight">
+ <ref name="virYesNo"/>
+ </attribute>
+ </optional>
+ </define>
+
+ <define name="VsockSocketAddress">
+ <attribute name="type">
+ <value>vsock</value>
+ </attribute>
+ <attribute name="cid">
+ <data type="string"/>
+ </attribute>
+ <attribute name="port">
+ <data type="string"/>
+ </attribute>
+ </define>
+
+ <define name="FdSocketAddress">
+ <attribute name="type">
+ <value>fd</value>
+ </attribute>
+ <attribute name="str">
+ <data type="string"/>
+ </attribute>
+ </define>
+
<!--
Enable or disable perf events for the domain. For each
of the events the following rules apply:
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index d212d80038..05fec05cd5 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -9745,21 +9745,127 @@ qemuBuildPVCommandLine(virDomainObj *vm, virCommand *cmd)
}
+static virJSONValue *
+qemuJSONBuildInetSocketAddress(const InetSocketAddress *inet)
+{
+ g_autoptr(virJSONValue) addr = NULL;
+ g_autoptr(virJSONValue) data = NULL;
+
+ if (virJSONValueObjectAdd(&addr,
+ "s:type", "inet",
+ "s:host", inet->host,
+ "s:port", inet->port,
+ "T:numeric", inet->numeric,
+ "p:to", inet->to,
+ "T:ipv4", inet->ipv4,
+ "T:ipv6", inet->ipv6,
+ "T:keep-alive", inet->keep_alive,
+ "T:mptcp", inet->mptcp,
+ NULL) < 0)
+ return NULL;
+
+ return g_steal_pointer(&addr);
+}
+
+
+static virJSONValue *
+qemuJSONBuildUnixSocketAddress(const UnixSocketAddress *Unix)
+{
+ g_autoptr(virJSONValue) addr = NULL;
+ g_autoptr(virJSONValue) data = NULL;
+
+ if (virJSONValueObjectAdd(&addr,
+ "s:type", "unix",
+ "s:path", Unix->path,
+ "T:abstract", Unix->abstract,
+ "T:tight", Unix->tight,
+ NULL) < 0)
+ return NULL;
+
+ return g_steal_pointer(&addr);
+}
+
+
+static virJSONValue *
+qemuJSONBuildVsockSocketAddress(const VsockSocketAddress *vsock)
+{
+ g_autoptr(virJSONValue) addr = NULL;
+ g_autoptr(virJSONValue) data = NULL;
+
+ if (virJSONValueObjectAdd(&addr,
+ "s:type", "vsock",
+ "s:cid", vsock->cid,
+ "s:port", vsock->port,
+ NULL) < 0)
+ return NULL;
+
+ return g_steal_pointer(&addr);
+}
+
+
+static virJSONValue *
+qemuJSONBuildFdSocketAddress(const FdSocketAddress *fd)
+{
+ g_autoptr(virJSONValue) addr = NULL;
+ g_autoptr(virJSONValue) data = NULL;
+
+ if (virJSONValueObjectAdd(&addr,
+ "s:type", "fd",
+ "s:str", fd->str,
+ NULL) < 0)
+ return NULL;
+
+ return g_steal_pointer(&addr);
+}
+
+
+static virJSONValue *
+qemuBuildTDXQGSCommandLine(virDomainTDXDef *tdx)
+{
+ g_autoptr(virJSONValue) addr = NULL;
+
+ switch ((virDomainSocketAddress) tdx->qgs_sa.type) {
+ case VIR_DOMAIN_SOCKET_ADDRESS_INET:
+ addr = qemuJSONBuildInetSocketAddress(&tdx->qgs_sa.u.inet);
+ break;
+ case VIR_DOMAIN_SOCKET_ADDRESS_UNIX:
+ addr = qemuJSONBuildUnixSocketAddress(&tdx->qgs_sa.u.Unix);
+ break;
+ case VIR_DOMAIN_SOCKET_ADDRESS_VSOCK:
+ addr = qemuJSONBuildVsockSocketAddress(&tdx->qgs_sa.u.vsock);
+ break;
+ case VIR_DOMAIN_SOCKET_ADDRESS_FD:
+ addr = qemuJSONBuildFdSocketAddress(&tdx->qgs_sa.u.fd);
+ break;
+ case VIR_DOMAIN_SOCKET_ADDRESS_NONE:
+ case VIR_DOMAIN_SOCKET_ADDRESS_LAST:
+ default:
+ return NULL;
+ }
+
+ return g_steal_pointer(&addr);
+}
+
+
static int
qemuBuildTDXCommandLine(virDomainObj *vm, virCommand *cmd,
virDomainTDXDef *tdx)
{
+ g_autoptr(virJSONValue) addr = NULL;
g_autoptr(virJSONValue) props = NULL;
qemuDomainObjPrivate *priv = vm->privateData;
bool sept_ve_disable = tdx->policy & VIR_DOMAIN_TDX_POLICY_SEPT_VE_DISABLE;
VIR_DEBUG("policy=0x%llx", tdx->policy);
+ addr = qemuBuildTDXQGSCommandLine(tdx);
+
if (qemuMonitorCreateObjectProps(&props, "tdx-guest",
"lsec0",
"B:debug", !!(tdx->policy &
VIR_DOMAIN_TDX_POLICY_DEBUG),
"S:mrconfigid", tdx->mrconfigid,
"S:mrowner", tdx->mrowner,
"S:mrownerconfig", tdx->mrownerconfig,
+ "A:quote-generation-socket", &addr,
NULL) < 0)
return -1;
--
2.34.1