Also, added logic for retrieving eBPF objects from QEMU.
eBPF objects stored in the hash table during runtime.
eBPF objects cached encoded in base64 in the .xml cache file.
Signed-off-by: Andrew Melnychenko <andrew(a)daynix.com>
---
src/qemu/qemu_capabilities.c | 181 +++++++++++++++++++++++++++++++++++
src/qemu/qemu_capabilities.h | 4 +
2 files changed, 185 insertions(+)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 3a1bfbf74d..d9b5d6fb22 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -698,6 +698,7 @@ VIR_ENUM_IMPL(virQEMUCaps,
/* 450 */
"run-with.async-teardown", /* QEMU_CAPS_RUN_WITH_ASYNC_TEARDOWN
*/
"virtio-blk-vhost-vdpa", /*
QEMU_CAPS_DEVICE_VIRTIO_BLK_VHOST_VDPA */
+ "virtio-net.ebpf_rss_fds", /* QEMU_CAPS_VIRTIO_NET_EBPF_RSS_FDS
*/
);
@@ -789,6 +790,9 @@ struct _virQEMUCaps {
virQEMUCapsAccel kvm;
virQEMUCapsAccel hvf;
virQEMUCapsAccel tcg;
+
+ /* Hash of ebpf objects virQEMUEbpfOBjectData */
+ GHashTable *ebpfObjects;
};
struct virQEMUCapsSearchData {
@@ -796,6 +800,18 @@ struct virQEMUCapsSearchData {
const char *binaryFilter;
};
+struct virQEMUEbpfOBjectData {
+ void *ebpfData;
+ size_t ebpfSize;
+};
+
+void virQEMUEbpfOBjectDataDestroy(gpointer data) {
+ if (!data)
+ return;
+ struct virQEMUEbpfOBjectData *object = data;
+ g_free(object->ebpfData);
+ g_free(data);
+}
static virClass *virQEMUCapsClass;
static void virQEMUCapsDispose(void *obj);
@@ -836,6 +852,19 @@ const char *virQEMUCapsArchToString(virArch arch)
}
+const void *
+virQEMUCapsGetEbpf(virQEMUCaps *qemuCaps, const char *id, size_t *size)
+{
+ struct virQEMUEbpfOBjectData *object = virHashLookup(qemuCaps->ebpfObjects, id);
+
+ if (!object)
+ return NULL;
+
+ *size = object->ebpfSize;
+ return object->ebpfData;
+}
+
+
/* Checks whether a domain with @guest arch can run natively on @host.
*/
bool
@@ -1426,6 +1455,7 @@ static struct virQEMUCapsDevicePropsFlags
virQEMUCapsDevicePropsVirtioBlk[] = {
static struct virQEMUCapsDevicePropsFlags virQEMUCapsDevicePropsVirtioNet[] = {
{ "acpi-index", QEMU_CAPS_ACPI_INDEX, NULL },
{ "rss", QEMU_CAPS_VIRTIO_NET_RSS, NULL },
+ { "ebpf_rss_fds", QEMU_CAPS_VIRTIO_NET_EBPF_RSS_FDS, NULL },
};
static struct virQEMUCapsDevicePropsFlags virQEMUCapsDevicePropsPCIeRootPort[] = {
@@ -1804,6 +1834,8 @@ virQEMUCapsNew(void)
qemuCaps->invalidation = true;
qemuCaps->flags = virBitmapNew(QEMU_CAPS_LAST);
+ qemuCaps->ebpfObjects = virHashNew(virQEMUEbpfOBjectDataDestroy);
+
return qemuCaps;
}
@@ -1984,6 +2016,8 @@ virQEMUCaps *virQEMUCapsNewCopy(virQEMUCaps *qemuCaps)
ret->hypervCapabilities = g_memdup(qemuCaps->hypervCapabilities,
sizeof(virDomainCapsFeatureHyperv));
+ ret->ebpfObjects = g_hash_table_ref(qemuCaps->ebpfObjects);
+
return g_steal_pointer(&ret);
}
@@ -2026,6 +2060,8 @@ void virQEMUCapsDispose(void *obj)
g_free(qemuCaps->hypervCapabilities);
+ g_hash_table_unref(qemuCaps->ebpfObjects);
+
virQEMUCapsAccelClear(&qemuCaps->kvm);
virQEMUCapsAccelClear(&qemuCaps->hvf);
virQEMUCapsAccelClear(&qemuCaps->tcg);
@@ -4541,6 +4577,46 @@ virQEMUCapsValidateArch(virQEMUCaps *qemuCaps, xmlXPathContextPtr
ctxt)
}
+static int
+virQEMUCapsParseEbpfObjects(virQEMUCaps *qemuCaps, xmlXPathContextPtr ctxt)
+{
+ g_autofree xmlNodePtr *nodes = NULL;
+ size_t i;
+ int n;
+
+ if ((n = virXPathNodeSet("./ebpf", ctxt, &nodes)) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to parse qemu cached eBPF object"));
+ return -1;
+ }
+
+ for (i = 0; i < n; i++) {
+ g_autofree char *id = NULL;
+ g_autofree char *ebpf = NULL;
+ struct virQEMUEbpfOBjectData *ebpfObject = NULL;
+
+ if (!(id = virXMLPropString(nodes[i], "id"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("missing eBPF object ID in QEMU capabilities
cache"));
+ return -1;
+ }
+
+ if (!(ebpf = virXMLNodeContentString(nodes[i]))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s %s",
+ _("can't get eBPF base64 data from cache for ID:
"), id);
+ return -1;
+ }
+
+ ebpfObject = g_malloc(sizeof(*ebpfObject));
+ ebpfObject->ebpfData = g_base64_decode(ebpf, &ebpfObject->ebpfSize);
+
+ virHashAddEntry(qemuCaps->ebpfObjects, id, ebpfObject);
+ }
+
+ return 0;
+}
+
+
/*
* Parsing a doc that looks like
*
@@ -4688,6 +4764,8 @@ virQEMUCapsLoadCache(virArch hostArch,
if (skipInvalidation)
qemuCaps->invalidation = false;
+ virQEMUCapsParseEbpfObjects(qemuCaps, ctxt);
+
return 0;
}
@@ -4925,6 +5003,32 @@ virQEMUCapsFormatHypervCapabilities(virQEMUCaps *qemuCaps,
}
+static int
+virQEMUCapsFormatEbpfObjectsIterator(void *payload, const char *name, void *opaque)
+{
+ virBuffer *buf = opaque;
+ struct virQEMUEbpfOBjectData *object = payload;
+ g_autofree char *objectBase64 = NULL;
+
+ if (!buf || !object)
+ return 0;
+
+ objectBase64 = g_base64_encode(object->ebpfData, object->ebpfSize);
+ if (!objectBase64)
+ return 0;
+
+ virBufferAsprintf(buf, "<ebpf id='%s'>\n", name);
+ virBufferAdjustIndent(buf, 2);
+
+ virBufferAddStr(buf, objectBase64);
+ virBufferAddLit(buf, "\n");
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</ebpf>\n");
+
+ return 0;
+}
+
char *
virQEMUCapsFormatCache(virQEMUCaps *qemuCaps)
{
@@ -5015,6 +5119,8 @@ virQEMUCapsFormatCache(virQEMUCaps *qemuCaps)
if (qemuCaps->kvmSupportsSecureGuest)
virBufferAddLit(&buf, "<kvmSupportsSecureGuest/>\n");
+ virHashForEach(qemuCaps->ebpfObjects, virQEMUCapsFormatEbpfObjectsIterator,
&buf);
+
virBufferAdjustIndent(&buf, -2);
virBufferAddLit(&buf, "</qemuCaps>\n");
@@ -5437,6 +5543,79 @@ virQEMUCapsInitProcessCaps(virQEMUCaps *qemuCaps)
}
+static int
+virQEMUCapsProbeQMPEbpfObject(virQEMUCaps *qemuCaps, const char *id,
+ qemuMonitor *mon)
+{
+ void *ebpfObject = NULL;
+ size_t size = 0;
+
+ if (!id)
+ return -1;
+
+ ebpfObject = qemuMonitorGetEbpf(mon, id, &size);
+ if(ebpfObject == NULL)
+ return -1;
+
+ struct virQEMUEbpfOBjectData *object = g_malloc(sizeof(*object));
+ object->ebpfData = ebpfObject;
+ object->ebpfSize = size;
+
+ virHashAddEntry(qemuCaps->ebpfObjects, id, object);
+
+ return 0;
+}
+
+static void virQEMUCapsProbeQMPSchemaEbpf(virQEMUCaps *qemuCaps, GHashTable* schema,
qemuMonitor *mon) {
+ if (schema == NULL)
+ return;
+
+ virJSONValue *requestSchema = virHashLookup(schema, "request-ebpf");
+ if (!requestSchema)
+ return;
+
+ const char *argType = virJSONValueObjectGetString(requestSchema,
"arg-type");
+ if (!argType)
+ return;
+
+ virJSONValue *argSchema = virHashLookup(schema, argType);
+ if (!argSchema)
+ return;
+
+ /* Get member id type*/
+ virJSONValue *members = virJSONValueObjectGetArray(argSchema, "members");
+ if (!members)
+ return;
+
+ /* Find "id" type */
+ virJSONValue *idSchema = NULL;
+ for (size_t i = 0; (idSchema = virJSONValueArrayGet(members, i)) != NULL; ++i) {
+ const char *name = virJSONValueObjectGetString(idSchema, "name");
+ if (strncmp(name, "id", 3) == 0)
+ break;
+ }
+
+ if (!idSchema)
+ return;
+
+ const char *ebpfIds = virJSONValueObjectGetString(idSchema, "type");
+ virJSONValue *ebpfIdsSchema = virHashLookup(schema, ebpfIds);
+ if (!ebpfIdsSchema)
+ return;
+
+ virJSONValue *ebpfIdsArray = virJSONValueObjectGetArray(ebpfIdsSchema,
"values");
+ if (!ebpfIdsArray)
+ return;
+
+ /* Try to request every eBPF */
+ virJSONValue *id = NULL;
+ for (size_t i = 0; (id = virJSONValueArrayGet(ebpfIdsArray, i)) != NULL; ++i) {
+ const char *name = virJSONValueGetString(id);
+ virQEMUCapsProbeQMPEbpfObject(qemuCaps, name, mon);
+ }
+}
+
+
static int
virQEMUCapsProbeQMPSchemaCapabilities(virQEMUCaps *qemuCaps,
qemuMonitor *mon)
@@ -5466,6 +5645,8 @@ virQEMUCapsProbeQMPSchemaCapabilities(virQEMUCaps *qemuCaps,
virQEMUCapsSet(qemuCaps, cmd->flag);
}
+ virQEMUCapsProbeQMPSchemaEbpf(qemuCaps, schema, mon);
+
return 0;
}
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 3c4f7f625b..164dc003d0 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -677,6 +677,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check
*/
/* 450 */
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_VIRTIO_NET_EBPF_RSS_FDS, /* virtio-net ebpf_rss_fds feature */
QEMU_CAPS_LAST /* this must always be the last item */
} virQEMUCapsFlags;
@@ -895,3 +896,6 @@ int
virQEMUCapsProbeQMPMachineTypes(virQEMUCaps *qemuCaps,
virDomainVirtType virtType,
qemuMonitor *mon);
+
+const void *
+virQEMUCapsGetEbpf(virQEMUCaps *qemuCaps, const char *id, size_t *size);
--
2.42.0