Added logic for loading the "RSS" eBPF program.
eBPF file descriptors passed to the QEMU.

Signed-off-by: Andrew Melnychenko <and...@daynix.com>
---
 src/qemu/qemu_command.c | 53 +++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_domain.c  |  4 ++++
 src/qemu/qemu_domain.h  |  3 +++
 3 files changed, 60 insertions(+)

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 8a7b80719f..ca6cb1bc7a 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3786,6 +3786,23 @@ qemuBuildLegacyNicStr(virDomainNetDef *net)
                            NULLSTR_EMPTY(net->info.alias));
 }
 
+static char *qemuBuildEbpfRssArg(virDomainNetDef *net) {
+    qemuDomainNetworkPrivate *netpriv = QEMU_DOMAIN_NETWORK_PRIVATE(net);
+    g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
+    size_t nfds;
+    GSList *n;
+
+    if (netpriv->ebpfrssfds) {
+        nfds = 0;
+        for (n = netpriv->ebpfrssfds; n; n = n->next) {
+            virBufferAsprintf(&buf, "%s:", qemuFDPassDirectGetPath(n->data));
+            nfds++;
+        }
+    }
+    virBufferTrim(&buf, ":");
+
+    return virBufferContentAndReset(&buf);
+}
 
 virJSONValue *
 qemuBuildNicDevProps(virDomainDef *def,
@@ -3871,6 +3888,11 @@ qemuBuildNicDevProps(virDomainDef *def,
                                   "T:failover", failover,
                                   NULL) < 0)
             return NULL;
+        if (net->driver.virtio.rss == VIR_TRISTATE_SWITCH_ON && 
virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_NET_EBPF_RSS_FDS)){
+            g_autofree char *ebpf = qemuBuildEbpfRssArg(net);
+            if (virJSONValueObjectAdd(&props, "S:ebpf_rss_fds", ebpf, NULL) < 
0)
+                return NULL;
+        }
     } else {
         if (virJSONValueObjectAdd(&props,
                                   "s:driver", virDomainNetGetModelString(net),
@@ -4152,6 +4174,33 @@ qemuBuildWatchdogDevProps(const virDomainDef *def,
 }
 
 
+static void qemuOpenEbpfRssFds(virDomainNetDef *net,
+                              virQEMUCaps *qemuCaps) {
+    const void *ebpfRSSObject = NULL;
+    size_t ebpfRSSObjectSize = 0;
+    int fds[16];
+    int nfds = 0;
+    qemuDomainNetworkPrivate *netpriv = QEMU_DOMAIN_NETWORK_PRIVATE(net);
+
+    netpriv->libbpfRSSObject = NULL;
+    netpriv->ebpfrssfds = NULL;
+
+    /* Add ebpf values */
+    if (net->driver.virtio.rss == VIR_TRISTATE_SWITCH_ON && 
virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_NET_EBPF_RSS_FDS)) {
+        ebpfRSSObject = virQEMUCapsGetEbpf(qemuCaps, "rss", 
&ebpfRSSObjectSize);
+        nfds = qemuInterfaceLoadEbpf(ebpfRSSObject, ebpfRSSObjectSize, 
&netpriv->libbpfRSSObject, fds, 16);
+
+        if (nfds > 0) {
+            for (int i = 0; i < nfds; ++i) {
+                g_autofree char *name = g_strdup_printf("ebpfrssfd-%s-%u", 
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,
@@ -8735,6 +8784,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 eec7bed28b..c696482f29 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"
@@ -1078,6 +1079,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);
 }
 
 
@@ -1089,6 +1091,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 a3fc6acaaa..5e155b77cc 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -431,6 +431,9 @@ struct _qemuDomainNetworkPrivate {
     GSList *tapfds; /* qemuFDPassDirect */
     GSList *vhostfds; /* qemuFDPassDirect */
     qemuFDPass *vdpafd;
+
+    void *libbpfRSSObject;
+    GSList *ebpfrssfds; /* qemuFDPassDirect eBPF RSS fds from helper */
 };
 
 
-- 
2.42.0

Reply via email to