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