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,