1
The following changes since commit 92f8c6fef13b31ba222c4d20ad8afd2b79c4c28e:
1
The following changes since commit 7fe7fae8b48e3f9c647fd685e5155ebc8e6fb84d:
2
2
3
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210525' into staging (2021-05-25 16:17:06 +0100)
3
Merge remote-tracking branch 'remotes/dgilbert-gitlab/tags/pull-migration-20210609a' into staging (2021-06-09 16:40:21 +0100)
4
4
5
are available in the git repository at:
5
are available in the git repository at:
6
6
7
https://github.com/jasowang/qemu.git tags/net-pull-request
7
https://github.com/jasowang/qemu.git tags/net-pull-request
8
8
9
for you to fetch changes up to 90322e646e87c1440661cb3ddbc0cc94309d8a4f:
9
for you to fetch changes up to 5a2d9929ac1f01a1e8ef2a3f56f69e6069863dad:
10
10
11
MAINTAINERS: Added eBPF maintainers information. (2021-06-04 15:25:46 +0800)
11
Fixed calculation error of pkt->header_size in fill_pkt_tcp_info() (2021-06-11 10:30:13 +0800)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
14
15
----------------------------------------------------------------
15
----------------------------------------------------------------
16
Andrew Melnychenko (7):
16
Jason Wang (4):
17
net/tap: Added TUNSETSTEERINGEBPF code.
17
vhost-vdpa: skip ram device from the IOTLB mapping
18
net: Added SetSteeringEBPF method for NetClientState.
18
vhost-vdpa: map virtqueue notification area if possible
19
ebpf: Added eBPF RSS program.
19
vhost-vdpa: don't initialize backend_features
20
ebpf: Added eBPF RSS loader.
20
vhost-vdpa: remove the unused vhost_vdpa_get_acked_features()
21
virtio-net: Added eBPF RSS to virtio-net.
22
docs: Added eBPF documentation.
23
MAINTAINERS: Added eBPF maintainers information.
24
21
25
MAINTAINERS | 8 +
22
Paolo Bonzini (1):
26
configure | 8 +-
23
netdev: add more commands to preconfig mode
27
docs/devel/ebpf_rss.rst | 125 +++++++++
24
28
docs/devel/index.rst | 1 +
25
Rao, Lei (7):
29
ebpf/ebpf_rss-stub.c | 40 +++
26
Remove some duplicate trace code.
30
ebpf/ebpf_rss.c | 165 ++++++++++++
27
Fix the qemu crash when guest shutdown during checkpoint
31
ebpf/ebpf_rss.h | 44 ++++
28
Optimize the function of filter_send
32
ebpf/meson.build | 1 +
29
Remove migrate_set_block_enabled in checkpoint
33
ebpf/rss.bpf.skeleton.h | 431 +++++++++++++++++++++++++++++++
30
Add a function named packet_new_nocopy for COLO.
34
ebpf/trace-events | 4 +
31
Add the function of colo_compare_cleanup
35
ebpf/trace.h | 1 +
32
Fixed calculation error of pkt->header_size in fill_pkt_tcp_info()
36
hw/net/vhost_net.c | 3 +
33
37
hw/net/virtio-net.c | 116 ++++++++-
34
hmp-commands.hx | 2 +
38
include/hw/virtio/virtio-net.h | 4 +
35
hw/virtio/vhost-vdpa.c | 100 +++++++++++++++++++++++++++++++++++------
39
include/net/net.h | 2 +
36
include/hw/virtio/vhost-vdpa.h | 6 +++
40
meson.build | 23 ++
37
include/net/vhost-vdpa.h | 1 -
41
meson_options.txt | 2 +
38
migration/colo.c | 6 ---
42
net/tap-bsd.c | 5 +
39
migration/migration.c | 4 ++
43
net/tap-linux.c | 13 +
40
net/colo-compare.c | 25 +++++------
44
net/tap-linux.h | 1 +
41
net/colo-compare.h | 1 +
45
net/tap-solaris.c | 5 +
42
net/colo.c | 25 +++++++----
46
net/tap-stub.c | 5 +
43
net/colo.h | 1 +
47
net/tap.c | 9 +
44
net/filter-mirror.c | 8 ++--
48
net/tap_int.h | 1 +
45
net/filter-rewriter.c | 3 +-
49
net/vhost-vdpa.c | 2 +
46
net/net.c | 4 ++
50
tools/ebpf/Makefile.ebpf | 21 ++
47
net/vhost-vdpa.c | 9 ----
51
tools/ebpf/rss.bpf.c | 571 +++++++++++++++++++++++++++++++++++++++++
48
qapi/net.json | 6 ++-
52
27 files changed, 1607 insertions(+), 4 deletions(-)
49
softmmu/runstate.c | 1 +
53
create mode 100644 docs/devel/ebpf_rss.rst
50
16 files changed, 143 insertions(+), 59 deletions(-)
54
create mode 100644 ebpf/ebpf_rss-stub.c
55
create mode 100644 ebpf/ebpf_rss.c
56
create mode 100644 ebpf/ebpf_rss.h
57
create mode 100644 ebpf/meson.build
58
create mode 100644 ebpf/rss.bpf.skeleton.h
59
create mode 100644 ebpf/trace-events
60
create mode 100644 ebpf/trace.h
61
create mode 100755 tools/ebpf/Makefile.ebpf
62
create mode 100644 tools/ebpf/rss.bpf.c
63
51
64
52
53
54
diff view generated by jsdifflib
New patch
1
vDPA is not tie to any specific hardware, for safety and simplicity,
2
vhost-vDPA doesn't allow MMIO area to be mapped via IOTLB. Only the
3
doorbell could be mapped via mmap(). So this patch exclude skip the
4
ram device from the IOTLB mapping.
1
5
6
Reviewed-by: Si-Wei Liu <si-wei.liu@oracle.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
9
hw/virtio/vhost-vdpa.c | 12 ++----------
10
1 file changed, 2 insertions(+), 10 deletions(-)
11
12
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/virtio/vhost-vdpa.c
15
+++ b/hw/virtio/vhost-vdpa.c
16
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_listener_skipped_section(MemoryRegionSection *section)
17
{
18
return (!memory_region_is_ram(section->mr) &&
19
!memory_region_is_iommu(section->mr)) ||
20
+ /* vhost-vDPA doesn't allow MMIO to be mapped */
21
+ memory_region_is_ram_device(section->mr) ||
22
/*
23
* Sizing an enabled 64-bit BAR can cause spurious mappings to
24
* addresses in the upper part of the 64-bit address space. These
25
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener,
26
vaddr, section->readonly);
27
if (ret) {
28
error_report("vhost vdpa map fail!");
29
- if (memory_region_is_ram_device(section->mr)) {
30
- /* Allow unexpected mappings not to be fatal for RAM devices */
31
- error_report("map ram fail!");
32
- return ;
33
- }
34
goto fail;
35
}
36
37
return;
38
39
fail:
40
- if (memory_region_is_ram_device(section->mr)) {
41
- error_report("failed to vdpa_dma_map. pci p2p may not work");
42
- return;
43
-
44
- }
45
/*
46
* On the initfn path, store the first error in the container so we
47
* can gracefully fail. Runtime, there's not much we can do other
48
--
49
2.7.4
50
51
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
This patch implements the vq notification mapping support for
2
vhost-vDPA. This is simply done by using mmap()/munmap() for the
3
vhost-vDPA fd during device start/stop. For the device without
4
notification mapping support, we fall back to eventfd based
5
notification gracefully.
2
6
3
Added function that loads RSS eBPF program.
7
Reviewed-by: Si-Wei Liu <si-wei.liu@oracle.com>
4
Added stub functions for RSS eBPF loader.
5
Added meson and configuration options.
6
7
By default, eBPF feature enabled if libbpf is present in the build system.
8
libbpf checked in configuration shell script and meson script.
9
10
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
11
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
12
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
13
---
9
---
14
configure | 8 +-
10
hw/virtio/vhost-vdpa.c | 85 ++++++++++++++++++++++++++++++++++++++++++
15
ebpf/ebpf_rss-stub.c | 40 +++++
11
include/hw/virtio/vhost-vdpa.h | 6 +++
16
ebpf/ebpf_rss.c | 165 ++++++++++++++++++
12
2 files changed, 91 insertions(+)
17
ebpf/ebpf_rss.h | 44 +++++
18
ebpf/meson.build | 1 +
19
ebpf/rss.bpf.skeleton.h | 431 ++++++++++++++++++++++++++++++++++++++++++++++++
20
ebpf/trace-events | 4 +
21
ebpf/trace.h | 1 +
22
meson.build | 23 +++
23
meson_options.txt | 2 +
24
10 files changed, 718 insertions(+), 1 deletion(-)
25
create mode 100644 ebpf/ebpf_rss-stub.c
26
create mode 100644 ebpf/ebpf_rss.c
27
create mode 100644 ebpf/ebpf_rss.h
28
create mode 100644 ebpf/meson.build
29
create mode 100644 ebpf/rss.bpf.skeleton.h
30
create mode 100644 ebpf/trace-events
31
create mode 100644 ebpf/trace.h
32
13
33
diff --git a/configure b/configure
14
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
34
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100644
35
--- a/configure
16
--- a/hw/virtio/vhost-vdpa.c
36
+++ b/configure
17
+++ b/hw/virtio/vhost-vdpa.c
37
@@ -XXX,XX +XXX,XX @@ vhost_vsock="$default_feature"
18
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque)
38
vhost_user="no"
19
return 0;
39
vhost_user_blk_server="auto"
20
}
40
vhost_user_fs="$default_feature"
21
41
+bpf="auto"
22
+static void vhost_vdpa_host_notifier_uninit(struct vhost_dev *dev,
42
kvm="auto"
23
+ int queue_index)
43
hax="auto"
24
+{
44
hvf="auto"
25
+ size_t page_size = qemu_real_host_page_size;
45
@@ -XXX,XX +XXX,XX @@ for opt do
26
+ struct vhost_vdpa *v = dev->opaque;
46
;;
27
+ VirtIODevice *vdev = dev->vdev;
47
--enable-membarrier) membarrier="yes"
28
+ VhostVDPAHostNotifier *n;
48
;;
49
+ --disable-bpf) bpf="disabled"
50
+ ;;
51
+ --enable-bpf) bpf="enabled"
52
+ ;;
53
--disable-blobs) blobs="false"
54
;;
55
--with-pkgversion=*) pkgversion="$optarg"
56
@@ -XXX,XX +XXX,XX @@ disabled with --disable-FEATURE, default is enabled if available
57
vhost-user vhost-user backend support
58
vhost-user-blk-server vhost-user-blk server support
59
vhost-vdpa vhost-vdpa kernel backend support
60
+ bpf BPF kernel support
61
spice spice
62
spice-protocol spice-protocol
63
rbd rados block device (rbd)
64
@@ -XXX,XX +XXX,XX @@ if test "$skip_meson" = no; then
65
-Dattr=$attr -Ddefault_devices=$default_devices \
66
-Ddocs=$docs -Dsphinx_build=$sphinx_build -Dinstall_blobs=$blobs \
67
-Dvhost_user_blk_server=$vhost_user_blk_server -Dmultiprocess=$multiprocess \
68
- -Dfuse=$fuse -Dfuse_lseek=$fuse_lseek -Dguest_agent_msi=$guest_agent_msi \
69
+ -Dfuse=$fuse -Dfuse_lseek=$fuse_lseek -Dguest_agent_msi=$guest_agent_msi -Dbpf=$bpf\
70
$(if test "$default_features" = no; then echo "-Dauto_features=disabled"; fi) \
71
    -Dtcg_interpreter=$tcg_interpreter \
72
$cross_arg \
73
diff --git a/ebpf/ebpf_rss-stub.c b/ebpf/ebpf_rss-stub.c
74
new file mode 100644
75
index XXXXXXX..XXXXXXX
76
--- /dev/null
77
+++ b/ebpf/ebpf_rss-stub.c
78
@@ -XXX,XX +XXX,XX @@
79
+/*
80
+ * eBPF RSS stub file
81
+ *
82
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
83
+ *
84
+ * Authors:
85
+ * Yuri Benditovich <yuri.benditovich@daynix.com>
86
+ *
87
+ * This work is licensed under the terms of the GNU GPL, version 2. See
88
+ * the COPYING file in the top-level directory.
89
+ */
90
+
29
+
91
+#include "qemu/osdep.h"
30
+ n = &v->notifier[queue_index];
92
+#include "ebpf/ebpf_rss.h"
93
+
31
+
94
+void ebpf_rss_init(struct EBPFRSSContext *ctx)
32
+ if (n->addr) {
95
+{
33
+ virtio_queue_set_host_notifier_mr(vdev, queue_index, &n->mr, false);
96
+
34
+ object_unparent(OBJECT(&n->mr));
97
+}
35
+ munmap(n->addr, page_size);
98
+
36
+ n->addr = NULL;
99
+bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
100
+{
101
+ return false;
102
+}
103
+
104
+bool ebpf_rss_load(struct EBPFRSSContext *ctx)
105
+{
106
+ return false;
107
+}
108
+
109
+bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
110
+ uint16_t *indirections_table, uint8_t *toeplitz_key)
111
+{
112
+ return false;
113
+}
114
+
115
+void ebpf_rss_unload(struct EBPFRSSContext *ctx)
116
+{
117
+
118
+}
119
diff --git a/ebpf/ebpf_rss.c b/ebpf/ebpf_rss.c
120
new file mode 100644
121
index XXXXXXX..XXXXXXX
122
--- /dev/null
123
+++ b/ebpf/ebpf_rss.c
124
@@ -XXX,XX +XXX,XX @@
125
+/*
126
+ * eBPF RSS loader
127
+ *
128
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
129
+ *
130
+ * Authors:
131
+ * Andrew Melnychenko <andrew@daynix.com>
132
+ * Yuri Benditovich <yuri.benditovich@daynix.com>
133
+ *
134
+ * This work is licensed under the terms of the GNU GPL, version 2. See
135
+ * the COPYING file in the top-level directory.
136
+ */
137
+
138
+#include "qemu/osdep.h"
139
+#include "qemu/error-report.h"
140
+
141
+#include <bpf/libbpf.h>
142
+#include <bpf/bpf.h>
143
+
144
+#include "hw/virtio/virtio-net.h" /* VIRTIO_NET_RSS_MAX_TABLE_LEN */
145
+
146
+#include "ebpf/ebpf_rss.h"
147
+#include "ebpf/rss.bpf.skeleton.h"
148
+#include "trace.h"
149
+
150
+void ebpf_rss_init(struct EBPFRSSContext *ctx)
151
+{
152
+ if (ctx != NULL) {
153
+ ctx->obj = NULL;
154
+ }
37
+ }
155
+}
38
+}
156
+
39
+
157
+bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
40
+static void vhost_vdpa_host_notifiers_uninit(struct vhost_dev *dev, int n)
158
+{
41
+{
159
+ return ctx != NULL && ctx->obj != NULL;
42
+ int i;
43
+
44
+ for (i = 0; i < n; i++) {
45
+ vhost_vdpa_host_notifier_uninit(dev, i);
46
+ }
160
+}
47
+}
161
+
48
+
162
+bool ebpf_rss_load(struct EBPFRSSContext *ctx)
49
+static int vhost_vdpa_host_notifier_init(struct vhost_dev *dev, int queue_index)
163
+{
50
+{
164
+ struct rss_bpf *rss_bpf_ctx;
51
+ size_t page_size = qemu_real_host_page_size;
52
+ struct vhost_vdpa *v = dev->opaque;
53
+ VirtIODevice *vdev = dev->vdev;
54
+ VhostVDPAHostNotifier *n;
55
+ int fd = v->device_fd;
56
+ void *addr;
57
+ char *name;
165
+
58
+
166
+ if (ctx == NULL) {
59
+ vhost_vdpa_host_notifier_uninit(dev, queue_index);
167
+ return false;
60
+
61
+ n = &v->notifier[queue_index];
62
+
63
+ addr = mmap(NULL, page_size, PROT_WRITE, MAP_SHARED, fd,
64
+ queue_index * page_size);
65
+ if (addr == MAP_FAILED) {
66
+ goto err;
168
+ }
67
+ }
169
+
68
+
170
+ rss_bpf_ctx = rss_bpf__open();
69
+ name = g_strdup_printf("vhost-vdpa/host-notifier@%p mmaps[%d]",
171
+ if (rss_bpf_ctx == NULL) {
70
+ v, queue_index);
172
+ trace_ebpf_error("eBPF RSS", "can not open eBPF RSS object");
71
+ memory_region_init_ram_device_ptr(&n->mr, OBJECT(vdev), name,
173
+ goto error;
72
+ page_size, addr);
73
+ g_free(name);
74
+
75
+ if (virtio_queue_set_host_notifier_mr(vdev, queue_index, &n->mr, true)) {
76
+ munmap(addr, page_size);
77
+ goto err;
78
+ }
79
+ n->addr = addr;
80
+
81
+ return 0;
82
+
83
+err:
84
+ return -1;
85
+}
86
+
87
+static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev)
88
+{
89
+ int i;
90
+
91
+ for (i = dev->vq_index; i < dev->vq_index + dev->nvqs; i++) {
92
+ if (vhost_vdpa_host_notifier_init(dev, i)) {
93
+ goto err;
94
+ }
174
+ }
95
+ }
175
+
96
+
176
+ bpf_program__set_socket_filter(rss_bpf_ctx->progs.tun_rss_steering_prog);
97
+ return;
177
+
98
+
178
+ if (rss_bpf__load(rss_bpf_ctx)) {
99
+err:
179
+ trace_ebpf_error("eBPF RSS", "can not load RSS program");
100
+ vhost_vdpa_host_notifiers_uninit(dev, i);
180
+ goto error;
101
+ return;
181
+ }
182
+
183
+ ctx->obj = rss_bpf_ctx;
184
+ ctx->program_fd = bpf_program__fd(
185
+ rss_bpf_ctx->progs.tun_rss_steering_prog);
186
+ ctx->map_configuration = bpf_map__fd(
187
+ rss_bpf_ctx->maps.tap_rss_map_configurations);
188
+ ctx->map_indirections_table = bpf_map__fd(
189
+ rss_bpf_ctx->maps.tap_rss_map_indirection_table);
190
+ ctx->map_toeplitz_key = bpf_map__fd(
191
+ rss_bpf_ctx->maps.tap_rss_map_toeplitz_key);
192
+
193
+ return true;
194
+error:
195
+ rss_bpf__destroy(rss_bpf_ctx);
196
+ ctx->obj = NULL;
197
+
198
+ return false;
199
+}
102
+}
200
+
103
+
201
+static bool ebpf_rss_set_config(struct EBPFRSSContext *ctx,
104
static int vhost_vdpa_cleanup(struct vhost_dev *dev)
202
+ struct EBPFRSSConfig *config)
105
{
203
+{
106
struct vhost_vdpa *v;
204
+ uint32_t map_key = 0;
107
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_VDPA);
108
v = dev->opaque;
109
trace_vhost_vdpa_cleanup(dev, v);
110
+ vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
111
memory_listener_unregister(&v->listener);
112
113
dev->opaque = NULL;
114
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
115
if (started) {
116
uint8_t status = 0;
117
memory_listener_register(&v->listener, &address_space_memory);
118
+ vhost_vdpa_host_notifiers_init(dev);
119
vhost_vdpa_set_vring_ready(dev);
120
vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
121
vhost_vdpa_call(dev, VHOST_VDPA_GET_STATUS, &status);
122
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
123
vhost_vdpa_reset_device(dev);
124
vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE |
125
VIRTIO_CONFIG_S_DRIVER);
126
+ vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
127
memory_listener_unregister(&v->listener);
128
129
return 0;
130
diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h
131
index XXXXXXX..XXXXXXX 100644
132
--- a/include/hw/virtio/vhost-vdpa.h
133
+++ b/include/hw/virtio/vhost-vdpa.h
134
@@ -XXX,XX +XXX,XX @@
135
136
#include "hw/virtio/virtio.h"
137
138
+typedef struct VhostVDPAHostNotifier {
139
+ MemoryRegion mr;
140
+ void *addr;
141
+} VhostVDPAHostNotifier;
205
+
142
+
206
+ if (!ebpf_rss_is_loaded(ctx)) {
143
typedef struct vhost_vdpa {
207
+ return false;
144
int device_fd;
208
+ }
145
uint32_t msg_type;
209
+ if (bpf_map_update_elem(ctx->map_configuration,
146
MemoryListener listener;
210
+ &map_key, config, 0) < 0) {
147
struct vhost_dev *dev;
211
+ return false;
148
+ VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX];
212
+ }
149
} VhostVDPA;
213
+ return true;
150
214
+}
151
#endif
215
+
216
+static bool ebpf_rss_set_indirections_table(struct EBPFRSSContext *ctx,
217
+ uint16_t *indirections_table,
218
+ size_t len)
219
+{
220
+ uint32_t i = 0;
221
+
222
+ if (!ebpf_rss_is_loaded(ctx) || indirections_table == NULL ||
223
+ len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
224
+ return false;
225
+ }
226
+
227
+ for (; i < len; ++i) {
228
+ if (bpf_map_update_elem(ctx->map_indirections_table, &i,
229
+ indirections_table + i, 0) < 0) {
230
+ return false;
231
+ }
232
+ }
233
+ return true;
234
+}
235
+
236
+static bool ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx,
237
+ uint8_t *toeplitz_key)
238
+{
239
+ uint32_t map_key = 0;
240
+
241
+ /* prepare toeplitz key */
242
+ uint8_t toe[VIRTIO_NET_RSS_MAX_KEY_SIZE] = {};
243
+
244
+ if (!ebpf_rss_is_loaded(ctx) || toeplitz_key == NULL) {
245
+ return false;
246
+ }
247
+ memcpy(toe, toeplitz_key, VIRTIO_NET_RSS_MAX_KEY_SIZE);
248
+ *(uint32_t *)toe = ntohl(*(uint32_t *)toe);
249
+
250
+ if (bpf_map_update_elem(ctx->map_toeplitz_key, &map_key, toe,
251
+ 0) < 0) {
252
+ return false;
253
+ }
254
+ return true;
255
+}
256
+
257
+bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
258
+ uint16_t *indirections_table, uint8_t *toeplitz_key)
259
+{
260
+ if (!ebpf_rss_is_loaded(ctx) || config == NULL ||
261
+ indirections_table == NULL || toeplitz_key == NULL) {
262
+ return false;
263
+ }
264
+
265
+ if (!ebpf_rss_set_config(ctx, config)) {
266
+ return false;
267
+ }
268
+
269
+ if (!ebpf_rss_set_indirections_table(ctx, indirections_table,
270
+ config->indirections_len)) {
271
+ return false;
272
+ }
273
+
274
+ if (!ebpf_rss_set_toepliz_key(ctx, toeplitz_key)) {
275
+ return false;
276
+ }
277
+
278
+ return true;
279
+}
280
+
281
+void ebpf_rss_unload(struct EBPFRSSContext *ctx)
282
+{
283
+ if (!ebpf_rss_is_loaded(ctx)) {
284
+ return;
285
+ }
286
+
287
+ rss_bpf__destroy(ctx->obj);
288
+ ctx->obj = NULL;
289
+}
290
diff --git a/ebpf/ebpf_rss.h b/ebpf/ebpf_rss.h
291
new file mode 100644
292
index XXXXXXX..XXXXXXX
293
--- /dev/null
294
+++ b/ebpf/ebpf_rss.h
295
@@ -XXX,XX +XXX,XX @@
296
+/*
297
+ * eBPF RSS header
298
+ *
299
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
300
+ *
301
+ * Authors:
302
+ * Andrew Melnychenko <andrew@daynix.com>
303
+ * Yuri Benditovich <yuri.benditovich@daynix.com>
304
+ *
305
+ * This work is licensed under the terms of the GNU GPL, version 2. See
306
+ * the COPYING file in the top-level directory.
307
+ */
308
+
309
+#ifndef QEMU_EBPF_RSS_H
310
+#define QEMU_EBPF_RSS_H
311
+
312
+struct EBPFRSSContext {
313
+ void *obj;
314
+ int program_fd;
315
+ int map_configuration;
316
+ int map_toeplitz_key;
317
+ int map_indirections_table;
318
+};
319
+
320
+struct EBPFRSSConfig {
321
+ uint8_t redirect;
322
+ uint8_t populate_hash;
323
+ uint32_t hash_types;
324
+ uint16_t indirections_len;
325
+ uint16_t default_queue;
326
+} __attribute__((packed));
327
+
328
+void ebpf_rss_init(struct EBPFRSSContext *ctx);
329
+
330
+bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx);
331
+
332
+bool ebpf_rss_load(struct EBPFRSSContext *ctx);
333
+
334
+bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
335
+ uint16_t *indirections_table, uint8_t *toeplitz_key);
336
+
337
+void ebpf_rss_unload(struct EBPFRSSContext *ctx);
338
+
339
+#endif /* QEMU_EBPF_RSS_H */
340
diff --git a/ebpf/meson.build b/ebpf/meson.build
341
new file mode 100644
342
index XXXXXXX..XXXXXXX
343
--- /dev/null
344
+++ b/ebpf/meson.build
345
@@ -0,0 +1 @@
346
+common_ss.add(when: libbpf, if_true: files('ebpf_rss.c'), if_false: files('ebpf_rss-stub.c'))
347
diff --git a/ebpf/rss.bpf.skeleton.h b/ebpf/rss.bpf.skeleton.h
348
new file mode 100644
349
index XXXXXXX..XXXXXXX
350
--- /dev/null
351
+++ b/ebpf/rss.bpf.skeleton.h
352
@@ -XXX,XX +XXX,XX @@
353
+/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
354
+
355
+/* THIS FILE IS AUTOGENERATED! */
356
+#ifndef __RSS_BPF_SKEL_H__
357
+#define __RSS_BPF_SKEL_H__
358
+
359
+#include <stdlib.h>
360
+#include <bpf/libbpf.h>
361
+
362
+struct rss_bpf {
363
+    struct bpf_object_skeleton *skeleton;
364
+    struct bpf_object *obj;
365
+    struct {
366
+        struct bpf_map *tap_rss_map_configurations;
367
+        struct bpf_map *tap_rss_map_indirection_table;
368
+        struct bpf_map *tap_rss_map_toeplitz_key;
369
+    } maps;
370
+    struct {
371
+        struct bpf_program *tun_rss_steering_prog;
372
+    } progs;
373
+    struct {
374
+        struct bpf_link *tun_rss_steering_prog;
375
+    } links;
376
+};
377
+
378
+static void
379
+rss_bpf__destroy(struct rss_bpf *obj)
380
+{
381
+    if (!obj)
382
+        return;
383
+    if (obj->skeleton)
384
+        bpf_object__destroy_skeleton(obj->skeleton);
385
+    free(obj);
386
+}
387
+
388
+static inline int
389
+rss_bpf__create_skeleton(struct rss_bpf *obj);
390
+
391
+static inline struct rss_bpf *
392
+rss_bpf__open_opts(const struct bpf_object_open_opts *opts)
393
+{
394
+    struct rss_bpf *obj;
395
+
396
+    obj = (struct rss_bpf *)calloc(1, sizeof(*obj));
397
+    if (!obj)
398
+        return NULL;
399
+    if (rss_bpf__create_skeleton(obj))
400
+        goto err;
401
+    if (bpf_object__open_skeleton(obj->skeleton, opts))
402
+        goto err;
403
+
404
+    return obj;
405
+err:
406
+    rss_bpf__destroy(obj);
407
+    return NULL;
408
+}
409
+
410
+static inline struct rss_bpf *
411
+rss_bpf__open(void)
412
+{
413
+    return rss_bpf__open_opts(NULL);
414
+}
415
+
416
+static inline int
417
+rss_bpf__load(struct rss_bpf *obj)
418
+{
419
+    return bpf_object__load_skeleton(obj->skeleton);
420
+}
421
+
422
+static inline struct rss_bpf *
423
+rss_bpf__open_and_load(void)
424
+{
425
+    struct rss_bpf *obj;
426
+
427
+    obj = rss_bpf__open();
428
+    if (!obj)
429
+        return NULL;
430
+    if (rss_bpf__load(obj)) {
431
+        rss_bpf__destroy(obj);
432
+        return NULL;
433
+    }
434
+    return obj;
435
+}
436
+
437
+static inline int
438
+rss_bpf__attach(struct rss_bpf *obj)
439
+{
440
+    return bpf_object__attach_skeleton(obj->skeleton);
441
+}
442
+
443
+static inline void
444
+rss_bpf__detach(struct rss_bpf *obj)
445
+{
446
+    return bpf_object__detach_skeleton(obj->skeleton);
447
+}
448
+
449
+static inline int
450
+rss_bpf__create_skeleton(struct rss_bpf *obj)
451
+{
452
+    struct bpf_object_skeleton *s;
453
+
454
+    s = (struct bpf_object_skeleton *)calloc(1, sizeof(*s));
455
+    if (!s)
456
+        return -1;
457
+    obj->skeleton = s;
458
+
459
+    s->sz = sizeof(*s);
460
+    s->name = "rss_bpf";
461
+    s->obj = &obj->obj;
462
+
463
+    /* maps */
464
+    s->map_cnt = 3;
465
+    s->map_skel_sz = sizeof(*s->maps);
466
+    s->maps = (struct bpf_map_skeleton *)calloc(s->map_cnt, s->map_skel_sz);
467
+    if (!s->maps)
468
+        goto err;
469
+
470
+    s->maps[0].name = "tap_rss_map_configurations";
471
+    s->maps[0].map = &obj->maps.tap_rss_map_configurations;
472
+
473
+    s->maps[1].name = "tap_rss_map_indirection_table";
474
+    s->maps[1].map = &obj->maps.tap_rss_map_indirection_table;
475
+
476
+    s->maps[2].name = "tap_rss_map_toeplitz_key";
477
+    s->maps[2].map = &obj->maps.tap_rss_map_toeplitz_key;
478
+
479
+    /* programs */
480
+    s->prog_cnt = 1;
481
+    s->prog_skel_sz = sizeof(*s->progs);
482
+    s->progs = (struct bpf_prog_skeleton *)calloc(s->prog_cnt, s->prog_skel_sz);
483
+    if (!s->progs)
484
+        goto err;
485
+
486
+    s->progs[0].name = "tun_rss_steering_prog";
487
+    s->progs[0].prog = &obj->progs.tun_rss_steering_prog;
488
+    s->progs[0].link = &obj->links.tun_rss_steering_prog;
489
+
490
+    s->data_sz = 8088;
491
+    s->data = (void *)"\
492
+\x7f\x45\x4c\x46\x02\x01\x01\0\0\0\0\0\0\0\0\0\x01\0\xf7\0\x01\0\0\0\0\0\0\0\0\
493
+\0\0\0\0\0\0\0\0\0\0\0\x18\x1d\0\0\0\0\0\0\0\0\0\0\x40\0\0\0\0\0\x40\0\x0a\0\
494
+\x01\0\xbf\x18\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\x4c\xff\0\0\0\0\xbf\xa7\
495
+\0\0\0\0\0\0\x07\x07\0\0\x4c\xff\xff\xff\x18\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
496
+\xbf\x72\0\0\0\0\0\0\x85\0\0\0\x01\0\0\0\xbf\x06\0\0\0\0\0\0\x18\x01\0\0\0\0\0\
497
+\0\0\0\0\0\0\0\0\0\xbf\x72\0\0\0\0\0\0\x85\0\0\0\x01\0\0\0\xbf\x07\0\0\0\0\0\0\
498
+\x18\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0\x15\x06\x66\x02\0\0\0\0\xbf\x79\0\0\
499
+\0\0\0\0\x15\x09\x64\x02\0\0\0\0\x71\x61\0\0\0\0\0\0\x55\x01\x01\0\0\0\0\0\x05\
500
+\0\x5d\x02\0\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\xc0\xff\0\0\0\0\x7b\x1a\xb8\xff\
501
+\0\0\0\0\x7b\x1a\xb0\xff\0\0\0\0\x7b\x1a\xa8\xff\0\0\0\0\x7b\x1a\xa0\xff\0\0\0\
502
+\0\x63\x1a\x98\xff\0\0\0\0\x7b\x1a\x90\xff\0\0\0\0\x7b\x1a\x88\xff\0\0\0\0\x7b\
503
+\x1a\x80\xff\0\0\0\0\x7b\x1a\x78\xff\0\0\0\0\x7b\x1a\x70\xff\0\0\0\0\x7b\x1a\
504
+\x68\xff\0\0\0\0\x7b\x1a\x60\xff\0\0\0\0\x7b\x1a\x58\xff\0\0\0\0\x7b\x1a\x50\
505
+\xff\0\0\0\0\x15\x08\x4c\x02\0\0\0\0\x6b\x1a\xd0\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\
506
+\0\x07\x03\0\0\xd0\xff\xff\xff\xbf\x81\0\0\0\0\0\0\xb7\x02\0\0\x0c\0\0\0\xb7\
507
+\x04\0\0\x02\0\0\0\xb7\x05\0\0\0\0\0\0\x85\0\0\0\x44\0\0\0\x67\0\0\0\x20\0\0\0\
508
+\x77\0\0\0\x20\0\0\0\x55\0\x11\0\0\0\0\0\xb7\x02\0\0\x10\0\0\0\x69\xa1\xd0\xff\
509
+\0\0\0\0\xbf\x13\0\0\0\0\0\0\xdc\x03\0\0\x10\0\0\0\x15\x03\x02\0\0\x81\0\0\x55\
510
+\x03\x0c\0\xa8\x88\0\0\xb7\x02\0\0\x14\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\
511
+\xd0\xff\xff\xff\xbf\x81\0\0\0\0\0\0\xb7\x04\0\0\x02\0\0\0\xb7\x05\0\0\0\0\0\0\
512
+\x85\0\0\0\x44\0\0\0\x69\xa1\xd0\xff\0\0\0\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\
513
+\0\0\0\x15\0\x01\0\0\0\0\0\x05\0\x2f\x02\0\0\0\0\x15\x01\x2e\x02\0\0\0\0\x7b\
514
+\x9a\x30\xff\0\0\0\0\x15\x01\x57\0\x86\xdd\0\0\x55\x01\x3b\0\x08\0\0\0\x7b\x7a\
515
+\x20\xff\0\0\0\0\xb7\x07\0\0\x01\0\0\0\x73\x7a\x50\xff\0\0\0\0\xb7\x01\0\0\0\0\
516
+\0\0\x63\x1a\xe0\xff\0\0\0\0\x7b\x1a\xd8\xff\0\0\0\0\x7b\x1a\xd0\xff\0\0\0\0\
517
+\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xd0\xff\xff\xff\xbf\x81\0\0\0\0\0\0\xb7\x02\0\
518
+\0\0\0\0\0\xb7\x04\0\0\x14\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\x67\
519
+\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x55\0\x1a\x02\0\0\0\0\x69\xa1\xd6\xff\0\0\
520
+\0\0\x55\x01\x01\0\0\0\0\0\xb7\x07\0\0\0\0\0\0\x61\xa1\xdc\xff\0\0\0\0\x63\x1a\
521
+\x5c\xff\0\0\0\0\x61\xa1\xe0\xff\0\0\0\0\x63\x1a\x60\xff\0\0\0\0\x73\x7a\x56\
522
+\xff\0\0\0\0\x71\xa9\xd9\xff\0\0\0\0\x71\xa1\xd0\xff\0\0\0\0\x67\x01\0\0\x02\0\
523
+\0\0\x57\x01\0\0\x3c\0\0\0\x7b\x1a\x40\xff\0\0\0\0\x79\xa7\x20\xff\0\0\0\0\xbf\
524
+\x91\0\0\0\0\0\0\x57\x01\0\0\xff\0\0\0\x15\x01\x19\0\0\0\0\0\x71\xa1\x56\xff\0\
525
+\0\0\0\x55\x01\x17\0\0\0\0\0\x57\x09\0\0\xff\0\0\0\x15\x09\x7a\x01\x11\0\0\0\
526
+\x55\x09\x14\0\x06\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x53\xff\0\0\0\0\xb7\x01\
527
+\0\0\0\0\0\0\x63\x1a\xe0\xff\0\0\0\0\x7b\x1a\xd8\xff\0\0\0\0\x7b\x1a\xd0\xff\0\
528
+\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xd0\xff\xff\xff\xbf\x81\0\0\0\0\0\0\x79\
529
+\xa2\x40\xff\0\0\0\0\xb7\x04\0\0\x14\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\
530
+\0\0\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x55\0\xf4\x01\0\0\0\0\x69\xa1\
531
+\xd0\xff\0\0\0\0\x6b\x1a\x58\xff\0\0\0\0\x69\xa1\xd2\xff\0\0\0\0\x6b\x1a\x5a\
532
+\xff\0\0\0\0\x71\xa1\x50\xff\0\0\0\0\x15\x01\xd4\0\0\0\0\0\x71\x62\x03\0\0\0\0\
533
+\0\x67\x02\0\0\x08\0\0\0\x71\x61\x02\0\0\0\0\0\x4f\x12\0\0\0\0\0\0\x71\x63\x04\
534
+\0\0\0\0\0\x71\x61\x05\0\0\0\0\0\x67\x01\0\0\x08\0\0\0\x4f\x31\0\0\0\0\0\0\x67\
535
+\x01\0\0\x10\0\0\0\x4f\x21\0\0\0\0\0\0\x71\xa2\x53\xff\0\0\0\0\x79\xa0\x30\xff\
536
+\0\0\0\0\x15\x02\x06\x01\0\0\0\0\xbf\x12\0\0\0\0\0\0\x57\x02\0\0\x02\0\0\0\x15\
537
+\x02\x03\x01\0\0\0\0\x61\xa1\x5c\xff\0\0\0\0\x63\x1a\xa0\xff\0\0\0\0\x61\xa1\
538
+\x60\xff\0\0\0\0\x63\x1a\xa4\xff\0\0\0\0\x69\xa1\x58\xff\0\0\0\0\x6b\x1a\xa8\
539
+\xff\0\0\0\0\x69\xa1\x5a\xff\0\0\0\0\x6b\x1a\xaa\xff\0\0\0\0\x05\0\x65\x01\0\0\
540
+\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x51\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x7b\x1a\
541
+\xf0\xff\0\0\0\0\x7b\x1a\xe8\xff\0\0\0\0\x7b\x1a\xe0\xff\0\0\0\0\x7b\x1a\xd8\
542
+\xff\0\0\0\0\x7b\x1a\xd0\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xd0\xff\
543
+\xff\xff\xb7\x01\0\0\x28\0\0\0\x7b\x1a\x40\xff\0\0\0\0\xbf\x81\0\0\0\0\0\0\xb7\
544
+\x02\0\0\0\0\0\0\xb7\x04\0\0\x28\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\
545
+\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x55\0\x10\x01\0\0\0\0\x79\xa1\xe0\
546
+\xff\0\0\0\0\x63\x1a\x64\xff\0\0\0\0\x77\x01\0\0\x20\0\0\0\x63\x1a\x68\xff\0\0\
547
+\0\0\x79\xa1\xd8\xff\0\0\0\0\x63\x1a\x5c\xff\0\0\0\0\x77\x01\0\0\x20\0\0\0\x63\
548
+\x1a\x60\xff\0\0\0\0\x79\xa1\xe8\xff\0\0\0\0\x63\x1a\x6c\xff\0\0\0\0\x77\x01\0\
549
+\0\x20\0\0\0\x63\x1a\x70\xff\0\0\0\0\x79\xa1\xf0\xff\0\0\0\0\x63\x1a\x74\xff\0\
550
+\0\0\0\x77\x01\0\0\x20\0\0\0\x63\x1a\x78\xff\0\0\0\0\x71\xa9\xd6\xff\0\0\0\0\
551
+\x25\x09\xff\0\x3c\0\0\0\xb7\x01\0\0\x01\0\0\0\x6f\x91\0\0\0\0\0\0\x18\x02\0\0\
552
+\x01\0\0\0\0\0\0\0\0\x18\0\x1c\x5f\x21\0\0\0\0\0\0\x55\x01\x01\0\0\0\0\0\x05\0\
553
+\xf8\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x6b\x1a\xfe\xff\0\0\0\0\xb7\x01\0\0\x28\0\0\
554
+\0\x7b\x1a\x40\xff\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\x8c\xff\xff\xff\x7b\
555
+\x1a\x18\xff\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\x7c\xff\xff\xff\x7b\x1a\
556
+\x10\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x7b\x1a\x28\xff\0\0\0\0\x7b\x7a\x20\xff\0\
557
+\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xfe\xff\xff\xff\xbf\x81\0\0\0\0\0\0\x79\
558
+\xa2\x40\xff\0\0\0\0\xb7\x04\0\0\x02\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\
559
+\0\0\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x15\0\x01\0\0\0\0\0\x05\0\x90\
560
+\x01\0\0\0\0\xbf\x91\0\0\0\0\0\0\x15\x01\x23\0\x3c\0\0\0\x15\x01\x59\0\x2c\0\0\
561
+\0\x55\x01\x5a\0\x2b\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\xf8\xff\0\0\0\0\xbf\xa3\
562
+\0\0\0\0\0\0\x07\x03\0\0\xf8\xff\xff\xff\xbf\x81\0\0\0\0\0\0\x79\xa2\x40\xff\0\
563
+\0\0\0\xb7\x04\0\0\x04\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\xbf\x01\
564
+\0\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\x03\x01\0\0\0\
565
+\0\x71\xa1\xfa\xff\0\0\0\0\x55\x01\x4b\0\x02\0\0\0\x71\xa1\xf9\xff\0\0\0\0\x55\
566
+\x01\x49\0\x02\0\0\0\x71\xa1\xfb\xff\0\0\0\0\x55\x01\x47\0\x01\0\0\0\x79\xa2\
567
+\x40\xff\0\0\0\0\x07\x02\0\0\x08\0\0\0\xbf\x81\0\0\0\0\0\0\x79\xa3\x18\xff\0\0\
568
+\0\0\xb7\x04\0\0\x10\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\xbf\x01\0\
569
+\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\xf2\0\0\0\0\0\
570
+\xb7\x01\0\0\x01\0\0\0\x73\x1a\x55\xff\0\0\0\0\x05\0\x39\0\0\0\0\0\xb7\x01\0\0\
571
+\0\0\0\0\x6b\x1a\xf8\xff\0\0\0\0\xb7\x09\0\0\x02\0\0\0\xb7\x07\0\0\x1e\0\0\0\
572
+\x05\0\x0e\0\0\0\0\0\x79\xa2\x38\xff\0\0\0\0\x0f\x29\0\0\0\0\0\0\xbf\x92\0\0\0\
573
+\0\0\0\x07\x02\0\0\x01\0\0\0\x71\xa3\xff\xff\0\0\0\0\x67\x03\0\0\x03\0\0\0\x2d\
574
+\x23\x02\0\0\0\0\0\x79\xa7\x20\xff\0\0\0\0\x05\0\x2b\0\0\0\0\0\x07\x07\0\0\xff\
575
+\xff\xff\xff\xbf\x72\0\0\0\0\0\0\x67\x02\0\0\x20\0\0\0\x77\x02\0\0\x20\0\0\0\
576
+\x15\x02\xf9\xff\0\0\0\0\x7b\x9a\x38\xff\0\0\0\0\x79\xa1\x40\xff\0\0\0\0\x0f\
577
+\x19\0\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xf8\xff\xff\xff\xbf\x81\0\0\0\
578
+\0\0\0\xbf\x92\0\0\0\0\0\0\xb7\x04\0\0\x02\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\
579
+\0\x44\0\0\0\xbf\x01\0\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\
580
+\x55\x01\x94\0\0\0\0\0\x71\xa2\xf8\xff\0\0\0\0\x55\x02\x0f\0\xc9\0\0\0\x07\x09\
581
+\0\0\x02\0\0\0\xbf\x81\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x79\xa3\x10\xff\0\0\0\0\
582
+\xb7\x04\0\0\x10\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\xbf\x01\0\0\0\
583
+\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\x87\0\0\0\0\0\xb7\
584
+\x01\0\0\x01\0\0\0\x73\x1a\x54\xff\0\0\0\0\x79\xa7\x20\xff\0\0\0\0\x05\0\x07\0\
585
+\0\0\0\0\xb7\x09\0\0\x01\0\0\0\x15\x02\xd1\xff\0\0\0\0\x71\xa9\xf9\xff\0\0\0\0\
586
+\x07\x09\0\0\x02\0\0\0\x05\0\xce\xff\0\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x56\
587
+\xff\0\0\0\0\x71\xa1\xff\xff\0\0\0\0\x67\x01\0\0\x03\0\0\0\x79\xa2\x40\xff\0\0\
588
+\0\0\x0f\x12\0\0\0\0\0\0\x07\x02\0\0\x08\0\0\0\x7b\x2a\x40\xff\0\0\0\0\x71\xa9\
589
+\xfe\xff\0\0\0\0\x25\x09\x0e\0\x3c\0\0\0\xb7\x01\0\0\x01\0\0\0\x6f\x91\0\0\0\0\
590
+\0\0\x18\x02\0\0\x01\0\0\0\0\0\0\0\0\x18\0\x1c\x5f\x21\0\0\0\0\0\0\x55\x01\x01\
591
+\0\0\0\0\0\x05\0\x07\0\0\0\0\0\x79\xa1\x28\xff\0\0\0\0\x07\x01\0\0\x01\0\0\0\
592
+\x7b\x1a\x28\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\
593
+\x82\xff\x0b\0\0\0\x05\0\x10\xff\0\0\0\0\x15\x09\xf8\xff\x87\0\0\0\x05\0\xfd\
594
+\xff\0\0\0\0\x71\xa1\x51\xff\0\0\0\0\x79\xa0\x30\xff\0\0\0\0\x15\x01\x17\x01\0\
595
+\0\0\0\x71\x62\x03\0\0\0\0\0\x67\x02\0\0\x08\0\0\0\x71\x61\x02\0\0\0\0\0\x4f\
596
+\x12\0\0\0\0\0\0\x71\x63\x04\0\0\0\0\0\x71\x61\x05\0\0\0\0\0\x67\x01\0\0\x08\0\
597
+\0\0\x4f\x31\0\0\0\0\0\0\x67\x01\0\0\x10\0\0\0\x4f\x21\0\0\0\0\0\0\x71\xa2\x53\
598
+\xff\0\0\0\0\x15\x02\x3d\0\0\0\0\0\xbf\x12\0\0\0\0\0\0\x57\x02\0\0\x10\0\0\0\
599
+\x15\x02\x3a\0\0\0\0\0\xbf\xa2\0\0\0\0\0\0\x07\x02\0\0\x5c\xff\xff\xff\x71\xa4\
600
+\x54\xff\0\0\0\0\xbf\x23\0\0\0\0\0\0\x15\x04\x02\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\
601
+\x07\x03\0\0\x7c\xff\xff\xff\x67\x01\0\0\x38\0\0\0\xc7\x01\0\0\x38\0\0\0\x65\
602
+\x01\x01\0\xff\xff\xff\xff\xbf\x32\0\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\
603
+\x6c\xff\xff\xff\x71\xa5\x55\xff\0\0\0\0\xbf\x34\0\0\0\0\0\0\x15\x05\x02\0\0\0\
604
+\0\0\xbf\xa4\0\0\0\0\0\0\x07\x04\0\0\x8c\xff\xff\xff\x65\x01\x01\0\xff\xff\xff\
605
+\xff\xbf\x43\0\0\0\0\0\0\x61\x21\x04\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\x24\0\
606
+\0\0\0\0\0\x4f\x41\0\0\0\0\0\0\x7b\x1a\xa0\xff\0\0\0\0\x61\x21\x08\0\0\0\0\0\
607
+\x61\x22\x0c\0\0\0\0\0\x67\x02\0\0\x20\0\0\0\x4f\x12\0\0\0\0\0\0\x7b\x2a\xa8\
608
+\xff\0\0\0\0\x61\x31\0\0\0\0\0\0\x61\x32\x04\0\0\0\0\0\x61\x34\x08\0\0\0\0\0\
609
+\x61\x33\x0c\0\0\0\0\0\x69\xa5\x5a\xff\0\0\0\0\x6b\x5a\xc2\xff\0\0\0\0\x69\xa5\
610
+\x58\xff\0\0\0\0\x6b\x5a\xc0\xff\0\0\0\0\x67\x03\0\0\x20\0\0\0\x4f\x43\0\0\0\0\
611
+\0\0\x7b\x3a\xb8\xff\0\0\0\0\x67\x02\0\0\x20\0\0\0\x4f\x12\0\0\0\0\0\0\x7b\x2a\
612
+\xb0\xff\0\0\0\0\x05\0\x6b\0\0\0\0\0\x71\xa2\x52\xff\0\0\0\0\x15\x02\x04\0\0\0\
613
+\0\0\xbf\x12\0\0\0\0\0\0\x57\x02\0\0\x04\0\0\0\x15\x02\x01\0\0\0\0\0\x05\0\xf7\
614
+\xfe\0\0\0\0\x57\x01\0\0\x01\0\0\0\x15\x01\xd3\0\0\0\0\0\x61\xa1\x5c\xff\0\0\0\
615
+\0\x63\x1a\xa0\xff\0\0\0\0\x61\xa1\x60\xff\0\0\0\0\x63\x1a\xa4\xff\0\0\0\0\x05\
616
+\0\x5e\0\0\0\0\0\x71\xa2\x52\xff\0\0\0\0\x15\x02\x1e\0\0\0\0\0\xbf\x12\0\0\0\0\
617
+\0\0\x57\x02\0\0\x20\0\0\0\x15\x02\x1b\0\0\0\0\0\xbf\xa2\0\0\0\0\0\0\x07\x02\0\
618
+\0\x5c\xff\xff\xff\x71\xa4\x54\xff\0\0\0\0\xbf\x23\0\0\0\0\0\0\x15\x04\x02\0\0\
619
+\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\x7c\xff\xff\xff\x57\x01\0\0\0\x01\0\0\
620
+\x15\x01\x01\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\x6c\
621
+\xff\xff\xff\x71\xa5\x55\xff\0\0\0\0\xbf\x34\0\0\0\0\0\0\x15\x05\x02\0\0\0\0\0\
622
+\xbf\xa4\0\0\0\0\0\0\x07\x04\0\0\x8c\xff\xff\xff\x15\x01\xc3\xff\0\0\0\0\x05\0\
623
+\xc1\xff\0\0\0\0\xb7\x09\0\0\x3c\0\0\0\x79\xa7\x20\xff\0\0\0\0\x67\0\0\0\x20\0\
624
+\0\0\x77\0\0\0\x20\0\0\0\x15\0\xa5\xfe\0\0\0\0\x05\0\xb0\0\0\0\0\0\x15\x09\x07\
625
+\xff\x87\0\0\0\x05\0\xa2\xfe\0\0\0\0\xbf\x12\0\0\0\0\0\0\x57\x02\0\0\x08\0\0\0\
626
+\x15\x02\xab\0\0\0\0\0\xbf\xa2\0\0\0\0\0\0\x07\x02\0\0\x5c\xff\xff\xff\x71\xa4\
627
+\x54\xff\0\0\0\0\xbf\x23\0\0\0\0\0\0\x15\x04\x02\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\
628
+\x07\x03\0\0\x7c\xff\xff\xff\x57\x01\0\0\x40\0\0\0\x15\x01\x01\0\0\0\0\0\xbf\
629
+\x32\0\0\0\0\0\0\x61\x23\x04\0\0\0\0\0\x67\x03\0\0\x20\0\0\0\x61\x24\0\0\0\0\0\
630
+\0\x4f\x43\0\0\0\0\0\0\x7b\x3a\xa0\xff\0\0\0\0\x61\x23\x08\0\0\0\0\0\x61\x22\
631
+\x0c\0\0\0\0\0\x67\x02\0\0\x20\0\0\0\x4f\x32\0\0\0\0\0\0\x7b\x2a\xa8\xff\0\0\0\
632
+\0\x15\x01\x1c\0\0\0\0\0\x71\xa1\x55\xff\0\0\0\0\x15\x01\x1a\0\0\0\0\0\x61\xa1\
633
+\x98\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\xa2\x94\xff\0\0\0\0\x4f\x21\0\0\0\0\
634
+\0\0\x7b\x1a\xb8\xff\0\0\0\0\x61\xa1\x90\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\
635
+\xa2\x8c\xff\0\0\0\0\x05\0\x19\0\0\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x52\xff\
636
+\0\0\0\0\xb7\x01\0\0\0\0\0\0\x7b\x1a\xd0\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\
637
+\x03\0\0\xd0\xff\xff\xff\xbf\x81\0\0\0\0\0\0\x79\xa2\x40\xff\0\0\0\0\xb7\x04\0\
638
+\0\x08\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\x67\0\0\0\x20\0\0\0\x77\
639
+\0\0\0\x20\0\0\0\x55\0\x7d\0\0\0\0\0\x05\0\x88\xfe\0\0\0\0\xb7\x09\0\0\x2b\0\0\
640
+\0\x05\0\xc6\xff\0\0\0\0\x61\xa1\x78\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\xa2\
641
+\x74\xff\0\0\0\0\x4f\x21\0\0\0\0\0\0\x7b\x1a\xb8\xff\0\0\0\0\x61\xa1\x70\xff\0\
642
+\0\0\0\x67\x01\0\0\x20\0\0\0\x61\xa2\x6c\xff\0\0\0\0\x4f\x21\0\0\0\0\0\0\x7b\
643
+\x1a\xb0\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x07\x07\0\0\x04\0\0\0\x61\x03\0\0\0\0\
644
+\0\0\xb7\x05\0\0\0\0\0\0\x05\0\x4e\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x75\0\0\0\
645
+\0\0\0\x0f\x15\0\0\0\0\0\0\x71\x55\0\0\0\0\0\0\x67\x03\0\0\x01\0\0\0\xbf\x50\0\
646
+\0\0\0\0\0\x77\0\0\0\x07\0\0\0\x4f\x03\0\0\0\0\0\0\xbf\x40\0\0\0\0\0\0\x67\0\0\
647
+\0\x39\0\0\0\xc7\0\0\0\x3f\0\0\0\x5f\x30\0\0\0\0\0\0\xaf\x02\0\0\0\0\0\0\xbf\
648
+\x50\0\0\0\0\0\0\x77\0\0\0\x06\0\0\0\x57\0\0\0\x01\0\0\0\x67\x03\0\0\x01\0\0\0\
649
+\x4f\x03\0\0\0\0\0\0\xbf\x40\0\0\0\0\0\0\x67\0\0\0\x3a\0\0\0\xc7\0\0\0\x3f\0\0\
650
+\0\x5f\x30\0\0\0\0\0\0\xaf\x02\0\0\0\0\0\0\x67\x03\0\0\x01\0\0\0\xbf\x50\0\0\0\
651
+\0\0\0\x77\0\0\0\x05\0\0\0\x57\0\0\0\x01\0\0\0\x4f\x03\0\0\0\0\0\0\xbf\x40\0\0\
652
+\0\0\0\0\x67\0\0\0\x3b\0\0\0\xc7\0\0\0\x3f\0\0\0\x5f\x30\0\0\0\0\0\0\xaf\x02\0\
653
+\0\0\0\0\0\x67\x03\0\0\x01\0\0\0\xbf\x50\0\0\0\0\0\0\x77\0\0\0\x04\0\0\0\x57\0\
654
+\0\0\x01\0\0\0\x4f\x03\0\0\0\0\0\0\xbf\x40\0\0\0\0\0\0\x67\0\0\0\x3c\0\0\0\xc7\
655
+\0\0\0\x3f\0\0\0\x5f\x30\0\0\0\0\0\0\xaf\x02\0\0\0\0\0\0\xbf\x50\0\0\0\0\0\0\
656
+\x77\0\0\0\x03\0\0\0\x57\0\0\0\x01\0\0\0\x67\x03\0\0\x01\0\0\0\x4f\x03\0\0\0\0\
657
+\0\0\xbf\x40\0\0\0\0\0\0\x67\0\0\0\x3d\0\0\0\xc7\0\0\0\x3f\0\0\0\x5f\x30\0\0\0\
658
+\0\0\0\xaf\x02\0\0\0\0\0\0\xbf\x50\0\0\0\0\0\0\x77\0\0\0\x02\0\0\0\x57\0\0\0\
659
+\x01\0\0\0\x67\x03\0\0\x01\0\0\0\x4f\x03\0\0\0\0\0\0\xbf\x40\0\0\0\0\0\0\x67\0\
660
+\0\0\x3e\0\0\0\xc7\0\0\0\x3f\0\0\0\x5f\x30\0\0\0\0\0\0\xaf\x02\0\0\0\0\0\0\xbf\
661
+\x50\0\0\0\0\0\0\x77\0\0\0\x01\0\0\0\x57\0\0\0\x01\0\0\0\x67\x03\0\0\x01\0\0\0\
662
+\x4f\x03\0\0\0\0\0\0\x57\x04\0\0\x01\0\0\0\x87\x04\0\0\0\0\0\0\x5f\x34\0\0\0\0\
663
+\0\0\xaf\x42\0\0\0\0\0\0\x57\x05\0\0\x01\0\0\0\x67\x03\0\0\x01\0\0\0\x4f\x53\0\
664
+\0\0\0\0\0\x07\x01\0\0\x01\0\0\0\xbf\x25\0\0\0\0\0\0\x15\x01\x0b\0\x24\0\0\0\
665
+\xbf\xa2\0\0\0\0\0\0\x07\x02\0\0\xa0\xff\xff\xff\x0f\x12\0\0\0\0\0\0\x71\x24\0\
666
+\0\0\0\0\0\xbf\x40\0\0\0\0\0\0\x67\0\0\0\x38\0\0\0\xc7\0\0\0\x38\0\0\0\xb7\x02\
667
+\0\0\0\0\0\0\x65\0\xa9\xff\xff\xff\xff\xff\xbf\x32\0\0\0\0\0\0\x05\0\xa7\xff\0\
668
+\0\0\0\xbf\x21\0\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x15\x01\
669
+\x0e\0\0\0\0\0\x71\x63\x06\0\0\0\0\0\x71\x64\x07\0\0\0\0\0\x67\x04\0\0\x08\0\0\
670
+\0\x4f\x34\0\0\0\0\0\0\x3f\x41\0\0\0\0\0\0\x2f\x41\0\0\0\0\0\0\x1f\x12\0\0\0\0\
671
+\0\0\x63\x2a\x50\xff\0\0\0\0\xbf\xa2\0\0\0\0\0\0\x07\x02\0\0\x50\xff\xff\xff\
672
+\x18\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x85\0\0\0\x01\0\0\0\x55\0\x05\0\0\0\0\0\
673
+\x71\x61\x08\0\0\0\0\0\x71\x60\x09\0\0\0\0\0\x67\0\0\0\x08\0\0\0\x4f\x10\0\0\0\
674
+\0\0\0\x95\0\0\0\0\0\0\0\x69\0\0\0\0\0\0\0\x05\0\xfd\xff\0\0\0\0\x02\0\0\0\x04\
675
+\0\0\0\x0a\0\0\0\x01\0\0\0\0\0\0\0\x02\0\0\0\x04\0\0\0\x28\0\0\0\x01\0\0\0\0\0\
676
+\0\0\x02\0\0\0\x04\0\0\0\x02\0\0\0\x80\0\0\0\0\0\0\0\x47\x50\x4c\x20\x76\x32\0\
677
+\0\0\0\0\0\x10\0\0\0\0\0\0\0\x01\x7a\x52\0\x08\x7c\x0b\x01\x0c\0\0\0\x18\0\0\0\
678
+\x18\0\0\0\0\0\0\0\0\0\0\0\xd8\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
679
+\0\0\0\0\0\0\0\0\0\0\0\0\xa0\0\0\0\x04\0\xf1\xff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
680
+\0\x60\x02\0\0\0\0\x03\0\x20\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3f\x02\0\0\0\0\
681
+\x03\0\xd0\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xed\x01\0\0\0\0\x03\0\x10\x10\0\0\0\
682
+\0\0\0\0\0\0\0\0\0\0\0\xd4\x01\0\0\0\0\x03\0\x20\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\
683
+\0\xa3\x01\0\0\0\0\x03\0\xb8\x12\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x63\x01\0\0\0\0\
684
+\x03\0\x48\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2a\x01\0\0\0\0\x03\0\x10\x13\0\0\0\
685
+\0\0\0\0\0\0\0\0\0\0\0\xe1\0\0\0\0\0\x03\0\xa0\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
686
+\x2e\x02\0\0\0\0\x03\0\x28\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\x02\0\0\0\0\x03\
687
+\0\xc0\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x36\x02\0\0\0\0\x03\0\xc8\x13\0\0\0\0\0\
688
+\0\0\0\0\0\0\0\0\0\x22\x01\0\0\0\0\x03\0\xe8\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
689
+\x02\x01\0\0\0\0\x03\0\x40\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd9\0\0\0\0\0\x03\0\
690
+\xf8\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x26\x02\0\0\0\0\x03\0\x20\x0e\0\0\0\0\0\0\
691
+\0\0\0\0\0\0\0\0\xcc\x01\0\0\0\0\x03\0\x60\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9b\
692
+\x01\0\0\0\0\x03\0\xc8\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5b\x01\0\0\0\0\x03\0\
693
+\x20\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7c\x01\0\0\0\0\x03\0\x48\x08\0\0\0\0\0\0\
694
+\0\0\0\0\0\0\0\0\x53\x01\0\0\0\0\x03\0\xb8\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1a\
695
+\x01\0\0\0\0\x03\0\xe0\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x84\x01\0\0\0\0\x03\0\
696
+\xb8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1e\x02\0\0\0\0\x03\0\xd8\x09\0\0\0\0\0\0\0\
697
+\0\0\0\0\0\0\0\xc4\x01\0\0\0\0\x03\0\x70\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x93\
698
+\x01\0\0\0\0\x03\0\xa8\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x74\x01\0\0\0\0\x03\0\
699
+\xf0\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4b\x01\0\0\0\0\x03\0\0\x0a\0\0\0\0\0\0\0\
700
+\0\0\0\0\0\0\0\x12\x01\0\0\0\0\x03\0\x10\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xfa\0\
701
+\0\0\0\0\x03\0\xc0\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x58\x02\0\0\0\0\x03\0\x88\
702
+\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x02\0\0\0\0\x03\0\xb8\x0a\0\0\0\0\0\0\0\0\
703
+\0\0\0\0\0\0\xe5\x01\0\0\0\0\x03\0\xc0\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xbc\x01\
704
+\0\0\0\0\x03\0\0\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8b\x01\0\0\0\0\x03\0\x18\x0e\
705
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd1\0\0\0\0\0\x03\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\
706
+\0\0\x50\x02\0\0\0\0\x03\0\x20\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0e\x02\0\0\0\0\
707
+\x03\0\x48\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6c\x01\0\0\0\0\x03\0\xb0\x04\0\0\0\
708
+\0\0\0\0\0\0\0\0\0\0\0\x43\x01\0\0\0\0\x03\0\xc8\x0c\0\0\0\0\0\0\0\0\0\0\0\0\0\
709
+\0\xc9\0\0\0\0\0\x03\0\xf8\x0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x06\x02\0\0\0\0\x03\
710
+\0\xd0\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3b\x01\0\0\0\0\x03\0\x98\x0b\0\0\0\0\0\
711
+\0\0\0\0\0\0\0\0\0\xf2\0\0\0\0\0\x03\0\xb8\x0b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x48\
712
+\x02\0\0\0\0\x03\0\xf0\x0b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xfe\x01\0\0\0\0\x03\0\
713
+\xf8\x0b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xdd\x01\0\0\0\0\x03\0\0\x0c\0\0\0\0\0\0\0\
714
+\0\0\0\0\0\0\0\xb4\x01\0\0\0\0\x03\0\x30\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0a\
715
+\x01\0\0\0\0\x03\0\x90\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc1\0\0\0\0\0\x03\0\xa8\
716
+\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xba\0\0\0\0\0\x03\0\xd0\x01\0\0\0\0\0\0\0\0\0\
717
+\0\0\0\0\0\xf6\x01\0\0\0\0\x03\0\xe0\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xac\x01\0\
718
+\0\0\0\x03\0\x30\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x33\x01\0\0\0\0\x03\0\x80\x0e\
719
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xea\0\0\0\0\0\x03\0\x98\x0e\0\0\0\0\0\0\0\0\0\0\0\
720
+\0\0\0\0\0\0\0\x03\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6b\0\0\0\x11\0\x06\
721
+\0\0\0\0\0\0\0\0\0\x07\0\0\0\0\0\0\0\x25\0\0\0\x11\0\x05\0\0\0\0\0\0\0\0\0\x14\
722
+\0\0\0\0\0\0\0\x82\0\0\0\x11\0\x05\0\x28\0\0\0\0\0\0\0\x14\0\0\0\0\0\0\0\x01\0\
723
+\0\0\x11\0\x05\0\x14\0\0\0\0\0\0\0\x14\0\0\0\0\0\0\0\x40\0\0\0\x12\0\x03\0\0\0\
724
+\0\0\0\0\0\0\xd8\x13\0\0\0\0\0\0\x28\0\0\0\0\0\0\0\x01\0\0\0\x3a\0\0\0\x50\0\0\
725
+\0\0\0\0\0\x01\0\0\0\x3c\0\0\0\x80\x13\0\0\0\0\0\0\x01\0\0\0\x3b\0\0\0\x1c\0\0\
726
+\0\0\0\0\0\x01\0\0\0\x38\0\0\0\0\x74\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\
727
+\x5f\x74\x6f\x65\x70\x6c\x69\x74\x7a\x5f\x6b\x65\x79\0\x2e\x74\x65\x78\x74\0\
728
+\x6d\x61\x70\x73\0\x74\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\x5f\x63\x6f\x6e\
729
+\x66\x69\x67\x75\x72\x61\x74\x69\x6f\x6e\x73\0\x74\x75\x6e\x5f\x72\x73\x73\x5f\
730
+\x73\x74\x65\x65\x72\x69\x6e\x67\x5f\x70\x72\x6f\x67\0\x2e\x72\x65\x6c\x74\x75\
731
+\x6e\x5f\x72\x73\x73\x5f\x73\x74\x65\x65\x72\x69\x6e\x67\0\x5f\x6c\x69\x63\x65\
732
+\x6e\x73\x65\0\x2e\x72\x65\x6c\x2e\x65\x68\x5f\x66\x72\x61\x6d\x65\0\x74\x61\
733
+\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\x5f\x69\x6e\x64\x69\x72\x65\x63\x74\x69\
734
+\x6f\x6e\x5f\x74\x61\x62\x6c\x65\0\x72\x73\x73\x2e\x62\x70\x66\x2e\x63\0\x2e\
735
+\x73\x74\x72\x74\x61\x62\0\x2e\x73\x79\x6d\x74\x61\x62\0\x4c\x42\x42\x30\x5f\
736
+\x39\0\x4c\x42\x42\x30\x5f\x38\x39\0\x4c\x42\x42\x30\x5f\x36\x39\0\x4c\x42\x42\
737
+\x30\x5f\x35\x39\0\x4c\x42\x42\x30\x5f\x31\x39\0\x4c\x42\x42\x30\x5f\x31\x30\
738
+\x39\0\x4c\x42\x42\x30\x5f\x39\x38\0\x4c\x42\x42\x30\x5f\x37\x38\0\x4c\x42\x42\
739
+\x30\x5f\x34\x38\0\x4c\x42\x42\x30\x5f\x31\x38\0\x4c\x42\x42\x30\x5f\x38\x37\0\
740
+\x4c\x42\x42\x30\x5f\x34\x37\0\x4c\x42\x42\x30\x5f\x33\x37\0\x4c\x42\x42\x30\
741
+\x5f\x31\x37\0\x4c\x42\x42\x30\x5f\x31\x30\x37\0\x4c\x42\x42\x30\x5f\x39\x36\0\
742
+\x4c\x42\x42\x30\x5f\x37\x36\0\x4c\x42\x42\x30\x5f\x36\x36\0\x4c\x42\x42\x30\
743
+\x5f\x34\x36\0\x4c\x42\x42\x30\x5f\x33\x36\0\x4c\x42\x42\x30\x5f\x32\x36\0\x4c\
744
+\x42\x42\x30\x5f\x31\x30\x36\0\x4c\x42\x42\x30\x5f\x36\x35\0\x4c\x42\x42\x30\
745
+\x5f\x34\x35\0\x4c\x42\x42\x30\x5f\x33\x35\0\x4c\x42\x42\x30\x5f\x34\0\x4c\x42\
746
+\x42\x30\x5f\x35\x34\0\x4c\x42\x42\x30\x5f\x34\x34\0\x4c\x42\x42\x30\x5f\x32\
747
+\x34\0\x4c\x42\x42\x30\x5f\x31\x30\x34\0\x4c\x42\x42\x30\x5f\x39\x33\0\x4c\x42\
748
+\x42\x30\x5f\x38\x33\0\x4c\x42\x42\x30\x5f\x35\x33\0\x4c\x42\x42\x30\x5f\x34\
749
+\x33\0\x4c\x42\x42\x30\x5f\x32\x33\0\x4c\x42\x42\x30\x5f\x31\x30\x33\0\x4c\x42\
750
+\x42\x30\x5f\x38\x32\0\x4c\x42\x42\x30\x5f\x35\x32\0\x4c\x42\x42\x30\x5f\x31\
751
+\x30\x32\0\x4c\x42\x42\x30\x5f\x39\x31\0\x4c\x42\x42\x30\x5f\x38\x31\0\x4c\x42\
752
+\x42\x30\x5f\x37\x31\0\x4c\x42\x42\x30\x5f\x36\x31\0\x4c\x42\x42\x30\x5f\x35\
753
+\x31\0\x4c\x42\x42\x30\x5f\x34\x31\0\x4c\x42\x42\x30\x5f\x32\x31\0\x4c\x42\x42\
754
+\x30\x5f\x31\x31\0\x4c\x42\x42\x30\x5f\x31\x31\x31\0\x4c\x42\x42\x30\x5f\x31\
755
+\x30\x31\0\x4c\x42\x42\x30\x5f\x38\x30\0\x4c\x42\x42\x30\x5f\x36\x30\0\x4c\x42\
756
+\x42\x30\x5f\x35\x30\0\x4c\x42\x42\x30\x5f\x31\x30\0\x4c\x42\x42\x30\x5f\x31\
757
+\x31\x30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
758
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xaa\
759
+\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa0\x1a\0\0\0\0\0\0\x71\x02\0\
760
+\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1a\0\0\0\x01\0\0\
761
+\0\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
762
+\0\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5a\0\0\0\x01\0\0\0\x06\0\0\0\0\0\0\
763
+\0\0\0\0\0\0\0\0\0\x40\0\0\0\0\0\0\0\xd8\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08\0\
764
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x56\0\0\0\x09\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
765
+\0\x60\x1a\0\0\0\0\0\0\x30\0\0\0\0\0\0\0\x09\0\0\0\x03\0\0\0\x08\0\0\0\0\0\0\0\
766
+\x10\0\0\0\0\0\0\0\x20\0\0\0\x01\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x18\
767
+\x14\0\0\0\0\0\0\x3c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\
768
+\0\0\0\x6c\0\0\0\x01\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x54\x14\0\0\0\0\0\
769
+\0\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x78\0\0\
770
+\0\x01\0\0\0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x60\x14\0\0\0\0\0\0\x30\0\0\0\0\
771
+\0\0\0\0\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x74\0\0\0\x09\0\0\0\0\
772
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x1a\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x09\0\0\0\
773
+\x07\0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\xb2\0\0\0\x02\0\0\0\0\0\0\0\0\0\
774
+\0\0\0\0\0\0\0\0\0\0\x90\x14\0\0\0\0\0\0\xd0\x05\0\0\0\0\0\0\x01\0\0\0\x39\0\0\
775
+\0\x08\0\0\0\0\0\0\0\x18\0\0\0\0\0\0\0";
776
+
777
+    return 0;
778
+err:
779
+    bpf_object__destroy_skeleton(s);
780
+    return -1;
781
+}
782
+
783
+#endif /* __RSS_BPF_SKEL_H__ */
784
diff --git a/ebpf/trace-events b/ebpf/trace-events
785
new file mode 100644
786
index XXXXXXX..XXXXXXX
787
--- /dev/null
788
+++ b/ebpf/trace-events
789
@@ -XXX,XX +XXX,XX @@
790
+# See docs/devel/tracing.txt for syntax documentation.
791
+
792
+# ebpf-rss.c
793
+ebpf_error(const char *s1, const char *s2) "error in %s: %s"
794
diff --git a/ebpf/trace.h b/ebpf/trace.h
795
new file mode 100644
796
index XXXXXXX..XXXXXXX
797
--- /dev/null
798
+++ b/ebpf/trace.h
799
@@ -0,0 +1 @@
800
+#include "trace/trace-ebpf.h"
801
diff --git a/meson.build b/meson.build
802
index XXXXXXX..XXXXXXX 100644
803
--- a/meson.build
804
+++ b/meson.build
805
@@ -XXX,XX +XXX,XX @@ if not get_option('fuse_lseek').disabled()
806
endif
807
endif
808
809
+# libbpf
810
+libbpf = dependency('libbpf', required: get_option('bpf'), method: 'pkg-config')
811
+if libbpf.found() and not cc.links('''
812
+ #include <bpf/libbpf.h>
813
+ int main(void)
814
+ {
815
+ bpf_object__destroy_skeleton(NULL);
816
+ return 0;
817
+ }''', dependencies: libbpf)
818
+ libbpf = not_found
819
+ if get_option('bpf').enabled()
820
+ error('libbpf skeleton test failed')
821
+ else
822
+ warning('libbpf skeleton test failed, disabling')
823
+ endif
824
+endif
825
+
826
if get_option('cfi')
827
cfi_flags=[]
828
# Check for dependency on LTO
829
@@ -XXX,XX +XXX,XX @@ endif
830
config_host_data.set('CONFIG_GTK', gtk.found())
831
config_host_data.set('CONFIG_LIBATTR', have_old_libattr)
832
config_host_data.set('CONFIG_LIBCAP_NG', libcap_ng.found())
833
+config_host_data.set('CONFIG_EBPF', libbpf.found())
834
config_host_data.set('CONFIG_LIBISCSI', libiscsi.found())
835
config_host_data.set('CONFIG_LIBNFS', libnfs.found())
836
config_host_data.set('CONFIG_RBD', rbd.found())
837
@@ -XXX,XX +XXX,XX @@ if have_system
838
'backends',
839
'backends/tpm',
840
'chardev',
841
+ 'ebpf',
842
'hw/9pfs',
843
'hw/acpi',
844
'hw/adc',
845
@@ -XXX,XX +XXX,XX @@ subdir('accel')
846
subdir('plugins')
847
subdir('bsd-user')
848
subdir('linux-user')
849
+subdir('ebpf')
850
+
851
+common_ss.add(libbpf)
852
853
bsd_user_ss.add(files('gdbstub.c'))
854
specific_ss.add_all(when: 'CONFIG_BSD_USER', if_true: bsd_user_ss)
855
@@ -XXX,XX +XXX,XX @@ summary_info += {'RDMA support': config_host.has_key('CONFIG_RDMA')}
856
summary_info += {'PVRDMA support': config_host.has_key('CONFIG_PVRDMA')}
857
summary_info += {'fdt support': fdt_opt == 'disabled' ? false : fdt_opt}
858
summary_info += {'libcap-ng support': libcap_ng.found()}
859
+summary_info += {'bpf support': libbpf.found()}
860
# TODO: add back protocol and server version
861
summary_info += {'spice support': config_host.has_key('CONFIG_SPICE')}
862
summary_info += {'rbd support': rbd.found()}
863
diff --git a/meson_options.txt b/meson_options.txt
864
index XXXXXXX..XXXXXXX 100644
865
--- a/meson_options.txt
866
+++ b/meson_options.txt
867
@@ -XXX,XX +XXX,XX @@ option('bzip2', type : 'feature', value : 'auto',
868
description: 'bzip2 support for DMG images')
869
option('cap_ng', type : 'feature', value : 'auto',
870
description: 'cap_ng support')
871
+option('bpf', type : 'feature', value : 'auto',
872
+ description: 'eBPF support')
873
option('cocoa', type : 'feature', value : 'auto',
874
description: 'Cocoa user interface (macOS only)')
875
option('curl', type : 'feature', value : 'auto',
876
--
152
--
877
2.7.4
153
2.7.4
878
154
879
155
diff view generated by jsdifflib
New patch
1
We used to initialize backend_features during vhost_vdpa_init()
2
regardless whether or not it was supported by vhost. This will lead
3
the unsupported features like VIRTIO_F_IN_ORDER to be included and set
4
to the vhost-vdpa during vhost_dev_start. Because the
5
VIRTIO_F_IN_ORDER is not supported by vhost-vdpa so it won't be
6
advertised to guest which will break the datapath.
1
7
8
Fix this by not initializing the backend_features, so the
9
acked_features could be built only from guest features via
10
vhost_net_ack_features().
11
12
Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend")
13
Cc: qemu-stable@nongnu.org
14
Cc: Gautam Dawar <gdawar@xilinx.com>
15
Signed-off-by: Jason Wang <jasowang@redhat.com>
16
---
17
hw/virtio/vhost-vdpa.c | 3 ---
18
1 file changed, 3 deletions(-)
19
20
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/hw/virtio/vhost-vdpa.c
23
+++ b/hw/virtio/vhost-vdpa.c
24
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_add_status(struct vhost_dev *dev, uint8_t status)
25
static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque)
26
{
27
struct vhost_vdpa *v;
28
- uint64_t features;
29
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_VDPA);
30
trace_vhost_vdpa_init(dev, opaque);
31
32
v = opaque;
33
v->dev = dev;
34
dev->opaque = opaque ;
35
- vhost_vdpa_call(dev, VHOST_GET_FEATURES, &features);
36
- dev->backend_features = features;
37
v->listener = vhost_vdpa_memory_listener;
38
v->msg_type = VHOST_IOTLB_MSG_V2;
39
40
--
41
2.7.4
42
43
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
No user for this helper, let's remove it.
2
2
3
When RSS is enabled the device tries to load the eBPF program
4
to select RX virtqueue in the TUN. If eBPF can be loaded
5
the RSS will function also with vhost (works with kernel 5.8 and later).
6
Software RSS is used as a fallback with vhost=off when eBPF can't be loaded
7
or when hash population requested by the guest.
8
9
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
10
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
3
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
4
---
13
hw/net/vhost_net.c | 3 ++
5
include/net/vhost-vdpa.h | 1 -
14
hw/net/virtio-net.c | 116 +++++++++++++++++++++++++++++++++++++++--
6
net/vhost-vdpa.c | 9 ---------
15
include/hw/virtio/virtio-net.h | 4 ++
7
2 files changed, 10 deletions(-)
16
net/vhost-vdpa.c | 2 +
17
4 files changed, 122 insertions(+), 3 deletions(-)
18
8
19
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
9
diff --git a/include/net/vhost-vdpa.h b/include/net/vhost-vdpa.h
20
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/net/vhost_net.c
11
--- a/include/net/vhost-vdpa.h
22
+++ b/hw/net/vhost_net.c
12
+++ b/include/net/vhost-vdpa.h
23
@@ -XXX,XX +XXX,XX @@ static const int kernel_feature_bits[] = {
24
VIRTIO_NET_F_MTU,
25
VIRTIO_F_IOMMU_PLATFORM,
26
VIRTIO_F_RING_PACKED,
27
+ VIRTIO_NET_F_HASH_REPORT,
28
VHOST_INVALID_FEATURE_BIT
29
};
30
31
@@ -XXX,XX +XXX,XX @@ static const int user_feature_bits[] = {
32
VIRTIO_NET_F_MTU,
33
VIRTIO_F_IOMMU_PLATFORM,
34
VIRTIO_F_RING_PACKED,
35
+ VIRTIO_NET_F_RSS,
36
+ VIRTIO_NET_F_HASH_REPORT,
37
38
/* This bit implies RARP isn't sent by QEMU out of band */
39
VIRTIO_NET_F_GUEST_ANNOUNCE,
40
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
41
index XXXXXXX..XXXXXXX 100644
42
--- a/hw/net/virtio-net.c
43
+++ b/hw/net/virtio-net.c
44
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
45
return features;
46
}
47
48
- virtio_clear_feature(&features, VIRTIO_NET_F_RSS);
49
- virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT);
50
+ if (!ebpf_rss_is_loaded(&n->ebpf_rss)) {
51
+ virtio_clear_feature(&features, VIRTIO_NET_F_RSS);
52
+ }
53
features = vhost_net_get_features(get_vhost_net(nc->peer), features);
54
vdev->backend_features = features;
55
56
@@ -XXX,XX +XXX,XX @@ static int virtio_net_handle_announce(VirtIONet *n, uint8_t cmd,
57
}
58
}
59
60
+static void virtio_net_detach_epbf_rss(VirtIONet *n);
61
+
62
static void virtio_net_disable_rss(VirtIONet *n)
63
{
64
if (n->rss_data.enabled) {
65
trace_virtio_net_rss_disable();
66
}
67
n->rss_data.enabled = false;
68
+
69
+ virtio_net_detach_epbf_rss(n);
70
+}
71
+
72
+static bool virtio_net_attach_ebpf_to_backend(NICState *nic, int prog_fd)
73
+{
74
+ NetClientState *nc = qemu_get_peer(qemu_get_queue(nic), 0);
75
+ if (nc == NULL || nc->info->set_steering_ebpf == NULL) {
76
+ return false;
77
+ }
78
+
79
+ return nc->info->set_steering_ebpf(nc, prog_fd);
80
+}
81
+
82
+static void rss_data_to_rss_config(struct VirtioNetRssData *data,
83
+ struct EBPFRSSConfig *config)
84
+{
85
+ config->redirect = data->redirect;
86
+ config->populate_hash = data->populate_hash;
87
+ config->hash_types = data->hash_types;
88
+ config->indirections_len = data->indirections_len;
89
+ config->default_queue = data->default_queue;
90
+}
91
+
92
+static bool virtio_net_attach_epbf_rss(VirtIONet *n)
93
+{
94
+ struct EBPFRSSConfig config = {};
95
+
96
+ if (!ebpf_rss_is_loaded(&n->ebpf_rss)) {
97
+ return false;
98
+ }
99
+
100
+ rss_data_to_rss_config(&n->rss_data, &config);
101
+
102
+ if (!ebpf_rss_set_all(&n->ebpf_rss, &config,
103
+ n->rss_data.indirections_table, n->rss_data.key)) {
104
+ return false;
105
+ }
106
+
107
+ if (!virtio_net_attach_ebpf_to_backend(n->nic, n->ebpf_rss.program_fd)) {
108
+ return false;
109
+ }
110
+
111
+ return true;
112
+}
113
+
114
+static void virtio_net_detach_epbf_rss(VirtIONet *n)
115
+{
116
+ virtio_net_attach_ebpf_to_backend(n->nic, -1);
117
+}
118
+
119
+static bool virtio_net_load_ebpf(VirtIONet *n)
120
+{
121
+ if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
122
+ /* backend does't support steering ebpf */
123
+ return false;
124
+ }
125
+
126
+ return ebpf_rss_load(&n->ebpf_rss);
127
+}
128
+
129
+static void virtio_net_unload_ebpf(VirtIONet *n)
130
+{
131
+ virtio_net_attach_ebpf_to_backend(n->nic, -1);
132
+ ebpf_rss_unload(&n->ebpf_rss);
133
}
134
135
static uint16_t virtio_net_handle_rss(VirtIONet *n,
136
@@ -XXX,XX +XXX,XX @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
137
goto error;
138
}
139
n->rss_data.enabled = true;
140
+
141
+ if (!n->rss_data.populate_hash) {
142
+ if (!virtio_net_attach_epbf_rss(n)) {
143
+ /* EBPF must be loaded for vhost */
144
+ if (get_vhost_net(qemu_get_queue(n->nic)->peer)) {
145
+ warn_report("Can't load eBPF RSS for vhost");
146
+ goto error;
147
+ }
148
+ /* fallback to software RSS */
149
+ warn_report("Can't load eBPF RSS - fallback to software RSS");
150
+ n->rss_data.enabled_software_rss = true;
151
+ }
152
+ } else {
153
+ /* use software RSS for hash populating */
154
+ /* and detach eBPF if was loaded before */
155
+ virtio_net_detach_epbf_rss(n);
156
+ n->rss_data.enabled_software_rss = true;
157
+ }
158
+
159
trace_virtio_net_rss_enable(n->rss_data.hash_types,
160
n->rss_data.indirections_len,
161
temp.b);
162
@@ -XXX,XX +XXX,XX @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
163
return -1;
164
}
165
166
- if (!no_rss && n->rss_data.enabled) {
167
+ if (!no_rss && n->rss_data.enabled && n->rss_data.enabled_software_rss) {
168
int index = virtio_net_process_rss(nc, buf, size);
169
if (index >= 0) {
170
NetClientState *nc2 = qemu_get_subqueue(n->nic, index);
171
@@ -XXX,XX +XXX,XX @@ static int virtio_net_post_load_device(void *opaque, int version_id)
172
}
173
174
if (n->rss_data.enabled) {
175
+ n->rss_data.enabled_software_rss = n->rss_data.populate_hash;
176
+ if (!n->rss_data.populate_hash) {
177
+ if (!virtio_net_attach_epbf_rss(n)) {
178
+ if (get_vhost_net(qemu_get_queue(n->nic)->peer)) {
179
+ warn_report("Can't post-load eBPF RSS for vhost");
180
+ } else {
181
+ warn_report("Can't post-load eBPF RSS - "
182
+ "fallback to software RSS");
183
+ n->rss_data.enabled_software_rss = true;
184
+ }
185
+ }
186
+ }
187
+
188
trace_virtio_net_rss_enable(n->rss_data.hash_types,
189
n->rss_data.indirections_len,
190
sizeof(n->rss_data.key));
191
@@ -XXX,XX +XXX,XX @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
192
n->qdev = dev;
193
194
net_rx_pkt_init(&n->rx_pkt, false);
195
+
196
+ if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
197
+ virtio_net_load_ebpf(n);
198
+ }
199
}
200
201
static void virtio_net_device_unrealize(DeviceState *dev)
202
@@ -XXX,XX +XXX,XX @@ static void virtio_net_device_unrealize(DeviceState *dev)
203
VirtIONet *n = VIRTIO_NET(dev);
204
int i, max_queues;
205
206
+ if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
207
+ virtio_net_unload_ebpf(n);
208
+ }
209
+
210
/* This will stop vhost backend if appropriate. */
211
virtio_net_set_status(vdev, 0);
212
213
@@ -XXX,XX +XXX,XX @@ static void virtio_net_instance_init(Object *obj)
214
device_add_bootindex_property(obj, &n->nic_conf.bootindex,
215
"bootindex", "/ethernet-phy@0",
216
DEVICE(n));
217
+
218
+ ebpf_rss_init(&n->ebpf_rss);
219
}
220
221
static int virtio_net_pre_save(void *opaque)
222
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
223
index XXXXXXX..XXXXXXX 100644
224
--- a/include/hw/virtio/virtio-net.h
225
+++ b/include/hw/virtio/virtio-net.h
226
@@ -XXX,XX +XXX,XX @@
13
@@ -XXX,XX +XXX,XX @@
227
#include "qemu/option_int.h"
14
#define TYPE_VHOST_VDPA "vhost-vdpa"
228
#include "qom/object.h"
15
229
16
struct vhost_net *vhost_vdpa_get_vhost_net(NetClientState *nc);
230
+#include "ebpf/ebpf_rss.h"
17
-uint64_t vhost_vdpa_get_acked_features(NetClientState *nc);
231
+
18
232
#define TYPE_VIRTIO_NET "virtio-net-device"
19
extern const int vdpa_feature_bits[];
233
OBJECT_DECLARE_SIMPLE_TYPE(VirtIONet, VIRTIO_NET)
20
234
235
@@ -XXX,XX +XXX,XX @@ typedef struct VirtioNetRscChain {
236
237
typedef struct VirtioNetRssData {
238
bool enabled;
239
+ bool enabled_software_rss;
240
bool redirect;
241
bool populate_hash;
242
uint32_t hash_types;
243
@@ -XXX,XX +XXX,XX @@ struct VirtIONet {
244
Notifier migration_state;
245
VirtioNetRssData rss_data;
246
struct NetRxPkt *rx_pkt;
247
+ struct EBPFRSSContext ebpf_rss;
248
};
249
250
void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
251
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
21
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
252
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
253
--- a/net/vhost-vdpa.c
23
--- a/net/vhost-vdpa.c
254
+++ b/net/vhost-vdpa.c
24
+++ b/net/vhost-vdpa.c
255
@@ -XXX,XX +XXX,XX @@ const int vdpa_feature_bits[] = {
25
@@ -XXX,XX +XXX,XX @@ VHostNetState *vhost_vdpa_get_vhost_net(NetClientState *nc)
256
VIRTIO_NET_F_MTU,
26
return s->vhost_net;
257
VIRTIO_F_IOMMU_PLATFORM,
27
}
258
VIRTIO_F_RING_PACKED,
28
259
+ VIRTIO_NET_F_RSS,
29
-uint64_t vhost_vdpa_get_acked_features(NetClientState *nc)
260
+ VIRTIO_NET_F_HASH_REPORT,
30
-{
261
VIRTIO_NET_F_GUEST_ANNOUNCE,
31
- VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc);
262
VIRTIO_NET_F_STATUS,
32
- assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
263
VHOST_INVALID_FEATURE_BIT
33
- s->acked_features = vhost_net_get_acked_features(s->vhost_net);
34
-
35
- return s->acked_features;
36
-}
37
-
38
static int vhost_vdpa_net_check_device_id(struct vhost_net *net)
39
{
40
uint32_t device_id;
264
--
41
--
265
2.7.4
42
2.7.4
266
43
267
44
diff view generated by jsdifflib
New patch
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
2
3
Creating and destroying network backend does not require a fully
4
constructed machine. Allow the related monitor commands to run before
5
machine initialization has concluded.
6
7
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
---
11
hmp-commands.hx | 2 ++
12
qapi/net.json | 6 ++++--
13
2 files changed, 6 insertions(+), 2 deletions(-)
14
15
diff --git a/hmp-commands.hx b/hmp-commands.hx
16
index XXXXXXX..XXXXXXX 100644
17
--- a/hmp-commands.hx
18
+++ b/hmp-commands.hx
19
@@ -XXX,XX +XXX,XX @@ ERST
20
.help = "add host network device",
21
.cmd = hmp_netdev_add,
22
.command_completion = netdev_add_completion,
23
+ .flags = "p",
24
},
25
26
SRST
27
@@ -XXX,XX +XXX,XX @@ ERST
28
.help = "remove host network device",
29
.cmd = hmp_netdev_del,
30
.command_completion = netdev_del_completion,
31
+ .flags = "p",
32
},
33
34
SRST
35
diff --git a/qapi/net.json b/qapi/net.json
36
index XXXXXXX..XXXXXXX 100644
37
--- a/qapi/net.json
38
+++ b/qapi/net.json
39
@@ -XXX,XX +XXX,XX @@
40
# <- { "return": {} }
41
#
42
##
43
-{ 'command': 'netdev_add', 'data': 'Netdev', 'boxed': true }
44
+{ 'command': 'netdev_add', 'data': 'Netdev', 'boxed': true,
45
+ 'allow-preconfig': true }
46
47
##
48
# @netdev_del:
49
@@ -XXX,XX +XXX,XX @@
50
# <- { "return": {} }
51
#
52
##
53
-{ 'command': 'netdev_del', 'data': {'id': 'str'} }
54
+{ 'command': 'netdev_del', 'data': {'id': 'str'},
55
+ 'allow-preconfig': true }
56
57
##
58
# @NetLegacyNicOptions:
59
--
60
2.7.4
61
62
diff view generated by jsdifflib
New patch
1
From: "Rao, Lei" <lei.rao@intel.com>
1
2
3
There is the same trace code in the colo_compare_packet_payload.
4
5
Signed-off-by: Lei Rao <lei.rao@intel.com>
6
Reviewed-by: Li Zhijian <lizhijian@fujitsu.com>
7
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
8
Reviewed-by: Lukas Straub <lukasstraub2@web.de>
9
Tested-by: Lukas Straub <lukasstraub2@web.de>
10
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
13
net/colo-compare.c | 13 -------------
14
1 file changed, 13 deletions(-)
15
16
diff --git a/net/colo-compare.c b/net/colo-compare.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/net/colo-compare.c
19
+++ b/net/colo-compare.c
20
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_other(Packet *spkt, Packet *ppkt)
21
uint16_t offset = ppkt->vnet_hdr_len;
22
23
trace_colo_compare_main("compare other");
24
- if (trace_event_get_state_backends(TRACE_COLO_COMPARE_IP_INFO)) {
25
- char pri_ip_src[20], pri_ip_dst[20], sec_ip_src[20], sec_ip_dst[20];
26
-
27
- strcpy(pri_ip_src, inet_ntoa(ppkt->ip->ip_src));
28
- strcpy(pri_ip_dst, inet_ntoa(ppkt->ip->ip_dst));
29
- strcpy(sec_ip_src, inet_ntoa(spkt->ip->ip_src));
30
- strcpy(sec_ip_dst, inet_ntoa(spkt->ip->ip_dst));
31
-
32
- trace_colo_compare_ip_info(ppkt->size, pri_ip_src,
33
- pri_ip_dst, spkt->size,
34
- sec_ip_src, sec_ip_dst);
35
- }
36
-
37
if (ppkt->size != spkt->size) {
38
trace_colo_compare_main("Other: payload size of packets are different");
39
return -1;
40
--
41
2.7.4
42
43
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: "Rao, Lei" <lei.rao@intel.com>
2
2
3
Additional code that will be used for eBPF setting steering routine.
3
This patch fixes the following:
4
qemu-system-x86_64: invalid runstate transition: 'colo' ->'shutdown'
5
Aborted (core dumped)
4
6
5
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
7
Signed-off-by: Lei Rao <lei.rao@intel.com>
8
Reviewed-by: Li Zhijian <lizhijian@fujitsu.com>
9
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
10
Reviewed-by: Lukas Straub <lukasstraub2@web.de>
11
Tested-by: Lukas Straub <lukasstraub2@web.de>
12
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
6
Signed-off-by: Jason Wang <jasowang@redhat.com>
13
Signed-off-by: Jason Wang <jasowang@redhat.com>
7
---
14
---
8
net/tap-linux.h | 1 +
15
softmmu/runstate.c | 1 +
9
1 file changed, 1 insertion(+)
16
1 file changed, 1 insertion(+)
10
17
11
diff --git a/net/tap-linux.h b/net/tap-linux.h
18
diff --git a/softmmu/runstate.c b/softmmu/runstate.c
12
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
13
--- a/net/tap-linux.h
20
--- a/softmmu/runstate.c
14
+++ b/net/tap-linux.h
21
+++ b/softmmu/runstate.c
15
@@ -XXX,XX +XXX,XX @@
22
@@ -XXX,XX +XXX,XX @@ static const RunStateTransition runstate_transitions_def[] = {
16
#define TUNSETQUEUE _IOW('T', 217, int)
23
{ RUN_STATE_RESTORE_VM, RUN_STATE_PRELAUNCH },
17
#define TUNSETVNETLE _IOW('T', 220, int)
24
18
#define TUNSETVNETBE _IOW('T', 222, int)
25
{ RUN_STATE_COLO, RUN_STATE_RUNNING },
19
+#define TUNSETSTEERINGEBPF _IOR('T', 224, int)
26
+ { RUN_STATE_COLO, RUN_STATE_SHUTDOWN},
20
27
21
#endif
28
{ RUN_STATE_RUNNING, RUN_STATE_DEBUG },
22
29
{ RUN_STATE_RUNNING, RUN_STATE_INTERNAL_ERROR },
23
--
30
--
24
2.7.4
31
2.7.4
25
32
26
33
diff view generated by jsdifflib
New patch
1
From: "Rao, Lei" <lei.rao@intel.com>
1
2
3
The iov_size has been calculated in filter_send(). we can directly
4
return the size.In this way, this is no need to repeat calculations
5
in filter_redirector_receive_iov();
6
7
Signed-off-by: Lei Rao <lei.rao@intel.com>
8
Reviewed-by: Li Zhijian <lizhijian@fujitsu.com>
9
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
10
Reviewed-by: Lukas Straub <lukasstraub2@web.de>
11
Tested-by: Lukas Straub <lukasstraub2@web.de>
12
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
13
Signed-off-by: Jason Wang <jasowang@redhat.com>
14
---
15
net/filter-mirror.c | 8 ++++----
16
1 file changed, 4 insertions(+), 4 deletions(-)
17
18
diff --git a/net/filter-mirror.c b/net/filter-mirror.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/net/filter-mirror.c
21
+++ b/net/filter-mirror.c
22
@@ -XXX,XX +XXX,XX @@ static int filter_send(MirrorState *s,
23
goto err;
24
}
25
26
- return 0;
27
+ return size;
28
29
err:
30
return ret < 0 ? ret : -EIO;
31
@@ -XXX,XX +XXX,XX @@ static ssize_t filter_mirror_receive_iov(NetFilterState *nf,
32
int ret;
33
34
ret = filter_send(s, iov, iovcnt);
35
- if (ret) {
36
+ if (ret < 0) {
37
error_report("filter mirror send failed(%s)", strerror(-ret));
38
}
39
40
@@ -XXX,XX +XXX,XX @@ static ssize_t filter_redirector_receive_iov(NetFilterState *nf,
41
42
if (qemu_chr_fe_backend_connected(&s->chr_out)) {
43
ret = filter_send(s, iov, iovcnt);
44
- if (ret) {
45
+ if (ret < 0) {
46
error_report("filter redirector send failed(%s)", strerror(-ret));
47
}
48
- return iov_size(iov, iovcnt);
49
+ return ret;
50
} else {
51
return 0;
52
}
53
--
54
2.7.4
55
56
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: "Rao, Lei" <lei.rao@intel.com>
2
2
3
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
3
We can detect disk migration in migrate_prepare, if disk migration
4
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
4
is enabled in COLO mode, we can directly report an error.and there
5
is no need to disable block migration at every checkpoint.
6
7
Signed-off-by: Lei Rao <lei.rao@intel.com>
8
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
9
Reviewed-by: Li Zhijian <lizhijian@fujitsu.com>
10
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
11
Reviewed-by: Lukas Straub <lukasstraub2@web.de>
12
Tested-by: Lukas Straub <lukasstraub2@web.de>
5
Signed-off-by: Jason Wang <jasowang@redhat.com>
13
Signed-off-by: Jason Wang <jasowang@redhat.com>
6
---
14
---
7
MAINTAINERS | 8 ++++++++
15
migration/colo.c | 6 ------
8
1 file changed, 8 insertions(+)
16
migration/migration.c | 4 ++++
17
2 files changed, 4 insertions(+), 6 deletions(-)
9
18
10
diff --git a/MAINTAINERS b/MAINTAINERS
19
diff --git a/migration/colo.c b/migration/colo.c
11
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
12
--- a/MAINTAINERS
21
--- a/migration/colo.c
13
+++ b/MAINTAINERS
22
+++ b/migration/colo.c
14
@@ -XXX,XX +XXX,XX @@ F: include/hw/remote/proxy-memory-listener.h
23
@@ -XXX,XX +XXX,XX @@ static int colo_do_checkpoint_transaction(MigrationState *s,
15
F: hw/remote/iohub.c
24
if (failover_get_state() != FAILOVER_STATUS_NONE) {
16
F: include/hw/remote/iohub.h
25
goto out;
17
26
}
18
+EBPF:
27
-
19
+M: Jason Wang <jasowang@redhat.com>
28
- /* Disable block migration */
20
+R: Andrew Melnychenko <andrew@daynix.com>
29
- migrate_set_block_enabled(false, &local_err);
21
+R: Yuri Benditovich <yuri.benditovich@daynix.com>
30
- if (local_err) {
22
+S: Maintained
31
- goto out;
23
+F: ebpf/*
32
- }
24
+F: tools/ebpf/*
33
qemu_mutex_lock_iothread();
25
+
34
26
Build and test automation
35
#ifdef CONFIG_REPLICATION
27
-------------------------
36
diff --git a/migration/migration.c b/migration/migration.c
28
Build and test automation, general continuous integration
37
index XXXXXXX..XXXXXXX 100644
38
--- a/migration/migration.c
39
+++ b/migration/migration.c
40
@@ -XXX,XX +XXX,XX @@ static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc,
41
}
42
43
if (blk || blk_inc) {
44
+ if (migrate_colo_enabled()) {
45
+ error_setg(errp, "No disk migration is required in COLO mode");
46
+ return false;
47
+ }
48
if (migrate_use_block() || migrate_use_block_incremental()) {
49
error_setg(errp, "Command options are incompatible with "
50
"current migration capabilities");
29
--
51
--
30
2.7.4
52
2.7.4
31
53
32
54
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: "Rao, Lei" <lei.rao@intel.com>
2
2
3
RSS program and Makefile to build it.
3
Use the packet_new_nocopy instead of packet_new in the
4
The bpftool used to generate '.h' file.
4
filter-rewriter module. There will be one less memory
5
The data in that file may be loaded by libbpf.
5
copy in the processing of each network packet.
6
EBPF compilation is not required for building qemu.
7
You can use Makefile if you need to regenerate rss.bpf.skeleton.h.
8
6
9
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
7
Signed-off-by: Lei Rao <lei.rao@intel.com>
10
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
8
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
9
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
11
---
13
tools/ebpf/Makefile.ebpf | 21 ++
12
net/colo.c | 25 +++++++++++++++++--------
14
tools/ebpf/rss.bpf.c | 571 +++++++++++++++++++++++++++++++++++++++++++++++
13
net/colo.h | 1 +
15
2 files changed, 592 insertions(+)
14
net/filter-rewriter.c | 3 +--
16
create mode 100755 tools/ebpf/Makefile.ebpf
15
3 files changed, 19 insertions(+), 10 deletions(-)
17
create mode 100644 tools/ebpf/rss.bpf.c
18
16
19
diff --git a/tools/ebpf/Makefile.ebpf b/tools/ebpf/Makefile.ebpf
17
diff --git a/net/colo.c b/net/colo.c
20
new file mode 100755
18
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX
19
--- a/net/colo.c
22
--- /dev/null
20
+++ b/net/colo.c
23
+++ b/tools/ebpf/Makefile.ebpf
21
@@ -XXX,XX +XXX,XX @@ void connection_destroy(void *opaque)
24
@@ -XXX,XX +XXX,XX @@
22
25
+OBJS = rss.bpf.o
23
Packet *packet_new(const void *data, int size, int vnet_hdr_len)
24
{
25
- Packet *pkt = g_slice_new(Packet);
26
+ Packet *pkt = g_slice_new0(Packet);
27
28
pkt->data = g_memdup(data, size);
29
pkt->size = size;
30
pkt->creation_ms = qemu_clock_get_ms(QEMU_CLOCK_HOST);
31
pkt->vnet_hdr_len = vnet_hdr_len;
32
- pkt->tcp_seq = 0;
33
- pkt->tcp_ack = 0;
34
- pkt->seq_end = 0;
35
- pkt->header_size = 0;
36
- pkt->payload_size = 0;
37
- pkt->offset = 0;
38
- pkt->flags = 0;
26
+
39
+
27
+LLC ?= llc
40
+ return pkt;
28
+CLANG ?= clang
29
+INC_FLAGS = `$(CLANG) -print-file-name=include`
30
+EXTRA_CFLAGS ?= -O2 -emit-llvm -fno-stack-protector
31
+
32
+all: $(OBJS)
33
+
34
+.PHONY: clean
35
+
36
+clean:
37
+    rm -f $(OBJS)
38
+
39
+$(OBJS): %.o:%.c
40
+    $(CLANG) $(INC_FLAGS) \
41
+ -D__KERNEL__ -D__ASM_SYSREG_H \
42
+ -I../include $(LINUXINCLUDE) \
43
+ $(EXTRA_CFLAGS) -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $@
44
+    bpftool gen skeleton rss.bpf.o > rss.bpf.skeleton.h
45
+    cp rss.bpf.skeleton.h ../../ebpf/
46
diff --git a/tools/ebpf/rss.bpf.c b/tools/ebpf/rss.bpf.c
47
new file mode 100644
48
index XXXXXXX..XXXXXXX
49
--- /dev/null
50
+++ b/tools/ebpf/rss.bpf.c
51
@@ -XXX,XX +XXX,XX @@
52
+/*
53
+ * eBPF RSS program
54
+ *
55
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
56
+ *
57
+ * Authors:
58
+ * Andrew Melnychenko <andrew@daynix.com>
59
+ * Yuri Benditovich <yuri.benditovich@daynix.com>
60
+ *
61
+ * This work is licensed under the terms of the GNU GPL, version 2. See
62
+ * the COPYING file in the top-level directory.
63
+ *
64
+ * Prepare:
65
+ * Requires llvm, clang, bpftool, linux kernel tree
66
+ *
67
+ * Build rss.bpf.skeleton.h:
68
+ * make -f Makefile.ebpf clean all
69
+ */
70
+
71
+#include <stddef.h>
72
+#include <stdbool.h>
73
+#include <linux/bpf.h>
74
+
75
+#include <linux/in.h>
76
+#include <linux/if_ether.h>
77
+#include <linux/ip.h>
78
+#include <linux/ipv6.h>
79
+
80
+#include <linux/udp.h>
81
+#include <linux/tcp.h>
82
+
83
+#include <bpf/bpf_helpers.h>
84
+#include <bpf/bpf_endian.h>
85
+#include <linux/virtio_net.h>
86
+
87
+#define INDIRECTION_TABLE_SIZE 128
88
+#define HASH_CALCULATION_BUFFER_SIZE 36
89
+
90
+struct rss_config_t {
91
+ __u8 redirect;
92
+ __u8 populate_hash;
93
+ __u32 hash_types;
94
+ __u16 indirections_len;
95
+ __u16 default_queue;
96
+} __attribute__((packed));
97
+
98
+struct toeplitz_key_data_t {
99
+ __u32 leftmost_32_bits;
100
+ __u8 next_byte[HASH_CALCULATION_BUFFER_SIZE];
101
+};
102
+
103
+struct packet_hash_info_t {
104
+ __u8 is_ipv4;
105
+ __u8 is_ipv6;
106
+ __u8 is_udp;
107
+ __u8 is_tcp;
108
+ __u8 is_ipv6_ext_src;
109
+ __u8 is_ipv6_ext_dst;
110
+ __u8 is_fragmented;
111
+
112
+ __u16 src_port;
113
+ __u16 dst_port;
114
+
115
+ union {
116
+ struct {
117
+ __be32 in_src;
118
+ __be32 in_dst;
119
+ };
120
+
121
+ struct {
122
+ struct in6_addr in6_src;
123
+ struct in6_addr in6_dst;
124
+ struct in6_addr in6_ext_src;
125
+ struct in6_addr in6_ext_dst;
126
+ };
127
+ };
128
+};
129
+
130
+struct bpf_map_def SEC("maps")
131
+tap_rss_map_configurations = {
132
+ .type = BPF_MAP_TYPE_ARRAY,
133
+ .key_size = sizeof(__u32),
134
+ .value_size = sizeof(struct rss_config_t),
135
+ .max_entries = 1,
136
+};
137
+
138
+struct bpf_map_def SEC("maps")
139
+tap_rss_map_toeplitz_key = {
140
+ .type = BPF_MAP_TYPE_ARRAY,
141
+ .key_size = sizeof(__u32),
142
+ .value_size = sizeof(struct toeplitz_key_data_t),
143
+ .max_entries = 1,
144
+};
145
+
146
+struct bpf_map_def SEC("maps")
147
+tap_rss_map_indirection_table = {
148
+ .type = BPF_MAP_TYPE_ARRAY,
149
+ .key_size = sizeof(__u32),
150
+ .value_size = sizeof(__u16),
151
+ .max_entries = INDIRECTION_TABLE_SIZE,
152
+};
153
+
154
+static inline void net_rx_rss_add_chunk(__u8 *rss_input, size_t *bytes_written,
155
+ const void *ptr, size_t size) {
156
+ __builtin_memcpy(&rss_input[*bytes_written], ptr, size);
157
+ *bytes_written += size;
158
+}
41
+}
159
+
42
+
160
+static inline
43
+/*
161
+void net_toeplitz_add(__u32 *result,
44
+ * packet_new_nocopy will not copy data, so the caller can't release
162
+ __u8 *input,
45
+ * the data. And it will be released in packet_destroy.
163
+ __u32 len
46
+ */
164
+ , struct toeplitz_key_data_t *key) {
47
+Packet *packet_new_nocopy(void *data, int size, int vnet_hdr_len)
48
+{
49
+ Packet *pkt = g_slice_new0(Packet);
165
+
50
+
166
+ __u32 accumulator = *result;
51
+ pkt->data = data;
167
+ __u32 leftmost_32_bits = key->leftmost_32_bits;
52
+ pkt->size = size;
168
+ __u32 byte;
53
+ pkt->creation_ms = qemu_clock_get_ms(QEMU_CLOCK_HOST);
169
+
54
+ pkt->vnet_hdr_len = vnet_hdr_len;
170
+ for (byte = 0; byte < HASH_CALCULATION_BUFFER_SIZE; byte++) {
55
171
+ __u8 input_byte = input[byte];
56
return pkt;
172
+ __u8 key_byte = key->next_byte[byte];
57
}
173
+ __u8 bit;
58
diff --git a/net/colo.h b/net/colo.h
174
+
59
index XXXXXXX..XXXXXXX 100644
175
+ for (bit = 0; bit < 8; bit++) {
60
--- a/net/colo.h
176
+ if (input_byte & (1 << 7)) {
61
+++ b/net/colo.h
177
+ accumulator ^= leftmost_32_bits;
62
@@ -XXX,XX +XXX,XX @@ bool connection_has_tracked(GHashTable *connection_track_table,
178
+ }
63
ConnectionKey *key);
179
+
64
void connection_hashtable_reset(GHashTable *connection_track_table);
180
+ leftmost_32_bits =
65
Packet *packet_new(const void *data, int size, int vnet_hdr_len);
181
+ (leftmost_32_bits << 1) | ((key_byte & (1 << 7)) >> 7);
66
+Packet *packet_new_nocopy(void *data, int size, int vnet_hdr_len);
182
+
67
void packet_destroy(void *opaque, void *user_data);
183
+ input_byte <<= 1;
68
void packet_destroy_partial(void *opaque, void *user_data);
184
+ key_byte <<= 1;
69
185
+ }
70
diff --git a/net/filter-rewriter.c b/net/filter-rewriter.c
186
+ }
71
index XXXXXXX..XXXXXXX 100644
187
+
72
--- a/net/filter-rewriter.c
188
+ *result = accumulator;
73
+++ b/net/filter-rewriter.c
189
+}
74
@@ -XXX,XX +XXX,XX @@ static ssize_t colo_rewriter_receive_iov(NetFilterState *nf,
190
+
75
vnet_hdr_len = nf->netdev->vnet_hdr_len;
191
+
76
}
192
+static inline int ip6_extension_header_type(__u8 hdr_type)
77
193
+{
78
- pkt = packet_new(buf, size, vnet_hdr_len);
194
+ switch (hdr_type) {
79
- g_free(buf);
195
+ case IPPROTO_HOPOPTS:
80
+ pkt = packet_new_nocopy(buf, size, vnet_hdr_len);
196
+ case IPPROTO_ROUTING:
81
197
+ case IPPROTO_FRAGMENT:
82
/*
198
+ case IPPROTO_ICMPV6:
83
* if we get tcp packet
199
+ case IPPROTO_NONE:
200
+ case IPPROTO_DSTOPTS:
201
+ case IPPROTO_MH:
202
+ return 1;
203
+ default:
204
+ return 0;
205
+ }
206
+}
207
+/*
208
+ * According to
209
+ * https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml
210
+ * we expect that there are would be no more than 11 extensions in IPv6 header,
211
+ * also there is 27 TLV options for Destination and Hop-by-hop extensions.
212
+ * Need to choose reasonable amount of maximum extensions/options we may
213
+ * check to find ext src/dst.
214
+ */
215
+#define IP6_EXTENSIONS_COUNT 11
216
+#define IP6_OPTIONS_COUNT 30
217
+
218
+static inline int parse_ipv6_ext(struct __sk_buff *skb,
219
+ struct packet_hash_info_t *info,
220
+ __u8 *l4_protocol, size_t *l4_offset)
221
+{
222
+ int err = 0;
223
+
224
+ if (!ip6_extension_header_type(*l4_protocol)) {
225
+ return 0;
226
+ }
227
+
228
+ struct ipv6_opt_hdr ext_hdr = {};
229
+
230
+ for (unsigned int i = 0; i < IP6_EXTENSIONS_COUNT; ++i) {
231
+
232
+ err = bpf_skb_load_bytes_relative(skb, *l4_offset, &ext_hdr,
233
+ sizeof(ext_hdr), BPF_HDR_START_NET);
234
+ if (err) {
235
+ goto error;
236
+ }
237
+
238
+ if (*l4_protocol == IPPROTO_ROUTING) {
239
+ struct ipv6_rt_hdr ext_rt = {};
240
+
241
+ err = bpf_skb_load_bytes_relative(skb, *l4_offset, &ext_rt,
242
+ sizeof(ext_rt), BPF_HDR_START_NET);
243
+ if (err) {
244
+ goto error;
245
+ }
246
+
247
+ if ((ext_rt.type == IPV6_SRCRT_TYPE_2) &&
248
+ (ext_rt.hdrlen == sizeof(struct in6_addr) / 8) &&
249
+ (ext_rt.segments_left == 1)) {
250
+
251
+ err = bpf_skb_load_bytes_relative(skb,
252
+ *l4_offset + offsetof(struct rt2_hdr, addr),
253
+ &info->in6_ext_dst, sizeof(info->in6_ext_dst),
254
+ BPF_HDR_START_NET);
255
+ if (err) {
256
+ goto error;
257
+ }
258
+
259
+ info->is_ipv6_ext_dst = 1;
260
+ }
261
+
262
+ } else if (*l4_protocol == IPPROTO_DSTOPTS) {
263
+ struct ipv6_opt_t {
264
+ __u8 type;
265
+ __u8 length;
266
+ } __attribute__((packed)) opt = {};
267
+
268
+ size_t opt_offset = sizeof(ext_hdr);
269
+
270
+ for (unsigned int j = 0; j < IP6_OPTIONS_COUNT; ++j) {
271
+ err = bpf_skb_load_bytes_relative(skb, *l4_offset + opt_offset,
272
+ &opt, sizeof(opt), BPF_HDR_START_NET);
273
+ if (err) {
274
+ goto error;
275
+ }
276
+
277
+ if (opt.type == IPV6_TLV_HAO) {
278
+ err = bpf_skb_load_bytes_relative(skb,
279
+ *l4_offset + opt_offset
280
+ + offsetof(struct ipv6_destopt_hao, addr),
281
+ &info->in6_ext_src, sizeof(info->in6_ext_src),
282
+ BPF_HDR_START_NET);
283
+ if (err) {
284
+ goto error;
285
+ }
286
+
287
+ info->is_ipv6_ext_src = 1;
288
+ break;
289
+ }
290
+
291
+ opt_offset += (opt.type == IPV6_TLV_PAD1) ?
292
+ 1 : opt.length + sizeof(opt);
293
+
294
+ if (opt_offset + 1 >= ext_hdr.hdrlen * 8) {
295
+ break;
296
+ }
297
+ }
298
+ } else if (*l4_protocol == IPPROTO_FRAGMENT) {
299
+ info->is_fragmented = true;
300
+ }
301
+
302
+ *l4_protocol = ext_hdr.nexthdr;
303
+ *l4_offset += (ext_hdr.hdrlen + 1) * 8;
304
+
305
+ if (!ip6_extension_header_type(ext_hdr.nexthdr)) {
306
+ return 0;
307
+ }
308
+ }
309
+
310
+ return 0;
311
+error:
312
+ return err;
313
+}
314
+
315
+static __be16 parse_eth_type(struct __sk_buff *skb)
316
+{
317
+ unsigned int offset = 12;
318
+ __be16 ret = 0;
319
+ int err = 0;
320
+
321
+ err = bpf_skb_load_bytes_relative(skb, offset, &ret, sizeof(ret),
322
+ BPF_HDR_START_MAC);
323
+ if (err) {
324
+ return 0;
325
+ }
326
+
327
+ switch (bpf_ntohs(ret)) {
328
+ case ETH_P_8021AD:
329
+ offset += 4;
330
+ case ETH_P_8021Q:
331
+ offset += 4;
332
+ err = bpf_skb_load_bytes_relative(skb, offset, &ret, sizeof(ret),
333
+ BPF_HDR_START_MAC);
334
+ default:
335
+ break;
336
+ }
337
+
338
+ if (err) {
339
+ return 0;
340
+ }
341
+
342
+ return ret;
343
+}
344
+
345
+static inline int parse_packet(struct __sk_buff *skb,
346
+ struct packet_hash_info_t *info)
347
+{
348
+ int err = 0;
349
+
350
+ if (!info || !skb) {
351
+ return -1;
352
+ }
353
+
354
+ size_t l4_offset = 0;
355
+ __u8 l4_protocol = 0;
356
+ __u16 l3_protocol = bpf_ntohs(parse_eth_type(skb));
357
+ if (l3_protocol == 0) {
358
+ err = -1;
359
+ goto error;
360
+ }
361
+
362
+ if (l3_protocol == ETH_P_IP) {
363
+ info->is_ipv4 = 1;
364
+
365
+ struct iphdr ip = {};
366
+ err = bpf_skb_load_bytes_relative(skb, 0, &ip, sizeof(ip),
367
+ BPF_HDR_START_NET);
368
+ if (err) {
369
+ goto error;
370
+ }
371
+
372
+ info->in_src = ip.saddr;
373
+ info->in_dst = ip.daddr;
374
+ info->is_fragmented = !!ip.frag_off;
375
+
376
+ l4_protocol = ip.protocol;
377
+ l4_offset = ip.ihl * 4;
378
+ } else if (l3_protocol == ETH_P_IPV6) {
379
+ info->is_ipv6 = 1;
380
+
381
+ struct ipv6hdr ip6 = {};
382
+ err = bpf_skb_load_bytes_relative(skb, 0, &ip6, sizeof(ip6),
383
+ BPF_HDR_START_NET);
384
+ if (err) {
385
+ goto error;
386
+ }
387
+
388
+ info->in6_src = ip6.saddr;
389
+ info->in6_dst = ip6.daddr;
390
+
391
+ l4_protocol = ip6.nexthdr;
392
+ l4_offset = sizeof(ip6);
393
+
394
+ err = parse_ipv6_ext(skb, info, &l4_protocol, &l4_offset);
395
+ if (err) {
396
+ goto error;
397
+ }
398
+ }
399
+
400
+ if (l4_protocol != 0 && !info->is_fragmented) {
401
+ if (l4_protocol == IPPROTO_TCP) {
402
+ info->is_tcp = 1;
403
+
404
+ struct tcphdr tcp = {};
405
+ err = bpf_skb_load_bytes_relative(skb, l4_offset, &tcp, sizeof(tcp),
406
+ BPF_HDR_START_NET);
407
+ if (err) {
408
+ goto error;
409
+ }
410
+
411
+ info->src_port = tcp.source;
412
+ info->dst_port = tcp.dest;
413
+ } else if (l4_protocol == IPPROTO_UDP) { /* TODO: add udplite? */
414
+ info->is_udp = 1;
415
+
416
+ struct udphdr udp = {};
417
+ err = bpf_skb_load_bytes_relative(skb, l4_offset, &udp, sizeof(udp),
418
+ BPF_HDR_START_NET);
419
+ if (err) {
420
+ goto error;
421
+ }
422
+
423
+ info->src_port = udp.source;
424
+ info->dst_port = udp.dest;
425
+ }
426
+ }
427
+
428
+ return 0;
429
+
430
+error:
431
+ return err;
432
+}
433
+
434
+static inline __u32 calculate_rss_hash(struct __sk_buff *skb,
435
+ struct rss_config_t *config, struct toeplitz_key_data_t *toe)
436
+{
437
+ __u8 rss_input[HASH_CALCULATION_BUFFER_SIZE] = {};
438
+ size_t bytes_written = 0;
439
+ __u32 result = 0;
440
+ int err = 0;
441
+ struct packet_hash_info_t packet_info = {};
442
+
443
+ err = parse_packet(skb, &packet_info);
444
+ if (err) {
445
+ return 0;
446
+ }
447
+
448
+ if (packet_info.is_ipv4) {
449
+ if (packet_info.is_tcp &&
450
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_TCPv4) {
451
+
452
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
453
+ &packet_info.in_src,
454
+ sizeof(packet_info.in_src));
455
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
456
+ &packet_info.in_dst,
457
+ sizeof(packet_info.in_dst));
458
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
459
+ &packet_info.src_port,
460
+ sizeof(packet_info.src_port));
461
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
462
+ &packet_info.dst_port,
463
+ sizeof(packet_info.dst_port));
464
+ } else if (packet_info.is_udp &&
465
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_UDPv4) {
466
+
467
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
468
+ &packet_info.in_src,
469
+ sizeof(packet_info.in_src));
470
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
471
+ &packet_info.in_dst,
472
+ sizeof(packet_info.in_dst));
473
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
474
+ &packet_info.src_port,
475
+ sizeof(packet_info.src_port));
476
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
477
+ &packet_info.dst_port,
478
+ sizeof(packet_info.dst_port));
479
+ } else if (config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
480
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
481
+ &packet_info.in_src,
482
+ sizeof(packet_info.in_src));
483
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
484
+ &packet_info.in_dst,
485
+ sizeof(packet_info.in_dst));
486
+ }
487
+ } else if (packet_info.is_ipv6) {
488
+ if (packet_info.is_tcp &&
489
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_TCPv6) {
490
+
491
+ if (packet_info.is_ipv6_ext_src &&
492
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_TCP_EX) {
493
+
494
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
495
+ &packet_info.in6_ext_src,
496
+ sizeof(packet_info.in6_ext_src));
497
+ } else {
498
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
499
+ &packet_info.in6_src,
500
+ sizeof(packet_info.in6_src));
501
+ }
502
+ if (packet_info.is_ipv6_ext_dst &&
503
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_TCP_EX) {
504
+
505
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
506
+ &packet_info.in6_ext_dst,
507
+ sizeof(packet_info.in6_ext_dst));
508
+ } else {
509
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
510
+ &packet_info.in6_dst,
511
+ sizeof(packet_info.in6_dst));
512
+ }
513
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
514
+ &packet_info.src_port,
515
+ sizeof(packet_info.src_port));
516
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
517
+ &packet_info.dst_port,
518
+ sizeof(packet_info.dst_port));
519
+ } else if (packet_info.is_udp &&
520
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_UDPv6) {
521
+
522
+ if (packet_info.is_ipv6_ext_src &&
523
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) {
524
+
525
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
526
+ &packet_info.in6_ext_src,
527
+ sizeof(packet_info.in6_ext_src));
528
+ } else {
529
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
530
+ &packet_info.in6_src,
531
+ sizeof(packet_info.in6_src));
532
+ }
533
+ if (packet_info.is_ipv6_ext_dst &&
534
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) {
535
+
536
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
537
+ &packet_info.in6_ext_dst,
538
+ sizeof(packet_info.in6_ext_dst));
539
+ } else {
540
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
541
+ &packet_info.in6_dst,
542
+ sizeof(packet_info.in6_dst));
543
+ }
544
+
545
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
546
+ &packet_info.src_port,
547
+ sizeof(packet_info.src_port));
548
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
549
+ &packet_info.dst_port,
550
+ sizeof(packet_info.dst_port));
551
+
552
+ } else if (config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_IPv6) {
553
+ if (packet_info.is_ipv6_ext_src &&
554
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_IP_EX) {
555
+
556
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
557
+ &packet_info.in6_ext_src,
558
+ sizeof(packet_info.in6_ext_src));
559
+ } else {
560
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
561
+ &packet_info.in6_src,
562
+ sizeof(packet_info.in6_src));
563
+ }
564
+ if (packet_info.is_ipv6_ext_dst &&
565
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_IP_EX) {
566
+
567
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
568
+ &packet_info.in6_ext_dst,
569
+ sizeof(packet_info.in6_ext_dst));
570
+ } else {
571
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
572
+ &packet_info.in6_dst,
573
+ sizeof(packet_info.in6_dst));
574
+ }
575
+ }
576
+ }
577
+
578
+ if (bytes_written) {
579
+ net_toeplitz_add(&result, rss_input, bytes_written, toe);
580
+ }
581
+
582
+ return result;
583
+}
584
+
585
+SEC("tun_rss_steering")
586
+int tun_rss_steering_prog(struct __sk_buff *skb)
587
+{
588
+
589
+ struct rss_config_t *config;
590
+ struct toeplitz_key_data_t *toe;
591
+
592
+ __u32 key = 0;
593
+ __u32 hash = 0;
594
+
595
+ config = bpf_map_lookup_elem(&tap_rss_map_configurations, &key);
596
+ toe = bpf_map_lookup_elem(&tap_rss_map_toeplitz_key, &key);
597
+
598
+ if (config && toe) {
599
+ if (!config->redirect) {
600
+ return config->default_queue;
601
+ }
602
+
603
+ hash = calculate_rss_hash(skb, config, toe);
604
+ if (hash) {
605
+ __u32 table_idx = hash % config->indirections_len;
606
+ __u16 *queue = 0;
607
+
608
+ queue = bpf_map_lookup_elem(&tap_rss_map_indirection_table,
609
+ &table_idx);
610
+
611
+ if (queue) {
612
+ return *queue;
613
+ }
614
+ }
615
+
616
+ return config->default_queue;
617
+ }
618
+
619
+ return -1;
620
+}
621
+
622
+char _license[] SEC("license") = "GPL v2";
623
--
84
--
624
2.7.4
85
2.7.4
625
86
626
87
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: "Rao, Lei" <lei.rao@intel.com>
2
2
3
For now, that method supported only by Linux TAP.
3
This patch fixes the following:
4
Linux TAP uses TUNSETSTEERINGEBPF ioctl.
4
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
5
#1 0x00007f6ae4559859 in __GI_abort () at abort.c:79
6
#2 0x0000559aaa386720 in error_exit (err=16, msg=0x559aaa5973d0 <__func__.16227> "qemu_mutex_destroy") at util/qemu-thread-posix.c:36
7
#3 0x0000559aaa3868c5 in qemu_mutex_destroy (mutex=0x559aabffe828) at util/qemu-thread-posix.c:69
8
#4 0x0000559aaa2f93a8 in char_finalize (obj=0x559aabffe800) at chardev/char.c:285
9
#5 0x0000559aaa23318a in object_deinit (obj=0x559aabffe800, type=0x559aabfd7d20) at qom/object.c:606
10
#6 0x0000559aaa2331b8 in object_deinit (obj=0x559aabffe800, type=0x559aabfd9060) at qom/object.c:610
11
#7 0x0000559aaa233200 in object_finalize (data=0x559aabffe800) at qom/object.c:620
12
#8 0x0000559aaa234202 in object_unref (obj=0x559aabffe800) at qom/object.c:1074
13
#9 0x0000559aaa2356b6 in object_finalize_child_property (obj=0x559aac0dac10, name=0x559aac778760 "compare0-0", opaque=0x559aabffe800) at qom/object.c:1584
14
#10 0x0000559aaa232f70 in object_property_del_all (obj=0x559aac0dac10) at qom/object.c:557
15
#11 0x0000559aaa2331ed in object_finalize (data=0x559aac0dac10) at qom/object.c:619
16
#12 0x0000559aaa234202 in object_unref (obj=0x559aac0dac10) at qom/object.c:1074
17
#13 0x0000559aaa2356b6 in object_finalize_child_property (obj=0x559aac0c75c0, name=0x559aac0dadc0 "chardevs", opaque=0x559aac0dac10) at qom/object.c:1584
18
#14 0x0000559aaa233071 in object_property_del_child (obj=0x559aac0c75c0, child=0x559aac0dac10, errp=0x0) at qom/object.c:580
19
#15 0x0000559aaa233155 in object_unparent (obj=0x559aac0dac10) at qom/object.c:599
20
#16 0x0000559aaa2fb721 in qemu_chr_cleanup () at chardev/char.c:1159
21
#17 0x0000559aa9f9b110 in main (argc=54, argv=0x7ffeb62fa998, envp=0x7ffeb62fab50) at vl.c:4539
5
22
6
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
23
When chardev is cleaned up, chr_write_lock needs to be destroyed. But
24
the colo-compare module is not cleaned up normally before it when the
25
guest poweroff. It is holding chr_write_lock at this time. This will
26
cause qemu crash.So we add the function of colo_compare_cleanup() before
27
qemu_chr_cleanup() to fix the bug.
28
29
Signed-off-by: Lei Rao <lei.rao@intel.com>
30
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
31
Reviewed-by: Lukas Straub <lukasstraub2@web.de>
32
Tested-by: Lukas Straub <lukasstraub2@web.de>
33
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
34
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
35
---
9
include/net/net.h | 2 ++
36
net/colo-compare.c | 10 ++++++++++
10
net/tap-bsd.c | 5 +++++
37
net/colo-compare.h | 1 +
11
net/tap-linux.c | 13 +++++++++++++
38
net/net.c | 4 ++++
12
net/tap-solaris.c | 5 +++++
39
3 files changed, 15 insertions(+)
13
net/tap-stub.c | 5 +++++
14
net/tap.c | 9 +++++++++
15
net/tap_int.h | 1 +
16
7 files changed, 40 insertions(+)
17
40
18
diff --git a/include/net/net.h b/include/net/net.h
41
diff --git a/net/colo-compare.c b/net/colo-compare.c
19
index XXXXXXX..XXXXXXX 100644
42
index XXXXXXX..XXXXXXX 100644
20
--- a/include/net/net.h
43
--- a/net/colo-compare.c
21
+++ b/include/net/net.h
44
+++ b/net/colo-compare.c
22
@@ -XXX,XX +XXX,XX @@ typedef int (SetVnetBE)(NetClientState *, bool);
45
@@ -XXX,XX +XXX,XX @@ static void colo_compare_init(Object *obj)
23
typedef struct SocketReadState SocketReadState;
46
compare_set_vnet_hdr);
24
typedef void (SocketReadStateFinalize)(SocketReadState *rs);
25
typedef void (NetAnnounce)(NetClientState *);
26
+typedef bool (SetSteeringEBPF)(NetClientState *, int);
27
28
typedef struct NetClientInfo {
29
NetClientDriver type;
30
@@ -XXX,XX +XXX,XX @@ typedef struct NetClientInfo {
31
SetVnetLE *set_vnet_le;
32
SetVnetBE *set_vnet_be;
33
NetAnnounce *announce;
34
+ SetSteeringEBPF *set_steering_ebpf;
35
} NetClientInfo;
36
37
struct NetClientState {
38
diff --git a/net/tap-bsd.c b/net/tap-bsd.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/net/tap-bsd.c
41
+++ b/net/tap-bsd.c
42
@@ -XXX,XX +XXX,XX @@ int tap_fd_get_ifname(int fd, char *ifname)
43
{
44
return -1;
45
}
47
}
48
49
+void colo_compare_cleanup(void)
50
+{
51
+ CompareState *tmp = NULL;
52
+ CompareState *n = NULL;
46
+
53
+
47
+int tap_fd_set_steering_ebpf(int fd, int prog_fd)
54
+ QTAILQ_FOREACH_SAFE(tmp, &net_compares, next, n) {
48
+{
55
+ object_unparent(OBJECT(tmp));
49
+ return -1;
50
+}
51
diff --git a/net/tap-linux.c b/net/tap-linux.c
52
index XXXXXXX..XXXXXXX 100644
53
--- a/net/tap-linux.c
54
+++ b/net/tap-linux.c
55
@@ -XXX,XX +XXX,XX @@ int tap_fd_get_ifname(int fd, char *ifname)
56
pstrcpy(ifname, sizeof(ifr.ifr_name), ifr.ifr_name);
57
return 0;
58
}
59
+
60
+int tap_fd_set_steering_ebpf(int fd, int prog_fd)
61
+{
62
+ if (ioctl(fd, TUNSETSTEERINGEBPF, (void *) &prog_fd) != 0) {
63
+ error_report("Issue while setting TUNSETSTEERINGEBPF:"
64
+ " %s with fd: %d, prog_fd: %d",
65
+ strerror(errno), fd, prog_fd);
66
+
67
+ return -1;
68
+ }
56
+ }
69
+
70
+ return 0;
71
+}
72
diff --git a/net/tap-solaris.c b/net/tap-solaris.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/net/tap-solaris.c
75
+++ b/net/tap-solaris.c
76
@@ -XXX,XX +XXX,XX @@ int tap_fd_get_ifname(int fd, char *ifname)
77
{
78
return -1;
79
}
80
+
81
+int tap_fd_set_steering_ebpf(int fd, int prog_fd)
82
+{
83
+ return -1;
84
+}
85
diff --git a/net/tap-stub.c b/net/tap-stub.c
86
index XXXXXXX..XXXXXXX 100644
87
--- a/net/tap-stub.c
88
+++ b/net/tap-stub.c
89
@@ -XXX,XX +XXX,XX @@ int tap_fd_get_ifname(int fd, char *ifname)
90
{
91
return -1;
92
}
93
+
94
+int tap_fd_set_steering_ebpf(int fd, int prog_fd)
95
+{
96
+ return -1;
97
+}
98
diff --git a/net/tap.c b/net/tap.c
99
index XXXXXXX..XXXXXXX 100644
100
--- a/net/tap.c
101
+++ b/net/tap.c
102
@@ -XXX,XX +XXX,XX @@ static void tap_poll(NetClientState *nc, bool enable)
103
tap_write_poll(s, enable);
104
}
105
106
+static bool tap_set_steering_ebpf(NetClientState *nc, int prog_fd)
107
+{
108
+ TAPState *s = DO_UPCAST(TAPState, nc, nc);
109
+ assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
110
+
111
+ return tap_fd_set_steering_ebpf(s->fd, prog_fd) == 0;
112
+}
57
+}
113
+
58
+
114
int tap_get_fd(NetClientState *nc)
59
static void colo_compare_finalize(Object *obj)
115
{
60
{
116
TAPState *s = DO_UPCAST(TAPState, nc, nc);
61
CompareState *s = COLO_COMPARE(obj);
117
@@ -XXX,XX +XXX,XX @@ static NetClientInfo net_tap_info = {
62
diff --git a/net/colo-compare.h b/net/colo-compare.h
118
.set_vnet_hdr_len = tap_set_vnet_hdr_len,
119
.set_vnet_le = tap_set_vnet_le,
120
.set_vnet_be = tap_set_vnet_be,
121
+ .set_steering_ebpf = tap_set_steering_ebpf,
122
};
123
124
static TAPState *net_tap_fd_init(NetClientState *peer,
125
diff --git a/net/tap_int.h b/net/tap_int.h
126
index XXXXXXX..XXXXXXX 100644
63
index XXXXXXX..XXXXXXX 100644
127
--- a/net/tap_int.h
64
--- a/net/colo-compare.h
128
+++ b/net/tap_int.h
65
+++ b/net/colo-compare.h
129
@@ -XXX,XX +XXX,XX @@ int tap_fd_set_vnet_be(int fd, int vnet_is_be);
66
@@ -XXX,XX +XXX,XX @@
130
int tap_fd_enable(int fd);
67
void colo_notify_compares_event(void *opaque, int event, Error **errp);
131
int tap_fd_disable(int fd);
68
void colo_compare_register_notifier(Notifier *notify);
132
int tap_fd_get_ifname(int fd, char *ifname);
69
void colo_compare_unregister_notifier(Notifier *notify);
133
+int tap_fd_set_steering_ebpf(int fd, int prog_fd);
70
+void colo_compare_cleanup(void);
134
71
135
#endif /* NET_TAP_INT_H */
72
#endif /* QEMU_COLO_COMPARE_H */
73
diff --git a/net/net.c b/net/net.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/net/net.c
76
+++ b/net/net.c
77
@@ -XXX,XX +XXX,XX @@
78
#include "qapi/error.h"
79
#include "qapi/opts-visitor.h"
80
#include "sysemu/runstate.h"
81
+#include "net/colo-compare.h"
82
#include "net/filter.h"
83
#include "qapi/string-output-visitor.h"
84
85
@@ -XXX,XX +XXX,XX @@ void net_cleanup(void)
86
{
87
NetClientState *nc;
88
89
+ /*cleanup colo compare module for COLO*/
90
+ colo_compare_cleanup();
91
+
92
/* We may del multiple entries during qemu_del_net_client(),
93
* so QTAILQ_FOREACH_SAFE() is also not safe here.
94
*/
136
--
95
--
137
2.7.4
96
2.7.4
138
97
139
98
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: "Rao, Lei" <lei.rao@intel.com>
2
2
3
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
3
The data pointer has skipped vnet_hdr_len in the function of
4
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
4
parse_packet_early().So, we can not subtract vnet_hdr_len again
5
when calculating pkt->header_size in fill_pkt_tcp_info(). Otherwise,
6
it will cause network packet comparsion errors and greatly increase
7
the frequency of checkpoints.
8
9
Signed-off-by: Lei Rao <lei.rao@intel.com>
10
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
11
Reviewed-by: Li Zhijian <lizhijian@fujitsu.com>
12
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
13
Reviewed-by: Lukas Straub <lukasstraub2@web.de>
14
Tested-by: Lukas Straub <lukasstraub2@web.de>
5
Signed-off-by: Jason Wang <jasowang@redhat.com>
15
Signed-off-by: Jason Wang <jasowang@redhat.com>
6
---
16
---
7
docs/devel/ebpf_rss.rst | 125 ++++++++++++++++++++++++++++++++++++++++++++++++
17
net/colo-compare.c | 2 +-
8
docs/devel/index.rst | 1 +
18
1 file changed, 1 insertion(+), 1 deletion(-)
9
2 files changed, 126 insertions(+)
10
create mode 100644 docs/devel/ebpf_rss.rst
11
19
12
diff --git a/docs/devel/ebpf_rss.rst b/docs/devel/ebpf_rss.rst
20
diff --git a/net/colo-compare.c b/net/colo-compare.c
13
new file mode 100644
14
index XXXXXXX..XXXXXXX
15
--- /dev/null
16
+++ b/docs/devel/ebpf_rss.rst
17
@@ -XXX,XX +XXX,XX @@
18
+===========================
19
+eBPF RSS virtio-net support
20
+===========================
21
+
22
+RSS(Receive Side Scaling) is used to distribute network packets to guest virtqueues
23
+by calculating packet hash. Usually every queue is processed then by a specific guest CPU core.
24
+
25
+For now there are 2 RSS implementations in qemu:
26
+- 'in-qemu' RSS (functions if qemu receives network packets, i.e. vhost=off)
27
+- eBPF RSS (can function with also with vhost=on)
28
+
29
+eBPF support (CONFIG_EBPF) is enabled by 'configure' script.
30
+To enable eBPF RSS support use './configure --enable-bpf'.
31
+
32
+If steering BPF is not set for kernel's TUN module, the TUN uses automatic selection
33
+of rx virtqueue based on lookup table built according to calculated symmetric hash
34
+of transmitted packets.
35
+If steering BPF is set for TUN the BPF code calculates the hash of packet header and
36
+returns the virtqueue number to place the packet to.
37
+
38
+Simplified decision formula:
39
+
40
+.. code:: C
41
+
42
+ queue_index = indirection_table[hash(<packet data>)%<indirection_table size>]
43
+
44
+
45
+Not for all packets, the hash can/should be calculated.
46
+
47
+Note: currently, eBPF RSS does not support hash reporting.
48
+
49
+eBPF RSS turned on by different combinations of vhost-net, vitrio-net and tap configurations:
50
+
51
+- eBPF is used:
52
+
53
+ tap,vhost=off & virtio-net-pci,rss=on,hash=off
54
+
55
+- eBPF is used:
56
+
57
+ tap,vhost=on & virtio-net-pci,rss=on,hash=off
58
+
59
+- 'in-qemu' RSS is used:
60
+
61
+ tap,vhost=off & virtio-net-pci,rss=on,hash=on
62
+
63
+- eBPF is used, hash population feature is not reported to the guest:
64
+
65
+ tap,vhost=on & virtio-net-pci,rss=on,hash=on
66
+
67
+If CONFIG_EBPF is not set then only 'in-qemu' RSS is supported.
68
+Also 'in-qemu' RSS, as a fallback, is used if the eBPF program failed to load or set to TUN.
69
+
70
+RSS eBPF program
71
+----------------
72
+
73
+RSS program located in ebpf/rss.bpf.skeleton.h generated by bpftool.
74
+So the program is part of the qemu binary.
75
+Initially, the eBPF program was compiled by clang and source code located at tools/ebpf/rss.bpf.c.
76
+Prerequisites to recompile the eBPF program (regenerate ebpf/rss.bpf.skeleton.h):
77
+
78
+ llvm, clang, kernel source tree, bpftool
79
+ Adjust Makefile.ebpf to reflect the location of the kernel source tree
80
+
81
+ $ cd tools/ebpf
82
+ $ make -f Makefile.ebpf
83
+
84
+Current eBPF RSS implementation uses 'bounded loops' with 'backward jump instructions' which present in the last kernels.
85
+Overall eBPF RSS works on kernels 5.8+.
86
+
87
+eBPF RSS implementation
88
+-----------------------
89
+
90
+eBPF RSS loading functionality located in ebpf/ebpf_rss.c and ebpf/ebpf_rss.h.
91
+
92
+The `struct EBPFRSSContext` structure that holds 4 file descriptors:
93
+
94
+- ctx - pointer of the libbpf context.
95
+- program_fd - file descriptor of the eBPF RSS program.
96
+- map_configuration - file descriptor of the 'configuration' map. This map contains one element of 'struct EBPFRSSConfig'. This configuration determines eBPF program behavior.
97
+- map_toeplitz_key - file descriptor of the 'Toeplitz key' map. One element of the 40byte key prepared for the hashing algorithm.
98
+- map_indirections_table - 128 elements of queue indexes.
99
+
100
+`struct EBPFRSSConfig` fields:
101
+
102
+- redirect - "boolean" value, should the hash be calculated, on false - `default_queue` would be used as the final decision.
103
+- populate_hash - for now, not used. eBPF RSS doesn't support hash reporting.
104
+- hash_types - binary mask of different hash types. See `VIRTIO_NET_RSS_HASH_TYPE_*` defines. If for packet hash should not be calculated - `default_queue` would be used.
105
+- indirections_len - length of the indirections table, maximum 128.
106
+- default_queue - the queue index that used for packet that shouldn't be hashed. For some packets, the hash can't be calculated(g.e ARP).
107
+
108
+Functions:
109
+
110
+- `ebpf_rss_init()` - sets ctx to NULL, which indicates that EBPFRSSContext is not loaded.
111
+- `ebpf_rss_load()` - creates 3 maps and loads eBPF program from the rss.bpf.skeleton.h. Returns 'true' on success. After that, program_fd can be used to set steering for TAP.
112
+- `ebpf_rss_set_all()` - sets values for eBPF maps. `indirections_table` length is in EBPFRSSConfig. `toeplitz_key` is VIRTIO_NET_RSS_MAX_KEY_SIZE aka 40 bytes array.
113
+- `ebpf_rss_unload()` - close all file descriptors and set ctx to NULL.
114
+
115
+Simplified eBPF RSS workflow:
116
+
117
+.. code:: C
118
+
119
+ struct EBPFRSSConfig config;
120
+ config.redirect = 1;
121
+ config.hash_types = VIRTIO_NET_RSS_HASH_TYPE_UDPv4 | VIRTIO_NET_RSS_HASH_TYPE_TCPv4;
122
+ config.indirections_len = VIRTIO_NET_RSS_MAX_TABLE_LEN;
123
+ config.default_queue = 0;
124
+
125
+ uint16_t table[VIRTIO_NET_RSS_MAX_TABLE_LEN] = {...};
126
+ uint8_t key[VIRTIO_NET_RSS_MAX_KEY_SIZE] = {...};
127
+
128
+ struct EBPFRSSContext ctx;
129
+ ebpf_rss_init(&ctx);
130
+ ebpf_rss_load(&ctx);
131
+ ebpf_rss_set_all(&ctx, &config, table, key);
132
+ if (net_client->info->set_steering_ebpf != NULL) {
133
+ net_client->info->set_steering_ebpf(net_client, ctx->program_fd);
134
+ }
135
+ ...
136
+ ebpf_unload(&ctx);
137
+
138
+
139
+NetClientState SetSteeringEBPF()
140
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
141
+
142
+For now, `set_steering_ebpf()` method supported by Linux TAP NetClientState. The method requires an eBPF program file descriptor as an argument.
143
diff --git a/docs/devel/index.rst b/docs/devel/index.rst
144
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
145
--- a/docs/devel/index.rst
22
--- a/net/colo-compare.c
146
+++ b/docs/devel/index.rst
23
+++ b/net/colo-compare.c
147
@@ -XXX,XX +XXX,XX @@ Contents:
24
@@ -XXX,XX +XXX,XX @@ static void fill_pkt_tcp_info(void *data, uint32_t *max_ack)
148
qom
25
pkt->tcp_ack = ntohl(tcphd->th_ack);
149
block-coroutine-wrapper
26
*max_ack = *max_ack > pkt->tcp_ack ? *max_ack : pkt->tcp_ack;
150
multi-process
27
pkt->header_size = pkt->transport_header - (uint8_t *)pkt->data
151
+ ebpf_rss
28
- + (tcphd->th_off << 2) - pkt->vnet_hdr_len;
29
+ + (tcphd->th_off << 2);
30
pkt->payload_size = pkt->size - pkt->header_size;
31
pkt->seq_end = pkt->tcp_seq + pkt->payload_size;
32
pkt->flags = tcphd->th_flags;
152
--
33
--
153
2.7.4
34
2.7.4
154
35
155
36
diff view generated by jsdifflib