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