1
The following changes since commit 92f8c6fef13b31ba222c4d20ad8afd2b79c4c28e:
1
The following changes since commit 7dd9d7e0bd29abf590d1ac235c0a00606ef81153:
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 tag 'pull-ppc-20220831' of https://gitlab.com/danielhb/qemu into staging (2022-09-01 13:53:20 -0400)
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 36a894aeb64a2e02871016da1c37d4a4ca109182:
10
10
11
MAINTAINERS: Added eBPF maintainers information. (2021-06-04 15:25:46 +0800)
11
net: tulip: Restrict DMA engine to memories (2022-09-02 10:22:39 +0800)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
14
15
----------------------------------------------------------------
15
----------------------------------------------------------------
16
Andrew Melnychenko (7):
16
Eugenio Pérez (19):
17
net/tap: Added TUNSETSTEERINGEBPF code.
17
vdpa: Skip the maps not in the iova tree
18
net: Added SetSteeringEBPF method for NetClientState.
18
vdpa: do not save failed dma maps in SVQ iova tree
19
ebpf: Added eBPF RSS program.
19
util: accept iova_tree_remove_parameter by value
20
ebpf: Added eBPF RSS loader.
20
vdpa: Remove SVQ vring from iova_tree at shutdown
21
virtio-net: Added eBPF RSS to virtio-net.
21
vdpa: Make SVQ vring unmapping return void
22
docs: Added eBPF documentation.
22
vhost: Always store new kick fd on vhost_svq_set_svq_kick_fd
23
MAINTAINERS: Added eBPF maintainers information.
23
vdpa: Use ring hwaddr at vhost_vdpa_svq_unmap_ring
24
vhost: stop transfer elem ownership in vhost_handle_guest_kick
25
vhost: use SVQ element ndescs instead of opaque data for desc validation
26
vhost: Delete useless read memory barrier
27
vhost: Do not depend on !NULL VirtQueueElement on vhost_svq_flush
28
vhost_net: Add NetClientInfo start callback
29
vhost_net: Add NetClientInfo stop callback
30
vdpa: add net_vhost_vdpa_cvq_info NetClientInfo
31
vdpa: Move command buffers map to start of net device
32
vdpa: extract vhost_vdpa_net_cvq_add from vhost_vdpa_net_handle_ctrl_avail
33
vhost_net: add NetClientState->load() callback
34
vdpa: Add virtio-net mac address via CVQ at start
35
vdpa: Delete CVQ migration blocker
24
36
25
MAINTAINERS | 8 +
37
Zhang Chen (1):
26
configure | 8 +-
38
net/colo.c: Fix the pointer issue reported by Coverity.
27
docs/devel/ebpf_rss.rst | 125 +++++++++
39
28
docs/devel/index.rst | 1 +
40
Zheyu Ma (1):
29
ebpf/ebpf_rss-stub.c | 40 +++
41
net: tulip: Restrict DMA engine to memories
30
ebpf/ebpf_rss.c | 165 ++++++++++++
42
31
ebpf/ebpf_rss.h | 44 ++++
43
hw/i386/intel_iommu.c | 6 +-
32
ebpf/meson.build | 1 +
44
hw/net/tulip.c | 4 +-
33
ebpf/rss.bpf.skeleton.h | 431 +++++++++++++++++++++++++++++++
45
hw/net/vhost_net.c | 17 +++
34
ebpf/trace-events | 4 +
46
hw/virtio/vhost-iova-tree.c | 2 +-
35
ebpf/trace.h | 1 +
47
hw/virtio/vhost-iova-tree.h | 2 +-
36
hw/net/vhost_net.c | 3 +
48
hw/virtio/vhost-shadow-virtqueue.c | 31 +++--
37
hw/net/virtio-net.c | 116 ++++++++-
49
hw/virtio/vhost-vdpa.c | 90 +++++++--------
38
include/hw/virtio/virtio-net.h | 4 +
50
include/hw/virtio/vhost-vdpa.h | 1 -
39
include/net/net.h | 2 +
51
include/net/net.h | 6 +
40
meson.build | 23 ++
52
include/qemu/iova-tree.h | 2 +-
41
meson_options.txt | 2 +
53
net/colo.c | 25 ++--
42
net/tap-bsd.c | 5 +
54
net/colo.h | 1 +
43
net/tap-linux.c | 13 +
55
net/trace-events | 2 +-
44
net/tap-linux.h | 1 +
56
net/vhost-vdpa.c | 228 +++++++++++++++++++++++--------------
45
net/tap-solaris.c | 5 +
57
util/iova-tree.c | 4 +-
46
net/tap-stub.c | 5 +
58
15 files changed, 248 insertions(+), 173 deletions(-)
47
net/tap.c | 9 +
48
net/tap_int.h | 1 +
49
net/vhost-vdpa.c | 2 +
50
tools/ebpf/Makefile.ebpf | 21 ++
51
tools/ebpf/rss.bpf.c | 571 +++++++++++++++++++++++++++++++++++++++++
52
27 files changed, 1607 insertions(+), 4 deletions(-)
53
create mode 100644 docs/devel/ebpf_rss.rst
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
59
64
60
diff view generated by jsdifflib
New patch
1
From: Eugenio Pérez <eperezma@redhat.com>
1
2
3
Next patch will skip the registering of dma maps that the vdpa device
4
rejects in the iova tree. We need to consider that here or we cause a
5
SIGSEGV accessing result.
6
7
Reported-by: Lei Yang <leiyang@redhat.com>
8
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
9
Acked-by: Jason Wang <jasowang@redhat.com>
10
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
---
12
hw/virtio/vhost-vdpa.c | 4 ++++
13
1 file changed, 4 insertions(+)
14
15
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/virtio/vhost-vdpa.c
18
+++ b/hw/virtio/vhost-vdpa.c
19
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener,
20
};
21
22
result = vhost_iova_tree_find_iova(v->iova_tree, &mem_region);
23
+ if (!result) {
24
+ /* The memory listener map wasn't mapped */
25
+ return;
26
+ }
27
iova = result->iova;
28
vhost_iova_tree_remove(v->iova_tree, result);
29
}
30
--
31
2.7.4
32
33
diff view generated by jsdifflib
New patch
1
From: Eugenio Pérez <eperezma@redhat.com>
1
2
3
If a map fails for whatever reason, it must not be saved in the tree.
4
Otherwise, qemu will try to unmap it in cleanup, leaving to more errors.
5
6
Fixes: 34e3c94eda ("vdpa: Add custom IOTLB translations to SVQ")
7
Reported-by: Lei Yang <leiyang@redhat.com>
8
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
9
Acked-by: Jason Wang <jasowang@redhat.com>
10
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
---
12
hw/virtio/vhost-vdpa.c | 20 +++++++++++++-------
13
1 file changed, 13 insertions(+), 7 deletions(-)
14
15
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/virtio/vhost-vdpa.c
18
+++ b/hw/virtio/vhost-vdpa.c
19
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_listener_commit(MemoryListener *listener)
20
static void vhost_vdpa_listener_region_add(MemoryListener *listener,
21
MemoryRegionSection *section)
22
{
23
+ DMAMap mem_region = {};
24
struct vhost_vdpa *v = container_of(listener, struct vhost_vdpa, listener);
25
hwaddr iova;
26
Int128 llend, llsize;
27
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener,
28
29
llsize = int128_sub(llend, int128_make64(iova));
30
if (v->shadow_vqs_enabled) {
31
- DMAMap mem_region = {
32
- .translated_addr = (hwaddr)(uintptr_t)vaddr,
33
- .size = int128_get64(llsize) - 1,
34
- .perm = IOMMU_ACCESS_FLAG(true, section->readonly),
35
- };
36
+ int r;
37
38
- int r = vhost_iova_tree_map_alloc(v->iova_tree, &mem_region);
39
+ mem_region.translated_addr = (hwaddr)(uintptr_t)vaddr,
40
+ mem_region.size = int128_get64(llsize) - 1,
41
+ mem_region.perm = IOMMU_ACCESS_FLAG(true, section->readonly),
42
+
43
+ r = vhost_iova_tree_map_alloc(v->iova_tree, &mem_region);
44
if (unlikely(r != IOVA_OK)) {
45
error_report("Can't allocate a mapping (%d)", r);
46
goto fail;
47
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener,
48
vaddr, section->readonly);
49
if (ret) {
50
error_report("vhost vdpa map fail!");
51
- goto fail;
52
+ goto fail_map;
53
}
54
55
return;
56
57
+fail_map:
58
+ if (v->shadow_vqs_enabled) {
59
+ vhost_iova_tree_remove(v->iova_tree, &mem_region);
60
+ }
61
+
62
fail:
63
/*
64
* On the initfn path, store the first error in the container so we
65
--
66
2.7.4
67
68
diff view generated by jsdifflib
New patch
1
From: Eugenio Pérez <eperezma@redhat.com>
1
2
3
It's convenient to call iova_tree_remove from a map returned from
4
iova_tree_find or iova_tree_find_iova. With the current code this is not
5
possible, since we will free it, and then we will try to search for it
6
again.
7
8
Fix it making accepting the map by value, forcing a copy of the
9
argument. Not applying a fixes tag, since there is no use like that at
10
the moment.
11
12
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
13
Signed-off-by: Jason Wang <jasowang@redhat.com>
14
---
15
hw/i386/intel_iommu.c | 6 +++---
16
hw/virtio/vhost-iova-tree.c | 2 +-
17
hw/virtio/vhost-iova-tree.h | 2 +-
18
hw/virtio/vhost-vdpa.c | 6 +++---
19
include/qemu/iova-tree.h | 2 +-
20
net/vhost-vdpa.c | 4 ++--
21
util/iova-tree.c | 4 ++--
22
7 files changed, 13 insertions(+), 13 deletions(-)
23
24
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/hw/i386/intel_iommu.c
27
+++ b/hw/i386/intel_iommu.c
28
@@ -XXX,XX +XXX,XX @@ static int vtd_page_walk_one(IOMMUTLBEvent *event, vtd_page_walk_info *info)
29
return ret;
30
}
31
/* Drop any existing mapping */
32
- iova_tree_remove(as->iova_tree, &target);
33
+ iova_tree_remove(as->iova_tree, target);
34
/* Recover the correct type */
35
event->type = IOMMU_NOTIFIER_MAP;
36
entry->perm = cache_perm;
37
@@ -XXX,XX +XXX,XX @@ static int vtd_page_walk_one(IOMMUTLBEvent *event, vtd_page_walk_info *info)
38
trace_vtd_page_walk_one_skip_unmap(entry->iova, entry->addr_mask);
39
return 0;
40
}
41
- iova_tree_remove(as->iova_tree, &target);
42
+ iova_tree_remove(as->iova_tree, target);
43
}
44
45
trace_vtd_page_walk_one(info->domain_id, entry->iova,
46
@@ -XXX,XX +XXX,XX @@ static void vtd_address_space_unmap(VTDAddressSpace *as, IOMMUNotifier *n)
47
48
map.iova = n->start;
49
map.size = size;
50
- iova_tree_remove(as->iova_tree, &map);
51
+ iova_tree_remove(as->iova_tree, map);
52
}
53
54
static void vtd_address_space_unmap_all(IntelIOMMUState *s)
55
diff --git a/hw/virtio/vhost-iova-tree.c b/hw/virtio/vhost-iova-tree.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/hw/virtio/vhost-iova-tree.c
58
+++ b/hw/virtio/vhost-iova-tree.c
59
@@ -XXX,XX +XXX,XX @@ int vhost_iova_tree_map_alloc(VhostIOVATree *tree, DMAMap *map)
60
* @iova_tree: The vhost iova tree
61
* @map: The map to remove
62
*/
63
-void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map)
64
+void vhost_iova_tree_remove(VhostIOVATree *iova_tree, DMAMap map)
65
{
66
iova_tree_remove(iova_tree->iova_taddr_map, map);
67
}
68
diff --git a/hw/virtio/vhost-iova-tree.h b/hw/virtio/vhost-iova-tree.h
69
index XXXXXXX..XXXXXXX 100644
70
--- a/hw/virtio/vhost-iova-tree.h
71
+++ b/hw/virtio/vhost-iova-tree.h
72
@@ -XXX,XX +XXX,XX @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostIOVATree, vhost_iova_tree_delete);
73
const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *iova_tree,
74
const DMAMap *map);
75
int vhost_iova_tree_map_alloc(VhostIOVATree *iova_tree, DMAMap *map);
76
-void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map);
77
+void vhost_iova_tree_remove(VhostIOVATree *iova_tree, DMAMap map);
78
79
#endif
80
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
81
index XXXXXXX..XXXXXXX 100644
82
--- a/hw/virtio/vhost-vdpa.c
83
+++ b/hw/virtio/vhost-vdpa.c
84
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener,
85
86
fail_map:
87
if (v->shadow_vqs_enabled) {
88
- vhost_iova_tree_remove(v->iova_tree, &mem_region);
89
+ vhost_iova_tree_remove(v->iova_tree, mem_region);
90
}
91
92
fail:
93
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener,
94
return;
95
}
96
iova = result->iova;
97
- vhost_iova_tree_remove(v->iova_tree, result);
98
+ vhost_iova_tree_remove(v->iova_tree, *result);
99
}
100
vhost_vdpa_iotlb_batch_begin_once(v);
101
ret = vhost_vdpa_dma_unmap(v, iova, int128_get64(llsize));
102
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_svq_map_ring(struct vhost_vdpa *v, DMAMap *needle,
103
needle->perm == IOMMU_RO);
104
if (unlikely(r != 0)) {
105
error_setg_errno(errp, -r, "Cannot map region to device");
106
- vhost_iova_tree_remove(v->iova_tree, needle);
107
+ vhost_iova_tree_remove(v->iova_tree, *needle);
108
}
109
110
return r == 0;
111
diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h
112
index XXXXXXX..XXXXXXX 100644
113
--- a/include/qemu/iova-tree.h
114
+++ b/include/qemu/iova-tree.h
115
@@ -XXX,XX +XXX,XX @@ int iova_tree_insert(IOVATree *tree, const DMAMap *map);
116
* all the mappings that are included in the provided range will be
117
* removed from the tree. Here map->translated_addr is meaningless.
118
*/
119
-void iova_tree_remove(IOVATree *tree, const DMAMap *map);
120
+void iova_tree_remove(IOVATree *tree, DMAMap map);
121
122
/**
123
* iova_tree_find:
124
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
125
index XXXXXXX..XXXXXXX 100644
126
--- a/net/vhost-vdpa.c
127
+++ b/net/vhost-vdpa.c
128
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_cvq_unmap_buf(struct vhost_vdpa *v, void *addr)
129
error_report("Device cannot unmap: %s(%d)", g_strerror(r), r);
130
}
131
132
- vhost_iova_tree_remove(tree, map);
133
+ vhost_iova_tree_remove(tree, *map);
134
}
135
136
static size_t vhost_vdpa_net_cvq_cmd_len(void)
137
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v,
138
return true;
139
140
dma_map_err:
141
- vhost_iova_tree_remove(v->iova_tree, &map);
142
+ vhost_iova_tree_remove(v->iova_tree, map);
143
return false;
144
}
145
146
diff --git a/util/iova-tree.c b/util/iova-tree.c
147
index XXXXXXX..XXXXXXX 100644
148
--- a/util/iova-tree.c
149
+++ b/util/iova-tree.c
150
@@ -XXX,XX +XXX,XX @@ void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator)
151
g_tree_foreach(tree->tree, iova_tree_traverse, iterator);
152
}
153
154
-void iova_tree_remove(IOVATree *tree, const DMAMap *map)
155
+void iova_tree_remove(IOVATree *tree, DMAMap map)
156
{
157
const DMAMap *overlap;
158
159
- while ((overlap = iova_tree_find(tree, map))) {
160
+ while ((overlap = iova_tree_find(tree, &map))) {
161
g_tree_remove(tree->tree, overlap);
162
}
163
}
164
--
165
2.7.4
166
167
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Added function that loads RSS eBPF program.
3
Although the device will be reset before usage, the right thing to do is
4
Added stub functions for RSS eBPF loader.
4
to clean it.
5
Added meson and configuration options.
6
5
7
By default, eBPF feature enabled if libbpf is present in the build system.
6
Reported-by: Lei Yang <leiyang@redhat.com>
8
libbpf checked in configuration shell script and meson script.
7
Fixes: 34e3c94eda ("vdpa: Add custom IOTLB translations to SVQ")
9
8
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
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>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
13
---
10
---
14
configure | 8 +-
11
hw/virtio/vhost-vdpa.c | 6 ++++++
15
ebpf/ebpf_rss-stub.c | 40 +++++
12
1 file changed, 6 insertions(+)
16
ebpf/ebpf_rss.c | 165 ++++++++++++++++++
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 bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v,
38
vhost_user="no"
19
39
vhost_user_blk_server="auto"
20
size = ROUND_UP(result->size, qemu_real_host_page_size());
40
vhost_user_fs="$default_feature"
21
r = vhost_vdpa_dma_unmap(v, result->iova, size);
41
+bpf="auto"
22
+ if (unlikely(r < 0)) {
42
kvm="auto"
23
+ error_report("Unable to unmap SVQ vring: %s (%d)", g_strerror(-r), -r);
43
hax="auto"
44
hvf="auto"
45
@@ -XXX,XX +XXX,XX @@ for opt do
46
;;
47
--enable-membarrier) membarrier="yes"
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
+
91
+#include "qemu/osdep.h"
92
+#include "ebpf/ebpf_rss.h"
93
+
94
+void ebpf_rss_init(struct EBPFRSSContext *ctx)
95
+{
96
+
97
+}
98
+
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
+ }
155
+}
156
+
157
+bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
158
+{
159
+ return ctx != NULL && ctx->obj != NULL;
160
+}
161
+
162
+bool ebpf_rss_load(struct EBPFRSSContext *ctx)
163
+{
164
+ struct rss_bpf *rss_bpf_ctx;
165
+
166
+ if (ctx == NULL) {
167
+ return false;
24
+ return false;
168
+ }
25
+ }
169
+
26
+
170
+ rss_bpf_ctx = rss_bpf__open();
27
+ vhost_iova_tree_remove(v->iova_tree, *result);
171
+ if (rss_bpf_ctx == NULL) {
28
return r == 0;
172
+ trace_ebpf_error("eBPF RSS", "can not open eBPF RSS object");
29
}
173
+ goto error;
30
174
+ }
175
+
176
+ bpf_program__set_socket_filter(rss_bpf_ctx->progs.tun_rss_steering_prog);
177
+
178
+ if (rss_bpf__load(rss_bpf_ctx)) {
179
+ trace_ebpf_error("eBPF RSS", "can not load RSS program");
180
+ goto error;
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
+}
200
+
201
+static bool ebpf_rss_set_config(struct EBPFRSSContext *ctx,
202
+ struct EBPFRSSConfig *config)
203
+{
204
+ uint32_t map_key = 0;
205
+
206
+ if (!ebpf_rss_is_loaded(ctx)) {
207
+ return false;
208
+ }
209
+ if (bpf_map_update_elem(ctx->map_configuration,
210
+ &map_key, config, 0) < 0) {
211
+ return false;
212
+ }
213
+ return true;
214
+}
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
--
31
--
877
2.7.4
32
2.7.4
878
33
879
34
diff view generated by jsdifflib
New patch
1
From: Eugenio Pérez <eperezma@redhat.com>
1
2
3
Nothing actually reads the return value, but an error in cleaning some
4
entries could cause device stop to abort, making a restart impossible.
5
Better ignore explicitely the return value.
6
7
Reported-by: Lei Yang <leiyang@redhat.com>
8
Fixes: 34e3c94eda ("vdpa: Add custom IOTLB translations to SVQ")
9
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
10
Acked-by: Jason Wang <jasowang@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
13
hw/virtio/vhost-vdpa.c | 32 ++++++++++----------------------
14
1 file changed, 10 insertions(+), 22 deletions(-)
15
16
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/virtio/vhost-vdpa.c
19
+++ b/hw/virtio/vhost-vdpa.c
20
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev,
21
/**
22
* Unmap a SVQ area in the device
23
*/
24
-static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v,
25
+static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v,
26
const DMAMap *needle)
27
{
28
const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, needle);
29
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v,
30
31
if (unlikely(!result)) {
32
error_report("Unable to find SVQ address to unmap");
33
- return false;
34
+ return;
35
}
36
37
size = ROUND_UP(result->size, qemu_real_host_page_size());
38
r = vhost_vdpa_dma_unmap(v, result->iova, size);
39
if (unlikely(r < 0)) {
40
error_report("Unable to unmap SVQ vring: %s (%d)", g_strerror(-r), -r);
41
- return false;
42
+ return;
43
}
44
45
vhost_iova_tree_remove(v->iova_tree, *result);
46
- return r == 0;
47
}
48
49
-static bool vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev,
50
+static void vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev,
51
const VhostShadowVirtqueue *svq)
52
{
53
DMAMap needle = {};
54
struct vhost_vdpa *v = dev->opaque;
55
struct vhost_vring_addr svq_addr;
56
- bool ok;
57
58
vhost_svq_get_vring_addr(svq, &svq_addr);
59
60
needle.translated_addr = svq_addr.desc_user_addr;
61
- ok = vhost_vdpa_svq_unmap_ring(v, &needle);
62
- if (unlikely(!ok)) {
63
- return false;
64
- }
65
+ vhost_vdpa_svq_unmap_ring(v, &needle);
66
67
needle.translated_addr = svq_addr.used_user_addr;
68
- return vhost_vdpa_svq_unmap_ring(v, &needle);
69
+ vhost_vdpa_svq_unmap_ring(v, &needle);
70
}
71
72
/**
73
@@ -XXX,XX +XXX,XX @@ err:
74
return false;
75
}
76
77
-static bool vhost_vdpa_svqs_stop(struct vhost_dev *dev)
78
+static void vhost_vdpa_svqs_stop(struct vhost_dev *dev)
79
{
80
struct vhost_vdpa *v = dev->opaque;
81
82
if (!v->shadow_vqs) {
83
- return true;
84
+ return;
85
}
86
87
for (unsigned i = 0; i < v->shadow_vqs->len; ++i) {
88
VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i);
89
- bool ok = vhost_vdpa_svq_unmap_rings(dev, svq);
90
- if (unlikely(!ok)) {
91
- return false;
92
- }
93
+ vhost_vdpa_svq_unmap_rings(dev, svq);
94
}
95
96
if (v->migration_blocker) {
97
migrate_del_blocker(v->migration_blocker);
98
}
99
- return true;
100
}
101
102
static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
103
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
104
}
105
vhost_vdpa_set_vring_ready(dev);
106
} else {
107
- ok = vhost_vdpa_svqs_stop(dev);
108
- if (unlikely(!ok)) {
109
- return -1;
110
- }
111
+ vhost_vdpa_svqs_stop(dev);
112
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
113
}
114
115
--
116
2.7.4
117
118
diff view generated by jsdifflib
New patch
1
From: Eugenio Pérez <eperezma@redhat.com>
1
2
3
We can unbind twice a file descriptor if we call twice
4
vhost_svq_set_svq_kick_fd because of this. Since it comes from vhost and
5
not from SVQ, that file descriptor could be a different thing that
6
guest's vhost notifier.
7
8
Likewise, it can happens the same if a guest start and stop the device
9
multiple times.
10
11
Reported-by: Lei Yang <leiyang@redhat.com>
12
Fixes: dff4426fa6 ("vhost: Add Shadow VirtQueue kick forwarding capabilities")
13
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
14
Acked-by: Jason Wang <jasowang@redhat.com>
15
Signed-off-by: Jason Wang <jasowang@redhat.com>
16
---
17
hw/virtio/vhost-shadow-virtqueue.c | 4 ++--
18
1 file changed, 2 insertions(+), 2 deletions(-)
19
20
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/hw/virtio/vhost-shadow-virtqueue.c
23
+++ b/hw/virtio/vhost-shadow-virtqueue.c
24
@@ -XXX,XX +XXX,XX @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd)
25
event_notifier_set_handler(svq_kick, NULL);
26
}
27
28
+ event_notifier_init_fd(svq_kick, svq_kick_fd);
29
/*
30
* event_notifier_set_handler already checks for guest's notifications if
31
* they arrive at the new file descriptor in the switch, so there is no
32
* need to explicitly check for them.
33
*/
34
if (poll_start) {
35
- event_notifier_init_fd(svq_kick, svq_kick_fd);
36
event_notifier_set(svq_kick);
37
event_notifier_set_handler(svq_kick, vhost_handle_guest_kick_notifier);
38
}
39
@@ -XXX,XX +XXX,XX @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev,
40
*/
41
void vhost_svq_stop(VhostShadowVirtqueue *svq)
42
{
43
- event_notifier_set_handler(&svq->svq_kick, NULL);
44
+ vhost_svq_set_svq_kick_fd(svq, VHOST_FILE_UNBIND);
45
g_autofree VirtQueueElement *next_avail_elem = NULL;
46
47
if (!svq->vq) {
48
--
49
2.7.4
50
51
diff view generated by jsdifflib
New patch
1
From: Eugenio Pérez <eperezma@redhat.com>
1
2
3
Reduce code duplication.
4
5
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
6
Acked-by: Jason Wang <jasowang@redhat.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
9
hw/virtio/vhost-vdpa.c | 17 ++++++++---------
10
1 file changed, 8 insertions(+), 9 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 int vhost_vdpa_svq_set_fds(struct vhost_dev *dev,
17
/**
18
* Unmap a SVQ area in the device
19
*/
20
-static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v,
21
- const DMAMap *needle)
22
+static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, hwaddr addr)
23
{
24
- const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, needle);
25
+ const DMAMap needle = {
26
+ .translated_addr = addr,
27
+ };
28
+ const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, &needle);
29
hwaddr size;
30
int r;
31
32
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v,
33
static void vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev,
34
const VhostShadowVirtqueue *svq)
35
{
36
- DMAMap needle = {};
37
struct vhost_vdpa *v = dev->opaque;
38
struct vhost_vring_addr svq_addr;
39
40
vhost_svq_get_vring_addr(svq, &svq_addr);
41
42
- needle.translated_addr = svq_addr.desc_user_addr;
43
- vhost_vdpa_svq_unmap_ring(v, &needle);
44
+ vhost_vdpa_svq_unmap_ring(v, svq_addr.desc_user_addr);
45
46
- needle.translated_addr = svq_addr.used_user_addr;
47
- vhost_vdpa_svq_unmap_ring(v, &needle);
48
+ vhost_vdpa_svq_unmap_ring(v, svq_addr.used_user_addr);
49
}
50
51
/**
52
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev,
53
ok = vhost_vdpa_svq_map_ring(v, &device_region, errp);
54
if (unlikely(!ok)) {
55
error_prepend(errp, "Cannot create vq device region: ");
56
- vhost_vdpa_svq_unmap_ring(v, &driver_region);
57
+ vhost_vdpa_svq_unmap_ring(v, driver_region.translated_addr);
58
}
59
addr->used_user_addr = device_region.iova;
60
61
--
62
2.7.4
63
64
diff view generated by jsdifflib
New patch
1
From: Eugenio Pérez <eperezma@redhat.com>
1
2
3
It was easier to allow vhost_svq_add to handle the memory. Now that we
4
will allow qemu to add elements to a SVQ without the guest's knowledge,
5
it's better to handle it in the caller.
6
7
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
8
Acked-by: Jason Wang <jasowang@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
---
11
hw/virtio/vhost-shadow-virtqueue.c | 10 ++++------
12
1 file changed, 4 insertions(+), 6 deletions(-)
13
14
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/virtio/vhost-shadow-virtqueue.c
17
+++ b/hw/virtio/vhost-shadow-virtqueue.c
18
@@ -XXX,XX +XXX,XX @@ static void vhost_svq_kick(VhostShadowVirtqueue *svq)
19
/**
20
* Add an element to a SVQ.
21
*
22
- * The caller must check that there is enough slots for the new element. It
23
- * takes ownership of the element: In case of failure not ENOSPC, it is free.
24
- *
25
* Return -EINVAL if element is invalid, -ENOSPC if dev queue is full
26
*/
27
int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg,
28
@@ -XXX,XX +XXX,XX @@ int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg,
29
30
ok = vhost_svq_add_split(svq, out_sg, out_num, in_sg, in_num, &qemu_head);
31
if (unlikely(!ok)) {
32
- g_free(elem);
33
return -EINVAL;
34
}
35
36
@@ -XXX,XX +XXX,XX @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq)
37
virtio_queue_set_notification(svq->vq, false);
38
39
while (true) {
40
- VirtQueueElement *elem;
41
+ g_autofree VirtQueueElement *elem;
42
int r;
43
44
if (svq->next_guest_avail_elem) {
45
@@ -XXX,XX +XXX,XX @@ static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq)
46
* queue the current guest descriptor and ignore kicks
47
* until some elements are used.
48
*/
49
- svq->next_guest_avail_elem = elem;
50
+ svq->next_guest_avail_elem = g_steal_pointer(&elem);
51
}
52
53
/* VQ is full or broken, just return and ignore kicks */
54
return;
55
}
56
+ /* elem belongs to SVQ or external caller now */
57
+ elem = NULL;
58
}
59
60
virtio_queue_set_notification(svq->vq, true);
61
--
62
2.7.4
63
64
diff view generated by jsdifflib
New patch
1
From: Eugenio Pérez <eperezma@redhat.com>
1
2
3
Since we're going to allow SVQ to add elements without the guest's
4
knowledge and without its own VirtQueueElement, it's easier to check if
5
an element is a valid head checking a different thing than the
6
VirtQueueElement.
7
8
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
9
Acked-by: Jason Wang <jasowang@redhat.com>
10
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
---
12
hw/virtio/vhost-shadow-virtqueue.c | 3 ++-
13
1 file changed, 2 insertions(+), 1 deletion(-)
14
15
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/virtio/vhost-shadow-virtqueue.c
18
+++ b/hw/virtio/vhost-shadow-virtqueue.c
19
@@ -XXX,XX +XXX,XX @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq,
20
return NULL;
21
}
22
23
- if (unlikely(!svq->desc_state[used_elem.id].elem)) {
24
+ if (unlikely(!svq->desc_state[used_elem.id].ndescs)) {
25
qemu_log_mask(LOG_GUEST_ERROR,
26
"Device %s says index %u is used, but it was not available",
27
svq->vdev->name, used_elem.id);
28
@@ -XXX,XX +XXX,XX @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq,
29
}
30
31
num = svq->desc_state[used_elem.id].ndescs;
32
+ svq->desc_state[used_elem.id].ndescs = 0;
33
last_used_chain = vhost_svq_last_desc_of_chain(svq, num, used_elem.id);
34
svq->desc_next[last_used_chain] = svq->free_head;
35
svq->free_head = used_elem.id;
36
--
37
2.7.4
38
39
diff view generated by jsdifflib
New patch
1
From: Eugenio Pérez <eperezma@redhat.com>
1
2
3
As discussed in previous series [1], this memory barrier is useless with
4
the atomic read of used idx at vhost_svq_more_used. Deleting it.
5
6
[1] https://lists.nongnu.org/archive/html/qemu-devel/2022-07/msg02616.html
7
8
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
9
Acked-by: Jason Wang <jasowang@redhat.com>
10
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
---
12
hw/virtio/vhost-shadow-virtqueue.c | 3 ---
13
1 file changed, 3 deletions(-)
14
15
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/virtio/vhost-shadow-virtqueue.c
18
+++ b/hw/virtio/vhost-shadow-virtqueue.c
19
@@ -XXX,XX +XXX,XX @@ size_t vhost_svq_poll(VhostShadowVirtqueue *svq)
20
if (unlikely(g_get_monotonic_time() - start_us > 10e6)) {
21
return 0;
22
}
23
-
24
- /* Make sure we read new used_idx */
25
- smp_rmb();
26
} while (true);
27
}
28
29
--
30
2.7.4
31
32
diff view generated by jsdifflib
New patch
1
From: Eugenio Pérez <eperezma@redhat.com>
1
2
3
Since QEMU will be able to inject new elements on CVQ to restore the
4
state, we need not to depend on a VirtQueueElement to know if a new
5
element has been used by the device or not. Instead of check that, check
6
if there are new elements only using used idx on vhost_svq_flush.
7
8
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
9
Acked-by: Jason Wang <jasowang@redhat.com>
10
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
---
12
hw/virtio/vhost-shadow-virtqueue.c | 11 +++++++----
13
1 file changed, 7 insertions(+), 4 deletions(-)
14
15
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/virtio/vhost-shadow-virtqueue.c
18
+++ b/hw/virtio/vhost-shadow-virtqueue.c
19
@@ -XXX,XX +XXX,XX @@ static void vhost_svq_flush(VhostShadowVirtqueue *svq,
20
size_t vhost_svq_poll(VhostShadowVirtqueue *svq)
21
{
22
int64_t start_us = g_get_monotonic_time();
23
+ uint32_t len;
24
+
25
do {
26
- uint32_t len;
27
- VirtQueueElement *elem = vhost_svq_get_buf(svq, &len);
28
- if (elem) {
29
- return len;
30
+ if (vhost_svq_more_used(svq)) {
31
+ break;
32
}
33
34
if (unlikely(g_get_monotonic_time() - start_us > 10e6)) {
35
return 0;
36
}
37
} while (true);
38
+
39
+ vhost_svq_get_buf(svq, &len);
40
+ return len;
41
}
42
43
/**
44
--
45
2.7.4
46
47
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
When RSS is enabled the device tries to load the eBPF program
3
This is used by the backend to perform actions before the device is
4
to select RX virtqueue in the TUN. If eBPF can be loaded
4
started.
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
5
9
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
6
In particular, vdpa net use it to map CVQ buffers to the device, so it
10
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
7
can send control commands using them.
8
9
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
10
Acked-by: Jason Wang <jasowang@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
12
---
13
hw/net/vhost_net.c | 3 ++
13
hw/net/vhost_net.c | 7 +++++++
14
hw/net/virtio-net.c | 116 +++++++++++++++++++++++++++++++++++++++--
14
include/net/net.h | 2 ++
15
include/hw/virtio/virtio-net.h | 4 ++
15
2 files changed, 9 insertions(+)
16
net/vhost-vdpa.c | 2 +
17
4 files changed, 122 insertions(+), 3 deletions(-)
18
16
19
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
17
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
20
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/net/vhost_net.c
19
--- a/hw/net/vhost_net.c
22
+++ b/hw/net/vhost_net.c
20
+++ b/hw/net/vhost_net.c
23
@@ -XXX,XX +XXX,XX @@ static const int kernel_feature_bits[] = {
21
@@ -XXX,XX +XXX,XX @@ static int vhost_net_start_one(struct vhost_net *net,
24
VIRTIO_NET_F_MTU,
22
struct vhost_vring_file file = { };
25
VIRTIO_F_IOMMU_PLATFORM,
23
int r;
26
VIRTIO_F_RING_PACKED,
24
27
+ VIRTIO_NET_F_HASH_REPORT,
25
+ if (net->nc->info->start) {
28
VHOST_INVALID_FEATURE_BIT
26
+ r = net->nc->info->start(net->nc);
29
};
27
+ if (r < 0) {
30
28
+ return r;
31
@@ -XXX,XX +XXX,XX @@ static const int user_feature_bits[] = {
29
+ }
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
+ }
30
+ }
78
+
31
+
79
+ return nc->info->set_steering_ebpf(nc, prog_fd);
32
r = vhost_dev_enable_notifiers(&net->dev, dev);
80
+}
33
if (r < 0) {
81
+
34
goto fail_notifiers;
82
+static void rss_data_to_rss_config(struct VirtioNetRssData *data,
35
diff --git a/include/net/net.h b/include/net/net.h
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
36
index XXXXXXX..XXXXXXX 100644
224
--- a/include/hw/virtio/virtio-net.h
37
--- a/include/net/net.h
225
+++ b/include/hw/virtio/virtio-net.h
38
+++ b/include/net/net.h
226
@@ -XXX,XX +XXX,XX @@
39
@@ -XXX,XX +XXX,XX @@ typedef struct NICConf {
227
#include "qemu/option_int.h"
40
228
#include "qom/object.h"
41
typedef void (NetPoll)(NetClientState *, bool enable);
229
42
typedef bool (NetCanReceive)(NetClientState *);
230
+#include "ebpf/ebpf_rss.h"
43
+typedef int (NetStart)(NetClientState *);
231
+
44
typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t);
232
#define TYPE_VIRTIO_NET "virtio-net-device"
45
typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int);
233
OBJECT_DECLARE_SIMPLE_TYPE(VirtIONet, VIRTIO_NET)
46
typedef void (NetCleanup) (NetClientState *);
234
47
@@ -XXX,XX +XXX,XX @@ typedef struct NetClientInfo {
235
@@ -XXX,XX +XXX,XX @@ typedef struct VirtioNetRscChain {
48
NetReceive *receive_raw;
236
49
NetReceiveIOV *receive_iov;
237
typedef struct VirtioNetRssData {
50
NetCanReceive *can_receive;
238
bool enabled;
51
+ NetStart *start;
239
+ bool enabled_software_rss;
52
NetCleanup *cleanup;
240
bool redirect;
53
LinkStatusChanged *link_status_changed;
241
bool populate_hash;
54
QueryRxFilter *query_rx_filter;
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
252
index XXXXXXX..XXXXXXX 100644
253
--- a/net/vhost-vdpa.c
254
+++ b/net/vhost-vdpa.c
255
@@ -XXX,XX +XXX,XX @@ const int vdpa_feature_bits[] = {
256
VIRTIO_NET_F_MTU,
257
VIRTIO_F_IOMMU_PLATFORM,
258
VIRTIO_F_RING_PACKED,
259
+ VIRTIO_NET_F_RSS,
260
+ VIRTIO_NET_F_HASH_REPORT,
261
VIRTIO_NET_F_GUEST_ANNOUNCE,
262
VIRTIO_NET_F_STATUS,
263
VHOST_INVALID_FEATURE_BIT
264
--
55
--
265
2.7.4
56
2.7.4
266
57
267
58
diff view generated by jsdifflib
New patch
1
From: Eugenio Pérez <eperezma@redhat.com>
1
2
3
Used by the backend to perform actions after the device is stopped.
4
5
In particular, vdpa net use it to unmap CVQ buffers to the device,
6
cleaning the actions performed in prepare().
7
8
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
9
Acked-by: Jason Wang <jasowang@redhat.com>
10
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
---
12
hw/net/vhost_net.c | 3 +++
13
include/net/net.h | 2 ++
14
2 files changed, 5 insertions(+)
15
16
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/net/vhost_net.c
19
+++ b/hw/net/vhost_net.c
20
@@ -XXX,XX +XXX,XX @@ static void vhost_net_stop_one(struct vhost_net *net,
21
net->nc->info->poll(net->nc, true);
22
}
23
vhost_dev_stop(&net->dev, dev);
24
+ if (net->nc->info->stop) {
25
+ net->nc->info->stop(net->nc);
26
+ }
27
vhost_dev_disable_notifiers(&net->dev, dev);
28
}
29
30
diff --git a/include/net/net.h b/include/net/net.h
31
index XXXXXXX..XXXXXXX 100644
32
--- a/include/net/net.h
33
+++ b/include/net/net.h
34
@@ -XXX,XX +XXX,XX @@ typedef struct NICConf {
35
typedef void (NetPoll)(NetClientState *, bool enable);
36
typedef bool (NetCanReceive)(NetClientState *);
37
typedef int (NetStart)(NetClientState *);
38
+typedef void (NetStop)(NetClientState *);
39
typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t);
40
typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int);
41
typedef void (NetCleanup) (NetClientState *);
42
@@ -XXX,XX +XXX,XX @@ typedef struct NetClientInfo {
43
NetReceiveIOV *receive_iov;
44
NetCanReceive *can_receive;
45
NetStart *start;
46
+ NetStop *stop;
47
NetCleanup *cleanup;
48
LinkStatusChanged *link_status_changed;
49
QueryRxFilter *query_rx_filter;
50
--
51
2.7.4
52
53
diff view generated by jsdifflib
New patch
1
From: Eugenio Pérez <eperezma@redhat.com>
1
2
3
Next patches will add a new info callback to restore NIC status through
4
CVQ. Since only the CVQ vhost device is needed, create it with a new
5
NetClientInfo.
6
7
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
8
Acked-by: Jason Wang <jasowang@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
---
11
net/vhost-vdpa.c | 12 +++++++++++-
12
1 file changed, 11 insertions(+), 1 deletion(-)
13
14
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/net/vhost-vdpa.c
17
+++ b/net/vhost-vdpa.c
18
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_net_cvq_map_elem(VhostVDPAState *s,
19
return true;
20
}
21
22
+static NetClientInfo net_vhost_vdpa_cvq_info = {
23
+ .type = NET_CLIENT_DRIVER_VHOST_VDPA,
24
+ .size = sizeof(VhostVDPAState),
25
+ .receive = vhost_vdpa_receive,
26
+ .cleanup = vhost_vdpa_cleanup,
27
+ .has_vnet_hdr = vhost_vdpa_has_vnet_hdr,
28
+ .has_ufo = vhost_vdpa_has_ufo,
29
+ .check_peer_type = vhost_vdpa_check_peer_type,
30
+};
31
+
32
/**
33
* Do not forward commands not supported by SVQ. Otherwise, the device could
34
* accept it and qemu would not know how to update the device model.
35
@@ -XXX,XX +XXX,XX @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer,
36
nc = qemu_new_net_client(&net_vhost_vdpa_info, peer, device,
37
name);
38
} else {
39
- nc = qemu_new_net_control_client(&net_vhost_vdpa_info, peer,
40
+ nc = qemu_new_net_control_client(&net_vhost_vdpa_cvq_info, peer,
41
device, name);
42
}
43
snprintf(nc->info_str, sizeof(nc->info_str), TYPE_VHOST_VDPA);
44
--
45
2.7.4
46
47
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Additional code that will be used for eBPF setting steering routine.
3
As this series will reuse them to restore the device state at the end of
4
4
a migration (or a device start), let's allocate only once at the device
5
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
5
start so we don't duplicate their map and unmap.
6
7
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
8
Acked-by: Jason Wang <jasowang@redhat.com>
6
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
7
---
10
---
8
net/tap-linux.h | 1 +
11
net/vhost-vdpa.c | 123 ++++++++++++++++++++++++++-----------------------------
9
1 file changed, 1 insertion(+)
12
1 file changed, 58 insertions(+), 65 deletions(-)
10
13
11
diff --git a/net/tap-linux.h b/net/tap-linux.h
14
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
12
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
13
--- a/net/tap-linux.h
16
--- a/net/vhost-vdpa.c
14
+++ b/net/tap-linux.h
17
+++ b/net/vhost-vdpa.c
15
@@ -XXX,XX +XXX,XX @@
18
@@ -XXX,XX +XXX,XX @@ static size_t vhost_vdpa_net_cvq_cmd_page_len(void)
16
#define TUNSETQUEUE _IOW('T', 217, int)
19
return ROUND_UP(vhost_vdpa_net_cvq_cmd_len(), qemu_real_host_page_size());
17
#define TUNSETVNETLE _IOW('T', 220, int)
20
}
18
#define TUNSETVNETBE _IOW('T', 222, int)
21
19
+#define TUNSETSTEERINGEBPF _IOR('T', 224, int)
22
-/** Copy and map a guest buffer. */
20
23
-static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v,
21
#endif
24
- const struct iovec *out_data,
25
- size_t out_num, size_t data_len, void *buf,
26
- size_t *written, bool write)
27
+/** Map CVQ buffer. */
28
+static int vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v, void *buf, size_t size,
29
+ bool write)
30
{
31
DMAMap map = {};
32
int r;
33
34
- if (unlikely(!data_len)) {
35
- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid legnth of %s buffer\n",
36
- __func__, write ? "in" : "out");
37
- return false;
38
- }
39
-
40
- *written = iov_to_buf(out_data, out_num, 0, buf, data_len);
41
map.translated_addr = (hwaddr)(uintptr_t)buf;
42
- map.size = vhost_vdpa_net_cvq_cmd_page_len() - 1;
43
+ map.size = size - 1;
44
map.perm = write ? IOMMU_RW : IOMMU_RO,
45
r = vhost_iova_tree_map_alloc(v->iova_tree, &map);
46
if (unlikely(r != IOVA_OK)) {
47
error_report("Cannot map injected element");
48
- return false;
49
+ return r;
50
}
51
52
r = vhost_vdpa_dma_map(v, map.iova, vhost_vdpa_net_cvq_cmd_page_len(), buf,
53
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_cvq_map_buf(struct vhost_vdpa *v,
54
goto dma_map_err;
55
}
56
57
- return true;
58
+ return 0;
59
60
dma_map_err:
61
vhost_iova_tree_remove(v->iova_tree, map);
62
- return false;
63
+ return r;
64
}
65
66
-/**
67
- * Copy the guest element into a dedicated buffer suitable to be sent to NIC
68
- *
69
- * @iov: [0] is the out buffer, [1] is the in one
70
- */
71
-static bool vhost_vdpa_net_cvq_map_elem(VhostVDPAState *s,
72
- VirtQueueElement *elem,
73
- struct iovec *iov)
74
+static int vhost_vdpa_net_cvq_start(NetClientState *nc)
75
{
76
- size_t in_copied;
77
- bool ok;
78
+ VhostVDPAState *s;
79
+ int r;
80
81
- iov[0].iov_base = s->cvq_cmd_out_buffer;
82
- ok = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, elem->out_sg, elem->out_num,
83
- vhost_vdpa_net_cvq_cmd_len(), iov[0].iov_base,
84
- &iov[0].iov_len, false);
85
- if (unlikely(!ok)) {
86
- return false;
87
+ assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
88
+
89
+ s = DO_UPCAST(VhostVDPAState, nc, nc);
90
+ if (!s->vhost_vdpa.shadow_vqs_enabled) {
91
+ return 0;
92
}
93
94
- iov[1].iov_base = s->cvq_cmd_in_buffer;
95
- ok = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, NULL, 0,
96
- sizeof(virtio_net_ctrl_ack), iov[1].iov_base,
97
- &in_copied, true);
98
- if (unlikely(!ok)) {
99
+ r = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer,
100
+ vhost_vdpa_net_cvq_cmd_page_len(), false);
101
+ if (unlikely(r < 0)) {
102
+ return r;
103
+ }
104
+
105
+ r = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, s->cvq_cmd_in_buffer,
106
+ vhost_vdpa_net_cvq_cmd_page_len(), true);
107
+ if (unlikely(r < 0)) {
108
vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer);
109
- return false;
110
}
111
112
- iov[1].iov_len = sizeof(virtio_net_ctrl_ack);
113
- return true;
114
+ return r;
115
+}
116
+
117
+static void vhost_vdpa_net_cvq_stop(NetClientState *nc)
118
+{
119
+ VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc);
120
+
121
+ assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
122
+
123
+ if (s->vhost_vdpa.shadow_vqs_enabled) {
124
+ vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer);
125
+ vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, s->cvq_cmd_in_buffer);
126
+ }
127
}
128
129
static NetClientInfo net_vhost_vdpa_cvq_info = {
130
.type = NET_CLIENT_DRIVER_VHOST_VDPA,
131
.size = sizeof(VhostVDPAState),
132
.receive = vhost_vdpa_receive,
133
+ .start = vhost_vdpa_net_cvq_start,
134
+ .stop = vhost_vdpa_net_cvq_stop,
135
.cleanup = vhost_vdpa_cleanup,
136
.has_vnet_hdr = vhost_vdpa_has_vnet_hdr,
137
.has_ufo = vhost_vdpa_has_ufo,
138
@@ -XXX,XX +XXX,XX @@ static NetClientInfo net_vhost_vdpa_cvq_info = {
139
* Do not forward commands not supported by SVQ. Otherwise, the device could
140
* accept it and qemu would not know how to update the device model.
141
*/
142
-static bool vhost_vdpa_net_cvq_validate_cmd(const struct iovec *out,
143
- size_t out_num)
144
+static bool vhost_vdpa_net_cvq_validate_cmd(const void *out_buf, size_t len)
145
{
146
struct virtio_net_ctrl_hdr ctrl;
147
- size_t n;
148
149
- n = iov_to_buf(out, out_num, 0, &ctrl, sizeof(ctrl));
150
- if (unlikely(n < sizeof(ctrl))) {
151
+ if (unlikely(len < sizeof(ctrl))) {
152
qemu_log_mask(LOG_GUEST_ERROR,
153
- "%s: invalid legnth of out buffer %zu\n", __func__, n);
154
+ "%s: invalid legnth of out buffer %zu\n", __func__, len);
155
return false;
156
}
157
158
+ memcpy(&ctrl, out_buf, sizeof(ctrl));
159
switch (ctrl.class) {
160
case VIRTIO_NET_CTRL_MAC:
161
switch (ctrl.cmd) {
162
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq,
163
VhostVDPAState *s = opaque;
164
size_t in_len, dev_written;
165
virtio_net_ctrl_ack status = VIRTIO_NET_ERR;
166
- /* out and in buffers sent to the device */
167
- struct iovec dev_buffers[2] = {
168
- { .iov_base = s->cvq_cmd_out_buffer },
169
- { .iov_base = s->cvq_cmd_in_buffer },
170
+ /* Out buffer sent to both the vdpa device and the device model */
171
+ struct iovec out = {
172
+ .iov_base = s->cvq_cmd_out_buffer,
173
+ };
174
+ /* In buffer sent to the device */
175
+ const struct iovec dev_in = {
176
+ .iov_base = s->cvq_cmd_in_buffer,
177
+ .iov_len = sizeof(virtio_net_ctrl_ack),
178
};
179
/* in buffer used for device model */
180
const struct iovec in = {
181
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq,
182
int r = -EINVAL;
183
bool ok;
184
185
- ok = vhost_vdpa_net_cvq_map_elem(s, elem, dev_buffers);
186
- if (unlikely(!ok)) {
187
- goto out;
188
- }
189
-
190
- ok = vhost_vdpa_net_cvq_validate_cmd(&dev_buffers[0], 1);
191
+ out.iov_len = iov_to_buf(elem->out_sg, elem->out_num, 0,
192
+ s->cvq_cmd_out_buffer,
193
+ vhost_vdpa_net_cvq_cmd_len());
194
+ ok = vhost_vdpa_net_cvq_validate_cmd(s->cvq_cmd_out_buffer, out.iov_len);
195
if (unlikely(!ok)) {
196
goto out;
197
}
198
199
- r = vhost_svq_add(svq, &dev_buffers[0], 1, &dev_buffers[1], 1, elem);
200
+ r = vhost_svq_add(svq, &out, 1, &dev_in, 1, elem);
201
if (unlikely(r != 0)) {
202
if (unlikely(r == -ENOSPC)) {
203
qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n",
204
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq,
205
goto out;
206
}
207
208
- memcpy(&status, dev_buffers[1].iov_base, sizeof(status));
209
+ memcpy(&status, s->cvq_cmd_in_buffer, sizeof(status));
210
if (status != VIRTIO_NET_OK) {
211
goto out;
212
}
213
214
status = VIRTIO_NET_ERR;
215
- virtio_net_handle_ctrl_iov(svq->vdev, &in, 1, dev_buffers, 1);
216
+ virtio_net_handle_ctrl_iov(svq->vdev, &in, 1, &out, 1);
217
if (status != VIRTIO_NET_OK) {
218
error_report("Bad CVQ processing in model");
219
}
220
@@ -XXX,XX +XXX,XX @@ out:
221
}
222
vhost_svq_push_elem(svq, elem, MIN(in_len, sizeof(status)));
223
g_free(elem);
224
- if (dev_buffers[0].iov_base) {
225
- vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, dev_buffers[0].iov_base);
226
- }
227
- if (dev_buffers[1].iov_base) {
228
- vhost_vdpa_cvq_unmap_buf(&s->vhost_vdpa, dev_buffers[1].iov_base);
229
- }
230
return r;
231
}
22
232
23
--
233
--
24
2.7.4
234
2.7.4
25
235
26
236
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
3
So we can reuse it to inject state messages.
4
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
4
5
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
6
Acked-by: Jason Wang <jasowang@redhat.com>
7
--
8
v7:
9
* Remove double free error
10
11
v6:
12
* Do not assume in buffer sent to the device is sizeof(virtio_net_ctrl_ack)
13
14
v5:
15
* Do not use an artificial !NULL VirtQueueElement
16
* Use only out size instead of iovec dev_buffers for these functions.
17
5
Signed-off-by: Jason Wang <jasowang@redhat.com>
18
Signed-off-by: Jason Wang <jasowang@redhat.com>
6
---
19
---
7
MAINTAINERS | 8 ++++++++
20
net/vhost-vdpa.c | 59 ++++++++++++++++++++++++++++++++++++--------------------
8
1 file changed, 8 insertions(+)
21
1 file changed, 38 insertions(+), 21 deletions(-)
9
22
10
diff --git a/MAINTAINERS b/MAINTAINERS
23
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
11
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
12
--- a/MAINTAINERS
25
--- a/net/vhost-vdpa.c
13
+++ b/MAINTAINERS
26
+++ b/net/vhost-vdpa.c
14
@@ -XXX,XX +XXX,XX @@ F: include/hw/remote/proxy-memory-listener.h
27
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_net_cvq_stop(NetClientState *nc)
15
F: hw/remote/iohub.c
28
}
16
F: include/hw/remote/iohub.h
29
}
17
30
18
+EBPF:
31
+static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, size_t out_len,
19
+M: Jason Wang <jasowang@redhat.com>
32
+ size_t in_len)
20
+R: Andrew Melnychenko <andrew@daynix.com>
33
+{
21
+R: Yuri Benditovich <yuri.benditovich@daynix.com>
34
+ /* Buffers for the device */
22
+S: Maintained
35
+ const struct iovec out = {
23
+F: ebpf/*
36
+ .iov_base = s->cvq_cmd_out_buffer,
24
+F: tools/ebpf/*
37
+ .iov_len = out_len,
38
+ };
39
+ const struct iovec in = {
40
+ .iov_base = s->cvq_cmd_in_buffer,
41
+ .iov_len = sizeof(virtio_net_ctrl_ack),
42
+ };
43
+ VhostShadowVirtqueue *svq = g_ptr_array_index(s->vhost_vdpa.shadow_vqs, 0);
44
+ int r;
25
+
45
+
26
Build and test automation
46
+ r = vhost_svq_add(svq, &out, 1, &in, 1, NULL);
27
-------------------------
47
+ if (unlikely(r != 0)) {
28
Build and test automation, general continuous integration
48
+ if (unlikely(r == -ENOSPC)) {
49
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n",
50
+ __func__);
51
+ }
52
+ return r;
53
+ }
54
+
55
+ /*
56
+ * We can poll here since we've had BQL from the time we sent the
57
+ * descriptor. Also, we need to take the answer before SVQ pulls by itself,
58
+ * when BQL is released
59
+ */
60
+ return vhost_svq_poll(svq);
61
+}
62
+
63
static NetClientInfo net_vhost_vdpa_cvq_info = {
64
.type = NET_CLIENT_DRIVER_VHOST_VDPA,
65
.size = sizeof(VhostVDPAState),
66
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq,
67
void *opaque)
68
{
69
VhostVDPAState *s = opaque;
70
- size_t in_len, dev_written;
71
+ size_t in_len;
72
virtio_net_ctrl_ack status = VIRTIO_NET_ERR;
73
/* Out buffer sent to both the vdpa device and the device model */
74
struct iovec out = {
75
.iov_base = s->cvq_cmd_out_buffer,
76
};
77
- /* In buffer sent to the device */
78
- const struct iovec dev_in = {
79
- .iov_base = s->cvq_cmd_in_buffer,
80
- .iov_len = sizeof(virtio_net_ctrl_ack),
81
- };
82
/* in buffer used for device model */
83
const struct iovec in = {
84
.iov_base = &status,
85
.iov_len = sizeof(status),
86
};
87
- int r = -EINVAL;
88
+ ssize_t dev_written = -EINVAL;
89
bool ok;
90
91
out.iov_len = iov_to_buf(elem->out_sg, elem->out_num, 0,
92
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq,
93
goto out;
94
}
95
96
- r = vhost_svq_add(svq, &out, 1, &dev_in, 1, elem);
97
- if (unlikely(r != 0)) {
98
- if (unlikely(r == -ENOSPC)) {
99
- qemu_log_mask(LOG_GUEST_ERROR, "%s: No space on device queue\n",
100
- __func__);
101
- }
102
+ dev_written = vhost_vdpa_net_cvq_add(s, out.iov_len, sizeof(status));
103
+ if (unlikely(dev_written < 0)) {
104
goto out;
105
}
106
107
- /*
108
- * We can poll here since we've had BQL from the time we sent the
109
- * descriptor. Also, we need to take the answer before SVQ pulls by itself,
110
- * when BQL is released
111
- */
112
- dev_written = vhost_svq_poll(svq);
113
if (unlikely(dev_written < sizeof(status))) {
114
error_report("Insufficient written data (%zu)", dev_written);
115
goto out;
116
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq,
117
118
memcpy(&status, s->cvq_cmd_in_buffer, sizeof(status));
119
if (status != VIRTIO_NET_OK) {
120
- goto out;
121
+ return VIRTIO_NET_ERR;
122
}
123
124
status = VIRTIO_NET_ERR;
125
@@ -XXX,XX +XXX,XX @@ out:
126
}
127
vhost_svq_push_elem(svq, elem, MIN(in_len, sizeof(status)));
128
g_free(elem);
129
- return r;
130
+ return dev_written < 0 ? dev_written : 0;
131
}
132
133
static const VhostShadowVirtqueueOps vhost_vdpa_net_svq_ops = {
29
--
134
--
30
2.7.4
135
2.7.4
31
136
32
137
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
For now, that method supported only by Linux TAP.
3
It allows per-net client operations right after device's successful
4
Linux TAP uses TUNSETSTEERINGEBPF ioctl.
4
start. In particular, to load the device status.
5
5
6
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
6
Vhost-vdpa net will use it to add the CVQ buffers to restore the device
7
status.
8
9
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
10
Acked-by: Jason Wang <jasowang@redhat.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
12
---
9
include/net/net.h | 2 ++
13
hw/net/vhost_net.c | 7 +++++++
10
net/tap-bsd.c | 5 +++++
14
include/net/net.h | 2 ++
11
net/tap-linux.c | 13 +++++++++++++
15
2 files changed, 9 insertions(+)
12
net/tap-solaris.c | 5 +++++
13
net/tap-stub.c | 5 +++++
14
net/tap.c | 9 +++++++++
15
net/tap_int.h | 1 +
16
7 files changed, 40 insertions(+)
17
16
17
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/net/vhost_net.c
20
+++ b/hw/net/vhost_net.c
21
@@ -XXX,XX +XXX,XX @@ static int vhost_net_start_one(struct vhost_net *net,
22
}
23
}
24
}
25
+
26
+ if (net->nc->info->load) {
27
+ r = net->nc->info->load(net->nc);
28
+ if (r < 0) {
29
+ goto fail;
30
+ }
31
+ }
32
return 0;
33
fail:
34
file.fd = -1;
18
diff --git a/include/net/net.h b/include/net/net.h
35
diff --git a/include/net/net.h b/include/net/net.h
19
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
20
--- a/include/net/net.h
37
--- a/include/net/net.h
21
+++ b/include/net/net.h
38
+++ b/include/net/net.h
22
@@ -XXX,XX +XXX,XX @@ typedef int (SetVnetBE)(NetClientState *, bool);
39
@@ -XXX,XX +XXX,XX @@ typedef struct NICConf {
23
typedef struct SocketReadState SocketReadState;
40
typedef void (NetPoll)(NetClientState *, bool enable);
24
typedef void (SocketReadStateFinalize)(SocketReadState *rs);
41
typedef bool (NetCanReceive)(NetClientState *);
25
typedef void (NetAnnounce)(NetClientState *);
42
typedef int (NetStart)(NetClientState *);
26
+typedef bool (SetSteeringEBPF)(NetClientState *, int);
43
+typedef int (NetLoad)(NetClientState *);
27
44
typedef void (NetStop)(NetClientState *);
28
typedef struct NetClientInfo {
45
typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t);
29
NetClientDriver type;
46
typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int);
30
@@ -XXX,XX +XXX,XX @@ typedef struct NetClientInfo {
47
@@ -XXX,XX +XXX,XX @@ typedef struct NetClientInfo {
31
SetVnetLE *set_vnet_le;
48
NetReceiveIOV *receive_iov;
32
SetVnetBE *set_vnet_be;
49
NetCanReceive *can_receive;
33
NetAnnounce *announce;
50
NetStart *start;
34
+ SetSteeringEBPF *set_steering_ebpf;
51
+ NetLoad *load;
35
} NetClientInfo;
52
NetStop *stop;
36
53
NetCleanup *cleanup;
37
struct NetClientState {
54
LinkStatusChanged *link_status_changed;
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
}
46
+
47
+int tap_fd_set_steering_ebpf(int fd, int prog_fd)
48
+{
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
+ }
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
+}
113
+
114
int tap_get_fd(NetClientState *nc)
115
{
116
TAPState *s = DO_UPCAST(TAPState, nc, nc);
117
@@ -XXX,XX +XXX,XX @@ static NetClientInfo net_tap_info = {
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
127
--- a/net/tap_int.h
128
+++ b/net/tap_int.h
129
@@ -XXX,XX +XXX,XX @@ int tap_fd_set_vnet_be(int fd, int vnet_is_be);
130
int tap_fd_enable(int fd);
131
int tap_fd_disable(int fd);
132
int tap_fd_get_ifname(int fd, char *ifname);
133
+int tap_fd_set_steering_ebpf(int fd, int prog_fd);
134
135
#endif /* NET_TAP_INT_H */
136
--
55
--
137
2.7.4
56
2.7.4
138
57
139
58
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
RSS program and Makefile to build it.
3
This is needed so the destination vdpa device see the same state a the
4
The bpftool used to generate '.h' file.
4
guest set in the source.
5
The data in that file may be loaded by libbpf.
6
EBPF compilation is not required for building qemu.
7
You can use Makefile if you need to regenerate rss.bpf.skeleton.h.
8
5
9
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
6
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
10
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
7
Acked-by: Jason Wang <jasowang@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
9
---
13
tools/ebpf/Makefile.ebpf | 21 ++
10
net/vhost-vdpa.c | 40 ++++++++++++++++++++++++++++++++++++++++
14
tools/ebpf/rss.bpf.c | 571 +++++++++++++++++++++++++++++++++++++++++++++++
11
1 file changed, 40 insertions(+)
15
2 files changed, 592 insertions(+)
16
create mode 100755 tools/ebpf/Makefile.ebpf
17
create mode 100644 tools/ebpf/rss.bpf.c
18
12
19
diff --git a/tools/ebpf/Makefile.ebpf b/tools/ebpf/Makefile.ebpf
13
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
20
new file mode 100755
14
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX
15
--- a/net/vhost-vdpa.c
22
--- /dev/null
16
+++ b/net/vhost-vdpa.c
23
+++ b/tools/ebpf/Makefile.ebpf
17
@@ -XXX,XX +XXX,XX @@ static ssize_t vhost_vdpa_net_cvq_add(VhostVDPAState *s, size_t out_len,
24
@@ -XXX,XX +XXX,XX @@
18
return vhost_svq_poll(svq);
25
+OBJS = rss.bpf.o
19
}
20
21
+static int vhost_vdpa_net_load(NetClientState *nc)
22
+{
23
+ VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc);
24
+ const struct vhost_vdpa *v = &s->vhost_vdpa;
25
+ const VirtIONet *n;
26
+ uint64_t features;
26
+
27
+
27
+LLC ?= llc
28
+ assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
28
+CLANG ?= clang
29
+INC_FLAGS = `$(CLANG) -print-file-name=include`
30
+EXTRA_CFLAGS ?= -O2 -emit-llvm -fno-stack-protector
31
+
29
+
32
+all: $(OBJS)
30
+ if (!v->shadow_vqs_enabled) {
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
+}
159
+
160
+static inline
161
+void net_toeplitz_add(__u32 *result,
162
+ __u8 *input,
163
+ __u32 len
164
+ , struct toeplitz_key_data_t *key) {
165
+
166
+ __u32 accumulator = *result;
167
+ __u32 leftmost_32_bits = key->leftmost_32_bits;
168
+ __u32 byte;
169
+
170
+ for (byte = 0; byte < HASH_CALCULATION_BUFFER_SIZE; byte++) {
171
+ __u8 input_byte = input[byte];
172
+ __u8 key_byte = key->next_byte[byte];
173
+ __u8 bit;
174
+
175
+ for (bit = 0; bit < 8; bit++) {
176
+ if (input_byte & (1 << 7)) {
177
+ accumulator ^= leftmost_32_bits;
178
+ }
179
+
180
+ leftmost_32_bits =
181
+ (leftmost_32_bits << 1) | ((key_byte & (1 << 7)) >> 7);
182
+
183
+ input_byte <<= 1;
184
+ key_byte <<= 1;
185
+ }
186
+ }
187
+
188
+ *result = accumulator;
189
+}
190
+
191
+
192
+static inline int ip6_extension_header_type(__u8 hdr_type)
193
+{
194
+ switch (hdr_type) {
195
+ case IPPROTO_HOPOPTS:
196
+ case IPPROTO_ROUTING:
197
+ case IPPROTO_FRAGMENT:
198
+ case IPPROTO_ICMPV6:
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;
31
+ return 0;
226
+ }
32
+ }
227
+
33
+
228
+ struct ipv6_opt_hdr ext_hdr = {};
34
+ n = VIRTIO_NET(v->dev->vdev);
35
+ features = n->parent_obj.guest_features;
36
+ if (features & BIT_ULL(VIRTIO_NET_F_CTRL_MAC_ADDR)) {
37
+ const struct virtio_net_ctrl_hdr ctrl = {
38
+ .class = VIRTIO_NET_CTRL_MAC,
39
+ .cmd = VIRTIO_NET_CTRL_MAC_ADDR_SET,
40
+ };
41
+ char *cursor = s->cvq_cmd_out_buffer;
42
+ ssize_t dev_written;
229
+
43
+
230
+ for (unsigned int i = 0; i < IP6_EXTENSIONS_COUNT; ++i) {
44
+ memcpy(cursor, &ctrl, sizeof(ctrl));
45
+ cursor += sizeof(ctrl);
46
+ memcpy(cursor, n->mac, sizeof(n->mac));
231
+
47
+
232
+ err = bpf_skb_load_bytes_relative(skb, *l4_offset, &ext_hdr,
48
+ dev_written = vhost_vdpa_net_cvq_add(s, sizeof(ctrl) + sizeof(n->mac),
233
+ sizeof(ext_hdr), BPF_HDR_START_NET);
49
+ sizeof(virtio_net_ctrl_ack));
234
+ if (err) {
50
+ if (unlikely(dev_written < 0)) {
235
+ goto error;
51
+ return dev_written;
236
+ }
52
+ }
237
+
53
+
238
+ if (*l4_protocol == IPPROTO_ROUTING) {
54
+ return *((virtio_net_ctrl_ack *)s->cvq_cmd_in_buffer) != VIRTIO_NET_OK;
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
+ }
55
+ }
309
+
56
+
310
+ return 0;
57
+ return 0;
311
+error:
312
+ return err;
313
+}
58
+}
314
+
59
+
315
+static __be16 parse_eth_type(struct __sk_buff *skb)
60
static NetClientInfo net_vhost_vdpa_cvq_info = {
316
+{
61
.type = NET_CLIENT_DRIVER_VHOST_VDPA,
317
+ unsigned int offset = 12;
62
.size = sizeof(VhostVDPAState),
318
+ __be16 ret = 0;
63
.receive = vhost_vdpa_receive,
319
+ int err = 0;
64
.start = vhost_vdpa_net_cvq_start,
320
+
65
+ .load = vhost_vdpa_net_load,
321
+ err = bpf_skb_load_bytes_relative(skb, offset, &ret, sizeof(ret),
66
.stop = vhost_vdpa_net_cvq_stop,
322
+ BPF_HDR_START_MAC);
67
.cleanup = vhost_vdpa_cleanup,
323
+ if (err) {
68
.has_vnet_hdr = vhost_vdpa_has_vnet_hdr,
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
--
69
--
624
2.7.4
70
2.7.4
625
71
626
72
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
3
We can restore the device state in the destination via CVQ now. Remove
4
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
4
the migration blocker.
5
6
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
7
Acked-by: Jason Wang <jasowang@redhat.com>
5
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
6
---
9
---
7
docs/devel/ebpf_rss.rst | 125 ++++++++++++++++++++++++++++++++++++++++++++++++
10
hw/virtio/vhost-vdpa.c | 15 ---------------
8
docs/devel/index.rst | 1 +
11
include/hw/virtio/vhost-vdpa.h | 1 -
9
2 files changed, 126 insertions(+)
12
net/vhost-vdpa.c | 2 --
10
create mode 100644 docs/devel/ebpf_rss.rst
13
3 files changed, 18 deletions(-)
11
14
12
diff --git a/docs/devel/ebpf_rss.rst b/docs/devel/ebpf_rss.rst
15
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.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
16
index XXXXXXX..XXXXXXX 100644
145
--- a/docs/devel/index.rst
17
--- a/hw/virtio/vhost-vdpa.c
146
+++ b/docs/devel/index.rst
18
+++ b/hw/virtio/vhost-vdpa.c
147
@@ -XXX,XX +XXX,XX @@ Contents:
19
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev)
148
qom
20
return true;
149
block-coroutine-wrapper
21
}
150
multi-process
22
151
+ ebpf_rss
23
- if (v->migration_blocker) {
24
- int r = migrate_add_blocker(v->migration_blocker, &err);
25
- if (unlikely(r < 0)) {
26
- return false;
27
- }
28
- }
29
-
30
for (i = 0; i < v->shadow_vqs->len; ++i) {
31
VirtQueue *vq = virtio_get_queue(dev->vdev, dev->vq_index + i);
32
VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i);
33
@@ -XXX,XX +XXX,XX @@ err:
34
vhost_svq_stop(svq);
35
}
36
37
- if (v->migration_blocker) {
38
- migrate_del_blocker(v->migration_blocker);
39
- }
40
-
41
return false;
42
}
43
44
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_svqs_stop(struct vhost_dev *dev)
45
VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i);
46
vhost_vdpa_svq_unmap_rings(dev, svq);
47
}
48
-
49
- if (v->migration_blocker) {
50
- migrate_del_blocker(v->migration_blocker);
51
- }
52
}
53
54
static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
55
diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h
56
index XXXXXXX..XXXXXXX 100644
57
--- a/include/hw/virtio/vhost-vdpa.h
58
+++ b/include/hw/virtio/vhost-vdpa.h
59
@@ -XXX,XX +XXX,XX @@ typedef struct vhost_vdpa {
60
bool shadow_vqs_enabled;
61
/* IOVA mapping used by the Shadow Virtqueue */
62
VhostIOVATree *iova_tree;
63
- Error *migration_blocker;
64
GPtrArray *shadow_vqs;
65
const VhostShadowVirtqueueOps *shadow_vq_ops;
66
void *shadow_vq_ops_opaque;
67
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
68
index XXXXXXX..XXXXXXX 100644
69
--- a/net/vhost-vdpa.c
70
+++ b/net/vhost-vdpa.c
71
@@ -XXX,XX +XXX,XX @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer,
72
73
s->vhost_vdpa.shadow_vq_ops = &vhost_vdpa_net_svq_ops;
74
s->vhost_vdpa.shadow_vq_ops_opaque = s;
75
- error_setg(&s->vhost_vdpa.migration_blocker,
76
- "Migration disabled: vhost-vdpa uses CVQ.");
77
}
78
ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa, queue_pair_index, nvqs);
79
if (ret) {
152
--
80
--
153
2.7.4
81
2.7.4
154
82
155
83
diff view generated by jsdifflib
New patch
1
From: Zhang Chen <chen.zhang@intel.com>
1
2
3
When enabled the virtio-net-pci, guest network packet will
4
load the vnet_hdr. In COLO status, the primary VM's network
5
packet maybe redirect to another VM, it needs filter-redirect
6
enable the vnet_hdr flag at the same time, COLO-proxy will
7
correctly parse the original network packet. If have any
8
misconfiguration here, the vnet_hdr_len is wrong for parse
9
the packet, the data+offset will point to wrong place.
10
11
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
12
Signed-off-by: Jason Wang <jasowang@redhat.com>
13
---
14
net/colo.c | 25 ++++++++++++++++---------
15
net/colo.h | 1 +
16
net/trace-events | 2 +-
17
3 files changed, 18 insertions(+), 10 deletions(-)
18
19
diff --git a/net/colo.c b/net/colo.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/net/colo.c
22
+++ b/net/colo.c
23
@@ -XXX,XX +XXX,XX @@ int parse_packet_early(Packet *pkt)
24
{
25
int network_length;
26
static const uint8_t vlan[] = {0x81, 0x00};
27
- uint8_t *data = pkt->data + pkt->vnet_hdr_len;
28
+ uint8_t *data = pkt->data;
29
uint16_t l3_proto;
30
ssize_t l2hdr_len;
31
32
- if (data == NULL) {
33
- trace_colo_proxy_main_vnet_info("This packet is not parsed correctly, "
34
- "pkt->vnet_hdr_len", pkt->vnet_hdr_len);
35
+ assert(data);
36
+
37
+ /* Check the received vnet_hdr_len then add the offset */
38
+ if ((pkt->vnet_hdr_len > sizeof(struct virtio_net_hdr_v1_hash)) ||
39
+ (pkt->size < sizeof(struct eth_header) + sizeof(struct vlan_header) +
40
+ pkt->vnet_hdr_len)) {
41
+ /*
42
+ * The received remote packet maybe misconfiguration here,
43
+ * Please enable/disable filter module's the vnet_hdr flag at
44
+ * the same time.
45
+ */
46
+ trace_colo_proxy_main_vnet_info("This received packet load wrong ",
47
+ pkt->vnet_hdr_len, pkt->size);
48
return 1;
49
}
50
- l2hdr_len = eth_get_l2_hdr_length(data);
51
+ data += pkt->vnet_hdr_len;
52
53
- if (pkt->size < ETH_HLEN + pkt->vnet_hdr_len) {
54
- trace_colo_proxy_main("pkt->size < ETH_HLEN");
55
- return 1;
56
- }
57
+ l2hdr_len = eth_get_l2_hdr_length(data);
58
59
/*
60
* TODO: support vlan.
61
diff --git a/net/colo.h b/net/colo.h
62
index XXXXXXX..XXXXXXX 100644
63
--- a/net/colo.h
64
+++ b/net/colo.h
65
@@ -XXX,XX +XXX,XX @@
66
#include "qemu/jhash.h"
67
#include "qemu/timer.h"
68
#include "net/eth.h"
69
+#include "standard-headers/linux/virtio_net.h"
70
71
#define HASHTABLE_MAX_SIZE 16384
72
73
diff --git a/net/trace-events b/net/trace-events
74
index XXXXXXX..XXXXXXX 100644
75
--- a/net/trace-events
76
+++ b/net/trace-events
77
@@ -XXX,XX +XXX,XX @@ vhost_user_event(const char *chr, int event) "chr: %s got event: %d"
78
79
# colo.c
80
colo_proxy_main(const char *chr) ": %s"
81
-colo_proxy_main_vnet_info(const char *sta, int size) ": %s = %d"
82
+colo_proxy_main_vnet_info(const char *sta, uint32_t vnet_hdr, int size) ": %s pkt->vnet_hdr_len = %u, pkt->size = %d"
83
84
# colo-compare.c
85
colo_compare_main(const char *chr) ": %s"
86
--
87
2.7.4
diff view generated by jsdifflib
New patch
1
From: Zheyu Ma <zheyuma97@gmail.com>
1
2
3
The DMA engine is started by I/O access and then itself accesses the
4
I/O registers, triggering a reentrancy bug.
5
6
The following log can reveal it:
7
==5637==ERROR: AddressSanitizer: stack-overflow
8
#0 0x5595435f6078 in tulip_xmit_list_update qemu/hw/net/tulip.c:673
9
#1 0x5595435f204a in tulip_write qemu/hw/net/tulip.c:805:13
10
#2 0x559544637f86 in memory_region_write_accessor qemu/softmmu/memory.c:492:5
11
#3 0x5595446379fa in access_with_adjusted_size qemu/softmmu/memory.c:554:18
12
#4 0x5595446372fa in memory_region_dispatch_write qemu/softmmu/memory.c
13
#5 0x55954468b74c in flatview_write_continue qemu/softmmu/physmem.c:2825:23
14
#6 0x559544683662 in flatview_write qemu/softmmu/physmem.c:2867:12
15
#7 0x5595446833f3 in address_space_write qemu/softmmu/physmem.c:2963:18
16
#8 0x5595435fb082 in dma_memory_rw_relaxed qemu/include/sysemu/dma.h:87:12
17
#9 0x5595435fb082 in dma_memory_rw qemu/include/sysemu/dma.h:130:12
18
#10 0x5595435fb082 in dma_memory_write qemu/include/sysemu/dma.h:171:12
19
#11 0x5595435fb082 in stl_le_dma qemu/include/sysemu/dma.h:272:1
20
#12 0x5595435fb082 in stl_le_pci_dma qemu/include/hw/pci/pci.h:910:1
21
#13 0x5595435fb082 in tulip_desc_write qemu/hw/net/tulip.c:101:9
22
#14 0x5595435f7e3d in tulip_xmit_list_update qemu/hw/net/tulip.c:706:9
23
#15 0x5595435f204a in tulip_write qemu/hw/net/tulip.c:805:13
24
25
Fix this bug by restricting the DMA engine to memories regions.
26
27
Signed-off-by: Zheyu Ma <zheyuma97@gmail.com>
28
Signed-off-by: Jason Wang <jasowang@redhat.com>
29
---
30
hw/net/tulip.c | 4 ++--
31
1 file changed, 2 insertions(+), 2 deletions(-)
32
33
diff --git a/hw/net/tulip.c b/hw/net/tulip.c
34
index XXXXXXX..XXXXXXX 100644
35
--- a/hw/net/tulip.c
36
+++ b/hw/net/tulip.c
37
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_pci_tulip = {
38
static void tulip_desc_read(TULIPState *s, hwaddr p,
39
struct tulip_descriptor *desc)
40
{
41
- const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
42
+ const MemTxAttrs attrs = { .memory = true };
43
44
if (s->csr[0] & CSR0_DBO) {
45
ldl_be_pci_dma(&s->dev, p, &desc->status, attrs);
46
@@ -XXX,XX +XXX,XX @@ static void tulip_desc_read(TULIPState *s, hwaddr p,
47
static void tulip_desc_write(TULIPState *s, hwaddr p,
48
struct tulip_descriptor *desc)
49
{
50
- const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
51
+ const MemTxAttrs attrs = { .memory = true };
52
53
if (s->csr[0] & CSR0_DBO) {
54
stl_be_pci_dma(&s->dev, p, desc->status, attrs);
55
--
56
2.7.4
diff view generated by jsdifflib