diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c
index f6e09dc5848fd339af8644f9db2915e4dcb8b3a6..f390ad9fef2e66274399c399e1713cb44a7cf548 100644
--- a/src/conf/domain_capabilities.c
+++ b/src/conf/domain_capabilities.c
@@ -88,6 +88,16 @@ virSGXCapabilitiesFree(virSGXCapability *cap)
}
+void
+virVIRTCCACapabilitiesFree(virVIRTCCACapability *cap)
+{
+ if (!cap)
+ return;
+
+ g_free(cap);
+}
+
+
static void
virDomainCapsDispose(void *obj)
{
@@ -101,6 +111,7 @@ virDomainCapsDispose(void *obj)
virCPUDefFree(caps->cpu.hostModel);
virSEVCapabilitiesFree(caps->sev);
virSGXCapabilitiesFree(caps->sgx);
+ virVIRTCCACapabilitiesFree(caps->virtcca);
g_free(caps->hyperv);
values = &caps->os.loader.values;
@@ -707,6 +718,29 @@ virDomainCapsFeatureHypervFormat(virBuffer *buf,
FORMAT_EPILOGUE(hyperv);
}
+/**
+ * virDomainCapsFeatureVIRTCCAFormat:
+ * @buf: target buffer
+ * @virtcca: VIRTCCA features
+ *
+ * Format VIRTCCA features for inclusion in the domcapabilities XML.
+ *
+ * The resulting XML will look like
+ *
+ *
+ */
+static void
+virDomainCapsFeatureVIRTCCAFormat(virBuffer *buf,
+ const virVIRTCCACapability *virtcca)
+{
+ if (!virtcca) {
+ virBufferAddLit(buf, "\n");
+ return;
+ }
+
+ virBufferAddLit(buf, "\n");
+}
+
static void
virDomainCapsFormatFeatures(const virDomainCaps *caps,
virBuffer *buf)
diff --git a/src/conf/domain_capabilities.h b/src/conf/domain_capabilities.h
index 01bcfa2e395d470b15ab39c9023f099458219a96..718fb75467b256ee8621ea3bf1793f648cb3b3e6 100644
--- a/src/conf/domain_capabilities.h
+++ b/src/conf/domain_capabilities.h
@@ -231,6 +231,11 @@ struct _virSGXCapability {
virSGXSection *sgxSections;
};
+typedef struct _virVIRTCCACapability virVIRTCCACapability;
+struct _virVIRTCCACapability {
+ bool enabled;
+};
+
STATIC_ASSERT_ENUM(VIR_DOMAIN_CRYPTO_MODEL_LAST);
STATIC_ASSERT_ENUM(VIR_DOMAIN_CRYPTO_TYPE_LAST);
STATIC_ASSERT_ENUM(VIR_DOMAIN_CRYPTO_BACKEND_LAST);
@@ -284,6 +289,7 @@ struct _virDomainCaps {
virSEVCapability *sev;
virSGXCapability *sgx;
virDomainCapsFeatureHyperv *hyperv;
+ virVIRTCCACapability *virtcca;
/* add new domain features here */
virTristateBool features[VIR_DOMAIN_CAPS_FEATURE_LAST];
@@ -339,3 +345,8 @@ void
virSGXCapabilitiesFree(virSGXCapability *capabilities);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virSGXCapability, virSGXCapabilitiesFree);
+
+void
+virVIRTCCACapabilitiesFree(virVIRTCCACapability *capabilities);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(virVIRTCCACapability, virVIRTCCACapabilitiesFree);
\ No newline at end of file
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 4d712f0d79efdabda165240d429d50208f00b6ce..cd99cc302ac644cd1fd780ddd04dc41bede89f0f 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -218,6 +218,7 @@ virDomainCapsFormat;
virDomainCapsNew;
virSEVCapabilitiesFree;
virSGXCapabilitiesFree;
+virVIRTCCACapabilitiesFree;
# conf/domain_conf.h
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 79414becfdc36829c1d4aadbda7764cd6560fc14..e19e5a87c517ed8bbc922a711418643a6d54be2e 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -699,6 +699,7 @@ VIR_ENUM_IMPL(virQEMUCaps,
"run-with.async-teardown", /* QEMU_CAPS_RUN_WITH_ASYNC_TEARDOWN */
"virtio-blk-vhost-vdpa", /* QEMU_CAPS_DEVICE_VIRTIO_BLK_VHOST_VDPA */
"smp-clusters", /* QEMU_CAPS_SMP_CLUSTERS */
+ "virtcca", /* QEMU_CAPS_VIRTCCA */
);
@@ -784,6 +785,8 @@ struct _virQEMUCaps {
virSGXCapability *sgxCapabilities;
+ virVIRTCCACapability *virtccaCapabilities;
+
virDomainCapsFeatureHyperv *hypervCapabilities;
/* Capabilities which may differ depending on the accelerator. */
@@ -1387,6 +1390,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = {
{ "virtio-crypto-device", QEMU_CAPS_DEVICE_VIRTIO_CRYPTO },
{ "cryptodev-backend-lkcf", QEMU_CAPS_OBJECT_CRYPTO_LKCF },
{ "pvpanic-pci", QEMU_CAPS_DEVICE_PANIC_PCI },
+ { "virtcca", QEMU_CAPS_VIRTCCA },
};
@@ -1910,6 +1914,25 @@ virQEMUCapsSGXInfoCopy(virSGXCapability **dst,
}
+static void
+virQEMUCapsVIRTCCAInfoCopy(virVIRTCCACapability **dst,
+ virVIRTCCACapability *src)
+{
+ g_autoptr(virVIRTCCACapability) tmp = NULL;
+
+ if (!src) {
+ *dst = NULL;
+ return;
+ }
+
+ tmp = g_new0(virVIRTCCACapability, 1);
+
+ tmp->enabled = src->enabled;
+
+ *dst = g_steal_pointer(&tmp);
+}
+
+
static void
virQEMUCapsAccelCopyMachineTypes(virQEMUCapsAccel *dst,
virQEMUCapsAccel *src)
@@ -1985,6 +2008,9 @@ virQEMUCaps *virQEMUCapsNewCopy(virQEMUCaps *qemuCaps)
if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_SGX_EPC))
virQEMUCapsSGXInfoCopy(&ret->sgxCapabilities, qemuCaps->sgxCapabilities);
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTCCA))
+ virQEMUCapsVIRTCCAInfoCopy(&ret->virtccaCapabilities, qemuCaps->virtccaCapabilities);
+
ret->hypervCapabilities = g_memdup(qemuCaps->hypervCapabilities,
sizeof(virDomainCapsFeatureHyperv));
@@ -2027,6 +2053,7 @@ void virQEMUCapsDispose(void *obj)
virSEVCapabilitiesFree(qemuCaps->sevCapabilities);
virSGXCapabilitiesFree(qemuCaps->sgxCapabilities);
+ virVIRTCCACapabilitiesFree(qemuCaps->virtccaCapabilities);
g_free(qemuCaps->hypervCapabilities);
@@ -3479,6 +3506,31 @@ virQEMUCapsProbeQMPSGXCapabilities(virQEMUCaps *qemuCaps,
}
+static int
+virQEMUCapsProbeQMPVIRTCCACapabilities(virQEMUCaps *qemuCaps,
+ qemuMonitor *mon)
+{
+ int rc = -1;
+ virVIRTCCACapability *caps = NULL;
+
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTCCA))
+ return 0;
+
+ if ((rc = qemuMonitorGetVIRTCCACapabilities(mon, &caps)) < 0)
+ return -1;
+
+ /* VIRTCCA isn't actually supported */
+ if (rc == 0) {
+ virQEMUCapsClear(qemuCaps, QEMU_CAPS_VIRTCCA);
+ return 0;
+ }
+
+ virVIRTCCACapabilitiesFree(qemuCaps->virtccaCapabilities);
+ qemuCaps->virtccaCapabilities = caps;
+ return 0;
+}
+
+
/*
* Filter for features which should never be passed to QEMU. Either because
* QEMU never supported them or they were dropped as they never did anything
@@ -4350,6 +4402,34 @@ virQEMUCapsParseSGXInfo(virQEMUCaps *qemuCaps,
}
+static int
+virQEMUCapsParseVIRTCCAInfo(virQEMUCaps *qemuCaps,
+ xmlXPathContextPtr ctxt)
+{
+ g_autoptr(virVIRTCCACapability) virtcca = NULL;
+
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTCCA))
+ return 0;
+
+ if (virXPathBoolean("boolean(./virtcca)", ctxt) == 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing virtcca platform data in QEMU capabilities cache"));
+ return -1;
+ }
+
+ if (virXPathBoolean("boolean(./virtcca/enabled)", ctxt) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing VIRTCCA enabled data in QEMU capabilities cache"));
+ return -1;
+ }
+
+ virtcca = g_new0(virVIRTCCACapability, 1);
+
+ qemuCaps->virtccaCapabilities = g_steal_pointer(&virtcca);
+ return 0;
+}
+
+
static int
virQEMUCapsParseHypervCapabilities(virQEMUCaps *qemuCaps,
xmlXPathContextPtr ctxt)
@@ -4676,6 +4756,9 @@ virQEMUCapsLoadCache(virArch hostArch,
if (virQEMUCapsParseSGXInfo(qemuCaps, ctxt) < 0)
return -1;
+ if (virQEMUCapsParseVIRTCCAInfo(qemuCaps, ctxt) < 0)
+ return -1;
+
if (virQEMUCapsParseHypervCapabilities(qemuCaps, ctxt) < 0)
return -1;
@@ -4904,6 +4987,14 @@ virQEMUCapsFormatSGXInfo(virQEMUCaps *qemuCaps,
}
+static void
+virQEMUCapsFormatVIRTCCAInfo(virBuffer *buf)
+{
+ virBufferAddLit(buf, "\n");
+ virBufferAddLit(buf, "\n");
+}
+
+
static void
virQEMUCapsFormatHypervCapabilities(virQEMUCaps *qemuCaps,
virBuffer *buf)
@@ -5012,6 +5103,9 @@ virQEMUCapsFormatCache(virQEMUCaps *qemuCaps)
if (qemuCaps->sgxCapabilities)
virQEMUCapsFormatSGXInfo(qemuCaps, &buf);
+ if (qemuCaps->virtccaCapabilities)
+ virQEMUCapsFormatVIRTCCAInfo(&buf);
+
if (qemuCaps->hypervCapabilities)
virQEMUCapsFormatHypervCapabilities(qemuCaps, &buf);
@@ -5566,6 +5660,8 @@ virQEMUCapsInitQMPMonitor(virQEMUCaps *qemuCaps,
return -1;
if (virQEMUCapsProbeQMPSGXCapabilities(qemuCaps, mon) < 0)
return -1;
+ if (virQEMUCapsProbeQMPVIRTCCACapabilities(qemuCaps, mon) < 0)
+ return -1;
virQEMUCapsInitProcessCaps(qemuCaps);
@@ -6601,6 +6697,23 @@ virQEMUCapsFillDomainFeatureSEVCaps(virQEMUCaps *qemuCaps,
}
+/**
+ * virQEMUCapsFillDomainFeatureVIRTCCACaps:
+ * @qemuCaps: QEMU capabilities
+ * @domCaps: domain capabilities
+ *
+ * Take the information about VIRTCCA capabilities that has been obtained
+ * using the 'query-virtcca-capabilities' QMP command and stored in @qemuCaps
+ * and convert it to a form suitable for @domCaps.
+ */
+static void
+virQEMUCapsFillDomainFeatureVIRTCCACaps(virQEMUCaps *qemuCaps,
+ virDomainCaps *domCaps)
+{
+ virQEMUCapsVIRTCCAInfoCopy(&domCaps->virtcca, qemuCaps->virtccaCapabilities);
+}
+
+
static void
virQEMUCapsFillDomainFeatureS390PVCaps(virQEMUCaps *qemuCaps,
virDomainCaps *domCaps)
@@ -6700,6 +6813,7 @@ virQEMUCapsFillDomainCaps(virQEMUCaps *qemuCaps,
virQEMUCapsFillDomainFeatureSGXCaps(qemuCaps, domCaps);
virQEMUCapsFillDomainFeatureHypervCaps(qemuCaps, domCaps);
virQEMUCapsFillDomainDeviceCryptoCaps(qemuCaps, crypto);
+ virQEMUCapsFillDomainFeatureVIRTCCACaps(qemuCaps, domCaps);
return 0;
}
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 959fbe63787378c3de2d7ccce777f1b56c7bd3b6..32ac2573e6edfe13f39cced136050a8769975d5e 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -678,6 +678,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */
QEMU_CAPS_RUN_WITH_ASYNC_TEARDOWN, /* asynchronous teardown -run-with async-teardown=on|off */
QEMU_CAPS_DEVICE_VIRTIO_BLK_VHOST_VDPA, /* virtio-blk-vhost-vdpa block driver */
QEMU_CAPS_SMP_CLUSTERS, /* -smp clusters= */
+ QEMU_CAPS_VIRTCCA, /* kvm-type=cvm */
QEMU_CAPS_LAST /* this must always be the last item */
} virQEMUCapsFlags;
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index e270bee2cd508d4213b2835fa8c2ddba556ae834..3fd26a04334f131314fc93b861cd252f9782c211 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -3469,6 +3469,16 @@ qemuMonitorGetSGXCapabilities(qemuMonitor *mon,
}
+int
+qemuMonitorGetVIRTCCACapabilities(qemuMonitor *mon,
+ virVIRTCCACapability **capabilities)
+{
+ QEMU_CHECK_MONITOR(mon);
+
+ return qemuMonitorJSONGetVIRTCCACapabilities(mon, capabilities);
+}
+
+
int
qemuMonitorNBDServerStart(qemuMonitor *mon,
const virStorageNetHostDef *server,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 4cbd225e8f327b812bc3dc830ab263a6bb5d21f7..6c57a797771614e8b3e6a6c81d6f3615a82c63c1 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -849,6 +849,9 @@ int qemuMonitorGetSEVCapabilities(qemuMonitor *mon,
int qemuMonitorGetSGXCapabilities(qemuMonitor *mon,
virSGXCapability **capabilities);
+int qemuMonitorGetVIRTCCACapabilities(qemuMonitor *mon,
+ virVIRTCCACapability **capabilities)
+
typedef enum {
QEMU_MONITOR_MIGRATE_RESUME = 1 << 0, /* resume failed post-copy migration */
QEMU_MONITOR_MIGRATION_FLAGS_LAST
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 3748034bb91fbb5f352420dad9ca06c166861eb7..6fc6afea30c564cf7a3206e3725fe3c83c36fa35 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -6139,6 +6139,54 @@ qemuMonitorJSONGetSGXCapabilities(qemuMonitor *mon,
}
+/**
+ * qemuMonitorJSONGetVIRTCCACapabilities:
+ * @mon: qemu monitor object
+ * @capabilities: pointer to pointer to a VIRTCCA capability structure to be filled
+ *
+ * Returns: -1 on error,
+ * 0 if VIRTCCA is not supported, and
+ * 1 if VIRTCCA is supported on the platform.
+ */
+int
+qemuMonitorJSONGetVIRTCCACapabilities(qemuMonitor *mon,
+ virVIRTCCACapability **capabilities)
+{
+ g_autoptr(virJSONValue) cmd = NULL;
+ g_autoptr(virJSONValue) reply = NULL;
+ g_autoptr(virVIRTCCACapability) capability = NULL;
+ virJSONValue *caps;
+
+ *capabilities = NULL;
+ capability = g_new0(virVIRTCCACapability, 1);
+
+ if (!(cmd = qemuMonitorJSONMakeCommand("query-virtcca-capabilities", NULL)))
+ return -1;
+
+ if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+ return -1;
+
+ /* QEMU has only compiled-in support of VIRTCCA */
+ if (qemuMonitorJSONHasError(reply, "GenericError"))
+ return 0;
+
+ if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+ return -1;
+
+ caps = virJSONValueObjectGetObject(reply, "return");
+
+ if (virJSONValueObjectGetBoolean(caps, "enabled", &capability->enabled) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("query-virtcca-capabilities reply was missing 'enabled' field"));
+ return -1;
+ }
+
+ *capabilities = g_steal_pointer(&capability);
+
+ return 1;
+}
+
+
static virJSONValue *
qemuMonitorJSONBuildInetSocketAddress(const char *host,
const char *port)
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index ed0027c118e6144458e83872c7d0d1d1e56818fe..8f5c25d015cd79751e585fec874d498f72b61b9b 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -168,6 +168,10 @@ int
qemuMonitorJSONGetSEVCapabilities(qemuMonitor *mon,
virSEVCapability **capabilities);
+int
+qemuMonitorJSONGetVIRTCCACapabilities(qemuMonitor *mon,
+ virVIRTCCACapability **capabilities)
+
int
qemuMonitorJSONMigrate(qemuMonitor *mon,
unsigned int flags,