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(a)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