aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-06-04 13:38:48 +0100
committerPeter Maydell <peter.maydell@linaro.org>2021-06-04 13:38:49 +0100
commit1cbd2d914939ee6028e9688d4ba859a528c28405 (patch)
tree6255cafeb0a6079ccfa1f2aced089f90e6d5f3e1 /hw
parent5a95f5ce3cd5842cc8f61a91ecd4fb4e8d10104f (diff)
parent90322e646e87c1440661cb3ddbc0cc94309d8a4f (diff)
Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging
# gpg: Signature made Fri 04 Jun 2021 08:26:16 BST # gpg: using RSA key EF04965B398D6211 # gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" [marginal] # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 215D 46F4 8246 689E C77F 3562 EF04 965B 398D 6211 * remotes/jasowang/tags/net-pull-request: MAINTAINERS: Added eBPF maintainers information. docs: Added eBPF documentation. virtio-net: Added eBPF RSS to virtio-net. ebpf: Added eBPF RSS loader. ebpf: Added eBPF RSS program. net: Added SetSteeringEBPF method for NetClientState. net/tap: Added TUNSETSTEERINGEBPF code. Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/net/vhost_net.c3
-rw-r--r--hw/net/virtio-net.c116
2 files changed, 116 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 05bd50d3f6..bd7958b9f0 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);
@@ -3403,6 +3511,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)