aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/net/vhost_net.c3
-rw-r--r--hw/net/virtio-net.c116
-rw-r--r--include/hw/virtio/virtio-net.h4
-rw-r--r--net/vhost-vdpa.c2
4 files changed, 122 insertions, 3 deletions
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 24d555e764..44c1ed92dc 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -45,6 +45,7 @@ static const int kernel_feature_bits[] = {
VIRTIO_NET_F_MTU,
VIRTIO_F_IOMMU_PLATFORM,
VIRTIO_F_RING_PACKED,
+ VIRTIO_NET_F_HASH_REPORT,
VHOST_INVALID_FEATURE_BIT
};
@@ -71,6 +72,8 @@ static const int user_feature_bits[] = {
VIRTIO_NET_F_MTU,
VIRTIO_F_IOMMU_PLATFORM,
VIRTIO_F_RING_PACKED,
+ VIRTIO_NET_F_RSS,
+ VIRTIO_NET_F_HASH_REPORT,
/* This bit implies RARP isn't sent by QEMU out of band */
VIRTIO_NET_F_GUEST_ANNOUNCE,
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 6b7e8dd04e..613be072c3 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -737,8 +737,9 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
return features;
}
- virtio_clear_feature(&features, VIRTIO_NET_F_RSS);
- virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT);
+ if (!ebpf_rss_is_loaded(&n->ebpf_rss)) {
+ virtio_clear_feature(&features, VIRTIO_NET_F_RSS);
+ }
features = vhost_net_get_features(get_vhost_net(nc->peer), features);
vdev->backend_features = features;
@@ -1163,12 +1164,79 @@ static int virtio_net_handle_announce(VirtIONet *n, uint8_t cmd,
}
}
+static void virtio_net_detach_epbf_rss(VirtIONet *n);
+
static void virtio_net_disable_rss(VirtIONet *n)
{
if (n->rss_data.enabled) {
trace_virtio_net_rss_disable();
}
n->rss_data.enabled = false;
+
+ virtio_net_detach_epbf_rss(n);
+}
+
+static bool virtio_net_attach_ebpf_to_backend(NICState *nic, int prog_fd)
+{
+ NetClientState *nc = qemu_get_peer(qemu_get_queue(nic), 0);
+ if (nc == NULL || nc->info->set_steering_ebpf == NULL) {
+ return false;
+ }
+
+ return nc->info->set_steering_ebpf(nc, prog_fd);
+}
+
+static void rss_data_to_rss_config(struct VirtioNetRssData *data,
+ struct EBPFRSSConfig *config)
+{
+ config->redirect = data->redirect;
+ config->populate_hash = data->populate_hash;
+ config->hash_types = data->hash_types;
+ config->indirections_len = data->indirections_len;
+ config->default_queue = data->default_queue;
+}
+
+static bool virtio_net_attach_epbf_rss(VirtIONet *n)
+{
+ struct EBPFRSSConfig config = {};
+
+ if (!ebpf_rss_is_loaded(&n->ebpf_rss)) {
+ return false;
+ }
+
+ rss_data_to_rss_config(&n->rss_data, &config);
+
+ if (!ebpf_rss_set_all(&n->ebpf_rss, &config,
+ n->rss_data.indirections_table, n->rss_data.key)) {
+ return false;
+ }
+
+ if (!virtio_net_attach_ebpf_to_backend(n->nic, n->ebpf_rss.program_fd)) {
+ return false;
+ }
+
+ return true;
+}
+
+static void virtio_net_detach_epbf_rss(VirtIONet *n)
+{
+ virtio_net_attach_ebpf_to_backend(n->nic, -1);
+}
+
+static bool virtio_net_load_ebpf(VirtIONet *n)
+{
+ if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
+ /* backend does't support steering ebpf */
+ return false;
+ }
+
+ return ebpf_rss_load(&n->ebpf_rss);
+}
+
+static void virtio_net_unload_ebpf(VirtIONet *n)
+{
+ virtio_net_attach_ebpf_to_backend(n->nic, -1);
+ ebpf_rss_unload(&n->ebpf_rss);
}
static uint16_t virtio_net_handle_rss(VirtIONet *n,
@@ -1283,6 +1351,25 @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
goto error;
}
n->rss_data.enabled = true;
+
+ if (!n->rss_data.populate_hash) {
+ if (!virtio_net_attach_epbf_rss(n)) {
+ /* EBPF must be loaded for vhost */
+ if (get_vhost_net(qemu_get_queue(n->nic)->peer)) {
+ warn_report("Can't load eBPF RSS for vhost");
+ goto error;
+ }
+ /* fallback to software RSS */
+ warn_report("Can't load eBPF RSS - fallback to software RSS");
+ n->rss_data.enabled_software_rss = true;
+ }
+ } else {
+ /* use software RSS for hash populating */
+ /* and detach eBPF if was loaded before */
+ virtio_net_detach_epbf_rss(n);
+ n->rss_data.enabled_software_rss = true;
+ }
+
trace_virtio_net_rss_enable(n->rss_data.hash_types,
n->rss_data.indirections_len,
temp.b);
@@ -1668,7 +1755,7 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
return -1;
}
- if (!no_rss && n->rss_data.enabled) {
+ if (!no_rss && n->rss_data.enabled && n->rss_data.enabled_software_rss) {
int index = virtio_net_process_rss(nc, buf, size);
if (index >= 0) {
NetClientState *nc2 = qemu_get_subqueue(n->nic, index);
@@ -2772,6 +2859,19 @@ static int virtio_net_post_load_device(void *opaque, int version_id)
}
if (n->rss_data.enabled) {
+ n->rss_data.enabled_software_rss = n->rss_data.populate_hash;
+ if (!n->rss_data.populate_hash) {
+ if (!virtio_net_attach_epbf_rss(n)) {
+ if (get_vhost_net(qemu_get_queue(n->nic)->peer)) {
+ warn_report("Can't post-load eBPF RSS for vhost");
+ } else {
+ warn_report("Can't post-load eBPF RSS - "
+ "fallback to software RSS");
+ n->rss_data.enabled_software_rss = true;
+ }
+ }
+ }
+
trace_virtio_net_rss_enable(n->rss_data.hash_types,
n->rss_data.indirections_len,
sizeof(n->rss_data.key));
@@ -3352,6 +3452,10 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
n->qdev = dev;
net_rx_pkt_init(&n->rx_pkt, false);
+
+ if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
+ virtio_net_load_ebpf(n);
+ }
}
static void virtio_net_device_unrealize(DeviceState *dev)
@@ -3360,6 +3464,10 @@ static void virtio_net_device_unrealize(DeviceState *dev)
VirtIONet *n = VIRTIO_NET(dev);
int i, max_queues;
+ if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
+ virtio_net_unload_ebpf(n);
+ }
+
/* This will stop vhost backend if appropriate. */
virtio_net_set_status(vdev, 0);
@@ -3402,6 +3510,8 @@ static void virtio_net_instance_init(Object *obj)
device_add_bootindex_property(obj, &n->nic_conf.bootindex,
"bootindex", "/ethernet-phy@0",
DEVICE(n));
+
+ ebpf_rss_init(&n->ebpf_rss);
}
static int virtio_net_pre_save(void *opaque)
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index 7e96d193aa..824a69c23f 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -21,6 +21,8 @@
#include "qemu/option_int.h"
#include "qom/object.h"
+#include "ebpf/ebpf_rss.h"
+
#define TYPE_VIRTIO_NET "virtio-net-device"
OBJECT_DECLARE_SIMPLE_TYPE(VirtIONet, VIRTIO_NET)
@@ -130,6 +132,7 @@ typedef struct VirtioNetRscChain {
typedef struct VirtioNetRssData {
bool enabled;
+ bool enabled_software_rss;
bool redirect;
bool populate_hash;
uint32_t hash_types;
@@ -209,6 +212,7 @@ struct VirtIONet {
Notifier migration_state;
VirtioNetRssData rss_data;
struct NetRxPkt *rx_pkt;
+ struct EBPFRSSContext ebpf_rss;
};
void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
index fe659ec9e2..8b14215549 100644
--- a/net/vhost-vdpa.c
+++ b/net/vhost-vdpa.c
@@ -54,6 +54,8 @@ const int vdpa_feature_bits[] = {
VIRTIO_NET_F_MTU,
VIRTIO_F_IOMMU_PLATFORM,
VIRTIO_F_RING_PACKED,
+ VIRTIO_NET_F_RSS,
+ VIRTIO_NET_F_HASH_REPORT,
VIRTIO_NET_F_GUEST_ANNOUNCE,
VIRTIO_NET_F_STATUS,
VHOST_INVALID_FEATURE_BIT