[RFC PATCH 2/4] qemu_capabilities: Added new capability ebpf_rss_fds for QEMU.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>
---
 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




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux