[RFC PATCH v4 4/5] qemu_command: Added "ebpf_rss_fds" support for virtio-net.

Andrew Melnychenko posted 5 patches 3 months ago
[RFC PATCH v4 4/5] qemu_command: Added "ebpf_rss_fds" support for virtio-net.
Posted by Andrew Melnychenko 3 months ago
Added new capability ebpf_rss_fds for QEMU.
Added logic for loading the "RSS" eBPF program.
eBPF file descriptors passed to the QEMU.

Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
---
 src/qemu/qemu_capabilities.c                  |  2 +
 src/qemu/qemu_capabilities.h                  |  1 +
 src/qemu/qemu_command.c                       | 60 +++++++++++++++++++
 src/qemu/qemu_domain.c                        |  4 ++
 src/qemu/qemu_domain.h                        |  3 +
 .../caps_9.0.0_x86_64.xml                     |  1 +
 .../caps_9.1.0_x86_64.xml                     |  1 +
 7 files changed, 72 insertions(+)

diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 2d2603e519..1191f96bec 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -713,6 +713,7 @@ VIR_ENUM_IMPL(virQEMUCaps,
               "sev-snp-guest", /* QEMU_CAPS_SEV_SNP_GUEST */
               "netdev.user", /* QEMU_CAPS_NETDEV_USER */
               "acpi-erst", /* QEMU_CAPS_DEVICE_ACPI_ERST */
+              "virtio-net.ebpf_rss_fds", /* QEMU_CAPS_VIRTIO_NET_EBPF_RSS_FDS */
     );
 
 
@@ -1454,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[] = {
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 2c53236132..4af5e657e4 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -692,6 +692,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */
     QEMU_CAPS_SEV_SNP_GUEST, /* -object sev-snp-guest */
     QEMU_CAPS_NETDEV_USER, /* -netdev user */
     QEMU_CAPS_DEVICE_ACPI_ERST, /* -device acpi-erst */
+    QEMU_CAPS_VIRTIO_NET_EBPF_RSS_FDS, /* virtio-net ebpf_rss_fds feature */
 
     QEMU_CAPS_LAST /* this must always be the last item */
 } virQEMUCapsFlags;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index f15e6bda1e..570bc9d1e6 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3806,6 +3806,25 @@ qemuBuildLegacyNicStr(virDomainNetDef *net)
 }
 
 
+static virJSONValue *
+qemuBuildEbpfRssArg(virDomainNetDef *net)
+{
+    qemuDomainNetworkPrivate *netpriv = QEMU_DOMAIN_NETWORK_PRIVATE(net);
+    g_autoptr(virJSONValue) props = NULL;
+    GSList *n;
+
+    if (!netpriv->ebpfrssfds)
+        return NULL;
+
+    props = virJSONValueNewArray();
+    for (n = netpriv->ebpfrssfds; n; n = n->next) {
+        virJSONValueArrayAppendString(props, qemuFDPassDirectGetPath(n->data));
+    }
+
+    return g_steal_pointer(&props);
+}
+
+
 virJSONValue *
 qemuBuildNicDevProps(virDomainDef *def,
                      virDomainNetDef *net,
@@ -3820,6 +3839,7 @@ qemuBuildNicDevProps(virDomainDef *def,
         virTristateSwitch mq = VIR_TRISTATE_SWITCH_ABSENT;
         unsigned long long vectors = 0;
         virTristateSwitch failover = VIR_TRISTATE_SWITCH_ABSENT;
+        g_autoptr(virJSONValue) ebpffds = NULL;
 
         switch (net->driver.virtio.txmode) {
         case VIR_DOMAIN_NET_VIRTIO_TX_MODE_IOTHREAD:
@@ -3864,6 +3884,8 @@ qemuBuildNicDevProps(virDomainDef *def,
         if (!(props = qemuBuildVirtioDevProps(VIR_DOMAIN_DEVICE_NET, net, qemuCaps)))
             return NULL;
 
+        ebpffds = qemuBuildEbpfRssArg(net);
+
         if (virJSONValueObjectAdd(&props,
                                   "S:tx", tx,
                                   "T:ioeventfd", net->driver.virtio.ioeventfd,
@@ -3888,6 +3910,7 @@ qemuBuildNicDevProps(virDomainDef *def,
                                   "T:hash", net->driver.virtio.rss_hash_report,
                                   "p:host_mtu", net->mtu,
                                   "T:failover", failover,
+                                  "A:ebpf-rss-fds", &ebpffds,
                                   NULL) < 0)
             return NULL;
     } else {
@@ -4171,6 +4194,38 @@ qemuBuildWatchdogDevProps(const virDomainDef *def,
 }
 
 
+static void
+qemuOpenEbpfRssFds(virDomainNetDef *net,
+                   virQEMUCaps *qemuCaps)
+{
+    const char *ebpfRSSObject = NULL;
+    int fds[16];
+    int nfds = 0;
+    size_t i = 0;
+    qemuDomainNetworkPrivate *netpriv = QEMU_DOMAIN_NETWORK_PRIVATE(net);
+
+    /* Add ebpf values */
+    if (net->driver.virtio.rss == VIR_TRISTATE_SWITCH_ON
+        && net->driver.virtio.rss_hash_report != VIR_TRISTATE_SWITCH_ON
+        && virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_NET_EBPF_RSS_FDS)) {
+        ebpfRSSObject = virQEMUCapsGetEbpf(qemuCaps, "rss");
+        nfds = qemuInterfaceLoadEbpf(ebpfRSSObject, &netpriv->libbpfRSSObject, fds, G_N_ELEMENTS(fds));
+
+        if (nfds <= 0)
+            return;
+
+        for (i = 0; i < nfds; ++i) {
+            g_autofree char *name = g_strdup_printf("ebpfrssfd-%s-%zu", net->info.alias, i);
+
+            netpriv->ebpfrssfds =
+                g_slist_prepend(netpriv->ebpfrssfds, qemuFDPassDirectNew(name, fds + i));
+        }
+
+        netpriv->ebpfrssfds = g_slist_reverse(netpriv->ebpfrssfds);
+    }
+}
+
+
 static int
 qemuBuildWatchdogCommandLine(virCommand *cmd,
                              const virDomainDef *def,
@@ -8729,6 +8784,7 @@ qemuBuildInterfaceCommandLine(virQEMUDriver *driver,
     g_autoptr(virJSONValue) hostnetprops = NULL;
     qemuDomainNetworkPrivate *netpriv = QEMU_DOMAIN_NETWORK_PRIVATE(net);
     GSList *n;
+    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
 
     if (qemuDomainValidateActualNetDef(net, qemuCaps) < 0)
         return -1;
@@ -8864,6 +8920,10 @@ qemuBuildInterfaceCommandLine(virQEMUDriver *driver,
     qemuFDPassDirectTransferCommand(netpriv->slirpfd, cmd);
     qemuFDPassTransferCommand(netpriv->vdpafd, cmd);
 
+    qemuOpenEbpfRssFds(net, qemuCaps);
+    for (n = netpriv->ebpfrssfds; n; n = n->next)
+        qemuFDPassDirectTransferCommand(n->data, cmd);
+
     if (!(hostnetprops = qemuBuildHostNetProps(vm, net)))
         goto cleanup;
 
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 298f4bfb9e..a73f62fb44 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -38,6 +38,7 @@
 #include "qemu_checkpoint.h"
 #include "qemu_validate.h"
 #include "qemu_namespace.h"
+#include "qemu_interface.h"
 #include "viralloc.h"
 #include "virlog.h"
 #include "virerror.h"
@@ -1085,6 +1086,7 @@ qemuDomainNetworkPrivateClearFDs(qemuDomainNetworkPrivate *priv)
     g_clear_pointer(&priv->vdpafd, qemuFDPassFree);
     g_slist_free_full(g_steal_pointer(&priv->vhostfds), (GDestroyNotify) qemuFDPassDirectFree);
     g_slist_free_full(g_steal_pointer(&priv->tapfds), (GDestroyNotify) qemuFDPassDirectFree);
+    g_slist_free_full(g_steal_pointer(&priv->ebpfrssfds), (GDestroyNotify) qemuFDPassDirectFree);
 }
 
 
@@ -1096,6 +1098,8 @@ qemuDomainNetworkPrivateDispose(void *obj G_GNUC_UNUSED)
     qemuSlirpFree(priv->slirp);
 
     qemuDomainNetworkPrivateClearFDs(priv);
+
+    qemuInterfaceCloseEbpf(priv->libbpfRSSObject);
 }
 
 
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index a5092dd7f0..3e0345c29d 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -435,6 +435,9 @@ struct _qemuDomainNetworkPrivate {
     GSList *tapfds; /* qemuFDPassDirect */
     GSList *vhostfds; /* qemuFDPassDirect */
     qemuFDPass *vdpafd;
+
+    void *libbpfRSSObject;
+    GSList *ebpfrssfds; /* qemuFDPassDirect eBPF RSS fds from helper */
 };
 
 
diff --git a/tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml
index dbe015d287..689402b472 100644
--- a/tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_9.0.0_x86_64.xml
@@ -207,6 +207,7 @@
   <flag name='virtio-sound'/>
   <flag name='netdev.user'/>
   <flag name='acpi-erst'/>
+  <flag name='virtio-net.ebpf_rss_fds'/>
   <version>9000000</version>
   <microcodeVersion>43100245</microcodeVersion>
   <package>v9.0.0</package>
diff --git a/tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml
index b0c16a0440..74cf1db19c 100644
--- a/tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_9.1.0_x86_64.xml
@@ -205,6 +205,7 @@
   <flag name='virtio-sound'/>
   <flag name='netdev.user'/>
   <flag name='acpi-erst'/>
+  <flag name='virtio-net.ebpf_rss_fds'/>
   <version>9000050</version>
   <microcodeVersion>43100246</microcodeVersion>
   <package>v9.0.0-1388-g80e8f06021-dirty</package>
-- 
2.45.2