1
The following changes since commit 03a3a62fbd0aa5227e978eef3c67d3978aec9e5f:
1
The following changes since commit 352998df1c53b366413690d95b35f76d0721ebed:
2
2
3
Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging (2023-09-07 10:29:06 -0400)
3
Merge tag 'i2c-20220314' of https://github.com/philmd/qemu into staging (2022-03-14 14:39:33 +0000)
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 049cfda145e96b2605cdf9739f1bcf9ebf3a83e1:
9
for you to fetch changes up to 12a195fa343aae2ead1301ce04727bd0ae25eb15:
10
10
11
ebpf: Updated eBPF program and skeleton. (2023-09-08 14:33:46 +0800)
11
vdpa: Expose VHOST_F_LOG_ALL on SVQ (2022-03-15 13:57:44 +0800)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
14
15
Changes since V2:
16
- fix 32bit build errros
17
15
----------------------------------------------------------------
18
----------------------------------------------------------------
16
Andrew Melnychenko (7):
19
Eugenio Pérez (14):
17
tap: Add USO support to tap device.
20
vhost: Add VhostShadowVirtqueue
18
virtio-net: Add USO flags to vhost support.
21
vhost: Add Shadow VirtQueue kick forwarding capabilities
19
ebpf: Added eBPF map update through mmap.
22
vhost: Add Shadow VirtQueue call forwarding capabilities
20
ebpf: Added eBPF initialization by fds.
23
vhost: Add vhost_svq_valid_features to shadow vq
21
virtio-net: Added property to load eBPF RSS with fds.
24
virtio: Add vhost_svq_get_vring_addr
22
qmp: Added new command to retrieve eBPF blob.
25
vdpa: adapt vhost_ops callbacks to svq
23
ebpf: Updated eBPF program and skeleton.
26
vhost: Shadow virtqueue buffers forwarding
27
util: Add iova_tree_alloc_map
28
util: add iova_tree_find_iova
29
vhost: Add VhostIOVATree
30
vdpa: Add custom IOTLB translations to SVQ
31
vdpa: Adapt vhost_vdpa_get_vring_base to SVQ
32
vdpa: Never set log_base addr if SVQ is enabled
33
vdpa: Expose VHOST_F_LOG_ALL on SVQ
24
34
25
Ilya Maximets (1):
35
Jason Wang (1):
26
net: add initial support for AF_XDP network backend
36
virtio-net: fix map leaking on error during receive
27
37
28
Tomasz Dzieciol (7):
38
hw/net/virtio-net.c | 1 +
29
igb: remove TCP ACK detection
39
hw/virtio/meson.build | 2 +-
30
igb: rename E1000E_RingInfo_st
40
hw/virtio/vhost-iova-tree.c | 110 +++++++
31
igb: RX descriptors guest writting refactoring
41
hw/virtio/vhost-iova-tree.h | 27 ++
32
igb: RX payload guest writting refactoring
42
hw/virtio/vhost-shadow-virtqueue.c | 636 +++++++++++++++++++++++++++++++++++++
33
igb: add IPv6 extended headers traffic detection
43
hw/virtio/vhost-shadow-virtqueue.h | 87 +++++
34
igb: packet-split descriptors support
44
hw/virtio/vhost-vdpa.c | 522 +++++++++++++++++++++++++++++-
35
e1000e: rename e1000e_ba_state and e1000e_write_hdr_to_rx_buffers
45
include/hw/virtio/vhost-vdpa.h | 8 +
46
include/qemu/iova-tree.h | 38 ++-
47
util/iova-tree.c | 170 ++++++++++
48
10 files changed, 1584 insertions(+), 17 deletions(-)
49
create mode 100644 hw/virtio/vhost-iova-tree.c
50
create mode 100644 hw/virtio/vhost-iova-tree.h
51
create mode 100644 hw/virtio/vhost-shadow-virtqueue.c
52
create mode 100644 hw/virtio/vhost-shadow-virtqueue.h
36
53
37
Yuri Benditovich (2):
38
tap: Add check for USO features
39
virtio-net: Add support for USO features
40
54
41
MAINTAINERS | 4 +
55
42
ebpf/ebpf.c | 70 ++
43
ebpf/ebpf.h | 31 +
44
ebpf/ebpf_rss-stub.c | 6 +
45
ebpf/ebpf_rss.c | 150 ++-
46
ebpf/ebpf_rss.h | 10 +
47
ebpf/meson.build | 2 +-
48
ebpf/rss.bpf.skeleton.h | 1460 ++++++++++++-----------
49
hmp-commands.hx | 3 +
50
hw/core/machine.c | 4 +
51
hw/net/e1000e_core.c | 80 +-
52
hw/net/igb_core.c | 732 ++++++++----
53
hw/net/igb_regs.h | 20 +-
54
hw/net/trace-events | 6 +-
55
hw/net/vhost_net.c | 3 +
56
hw/net/virtio-net.c | 90 +-
57
hw/net/vmxnet3.c | 2 +
58
include/hw/virtio/virtio-net.h | 1 +
59
include/net/net.h | 7 +-
60
meson.build | 19 +-
61
meson_options.txt | 2 +
62
net/af-xdp.c | 526 ++++++++
63
net/clients.h | 5 +
64
net/meson.build | 3 +
65
net/net.c | 19 +-
66
net/tap-bsd.c | 7 +-
67
net/tap-linux.c | 27 +-
68
net/tap-linux.h | 2 +
69
net/tap-solaris.c | 7 +-
70
net/tap-stub.c | 7 +-
71
net/tap-win32.c | 2 +-
72
net/tap.c | 18 +-
73
net/tap_int.h | 4 +-
74
net/vhost-vdpa.c | 3 +
75
qapi/ebpf.json | 66 +
76
qapi/meson.build | 1 +
77
qapi/net.json | 58 +
78
qapi/qapi-schema.json | 1 +
79
qemu-options.hx | 70 +-
80
scripts/ci/org.centos/stream/8/x86_64/configure | 1 +
81
scripts/meson-buildoptions.sh | 3 +
82
tests/docker/dockerfiles/debian-amd64.docker | 1 +
83
tests/qtest/libqos/igb.c | 5 +
84
tools/ebpf/rss.bpf.c | 5 +-
85
44 files changed, 2518 insertions(+), 1025 deletions(-)
86
create mode 100644 ebpf/ebpf.c
87
create mode 100644 ebpf/ebpf.h
88
create mode 100644 net/af-xdp.c
89
create mode 100644 qapi/ebpf.json
diff view generated by jsdifflib
Deleted patch
1
From: Andrew Melnychenko <andrew@daynix.com>
2
1
3
Passing additional parameters (USOv4 and USOv6 offloads) when
4
setting TAP offloads
5
6
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
7
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
10
hw/net/e1000e_core.c | 2 +-
11
hw/net/igb_core.c | 2 +-
12
hw/net/virtio-net.c | 4 +++-
13
hw/net/vmxnet3.c | 2 ++
14
include/net/net.h | 4 ++--
15
net/net.c | 4 ++--
16
net/tap-bsd.c | 2 +-
17
net/tap-linux.c | 15 ++++++++++++---
18
net/tap-linux.h | 2 ++
19
net/tap-solaris.c | 2 +-
20
net/tap-stub.c | 2 +-
21
net/tap-win32.c | 2 +-
22
net/tap.c | 6 +++---
23
net/tap_int.h | 3 ++-
24
14 files changed, 34 insertions(+), 18 deletions(-)
25
26
diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/hw/net/e1000e_core.c
29
+++ b/hw/net/e1000e_core.c
30
@@ -XXX,XX +XXX,XX @@ e1000e_update_rx_offloads(E1000ECore *core)
31
32
if (core->has_vnet) {
33
qemu_set_offload(qemu_get_queue(core->owner_nic)->peer,
34
- cso_state, 0, 0, 0, 0);
35
+ cso_state, 0, 0, 0, 0, 0, 0);
36
}
37
}
38
39
diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/hw/net/igb_core.c
42
+++ b/hw/net/igb_core.c
43
@@ -XXX,XX +XXX,XX @@ igb_update_rx_offloads(IGBCore *core)
44
45
if (core->has_vnet) {
46
qemu_set_offload(qemu_get_queue(core->owner_nic)->peer,
47
- cso_state, 0, 0, 0, 0);
48
+ cso_state, 0, 0, 0, 0, 0, 0);
49
}
50
}
51
52
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
53
index XXXXXXX..XXXXXXX 100644
54
--- a/hw/net/virtio-net.c
55
+++ b/hw/net/virtio-net.c
56
@@ -XXX,XX +XXX,XX @@ static void virtio_net_apply_guest_offloads(VirtIONet *n)
57
!!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_TSO4)),
58
!!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_TSO6)),
59
!!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_ECN)),
60
- !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_UFO)));
61
+ !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_UFO)),
62
+ !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_USO4)),
63
+ !!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_USO6)));
64
}
65
66
static uint64_t virtio_net_guest_offloads_by_features(uint32_t features)
67
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
68
index XXXXXXX..XXXXXXX 100644
69
--- a/hw/net/vmxnet3.c
70
+++ b/hw/net/vmxnet3.c
71
@@ -XXX,XX +XXX,XX @@ static void vmxnet3_update_features(VMXNET3State *s)
72
s->lro_supported,
73
s->lro_supported,
74
0,
75
+ 0,
76
+ 0,
77
0);
78
}
79
}
80
diff --git a/include/net/net.h b/include/net/net.h
81
index XXXXXXX..XXXXXXX 100644
82
--- a/include/net/net.h
83
+++ b/include/net/net.h
84
@@ -XXX,XX +XXX,XX @@ typedef bool (HasVnetHdr)(NetClientState *);
85
typedef bool (HasVnetHdrLen)(NetClientState *, int);
86
typedef bool (GetUsingVnetHdr)(NetClientState *);
87
typedef void (UsingVnetHdr)(NetClientState *, bool);
88
-typedef void (SetOffload)(NetClientState *, int, int, int, int, int);
89
+typedef void (SetOffload)(NetClientState *, int, int, int, int, int, int, int);
90
typedef int (GetVnetHdrLen)(NetClientState *);
91
typedef void (SetVnetHdrLen)(NetClientState *, int);
92
typedef int (SetVnetLE)(NetClientState *, bool);
93
@@ -XXX,XX +XXX,XX @@ bool qemu_has_vnet_hdr_len(NetClientState *nc, int len);
94
bool qemu_get_using_vnet_hdr(NetClientState *nc);
95
void qemu_using_vnet_hdr(NetClientState *nc, bool enable);
96
void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6,
97
- int ecn, int ufo);
98
+ int ecn, int ufo, int uso4, int uso6);
99
int qemu_get_vnet_hdr_len(NetClientState *nc);
100
void qemu_set_vnet_hdr_len(NetClientState *nc, int len);
101
int qemu_set_vnet_le(NetClientState *nc, bool is_le);
102
diff --git a/net/net.c b/net/net.c
103
index XXXXXXX..XXXXXXX 100644
104
--- a/net/net.c
105
+++ b/net/net.c
106
@@ -XXX,XX +XXX,XX @@ void qemu_using_vnet_hdr(NetClientState *nc, bool enable)
107
}
108
109
void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6,
110
- int ecn, int ufo)
111
+ int ecn, int ufo, int uso4, int uso6)
112
{
113
if (!nc || !nc->info->set_offload) {
114
return;
115
}
116
117
- nc->info->set_offload(nc, csum, tso4, tso6, ecn, ufo);
118
+ nc->info->set_offload(nc, csum, tso4, tso6, ecn, ufo, uso4, uso6);
119
}
120
121
int qemu_get_vnet_hdr_len(NetClientState *nc)
122
diff --git a/net/tap-bsd.c b/net/tap-bsd.c
123
index XXXXXXX..XXXXXXX 100644
124
--- a/net/tap-bsd.c
125
+++ b/net/tap-bsd.c
126
@@ -XXX,XX +XXX,XX @@ int tap_fd_set_vnet_be(int fd, int is_be)
127
}
128
129
void tap_fd_set_offload(int fd, int csum, int tso4,
130
- int tso6, int ecn, int ufo)
131
+ int tso6, int ecn, int ufo, int uso4, int uso6)
132
{
133
}
134
135
diff --git a/net/tap-linux.c b/net/tap-linux.c
136
index XXXXXXX..XXXXXXX 100644
137
--- a/net/tap-linux.c
138
+++ b/net/tap-linux.c
139
@@ -XXX,XX +XXX,XX @@ int tap_fd_set_vnet_be(int fd, int is_be)
140
}
141
142
void tap_fd_set_offload(int fd, int csum, int tso4,
143
- int tso6, int ecn, int ufo)
144
+ int tso6, int ecn, int ufo, int uso4, int uso6)
145
{
146
unsigned int offload = 0;
147
148
@@ -XXX,XX +XXX,XX @@ void tap_fd_set_offload(int fd, int csum, int tso4,
149
offload |= TUN_F_TSO_ECN;
150
if (ufo)
151
offload |= TUN_F_UFO;
152
+ if (uso4) {
153
+ offload |= TUN_F_USO4;
154
+ }
155
+ if (uso6) {
156
+ offload |= TUN_F_USO6;
157
+ }
158
}
159
160
if (ioctl(fd, TUNSETOFFLOAD, offload) != 0) {
161
- offload &= ~TUN_F_UFO;
162
+ offload &= ~(TUN_F_USO4 | TUN_F_USO6);
163
if (ioctl(fd, TUNSETOFFLOAD, offload) != 0) {
164
- fprintf(stderr, "TUNSETOFFLOAD ioctl() failed: %s\n",
165
+ offload &= ~TUN_F_UFO;
166
+ if (ioctl(fd, TUNSETOFFLOAD, offload) != 0) {
167
+ fprintf(stderr, "TUNSETOFFLOAD ioctl() failed: %s\n",
168
strerror(errno));
169
+ }
170
}
171
}
172
}
173
diff --git a/net/tap-linux.h b/net/tap-linux.h
174
index XXXXXXX..XXXXXXX 100644
175
--- a/net/tap-linux.h
176
+++ b/net/tap-linux.h
177
@@ -XXX,XX +XXX,XX @@
178
#define TUN_F_TSO6 0x04 /* I can handle TSO for IPv6 packets */
179
#define TUN_F_TSO_ECN 0x08 /* I can handle TSO with ECN bits. */
180
#define TUN_F_UFO 0x10 /* I can handle UFO packets */
181
+#define TUN_F_USO4 0x20 /* I can handle USO for IPv4 packets */
182
+#define TUN_F_USO6 0x40 /* I can handle USO for IPv6 packets */
183
184
#endif /* QEMU_TAP_LINUX_H */
185
diff --git a/net/tap-solaris.c b/net/tap-solaris.c
186
index XXXXXXX..XXXXXXX 100644
187
--- a/net/tap-solaris.c
188
+++ b/net/tap-solaris.c
189
@@ -XXX,XX +XXX,XX @@ int tap_fd_set_vnet_be(int fd, int is_be)
190
}
191
192
void tap_fd_set_offload(int fd, int csum, int tso4,
193
- int tso6, int ecn, int ufo)
194
+ int tso6, int ecn, int ufo, int uso4, int uso6)
195
{
196
}
197
198
diff --git a/net/tap-stub.c b/net/tap-stub.c
199
index XXXXXXX..XXXXXXX 100644
200
--- a/net/tap-stub.c
201
+++ b/net/tap-stub.c
202
@@ -XXX,XX +XXX,XX @@ int tap_fd_set_vnet_be(int fd, int is_be)
203
}
204
205
void tap_fd_set_offload(int fd, int csum, int tso4,
206
- int tso6, int ecn, int ufo)
207
+ int tso6, int ecn, int ufo, int uso4, int uso6)
208
{
209
}
210
211
diff --git a/net/tap-win32.c b/net/tap-win32.c
212
index XXXXXXX..XXXXXXX 100644
213
--- a/net/tap-win32.c
214
+++ b/net/tap-win32.c
215
@@ -XXX,XX +XXX,XX @@ static void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr)
216
}
217
218
static void tap_set_offload(NetClientState *nc, int csum, int tso4,
219
- int tso6, int ecn, int ufo)
220
+ int tso6, int ecn, int ufo, int uso4, int uso6)
221
{
222
}
223
224
diff --git a/net/tap.c b/net/tap.c
225
index XXXXXXX..XXXXXXX 100644
226
--- a/net/tap.c
227
+++ b/net/tap.c
228
@@ -XXX,XX +XXX,XX @@ static int tap_set_vnet_be(NetClientState *nc, bool is_be)
229
}
230
231
static void tap_set_offload(NetClientState *nc, int csum, int tso4,
232
- int tso6, int ecn, int ufo)
233
+ int tso6, int ecn, int ufo, int uso4, int uso6)
234
{
235
TAPState *s = DO_UPCAST(TAPState, nc, nc);
236
if (s->fd < 0) {
237
return;
238
}
239
240
- tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo);
241
+ tap_fd_set_offload(s->fd, csum, tso4, tso6, ecn, ufo, uso4, uso6);
242
}
243
244
static void tap_exit_notify(Notifier *notifier, void *data)
245
@@ -XXX,XX +XXX,XX @@ static TAPState *net_tap_fd_init(NetClientState *peer,
246
s->using_vnet_hdr = false;
247
s->has_ufo = tap_probe_has_ufo(s->fd);
248
s->enabled = true;
249
- tap_set_offload(&s->nc, 0, 0, 0, 0, 0);
250
+ tap_set_offload(&s->nc, 0, 0, 0, 0, 0, 0, 0);
251
/*
252
* Make sure host header length is set correctly in tap:
253
* it might have been modified by another instance of qemu.
254
diff --git a/net/tap_int.h b/net/tap_int.h
255
index XXXXXXX..XXXXXXX 100644
256
--- a/net/tap_int.h
257
+++ b/net/tap_int.h
258
@@ -XXX,XX +XXX,XX @@ void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp);
259
int tap_probe_vnet_hdr(int fd, Error **errp);
260
int tap_probe_vnet_hdr_len(int fd, int len);
261
int tap_probe_has_ufo(int fd);
262
-void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo);
263
+void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo,
264
+ int uso4, int uso6);
265
void tap_fd_set_vnet_hdr_len(int fd, int len);
266
int tap_fd_set_vnet_le(int fd, int vnet_is_le);
267
int tap_fd_set_vnet_be(int fd, int vnet_is_be);
268
--
269
2.7.4
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
Commit bedd7e93d0196 ("virtio-net: fix use after unmap/free for sg")
2
tries to fix the use after free of the sg by caching the virtqueue
3
elements in an array and unmap them at once after receiving the
4
packets, But it forgot to unmap the cached elements on error which
5
will lead to leaking of mapping and other unexpected results.
2
6
3
eBPF RSS program and maps may now be passed during initialization.
7
Fixing this by detaching the cached elements on error. This addresses
4
Initially was implemented for libvirt to launch qemu without permissions,
8
CVE-2022-26353.
5
and initialized eBPF program through the helper.
6
9
7
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
10
Reported-by: Victor Tom <vv474172261@gmail.com>
11
Cc: qemu-stable@nongnu.org
12
Fixes: CVE-2022-26353
13
Fixes: bedd7e93d0196 ("virtio-net: fix use after unmap/free for sg")
14
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
15
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
16
---
10
hw/net/virtio-net.c | 55 +++++++++++++++++++++++++++++++++++++-----
17
hw/net/virtio-net.c | 1 +
11
include/hw/virtio/virtio-net.h | 1 +
18
1 file changed, 1 insertion(+)
12
2 files changed, 50 insertions(+), 6 deletions(-)
13
19
14
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
20
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
15
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/net/virtio-net.c
22
--- a/hw/net/virtio-net.c
17
+++ b/hw/net/virtio-net.c
23
+++ b/hw/net/virtio-net.c
18
@@ -XXX,XX +XXX,XX @@
24
@@ -XXX,XX +XXX,XX @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
19
#include "sysemu/sysemu.h"
25
20
#include "trace.h"
26
err:
21
#include "monitor/qdev.h"
27
for (j = 0; j < i; j++) {
22
+#include "monitor/monitor.h"
28
+ virtqueue_detach_element(q->rx_vq, elems[j], lens[j]);
23
#include "hw/pci/pci_device.h"
29
g_free(elems[j]);
24
#include "net_rx_pkt.h"
25
#include "hw/virtio/vhost.h"
26
@@ -XXX,XX +XXX,XX @@ static void virtio_net_detach_epbf_rss(VirtIONet *n)
27
virtio_net_attach_ebpf_to_backend(n->nic, -1);
28
}
29
30
-static bool virtio_net_load_ebpf(VirtIONet *n)
31
+static bool virtio_net_load_ebpf_fds(VirtIONet *n, Error **errp)
32
{
33
- if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
34
- /* backend does't support steering ebpf */
35
- return false;
36
+ int fds[EBPF_RSS_MAX_FDS] = { [0 ... EBPF_RSS_MAX_FDS - 1] = -1};
37
+ int nfds = 0;
38
+ int ret = true;
39
+ int i = 0;
40
+ g_auto(GStrv) fds_strs = g_strsplit(n->ebpf_rss_fds, ":", 0);
41
+
42
+ ERRP_GUARD();
43
+
44
+ if (g_strv_length(fds_strs) != EBPF_RSS_MAX_FDS) {
45
+ error_setg(errp,
46
+ "Expected %d file descriptors but got %d",
47
+ EBPF_RSS_MAX_FDS, g_strv_length(fds_strs));
48
+ return false;
49
+ }
50
+
51
+ for (i = 0; i < nfds; i++) {
52
+ fds[i] = monitor_fd_param(monitor_cur(), fds_strs[i], errp);
53
+ if (*errp) {
54
+ ret = false;
55
+ goto exit;
56
+ }
57
+ }
58
+
59
+ ret = ebpf_rss_load_fds(&n->ebpf_rss, fds[0], fds[1], fds[2], fds[3]);
60
+
61
+exit:
62
+ if (!ret || *errp) {
63
+ for (i = 0; i < nfds && fds[i] != -1; i++) {
64
+ close(fds[i]);
65
+ }
66
}
30
}
67
31
68
- return ebpf_rss_load(&n->ebpf_rss);
69
+ return ret;
70
+}
71
+
72
+static bool virtio_net_load_ebpf(VirtIONet *n, Error **errp)
73
+{
74
+ bool ret = false;
75
+
76
+ if (virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
77
+ if (!(n->ebpf_rss_fds
78
+ && virtio_net_load_ebpf_fds(n, errp))) {
79
+ ret = ebpf_rss_load(&n->ebpf_rss);
80
+ }
81
+ }
82
+
83
+ return ret;
84
}
85
86
static void virtio_net_unload_ebpf(VirtIONet *n)
87
@@ -XXX,XX +XXX,XX @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
88
net_rx_pkt_init(&n->rx_pkt);
89
90
if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
91
- virtio_net_load_ebpf(n);
92
+ virtio_net_load_ebpf(n, errp);
93
}
94
}
95
96
@@ -XXX,XX +XXX,XX @@ static Property virtio_net_properties[] = {
97
VIRTIO_NET_F_RSS, false),
98
DEFINE_PROP_BIT64("hash", VirtIONet, host_features,
99
VIRTIO_NET_F_HASH_REPORT, false),
100
+ DEFINE_PROP_STRING("ebpf_rss_fds", VirtIONet, ebpf_rss_fds),
101
DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features,
102
VIRTIO_NET_F_RSC_EXT, false),
103
DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout,
104
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
105
index XXXXXXX..XXXXXXX 100644
106
--- a/include/hw/virtio/virtio-net.h
107
+++ b/include/hw/virtio/virtio-net.h
108
@@ -XXX,XX +XXX,XX @@ struct VirtIONet {
109
VirtioNetRssData rss_data;
110
struct NetRxPkt *rx_pkt;
111
struct EBPFRSSContext ebpf_rss;
112
+ char *ebpf_rss_fds;
113
};
114
115
size_t virtio_net_handle_ctrl_iov(VirtIODevice *vdev,
116
--
32
--
117
2.7.4
33
2.7.4
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Now, the binary objects may be retrieved by id.
3
Vhost shadow virtqueue (SVQ) is an intermediate jump for virtqueue
4
It would require for future qmp commands that may require specific
4
notifications and buffers, allowing qemu to track them. While qemu is
5
eBPF blob.
5
forwarding the buffers and virtqueue changes, it is able to commit the
6
memory it's being dirtied, the same way regular qemu's VirtIO devices
7
do.
6
8
7
Added command "request-ebpf". This command returns
9
This commit only exposes basic SVQ allocation and free. Next patches of
8
eBPF program encoded base64. The program taken from the
10
the series add functionality like notifications and buffers forwarding.
9
skeleton and essentially is an ELF object that can be
10
loaded in the future with libbpf.
11
11
12
The reason to use the command to provide the eBPF object
12
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
13
instead of a separate artifact was to avoid issues related
13
Acked-by: Michael S. Tsirkin <mst@redhat.com>
14
to finding the eBPF itself. eBPF object is an ELF binary
15
that contains the eBPF program and eBPF map description(BTF).
16
Overall, eBPF object should contain the program and enough
17
metadata to create/load eBPF with libbpf. As the eBPF
18
maps/program should correspond to QEMU, the eBPF can't
19
be used from different QEMU build.
20
21
The first solution was a helper that comes with QEMU
22
and loads appropriate eBPF objects. And the issue is
23
to find a proper helper if the system has several
24
different QEMUs installed and/or built from the source,
25
which helpers may not be compatible.
26
27
Another issue is QEMU updating while there is a running
28
QEMU instance. With an updated helper, it may not be
29
possible to hotplug virtio-net device to the already
30
running QEMU. Overall, requesting the eBPF object from
31
QEMU itself solves possible failures with acceptable effort.
32
33
Links:
34
[PATCH 3/5] qmp: Added the helper stamp check.
35
https://lore.kernel.org/all/20230219162100.174318-4-andrew@daynix.com/
36
37
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
38
Signed-off-by: Jason Wang <jasowang@redhat.com>
14
Signed-off-by: Jason Wang <jasowang@redhat.com>
39
---
15
---
40
ebpf/ebpf.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++
16
hw/virtio/meson.build | 2 +-
41
ebpf/ebpf.h | 31 +++++++++++++++++++++++
17
hw/virtio/vhost-shadow-virtqueue.c | 62 ++++++++++++++++++++++++++++++++++++++
42
ebpf/ebpf_rss.c | 6 +++++
18
hw/virtio/vhost-shadow-virtqueue.h | 28 +++++++++++++++++
43
ebpf/meson.build | 2 +-
19
3 files changed, 91 insertions(+), 1 deletion(-)
44
qapi/ebpf.json | 66 ++++++++++++++++++++++++++++++++++++++++++++++++
20
create mode 100644 hw/virtio/vhost-shadow-virtqueue.c
45
qapi/meson.build | 1 +
21
create mode 100644 hw/virtio/vhost-shadow-virtqueue.h
46
qapi/qapi-schema.json | 1 +
47
7 files changed, 176 insertions(+), 1 deletion(-)
48
create mode 100644 ebpf/ebpf.c
49
create mode 100644 ebpf/ebpf.h
50
create mode 100644 qapi/ebpf.json
51
22
52
diff --git a/ebpf/ebpf.c b/ebpf/ebpf.c
23
diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
24
index XXXXXXX..XXXXXXX 100644
25
--- a/hw/virtio/meson.build
26
+++ b/hw/virtio/meson.build
27
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c'))
28
29
virtio_ss = ss.source_set()
30
virtio_ss.add(files('virtio.c'))
31
-virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c'))
32
+virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-shadow-virtqueue.c'))
33
virtio_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user.c'))
34
virtio_ss.add(when: 'CONFIG_VHOST_VDPA', if_true: files('vhost-vdpa.c'))
35
virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c'))
36
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
53
new file mode 100644
37
new file mode 100644
54
index XXXXXXX..XXXXXXX
38
index XXXXXXX..XXXXXXX
55
--- /dev/null
39
--- /dev/null
56
+++ b/ebpf/ebpf.c
40
+++ b/hw/virtio/vhost-shadow-virtqueue.c
57
@@ -XXX,XX +XXX,XX @@
41
@@ -XXX,XX +XXX,XX @@
58
+/*
42
+/*
59
+ * QEMU eBPF binary declaration routine.
43
+ * vhost shadow virtqueue
60
+ *
44
+ *
61
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
45
+ * SPDX-FileCopyrightText: Red Hat, Inc. 2021
46
+ * SPDX-FileContributor: Author: Eugenio Pérez <eperezma@redhat.com>
62
+ *
47
+ *
63
+ * Authors:
48
+ * SPDX-License-Identifier: GPL-2.0-or-later
64
+ * Andrew Melnychenko <andrew@daynix.com>
65
+ *
66
+ * This work is licensed under the terms of the GNU GPL, version 2 or
67
+ * later. See the COPYING file in the top-level directory.
68
+ */
49
+ */
69
+
50
+
70
+#include "qemu/osdep.h"
51
+#include "qemu/osdep.h"
71
+#include "qemu/queue.h"
52
+#include "hw/virtio/vhost-shadow-virtqueue.h"
72
+#include "qapi/error.h"
73
+#include "qapi/qapi-commands-ebpf.h"
74
+#include "ebpf/ebpf.h"
75
+
53
+
76
+struct ElfBinaryDataEntry {
54
+#include "qemu/error-report.h"
77
+ int id;
78
+ const void *data;
79
+ size_t datalen;
80
+
55
+
81
+ QSLIST_ENTRY(ElfBinaryDataEntry) node;
56
+/**
82
+};
57
+ * Creates vhost shadow virtqueue, and instructs the vhost device to use the
58
+ * shadow methods and file descriptors.
59
+ *
60
+ * Returns the new virtqueue or NULL.
61
+ *
62
+ * In case of error, reason is reported through error_report.
63
+ */
64
+VhostShadowVirtqueue *vhost_svq_new(void)
65
+{
66
+ g_autofree VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1);
67
+ int r;
83
+
68
+
84
+static QSLIST_HEAD(, ElfBinaryDataEntry) ebpf_elf_obj_list =
69
+ r = event_notifier_init(&svq->hdev_kick, 0);
85
+ QSLIST_HEAD_INITIALIZER();
70
+ if (r != 0) {
86
+
71
+ error_report("Couldn't create kick event notifier: %s (%d)",
87
+void ebpf_register_binary_data(int id, const void *data, size_t datalen)
72
+ g_strerror(errno), errno);
88
+{
73
+ goto err_init_hdev_kick;
89
+ struct ElfBinaryDataEntry *dataentry = NULL;
90
+
91
+ dataentry = g_new0(struct ElfBinaryDataEntry, 1);
92
+ dataentry->data = data;
93
+ dataentry->datalen = datalen;
94
+ dataentry->id = id;
95
+
96
+ QSLIST_INSERT_HEAD(&ebpf_elf_obj_list, dataentry, node);
97
+}
98
+
99
+const void *ebpf_find_binary_by_id(int id, size_t *sz, Error **errp)
100
+{
101
+ struct ElfBinaryDataEntry *it = NULL;
102
+ QSLIST_FOREACH(it, &ebpf_elf_obj_list, node) {
103
+ if (id == it->id) {
104
+ *sz = it->datalen;
105
+ return it->data;
106
+ }
107
+ }
74
+ }
108
+
75
+
109
+ error_setg(errp, "can't find eBPF object with id: %d", id);
76
+ r = event_notifier_init(&svq->hdev_call, 0);
77
+ if (r != 0) {
78
+ error_report("Couldn't create call event notifier: %s (%d)",
79
+ g_strerror(errno), errno);
80
+ goto err_init_hdev_call;
81
+ }
110
+
82
+
83
+ return g_steal_pointer(&svq);
84
+
85
+err_init_hdev_call:
86
+ event_notifier_cleanup(&svq->hdev_kick);
87
+
88
+err_init_hdev_kick:
111
+ return NULL;
89
+ return NULL;
112
+}
90
+}
113
+
91
+
114
+EbpfObject *qmp_request_ebpf(EbpfProgramID id, Error **errp)
92
+/**
93
+ * Free the resources of the shadow virtqueue.
94
+ *
95
+ * @pvq: gpointer to SVQ so it can be used by autofree functions.
96
+ */
97
+void vhost_svq_free(gpointer pvq)
115
+{
98
+{
116
+ EbpfObject *ret = NULL;
99
+ VhostShadowVirtqueue *vq = pvq;
117
+ size_t size = 0;
100
+ event_notifier_cleanup(&vq->hdev_kick);
118
+ const void *data = ebpf_find_binary_by_id(id, &size, errp);
101
+ event_notifier_cleanup(&vq->hdev_call);
119
+ if (!data) {
102
+ g_free(vq);
120
+ return NULL;
121
+ }
122
+
123
+ ret = g_new0(EbpfObject, 1);
124
+ ret->object = g_base64_encode(data, size);
125
+
126
+ return ret;
127
+}
103
+}
128
diff --git a/ebpf/ebpf.h b/ebpf/ebpf.h
104
diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
129
new file mode 100644
105
new file mode 100644
130
index XXXXXXX..XXXXXXX
106
index XXXXXXX..XXXXXXX
131
--- /dev/null
107
--- /dev/null
132
+++ b/ebpf/ebpf.h
108
+++ b/hw/virtio/vhost-shadow-virtqueue.h
133
@@ -XXX,XX +XXX,XX @@
109
@@ -XXX,XX +XXX,XX @@
134
+/*
110
+/*
135
+ * QEMU eBPF binary declaration routine.
111
+ * vhost shadow virtqueue
136
+ *
112
+ *
137
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
113
+ * SPDX-FileCopyrightText: Red Hat, Inc. 2021
114
+ * SPDX-FileContributor: Author: Eugenio Pérez <eperezma@redhat.com>
138
+ *
115
+ *
139
+ * Authors:
116
+ * SPDX-License-Identifier: GPL-2.0-or-later
140
+ * Andrew Melnychenko <andrew@daynix.com>
141
+ *
142
+ * This work is licensed under the terms of the GNU GPL, version 2 or
143
+ * later. See the COPYING file in the top-level directory.
144
+ */
117
+ */
145
+
118
+
146
+#ifndef EBPF_H
119
+#ifndef VHOST_SHADOW_VIRTQUEUE_H
147
+#define EBPF_H
120
+#define VHOST_SHADOW_VIRTQUEUE_H
148
+
121
+
149
+struct Error;
122
+#include "qemu/event_notifier.h"
150
+
123
+
151
+void ebpf_register_binary_data(int id, const void *data,
124
+/* Shadow virtqueue to relay notifications */
152
+ size_t datalen);
125
+typedef struct VhostShadowVirtqueue {
153
+const void *ebpf_find_binary_by_id(int id, size_t *sz,
126
+ /* Shadow kick notifier, sent to vhost */
154
+ struct Error **errp);
127
+ EventNotifier hdev_kick;
128
+ /* Shadow call notifier, sent to vhost */
129
+ EventNotifier hdev_call;
130
+} VhostShadowVirtqueue;
155
+
131
+
156
+#define ebpf_binary_init(id, fn) \
132
+VhostShadowVirtqueue *vhost_svq_new(void);
157
+static void __attribute__((constructor)) ebpf_binary_init_ ## fn(void) \
158
+{ \
159
+ size_t datalen = 0; \
160
+ const void *data = fn(&datalen); \
161
+ ebpf_register_binary_data(id, data, datalen); \
162
+}
163
+
133
+
164
+#endif /* EBPF_H */
134
+void vhost_svq_free(gpointer vq);
165
diff --git a/ebpf/ebpf_rss.c b/ebpf/ebpf_rss.c
135
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostShadowVirtqueue, vhost_svq_free);
166
index XXXXXXX..XXXXXXX 100644
167
--- a/ebpf/ebpf_rss.c
168
+++ b/ebpf/ebpf_rss.c
169
@@ -XXX,XX +XXX,XX @@
170
171
#include "qemu/osdep.h"
172
#include "qemu/error-report.h"
173
+#include "qapi/qapi-types-misc.h"
174
+#include "qapi/qapi-commands-ebpf.h"
175
176
#include <bpf/libbpf.h>
177
#include <bpf/bpf.h>
178
@@ -XXX,XX +XXX,XX @@
179
180
#include "ebpf/ebpf_rss.h"
181
#include "ebpf/rss.bpf.skeleton.h"
182
+#include "ebpf/ebpf.h"
183
+
136
+
184
#include "trace.h"
137
+#endif
185
186
void ebpf_rss_init(struct EBPFRSSContext *ctx)
187
@@ -XXX,XX +XXX,XX @@ void ebpf_rss_unload(struct EBPFRSSContext *ctx)
188
ctx->map_toeplitz_key = -1;
189
ctx->map_indirections_table = -1;
190
}
191
+
192
+ebpf_binary_init(EBPF_PROGRAMID_RSS, rss_bpf__elf_bytes)
193
diff --git a/ebpf/meson.build b/ebpf/meson.build
194
index XXXXXXX..XXXXXXX 100644
195
--- a/ebpf/meson.build
196
+++ b/ebpf/meson.build
197
@@ -1 +1 @@
198
-system_ss.add(when: libbpf, if_true: files('ebpf_rss.c'), if_false: files('ebpf_rss-stub.c'))
199
+common_ss.add(when: libbpf, if_true: files('ebpf.c', 'ebpf_rss.c'), if_false: files('ebpf_rss-stub.c'))
200
diff --git a/qapi/ebpf.json b/qapi/ebpf.json
201
new file mode 100644
202
index XXXXXXX..XXXXXXX
203
--- /dev/null
204
+++ b/qapi/ebpf.json
205
@@ -XXX,XX +XXX,XX @@
206
+# -*- Mode: Python -*-
207
+# vim: filetype=python
208
+#
209
+# This work is licensed under the terms of the GNU GPL, version 2 or later.
210
+# See the COPYING file in the top-level directory.
211
+
212
+##
213
+# = eBPF Objects
214
+#
215
+# eBPF object is an ELF binary that contains the eBPF
216
+# program and eBPF map description(BTF). Overall, eBPF
217
+# object should contain the program and enough metadata
218
+# to create/load eBPF with libbpf. As the eBPF maps/program
219
+# should correspond to QEMU, the eBPF can't be used from
220
+# different QEMU build.
221
+#
222
+# Currently, there is a possible eBPF for receive-side scaling (RSS).
223
+#
224
+##
225
+
226
+##
227
+# @EbpfObject:
228
+#
229
+# An eBPF ELF object.
230
+#
231
+# @object: the eBPF object encoded in base64
232
+#
233
+# Since: 8.2
234
+##
235
+{ 'struct': 'EbpfObject',
236
+ 'data': {'object': 'str'},
237
+ 'if': 'CONFIG_EBPF' }
238
+
239
+##
240
+# @EbpfProgramID:
241
+#
242
+# The eBPF programs that can be gotten with request-ebpf.
243
+#
244
+# @rss: Receive side scaling, technology that allows steering traffic
245
+# between queues by calculation hash. Users may set up
246
+# indirection table and hash/packet types configurations. Used
247
+# with virtio-net.
248
+#
249
+# Since: 8.2
250
+##
251
+{ 'enum': 'EbpfProgramID',
252
+ 'if': 'CONFIG_EBPF',
253
+ 'data': [ { 'name': 'rss' } ] }
254
+
255
+##
256
+# @request-ebpf:
257
+#
258
+# Retrieve an eBPF object that can be loaded with libbpf. Management
259
+# applications (g.e. libvirt) may load it and pass file descriptors to
260
+# QEMU, so they can run running QEMU without BPF capabilities.
261
+#
262
+# @id: The ID of the program to return.
263
+#
264
+# Returns: eBPF object encoded in base64.
265
+#
266
+# Since: 8.2
267
+##
268
+{ 'command': 'request-ebpf',
269
+ 'data': { 'id': 'EbpfProgramID' },
270
+ 'returns': 'EbpfObject',
271
+ 'if': 'CONFIG_EBPF' }
272
diff --git a/qapi/meson.build b/qapi/meson.build
273
index XXXXXXX..XXXXXXX 100644
274
--- a/qapi/meson.build
275
+++ b/qapi/meson.build
276
@@ -XXX,XX +XXX,XX @@ qapi_all_modules = [
277
'crypto',
278
'cxl',
279
'dump',
280
+ 'ebpf',
281
'error',
282
'introspect',
283
'job',
284
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
285
index XXXXXXX..XXXXXXX 100644
286
--- a/qapi/qapi-schema.json
287
+++ b/qapi/qapi-schema.json
288
@@ -XXX,XX +XXX,XX @@
289
{ 'include': 'char.json' }
290
{ 'include': 'dump.json' }
291
{ 'include': 'net.json' }
292
+{ 'include': 'ebpf.json' }
293
{ 'include': 'rdma.json' }
294
{ 'include': 'rocker.json' }
295
{ 'include': 'tpm.json' }
296
--
138
--
297
2.7.4
139
2.7.4
140
141
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
It allows using file descriptors of eBPF provided
3
At this mode no buffer forwarding will be performed in SVQ mode: Qemu
4
outside of QEMU.
4
will just forward the guest's kicks to the device.
5
QEMU may be run without capabilities for eBPF and run
5
6
RSS program provided by management tool(g.e. libvirt).
6
Host memory notifiers regions are left out for simplicity, and they will
7
7
not be addressed in this series.
8
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
8
9
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
10
Acked-by: Michael S. Tsirkin <mst@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
---
12
---
11
ebpf/ebpf_rss-stub.c | 6 ++++++
13
hw/virtio/vhost-shadow-virtqueue.c | 55 ++++++++++++++
12
ebpf/ebpf_rss.c | 27 +++++++++++++++++++++++++++
14
hw/virtio/vhost-shadow-virtqueue.h | 14 ++++
13
ebpf/ebpf_rss.h | 5 +++++
15
hw/virtio/vhost-vdpa.c | 144 ++++++++++++++++++++++++++++++++++++-
14
3 files changed, 38 insertions(+)
16
include/hw/virtio/vhost-vdpa.h | 4 ++
15
17
4 files changed, 215 insertions(+), 2 deletions(-)
16
diff --git a/ebpf/ebpf_rss-stub.c b/ebpf/ebpf_rss-stub.c
18
19
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
17
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
18
--- a/ebpf/ebpf_rss-stub.c
21
--- a/hw/virtio/vhost-shadow-virtqueue.c
19
+++ b/ebpf/ebpf_rss-stub.c
22
+++ b/hw/virtio/vhost-shadow-virtqueue.c
20
@@ -XXX,XX +XXX,XX @@ bool ebpf_rss_load(struct EBPFRSSContext *ctx)
23
@@ -XXX,XX +XXX,XX @@
21
return false;
24
#include "hw/virtio/vhost-shadow-virtqueue.h"
22
}
25
23
26
#include "qemu/error-report.h"
24
+bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
27
+#include "qemu/main-loop.h"
25
+ int config_fd, int toeplitz_fd, int table_fd)
28
+#include "linux-headers/linux/vhost.h"
26
+{
29
+
27
+ return false;
30
+/**
28
+}
31
+ * Forward guest notifications.
29
+
32
+ *
30
bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
33
+ * @n: guest kick event notifier, the one that guest set to notify svq.
31
uint16_t *indirections_table, uint8_t *toeplitz_key)
34
+ */
32
{
35
+static void vhost_handle_guest_kick(EventNotifier *n)
33
diff --git a/ebpf/ebpf_rss.c b/ebpf/ebpf_rss.c
36
+{
37
+ VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue, svq_kick);
38
+ event_notifier_test_and_clear(n);
39
+ event_notifier_set(&svq->hdev_kick);
40
+}
41
+
42
+/**
43
+ * Set a new file descriptor for the guest to kick the SVQ and notify for avail
44
+ *
45
+ * @svq: The svq
46
+ * @svq_kick_fd: The svq kick fd
47
+ *
48
+ * Note that the SVQ will never close the old file descriptor.
49
+ */
50
+void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd)
51
+{
52
+ EventNotifier *svq_kick = &svq->svq_kick;
53
+ bool poll_stop = VHOST_FILE_UNBIND != event_notifier_get_fd(svq_kick);
54
+ bool poll_start = svq_kick_fd != VHOST_FILE_UNBIND;
55
+
56
+ if (poll_stop) {
57
+ event_notifier_set_handler(svq_kick, NULL);
58
+ }
59
+
60
+ /*
61
+ * event_notifier_set_handler already checks for guest's notifications if
62
+ * they arrive at the new file descriptor in the switch, so there is no
63
+ * need to explicitly check for them.
64
+ */
65
+ if (poll_start) {
66
+ event_notifier_init_fd(svq_kick, svq_kick_fd);
67
+ event_notifier_set(svq_kick);
68
+ event_notifier_set_handler(svq_kick, vhost_handle_guest_kick);
69
+ }
70
+}
71
+
72
+/**
73
+ * Stop the shadow virtqueue operation.
74
+ * @svq: Shadow Virtqueue
75
+ */
76
+void vhost_svq_stop(VhostShadowVirtqueue *svq)
77
+{
78
+ event_notifier_set_handler(&svq->svq_kick, NULL);
79
+}
80
81
/**
82
* Creates vhost shadow virtqueue, and instructs the vhost device to use the
83
@@ -XXX,XX +XXX,XX @@ VhostShadowVirtqueue *vhost_svq_new(void)
84
goto err_init_hdev_call;
85
}
86
87
+ event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND);
88
return g_steal_pointer(&svq);
89
90
err_init_hdev_call:
91
@@ -XXX,XX +XXX,XX @@ err_init_hdev_kick:
92
void vhost_svq_free(gpointer pvq)
93
{
94
VhostShadowVirtqueue *vq = pvq;
95
+ vhost_svq_stop(vq);
96
event_notifier_cleanup(&vq->hdev_kick);
97
event_notifier_cleanup(&vq->hdev_call);
98
g_free(vq);
99
diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
34
index XXXXXXX..XXXXXXX 100644
100
index XXXXXXX..XXXXXXX 100644
35
--- a/ebpf/ebpf_rss.c
101
--- a/hw/virtio/vhost-shadow-virtqueue.h
36
+++ b/ebpf/ebpf_rss.c
102
+++ b/hw/virtio/vhost-shadow-virtqueue.h
37
@@ -XXX,XX +XXX,XX @@ error:
103
@@ -XXX,XX +XXX,XX @@ typedef struct VhostShadowVirtqueue {
38
return false;
104
EventNotifier hdev_kick;
39
}
105
/* Shadow call notifier, sent to vhost */
40
106
EventNotifier hdev_call;
41
+bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
107
+
42
+ int config_fd, int toeplitz_fd, int table_fd)
108
+ /*
43
+{
109
+ * Borrowed virtqueue's guest to host notifier. To borrow it in this event
44
+ if (ctx == NULL || ebpf_rss_is_loaded(ctx)) {
110
+ * notifier allows to recover the VhostShadowVirtqueue from the event loop
45
+ return false;
111
+ * easily. If we use the VirtQueue's one, we don't have an easy way to
46
+ }
112
+ * retrieve VhostShadowVirtqueue.
47
+
113
+ *
48
+ if (program_fd < 0 || config_fd < 0 || toeplitz_fd < 0 || table_fd < 0) {
114
+ * So shadow virtqueue must not clean it, or we would lose VirtQueue one.
49
+ return false;
115
+ */
50
+ }
116
+ EventNotifier svq_kick;
51
+
117
} VhostShadowVirtqueue;
52
+ ctx->program_fd = program_fd;
118
53
+ ctx->map_configuration = config_fd;
119
+void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd);
54
+ ctx->map_toeplitz_key = toeplitz_fd;
120
+
55
+ ctx->map_indirections_table = table_fd;
121
+void vhost_svq_stop(VhostShadowVirtqueue *svq);
56
+
122
+
57
+ if (!ebpf_rss_mmap(ctx)) {
123
VhostShadowVirtqueue *vhost_svq_new(void);
58
+ ctx->program_fd = -1;
124
59
+ ctx->map_configuration = -1;
125
void vhost_svq_free(gpointer vq);
60
+ ctx->map_toeplitz_key = -1;
126
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
61
+ ctx->map_indirections_table = -1;
127
index XXXXXXX..XXXXXXX 100644
62
+ return false;
128
--- a/hw/virtio/vhost-vdpa.c
129
+++ b/hw/virtio/vhost-vdpa.c
130
@@ -XXX,XX +XXX,XX @@
131
#include "hw/virtio/vhost.h"
132
#include "hw/virtio/vhost-backend.h"
133
#include "hw/virtio/virtio-net.h"
134
+#include "hw/virtio/vhost-shadow-virtqueue.h"
135
#include "hw/virtio/vhost-vdpa.h"
136
#include "exec/address-spaces.h"
137
#include "qemu/main-loop.h"
138
#include "cpu.h"
139
#include "trace.h"
140
#include "qemu-common.h"
141
+#include "qapi/error.h"
142
143
/*
144
* Return one past the end of the end of section. Be careful with uint64_t
145
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_one_time_request(struct vhost_dev *dev)
146
return v->index != 0;
147
}
148
149
+static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v,
150
+ Error **errp)
151
+{
152
+ g_autoptr(GPtrArray) shadow_vqs = NULL;
153
+
154
+ if (!v->shadow_vqs_enabled) {
155
+ return 0;
156
+ }
157
+
158
+ shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free);
159
+ for (unsigned n = 0; n < hdev->nvqs; ++n) {
160
+ g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new();
161
+
162
+ if (unlikely(!svq)) {
163
+ error_setg(errp, "Cannot create svq %u", n);
164
+ return -1;
165
+ }
166
+ g_ptr_array_add(shadow_vqs, g_steal_pointer(&svq));
167
+ }
168
+
169
+ v->shadow_vqs = g_steal_pointer(&shadow_vqs);
170
+ return 0;
171
+}
172
+
173
static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp)
174
{
175
struct vhost_vdpa *v;
176
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp)
177
dev->opaque = opaque ;
178
v->listener = vhost_vdpa_memory_listener;
179
v->msg_type = VHOST_IOTLB_MSG_V2;
180
+ ret = vhost_vdpa_init_svq(dev, v, errp);
181
+ if (ret) {
182
+ goto err;
183
+ }
184
185
vhost_vdpa_get_iova_range(v);
186
187
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp)
188
VIRTIO_CONFIG_S_DRIVER);
189
190
return 0;
191
+
192
+err:
193
+ ram_block_discard_disable(false);
194
+ return ret;
195
}
196
197
static void vhost_vdpa_host_notifier_uninit(struct vhost_dev *dev,
198
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_host_notifiers_uninit(struct vhost_dev *dev, int n)
199
200
static void vhost_vdpa_host_notifiers_init(struct vhost_dev *dev)
201
{
202
+ struct vhost_vdpa *v = dev->opaque;
203
int i;
204
205
+ if (v->shadow_vqs_enabled) {
206
+ /* FIXME SVQ is not compatible with host notifiers mr */
207
+ return;
208
+ }
209
+
210
for (i = dev->vq_index; i < dev->vq_index + dev->nvqs; i++) {
211
if (vhost_vdpa_host_notifier_init(dev, i)) {
212
goto err;
213
@@ -XXX,XX +XXX,XX @@ err:
214
return;
215
}
216
217
+static void vhost_vdpa_svq_cleanup(struct vhost_dev *dev)
218
+{
219
+ struct vhost_vdpa *v = dev->opaque;
220
+ size_t idx;
221
+
222
+ if (!v->shadow_vqs) {
223
+ return;
224
+ }
225
+
226
+ for (idx = 0; idx < v->shadow_vqs->len; ++idx) {
227
+ vhost_svq_stop(g_ptr_array_index(v->shadow_vqs, idx));
228
+ }
229
+ g_ptr_array_free(v->shadow_vqs, true);
230
+}
231
+
232
static int vhost_vdpa_cleanup(struct vhost_dev *dev)
233
{
234
struct vhost_vdpa *v;
235
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_cleanup(struct vhost_dev *dev)
236
trace_vhost_vdpa_cleanup(dev, v);
237
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
238
memory_listener_unregister(&v->listener);
239
+ vhost_vdpa_svq_cleanup(dev);
240
241
dev->opaque = NULL;
242
ram_block_discard_disable(false);
243
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_get_device_id(struct vhost_dev *dev,
244
return ret;
245
}
246
247
+static void vhost_vdpa_reset_svq(struct vhost_vdpa *v)
248
+{
249
+ if (!v->shadow_vqs_enabled) {
250
+ return;
251
+ }
252
+
253
+ for (unsigned i = 0; i < v->shadow_vqs->len; ++i) {
254
+ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i);
255
+ vhost_svq_stop(svq);
256
+ }
257
+}
258
+
259
static int vhost_vdpa_reset_device(struct vhost_dev *dev)
260
{
261
+ struct vhost_vdpa *v = dev->opaque;
262
int ret;
263
uint8_t status = 0;
264
265
+ vhost_vdpa_reset_svq(v);
266
+
267
ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &status);
268
trace_vhost_vdpa_reset_device(dev, status);
269
return ret;
270
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_get_config(struct vhost_dev *dev, uint8_t *config,
271
return ret;
272
}
273
274
+static int vhost_vdpa_set_vring_dev_kick(struct vhost_dev *dev,
275
+ struct vhost_vring_file *file)
276
+{
277
+ trace_vhost_vdpa_set_vring_kick(dev, file->index, file->fd);
278
+ return vhost_vdpa_call(dev, VHOST_SET_VRING_KICK, file);
279
+}
280
+
281
+/**
282
+ * Set the shadow virtqueue descriptors to the device
283
+ *
284
+ * @dev: The vhost device model
285
+ * @svq: The shadow virtqueue
286
+ * @idx: The index of the virtqueue in the vhost device
287
+ * @errp: Error
288
+ */
289
+static bool vhost_vdpa_svq_setup(struct vhost_dev *dev,
290
+ VhostShadowVirtqueue *svq, unsigned idx,
291
+ Error **errp)
292
+{
293
+ struct vhost_vring_file file = {
294
+ .index = dev->vq_index + idx,
295
+ };
296
+ const EventNotifier *event_notifier = &svq->hdev_kick;
297
+ int r;
298
+
299
+ file.fd = event_notifier_get_fd(event_notifier);
300
+ r = vhost_vdpa_set_vring_dev_kick(dev, &file);
301
+ if (unlikely(r != 0)) {
302
+ error_setg_errno(errp, -r, "Can't set device kick fd");
303
+ }
304
+
305
+ return r == 0;
306
+}
307
+
308
+static bool vhost_vdpa_svqs_start(struct vhost_dev *dev)
309
+{
310
+ struct vhost_vdpa *v = dev->opaque;
311
+ Error *err = NULL;
312
+ unsigned i;
313
+
314
+ if (!v->shadow_vqs) {
315
+ return true;
316
+ }
317
+
318
+ for (i = 0; i < v->shadow_vqs->len; ++i) {
319
+ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i);
320
+ bool ok = vhost_vdpa_svq_setup(dev, svq, i, &err);
321
+ if (unlikely(!ok)) {
322
+ error_reportf_err(err, "Cannot setup SVQ %u: ", i);
323
+ return false;
324
+ }
63
+ }
325
+ }
64
+
326
+
65
+ return true;
327
+ return true;
66
+}
328
+}
67
+
329
+
68
static bool ebpf_rss_set_config(struct EBPFRSSContext *ctx,
330
static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
69
struct EBPFRSSConfig *config)
331
{
70
{
332
struct vhost_vdpa *v = dev->opaque;
71
diff --git a/ebpf/ebpf_rss.h b/ebpf/ebpf_rss.h
333
+ bool ok;
334
trace_vhost_vdpa_dev_start(dev, started);
335
336
if (started) {
337
vhost_vdpa_host_notifiers_init(dev);
338
+ ok = vhost_vdpa_svqs_start(dev);
339
+ if (unlikely(!ok)) {
340
+ return -1;
341
+ }
342
vhost_vdpa_set_vring_ready(dev);
343
} else {
344
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
345
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_get_vring_base(struct vhost_dev *dev,
346
static int vhost_vdpa_set_vring_kick(struct vhost_dev *dev,
347
struct vhost_vring_file *file)
348
{
349
- trace_vhost_vdpa_set_vring_kick(dev, file->index, file->fd);
350
- return vhost_vdpa_call(dev, VHOST_SET_VRING_KICK, file);
351
+ struct vhost_vdpa *v = dev->opaque;
352
+ int vdpa_idx = file->index - dev->vq_index;
353
+
354
+ if (v->shadow_vqs_enabled) {
355
+ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, vdpa_idx);
356
+ vhost_svq_set_svq_kick_fd(svq, file->fd);
357
+ return 0;
358
+ } else {
359
+ return vhost_vdpa_set_vring_dev_kick(dev, file);
360
+ }
361
}
362
363
static int vhost_vdpa_set_vring_call(struct vhost_dev *dev,
364
diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h
72
index XXXXXXX..XXXXXXX 100644
365
index XXXXXXX..XXXXXXX 100644
73
--- a/ebpf/ebpf_rss.h
366
--- a/include/hw/virtio/vhost-vdpa.h
74
+++ b/ebpf/ebpf_rss.h
367
+++ b/include/hw/virtio/vhost-vdpa.h
75
@@ -XXX,XX +XXX,XX @@
368
@@ -XXX,XX +XXX,XX @@
76
#ifndef QEMU_EBPF_RSS_H
369
#ifndef HW_VIRTIO_VHOST_VDPA_H
77
#define QEMU_EBPF_RSS_H
370
#define HW_VIRTIO_VHOST_VDPA_H
78
371
79
+#define EBPF_RSS_MAX_FDS 4
372
+#include <gmodule.h>
80
+
373
+
81
struct EBPFRSSContext {
374
#include "hw/virtio/virtio.h"
82
void *obj;
375
#include "standard-headers/linux/vhost_types.h"
83
int program_fd;
376
84
@@ -XXX,XX +XXX,XX @@ bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx);
377
@@ -XXX,XX +XXX,XX @@ typedef struct vhost_vdpa {
85
378
bool iotlb_batch_begin_sent;
86
bool ebpf_rss_load(struct EBPFRSSContext *ctx);
379
MemoryListener listener;
87
380
struct vhost_vdpa_iova_range iova_range;
88
+bool ebpf_rss_load_fds(struct EBPFRSSContext *ctx, int program_fd,
381
+ bool shadow_vqs_enabled;
89
+ int config_fd, int toeplitz_fd, int table_fd);
382
+ GPtrArray *shadow_vqs;
90
+
383
struct vhost_dev *dev;
91
bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
384
VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX];
92
uint16_t *indirections_table, uint8_t *toeplitz_key);
385
} VhostVDPA;
93
94
--
386
--
95
2.7.4
387
2.7.4
388
389
diff view generated by jsdifflib
1
From: Tomasz Dzieciol <t.dzieciol@partner.samsung.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Packet-split descriptors are used by Linux VF driver for MTU values from 2048
3
This will make qemu aware of the device used buffers, allowing it to
4
write the guest memory with its contents if needed.
4
5
5
Signed-off-by: Tomasz Dzieciol <t.dzieciol@partner.samsung.com>
6
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
6
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
7
Acked-by: Michael S. Tsirkin <mst@redhat.com>
7
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
9
---
10
hw/net/igb_core.c | 348 +++++++++++++++++++++++++++++++++++++++++++++-------
10
hw/virtio/vhost-shadow-virtqueue.c | 38 ++++++++++++++++++++++++++++++++++++++
11
hw/net/igb_regs.h | 9 ++
11
hw/virtio/vhost-shadow-virtqueue.h | 4 ++++
12
hw/net/trace-events | 2 +-
12
hw/virtio/vhost-vdpa.c | 31 +++++++++++++++++++++++++++++--
13
3 files changed, 316 insertions(+), 43 deletions(-)
13
3 files changed, 71 insertions(+), 2 deletions(-)
14
14
15
diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c
15
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
16
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/net/igb_core.c
17
--- a/hw/virtio/vhost-shadow-virtqueue.c
18
+++ b/hw/net/igb_core.c
18
+++ b/hw/virtio/vhost-shadow-virtqueue.c
19
@@ -XXX,XX +XXX,XX @@ igb_rx_use_legacy_descriptor(IGBCore *core)
19
@@ -XXX,XX +XXX,XX @@ static void vhost_handle_guest_kick(EventNotifier *n)
20
return false;
21
}
20
}
22
21
23
+typedef struct E1000ERingInfo {
22
/**
24
+ int dbah;
23
+ * Forward vhost notifications
25
+ int dbal;
24
+ *
26
+ int dlen;
25
+ * @n: hdev call event notifier, the one that device set to notify svq.
27
+ int dh;
26
+ */
28
+ int dt;
27
+static void vhost_svq_handle_call(EventNotifier *n)
29
+ int idx;
30
+} E1000ERingInfo;
31
+
32
+static uint32_t
33
+igb_rx_queue_desctyp_get(IGBCore *core, const E1000ERingInfo *r)
34
+{
28
+{
35
+ return core->mac[E1000_SRRCTL(r->idx) >> 2] & E1000_SRRCTL_DESCTYPE_MASK;
29
+ VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue,
30
+ hdev_call);
31
+ event_notifier_test_and_clear(n);
32
+ event_notifier_set(&svq->svq_call);
36
+}
33
+}
37
+
34
+
38
+static bool
35
+/**
39
+igb_rx_use_ps_descriptor(IGBCore *core, const E1000ERingInfo *r)
36
+ * Set the call notifier for the SVQ to call the guest
37
+ *
38
+ * @svq: Shadow virtqueue
39
+ * @call_fd: call notifier
40
+ *
41
+ * Called on BQL context.
42
+ */
43
+void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd)
40
+{
44
+{
41
+ uint32_t desctyp = igb_rx_queue_desctyp_get(core, r);
45
+ if (call_fd == VHOST_FILE_UNBIND) {
42
+ return desctyp == E1000_SRRCTL_DESCTYPE_HDR_SPLIT ||
46
+ /*
43
+ desctyp == E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
47
+ * Fail event_notifier_set if called handling device call.
48
+ *
49
+ * SVQ still needs device notifications, since it needs to keep
50
+ * forwarding used buffers even with the unbind.
51
+ */
52
+ memset(&svq->svq_call, 0, sizeof(svq->svq_call));
53
+ } else {
54
+ event_notifier_init_fd(&svq->svq_call, call_fd);
55
+ }
44
+}
56
+}
45
+
57
+
46
static inline bool
58
+/**
47
igb_rss_enabled(IGBCore *core)
59
* Set a new file descriptor for the guest to kick the SVQ and notify for avail
48
{
60
*
49
@@ -XXX,XX +XXX,XX @@ static uint32_t igb_rx_wb_eic(IGBCore *core, int queue_idx)
61
* @svq: The svq
50
return (ent & E1000_IVAR_VALID) ? BIT(ent & 0x1f) : 0;
62
@@ -XXX,XX +XXX,XX @@ VhostShadowVirtqueue *vhost_svq_new(void)
63
}
64
65
event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND);
66
+ event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call);
67
return g_steal_pointer(&svq);
68
69
err_init_hdev_call:
70
@@ -XXX,XX +XXX,XX @@ void vhost_svq_free(gpointer pvq)
71
VhostShadowVirtqueue *vq = pvq;
72
vhost_svq_stop(vq);
73
event_notifier_cleanup(&vq->hdev_kick);
74
+ event_notifier_set_handler(&vq->hdev_call, NULL);
75
event_notifier_cleanup(&vq->hdev_call);
76
g_free(vq);
51
}
77
}
52
78
diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
53
-typedef struct E1000ERingInfo {
79
index XXXXXXX..XXXXXXX 100644
54
- int dbah;
80
--- a/hw/virtio/vhost-shadow-virtqueue.h
55
- int dbal;
81
+++ b/hw/virtio/vhost-shadow-virtqueue.h
56
- int dlen;
82
@@ -XXX,XX +XXX,XX @@ typedef struct VhostShadowVirtqueue {
57
- int dh;
83
* So shadow virtqueue must not clean it, or we would lose VirtQueue one.
58
- int dt;
84
*/
59
- int idx;
85
EventNotifier svq_kick;
60
-} E1000ERingInfo;
86
+
61
-
87
+ /* Guest's call notifier, where the SVQ calls guest. */
62
static inline bool
88
+ EventNotifier svq_call;
63
igb_ring_empty(IGBCore *core, const E1000ERingInfo *r)
89
} VhostShadowVirtqueue;
64
{
90
65
@@ -XXX,XX +XXX,XX @@ igb_read_lgcy_rx_descr(IGBCore *core, struct e1000_rx_desc *desc,
91
void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd);
92
+void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd);
93
94
void vhost_svq_stop(VhostShadowVirtqueue *svq);
95
96
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
97
index XXXXXXX..XXXXXXX 100644
98
--- a/hw/virtio/vhost-vdpa.c
99
+++ b/hw/virtio/vhost-vdpa.c
100
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_vring_dev_kick(struct vhost_dev *dev,
101
return vhost_vdpa_call(dev, VHOST_SET_VRING_KICK, file);
66
}
102
}
67
103
68
static inline void
104
+static int vhost_vdpa_set_vring_dev_call(struct vhost_dev *dev,
69
-igb_read_adv_rx_descr(IGBCore *core, union e1000_adv_rx_desc *desc,
105
+ struct vhost_vring_file *file)
70
- hwaddr *buff_addr)
71
+igb_read_adv_rx_single_buf_descr(IGBCore *core, union e1000_adv_rx_desc *desc,
72
+ hwaddr *buff_addr)
73
{
74
*buff_addr = le64_to_cpu(desc->read.pkt_addr);
75
}
76
77
+static inline void
78
+igb_read_adv_rx_split_buf_descr(IGBCore *core, union e1000_adv_rx_desc *desc,
79
+ hwaddr *buff_addr)
80
+{
106
+{
81
+ buff_addr[0] = le64_to_cpu(desc->read.hdr_addr);
107
+ trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd);
82
+ buff_addr[1] = le64_to_cpu(desc->read.pkt_addr);
108
+ return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file);
83
+}
109
+}
84
+
110
+
85
+typedef struct IGBBAState {
111
/**
86
+ uint16_t written[IGB_MAX_PS_BUFFERS];
112
* Set the shadow virtqueue descriptors to the device
87
+ uint8_t cur_idx;
113
*
88
+} IGBBAState;
114
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_vring_dev_kick(struct vhost_dev *dev,
89
+
115
* @svq: The shadow virtqueue
90
+typedef struct IGBSplitDescriptorData {
116
* @idx: The index of the virtqueue in the vhost device
91
+ bool sph;
117
* @errp: Error
92
+ bool hbo;
118
+ *
93
+ size_t hdr_len;
119
+ * Note that this function does not rewind kick file descriptor if cannot set
94
+} IGBSplitDescriptorData;
120
+ * call one.
95
+
121
*/
96
typedef struct IGBPacketRxDMAState {
122
static bool vhost_vdpa_svq_setup(struct vhost_dev *dev,
97
size_t size;
123
VhostShadowVirtqueue *svq, unsigned idx,
98
size_t total_size;
124
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_svq_setup(struct vhost_dev *dev,
99
@@ -XXX,XX +XXX,XX @@ typedef struct IGBPacketRxDMAState {
125
r = vhost_vdpa_set_vring_dev_kick(dev, &file);
100
uint32_t rx_desc_header_buf_size;
126
if (unlikely(r != 0)) {
101
struct iovec *iov;
127
error_setg_errno(errp, -r, "Can't set device kick fd");
102
size_t iov_ofs;
103
+ bool do_ps;
104
bool is_first;
105
- uint16_t written;
106
- hwaddr ba;
107
+ IGBBAState bastate;
108
+ hwaddr ba[IGB_MAX_PS_BUFFERS];
109
+ IGBSplitDescriptorData ps_desc_data;
110
} IGBPacketRxDMAState;
111
112
static inline void
113
-igb_read_rx_descr(IGBCore *core, union e1000_rx_desc_union *desc,
114
- hwaddr *buff_addr)
115
+igb_read_rx_descr(IGBCore *core,
116
+ union e1000_rx_desc_union *desc,
117
+ IGBPacketRxDMAState *pdma_st,
118
+ const E1000ERingInfo *r)
119
{
120
+ uint32_t desc_type;
121
+
122
if (igb_rx_use_legacy_descriptor(core)) {
123
- igb_read_lgcy_rx_descr(core, &desc->legacy, buff_addr);
124
- } else {
125
- igb_read_adv_rx_descr(core, &desc->adv, buff_addr);
126
+ igb_read_lgcy_rx_descr(core, &desc->legacy, &pdma_st->ba[1]);
127
+ pdma_st->ba[0] = 0;
128
+ return;
129
+ }
130
+
131
+ /* advanced header split descriptor */
132
+ if (igb_rx_use_ps_descriptor(core, r)) {
133
+ igb_read_adv_rx_split_buf_descr(core, &desc->adv, &pdma_st->ba[0]);
134
+ return;
135
+ }
136
+
137
+ /* descriptor replication modes not supported */
138
+ desc_type = igb_rx_queue_desctyp_get(core, r);
139
+ if (desc_type != E1000_SRRCTL_DESCTYPE_ADV_ONEBUF) {
140
+ trace_igb_wrn_rx_desc_modes_not_supp(desc_type);
141
}
142
+
143
+ /* advanced single buffer descriptor */
144
+ igb_read_adv_rx_single_buf_descr(core, &desc->adv, &pdma_st->ba[1]);
145
+ pdma_st->ba[0] = 0;
146
}
147
148
static void
149
@@ -XXX,XX +XXX,XX @@ igb_write_lgcy_rx_descr(IGBCore *core, struct e1000_rx_desc *desc,
150
desc->status = (uint8_t) le32_to_cpu(status_flags);
151
}
152
153
+static bool
154
+igb_rx_ps_descriptor_split_always(IGBCore *core, const E1000ERingInfo *r)
155
+{
156
+ uint32_t desctyp = igb_rx_queue_desctyp_get(core, r);
157
+ return desctyp == E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
158
+}
159
+
160
static uint16_t
161
igb_rx_desc_get_packet_type(IGBCore *core, struct NetRxPkt *pkt, uint16_t etqf)
162
{
163
@@ -XXX,XX +XXX,XX @@ igb_write_adv_rx_descr(IGBCore *core, union e1000_adv_rx_desc *desc,
164
}
165
166
static inline void
167
-igb_write_rx_descr(IGBCore *core, union e1000_rx_desc_union *desc,
168
- struct NetRxPkt *pkt, const E1000E_RSSInfo *rss_info,
169
- uint16_t etqf, bool ts, uint16_t length)
170
+igb_write_adv_ps_rx_descr(IGBCore *core,
171
+ union e1000_adv_rx_desc *desc,
172
+ struct NetRxPkt *pkt,
173
+ const E1000E_RSSInfo *rss_info,
174
+ const E1000ERingInfo *r,
175
+ uint16_t etqf,
176
+ bool ts,
177
+ IGBPacketRxDMAState *pdma_st)
178
+{
179
+ size_t pkt_len;
180
+ uint16_t hdr_info = 0;
181
+
182
+ if (pdma_st->do_ps) {
183
+ pkt_len = pdma_st->bastate.written[1];
184
+ } else {
185
+ pkt_len = pdma_st->bastate.written[0] + pdma_st->bastate.written[1];
186
+ }
187
+
188
+ igb_write_adv_rx_descr(core, desc, pkt, rss_info, etqf, ts, pkt_len);
189
+
190
+ hdr_info = (pdma_st->ps_desc_data.hdr_len << E1000_ADVRXD_HDR_LEN_OFFSET) &
191
+ E1000_ADVRXD_ADV_HDR_LEN_MASK;
192
+ hdr_info |= pdma_st->ps_desc_data.sph ? E1000_ADVRXD_HDR_SPH : 0;
193
+ desc->wb.lower.lo_dword.hdr_info = cpu_to_le16(hdr_info);
194
+
195
+ desc->wb.upper.status_error |= cpu_to_le32(
196
+ pdma_st->ps_desc_data.hbo ? E1000_ADVRXD_ST_ERR_HBO_OFFSET : 0);
197
+}
198
+
199
+static inline void
200
+igb_write_rx_descr(IGBCore *core,
201
+ union e1000_rx_desc_union *desc,
202
+ struct NetRxPkt *pkt,
203
+ const E1000E_RSSInfo *rss_info,
204
+ uint16_t etqf,
205
+ bool ts,
206
+ IGBPacketRxDMAState *pdma_st,
207
+ const E1000ERingInfo *r)
208
{
209
if (igb_rx_use_legacy_descriptor(core)) {
210
- igb_write_lgcy_rx_descr(core, &desc->legacy, pkt, rss_info, length);
211
+ igb_write_lgcy_rx_descr(core, &desc->legacy, pkt, rss_info,
212
+ pdma_st->bastate.written[1]);
213
+ } else if (igb_rx_use_ps_descriptor(core, r)) {
214
+ igb_write_adv_ps_rx_descr(core, &desc->adv, pkt, rss_info, r, etqf, ts,
215
+ pdma_st);
216
} else {
217
igb_write_adv_rx_descr(core, &desc->adv, pkt, rss_info,
218
- etqf, ts, length);
219
+ etqf, ts, pdma_st->bastate.written[1]);
220
}
221
}
222
223
@@ -XXX,XX +XXX,XX @@ igb_rx_descr_threshold_hit(IGBCore *core, const E1000ERingInfo *rxi)
224
((core->mac[E1000_SRRCTL(rxi->idx) >> 2] >> 20) & 31) * 16;
225
}
226
227
+static bool
228
+igb_do_ps(IGBCore *core,
229
+ const E1000ERingInfo *r,
230
+ struct NetRxPkt *pkt,
231
+ IGBPacketRxDMAState *pdma_st)
232
+{
233
+ bool hasip4, hasip6;
234
+ EthL4HdrProto l4hdr_proto;
235
+ bool fragment;
236
+ bool split_always;
237
+ size_t bheader_size;
238
+ size_t total_pkt_len;
239
+
240
+ if (!igb_rx_use_ps_descriptor(core, r)) {
241
+ return false;
128
+ return false;
242
+ }
129
+ }
243
+
130
+
244
+ total_pkt_len = net_rx_pkt_get_total_len(pkt);
131
+ event_notifier = &svq->hdev_call;
245
+ bheader_size = igb_rxhdrbufsize(core, r);
132
+ file.fd = event_notifier_get_fd(event_notifier);
246
+ split_always = igb_rx_ps_descriptor_split_always(core, r);
133
+ r = vhost_vdpa_set_vring_dev_call(dev, &file);
247
+ if (split_always && total_pkt_len <= bheader_size) {
134
+ if (unlikely(r != 0)) {
248
+ pdma_st->ps_hdr_len = total_pkt_len;
135
+ error_setg_errno(errp, -r, "Can't set device call fd");
249
+ pdma_st->ps_desc_data.hdr_len = total_pkt_len;
136
}
250
+ return true;
137
251
+ }
138
return r == 0;
139
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_vring_kick(struct vhost_dev *dev,
140
static int vhost_vdpa_set_vring_call(struct vhost_dev *dev,
141
struct vhost_vring_file *file)
142
{
143
- trace_vhost_vdpa_set_vring_call(dev, file->index, file->fd);
144
- return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file);
145
+ struct vhost_vdpa *v = dev->opaque;
252
+
146
+
253
+ net_rx_pkt_get_protocols(pkt, &hasip4, &hasip6, &l4hdr_proto);
147
+ if (v->shadow_vqs_enabled) {
148
+ int vdpa_idx = file->index - dev->vq_index;
149
+ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, vdpa_idx);
254
+
150
+
255
+ if (hasip4) {
151
+ vhost_svq_set_svq_call_fd(svq, file->fd);
256
+ fragment = net_rx_pkt_get_ip4_info(pkt)->fragment;
152
+ return 0;
257
+ } else if (hasip6) {
258
+ fragment = net_rx_pkt_get_ip6_info(pkt)->fragment;
259
+ } else {
153
+ } else {
260
+ pdma_st->ps_desc_data.hdr_len = bheader_size;
154
+ return vhost_vdpa_set_vring_dev_call(dev, file);
261
+ goto header_not_handled;
262
+ }
263
+
264
+ if (fragment && (core->mac[RFCTL] & E1000_RFCTL_IPFRSP_DIS)) {
265
+ pdma_st->ps_desc_data.hdr_len = bheader_size;
266
+ goto header_not_handled;
267
+ }
268
+
269
+ /* no header splitting for SCTP */
270
+ if (!fragment && (l4hdr_proto == ETH_L4_HDR_PROTO_UDP ||
271
+ l4hdr_proto == ETH_L4_HDR_PROTO_TCP)) {
272
+ pdma_st->ps_hdr_len = net_rx_pkt_get_l5_hdr_offset(pkt);
273
+ } else {
274
+ pdma_st->ps_hdr_len = net_rx_pkt_get_l4_hdr_offset(pkt);
275
+ }
276
+
277
+ pdma_st->ps_desc_data.sph = true;
278
+ pdma_st->ps_desc_data.hdr_len = pdma_st->ps_hdr_len;
279
+
280
+ if (pdma_st->ps_hdr_len > bheader_size) {
281
+ pdma_st->ps_desc_data.hbo = true;
282
+ goto header_not_handled;
283
+ }
284
+
285
+ return true;
286
+
287
+header_not_handled:
288
+ if (split_always) {
289
+ pdma_st->ps_hdr_len = bheader_size;
290
+ return true;
291
+ }
292
+
293
+ return false;
294
+}
295
+
296
static void
297
igb_truncate_to_descriptor_size(IGBPacketRxDMAState *pdma_st, size_t *size)
298
{
299
- if (*size > pdma_st->rx_desc_packet_buf_size) {
300
- *size = pdma_st->rx_desc_packet_buf_size;
301
+ if (pdma_st->do_ps && pdma_st->is_first) {
302
+ if (*size > pdma_st->rx_desc_packet_buf_size + pdma_st->ps_hdr_len) {
303
+ *size = pdma_st->rx_desc_packet_buf_size + pdma_st->ps_hdr_len;
304
+ }
305
+ } else {
306
+ if (*size > pdma_st->rx_desc_packet_buf_size) {
307
+ *size = pdma_st->rx_desc_packet_buf_size;
308
+ }
309
+ }
310
+}
311
+
312
+static inline void
313
+igb_write_hdr_frag_to_rx_buffers(IGBCore *core,
314
+ PCIDevice *d,
315
+ IGBPacketRxDMAState *pdma_st,
316
+ const char *data,
317
+ dma_addr_t data_len)
318
+{
319
+ assert(data_len <= pdma_st->rx_desc_header_buf_size -
320
+ pdma_st->bastate.written[0]);
321
+ pci_dma_write(d,
322
+ pdma_st->ba[0] + pdma_st->bastate.written[0],
323
+ data, data_len);
324
+ pdma_st->bastate.written[0] += data_len;
325
+ pdma_st->bastate.cur_idx = 1;
326
+}
327
+
328
+static void
329
+igb_write_header_to_rx_buffers(IGBCore *core,
330
+ struct NetRxPkt *pkt,
331
+ PCIDevice *d,
332
+ IGBPacketRxDMAState *pdma_st,
333
+ size_t *copy_size)
334
+{
335
+ size_t iov_copy;
336
+ size_t ps_hdr_copied = 0;
337
+
338
+ if (!pdma_st->is_first) {
339
+ /* Leave buffer 0 of each descriptor except first */
340
+ /* empty */
341
+ pdma_st->bastate.cur_idx = 1;
342
+ return;
343
}
344
+
345
+ do {
346
+ iov_copy = MIN(pdma_st->ps_hdr_len - ps_hdr_copied,
347
+ pdma_st->iov->iov_len - pdma_st->iov_ofs);
348
+
349
+ igb_write_hdr_frag_to_rx_buffers(core, d, pdma_st,
350
+ pdma_st->iov->iov_base,
351
+ iov_copy);
352
+
353
+ *copy_size -= iov_copy;
354
+ ps_hdr_copied += iov_copy;
355
+
356
+ pdma_st->iov_ofs += iov_copy;
357
+ if (pdma_st->iov_ofs == pdma_st->iov->iov_len) {
358
+ pdma_st->iov++;
359
+ pdma_st->iov_ofs = 0;
360
+ }
361
+ } while (ps_hdr_copied < pdma_st->ps_hdr_len);
362
+
363
+ pdma_st->is_first = false;
364
}
365
366
static void
367
igb_write_payload_frag_to_rx_buffers(IGBCore *core,
368
PCIDevice *d,
369
- hwaddr ba,
370
- uint16_t *written,
371
- uint32_t cur_buf_len,
372
+ IGBPacketRxDMAState *pdma_st,
373
const char *data,
374
dma_addr_t data_len)
375
{
376
- trace_igb_rx_desc_buff_write(ba, *written, data, data_len);
377
- pci_dma_write(d, ba + *written, data, data_len);
378
- *written += data_len;
379
+ while (data_len > 0) {
380
+ assert(pdma_st->bastate.cur_idx < IGB_MAX_PS_BUFFERS);
381
+
382
+ uint32_t cur_buf_bytes_left =
383
+ pdma_st->rx_desc_packet_buf_size -
384
+ pdma_st->bastate.written[pdma_st->bastate.cur_idx];
385
+ uint32_t bytes_to_write = MIN(data_len, cur_buf_bytes_left);
386
+
387
+ trace_igb_rx_desc_buff_write(
388
+ pdma_st->bastate.cur_idx,
389
+ pdma_st->ba[pdma_st->bastate.cur_idx],
390
+ pdma_st->bastate.written[pdma_st->bastate.cur_idx],
391
+ data,
392
+ bytes_to_write);
393
+
394
+ pci_dma_write(d,
395
+ pdma_st->ba[pdma_st->bastate.cur_idx] +
396
+ pdma_st->bastate.written[pdma_st->bastate.cur_idx],
397
+ data, bytes_to_write);
398
+
399
+ pdma_st->bastate.written[pdma_st->bastate.cur_idx] += bytes_to_write;
400
+ data += bytes_to_write;
401
+ data_len -= bytes_to_write;
402
+
403
+ if (pdma_st->bastate.written[pdma_st->bastate.cur_idx] ==
404
+ pdma_st->rx_desc_packet_buf_size) {
405
+ pdma_st->bastate.cur_idx++;
406
+ }
407
+ }
155
+ }
408
}
156
}
409
157
410
static void
158
static int vhost_vdpa_get_features(struct vhost_dev *dev,
411
@@ -XXX,XX +XXX,XX @@ igb_write_payload_to_rx_buffers(IGBCore *core,
412
while (*copy_size) {
413
iov_copy = MIN(*copy_size, pdma_st->iov->iov_len - pdma_st->iov_ofs);
414
igb_write_payload_frag_to_rx_buffers(core, d,
415
- pdma_st->ba,
416
- &pdma_st->written,
417
- pdma_st->rx_desc_packet_buf_size,
418
+ pdma_st,
419
pdma_st->iov->iov_base +
420
pdma_st->iov_ofs,
421
iov_copy);
422
@@ -XXX,XX +XXX,XX @@ igb_write_payload_to_rx_buffers(IGBCore *core,
423
if (pdma_st->desc_offset + pdma_st->desc_size >= pdma_st->total_size) {
424
/* Simulate FCS checksum presence in the last descriptor */
425
igb_write_payload_frag_to_rx_buffers(core, d,
426
- pdma_st->ba,
427
- &pdma_st->written,
428
- pdma_st->rx_desc_packet_buf_size,
429
+ pdma_st,
430
(const char *) &fcs_pad,
431
e1000x_fcs_len(core->mac));
432
}
433
@@ -XXX,XX +XXX,XX @@ igb_write_to_rx_buffers(IGBCore *core,
434
{
435
size_t copy_size;
436
437
- if (!pdma_st->ba) {
438
+ if (!(pdma_st->ba)[1] || (pdma_st->do_ps && !(pdma_st->ba[0]))) {
439
/* as per intel docs; skip descriptors with null buf addr */
440
trace_e1000e_rx_null_descriptor();
441
return;
442
@@ -XXX,XX +XXX,XX @@ igb_write_to_rx_buffers(IGBCore *core,
443
igb_truncate_to_descriptor_size(pdma_st, &pdma_st->desc_size);
444
copy_size = pdma_st->size - pdma_st->desc_offset;
445
igb_truncate_to_descriptor_size(pdma_st, &copy_size);
446
+
447
+ /* For PS mode copy the packet header first */
448
+ if (pdma_st->do_ps) {
449
+ igb_write_header_to_rx_buffers(core, pkt, d, pdma_st, &copy_size);
450
+ } else {
451
+ pdma_st->bastate.cur_idx = 1;
452
+ }
453
+
454
igb_write_payload_to_rx_buffers(core, pkt, d, pdma_st, &copy_size);
455
}
456
457
@@ -XXX,XX +XXX,XX @@ igb_write_packet_to_guest(IGBCore *core, struct NetRxPkt *pkt,
458
d = core->owner;
459
}
460
461
+ pdma_st.do_ps = igb_do_ps(core, rxi, pkt, &pdma_st);
462
+
463
do {
464
- pdma_st.written = 0;
465
+ memset(&pdma_st.bastate, 0, sizeof(IGBBAState));
466
bool is_last = false;
467
468
if (igb_ring_empty(core, rxi)) {
469
@@ -XXX,XX +XXX,XX @@ igb_write_packet_to_guest(IGBCore *core, struct NetRxPkt *pkt,
470
pci_dma_read(d, base, &desc, rx_desc_len);
471
trace_e1000e_rx_descr(rxi->idx, base, rx_desc_len);
472
473
- igb_read_rx_descr(core, &desc, &pdma_st.ba);
474
+ igb_read_rx_descr(core, &desc, &pdma_st, rxi);
475
476
igb_write_to_rx_buffers(core, pkt, d, &pdma_st);
477
pdma_st.desc_offset += pdma_st.desc_size;
478
@@ -XXX,XX +XXX,XX @@ igb_write_packet_to_guest(IGBCore *core, struct NetRxPkt *pkt,
479
is_last = true;
480
}
481
482
- igb_write_rx_descr(core, &desc, is_last ? core->rx_pkt : NULL,
483
- rss_info, etqf, ts, pdma_st.written);
484
+ igb_write_rx_descr(core, &desc,
485
+ is_last ? pkt : NULL,
486
+ rss_info,
487
+ etqf, ts,
488
+ &pdma_st,
489
+ rxi);
490
igb_pci_dma_write_rx_desc(core, d, base, &desc, rx_desc_len);
491
igb_ring_advance(core, rxi, rx_desc_len / E1000_MIN_RX_DESC_LEN);
492
} while (pdma_st.desc_offset < pdma_st.total_size);
493
diff --git a/hw/net/igb_regs.h b/hw/net/igb_regs.h
494
index XXXXXXX..XXXXXXX 100644
495
--- a/hw/net/igb_regs.h
496
+++ b/hw/net/igb_regs.h
497
@@ -XXX,XX +XXX,XX @@ union e1000_adv_rx_desc {
498
#define E1000_SRRCTL_BSIZEHDRSIZE_MASK 0x00000F00
499
#define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT 2 /* Shift _left_ */
500
#define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000
501
+#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000
502
#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000
503
#define E1000_SRRCTL_DESCTYPE_MASK 0x0E000000
504
#define E1000_SRRCTL_DROP_EN 0x80000000
505
@@ -XXX,XX +XXX,XX @@ union e1000_adv_rx_desc {
506
#define E1000_ADVRXD_PKT_UDP BIT(5)
507
#define E1000_ADVRXD_PKT_SCTP BIT(6)
508
509
+#define IGB_MAX_PS_BUFFERS 2
510
+
511
+#define E1000_ADVRXD_HDR_LEN_OFFSET (21 - 16)
512
+#define E1000_ADVRXD_ADV_HDR_LEN_MASK ((BIT(10) - 1) << \
513
+ E1000_ADVRXD_HDR_LEN_OFFSET)
514
+#define E1000_ADVRXD_HDR_SPH BIT(15)
515
+#define E1000_ADVRXD_ST_ERR_HBO_OFFSET BIT(3 + 20)
516
+
517
static inline uint8_t igb_ivar_entry_rx(uint8_t i)
518
{
519
return i < 8 ? i * 4 : (i - 8) * 4 + 2;
520
diff --git a/hw/net/trace-events b/hw/net/trace-events
521
index XXXXXXX..XXXXXXX 100644
522
--- a/hw/net/trace-events
523
+++ b/hw/net/trace-events
524
@@ -XXX,XX +XXX,XX @@ igb_core_mdic_write_unhandled(uint32_t addr) "MDIC WRITE: PHY[%u] UNHANDLED"
525
igb_link_set_ext_params(bool asd_check, bool speed_select_bypass, bool pfrstd) "Set extended link params: ASD check: %d, Speed select bypass: %d, PF reset done: %d"
526
527
igb_rx_desc_buff_size(uint32_t b) "buffer size: %u"
528
-igb_rx_desc_buff_write(uint64_t addr, uint16_t offset, const void* source, uint32_t len) "addr: 0x%"PRIx64", offset: %u, from: %p, length: %u"
529
+igb_rx_desc_buff_write(uint8_t idx, uint64_t addr, uint16_t offset, const void* source, uint32_t len) "buffer %u, addr: 0x%"PRIx64", offset: %u, from: %p, length: %u"
530
531
igb_rx_metadata_rss(uint32_t rss, uint16_t rss_pkt_type) "RSS data: rss: 0x%X, rss_pkt_type: 0x%X"
532
533
--
159
--
534
2.7.4
160
2.7.4
161
162
diff view generated by jsdifflib
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
USO features of virtio-net device depend on kernel ability
3
This allows SVQ to negotiate features with the guest and the device. For
4
to support them, for backward compatibility by default the
4
the device, SVQ is a driver. While this function bypasses all
5
features are disabled on 8.0 and earlier.
5
non-transport features, it needs to disable the features that SVQ does
6
not support when forwarding buffers. This includes packed vq layout,
7
indirect descriptors or event idx.
6
8
7
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
9
Future changes can add support to offer more features to the guest,
8
Signed-off-by: Andrew Melnychecnko <andrew@daynix.com>
10
since the use of VirtQueue gives this for free. This is left out at the
11
moment for simplicity.
12
13
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
14
Acked-by: Michael S. Tsirkin <mst@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
15
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
---
16
---
11
hw/core/machine.c | 4 ++++
17
hw/virtio/vhost-shadow-virtqueue.c | 44 ++++++++++++++++++++++++++++++++++++++
12
hw/net/virtio-net.c | 31 +++++++++++++++++++++++++++++--
18
hw/virtio/vhost-shadow-virtqueue.h | 2 ++
13
2 files changed, 33 insertions(+), 2 deletions(-)
19
hw/virtio/vhost-vdpa.c | 15 +++++++++++++
20
3 files changed, 61 insertions(+)
14
21
15
diff --git a/hw/core/machine.c b/hw/core/machine.c
22
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
16
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/core/machine.c
24
--- a/hw/virtio/vhost-shadow-virtqueue.c
18
+++ b/hw/core/machine.c
25
+++ b/hw/virtio/vhost-shadow-virtqueue.c
19
@@ -XXX,XX +XXX,XX @@
26
@@ -XXX,XX +XXX,XX @@
20
#include "exec/confidential-guest-support.h"
27
#include "hw/virtio/vhost-shadow-virtqueue.h"
21
#include "hw/virtio/virtio.h"
28
22
#include "hw/virtio/virtio-pci.h"
29
#include "qemu/error-report.h"
23
+#include "hw/virtio/virtio-net.h"
30
+#include "qapi/error.h"
24
31
#include "qemu/main-loop.h"
25
GlobalProperty hw_compat_8_1[] = {};
32
#include "linux-headers/linux/vhost.h"
26
const size_t hw_compat_8_1_len = G_N_ELEMENTS(hw_compat_8_1);
33
27
@@ -XXX,XX +XXX,XX @@ const size_t hw_compat_8_1_len = G_N_ELEMENTS(hw_compat_8_1);
34
/**
28
GlobalProperty hw_compat_8_0[] = {
35
+ * Validate the transport device features that both guests can use with the SVQ
29
{ "migration", "multifd-flush-after-each-section", "on"},
36
+ * and SVQs can use with the device.
30
{ TYPE_PCI_DEVICE, "x-pcie-ari-nextfn-1", "on" },
37
+ *
31
+ { TYPE_VIRTIO_NET, "host_uso", "off"},
38
+ * @dev_features: The features
32
+ { TYPE_VIRTIO_NET, "guest_uso4", "off"},
39
+ * @errp: Error pointer
33
+ { TYPE_VIRTIO_NET, "guest_uso6", "off"},
40
+ */
34
};
41
+bool vhost_svq_valid_features(uint64_t features, Error **errp)
35
const size_t hw_compat_8_0_len = G_N_ELEMENTS(hw_compat_8_0);
36
37
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
38
index XXXXXXX..XXXXXXX 100644
39
--- a/hw/net/virtio-net.c
40
+++ b/hw/net/virtio-net.c
41
@@ -XXX,XX +XXX,XX @@ static int peer_has_ufo(VirtIONet *n)
42
return n->has_ufo;
43
}
44
45
+static int peer_has_uso(VirtIONet *n)
46
+{
42
+{
47
+ if (!peer_has_vnet_hdr(n)) {
43
+ bool ok = true;
48
+ return 0;
44
+ uint64_t svq_features = features;
45
+
46
+ for (uint64_t b = VIRTIO_TRANSPORT_F_START; b <= VIRTIO_TRANSPORT_F_END;
47
+ ++b) {
48
+ switch (b) {
49
+ case VIRTIO_F_ANY_LAYOUT:
50
+ continue;
51
+
52
+ case VIRTIO_F_ACCESS_PLATFORM:
53
+ /* SVQ trust in the host's IOMMU to translate addresses */
54
+ case VIRTIO_F_VERSION_1:
55
+ /* SVQ trust that the guest vring is little endian */
56
+ if (!(svq_features & BIT_ULL(b))) {
57
+ svq_features |= BIT_ULL(b);
58
+ ok = false;
59
+ }
60
+ continue;
61
+
62
+ default:
63
+ if (svq_features & BIT_ULL(b)) {
64
+ svq_features &= ~BIT_ULL(b);
65
+ ok = false;
66
+ }
67
+ }
49
+ }
68
+ }
50
+
69
+
51
+ return qemu_has_uso(qemu_get_queue(n->nic)->peer);
70
+ if (!ok) {
71
+ error_setg(errp, "SVQ Invalid device feature flags, offer: 0x%"PRIx64
72
+ ", ok: 0x%"PRIx64, features, svq_features);
73
+ }
74
+ return ok;
52
+}
75
+}
53
+
76
+
54
static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs,
77
+/**
55
int version_1, int hash_report)
78
* Forward guest notifications.
79
*
80
* @n: guest kick event notifier, the one that guest set to notify svq.
81
diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
82
index XXXXXXX..XXXXXXX 100644
83
--- a/hw/virtio/vhost-shadow-virtqueue.h
84
+++ b/hw/virtio/vhost-shadow-virtqueue.h
85
@@ -XXX,XX +XXX,XX @@ typedef struct VhostShadowVirtqueue {
86
EventNotifier svq_call;
87
} VhostShadowVirtqueue;
88
89
+bool vhost_svq_valid_features(uint64_t features, Error **errp);
90
+
91
void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd);
92
void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd);
93
94
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
95
index XXXXXXX..XXXXXXX 100644
96
--- a/hw/virtio/vhost-vdpa.c
97
+++ b/hw/virtio/vhost-vdpa.c
98
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v,
99
Error **errp)
56
{
100
{
57
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
101
g_autoptr(GPtrArray) shadow_vqs = NULL;
58
virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO6);
102
+ uint64_t dev_features, svq_features;
59
virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_ECN);
103
+ int r;
60
104
+ bool ok;
61
+ virtio_clear_feature(&features, VIRTIO_NET_F_HOST_USO);
105
62
+ virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO4);
106
if (!v->shadow_vqs_enabled) {
63
+ virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO6);
107
return 0;
64
+
65
virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT);
66
}
108
}
67
109
68
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
110
+ r = hdev->vhost_ops->vhost_get_features(hdev, &dev_features);
69
virtio_clear_feature(&features, VIRTIO_NET_F_HOST_UFO);
111
+ if (r != 0) {
70
}
112
+ error_setg_errno(errp, -r, "Can't get vdpa device features");
71
113
+ return r;
72
+ if (!peer_has_uso(n)) {
73
+ virtio_clear_feature(&features, VIRTIO_NET_F_HOST_USO);
74
+ virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO4);
75
+ virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_USO6);
76
+ }
114
+ }
77
+
115
+
78
if (!get_vhost_net(nc->peer)) {
116
+ svq_features = dev_features;
79
return features;
117
+ ok = vhost_svq_valid_features(svq_features, errp);
80
}
118
+ if (unlikely(!ok)) {
81
@@ -XXX,XX +XXX,XX @@ static void virtio_net_apply_guest_offloads(VirtIONet *n)
119
+ return -1;
82
!!(n->curr_guest_offloads & (1ULL << VIRTIO_NET_F_GUEST_USO6)));
120
+ }
83
}
121
+
84
122
shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free);
85
-static uint64_t virtio_net_guest_offloads_by_features(uint32_t features)
123
for (unsigned n = 0; n < hdev->nvqs; ++n) {
86
+static uint64_t virtio_net_guest_offloads_by_features(uint64_t features)
124
g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new();
87
{
88
static const uint64_t guest_offloads_mask =
89
(1ULL << VIRTIO_NET_F_GUEST_CSUM) |
90
(1ULL << VIRTIO_NET_F_GUEST_TSO4) |
91
(1ULL << VIRTIO_NET_F_GUEST_TSO6) |
92
(1ULL << VIRTIO_NET_F_GUEST_ECN) |
93
- (1ULL << VIRTIO_NET_F_GUEST_UFO);
94
+ (1ULL << VIRTIO_NET_F_GUEST_UFO) |
95
+ (1ULL << VIRTIO_NET_F_GUEST_USO4) |
96
+ (1ULL << VIRTIO_NET_F_GUEST_USO6);
97
98
return guest_offloads_mask & features;
99
}
100
@@ -XXX,XX +XXX,XX @@ static Property virtio_net_properties[] = {
101
DEFINE_PROP_INT32("speed", VirtIONet, net_conf.speed, SPEED_UNKNOWN),
102
DEFINE_PROP_STRING("duplex", VirtIONet, net_conf.duplex_str),
103
DEFINE_PROP_BOOL("failover", VirtIONet, failover, false),
104
+ DEFINE_PROP_BIT64("guest_uso4", VirtIONet, host_features,
105
+ VIRTIO_NET_F_GUEST_USO4, true),
106
+ DEFINE_PROP_BIT64("guest_uso6", VirtIONet, host_features,
107
+ VIRTIO_NET_F_GUEST_USO6, true),
108
+ DEFINE_PROP_BIT64("host_uso", VirtIONet, host_features,
109
+ VIRTIO_NET_F_HOST_USO, true),
110
DEFINE_PROP_END_OF_LIST(),
111
};
112
113
--
125
--
114
2.7.4
126
2.7.4
127
128
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Updated section name, so libbpf should init/gues proper
3
It reports the shadow virtqueue address from qemu virtual address space.
4
program type without specifications during open/load.
5
Also, added map_flags with explicitly declared BPF_F_MMAPABLE.
6
Added check for BPF_F_MMAPABLE flag to meson script and
7
requirements to libbpf version.
8
4
9
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
5
Since this will be different from the guest's vaddr, but the device can
6
access it, SVQ takes special care about its alignment & lack of garbage
7
data. It assumes that IOMMU will work in host_page_size ranges for that.
8
9
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
10
Acked-by: Michael S. Tsirkin <mst@redhat.com>
10
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
---
12
---
12
ebpf/rss.bpf.skeleton.h | 1460 ++++++++++++++++++++++++-----------------------
13
hw/virtio/vhost-shadow-virtqueue.c | 29 +++++++++++++++++++++++++++++
13
meson.build | 10 +-
14
hw/virtio/vhost-shadow-virtqueue.h | 9 +++++++++
14
tools/ebpf/rss.bpf.c | 5 +-
15
2 files changed, 38 insertions(+)
15
3 files changed, 748 insertions(+), 727 deletions(-)
16
16
17
diff --git a/ebpf/rss.bpf.skeleton.h b/ebpf/rss.bpf.skeleton.h
17
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
18
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
19
--- a/ebpf/rss.bpf.skeleton.h
19
--- a/hw/virtio/vhost-shadow-virtqueue.c
20
+++ b/ebpf/rss.bpf.skeleton.h
20
+++ b/hw/virtio/vhost-shadow-virtqueue.c
21
@@ -XXX,XX +XXX,XX @@ err:
21
@@ -XXX,XX +XXX,XX @@ void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd)
22
23
static inline const void *rss_bpf__elf_bytes(size_t *sz)
24
{
25
-    *sz = 20440;
26
+    *sz = 20824;
27
    return (const void *)"\
28
\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\
29
-\0\0\0\0\0\0\0\0\0\0\0\x98\x4c\0\0\0\0\0\0\0\0\0\0\x40\0\0\0\0\0\x40\0\x0d\0\
30
-\x01\0\xbf\x19\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\x54\xff\0\0\0\0\xbf\xa7\
31
-\0\0\0\0\0\0\x07\x07\0\0\x54\xff\xff\xff\x18\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
32
+\0\0\0\0\0\0\0\0\0\0\0\x18\x4e\0\0\0\0\0\0\0\0\0\0\x40\0\0\0\0\0\x40\0\x0d\0\
33
+\x01\0\xbf\x19\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\x4c\xff\0\0\0\0\xbf\xa7\
34
+\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\
35
\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\
36
\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\x08\0\0\0\0\0\0\
37
-\x18\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0\x15\x06\x67\x02\0\0\0\0\xbf\x87\0\0\
38
-\0\0\0\0\x15\x07\x65\x02\0\0\0\0\x71\x61\0\0\0\0\0\0\x55\x01\x01\0\0\0\0\0\x05\
39
-\0\x5e\x02\0\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\xc8\xff\0\0\0\0\x7b\x1a\xc0\xff\
40
-\0\0\0\0\x7b\x1a\xb8\xff\0\0\0\0\x7b\x1a\xb0\xff\0\0\0\0\x7b\x1a\xa8\xff\0\0\0\
41
-\0\x63\x1a\xa0\xff\0\0\0\0\x7b\x1a\x98\xff\0\0\0\0\x7b\x1a\x90\xff\0\0\0\0\x7b\
42
-\x1a\x88\xff\0\0\0\0\x7b\x1a\x80\xff\0\0\0\0\x7b\x1a\x78\xff\0\0\0\0\x7b\x1a\
43
-\x70\xff\0\0\0\0\x7b\x1a\x68\xff\0\0\0\0\x7b\x1a\x60\xff\0\0\0\0\x7b\x1a\x58\
44
-\xff\0\0\0\0\x15\x09\x4d\x02\0\0\0\0\x6b\x1a\xd0\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\
45
-\0\x07\x03\0\0\xd0\xff\xff\xff\xbf\x91\0\0\0\0\0\0\xb7\x02\0\0\x0c\0\0\0\xb7\
46
+\x18\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0\x15\x06\x64\x02\0\0\0\0\xbf\x87\0\0\
47
+\0\0\0\0\x15\x07\x62\x02\0\0\0\0\x71\x61\0\0\0\0\0\0\x55\x01\x01\0\0\0\0\0\x05\
48
+\0\x5b\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\
49
+\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\
50
+\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\
51
+\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\
52
+\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\
53
+\xff\0\0\0\0\x15\x09\x4a\x02\0\0\0\0\x6b\x1a\xc8\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\
54
+\0\x07\x03\0\0\xc8\xff\xff\xff\xbf\x91\0\0\0\0\0\0\xb7\x02\0\0\x0c\0\0\0\xb7\
55
\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\
56
-\x77\0\0\0\x20\0\0\0\x55\0\x42\x02\0\0\0\0\xb7\x02\0\0\x10\0\0\0\x69\xa1\xd0\
57
+\x77\0\0\0\x20\0\0\0\x55\0\x3f\x02\0\0\0\0\xb7\x02\0\0\x10\0\0\0\x69\xa1\xc8\
58
\xff\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\
59
\x55\x03\x0b\0\xa8\x88\0\0\xb7\x02\0\0\x14\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\
60
-\0\xd0\xff\xff\xff\xbf\x91\0\0\0\0\0\0\xb7\x04\0\0\x02\0\0\0\xb7\x05\0\0\0\0\0\
61
-\0\x85\0\0\0\x44\0\0\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x55\0\x32\x02\0\
62
-\0\0\0\x69\xa1\xd0\xff\0\0\0\0\x15\x01\x30\x02\0\0\0\0\x7b\x7a\x38\xff\0\0\0\0\
63
-\x7b\x9a\x40\xff\0\0\0\0\x15\x01\x55\0\x86\xdd\0\0\x55\x01\x39\0\x08\0\0\0\xb7\
64
-\x07\0\0\x01\0\0\0\x73\x7a\x58\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\xe0\xff\
65
-\0\0\0\0\x7b\x1a\xd8\xff\0\0\0\0\x7b\x1a\xd0\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\0\
66
-\x07\x03\0\0\xd0\xff\xff\xff\x79\xa1\x40\xff\0\0\0\0\xb7\x02\0\0\0\0\0\0\xb7\
67
+\0\xc8\xff\xff\xff\xbf\x91\0\0\0\0\0\0\xb7\x04\0\0\x02\0\0\0\xb7\x05\0\0\0\0\0\
68
+\0\x85\0\0\0\x44\0\0\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x55\0\x2f\x02\0\
69
+\0\0\0\x69\xa1\xc8\xff\0\0\0\0\x15\x01\x2d\x02\0\0\0\0\x7b\x7a\x30\xff\0\0\0\0\
70
+\x7b\x9a\x38\xff\0\0\0\0\x15\x01\x55\0\x86\xdd\0\0\x55\x01\x39\0\x08\0\0\0\xb7\
71
+\x07\0\0\x01\0\0\0\x73\x7a\x50\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\xd8\xff\
72
+\0\0\0\0\x7b\x1a\xd0\xff\0\0\0\0\x7b\x1a\xc8\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\0\
73
+\x07\x03\0\0\xc8\xff\xff\xff\x79\xa1\x38\xff\0\0\0\0\xb7\x02\0\0\0\0\0\0\xb7\
74
\x04\0\0\x14\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\
75
-\0\x77\0\0\0\x20\0\0\0\x55\0\x1c\x02\0\0\0\0\x69\xa1\xd6\xff\0\0\0\0\x55\x01\
76
-\x01\0\0\0\0\0\xb7\x07\0\0\0\0\0\0\x61\xa1\xdc\xff\0\0\0\0\x63\x1a\x64\xff\0\0\
77
-\0\0\x61\xa1\xe0\xff\0\0\0\0\x63\x1a\x68\xff\0\0\0\0\x71\xa9\xd9\xff\0\0\0\0\
78
-\x73\x7a\x5e\xff\0\0\0\0\x71\xa1\xd0\xff\0\0\0\0\x67\x01\0\0\x02\0\0\0\x57\x01\
79
-\0\0\x3c\0\0\0\x7b\x1a\x48\xff\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\xff\0\0\
80
+\0\x77\0\0\0\x20\0\0\0\x55\0\x19\x02\0\0\0\0\x69\xa1\xce\xff\0\0\0\0\x55\x01\
81
+\x01\0\0\0\0\0\xb7\x07\0\0\0\0\0\0\x61\xa1\xd4\xff\0\0\0\0\x63\x1a\x5c\xff\0\0\
82
+\0\0\x61\xa1\xd8\xff\0\0\0\0\x63\x1a\x60\xff\0\0\0\0\x71\xa9\xd1\xff\0\0\0\0\
83
+\x73\x7a\x56\xff\0\0\0\0\x71\xa1\xc8\xff\0\0\0\0\x67\x01\0\0\x02\0\0\0\x57\x01\
84
+\0\0\x3c\0\0\0\x7b\x1a\x40\xff\0\0\0\0\xbf\x91\0\0\0\0\0\0\x57\x01\0\0\xff\0\0\
85
\0\x15\x01\x19\0\0\0\0\0\x57\x07\0\0\xff\0\0\0\x55\x07\x17\0\0\0\0\0\x57\x09\0\
86
\0\xff\0\0\0\x15\x09\x5a\x01\x11\0\0\0\x55\x09\x14\0\x06\0\0\0\xb7\x01\0\0\x01\
87
-\0\0\0\x73\x1a\x5b\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\xe0\xff\0\0\0\0\x7b\
88
-\x1a\xd8\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\
89
-\xd0\xff\xff\xff\x79\xa1\x40\xff\0\0\0\0\x79\xa2\x48\xff\0\0\0\0\xb7\x04\0\0\
90
+\0\0\0\x73\x1a\x53\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\xd8\xff\0\0\0\0\x7b\
91
+\x1a\xd0\xff\0\0\0\0\x7b\x1a\xc8\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\
92
+\xc8\xff\xff\xff\x79\xa1\x38\xff\0\0\0\0\x79\xa2\x40\xff\0\0\0\0\xb7\x04\0\0\
93
\x14\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\0\
94
-\0\0\x20\0\0\0\x55\0\xf7\x01\0\0\0\0\x69\xa1\xd0\xff\0\0\0\0\x6b\x1a\x60\xff\0\
95
-\0\0\0\x69\xa1\xd2\xff\0\0\0\0\x6b\x1a\x62\xff\0\0\0\0\x71\xa1\x58\xff\0\0\0\0\
96
+\0\0\x20\0\0\0\x55\0\xf4\x01\0\0\0\0\x69\xa1\xc8\xff\0\0\0\0\x6b\x1a\x58\xff\0\
97
+\0\0\0\x69\xa1\xca\xff\0\0\0\0\x6b\x1a\x5a\xff\0\0\0\0\x71\xa1\x50\xff\0\0\0\0\
98
\x15\x01\xdb\0\0\0\0\0\x71\x62\x03\0\0\0\0\0\x67\x02\0\0\x08\0\0\0\x71\x61\x02\
99
\0\0\0\0\0\x4f\x12\0\0\0\0\0\0\x71\x63\x04\0\0\0\0\0\x71\x61\x05\0\0\0\0\0\x67\
100
\x01\0\0\x08\0\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\
101
-\0\x71\xa2\x5b\xff\0\0\0\0\x79\xa0\x38\xff\0\0\0\0\x15\x02\x0c\x01\0\0\0\0\xbf\
102
-\x12\0\0\0\0\0\0\x57\x02\0\0\x02\0\0\0\x15\x02\x09\x01\0\0\0\0\x61\xa1\x64\xff\
103
-\0\0\0\0\x63\x1a\xa8\xff\0\0\0\0\x61\xa1\x68\xff\0\0\0\0\x63\x1a\xac\xff\0\0\0\
104
-\0\x69\xa1\x60\xff\0\0\0\0\x6b\x1a\xb0\xff\0\0\0\0\x69\xa1\x62\xff\0\0\0\0\x6b\
105
-\x1a\xb2\xff\0\0\0\0\x05\0\x6b\x01\0\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x59\
106
-\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x7b\x1a\xf0\xff\0\0\0\0\x7b\x1a\xe8\xff\0\0\0\
107
-\0\x7b\x1a\xe0\xff\0\0\0\0\x7b\x1a\xd8\xff\0\0\0\0\x7b\x1a\xd0\xff\0\0\0\0\xbf\
108
-\xa3\0\0\0\0\0\0\x07\x03\0\0\xd0\xff\xff\xff\xb7\x01\0\0\x28\0\0\0\x7b\x1a\x48\
109
+\0\x71\xa2\x53\xff\0\0\0\0\x79\xa0\x30\xff\0\0\0\0\x15\x02\x0c\x01\0\0\0\0\xbf\
110
+\x12\0\0\0\0\0\0\x57\x02\0\0\x02\0\0\0\x15\x02\x09\x01\0\0\0\0\x61\xa1\x5c\xff\
111
+\0\0\0\0\x63\x1a\xa0\xff\0\0\0\0\x61\xa1\x60\xff\0\0\0\0\x63\x1a\xa4\xff\0\0\0\
112
+\0\x69\xa1\x58\xff\0\0\0\0\x6b\x1a\xa8\xff\0\0\0\0\x69\xa1\x5a\xff\0\0\0\0\x6b\
113
+\x1a\xaa\xff\0\0\0\0\x05\0\x6b\x01\0\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x51\
114
+\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x7b\x1a\xe8\xff\0\0\0\0\x7b\x1a\xe0\xff\0\0\0\
115
+\0\x7b\x1a\xd8\xff\0\0\0\0\x7b\x1a\xd0\xff\0\0\0\0\x7b\x1a\xc8\xff\0\0\0\0\xbf\
116
+\xa3\0\0\0\0\0\0\x07\x03\0\0\xc8\xff\xff\xff\xb7\x01\0\0\x28\0\0\0\x7b\x1a\x40\
117
\xff\0\0\0\0\xbf\x91\0\0\0\0\0\0\xb7\x02\0\0\0\0\0\0\xb7\x04\0\0\x28\0\0\0\xb7\
118
\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\
119
-\x55\0\xfe\0\0\0\0\0\x79\xa1\xe0\xff\0\0\0\0\x63\x1a\x6c\xff\0\0\0\0\x77\x01\0\
120
-\0\x20\0\0\0\x63\x1a\x70\xff\0\0\0\0\x79\xa1\xd8\xff\0\0\0\0\x63\x1a\x64\xff\0\
121
-\0\0\0\x77\x01\0\0\x20\0\0\0\x63\x1a\x68\xff\0\0\0\0\x79\xa1\xe8\xff\0\0\0\0\
122
-\x63\x1a\x74\xff\0\0\0\0\x77\x01\0\0\x20\0\0\0\x63\x1a\x78\xff\0\0\0\0\x79\xa1\
123
-\xf0\xff\0\0\0\0\x63\x1a\x7c\xff\0\0\0\0\x77\x01\0\0\x20\0\0\0\x63\x1a\x80\xff\
124
-\0\0\0\0\x71\xa9\xd6\xff\0\0\0\0\x25\x09\x13\x01\x3c\0\0\0\xb7\x01\0\0\x01\0\0\
125
+\x55\0\xfe\0\0\0\0\0\x79\xa1\xd8\xff\0\0\0\0\x63\x1a\x64\xff\0\0\0\0\x77\x01\0\
126
+\0\x20\0\0\0\x63\x1a\x68\xff\0\0\0\0\x79\xa1\xd0\xff\0\0\0\0\x63\x1a\x5c\xff\0\
127
+\0\0\0\x77\x01\0\0\x20\0\0\0\x63\x1a\x60\xff\0\0\0\0\x79\xa1\xe0\xff\0\0\0\0\
128
+\x63\x1a\x6c\xff\0\0\0\0\x77\x01\0\0\x20\0\0\0\x63\x1a\x70\xff\0\0\0\0\x79\xa1\
129
+\xe8\xff\0\0\0\0\x63\x1a\x74\xff\0\0\0\0\x77\x01\0\0\x20\0\0\0\x63\x1a\x78\xff\
130
+\0\0\0\0\x71\xa9\xce\xff\0\0\0\0\x25\x09\x13\x01\x3c\0\0\0\xb7\x01\0\0\x01\0\0\
131
\0\x6f\x91\0\0\0\0\0\0\x18\x02\0\0\x01\0\0\0\0\0\0\0\0\x18\0\x1c\x5f\x21\0\0\0\
132
\0\0\0\x55\x01\x01\0\0\0\0\0\x05\0\x0c\x01\0\0\0\0\xb7\x01\0\0\0\0\0\0\x6b\x1a\
133
-\xfe\xff\0\0\0\0\xb7\x01\0\0\x28\0\0\0\x7b\x1a\x48\xff\0\0\0\0\xbf\xa1\0\0\0\0\
134
-\0\0\x07\x01\0\0\x94\xff\xff\xff\x7b\x1a\x20\xff\0\0\0\0\xbf\xa1\0\0\0\0\0\0\
135
-\x07\x01\0\0\x84\xff\xff\xff\x7b\x1a\x18\xff\0\0\0\0\x18\x07\0\0\x01\0\0\0\0\0\
136
-\0\0\0\x18\0\x1c\xb7\x02\0\0\0\0\0\0\x7b\x8a\x28\xff\0\0\0\0\x7b\x2a\x30\xff\0\
137
-\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xfe\xff\xff\xff\x79\xa1\x40\xff\0\0\0\0\
138
-\x79\xa2\x48\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\
139
-\x44\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\
140
-\x91\x01\0\0\0\0\xbf\x91\0\0\0\0\0\0\x15\x01\x26\0\x3c\0\0\0\x15\x01\x5f\0\x2c\
141
-\0\0\0\x55\x01\x60\0\x2b\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\xf8\xff\0\0\0\0\xbf\
142
-\xa3\0\0\0\0\0\0\x07\x03\0\0\xf8\xff\xff\xff\x79\xa7\x40\xff\0\0\0\0\xbf\x71\0\
143
-\0\0\0\0\0\x79\xa2\x48\xff\0\0\0\0\xb7\x04\0\0\x04\0\0\0\xb7\x05\0\0\x01\0\0\0\
144
-\x85\0\0\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\
145
-\0\0\0\x55\x01\x06\x01\0\0\0\0\x71\xa1\xfa\xff\0\0\0\0\x55\x01\x11\0\x02\0\0\0\
146
-\x71\xa1\xf9\xff\0\0\0\0\x55\x01\x0f\0\x02\0\0\0\x71\xa1\xfb\xff\0\0\0\0\x55\
147
-\x01\x0d\0\x01\0\0\0\x79\xa2\x48\xff\0\0\0\0\x07\x02\0\0\x08\0\0\0\xbf\x71\0\0\
148
-\0\0\0\0\x79\xa3\x20\xff\0\0\0\0\xb7\x04\0\0\x10\0\0\0\xb7\x05\0\0\x01\0\0\0\
149
-\x85\0\0\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\
150
-\0\0\0\x55\x01\xf5\0\0\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x5d\xff\0\0\0\0\x18\
151
-\x07\0\0\x01\0\0\0\0\0\0\0\0\x18\0\x1c\x05\0\x3c\0\0\0\0\0\xb7\x08\0\0\x02\0\0\
152
-\0\xb7\x07\0\0\0\0\0\0\x6b\x7a\xf8\xff\0\0\0\0\x05\0\x13\0\0\0\0\0\x0f\x81\0\0\
153
-\0\0\0\0\xbf\x12\0\0\0\0\0\0\x07\x02\0\0\x01\0\0\0\x71\xa3\xff\xff\0\0\0\0\x67\
154
-\x03\0\0\x03\0\0\0\x3d\x32\x09\0\0\0\0\0\xbf\x72\0\0\0\0\0\0\x07\x02\0\0\x01\0\
155
-\0\0\x67\x07\0\0\x20\0\0\0\xbf\x73\0\0\0\0\0\0\x77\x03\0\0\x20\0\0\0\xbf\x27\0\
156
-\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xb7\x01\0\0\x1d\0\0\0\x2d\x31\x04\0\0\0\0\0\x79\
157
-\xa8\x28\xff\0\0\0\0\x18\x07\0\0\x01\0\0\0\0\0\0\0\0\x18\0\x1c\x05\0\x25\0\0\0\
158
-\0\0\xbf\x89\0\0\0\0\0\0\x79\xa1\x48\xff\0\0\0\0\x0f\x19\0\0\0\0\0\0\xbf\xa3\0\
159
-\0\0\0\0\0\x07\x03\0\0\xf8\xff\xff\xff\x79\xa1\x40\xff\0\0\0\0\xbf\x92\0\0\0\0\
160
-\0\0\xb7\x04\0\0\x02\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\xbf\x01\0\
161
-\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\x79\0\0\0\0\0\
162
-\x71\xa2\xf8\xff\0\0\0\0\x55\x02\x0e\0\xc9\0\0\0\x07\x09\0\0\x02\0\0\0\x79\xa1\
163
-\x40\xff\0\0\0\0\xbf\x92\0\0\0\0\0\0\x79\xa3\x18\xff\0\0\0\0\xb7\x04\0\0\x10\0\
164
-\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\xbf\x01\0\0\0\0\0\0\x67\x01\0\0\
165
-\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\x6c\0\0\0\0\0\xb7\x01\0\0\x01\0\0\0\
166
-\x73\x1a\x5c\xff\0\0\0\0\x05\0\xde\xff\0\0\0\0\xb7\x01\0\0\x01\0\0\0\x15\x02\
167
-\xcd\xff\0\0\0\0\x71\xa1\xf9\xff\0\0\0\0\x07\x01\0\0\x02\0\0\0\x05\0\xca\xff\0\
168
-\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x5e\xff\0\0\0\0\x71\xa1\xff\xff\0\0\0\0\
169
-\x67\x01\0\0\x03\0\0\0\x79\xa2\x48\xff\0\0\0\0\x0f\x12\0\0\0\0\0\0\x07\x02\0\0\
170
-\x08\0\0\0\x7b\x2a\x48\xff\0\0\0\0\x71\xa9\xfe\xff\0\0\0\0\x79\xa2\x30\xff\0\0\
171
-\0\0\x25\x09\x0c\0\x3c\0\0\0\xb7\x01\0\0\x01\0\0\0\x6f\x91\0\0\0\0\0\0\x5f\x71\
172
-\0\0\0\0\0\0\x55\x01\x01\0\0\0\0\0\x05\0\x07\0\0\0\0\0\x07\x02\0\0\x01\0\0\0\
173
-\xbf\x21\0\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\x7d\
174
-\xff\x0b\0\0\0\x71\xa7\x5e\xff\0\0\0\0\x05\0\x09\xff\0\0\0\0\x15\x09\xf8\xff\
175
-\x87\0\0\0\x05\0\xfc\xff\0\0\0\0\x71\xa1\x59\xff\0\0\0\0\x79\xa0\x38\xff\0\0\0\
176
-\0\x15\x01\x13\x01\0\0\0\0\x71\x62\x03\0\0\0\0\0\x67\x02\0\0\x08\0\0\0\x71\x61\
177
+\xf8\xff\0\0\0\0\xb7\x01\0\0\x28\0\0\0\x7b\x1a\x40\xff\0\0\0\0\xbf\xa1\0\0\0\0\
178
+\0\0\x07\x01\0\0\x8c\xff\xff\xff\x7b\x1a\x18\xff\0\0\0\0\xbf\xa1\0\0\0\0\0\0\
179
+\x07\x01\0\0\x7c\xff\xff\xff\x7b\x1a\x10\xff\0\0\0\0\x18\x07\0\0\x01\0\0\0\0\0\
180
+\0\0\0\x18\0\x1c\xb7\x02\0\0\0\0\0\0\x7b\x8a\x20\xff\0\0\0\0\x7b\x2a\x28\xff\0\
181
+\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xf8\xff\xff\xff\x79\xa1\x38\xff\0\0\0\0\
182
+\x79\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\
183
+\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\x55\
184
+\x01\xc8\0\0\0\0\0\xbf\x91\0\0\0\0\0\0\x15\x01\x26\0\x3c\0\0\0\x15\x01\x5f\0\
185
+\x2c\0\0\0\x55\x01\x60\0\x2b\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\xf0\xff\0\0\0\0\
186
+\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xf0\xff\xff\xff\x79\xa7\x38\xff\0\0\0\0\xbf\
187
+\x71\0\0\0\0\0\0\x79\xa2\x40\xff\0\0\0\0\xb7\x04\0\0\x04\0\0\0\xb7\x05\0\0\x01\
188
+\0\0\0\x85\0\0\0\x44\0\0\0\xbf\x01\0\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\
189
+\0\x20\0\0\0\x55\x01\x06\x01\0\0\0\0\x71\xa1\xf2\xff\0\0\0\0\x55\x01\x11\0\x02\
190
+\0\0\0\x71\xa1\xf1\xff\0\0\0\0\x55\x01\x0f\0\x02\0\0\0\x71\xa1\xf3\xff\0\0\0\0\
191
+\x55\x01\x0d\0\x01\0\0\0\x79\xa2\x40\xff\0\0\0\0\x07\x02\0\0\x08\0\0\0\xbf\x71\
192
+\0\0\0\0\0\0\x79\xa3\x18\xff\0\0\0\0\xb7\x04\0\0\x10\0\0\0\xb7\x05\0\0\x01\0\0\
193
+\0\x85\0\0\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\
194
+\x20\0\0\0\x55\x01\xf5\0\0\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x55\xff\0\0\0\0\
195
+\x18\x07\0\0\x01\0\0\0\0\0\0\0\0\x18\0\x1c\x05\0\x3c\0\0\0\0\0\xb7\x08\0\0\x02\
196
+\0\0\0\xb7\x07\0\0\0\0\0\0\x6b\x7a\xf0\xff\0\0\0\0\x05\0\x13\0\0\0\0\0\x0f\x81\
197
+\0\0\0\0\0\0\xbf\x12\0\0\0\0\0\0\x07\x02\0\0\x01\0\0\0\x71\xa3\xf9\xff\0\0\0\0\
198
+\x67\x03\0\0\x03\0\0\0\x3d\x32\x09\0\0\0\0\0\xbf\x72\0\0\0\0\0\0\x07\x02\0\0\
199
+\x01\0\0\0\x67\x07\0\0\x20\0\0\0\xbf\x73\0\0\0\0\0\0\x77\x03\0\0\x20\0\0\0\xbf\
200
+\x27\0\0\0\0\0\0\xbf\x18\0\0\0\0\0\0\xb7\x01\0\0\x1d\0\0\0\x2d\x31\x04\0\0\0\0\
201
+\0\x79\xa8\x20\xff\0\0\0\0\x18\x07\0\0\x01\0\0\0\0\0\0\0\0\x18\0\x1c\x05\0\x25\
202
+\0\0\0\0\0\xbf\x89\0\0\0\0\0\0\x79\xa1\x40\xff\0\0\0\0\x0f\x19\0\0\0\0\0\0\xbf\
203
+\xa3\0\0\0\0\0\0\x07\x03\0\0\xf0\xff\xff\xff\x79\xa1\x38\xff\0\0\0\0\xbf\x92\0\
204
+\0\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\0\0\0\xbf\
205
+\x01\0\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\x79\0\0\0\
206
+\0\0\x71\xa2\xf0\xff\0\0\0\0\x55\x02\x0e\0\xc9\0\0\0\x07\x09\0\0\x02\0\0\0\x79\
207
+\xa1\x38\xff\0\0\0\0\xbf\x92\0\0\0\0\0\0\x79\xa3\x10\xff\0\0\0\0\xb7\x04\0\0\
208
+\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\0\0\0\x67\
209
+\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\x6c\0\0\0\0\0\xb7\x01\0\0\x01\
210
+\0\0\0\x73\x1a\x54\xff\0\0\0\0\x05\0\xde\xff\0\0\0\0\xb7\x01\0\0\x01\0\0\0\x15\
211
+\x02\xcd\xff\0\0\0\0\x71\xa1\xf1\xff\0\0\0\0\x07\x01\0\0\x02\0\0\0\x05\0\xca\
212
+\xff\0\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x56\xff\0\0\0\0\x71\xa1\xf9\xff\0\0\
213
+\0\0\x67\x01\0\0\x03\0\0\0\x79\xa2\x40\xff\0\0\0\0\x0f\x12\0\0\0\0\0\0\x07\x02\
214
+\0\0\x08\0\0\0\x7b\x2a\x40\xff\0\0\0\0\x71\xa9\xf8\xff\0\0\0\0\x79\xa2\x28\xff\
215
+\0\0\0\0\x25\x09\x0c\0\x3c\0\0\0\xb7\x01\0\0\x01\0\0\0\x6f\x91\0\0\0\0\0\0\x5f\
216
+\x71\0\0\0\0\0\0\x55\x01\x01\0\0\0\0\0\x05\0\x07\0\0\0\0\0\x07\x02\0\0\x01\0\0\
217
+\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\x55\x01\x7d\
218
+\xff\x0b\0\0\0\x71\xa7\x56\xff\0\0\0\0\x05\0\x09\xff\0\0\0\0\x15\x09\xf8\xff\
219
+\x87\0\0\0\x05\0\xfc\xff\0\0\0\0\x71\xa1\x51\xff\0\0\0\0\x79\xa0\x30\xff\0\0\0\
220
+\0\x15\x01\x10\x01\0\0\0\0\x71\x62\x03\0\0\0\0\0\x67\x02\0\0\x08\0\0\0\x71\x61\
221
\x02\0\0\0\0\0\x4f\x12\0\0\0\0\0\0\x71\x63\x04\0\0\0\0\0\x71\x61\x05\0\0\0\0\0\
222
\x67\x01\0\0\x08\0\0\0\x4f\x31\0\0\0\0\0\0\x67\x01\0\0\x10\0\0\0\x4f\x21\0\0\0\
223
-\0\0\0\x71\xa2\x5b\xff\0\0\0\0\x15\x02\x42\0\0\0\0\0\xbf\x12\0\0\0\0\0\0\x57\
224
+\0\0\0\x71\xa2\x53\xff\0\0\0\0\x15\x02\x42\0\0\0\0\0\xbf\x12\0\0\0\0\0\0\x57\
225
\x02\0\0\x10\0\0\0\x15\x02\x3f\0\0\0\0\0\x57\x01\0\0\x80\0\0\0\xb7\x02\0\0\x10\
226
\0\0\0\xb7\x03\0\0\x10\0\0\0\x15\x01\x01\0\0\0\0\0\xb7\x03\0\0\x30\0\0\0\x71\
227
-\xa4\x5d\xff\0\0\0\0\x15\x04\x01\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\xbf\xa3\0\0\0\0\
228
-\0\0\x07\x03\0\0\x64\xff\xff\xff\xbf\x34\0\0\0\0\0\0\x15\x01\x02\0\0\0\0\0\xbf\
229
-\xa4\0\0\0\0\0\0\x07\x04\0\0\x84\xff\xff\xff\x71\xa5\x5c\xff\0\0\0\0\xbf\x31\0\
230
+\xa4\x55\xff\0\0\0\0\x15\x04\x01\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\xbf\xa3\0\0\0\0\
231
+\0\0\x07\x03\0\0\x5c\xff\xff\xff\xbf\x34\0\0\0\0\0\0\x15\x01\x02\0\0\0\0\0\xbf\
232
+\xa4\0\0\0\0\0\0\x07\x04\0\0\x7c\xff\xff\xff\x71\xa5\x54\xff\0\0\0\0\xbf\x31\0\
233
\0\0\0\0\0\x15\x05\x01\0\0\0\0\0\xbf\x41\0\0\0\0\0\0\x61\x14\x04\0\0\0\0\0\x67\
234
-\x04\0\0\x20\0\0\0\x61\x15\0\0\0\0\0\0\x4f\x54\0\0\0\0\0\0\x7b\x4a\xa8\xff\0\0\
235
+\x04\0\0\x20\0\0\0\x61\x15\0\0\0\0\0\0\x4f\x54\0\0\0\0\0\0\x7b\x4a\xa0\xff\0\0\
236
\0\0\x61\x14\x08\0\0\0\0\0\x61\x11\x0c\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x4f\x41\
237
-\0\0\0\0\0\0\x7b\x1a\xb0\xff\0\0\0\0\x0f\x23\0\0\0\0\0\0\x61\x31\0\0\0\0\0\0\
238
-\x61\x32\x04\0\0\0\0\0\x61\x34\x08\0\0\0\0\0\x61\x33\x0c\0\0\0\0\0\x69\xa5\x62\
239
-\xff\0\0\0\0\x6b\x5a\xca\xff\0\0\0\0\x69\xa5\x60\xff\0\0\0\0\x6b\x5a\xc8\xff\0\
240
-\0\0\0\x67\x03\0\0\x20\0\0\0\x4f\x43\0\0\0\0\0\0\x7b\x3a\xc0\xff\0\0\0\0\x67\
241
-\x02\0\0\x20\0\0\0\x4f\x12\0\0\0\0\0\0\x7b\x2a\xb8\xff\0\0\0\0\x05\0\x6b\0\0\0\
242
-\0\0\x71\xa2\x5a\xff\0\0\0\0\x15\x02\x04\0\0\0\0\0\xbf\x12\0\0\0\0\0\0\x57\x02\
243
+\0\0\0\0\0\0\x7b\x1a\xa8\xff\0\0\0\0\x0f\x23\0\0\0\0\0\0\x61\x31\0\0\0\0\0\0\
244
+\x61\x32\x04\0\0\0\0\0\x61\x34\x08\0\0\0\0\0\x61\x33\x0c\0\0\0\0\0\x69\xa5\x5a\
245
+\xff\0\0\0\0\x6b\x5a\xc2\xff\0\0\0\0\x69\xa5\x58\xff\0\0\0\0\x6b\x5a\xc0\xff\0\
246
+\0\0\0\x67\x03\0\0\x20\0\0\0\x4f\x43\0\0\0\0\0\0\x7b\x3a\xb8\xff\0\0\0\0\x67\
247
+\x02\0\0\x20\0\0\0\x4f\x12\0\0\0\0\0\0\x7b\x2a\xb0\xff\0\0\0\0\x05\0\x6b\0\0\0\
248
+\0\0\x71\xa2\x52\xff\0\0\0\0\x15\x02\x04\0\0\0\0\0\xbf\x12\0\0\0\0\0\0\x57\x02\
249
\0\0\x04\0\0\0\x15\x02\x01\0\0\0\0\0\x05\0\xf1\xfe\0\0\0\0\x57\x01\0\0\x01\0\0\
250
-\0\x15\x01\xd0\0\0\0\0\0\x61\xa1\x64\xff\0\0\0\0\x63\x1a\xa8\xff\0\0\0\0\x61\
251
-\xa1\x68\xff\0\0\0\0\x63\x1a\xac\xff\0\0\0\0\x05\0\x5e\0\0\0\0\0\xb7\x09\0\0\
252
-\x3c\0\0\0\x79\xa8\x28\xff\0\0\0\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x15\
253
-\0\xac\xff\0\0\0\0\x05\0\xc5\0\0\0\0\0\x71\xa2\x5a\xff\0\0\0\0\x15\x02\x26\0\0\
254
+\0\x15\x01\xcd\0\0\0\0\0\x61\xa1\x5c\xff\0\0\0\0\x63\x1a\xa0\xff\0\0\0\0\x61\
255
+\xa1\x60\xff\0\0\0\0\x63\x1a\xa4\xff\0\0\0\0\x05\0\x5e\0\0\0\0\0\xb7\x09\0\0\
256
+\x3c\0\0\0\x79\xa8\x20\xff\0\0\0\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x15\
257
+\0\xac\xff\0\0\0\0\x05\0\xc2\0\0\0\0\0\x71\xa2\x52\xff\0\0\0\0\x15\x02\x26\0\0\
258
\0\0\0\xbf\x12\0\0\0\0\0\0\x57\x02\0\0\x20\0\0\0\x15\x02\x23\0\0\0\0\0\x57\x01\
259
\0\0\0\x01\0\0\xb7\x02\0\0\x10\0\0\0\xb7\x03\0\0\x10\0\0\0\x15\x01\x01\0\0\0\0\
260
-\0\xb7\x03\0\0\x30\0\0\0\x71\xa4\x5d\xff\0\0\0\0\x15\x04\x01\0\0\0\0\0\xbf\x32\
261
-\0\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\x64\xff\xff\xff\xbf\x34\0\0\0\0\0\
262
-\0\x15\x01\x02\0\0\0\0\0\xbf\xa4\0\0\0\0\0\0\x07\x04\0\0\x84\xff\xff\xff\x71\
263
-\xa5\x5c\xff\0\0\0\0\xbf\x31\0\0\0\0\0\0\x15\x05\xbd\xff\0\0\0\0\x05\0\xbb\xff\
264
-\0\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x5a\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x7b\
265
-\x1a\xd0\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xd0\xff\xff\xff\x79\xa1\
266
-\x40\xff\0\0\0\0\x79\xa2\x48\xff\0\0\0\0\xb7\x04\0\0\x08\0\0\0\xb7\x05\0\0\x01\
267
-\0\0\0\x85\0\0\0\x44\0\0\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x55\0\xa0\0\
268
+\0\xb7\x03\0\0\x30\0\0\0\x71\xa4\x55\xff\0\0\0\0\x15\x04\x01\0\0\0\0\0\xbf\x32\
269
+\0\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\x5c\xff\xff\xff\xbf\x34\0\0\0\0\0\
270
+\0\x15\x01\x02\0\0\0\0\0\xbf\xa4\0\0\0\0\0\0\x07\x04\0\0\x7c\xff\xff\xff\x71\
271
+\xa5\x54\xff\0\0\0\0\xbf\x31\0\0\0\0\0\0\x15\x05\xbd\xff\0\0\0\0\x05\0\xbb\xff\
272
+\0\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x52\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x7b\
273
+\x1a\xc8\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xc8\xff\xff\xff\x79\xa1\
274
+\x38\xff\0\0\0\0\x79\xa2\x40\xff\0\0\0\0\xb7\x04\0\0\x08\0\0\0\xb7\x05\0\0\x01\
275
+\0\0\0\x85\0\0\0\x44\0\0\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x55\0\x9d\0\
276
\0\0\0\0\x05\0\xa8\xfe\0\0\0\0\x15\x09\xf3\xfe\x87\0\0\0\x05\0\x83\xff\0\0\0\0\
277
-\xbf\x12\0\0\0\0\0\0\x57\x02\0\0\x08\0\0\0\x15\x02\x9a\0\0\0\0\0\x57\x01\0\0\
278
+\xbf\x12\0\0\0\0\0\0\x57\x02\0\0\x08\0\0\0\x15\x02\x97\0\0\0\0\0\x57\x01\0\0\
279
\x40\0\0\0\xb7\x02\0\0\x0c\0\0\0\xb7\x03\0\0\x0c\0\0\0\x15\x01\x01\0\0\0\0\0\
280
-\xb7\x03\0\0\x2c\0\0\0\x71\xa4\x5c\xff\0\0\0\0\x15\x04\x01\0\0\0\0\0\xbf\x32\0\
281
-\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\x58\xff\xff\xff\x0f\x23\0\0\0\0\0\0\
282
+\xb7\x03\0\0\x2c\0\0\0\x71\xa4\x54\xff\0\0\0\0\x15\x04\x01\0\0\0\0\0\xbf\x32\0\
283
+\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\x50\xff\xff\xff\x0f\x23\0\0\0\0\0\0\
284
\x61\x32\x04\0\0\0\0\0\x67\x02\0\0\x20\0\0\0\x61\x34\0\0\0\0\0\0\x4f\x42\0\0\0\
285
-\0\0\0\x7b\x2a\xa8\xff\0\0\0\0\x61\x32\x08\0\0\0\0\0\x61\x33\x0c\0\0\0\0\0\x67\
286
-\x03\0\0\x20\0\0\0\x4f\x23\0\0\0\0\0\0\x7b\x3a\xb0\xff\0\0\0\0\x71\xa2\x5d\xff\
287
-\0\0\0\0\x15\x02\x0c\0\0\0\0\0\x15\x01\x0b\0\0\0\0\0\x61\xa1\xa0\xff\0\0\0\0\
288
-\x67\x01\0\0\x20\0\0\0\x61\xa2\x9c\xff\0\0\0\0\x4f\x21\0\0\0\0\0\0\x7b\x1a\xc0\
289
-\xff\0\0\0\0\x61\xa1\x98\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\xa2\x94\xff\0\0\
290
+\0\0\0\x7b\x2a\xa0\xff\0\0\0\0\x61\x32\x08\0\0\0\0\0\x61\x33\x0c\0\0\0\0\0\x67\
291
+\x03\0\0\x20\0\0\0\x4f\x23\0\0\0\0\0\0\x7b\x3a\xa8\xff\0\0\0\0\x71\xa2\x55\xff\
292
+\0\0\0\0\x15\x02\x0c\0\0\0\0\0\x15\x01\x0b\0\0\0\0\0\x61\xa1\x98\xff\0\0\0\0\
293
+\x67\x01\0\0\x20\0\0\0\x61\xa2\x94\xff\0\0\0\0\x4f\x21\0\0\0\0\0\0\x7b\x1a\xb8\
294
+\xff\0\0\0\0\x61\xa1\x90\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\xa2\x8c\xff\0\0\
295
\0\0\x05\0\x0a\0\0\0\0\0\xb7\x09\0\0\x2b\0\0\0\x05\0\xae\xff\0\0\0\0\x61\xa1\
296
-\x80\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\xa2\x7c\xff\0\0\0\0\x4f\x21\0\0\0\0\
297
-\0\0\x7b\x1a\xc0\xff\0\0\0\0\x61\xa1\x78\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\
298
-\xa2\x74\xff\0\0\0\0\x4f\x21\0\0\0\0\0\0\x7b\x1a\xb8\xff\0\0\0\0\xb7\x02\0\0\0\
299
+\x78\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\xa2\x74\xff\0\0\0\0\x4f\x21\0\0\0\0\
300
+\0\0\x7b\x1a\xb8\xff\0\0\0\0\x61\xa1\x70\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\
301
+\xa2\x6c\xff\0\0\0\0\x4f\x21\0\0\0\0\0\0\x7b\x1a\xb0\xff\0\0\0\0\xb7\x02\0\0\0\
302
\0\0\0\x07\x08\0\0\x04\0\0\0\x61\x03\0\0\0\0\0\0\xb7\x05\0\0\0\0\0\0\xbf\xa1\0\
303
-\0\0\0\0\0\x07\x01\0\0\xa8\xff\xff\xff\x0f\x21\0\0\0\0\0\0\x71\x14\0\0\0\0\0\0\
304
+\0\0\0\0\0\x07\x01\0\0\xa0\xff\xff\xff\x0f\x21\0\0\0\0\0\0\x71\x14\0\0\0\0\0\0\
305
\xbf\x41\0\0\0\0\0\0\x67\x01\0\0\x38\0\0\0\xc7\x01\0\0\x3f\0\0\0\x5f\x31\0\0\0\
306
\0\0\0\xaf\x51\0\0\0\0\0\0\xbf\x85\0\0\0\0\0\0\x0f\x25\0\0\0\0\0\0\x71\x55\0\0\
307
\0\0\0\0\x67\x03\0\0\x01\0\0\0\xbf\x50\0\0\0\0\0\0\x77\0\0\0\x07\0\0\0\x4f\x03\
308
@@ -XXX,XX +XXX,XX @@ static inline const void *rss_bpf__elf_bytes(size_t *sz)
309
\0\x57\0\0\0\x01\0\0\0\x67\x03\0\0\x01\0\0\0\x4f\x03\0\0\0\0\0\0\x57\x04\0\0\
310
\x01\0\0\0\x87\x04\0\0\0\0\0\0\x5f\x34\0\0\0\0\0\0\xaf\x41\0\0\0\0\0\0\x57\x05\
311
\0\0\x01\0\0\0\x67\x03\0\0\x01\0\0\0\x4f\x53\0\0\0\0\0\0\x07\x02\0\0\x01\0\0\0\
312
-\xbf\x15\0\0\0\0\0\0\x15\x02\x01\0\x24\0\0\0\x05\0\xa9\xff\0\0\0\0\xbf\x12\0\0\
313
-\0\0\0\0\x67\x02\0\0\x20\0\0\0\x77\x02\0\0\x20\0\0\0\x15\x02\x0e\0\0\0\0\0\x71\
314
-\x63\x06\0\0\0\0\0\x71\x64\x07\0\0\0\0\0\x67\x04\0\0\x08\0\0\0\x4f\x34\0\0\0\0\
315
-\0\0\x3f\x42\0\0\0\0\0\0\x2f\x42\0\0\0\0\0\0\x1f\x21\0\0\0\0\0\0\x63\x1a\x58\
316
-\xff\0\0\0\0\xbf\xa2\0\0\0\0\0\0\x07\x02\0\0\x58\xff\xff\xff\x18\x01\0\0\0\0\0\
317
-\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\x71\x61\x08\0\0\0\0\
318
-\0\x71\x60\x09\0\0\0\0\0\x67\0\0\0\x08\0\0\0\x4f\x10\0\0\0\0\0\0\x95\0\0\0\0\0\
319
-\0\0\x69\0\0\0\0\0\0\0\x05\0\xfd\xff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
320
+\xbf\x15\0\0\0\0\0\0\x15\x02\x01\0\x24\0\0\0\x05\0\xa9\xff\0\0\0\0\x67\x01\0\0\
321
+\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x15\x01\x0c\0\0\0\0\0\x71\x62\x06\0\0\0\0\0\
322
+\x71\x63\x07\0\0\0\0\0\x67\x03\0\0\x08\0\0\0\x4f\x23\0\0\0\0\0\0\x9f\x31\0\0\0\
323
+\0\0\0\x63\x1a\x50\xff\0\0\0\0\xbf\xa2\0\0\0\0\0\0\x07\x02\0\0\x50\xff\xff\xff\
324
+\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\
325
+\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\
326
+\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\0\0\0\0\0\0\0\
327
\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\0\0\
328
\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\0\0\
329
-\0\x47\x50\x4c\x20\x76\x32\0\0\x9f\xeb\x01\0\x18\0\0\0\0\0\0\0\x10\x05\0\0\x10\
330
-\x05\0\0\x65\x11\0\0\0\0\0\0\0\0\0\x02\x03\0\0\0\x01\0\0\0\0\0\0\x01\x04\0\0\0\
331
-\x20\0\0\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\x02\0\0\0\x05\0\0\0\
332
-\0\0\0\x01\x04\0\0\0\x20\0\0\0\0\0\0\0\0\0\0\x02\x06\0\0\0\0\0\0\0\0\0\0\x03\0\
333
-\0\0\0\x02\0\0\0\x04\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\x02\x08\0\0\0\0\0\0\0\0\0\0\
334
-\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\x0a\0\0\0\0\0\0\0\0\0\0\x02\x0a\0\0\0\0\0\0\0\
335
-\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\x01\0\0\0\0\0\0\0\x04\0\0\x04\x20\0\0\0\
336
+\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\x47\x50\
337
+\x4c\x20\x76\x32\0\0\x9f\xeb\x01\0\x18\0\0\0\0\0\0\0\x58\x05\0\0\x58\x05\0\0\
338
+\x6b\x11\0\0\0\0\0\0\0\0\0\x02\x03\0\0\0\x01\0\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\
339
+\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\x02\0\0\0\x05\0\0\0\0\0\0\
340
+\x01\x04\0\0\0\x20\0\0\0\0\0\0\0\0\0\0\x02\x06\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\
341
+\x02\0\0\0\x04\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\x02\x08\0\0\0\0\0\0\0\0\0\0\x03\0\
342
+\0\0\0\x02\0\0\0\x04\0\0\0\x0a\0\0\0\0\0\0\0\0\0\0\x02\x0a\0\0\0\0\0\0\0\0\0\0\
343
+\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\x02\x0c\0\0\0\0\0\0\0\
344
+\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\0\x04\0\0\0\0\0\0\x05\0\0\x04\x28\0\0\0\
345
\x19\0\0\0\x01\0\0\0\0\0\0\0\x1e\0\0\0\x05\0\0\0\x40\0\0\0\x27\0\0\0\x07\0\0\0\
346
-\x80\0\0\0\x32\0\0\0\x09\0\0\0\xc0\0\0\0\x3e\0\0\0\0\0\0\x0e\x0b\0\0\0\x01\0\0\
347
-\0\0\0\0\0\0\0\0\x02\x0e\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\
348
-\x28\0\0\0\0\0\0\0\x04\0\0\x04\x20\0\0\0\x19\0\0\0\x01\0\0\0\0\0\0\0\x1e\0\0\0\
349
-\x05\0\0\0\x40\0\0\0\x27\0\0\0\x0d\0\0\0\x80\0\0\0\x32\0\0\0\x09\0\0\0\xc0\0\0\
350
-\0\x59\0\0\0\0\0\0\x0e\x0f\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\x02\x12\0\0\0\0\0\0\0\
351
-\0\0\0\x03\0\0\0\0\x02\0\0\0\x04\0\0\0\x80\0\0\0\0\0\0\0\x04\0\0\x04\x20\0\0\0\
352
-\x19\0\0\0\x01\0\0\0\0\0\0\0\x1e\0\0\0\x05\0\0\0\x40\0\0\0\x27\0\0\0\x01\0\0\0\
353
-\x80\0\0\0\x32\0\0\0\x11\0\0\0\xc0\0\0\0\x72\0\0\0\0\0\0\x0e\x13\0\0\0\x01\0\0\
354
-\0\0\0\0\0\0\0\0\x02\x16\0\0\0\x90\0\0\0\x22\0\0\x04\xc0\0\0\0\x9a\0\0\0\x17\0\
355
-\0\0\0\0\0\0\x9e\0\0\0\x17\0\0\0\x20\0\0\0\xa7\0\0\0\x17\0\0\0\x40\0\0\0\xac\0\
356
-\0\0\x17\0\0\0\x60\0\0\0\xba\0\0\0\x17\0\0\0\x80\0\0\0\xc3\0\0\0\x17\0\0\0\xa0\
357
-\0\0\0\xd0\0\0\0\x17\0\0\0\xc0\0\0\0\xd9\0\0\0\x17\0\0\0\xe0\0\0\0\xe4\0\0\0\
358
-\x17\0\0\0\0\x01\0\0\xed\0\0\0\x17\0\0\0\x20\x01\0\0\xfd\0\0\0\x17\0\0\0\x40\
359
-\x01\0\0\x05\x01\0\0\x17\0\0\0\x60\x01\0\0\x0e\x01\0\0\x19\0\0\0\x80\x01\0\0\
360
-\x11\x01\0\0\x17\0\0\0\x20\x02\0\0\x16\x01\0\0\x17\0\0\0\x40\x02\0\0\x21\x01\0\
361
-\0\x17\0\0\0\x60\x02\0\0\x26\x01\0\0\x17\0\0\0\x80\x02\0\0\x2f\x01\0\0\x17\0\0\
362
-\0\xa0\x02\0\0\x37\x01\0\0\x17\0\0\0\xc0\x02\0\0\x3e\x01\0\0\x17\0\0\0\xe0\x02\
363
-\0\0\x49\x01\0\0\x17\0\0\0\0\x03\0\0\x53\x01\0\0\x1a\0\0\0\x20\x03\0\0\x5e\x01\
364
-\0\0\x1a\0\0\0\xa0\x03\0\0\x68\x01\0\0\x17\0\0\0\x20\x04\0\0\x74\x01\0\0\x17\0\
365
-\0\0\x40\x04\0\0\x7f\x01\0\0\x17\0\0\0\x60\x04\0\0\0\0\0\0\x1b\0\0\0\x80\x04\0\
366
-\0\x89\x01\0\0\x1d\0\0\0\xc0\x04\0\0\x90\x01\0\0\x17\0\0\0\0\x05\0\0\x99\x01\0\
367
-\0\x17\0\0\0\x20\x05\0\0\0\0\0\0\x1f\0\0\0\x40\x05\0\0\xa2\x01\0\0\x17\0\0\0\
368
-\x80\x05\0\0\xab\x01\0\0\x21\0\0\0\xa0\x05\0\0\xb7\x01\0\0\x1d\0\0\0\xc0\x05\0\
369
-\0\xc0\x01\0\0\0\0\0\x08\x18\0\0\0\xc6\x01\0\0\0\0\0\x01\x04\0\0\0\x20\0\0\0\0\
370
-\0\0\0\0\0\0\x03\0\0\0\0\x17\0\0\0\x04\0\0\0\x05\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\
371
-\0\x17\0\0\0\x04\0\0\0\x04\0\0\0\0\0\0\0\x01\0\0\x05\x08\0\0\0\xd3\x01\0\0\x1c\
372
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\x2a\0\0\0\xdd\x01\0\0\0\0\0\x08\x1e\0\0\0\xe3\
373
-\x01\0\0\0\0\0\x01\x08\0\0\0\x40\0\0\0\0\0\0\0\x01\0\0\x05\x08\0\0\0\xf6\x01\0\
374
-\0\x20\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\x2b\0\0\0\xf9\x01\0\0\0\0\0\x08\x22\0\0\
375
-\0\xfe\x01\0\0\0\0\0\x01\x01\0\0\0\x08\0\0\0\0\0\0\0\x01\0\0\x0d\x02\0\0\0\x0c\
376
-\x02\0\0\x15\0\0\0\x10\x02\0\0\x01\0\0\x0c\x23\0\0\0\x32\x11\0\0\0\0\0\x01\x01\
377
-\0\0\0\x08\0\0\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x25\0\0\0\x04\0\0\0\x07\0\0\0\x37\
378
-\x11\0\0\0\0\0\x0e\x26\0\0\0\x01\0\0\0\x40\x11\0\0\x03\0\0\x0f\0\0\0\0\x0c\0\0\
379
-\0\0\0\0\0\x20\0\0\0\x10\0\0\0\0\0\0\0\x20\0\0\0\x14\0\0\0\0\0\0\0\x20\0\0\0\
380
-\x46\x11\0\0\x01\0\0\x0f\0\0\0\0\x27\0\0\0\0\0\0\0\x07\0\0\0\x4e\x11\0\0\0\0\0\
381
-\x07\0\0\0\0\x5c\x11\0\0\0\0\0\x07\0\0\0\0\0\x69\x6e\x74\0\x5f\x5f\x41\x52\x52\
382
-\x41\x59\x5f\x53\x49\x5a\x45\x5f\x54\x59\x50\x45\x5f\x5f\0\x74\x79\x70\x65\0\
383
-\x6b\x65\x79\x5f\x73\x69\x7a\x65\0\x76\x61\x6c\x75\x65\x5f\x73\x69\x7a\x65\0\
384
-\x6d\x61\x78\x5f\x65\x6e\x74\x72\x69\x65\x73\0\x74\x61\x70\x5f\x72\x73\x73\x5f\
385
-\x6d\x61\x70\x5f\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x74\x69\x6f\x6e\x73\0\x74\
386
+\x80\0\0\0\x32\0\0\0\x09\0\0\0\xc0\0\0\0\x3e\0\0\0\x0b\0\0\0\0\x01\0\0\x48\0\0\
387
+\0\0\0\0\x0e\x0d\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\x02\x10\0\0\0\0\0\0\0\0\0\0\x03\
388
+\0\0\0\0\x02\0\0\0\x04\0\0\0\x28\0\0\0\0\0\0\0\x05\0\0\x04\x28\0\0\0\x19\0\0\0\
389
+\x01\0\0\0\0\0\0\0\x1e\0\0\0\x05\0\0\0\x40\0\0\0\x27\0\0\0\x0f\0\0\0\x80\0\0\0\
390
+\x32\0\0\0\x09\0\0\0\xc0\0\0\0\x3e\0\0\0\x0b\0\0\0\0\x01\0\0\x63\0\0\0\0\0\0\
391
+\x0e\x11\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\x02\x14\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\
392
+\x02\0\0\0\x04\0\0\0\x80\0\0\0\0\0\0\0\x05\0\0\x04\x28\0\0\0\x19\0\0\0\x01\0\0\
393
+\0\0\0\0\0\x1e\0\0\0\x05\0\0\0\x40\0\0\0\x27\0\0\0\x01\0\0\0\x80\0\0\0\x32\0\0\
394
+\0\x13\0\0\0\xc0\0\0\0\x3e\0\0\0\x0b\0\0\0\0\x01\0\0\x7c\0\0\0\0\0\0\x0e\x15\0\
395
+\0\0\x01\0\0\0\0\0\0\0\0\0\0\x02\x18\0\0\0\x9a\0\0\0\x22\0\0\x04\xc0\0\0\0\xa4\
396
+\0\0\0\x19\0\0\0\0\0\0\0\xa8\0\0\0\x19\0\0\0\x20\0\0\0\xb1\0\0\0\x19\0\0\0\x40\
397
+\0\0\0\xb6\0\0\0\x19\0\0\0\x60\0\0\0\xc4\0\0\0\x19\0\0\0\x80\0\0\0\xcd\0\0\0\
398
+\x19\0\0\0\xa0\0\0\0\xda\0\0\0\x19\0\0\0\xc0\0\0\0\xe3\0\0\0\x19\0\0\0\xe0\0\0\
399
+\0\xee\0\0\0\x19\0\0\0\0\x01\0\0\xf7\0\0\0\x19\0\0\0\x20\x01\0\0\x07\x01\0\0\
400
+\x19\0\0\0\x40\x01\0\0\x0f\x01\0\0\x19\0\0\0\x60\x01\0\0\x18\x01\0\0\x1b\0\0\0\
401
+\x80\x01\0\0\x1b\x01\0\0\x19\0\0\0\x20\x02\0\0\x20\x01\0\0\x19\0\0\0\x40\x02\0\
402
+\0\x2b\x01\0\0\x19\0\0\0\x60\x02\0\0\x30\x01\0\0\x19\0\0\0\x80\x02\0\0\x39\x01\
403
+\0\0\x19\0\0\0\xa0\x02\0\0\x41\x01\0\0\x19\0\0\0\xc0\x02\0\0\x48\x01\0\0\x19\0\
404
+\0\0\xe0\x02\0\0\x53\x01\0\0\x19\0\0\0\0\x03\0\0\x5d\x01\0\0\x1c\0\0\0\x20\x03\
405
+\0\0\x68\x01\0\0\x1c\0\0\0\xa0\x03\0\0\x72\x01\0\0\x19\0\0\0\x20\x04\0\0\x7e\
406
+\x01\0\0\x19\0\0\0\x40\x04\0\0\x89\x01\0\0\x19\0\0\0\x60\x04\0\0\0\0\0\0\x1d\0\
407
+\0\0\x80\x04\0\0\x93\x01\0\0\x1f\0\0\0\xc0\x04\0\0\x9a\x01\0\0\x19\0\0\0\0\x05\
408
+\0\0\xa3\x01\0\0\x19\0\0\0\x20\x05\0\0\0\0\0\0\x21\0\0\0\x40\x05\0\0\xac\x01\0\
409
+\0\x19\0\0\0\x80\x05\0\0\xb5\x01\0\0\x23\0\0\0\xa0\x05\0\0\xc1\x01\0\0\x1f\0\0\
410
+\0\xc0\x05\0\0\xca\x01\0\0\0\0\0\x08\x1a\0\0\0\xd0\x01\0\0\0\0\0\x01\x04\0\0\0\
411
+\x20\0\0\0\0\0\0\0\0\0\0\x03\0\0\0\0\x19\0\0\0\x04\0\0\0\x05\0\0\0\0\0\0\0\0\0\
412
+\0\x03\0\0\0\0\x19\0\0\0\x04\0\0\0\x04\0\0\0\0\0\0\0\x01\0\0\x05\x08\0\0\0\xdd\
413
+\x01\0\0\x1e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\x2c\0\0\0\xe7\x01\0\0\0\0\0\x08\
414
+\x20\0\0\0\xed\x01\0\0\0\0\0\x01\x08\0\0\0\x40\0\0\0\0\0\0\0\x01\0\0\x05\x08\0\
415
+\0\0\0\x02\0\0\x22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\x2d\0\0\0\x03\x02\0\0\0\0\0\
416
+\x08\x24\0\0\0\x08\x02\0\0\0\0\0\x01\x01\0\0\0\x08\0\0\0\0\0\0\0\x01\0\0\x0d\
417
+\x02\0\0\0\x16\x02\0\0\x17\0\0\0\x1a\x02\0\0\x01\0\0\x0c\x25\0\0\0\x38\x11\0\0\
418
+\0\0\0\x01\x01\0\0\0\x08\0\0\x01\0\0\0\0\0\0\0\x03\0\0\0\0\x27\0\0\0\x04\0\0\0\
419
+\x07\0\0\0\x3d\x11\0\0\0\0\0\x0e\x28\0\0\0\x01\0\0\0\x46\x11\0\0\x03\0\0\x0f\0\
420
+\0\0\0\x0e\0\0\0\0\0\0\0\x28\0\0\0\x12\0\0\0\0\0\0\0\x28\0\0\0\x16\0\0\0\0\0\0\
421
+\0\x28\0\0\0\x4c\x11\0\0\x01\0\0\x0f\0\0\0\0\x29\0\0\0\0\0\0\0\x07\0\0\0\x54\
422
+\x11\0\0\0\0\0\x07\0\0\0\0\x62\x11\0\0\0\0\0\x07\0\0\0\0\0\x69\x6e\x74\0\x5f\
423
+\x5f\x41\x52\x52\x41\x59\x5f\x53\x49\x5a\x45\x5f\x54\x59\x50\x45\x5f\x5f\0\x74\
424
+\x79\x70\x65\0\x6b\x65\x79\x5f\x73\x69\x7a\x65\0\x76\x61\x6c\x75\x65\x5f\x73\
425
+\x69\x7a\x65\0\x6d\x61\x78\x5f\x65\x6e\x74\x72\x69\x65\x73\0\x6d\x61\x70\x5f\
426
+\x66\x6c\x61\x67\x73\0\x74\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\x5f\x63\x6f\
427
+\x6e\x66\x69\x67\x75\x72\x61\x74\x69\x6f\x6e\x73\0\x74\x61\x70\x5f\x72\x73\x73\
428
+\x5f\x6d\x61\x70\x5f\x74\x6f\x65\x70\x6c\x69\x74\x7a\x5f\x6b\x65\x79\0\x74\x61\
429
+\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\x5f\x69\x6e\x64\x69\x72\x65\x63\x74\x69\
430
+\x6f\x6e\x5f\x74\x61\x62\x6c\x65\0\x5f\x5f\x73\x6b\x5f\x62\x75\x66\x66\0\x6c\
431
+\x65\x6e\0\x70\x6b\x74\x5f\x74\x79\x70\x65\0\x6d\x61\x72\x6b\0\x71\x75\x65\x75\
432
+\x65\x5f\x6d\x61\x70\x70\x69\x6e\x67\0\x70\x72\x6f\x74\x6f\x63\x6f\x6c\0\x76\
433
+\x6c\x61\x6e\x5f\x70\x72\x65\x73\x65\x6e\x74\0\x76\x6c\x61\x6e\x5f\x74\x63\x69\
434
+\0\x76\x6c\x61\x6e\x5f\x70\x72\x6f\x74\x6f\0\x70\x72\x69\x6f\x72\x69\x74\x79\0\
435
+\x69\x6e\x67\x72\x65\x73\x73\x5f\x69\x66\x69\x6e\x64\x65\x78\0\x69\x66\x69\x6e\
436
+\x64\x65\x78\0\x74\x63\x5f\x69\x6e\x64\x65\x78\0\x63\x62\0\x68\x61\x73\x68\0\
437
+\x74\x63\x5f\x63\x6c\x61\x73\x73\x69\x64\0\x64\x61\x74\x61\0\x64\x61\x74\x61\
438
+\x5f\x65\x6e\x64\0\x6e\x61\x70\x69\x5f\x69\x64\0\x66\x61\x6d\x69\x6c\x79\0\x72\
439
+\x65\x6d\x6f\x74\x65\x5f\x69\x70\x34\0\x6c\x6f\x63\x61\x6c\x5f\x69\x70\x34\0\
440
+\x72\x65\x6d\x6f\x74\x65\x5f\x69\x70\x36\0\x6c\x6f\x63\x61\x6c\x5f\x69\x70\x36\
441
+\0\x72\x65\x6d\x6f\x74\x65\x5f\x70\x6f\x72\x74\0\x6c\x6f\x63\x61\x6c\x5f\x70\
442
+\x6f\x72\x74\0\x64\x61\x74\x61\x5f\x6d\x65\x74\x61\0\x74\x73\x74\x61\x6d\x70\0\
443
+\x77\x69\x72\x65\x5f\x6c\x65\x6e\0\x67\x73\x6f\x5f\x73\x65\x67\x73\0\x67\x73\
444
+\x6f\x5f\x73\x69\x7a\x65\0\x74\x73\x74\x61\x6d\x70\x5f\x74\x79\x70\x65\0\x68\
445
+\x77\x74\x73\x74\x61\x6d\x70\0\x5f\x5f\x75\x33\x32\0\x75\x6e\x73\x69\x67\x6e\
446
+\x65\x64\x20\x69\x6e\x74\0\x66\x6c\x6f\x77\x5f\x6b\x65\x79\x73\0\x5f\x5f\x75\
447
+\x36\x34\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x6c\x6f\x6e\x67\x20\x6c\x6f\x6e\
448
+\x67\0\x73\x6b\0\x5f\x5f\x75\x38\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x63\x68\
449
+\x61\x72\0\x73\x6b\x62\0\x74\x75\x6e\x5f\x72\x73\x73\x5f\x73\x74\x65\x65\x72\
450
+\x69\x6e\x67\x5f\x70\x72\x6f\x67\0\x73\x6f\x63\x6b\x65\x74\0\x2f\x68\x6f\x6d\
451
+\x65\x2f\x61\x6e\x64\x2f\x57\x6f\x72\x6b\x2f\x44\x61\x79\x6e\x69\x78\x2f\x71\
452
+\x65\x6d\x75\x2f\x74\x6f\x6f\x6c\x73\x2f\x65\x62\x70\x66\x2f\x72\x73\x73\x2e\
453
+\x62\x70\x66\x2e\x63\0\x69\x6e\x74\x20\x74\x75\x6e\x5f\x72\x73\x73\x5f\x73\x74\
454
+\x65\x65\x72\x69\x6e\x67\x5f\x70\x72\x6f\x67\x28\x73\x74\x72\x75\x63\x74\x20\
455
+\x5f\x5f\x73\x6b\x5f\x62\x75\x66\x66\x20\x2a\x73\x6b\x62\x29\0\x20\x20\x20\x20\
456
+\x5f\x5f\x75\x33\x32\x20\x6b\x65\x79\x20\x3d\x20\x30\x3b\0\x20\x20\x20\x20\x63\
457
+\x6f\x6e\x66\x69\x67\x20\x3d\x20\x62\x70\x66\x5f\x6d\x61\x70\x5f\x6c\x6f\x6f\
458
+\x6b\x75\x70\x5f\x65\x6c\x65\x6d\x28\x26\x74\x61\x70\x5f\x72\x73\x73\x5f\x6d\
459
+\x61\x70\x5f\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x74\x69\x6f\x6e\x73\x2c\x20\
460
+\x26\x6b\x65\x79\x29\x3b\0\x20\x20\x20\x20\x74\x6f\x65\x20\x3d\x20\x62\x70\x66\
461
+\x5f\x6d\x61\x70\x5f\x6c\x6f\x6f\x6b\x75\x70\x5f\x65\x6c\x65\x6d\x28\x26\x74\
462
\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\x5f\x74\x6f\x65\x70\x6c\x69\x74\x7a\
463
-\x5f\x6b\x65\x79\0\x74\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\x5f\x69\x6e\x64\
464
-\x69\x72\x65\x63\x74\x69\x6f\x6e\x5f\x74\x61\x62\x6c\x65\0\x5f\x5f\x73\x6b\x5f\
465
-\x62\x75\x66\x66\0\x6c\x65\x6e\0\x70\x6b\x74\x5f\x74\x79\x70\x65\0\x6d\x61\x72\
466
-\x6b\0\x71\x75\x65\x75\x65\x5f\x6d\x61\x70\x70\x69\x6e\x67\0\x70\x72\x6f\x74\
467
-\x6f\x63\x6f\x6c\0\x76\x6c\x61\x6e\x5f\x70\x72\x65\x73\x65\x6e\x74\0\x76\x6c\
468
-\x61\x6e\x5f\x74\x63\x69\0\x76\x6c\x61\x6e\x5f\x70\x72\x6f\x74\x6f\0\x70\x72\
469
-\x69\x6f\x72\x69\x74\x79\0\x69\x6e\x67\x72\x65\x73\x73\x5f\x69\x66\x69\x6e\x64\
470
-\x65\x78\0\x69\x66\x69\x6e\x64\x65\x78\0\x74\x63\x5f\x69\x6e\x64\x65\x78\0\x63\
471
-\x62\0\x68\x61\x73\x68\0\x74\x63\x5f\x63\x6c\x61\x73\x73\x69\x64\0\x64\x61\x74\
472
-\x61\0\x64\x61\x74\x61\x5f\x65\x6e\x64\0\x6e\x61\x70\x69\x5f\x69\x64\0\x66\x61\
473
-\x6d\x69\x6c\x79\0\x72\x65\x6d\x6f\x74\x65\x5f\x69\x70\x34\0\x6c\x6f\x63\x61\
474
-\x6c\x5f\x69\x70\x34\0\x72\x65\x6d\x6f\x74\x65\x5f\x69\x70\x36\0\x6c\x6f\x63\
475
-\x61\x6c\x5f\x69\x70\x36\0\x72\x65\x6d\x6f\x74\x65\x5f\x70\x6f\x72\x74\0\x6c\
476
-\x6f\x63\x61\x6c\x5f\x70\x6f\x72\x74\0\x64\x61\x74\x61\x5f\x6d\x65\x74\x61\0\
477
-\x74\x73\x74\x61\x6d\x70\0\x77\x69\x72\x65\x5f\x6c\x65\x6e\0\x67\x73\x6f\x5f\
478
-\x73\x65\x67\x73\0\x67\x73\x6f\x5f\x73\x69\x7a\x65\0\x74\x73\x74\x61\x6d\x70\
479
-\x5f\x74\x79\x70\x65\0\x68\x77\x74\x73\x74\x61\x6d\x70\0\x5f\x5f\x75\x33\x32\0\
480
-\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\x74\0\x66\x6c\x6f\x77\x5f\x6b\x65\
481
-\x79\x73\0\x5f\x5f\x75\x36\x34\0\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x6c\x6f\
482
-\x6e\x67\x20\x6c\x6f\x6e\x67\0\x73\x6b\0\x5f\x5f\x75\x38\0\x75\x6e\x73\x69\x67\
483
-\x6e\x65\x64\x20\x63\x68\x61\x72\0\x73\x6b\x62\0\x74\x75\x6e\x5f\x72\x73\x73\
484
-\x5f\x73\x74\x65\x65\x72\x69\x6e\x67\x5f\x70\x72\x6f\x67\0\x74\x75\x6e\x5f\x72\
485
-\x73\x73\x5f\x73\x74\x65\x65\x72\x69\x6e\x67\0\x2f\x68\x6f\x6d\x65\x2f\x73\x68\
486
-\x72\x65\x65\x73\x68\x2f\x63\x2f\x71\x65\x6d\x75\x2f\x74\x6f\x6f\x6c\x73\x2f\
487
-\x65\x62\x70\x66\x2f\x72\x73\x73\x2e\x62\x70\x66\x2e\x63\0\x69\x6e\x74\x20\x74\
488
-\x75\x6e\x5f\x72\x73\x73\x5f\x73\x74\x65\x65\x72\x69\x6e\x67\x5f\x70\x72\x6f\
489
-\x67\x28\x73\x74\x72\x75\x63\x74\x20\x5f\x5f\x73\x6b\x5f\x62\x75\x66\x66\x20\
490
-\x2a\x73\x6b\x62\x29\0\x20\x20\x20\x20\x5f\x5f\x75\x33\x32\x20\x6b\x65\x79\x20\
491
-\x3d\x20\x30\x3b\0\x20\x20\x20\x20\x63\x6f\x6e\x66\x69\x67\x20\x3d\x20\x62\x70\
492
-\x66\x5f\x6d\x61\x70\x5f\x6c\x6f\x6f\x6b\x75\x70\x5f\x65\x6c\x65\x6d\x28\x26\
493
-\x74\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\x5f\x63\x6f\x6e\x66\x69\x67\x75\
494
-\x72\x61\x74\x69\x6f\x6e\x73\x2c\x20\x26\x6b\x65\x79\x29\x3b\0\x20\x20\x20\x20\
495
-\x74\x6f\x65\x20\x3d\x20\x62\x70\x66\x5f\x6d\x61\x70\x5f\x6c\x6f\x6f\x6b\x75\
496
-\x70\x5f\x65\x6c\x65\x6d\x28\x26\x74\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\
497
-\x5f\x74\x6f\x65\x70\x6c\x69\x74\x7a\x5f\x6b\x65\x79\x2c\x20\x26\x6b\x65\x79\
498
-\x29\x3b\0\x20\x20\x20\x20\x69\x66\x20\x28\x63\x6f\x6e\x66\x69\x67\x20\x26\x26\
499
-\x20\x74\x6f\x65\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\
500
-\x21\x63\x6f\x6e\x66\x69\x67\x2d\x3e\x72\x65\x64\x69\x72\x65\x63\x74\x29\x20\
501
-\x7b\0\x20\x20\x20\x20\x5f\x5f\x75\x38\x20\x72\x73\x73\x5f\x69\x6e\x70\x75\x74\
502
-\x5b\x48\x41\x53\x48\x5f\x43\x41\x4c\x43\x55\x4c\x41\x54\x49\x4f\x4e\x5f\x42\
503
-\x55\x46\x46\x45\x52\x5f\x53\x49\x5a\x45\x5d\x20\x3d\x20\x7b\x7d\x3b\0\x20\x20\
504
-\x20\x20\x73\x74\x72\x75\x63\x74\x20\x70\x61\x63\x6b\x65\x74\x5f\x68\x61\x73\
505
-\x68\x5f\x69\x6e\x66\x6f\x5f\x74\x20\x70\x61\x63\x6b\x65\x74\x5f\x69\x6e\x66\
506
-\x6f\x20\x3d\x20\x7b\x7d\x3b\0\x20\x20\x20\x20\x69\x66\x20\x28\x21\x69\x6e\x66\
507
-\x6f\x20\x7c\x7c\x20\x21\x73\x6b\x62\x29\x20\x7b\0\x20\x20\x20\x20\x5f\x5f\x62\
508
-\x65\x31\x36\x20\x72\x65\x74\x20\x3d\x20\x30\x3b\0\x20\x20\x20\x20\x65\x72\x72\
509
-\x20\x3d\x20\x62\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\x79\x74\
510
-\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\x20\x6f\x66\
511
-\x66\x73\x65\x74\x2c\x20\x26\x72\x65\x74\x2c\x20\x73\x69\x7a\x65\x6f\x66\x28\
512
-\x72\x65\x74\x29\x2c\0\x20\x20\x20\x20\x69\x66\x20\x28\x65\x72\x72\x29\x20\x7b\
513
-\0\x20\x20\x20\x20\x73\x77\x69\x74\x63\x68\x20\x28\x62\x70\x66\x5f\x6e\x74\x6f\
514
-\x68\x73\x28\x72\x65\x74\x29\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\x65\
515
-\x72\x72\x20\x3d\x20\x62\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\
516
-\x79\x74\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\x20\
517
-\x6f\x66\x66\x73\x65\x74\x2c\x20\x26\x72\x65\x74\x2c\x20\x73\x69\x7a\x65\x6f\
518
-\x66\x28\x72\x65\x74\x29\x2c\0\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x72\
519
-\x65\x74\x3b\0\x20\x20\x20\x20\x69\x66\x20\x28\x6c\x33\x5f\x70\x72\x6f\x74\x6f\
520
-\x63\x6f\x6c\x20\x3d\x3d\x20\x30\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\
521
-\x69\x6e\x66\x6f\x2d\x3e\x69\x73\x5f\x69\x70\x76\x34\x20\x3d\x20\x31\x3b\0\x20\
522
-\x20\x20\x20\x20\x20\x20\x20\x73\x74\x72\x75\x63\x74\x20\x69\x70\x68\x64\x72\
523
-\x20\x69\x70\x20\x3d\x20\x7b\x7d\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x65\x72\
524
-\x72\x20\x3d\x20\x62\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\x79\
525
-\x74\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\x20\x30\
526
-\x2c\x20\x26\x69\x70\x2c\x20\x73\x69\x7a\x65\x6f\x66\x28\x69\x70\x29\x2c\0\x20\
527
-\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\x65\x72\x72\x29\x20\x7b\0\x20\x20\
528
-\x20\x20\x20\x20\x20\x20\x69\x6e\x66\x6f\x2d\x3e\x69\x73\x5f\x66\x72\x61\x67\
529
-\x6d\x65\x6e\x74\x65\x64\x20\x3d\x20\x21\x21\x69\x70\x2e\x66\x72\x61\x67\x5f\
530
-\x6f\x66\x66\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x66\x6f\x2d\x3e\x69\
531
-\x6e\x5f\x73\x72\x63\x20\x3d\x20\x69\x70\x2e\x73\x61\x64\x64\x72\x3b\0\x20\x20\
532
-\x20\x20\x20\x20\x20\x20\x69\x6e\x66\x6f\x2d\x3e\x69\x6e\x5f\x64\x73\x74\x20\
533
-\x3d\x20\x69\x70\x2e\x64\x61\x64\x64\x72\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\
534
-\x6c\x34\x5f\x70\x72\x6f\x74\x6f\x63\x6f\x6c\x20\x3d\x20\x69\x70\x2e\x70\x72\
535
-\x6f\x74\x6f\x63\x6f\x6c\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x6c\x34\x5f\x6f\
536
-\x66\x66\x73\x65\x74\x20\x3d\x20\x69\x70\x2e\x69\x68\x6c\x20\x2a\x20\x34\x3b\0\
537
-\x20\x20\x20\x20\x69\x66\x20\x28\x6c\x34\x5f\x70\x72\x6f\x74\x6f\x63\x6f\x6c\
538
-\x20\x21\x3d\x20\x30\x20\x26\x26\x20\x21\x69\x6e\x66\x6f\x2d\x3e\x69\x73\x5f\
539
-\x66\x72\x61\x67\x6d\x65\x6e\x74\x65\x64\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\
540
-\x20\x20\x69\x66\x20\x28\x6c\x34\x5f\x70\x72\x6f\x74\x6f\x63\x6f\x6c\x20\x3d\
541
-\x3d\x20\x49\x50\x50\x52\x4f\x54\x4f\x5f\x54\x43\x50\x29\x20\x7b\0\x20\x20\x20\
542
-\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x66\x6f\x2d\x3e\x69\x73\x5f\x74\
543
-\x63\x70\x20\x3d\x20\x31\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
544
-\x73\x74\x72\x75\x63\x74\x20\x74\x63\x70\x68\x64\x72\x20\x74\x63\x70\x20\x3d\
545
-\x20\x7b\x7d\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x65\x72\x72\
546
-\x20\x3d\x20\x62\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\x79\x74\
547
-\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\x20\x6c\x34\
548
-\x5f\x6f\x66\x66\x73\x65\x74\x2c\x20\x26\x74\x63\x70\x2c\x20\x73\x69\x7a\x65\
549
-\x6f\x66\x28\x74\x63\x70\x29\x2c\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
550
-\x20\x69\x66\x20\x28\x65\x72\x72\x29\x20\x7b\0\x20\x20\x20\x20\x69\x66\x20\x28\
551
-\x70\x61\x63\x6b\x65\x74\x5f\x69\x6e\x66\x6f\x2e\x69\x73\x5f\x69\x70\x76\x34\
552
-\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\x70\x61\x63\x6b\
553
-\x65\x74\x5f\x69\x6e\x66\x6f\x2e\x69\x73\x5f\x74\x63\x70\x20\x26\x26\0\x20\x20\
554
-\x20\x20\x20\x20\x20\x20\x69\x6e\x66\x6f\x2d\x3e\x69\x73\x5f\x69\x70\x76\x36\
555
-\x20\x3d\x20\x31\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x72\x75\x63\x74\
556
-\x20\x69\x70\x76\x36\x68\x64\x72\x20\x69\x70\x36\x20\x3d\x20\x7b\x7d\x3b\0\x20\
557
-\x20\x20\x20\x20\x20\x20\x20\x65\x72\x72\x20\x3d\x20\x62\x70\x66\x5f\x73\x6b\
558
+\x5f\x6b\x65\x79\x2c\x20\x26\x6b\x65\x79\x29\x3b\0\x20\x20\x20\x20\x69\x66\x20\
559
+\x28\x63\x6f\x6e\x66\x69\x67\x20\x26\x26\x20\x74\x6f\x65\x29\x20\x7b\0\x20\x20\
560
+\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\x21\x63\x6f\x6e\x66\x69\x67\x2d\x3e\
561
+\x72\x65\x64\x69\x72\x65\x63\x74\x29\x20\x7b\0\x20\x20\x20\x20\x5f\x5f\x75\x38\
562
+\x20\x72\x73\x73\x5f\x69\x6e\x70\x75\x74\x5b\x48\x41\x53\x48\x5f\x43\x41\x4c\
563
+\x43\x55\x4c\x41\x54\x49\x4f\x4e\x5f\x42\x55\x46\x46\x45\x52\x5f\x53\x49\x5a\
564
+\x45\x5d\x20\x3d\x20\x7b\x7d\x3b\0\x20\x20\x20\x20\x73\x74\x72\x75\x63\x74\x20\
565
+\x70\x61\x63\x6b\x65\x74\x5f\x68\x61\x73\x68\x5f\x69\x6e\x66\x6f\x5f\x74\x20\
566
+\x70\x61\x63\x6b\x65\x74\x5f\x69\x6e\x66\x6f\x20\x3d\x20\x7b\x7d\x3b\0\x20\x20\
567
+\x20\x20\x69\x66\x20\x28\x21\x69\x6e\x66\x6f\x20\x7c\x7c\x20\x21\x73\x6b\x62\
568
+\x29\x20\x7b\0\x20\x20\x20\x20\x5f\x5f\x62\x65\x31\x36\x20\x72\x65\x74\x20\x3d\
569
+\x20\x30\x3b\0\x20\x20\x20\x20\x65\x72\x72\x20\x3d\x20\x62\x70\x66\x5f\x73\x6b\
570
\x62\x5f\x6c\x6f\x61\x64\x5f\x62\x79\x74\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\
571
-\x76\x65\x28\x73\x6b\x62\x2c\x20\x30\x2c\x20\x26\x69\x70\x36\x2c\x20\x73\x69\
572
-\x7a\x65\x6f\x66\x28\x69\x70\x36\x29\x2c\0\x20\x20\x20\x20\x20\x20\x20\x20\x69\
573
-\x6e\x66\x6f\x2d\x3e\x69\x6e\x36\x5f\x73\x72\x63\x20\x3d\x20\x69\x70\x36\x2e\
574
-\x73\x61\x64\x64\x72\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x66\x6f\x2d\
575
-\x3e\x69\x6e\x36\x5f\x64\x73\x74\x20\x3d\x20\x69\x70\x36\x2e\x64\x61\x64\x64\
576
+\x76\x65\x28\x73\x6b\x62\x2c\x20\x6f\x66\x66\x73\x65\x74\x2c\x20\x26\x72\x65\
577
+\x74\x2c\x20\x73\x69\x7a\x65\x6f\x66\x28\x72\x65\x74\x29\x2c\0\x20\x20\x20\x20\
578
+\x69\x66\x20\x28\x65\x72\x72\x29\x20\x7b\0\x20\x20\x20\x20\x73\x77\x69\x74\x63\
579
+\x68\x20\x28\x62\x70\x66\x5f\x6e\x74\x6f\x68\x73\x28\x72\x65\x74\x29\x29\x20\
580
+\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\x65\x72\x72\x20\x3d\x20\x62\x70\x66\x5f\
581
+\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\x79\x74\x65\x73\x5f\x72\x65\x6c\x61\
582
+\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\x20\x6f\x66\x66\x73\x65\x74\x2c\x20\x26\
583
+\x72\x65\x74\x2c\x20\x73\x69\x7a\x65\x6f\x66\x28\x72\x65\x74\x29\x2c\0\x20\x20\
584
+\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x72\x65\x74\x3b\0\x20\x20\x20\x20\x69\x66\
585
+\x20\x28\x6c\x33\x5f\x70\x72\x6f\x74\x6f\x63\x6f\x6c\x20\x3d\x3d\x20\x30\x29\
586
+\x20\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x66\x6f\x2d\x3e\x69\x73\x5f\
587
+\x69\x70\x76\x34\x20\x3d\x20\x31\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\
588
+\x72\x75\x63\x74\x20\x69\x70\x68\x64\x72\x20\x69\x70\x20\x3d\x20\x7b\x7d\x3b\0\
589
+\x20\x20\x20\x20\x20\x20\x20\x20\x65\x72\x72\x20\x3d\x20\x62\x70\x66\x5f\x73\
590
+\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\x79\x74\x65\x73\x5f\x72\x65\x6c\x61\x74\
591
+\x69\x76\x65\x28\x73\x6b\x62\x2c\x20\x30\x2c\x20\x26\x69\x70\x2c\x20\x73\x69\
592
+\x7a\x65\x6f\x66\x28\x69\x70\x29\x2c\0\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\
593
+\x20\x28\x65\x72\x72\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x66\
594
+\x6f\x2d\x3e\x69\x73\x5f\x66\x72\x61\x67\x6d\x65\x6e\x74\x65\x64\x20\x3d\x20\
595
+\x21\x21\x69\x70\x2e\x66\x72\x61\x67\x5f\x6f\x66\x66\x3b\0\x20\x20\x20\x20\x20\
596
+\x20\x20\x20\x69\x6e\x66\x6f\x2d\x3e\x69\x6e\x5f\x73\x72\x63\x20\x3d\x20\x69\
597
+\x70\x2e\x73\x61\x64\x64\x72\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x66\
598
+\x6f\x2d\x3e\x69\x6e\x5f\x64\x73\x74\x20\x3d\x20\x69\x70\x2e\x64\x61\x64\x64\
599
\x72\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x6c\x34\x5f\x70\x72\x6f\x74\x6f\x63\
600
-\x6f\x6c\x20\x3d\x20\x69\x70\x36\x2e\x6e\x65\x78\x74\x68\x64\x72\x3b\0\x20\x20\
601
-\x20\x20\x73\x77\x69\x74\x63\x68\x20\x28\x68\x64\x72\x5f\x74\x79\x70\x65\x29\
602
-\x20\x7b\0\x20\x20\x20\x20\x73\x74\x72\x75\x63\x74\x20\x69\x70\x76\x36\x5f\x6f\
603
-\x70\x74\x5f\x68\x64\x72\x20\x65\x78\x74\x5f\x68\x64\x72\x20\x3d\x20\x7b\x7d\
604
-\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x65\x72\x72\x20\x3d\x20\x62\x70\x66\x5f\
605
+\x6f\x6c\x20\x3d\x20\x69\x70\x2e\x70\x72\x6f\x74\x6f\x63\x6f\x6c\x3b\0\x20\x20\
606
+\x20\x20\x20\x20\x20\x20\x6c\x34\x5f\x6f\x66\x66\x73\x65\x74\x20\x3d\x20\x69\
607
+\x70\x2e\x69\x68\x6c\x20\x2a\x20\x34\x3b\0\x20\x20\x20\x20\x69\x66\x20\x28\x6c\
608
+\x34\x5f\x70\x72\x6f\x74\x6f\x63\x6f\x6c\x20\x21\x3d\x20\x30\x20\x26\x26\x20\
609
+\x21\x69\x6e\x66\x6f\x2d\x3e\x69\x73\x5f\x66\x72\x61\x67\x6d\x65\x6e\x74\x65\
610
+\x64\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\x6c\x34\x5f\
611
+\x70\x72\x6f\x74\x6f\x63\x6f\x6c\x20\x3d\x3d\x20\x49\x50\x50\x52\x4f\x54\x4f\
612
+\x5f\x54\x43\x50\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
613
+\x69\x6e\x66\x6f\x2d\x3e\x69\x73\x5f\x74\x63\x70\x20\x3d\x20\x31\x3b\0\x20\x20\
614
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x72\x75\x63\x74\x20\x74\x63\
615
+\x70\x68\x64\x72\x20\x74\x63\x70\x20\x3d\x20\x7b\x7d\x3b\0\x20\x20\x20\x20\x20\
616
+\x20\x20\x20\x20\x20\x20\x20\x65\x72\x72\x20\x3d\x20\x62\x70\x66\x5f\x73\x6b\
617
+\x62\x5f\x6c\x6f\x61\x64\x5f\x62\x79\x74\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\
618
+\x76\x65\x28\x73\x6b\x62\x2c\x20\x6c\x34\x5f\x6f\x66\x66\x73\x65\x74\x2c\x20\
619
+\x26\x74\x63\x70\x2c\x20\x73\x69\x7a\x65\x6f\x66\x28\x74\x63\x70\x29\x2c\0\x20\
620
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\x65\x72\x72\x29\
621
+\x20\x7b\0\x20\x20\x20\x20\x69\x66\x20\x28\x70\x61\x63\x6b\x65\x74\x5f\x69\x6e\
622
+\x66\x6f\x2e\x69\x73\x5f\x69\x70\x76\x34\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\
623
+\x20\x20\x69\x66\x20\x28\x70\x61\x63\x6b\x65\x74\x5f\x69\x6e\x66\x6f\x2e\x69\
624
+\x73\x5f\x74\x63\x70\x20\x26\x26\0\x20\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x66\
625
+\x6f\x2d\x3e\x69\x73\x5f\x69\x70\x76\x36\x20\x3d\x20\x31\x3b\0\x20\x20\x20\x20\
626
+\x20\x20\x20\x20\x73\x74\x72\x75\x63\x74\x20\x69\x70\x76\x36\x68\x64\x72\x20\
627
+\x69\x70\x36\x20\x3d\x20\x7b\x7d\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x65\x72\
628
+\x72\x20\x3d\x20\x62\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\x79\
629
+\x74\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\x20\x30\
630
+\x2c\x20\x26\x69\x70\x36\x2c\x20\x73\x69\x7a\x65\x6f\x66\x28\x69\x70\x36\x29\
631
+\x2c\0\x20\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x66\x6f\x2d\x3e\x69\x6e\x36\x5f\
632
+\x73\x72\x63\x20\x3d\x20\x69\x70\x36\x2e\x73\x61\x64\x64\x72\x3b\0\x20\x20\x20\
633
+\x20\x20\x20\x20\x20\x69\x6e\x66\x6f\x2d\x3e\x69\x6e\x36\x5f\x64\x73\x74\x20\
634
+\x3d\x20\x69\x70\x36\x2e\x64\x61\x64\x64\x72\x3b\0\x20\x20\x20\x20\x20\x20\x20\
635
+\x20\x6c\x34\x5f\x70\x72\x6f\x74\x6f\x63\x6f\x6c\x20\x3d\x20\x69\x70\x36\x2e\
636
+\x6e\x65\x78\x74\x68\x64\x72\x3b\0\x20\x20\x20\x20\x73\x77\x69\x74\x63\x68\x20\
637
+\x28\x68\x64\x72\x5f\x74\x79\x70\x65\x29\x20\x7b\0\x20\x20\x20\x20\x73\x74\x72\
638
+\x75\x63\x74\x20\x69\x70\x76\x36\x5f\x6f\x70\x74\x5f\x68\x64\x72\x20\x65\x78\
639
+\x74\x5f\x68\x64\x72\x20\x3d\x20\x7b\x7d\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\
640
+\x65\x72\x72\x20\x3d\x20\x62\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\
641
+\x62\x79\x74\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\
642
+\x20\x2a\x6c\x34\x5f\x6f\x66\x66\x73\x65\x74\x2c\x20\x26\x65\x78\x74\x5f\x68\
643
+\x64\x72\x2c\0\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\x2a\x6c\x34\x5f\
644
+\x70\x72\x6f\x74\x6f\x63\x6f\x6c\x20\x3d\x3d\x20\x49\x50\x50\x52\x4f\x54\x4f\
645
+\x5f\x52\x4f\x55\x54\x49\x4e\x47\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\
646
+\x20\x20\x20\x20\x73\x74\x72\x75\x63\x74\x20\x69\x70\x76\x36\x5f\x72\x74\x5f\
647
+\x68\x64\x72\x20\x65\x78\x74\x5f\x72\x74\x20\x3d\x20\x7b\x7d\x3b\0\x20\x20\x20\
648
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x65\x72\x72\x20\x3d\x20\x62\x70\x66\x5f\
649
\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\x79\x74\x65\x73\x5f\x72\x65\x6c\x61\
650
\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\x20\x2a\x6c\x34\x5f\x6f\x66\x66\x73\x65\
651
-\x74\x2c\x20\x26\x65\x78\x74\x5f\x68\x64\x72\x2c\0\x20\x20\x20\x20\x20\x20\x20\
652
-\x20\x69\x66\x20\x28\x2a\x6c\x34\x5f\x70\x72\x6f\x74\x6f\x63\x6f\x6c\x20\x3d\
653
-\x3d\x20\x49\x50\x50\x52\x4f\x54\x4f\x5f\x52\x4f\x55\x54\x49\x4e\x47\x29\x20\
654
-\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x72\x75\x63\x74\
655
-\x20\x69\x70\x76\x36\x5f\x72\x74\x5f\x68\x64\x72\x20\x65\x78\x74\x5f\x72\x74\
656
-\x20\x3d\x20\x7b\x7d\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x65\
657
-\x72\x72\x20\x3d\x20\x62\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\
658
-\x79\x74\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\x20\
659
-\x2a\x6c\x34\x5f\x6f\x66\x66\x73\x65\x74\x2c\x20\x26\x65\x78\x74\x5f\x72\x74\
660
-\x2c\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\x28\x65\
661
-\x78\x74\x5f\x72\x74\x2e\x74\x79\x70\x65\x20\x3d\x3d\x20\x49\x50\x56\x36\x5f\
662
-\x53\x52\x43\x52\x54\x5f\x54\x59\x50\x45\x5f\x32\x29\x20\x26\x26\0\x20\x20\x20\
663
-\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2a\x6c\
664
-\x34\x5f\x6f\x66\x66\x73\x65\x74\x20\x2b\x20\x6f\x66\x66\x73\x65\x74\x6f\x66\
665
-\x28\x73\x74\x72\x75\x63\x74\x20\x72\x74\x32\x5f\x68\x64\x72\x2c\x20\x61\x64\
666
-\x64\x72\x29\x2c\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
667
-\x20\x65\x72\x72\x20\x3d\x20\x62\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\x64\
668
-\x5f\x62\x79\x74\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\x76\x65\x28\x73\x6b\x62\
669
-\x2c\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\
670
-\x20\x28\x65\x72\x72\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
671
-\x20\x20\x20\x20\x20\x69\x6e\x66\x6f\x2d\x3e\x69\x73\x5f\x69\x70\x76\x36\x5f\
672
-\x65\x78\x74\x5f\x64\x73\x74\x20\x3d\x20\x31\x3b\0\x20\x20\x20\x20\x20\x20\x20\
673
-\x20\x20\x20\x20\x20\x7d\x20\x5f\x5f\x61\x74\x74\x72\x69\x62\x75\x74\x65\x5f\
674
-\x5f\x28\x28\x70\x61\x63\x6b\x65\x64\x29\x29\x20\x6f\x70\x74\x20\x3d\x20\x7b\
675
-\x7d\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\
676
-\x70\x74\x5f\x6f\x66\x66\x73\x65\x74\x20\x2b\x3d\x20\x28\x6f\x70\x74\x2e\x74\
677
-\x79\x70\x65\x20\x3d\x3d\x20\x49\x50\x56\x36\x5f\x54\x4c\x56\x5f\x50\x41\x44\
678
-\x31\x29\x20\x3f\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
679
-\x20\x69\x66\x20\x28\x6f\x70\x74\x5f\x6f\x66\x66\x73\x65\x74\x20\x2b\x20\x31\
680
-\x20\x3e\x3d\x20\x65\x78\x74\x5f\x68\x64\x72\x2e\x68\x64\x72\x6c\x65\x6e\x20\
681
-\x2a\x20\x38\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
682
-\x20\x20\x20\x65\x72\x72\x20\x3d\x20\x62\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\
683
-\x61\x64\x5f\x62\x79\x74\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\x76\x65\x28\x73\
684
-\x6b\x62\x2c\x20\x2a\x6c\x34\x5f\x6f\x66\x66\x73\x65\x74\x20\x2b\x20\x6f\x70\
685
-\x74\x5f\x6f\x66\x66\x73\x65\x74\x2c\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
686
-\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\x6f\x70\x74\x2e\x74\x79\x70\x65\x20\
687
-\x3d\x3d\x20\x49\x50\x56\x36\x5f\x54\x4c\x56\x5f\x48\x41\x4f\x29\x20\x7b\0\x20\
688
+\x74\x2c\x20\x26\x65\x78\x74\x5f\x72\x74\x2c\0\x20\x20\x20\x20\x20\x20\x20\x20\
689
+\x20\x20\x20\x20\x69\x66\x20\x28\x28\x65\x78\x74\x5f\x72\x74\x2e\x74\x79\x70\
690
+\x65\x20\x3d\x3d\x20\x49\x50\x56\x36\x5f\x53\x52\x43\x52\x54\x5f\x54\x59\x50\
691
+\x45\x5f\x32\x29\x20\x26\x26\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
692
+\x20\x20\x20\x20\x20\x20\x20\x20\x2a\x6c\x34\x5f\x6f\x66\x66\x73\x65\x74\x20\
693
+\x2b\x20\x6f\x66\x66\x73\x65\x74\x6f\x66\x28\x73\x74\x72\x75\x63\x74\x20\x72\
694
+\x74\x32\x5f\x68\x64\x72\x2c\x20\x61\x64\x64\x72\x29\x2c\0\x20\x20\x20\x20\x20\
695
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x65\x72\x72\x20\x3d\x20\x62\x70\
696
+\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\x79\x74\x65\x73\x5f\x72\x65\
697
+\x6c\x61\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\0\x20\x20\x20\x20\x20\x20\x20\x20\
698
+\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\x65\x72\x72\x29\x20\x7b\0\x20\
699
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x66\x6f\
700
+\x2d\x3e\x69\x73\x5f\x69\x70\x76\x36\x5f\x65\x78\x74\x5f\x64\x73\x74\x20\x3d\
701
+\x20\x31\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x7d\x20\x5f\x5f\
702
+\x61\x74\x74\x72\x69\x62\x75\x74\x65\x5f\x5f\x28\x28\x70\x61\x63\x6b\x65\x64\
703
+\x29\x29\x20\x6f\x70\x74\x20\x3d\x20\x7b\x7d\x3b\0\x20\x20\x20\x20\x20\x20\x20\
704
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x70\x74\x5f\x6f\x66\x66\x73\x65\x74\
705
+\x20\x2b\x3d\x20\x28\x6f\x70\x74\x2e\x74\x79\x70\x65\x20\x3d\x3d\x20\x49\x50\
706
+\x56\x36\x5f\x54\x4c\x56\x5f\x50\x41\x44\x31\x29\x20\x3f\0\x20\x20\x20\x20\x20\
707
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\x6f\x70\x74\x5f\
708
+\x6f\x66\x66\x73\x65\x74\x20\x2b\x20\x31\x20\x3e\x3d\x20\x65\x78\x74\x5f\x68\
709
+\x64\x72\x2e\x68\x64\x72\x6c\x65\x6e\x20\x2a\x20\x38\x29\x20\x7b\0\x20\x20\x20\
710
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x65\x72\x72\x20\x3d\x20\
711
+\x62\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\x79\x74\x65\x73\x5f\
712
+\x72\x65\x6c\x61\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\x20\x2a\x6c\x34\x5f\x6f\
713
+\x66\x66\x73\x65\x74\x20\x2b\x20\x6f\x70\x74\x5f\x6f\x66\x66\x73\x65\x74\x2c\0\
714
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\
715
+\x28\x6f\x70\x74\x2e\x74\x79\x70\x65\x20\x3d\x3d\x20\x49\x50\x56\x36\x5f\x54\
716
+\x4c\x56\x5f\x48\x41\x4f\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
717
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2a\x6c\x34\x5f\x6f\
718
+\x66\x66\x73\x65\x74\x20\x2b\x20\x6f\x70\x74\x5f\x6f\x66\x66\x73\x65\x74\0\x20\
719
\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
720
-\x20\x20\x20\x20\x2a\x6c\x34\x5f\x6f\x66\x66\x73\x65\x74\x20\x2b\x20\x6f\x70\
721
-\x74\x5f\x6f\x66\x66\x73\x65\x74\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
722
-\x20\x20\x20\x20\x20\x20\x20\x20\x20\x65\x72\x72\x20\x3d\x20\x62\x70\x66\x5f\
723
-\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\x79\x74\x65\x73\x5f\x72\x65\x6c\x61\
724
-\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
725
-\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\x65\x72\x72\x29\x20\
726
-\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
727
-\x20\x20\x69\x6e\x66\x6f\x2d\x3e\x69\x73\x5f\x69\x70\x76\x36\x5f\x65\x78\x74\
728
-\x5f\x73\x72\x63\x20\x3d\x20\x31\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
729
-\x20\x20\x69\x6e\x66\x6f\x2d\x3e\x69\x73\x5f\x66\x72\x61\x67\x6d\x65\x6e\x74\
730
-\x65\x64\x20\x3d\x20\x74\x72\x75\x65\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x2a\
731
-\x6c\x34\x5f\x6f\x66\x66\x73\x65\x74\x20\x2b\x3d\x20\x28\x65\x78\x74\x5f\x68\
732
-\x64\x72\x2e\x68\x64\x72\x6c\x65\x6e\x20\x2b\x20\x31\x29\x20\x2a\x20\x38\x3b\0\
733
-\x20\x20\x20\x20\x20\x20\x20\x20\x2a\x6c\x34\x5f\x70\x72\x6f\x74\x6f\x63\x6f\
734
-\x6c\x20\x3d\x20\x65\x78\x74\x5f\x68\x64\x72\x2e\x6e\x65\x78\x74\x68\x64\x72\
735
-\x3b\0\x20\x20\x20\x20\x66\x6f\x72\x20\x28\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\
736
-\x69\x6e\x74\x20\x69\x20\x3d\x20\x30\x3b\x20\x69\x20\x3c\x20\x49\x50\x36\x5f\
737
-\x45\x58\x54\x45\x4e\x53\x49\x4f\x4e\x53\x5f\x43\x4f\x55\x4e\x54\x3b\x20\x2b\
738
-\x2b\x69\x29\x20\x7b\0\x20\x20\x20\x20\x7d\x20\x65\x6c\x73\x65\x20\x69\x66\x20\
739
-\x28\x70\x61\x63\x6b\x65\x74\x5f\x69\x6e\x66\x6f\x2e\x69\x73\x5f\x69\x70\x76\
740
-\x36\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\
741
-\x28\x70\x61\x63\x6b\x65\x74\x5f\x69\x6e\x66\x6f\x2e\x69\x73\x5f\x69\x70\x76\
742
-\x36\x5f\x65\x78\x74\x5f\x64\x73\x74\x20\x26\x26\0\x20\x20\x20\x20\x20\x20\x20\
743
-\x20\x20\x20\x20\x20\x69\x66\x20\x28\x70\x61\x63\x6b\x65\x74\x5f\x69\x6e\x66\
744
-\x6f\x2e\x69\x73\x5f\x69\x70\x76\x36\x5f\x65\x78\x74\x5f\x73\x72\x63\x20\x26\
745
-\x26\0\x20\x20\x20\x20\x20\x20\x20\x20\x7d\x20\x65\x6c\x73\x65\x20\x69\x66\x20\
746
-\x28\x70\x61\x63\x6b\x65\x74\x5f\x69\x6e\x66\x6f\x2e\x69\x73\x5f\x75\x64\x70\
747
-\x20\x26\x26\0\x20\x20\x20\x20\x20\x20\x20\x20\x7d\x20\x65\x6c\x73\x65\x20\x69\
748
-\x66\x20\x28\x63\x6f\x6e\x66\x69\x67\x2d\x3e\x68\x61\x73\x68\x5f\x74\x79\x70\
749
-\x65\x73\x20\x26\x20\x56\x49\x52\x54\x49\x4f\x5f\x4e\x45\x54\x5f\x52\x53\x53\
750
-\x5f\x48\x41\x53\x48\x5f\x54\x59\x50\x45\x5f\x49\x50\x76\x34\x29\x20\x7b\0\x20\
751
-\x20\x20\x20\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x5f\x6d\x65\x6d\x63\x70\x79\
752
-\x28\x26\x72\x73\x73\x5f\x69\x6e\x70\x75\x74\x5b\x2a\x62\x79\x74\x65\x73\x5f\
753
-\x77\x72\x69\x74\x74\x65\x6e\x5d\x2c\x20\x70\x74\x72\x2c\x20\x73\x69\x7a\x65\
754
-\x29\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x66\x6f\x2d\
755
-\x3e\x69\x73\x5f\x75\x64\x70\x20\x3d\x20\x31\x3b\0\x20\x20\x20\x20\x20\x20\x20\
756
-\x20\x20\x20\x20\x20\x73\x74\x72\x75\x63\x74\x20\x75\x64\x70\x68\x64\x72\x20\
757
-\x75\x64\x70\x20\x3d\x20\x7b\x7d\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
758
-\x20\x20\x65\x72\x72\x20\x3d\x20\x62\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\
759
-\x64\x5f\x62\x79\x74\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\x76\x65\x28\x73\x6b\
760
-\x62\x2c\x20\x6c\x34\x5f\x6f\x66\x66\x73\x65\x74\x2c\x20\x26\x75\x64\x70\x2c\
761
-\x20\x73\x69\x7a\x65\x6f\x66\x28\x75\x64\x70\x29\x2c\0\x20\x20\x20\x20\x20\x20\
762
+\x65\x72\x72\x20\x3d\x20\x62\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\
763
+\x62\x79\x74\x65\x73\x5f\x72\x65\x6c\x61\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\0\
764
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
765
+\x20\x69\x66\x20\x28\x65\x72\x72\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\
766
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x66\x6f\x2d\x3e\x69\
767
+\x73\x5f\x69\x70\x76\x36\x5f\x65\x78\x74\x5f\x73\x72\x63\x20\x3d\x20\x31\x3b\0\
768
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x6e\x66\x6f\x2d\x3e\x69\
769
+\x73\x5f\x66\x72\x61\x67\x6d\x65\x6e\x74\x65\x64\x20\x3d\x20\x74\x72\x75\x65\
770
+\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x2a\x6c\x34\x5f\x6f\x66\x66\x73\x65\x74\
771
+\x20\x2b\x3d\x20\x28\x65\x78\x74\x5f\x68\x64\x72\x2e\x68\x64\x72\x6c\x65\x6e\
772
+\x20\x2b\x20\x31\x29\x20\x2a\x20\x38\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x2a\
773
+\x6c\x34\x5f\x70\x72\x6f\x74\x6f\x63\x6f\x6c\x20\x3d\x20\x65\x78\x74\x5f\x68\
774
+\x64\x72\x2e\x6e\x65\x78\x74\x68\x64\x72\x3b\0\x20\x20\x20\x20\x66\x6f\x72\x20\
775
+\x28\x75\x6e\x73\x69\x67\x6e\x65\x64\x20\x69\x6e\x74\x20\x69\x20\x3d\x20\x30\
776
+\x3b\x20\x69\x20\x3c\x20\x49\x50\x36\x5f\x45\x58\x54\x45\x4e\x53\x49\x4f\x4e\
777
+\x53\x5f\x43\x4f\x55\x4e\x54\x3b\x20\x2b\x2b\x69\x29\x20\x7b\0\x20\x20\x20\x20\
778
+\x7d\x20\x65\x6c\x73\x65\x20\x69\x66\x20\x28\x70\x61\x63\x6b\x65\x74\x5f\x69\
779
+\x6e\x66\x6f\x2e\x69\x73\x5f\x69\x70\x76\x36\x29\x20\x7b\0\x20\x20\x20\x20\x20\
780
+\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\x70\x61\x63\x6b\x65\x74\x5f\x69\
781
+\x6e\x66\x6f\x2e\x69\x73\x5f\x69\x70\x76\x36\x5f\x65\x78\x74\x5f\x64\x73\x74\
782
+\x20\x26\x26\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\
783
+\x70\x61\x63\x6b\x65\x74\x5f\x69\x6e\x66\x6f\x2e\x69\x73\x5f\x69\x70\x76\x36\
784
+\x5f\x65\x78\x74\x5f\x73\x72\x63\x20\x26\x26\0\x20\x20\x20\x20\x20\x20\x20\x20\
785
+\x7d\x20\x65\x6c\x73\x65\x20\x69\x66\x20\x28\x70\x61\x63\x6b\x65\x74\x5f\x69\
786
+\x6e\x66\x6f\x2e\x69\x73\x5f\x75\x64\x70\x20\x26\x26\0\x20\x20\x20\x20\x20\x20\
787
\x20\x20\x7d\x20\x65\x6c\x73\x65\x20\x69\x66\x20\x28\x63\x6f\x6e\x66\x69\x67\
788
\x2d\x3e\x68\x61\x73\x68\x5f\x74\x79\x70\x65\x73\x20\x26\x20\x56\x49\x52\x54\
789
\x49\x4f\x5f\x4e\x45\x54\x5f\x52\x53\x53\x5f\x48\x41\x53\x48\x5f\x54\x59\x50\
790
-\x45\x5f\x49\x50\x76\x36\x29\x20\x7b\0\x20\x20\x20\x20\x66\x6f\x72\x20\x28\x62\
791
-\x79\x74\x65\x20\x3d\x20\x30\x3b\x20\x62\x79\x74\x65\x20\x3c\x20\x48\x41\x53\
792
-\x48\x5f\x43\x41\x4c\x43\x55\x4c\x41\x54\x49\x4f\x4e\x5f\x42\x55\x46\x46\x45\
793
-\x52\x5f\x53\x49\x5a\x45\x3b\x20\x62\x79\x74\x65\x2b\x2b\x29\x20\x7b\0\x20\x20\
794
-\x20\x20\x5f\x5f\x75\x33\x32\x20\x6c\x65\x66\x74\x6d\x6f\x73\x74\x5f\x33\x32\
795
-\x5f\x62\x69\x74\x73\x20\x3d\x20\x6b\x65\x79\x2d\x3e\x6c\x65\x66\x74\x6d\x6f\
796
-\x73\x74\x5f\x33\x32\x5f\x62\x69\x74\x73\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\
797
-\x5f\x5f\x75\x38\x20\x69\x6e\x70\x75\x74\x5f\x62\x79\x74\x65\x20\x3d\x20\x69\
798
-\x6e\x70\x75\x74\x5b\x62\x79\x74\x65\x5d\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\
799
-\x20\x20\x20\x20\x69\x66\x20\x28\x69\x6e\x70\x75\x74\x5f\x62\x79\x74\x65\x20\
800
-\x26\x20\x28\x31\x20\x3c\x3c\x20\x37\x29\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\
801
-\x20\x20\x5f\x5f\x75\x38\x20\x6b\x65\x79\x5f\x62\x79\x74\x65\x20\x3d\x20\x6b\
802
-\x65\x79\x2d\x3e\x6e\x65\x78\x74\x5f\x62\x79\x74\x65\x5b\x62\x79\x74\x65\x5d\
803
-\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
804
-\x20\x20\x28\x6c\x65\x66\x74\x6d\x6f\x73\x74\x5f\x33\x32\x5f\x62\x69\x74\x73\
805
-\x20\x3c\x3c\x20\x31\x29\x20\x7c\x20\x28\x28\x6b\x65\x79\x5f\x62\x79\x74\x65\
806
-\x20\x26\x20\x28\x31\x20\x3c\x3c\x20\x37\x29\x29\x20\x3e\x3e\x20\x37\x29\x3b\0\
807
-\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\x68\x61\x73\x68\x29\x20\x7b\0\
808
-\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x5f\x5f\x75\x33\x32\x20\x74\
809
-\x61\x62\x6c\x65\x5f\x69\x64\x78\x20\x3d\x20\x68\x61\x73\x68\x20\x25\x20\x63\
810
-\x6f\x6e\x66\x69\x67\x2d\x3e\x69\x6e\x64\x69\x72\x65\x63\x74\x69\x6f\x6e\x73\
811
-\x5f\x6c\x65\x6e\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x71\x75\
812
-\x65\x75\x65\x20\x3d\x20\x62\x70\x66\x5f\x6d\x61\x70\x5f\x6c\x6f\x6f\x6b\x75\
813
-\x70\x5f\x65\x6c\x65\x6d\x28\x26\x74\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\
814
-\x5f\x69\x6e\x64\x69\x72\x65\x63\x74\x69\x6f\x6e\x5f\x74\x61\x62\x6c\x65\x2c\0\
815
-\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\x71\x75\x65\
816
-\x75\x65\x29\x20\x7b\0\x7d\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\
817
-\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6e\x20\x2a\x71\x75\x65\x75\x65\x3b\0\x63\
818
-\x68\x61\x72\0\x5f\x6c\x69\x63\x65\x6e\x73\x65\0\x2e\x6d\x61\x70\x73\0\x6c\x69\
819
-\x63\x65\x6e\x73\x65\0\x62\x70\x66\x5f\x66\x6c\x6f\x77\x5f\x6b\x65\x79\x73\0\
820
-\x62\x70\x66\x5f\x73\x6f\x63\x6b\0\0\0\0\x9f\xeb\x01\0\x20\0\0\0\0\0\0\0\x14\0\
821
-\0\0\x14\0\0\0\x6c\x0c\0\0\x80\x0c\0\0\0\0\0\0\x08\0\0\0\x26\x02\0\0\x01\0\0\0\
822
-\0\0\0\0\x24\0\0\0\x10\0\0\0\x26\x02\0\0\xc6\0\0\0\0\0\0\0\x37\x02\0\0\x61\x02\
823
-\0\0\0\x50\x08\0\x10\0\0\0\x37\x02\0\0\x92\x02\0\0\x0b\x68\x08\0\x20\0\0\0\x37\
824
-\x02\0\0\0\0\0\0\0\0\0\0\x28\0\0\0\x37\x02\0\0\xa5\x02\0\0\x0e\x74\x08\0\x50\0\
825
-\0\0\x37\x02\0\0\xea\x02\0\0\x0b\x78\x08\0\x88\0\0\0\x37\x02\0\0\x2a\x03\0\0\
826
-\x10\x80\x08\0\x90\0\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x98\0\0\0\x37\x02\0\0\x2a\
827
-\x03\0\0\x10\x80\x08\0\xa0\0\0\0\x37\x02\0\0\x43\x03\0\0\x16\x84\x08\0\xa8\0\0\
828
-\0\x37\x02\0\0\x43\x03\0\0\x0d\x84\x08\0\xc0\0\0\0\x37\x02\0\0\x64\x03\0\0\x0a\
829
-\xfc\x05\0\xe8\0\0\0\x37\x02\0\0\x9b\x03\0\0\x1f\x0c\x06\0\x38\x01\0\0\x37\x02\
830
-\0\0\xcb\x03\0\0\x0f\xa0\x04\0\x40\x01\0\0\x37\x02\0\0\xe4\x03\0\0\x0c\x20\x04\
831
-\0\x50\x01\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x58\x01\0\0\x37\x02\0\0\xf8\x03\0\0\
832
-\x0b\x2c\x04\0\x90\x01\0\0\x37\x02\0\0\x3e\x04\0\0\x09\x34\x04\0\xa0\x01\0\0\
833
-\x37\x02\0\0\x4d\x04\0\0\x0d\x44\x04\0\xb8\x01\0\0\x37\x02\0\0\x4d\x04\0\0\x05\
834
-\x44\x04\0\xd8\x01\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\xe0\x01\0\0\x37\x02\0\0\x6b\
835
-\x04\0\0\x0f\x58\x04\0\x10\x02\0\0\x37\x02\0\0\x3e\x04\0\0\x09\x70\x04\0\x18\
836
-\x02\0\0\x37\x02\0\0\xb5\x04\0\0\x0c\x80\x04\0\x20\x02\0\0\x37\x02\0\0\xc5\x04\
837
-\0\0\x09\xbc\x04\0\x50\x02\0\0\x37\x02\0\0\xe1\x04\0\0\x17\xd4\x04\0\x60\x02\0\
838
-\0\x37\x02\0\0\xfc\x04\0\0\x16\xdc\x04\0\x80\x02\0\0\x37\x02\0\0\xe1\x04\0\0\
839
-\x17\xd4\x04\0\x88\x02\0\0\x37\x02\0\0\x1a\x05\0\0\x0f\xe0\x04\0\xc0\x02\0\0\
840
-\x37\x02\0\0\x5d\x05\0\0\x0d\xe8\x04\0\xc8\x02\0\0\x37\x02\0\0\x70\x05\0\0\x24\
841
-\0\x05\0\xd0\x02\0\0\x37\x02\0\0\x70\x05\0\0\x20\0\x05\0\xe0\x02\0\0\x37\x02\0\
842
-\0\x9d\x05\0\0\x1b\xf8\x04\0\xe8\x02\0\0\x37\x02\0\0\x9d\x05\0\0\x16\xf8\x04\0\
843
-\xf0\x02\0\0\x37\x02\0\0\xbe\x05\0\0\x1b\xfc\x04\0\xf8\x02\0\0\x37\x02\0\0\xbe\
844
-\x05\0\0\x16\xfc\x04\0\0\x03\0\0\x37\x02\0\0\xdf\x05\0\0\x1a\x08\x05\0\x08\x03\
845
-\0\0\x37\x02\0\0\x70\x05\0\0\x1d\0\x05\0\x10\x03\0\0\x37\x02\0\0\x02\x06\0\0\
846
-\x18\x0c\x05\0\x18\x03\0\0\x37\x02\0\0\x02\x06\0\0\x1c\x0c\x05\0\x30\x03\0\0\
847
-\x37\x02\0\0\x22\x06\0\0\x15\x68\x05\0\x40\x03\0\0\x37\x02\0\0\x22\x06\0\0\x1a\
848
-\x68\x05\0\x58\x03\0\0\x37\x02\0\0\x56\x06\0\0\x0d\x6c\x05\0\x78\x03\0\0\x37\
849
-\x02\0\0\x80\x06\0\0\x1a\x70\x05\0\x88\x03\0\0\x37\x02\0\0\x9e\x06\0\0\x1b\x78\
850
-\x05\0\xa8\x03\0\0\x37\x02\0\0\x80\x06\0\0\x1a\x70\x05\0\xb0\x03\0\0\x37\x02\0\
851
-\0\xc2\x06\0\0\x13\x7c\x05\0\xe8\x03\0\0\x37\x02\0\0\x13\x07\0\0\x11\x84\x05\0\
852
-\xf0\x03\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x10\x04\0\0\x37\x02\0\0\x2a\x07\0\0\
853
-\x15\x28\x06\0\x18\x04\0\0\x37\x02\0\0\x2a\x07\0\0\x09\x28\x06\0\x20\x04\0\0\
854
-\x37\x02\0\0\0\0\0\0\0\0\0\0\x70\x04\0\0\x37\x02\0\0\x49\x07\0\0\x19\x2c\x06\0\
855
-\x80\x04\0\0\x37\x02\0\0\x49\x07\0\0\x20\x2c\x06\0\xa0\x04\0\0\x37\x02\0\0\0\0\
856
-\0\0\0\0\0\0\xf0\x04\0\0\x37\x02\0\0\x6b\x07\0\0\x17\x14\x05\0\0\x05\0\0\x37\
857
-\x02\0\0\x86\x07\0\0\x18\x1c\x05\0\x30\x05\0\0\x37\x02\0\0\x6b\x07\0\0\x17\x14\
858
-\x05\0\x48\x05\0\0\x37\x02\0\0\xa7\x07\0\0\x0f\x20\x05\0\x80\x05\0\0\x37\x02\0\
859
-\0\x5d\x05\0\0\x0d\x28\x05\0\x88\x05\0\0\x37\x02\0\0\xec\x07\0\0\x1d\x38\x05\0\
860
-\xc8\x05\0\0\x37\x02\0\0\x0f\x08\0\0\x1d\x3c\x05\0\x08\x06\0\0\x37\x02\0\0\x32\
861
-\x08\0\0\x1b\x44\x05\0\x10\x06\0\0\x37\x02\0\0\x55\x08\0\0\x05\x30\x02\0\x58\
862
-\x06\0\0\x37\x02\0\0\x6d\x08\0\0\x19\xb8\x02\0\xd0\x06\0\0\x37\x02\0\0\0\0\0\0\
863
-\0\0\0\0\xd8\x06\0\0\x37\x02\0\0\x93\x08\0\0\x0f\xc8\x02\0\x10\x07\0\0\x37\x02\
864
-\0\0\x5d\x05\0\0\x0d\xd0\x02\0\x20\x07\0\0\x37\x02\0\0\xd8\x08\0\0\x0d\xe0\x02\
865
-\0\x40\x07\0\0\x37\x02\0\0\x07\x09\0\0\x20\xe4\x02\0\x68\x07\0\0\x37\x02\0\0\
866
-\x33\x09\0\0\x13\xec\x02\0\xa8\x07\0\0\x37\x02\0\0\x13\x07\0\0\x11\xf4\x02\0\
867
-\xb0\x07\0\0\x37\x02\0\0\x7b\x09\0\0\x19\x04\x03\0\xb8\x07\0\0\x37\x02\0\0\x7b\
868
-\x09\0\0\x34\x04\x03\0\xe0\x07\0\0\x37\x02\0\0\xb1\x09\0\0\x15\x18\x03\0\xf0\
869
-\x07\0\0\x37\x02\0\0\xf2\x09\0\0\x17\x14\x03\0\x30\x08\0\0\x37\x02\0\0\x29\x0a\
870
-\0\0\x15\x24\x03\0\x38\x08\0\0\x37\x02\0\0\x44\x0a\0\0\x27\x34\x03\0\x70\x08\0\
871
-\0\x37\x02\0\0\x6f\x0a\0\0\x27\x50\x03\0\x80\x08\0\0\x37\x02\0\0\x9f\x0a\0\0\
872
-\x1c\xb4\x03\0\x88\x08\0\0\x37\x02\0\0\xdb\x0a\0\0\x20\xc0\x03\0\x98\x08\0\0\
873
-\x37\x02\0\0\xdb\x0a\0\0\x2f\xc0\x03\0\xa0\x08\0\0\x37\x02\0\0\xdb\x0a\0\0\x36\
874
-\xc0\x03\0\xa8\x08\0\0\x37\x02\0\0\xdb\x0a\0\0\x15\xc0\x03\0\x18\x09\0\0\x37\
875
-\x02\0\0\x17\x0b\0\0\x43\x64\x03\0\x38\x09\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x40\
876
-\x09\0\0\x37\x02\0\0\x17\x0b\0\0\x17\x64\x03\0\x80\x09\0\0\x37\x02\0\0\x29\x0a\
877
-\0\0\x15\x6c\x03\0\x88\x09\0\0\x37\x02\0\0\x67\x0b\0\0\x19\x7c\x03\0\x90\x09\0\
878
-\0\x37\x02\0\0\x67\x0b\0\0\x15\x7c\x03\0\x98\x09\0\0\x37\x02\0\0\x97\x0b\0\0\
879
-\x19\x84\x03\0\xa0\x09\0\0\x37\x02\0\0\xc7\x0b\0\0\x1b\x80\x03\0\xe8\x09\0\0\
880
-\x37\x02\0\0\x02\x0c\0\0\x19\x94\x03\0\xf0\x09\0\0\x37\x02\0\0\x21\x0c\0\0\x2b\
881
-\xa4\x03\0\x10\x0a\0\0\x37\x02\0\0\x9f\x0a\0\0\x1f\xb4\x03\0\x30\x0a\0\0\x37\
882
-\x02\0\0\x50\x0c\0\0\x21\xd4\x03\0\x40\x0a\0\0\x37\x02\0\0\x78\x0c\0\0\x20\xe4\
883
-\x03\0\x48\x0a\0\0\x37\x02\0\0\x78\x0c\0\0\x2c\xe4\x03\0\x60\x0a\0\0\x37\x02\0\
884
-\0\x78\x0c\0\0\x14\xe4\x03\0\x70\x0a\0\0\x37\x02\0\0\xa8\x0c\0\0\x20\xe0\x03\0\
885
-\x80\x0a\0\0\x37\x02\0\0\x55\x08\0\0\x05\x30\x02\0\xb0\x0a\0\0\x37\x02\0\0\xd0\
886
-\x0c\0\0\x38\xc0\x02\0\xd0\x0a\0\0\x37\x02\0\0\xd0\x0c\0\0\x05\xc0\x02\0\xe8\
887
-\x0a\0\0\x37\x02\0\0\x55\x08\0\0\x05\x30\x02\0\xf8\x0a\0\0\x37\x02\0\0\x0e\x0d\
888
-\0\0\x1c\xc4\x06\0\x08\x0b\0\0\x37\x02\0\0\x0e\x0d\0\0\x10\xc4\x06\0\x10\x0b\0\
889
-\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x60\x0b\0\0\x37\x02\0\0\x49\x07\0\0\x19\xc8\x06\
890
-\0\x68\x0b\0\0\x37\x02\0\0\x49\x07\0\0\x20\xc8\x06\0\xa0\x0b\0\0\x37\x02\0\0\
891
-\x34\x0d\0\0\x2d\0\x07\0\xb0\x0b\0\0\x37\x02\0\0\x34\x0d\0\0\x1d\0\x07\0\xb8\
892
-\x0b\0\0\x37\x02\0\0\x34\x0d\0\0\x2d\0\x07\0\xc8\x0b\0\0\x37\x02\0\0\x63\x0d\0\
893
-\0\x2d\xd4\x06\0\xf8\x0b\0\0\x37\x02\0\0\x63\x0d\0\0\x1d\xd4\x06\0\x08\x0c\0\0\
894
-\x37\x02\0\0\x63\x0d\0\0\x2d\xd4\x06\0\x18\x0c\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\
895
-\xe8\x0c\0\0\x37\x02\0\0\x92\x0d\0\0\x20\x68\x06\0\xf0\x0c\0\0\x37\x02\0\0\x92\
896
-\x0d\0\0\x27\x68\x06\0\x18\x0d\0\0\x37\x02\0\0\xbb\x0d\0\0\x27\xa4\x06\0\x20\
897
-\x0d\0\0\x37\x02\0\0\xbb\x0d\0\0\x14\xa4\x06\0\x28\x0d\0\0\x37\x02\0\0\x04\x0e\
898
-\0\0\x05\x98\x01\0\x38\x0d\0\0\x37\x02\0\0\x04\x0e\0\0\x05\x98\x01\0\x60\x0d\0\
899
-\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x70\x0d\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x80\x0d\
900
-\0\0\x37\x02\0\0\x92\x0d\0\0\x20\x44\x07\0\x88\x0d\0\0\x37\x02\0\0\x92\x0d\0\0\
901
-\x27\x44\x07\0\xc0\x0d\0\0\x37\x02\0\0\x34\x0d\0\0\x2d\x7c\x07\0\xd0\x0d\0\0\
902
-\x37\x02\0\0\x34\x0d\0\0\x1d\x7c\x07\0\xd8\x0d\0\0\x37\x02\0\0\x34\x0d\0\0\x2d\
903
-\x7c\x07\0\xe8\x0d\0\0\x37\x02\0\0\x63\x0d\0\0\x2d\x50\x07\0\x18\x0e\0\0\x37\
904
-\x02\0\0\x63\x0d\0\0\x1d\x50\x07\0\x28\x0e\0\0\x37\x02\0\0\x63\x0d\0\0\x2d\x50\
905
-\x07\0\x40\x0e\0\0\x37\x02\0\0\x41\x0e\0\0\x1a\xa0\x05\0\x50\x0e\0\0\x37\x02\0\
906
-\0\x5f\x0e\0\0\x1b\xa8\x05\0\x60\x0e\0\0\x37\x02\0\0\x41\x0e\0\0\x1a\xa0\x05\0\
907
-\x68\x0e\0\0\x37\x02\0\0\x83\x0e\0\0\x13\xac\x05\0\xa0\x0e\0\0\x37\x02\0\0\x13\
908
-\x07\0\0\x11\xb4\x05\0\xb0\x0e\0\0\x37\x02\0\0\x55\x08\0\0\x05\x30\x02\0\xc0\
909
-\x0e\0\0\x37\x02\0\0\xd4\x0e\0\0\x27\xc8\x07\0\xd0\x0e\0\0\x37\x02\0\0\xd4\x0e\
910
-\0\0\x14\xc8\x07\0\xf0\x0e\0\0\x37\x02\0\0\x63\x0d\0\0\x2d\xcc\x07\0\0\x0f\0\0\
911
-\x37\x02\0\0\x63\x0d\0\0\x1d\xcc\x07\0\x08\x0f\0\0\x37\x02\0\0\x63\x0d\0\0\x2d\
912
-\xcc\x07\0\x30\x0f\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x80\x0f\0\0\x37\x02\0\0\x34\
913
-\x0d\0\0\x1d\xf8\x07\0\x88\x0f\0\0\x37\x02\0\0\x34\x0d\0\0\x2d\xf8\x07\0\x98\
914
-\x0f\0\0\x37\x02\0\0\x04\x0e\0\0\x05\x98\x01\0\xf0\x0f\0\0\x37\x02\0\0\x04\x0e\
915
-\0\0\x05\x98\x01\0\x30\x10\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x48\x10\0\0\x37\x02\
916
-\0\0\x1d\x0f\0\0\x05\xd0\x01\0\x50\x10\0\0\x37\x02\0\0\x5f\x0f\0\0\x23\xc4\x01\
917
-\0\x68\x10\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x70\x10\0\0\x37\x02\0\0\x93\x0f\0\0\
918
-\x1b\xd4\x01\0\x90\x10\0\0\x37\x02\0\0\xba\x0f\0\0\x11\xe8\x01\0\xa8\x10\0\0\
919
-\x37\x02\0\0\xe3\x0f\0\0\x19\xd8\x01\0\xc0\x10\0\0\x37\x02\0\0\x11\x10\0\0\x27\
920
-\xfc\x01\0\xc8\x10\0\0\x37\x02\0\0\x11\x10\0\0\x46\xfc\x01\0\xd8\x10\0\0\x37\
921
-\x02\0\0\x11\x10\0\0\x2d\xfc\x01\0\xe0\x10\0\0\x37\x02\0\0\xba\x0f\0\0\x11\xe8\
922
-\x01\0\x08\x11\0\0\x37\x02\0\0\x11\x10\0\0\x46\xfc\x01\0\x20\x11\0\0\x37\x02\0\
923
-\0\x11\x10\0\0\x27\xfc\x01\0\x28\x11\0\0\x37\x02\0\0\x11\x10\0\0\x2d\xfc\x01\0\
924
-\x30\x11\0\0\x37\x02\0\0\xba\x0f\0\0\x11\xe8\x01\0\x58\x11\0\0\x37\x02\0\0\x11\
925
-\x10\0\0\x27\xfc\x01\0\x60\x11\0\0\x37\x02\0\0\x11\x10\0\0\x46\xfc\x01\0\x78\
926
-\x11\0\0\x37\x02\0\0\x11\x10\0\0\x2d\xfc\x01\0\x80\x11\0\0\x37\x02\0\0\xba\x0f\
927
-\0\0\x11\xe8\x01\0\xa8\x11\0\0\x37\x02\0\0\x11\x10\0\0\x27\xfc\x01\0\xb0\x11\0\
928
-\0\x37\x02\0\0\x11\x10\0\0\x46\xfc\x01\0\xc8\x11\0\0\x37\x02\0\0\x11\x10\0\0\
929
-\x2d\xfc\x01\0\xd0\x11\0\0\x37\x02\0\0\xba\x0f\0\0\x11\xe8\x01\0\xf8\x11\0\0\
930
-\x37\x02\0\0\x11\x10\0\0\x46\xfc\x01\0\x10\x12\0\0\x37\x02\0\0\x11\x10\0\0\x27\
931
-\xfc\x01\0\x18\x12\0\0\x37\x02\0\0\x11\x10\0\0\x2d\xfc\x01\0\x20\x12\0\0\x37\
932
-\x02\0\0\xba\x0f\0\0\x11\xe8\x01\0\x48\x12\0\0\x37\x02\0\0\x11\x10\0\0\x46\xfc\
933
-\x01\0\x60\x12\0\0\x37\x02\0\0\x11\x10\0\0\x27\xfc\x01\0\x68\x12\0\0\x37\x02\0\
934
-\0\x11\x10\0\0\x2d\xfc\x01\0\x70\x12\0\0\x37\x02\0\0\xba\x0f\0\0\x11\xe8\x01\0\
935
-\x98\x12\0\0\x37\x02\0\0\x11\x10\0\0\x46\xfc\x01\0\xb0\x12\0\0\x37\x02\0\0\x11\
936
-\x10\0\0\x27\xfc\x01\0\xb8\x12\0\0\x37\x02\0\0\x11\x10\0\0\x2d\xfc\x01\0\xc0\
937
-\x12\0\0\x37\x02\0\0\xba\x0f\0\0\x11\xe8\x01\0\xe0\x12\0\0\x37\x02\0\0\x11\x10\
938
-\0\0\x46\xfc\x01\0\xe8\x12\0\0\x37\x02\0\0\x11\x10\0\0\x27\xfc\x01\0\xf0\x12\0\
939
-\0\x37\x02\0\0\x11\x10\0\0\x2d\xfc\x01\0\xf8\x12\0\0\x37\x02\0\0\x1d\x0f\0\0\
940
-\x3d\xd0\x01\0\x08\x13\0\0\x37\x02\0\0\x1d\x0f\0\0\x05\xd0\x01\0\x18\x13\0\0\
941
-\x37\x02\0\0\x5d\x10\0\0\x0d\x98\x08\0\x30\x13\0\0\x37\x02\0\0\x5d\x10\0\0\x0d\
942
-\x98\x08\0\x38\x13\0\0\x37\x02\0\0\x71\x10\0\0\x2e\x9c\x08\0\x58\x13\0\0\x37\
943
-\x02\0\0\x71\x10\0\0\x24\x9c\x08\0\x70\x13\0\0\x37\x02\0\0\x71\x10\0\0\x13\x9c\
944
-\x08\0\x80\x13\0\0\x37\x02\0\0\x71\x10\0\0\x2e\x9c\x08\0\x88\x13\0\0\x37\x02\0\
945
-\0\xb0\x10\0\0\x15\xa8\x08\0\xa0\x13\0\0\x37\x02\0\0\xf8\x10\0\0\x11\xb4\x08\0\
946
-\xa8\x13\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\xc8\x13\0\0\x37\x02\0\0\x11\x11\0\0\
947
-\x01\xd8\x08\0\xd0\x13\0\0\x37\x02\0\0\x13\x11\0\0\x18\xb8\x08\0\0\0\0\0\0\0\0\
948
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\
949
-\0\0\0\0\xde\0\0\0\0\0\x03\0\xc8\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7a\x01\0\0\0\
950
-\0\x03\0\xb8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xff\0\0\0\0\0\x03\0\xa8\x13\0\0\0\0\
951
-\0\0\0\0\0\0\0\0\0\0\xc7\0\0\0\0\0\x03\0\xd0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
952
-\x2c\x02\0\0\0\0\x03\0\x20\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf7\0\0\0\0\0\x03\0\
953
-\xe8\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1c\x02\0\0\0\0\x03\0\x10\x04\0\0\0\0\0\0\
954
-\0\0\0\0\0\0\0\0\x28\x01\0\0\0\0\x03\0\xe0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf3\
955
-\x01\0\0\0\0\x03\0\x30\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xeb\x01\0\0\0\0\x03\0\
956
-\x38\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x44\x02\0\0\0\0\x03\0\xf0\x03\0\0\0\0\0\0\
957
-\0\0\0\0\0\0\0\0\xe3\x01\0\0\0\0\x03\0\xf8\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x18\
958
-\x01\0\0\0\0\x03\0\xe8\x0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x30\x01\0\0\0\0\x03\0\
959
-\xa0\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa9\x01\0\0\0\0\x03\0\x40\x10\0\0\0\0\0\0\
960
-\0\0\0\0\0\0\0\0\x51\x01\0\0\0\0\x03\0\x78\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5c\
961
-\x02\0\0\0\0\x03\0\xb0\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\x02\0\0\0\0\x03\0\
962
-\x50\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc2\x01\0\0\0\0\x03\0\xc0\x06\0\0\0\0\0\0\
963
-\0\0\0\0\0\0\0\0\x69\x01\0\0\0\0\x03\0\x20\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x61\
964
-\x01\0\0\0\0\x03\0\x60\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x38\x01\0\0\0\0\x03\0\
965
-\x30\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x20\x01\0\0\0\0\x03\0\x40\x0a\0\0\0\0\0\0\
966
-\0\0\0\0\0\0\0\0\xba\x01\0\0\0\0\x03\0\xe0\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa1\
967
-\x01\0\0\0\0\x03\0\x48\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x40\x01\0\0\0\0\x03\0\
968
-\x18\x09\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xfb\x01\0\0\0\0\x03\0\x80\x08\0\0\0\0\0\0\
969
-\0\0\0\0\0\0\0\0\x99\x01\0\0\0\0\x03\0\xf8\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x59\
970
-\x01\0\0\0\0\x03\0\x50\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x54\x02\0\0\0\0\x03\0\
971
-\x08\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xef\0\0\0\0\0\x03\0\xe8\x0a\0\0\0\0\0\0\0\
972
-\0\0\0\0\0\0\0\x4c\x02\0\0\0\0\x03\0\xb0\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x24\
973
-\x02\0\0\0\0\x03\0\xd8\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x89\x01\0\0\0\0\x03\0\
974
-\x80\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x10\x01\0\0\0\0\x03\0\xb0\x0b\0\0\0\0\0\0\
975
-\0\0\0\0\0\0\0\0\xd6\0\0\0\0\0\x03\0\xc8\x0b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x14\
976
-\x02\0\0\0\0\x03\0\xf8\x0b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb2\x01\0\0\0\0\x03\0\
977
-\x18\x0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xdb\x01\0\0\0\0\x03\0\x10\x0c\0\0\0\0\0\0\
978
-\0\0\0\0\0\0\0\0\x3c\x02\0\0\0\0\x03\0\x18\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x91\
979
-\x01\0\0\0\0\x03\0\x60\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81\x01\0\0\0\0\x03\0\
980
-\xc0\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe7\0\0\0\0\0\x03\0\xd0\x0d\0\0\0\0\0\0\0\
981
-\0\0\0\0\0\0\0\x34\x02\0\0\0\0\x03\0\xe8\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd3\
982
-\x01\0\0\0\0\x03\0\x18\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08\x01\0\0\0\0\x03\0\0\
983
-\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xce\0\0\0\0\0\x03\0\x18\x0f\0\0\0\0\0\0\0\0\0\
984
-\0\0\0\0\0\x0b\x02\0\0\0\0\x03\0\xf0\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xca\x01\0\
985
-\0\0\0\x03\0\x30\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x71\x01\0\0\0\0\x03\0\x60\x10\
986
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x48\x01\0\0\0\0\x03\0\x18\x13\0\0\0\0\0\0\0\0\0\0\
987
-\0\0\0\0\x64\x02\0\0\0\0\x03\0\xd0\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4e\0\0\0\
988
-\x12\0\x03\0\0\0\0\0\0\0\0\0\xe0\x13\0\0\0\0\0\0\x33\0\0\0\x11\0\x05\0\0\0\0\0\
989
-\0\0\0\0\x20\0\0\0\0\0\0\0\x01\0\0\0\x11\0\x05\0\x20\0\0\0\0\0\0\0\x20\0\0\0\0\
990
-\0\0\0\x90\0\0\0\x11\0\x05\0\x40\0\0\0\0\0\0\0\x20\0\0\0\0\0\0\0\x87\0\0\0\x11\
991
-\0\x06\0\0\0\0\0\0\0\0\0\x07\0\0\0\0\0\0\0\x28\0\0\0\0\0\0\0\x01\0\0\0\x37\0\0\
992
-\0\x50\0\0\0\0\0\0\0\x01\0\0\0\x38\0\0\0\x88\x13\0\0\0\0\0\0\x01\0\0\0\x39\0\0\
993
-\0\xd8\x04\0\0\0\0\0\0\x04\0\0\0\x37\0\0\0\xe4\x04\0\0\0\0\0\0\x04\0\0\0\x38\0\
994
-\0\0\xf0\x04\0\0\0\0\0\0\x04\0\0\0\x39\0\0\0\x08\x05\0\0\0\0\0\0\x04\0\0\0\x3a\
995
-\0\0\0\x2c\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\0\0\0\0\0\0\0\x04\0\0\0\x01\0\
996
-\0\0\x50\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\
997
-\0\x70\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x80\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\
998
-\x90\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xa0\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\
999
-\xb0\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\
1000
-\xd0\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\
1001
-\xf0\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\
1002
-\x10\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x20\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\
1003
-\0\x30\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\
1004
-\0\0\x50\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\x01\0\0\0\0\0\0\x04\0\0\0\x01\
1005
-\0\0\0\x70\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x80\x01\0\0\0\0\0\0\x04\0\0\0\
1006
-\x01\0\0\0\x90\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xa0\x01\0\0\0\0\0\0\x04\0\0\
1007
-\0\x01\0\0\0\xb0\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\x01\0\0\0\0\0\0\x04\0\
1008
-\0\0\x01\0\0\0\xd0\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\x01\0\0\0\0\0\0\x04\
1009
-\0\0\0\x01\0\0\0\xf0\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\x02\0\0\0\0\0\0\x04\
1010
-\0\0\0\x01\0\0\0\x10\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x20\x02\0\0\0\0\0\0\
1011
-\x04\0\0\0\x01\0\0\0\x30\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\x02\0\0\0\0\0\
1012
-\0\x04\0\0\0\x01\0\0\0\x50\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\x02\0\0\0\0\
1013
-\0\0\x04\0\0\0\x01\0\0\0\x70\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x80\x02\0\0\0\
1014
-\0\0\0\x04\0\0\0\x01\0\0\0\x90\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xa0\x02\0\0\
1015
-\0\0\0\0\x04\0\0\0\x01\0\0\0\xb0\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\x02\0\
1016
-\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xd0\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\x02\
1017
-\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xf0\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\x03\
1018
-\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x10\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x20\
1019
-\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x30\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\
1020
-\x40\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x50\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\
1021
-\0\x60\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x70\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\
1022
-\0\0\x80\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x90\x03\0\0\0\0\0\0\x04\0\0\0\x01\
1023
-\0\0\0\xa0\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xb0\x03\0\0\0\0\0\0\x04\0\0\0\
1024
-\x01\0\0\0\xc0\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xd0\x03\0\0\0\0\0\0\x04\0\0\
1025
-\0\x01\0\0\0\xe0\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xf0\x03\0\0\0\0\0\0\x04\0\
1026
-\0\0\x01\0\0\0\0\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x10\x04\0\0\0\0\0\0\x04\0\
1027
-\0\0\x01\0\0\0\x20\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x30\x04\0\0\0\0\0\0\x04\
1028
-\0\0\0\x01\0\0\0\x40\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x50\x04\0\0\0\0\0\0\
1029
-\x04\0\0\0\x01\0\0\0\x60\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x70\x04\0\0\0\0\0\
1030
-\0\x04\0\0\0\x01\0\0\0\x80\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x90\x04\0\0\0\0\
1031
-\0\0\x04\0\0\0\x01\0\0\0\xa0\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xb0\x04\0\0\0\
1032
-\0\0\0\x04\0\0\0\x01\0\0\0\xc0\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xd0\x04\0\0\
1033
-\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xf0\x04\0\
1034
-\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x10\x05\0\
1035
-\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x20\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x30\x05\
1036
-\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x50\
1037
-\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\
1038
-\x70\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x80\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\
1039
-\0\x90\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xa0\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\
1040
-\0\0\xb0\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\x05\0\0\0\0\0\0\x04\0\0\0\x01\
1041
-\0\0\0\xd0\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\x05\0\0\0\0\0\0\x04\0\0\0\
1042
-\x01\0\0\0\xf0\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\x06\0\0\0\0\0\0\x04\0\0\0\
1043
-\x01\0\0\0\x10\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x20\x06\0\0\0\0\0\0\x04\0\0\
1044
-\0\x01\0\0\0\x30\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\x06\0\0\0\0\0\0\x04\0\
1045
-\0\0\x01\0\0\0\x50\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\x06\0\0\0\0\0\0\x04\
1046
-\0\0\0\x01\0\0\0\x70\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x80\x06\0\0\0\0\0\0\
1047
-\x04\0\0\0\x01\0\0\0\x90\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xa0\x06\0\0\0\0\0\
1048
-\0\x04\0\0\0\x01\0\0\0\xb0\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\x06\0\0\0\0\
1049
-\0\0\x04\0\0\0\x01\0\0\0\xd0\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\x06\0\0\0\
1050
-\0\0\0\x04\0\0\0\x01\0\0\0\xf0\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\x07\0\0\0\
1051
-\0\0\0\x04\0\0\0\x01\0\0\0\x10\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x20\x07\0\0\
1052
-\0\0\0\0\x04\0\0\0\x01\0\0\0\x30\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\x07\0\
1053
-\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x50\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\x07\
1054
-\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x70\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x80\
1055
-\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x90\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\
1056
-\xa0\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xb0\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\
1057
-\0\xc0\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xd0\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\
1058
-\0\0\xe0\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xf0\x07\0\0\0\0\0\0\x04\0\0\0\x01\
1059
-\0\0\0\0\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x10\x08\0\0\0\0\0\0\x04\0\0\0\x01\
1060
-\0\0\0\x20\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x30\x08\0\0\0\0\0\0\x04\0\0\0\
1061
-\x01\0\0\0\x40\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x50\x08\0\0\0\0\0\0\x04\0\0\
1062
-\0\x01\0\0\0\x60\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x70\x08\0\0\0\0\0\0\x04\0\
1063
-\0\0\x01\0\0\0\x80\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x90\x08\0\0\0\0\0\0\x04\
1064
-\0\0\0\x01\0\0\0\xa0\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xb0\x08\0\0\0\0\0\0\
1065
-\x04\0\0\0\x01\0\0\0\xc0\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xd0\x08\0\0\0\0\0\
1066
-\0\x04\0\0\0\x01\0\0\0\xe0\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xf0\x08\0\0\0\0\
1067
-\0\0\x04\0\0\0\x01\0\0\0\0\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x10\x09\0\0\0\0\
1068
-\0\0\x04\0\0\0\x01\0\0\0\x20\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x30\x09\0\0\0\
1069
-\0\0\0\x04\0\0\0\x01\0\0\0\x40\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x50\x09\0\0\
1070
-\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x70\x09\0\
1071
-\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x80\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x90\x09\
1072
-\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xa0\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xb0\
1073
-\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\
1074
-\xd0\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\
1075
-\0\xf0\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\
1076
-\0\x10\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x20\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\
1077
-\0\0\x30\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\x0a\0\0\0\0\0\0\x04\0\0\0\x01\
1078
-\0\0\0\x50\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\x0a\0\0\0\0\0\0\x04\0\0\0\
1079
-\x01\0\0\0\x70\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x80\x0a\0\0\0\0\0\0\x04\0\0\
1080
-\0\x01\0\0\0\x90\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xa0\x0a\0\0\0\0\0\0\x04\0\
1081
-\0\0\x01\0\0\0\xb0\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\x0a\0\0\0\0\0\0\x04\
1082
-\0\0\0\x01\0\0\0\xd0\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\x0a\0\0\0\0\0\0\
1083
-\x04\0\0\0\x01\0\0\0\xf0\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\x0b\0\0\0\0\0\0\
1084
-\x04\0\0\0\x01\0\0\0\x10\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x20\x0b\0\0\0\0\0\
1085
-\0\x04\0\0\0\x01\0\0\0\x30\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\x0b\0\0\0\0\
1086
-\0\0\x04\0\0\0\x01\0\0\0\x50\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\x0b\0\0\0\
1087
-\0\0\0\x04\0\0\0\x01\0\0\0\x70\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x80\x0b\0\0\
1088
-\0\0\0\0\x04\0\0\0\x01\0\0\0\x90\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xa0\x0b\0\
1089
-\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xb0\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\x0b\
1090
-\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xd0\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\
1091
-\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xf0\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\
1092
-\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x10\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\
1093
-\x20\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x30\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\0\
1094
-\0\x40\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x50\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\
1095
-\0\0\x60\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x70\x0c\0\0\0\0\0\0\x04\0\0\0\x01\
1096
-\0\0\0\x80\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x90\x0c\0\0\0\0\0\0\x04\0\0\0\
1097
-\x01\0\0\0\x40\x41\x42\x43\x44\0\x74\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\
1098
-\x5f\x74\x6f\x65\x70\x6c\x69\x74\x7a\x5f\x6b\x65\x79\0\x2e\x74\x65\x78\x74\0\
1099
-\x2e\x72\x65\x6c\x2e\x42\x54\x46\x2e\x65\x78\x74\0\x2e\x6d\x61\x70\x73\0\x74\
1100
-\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\x5f\x63\x6f\x6e\x66\x69\x67\x75\x72\
1101
-\x61\x74\x69\x6f\x6e\x73\0\x74\x75\x6e\x5f\x72\x73\x73\x5f\x73\x74\x65\x65\x72\
1102
-\x69\x6e\x67\x5f\x70\x72\x6f\x67\0\x2e\x72\x65\x6c\x74\x75\x6e\x5f\x72\x73\x73\
1103
-\x5f\x73\x74\x65\x65\x72\x69\x6e\x67\0\x2e\x6c\x6c\x76\x6d\x5f\x61\x64\x64\x72\
1104
-\x73\x69\x67\0\x5f\x6c\x69\x63\x65\x6e\x73\x65\0\x74\x61\x70\x5f\x72\x73\x73\
1105
-\x5f\x6d\x61\x70\x5f\x69\x6e\x64\x69\x72\x65\x63\x74\x69\x6f\x6e\x5f\x74\x61\
1106
-\x62\x6c\x65\0\x2e\x73\x74\x72\x74\x61\x62\0\x2e\x73\x79\x6d\x74\x61\x62\0\x2e\
1107
-\x72\x65\x6c\x2e\x42\x54\x46\0\x4c\x42\x42\x30\x5f\x39\0\x4c\x42\x42\x30\x5f\
1108
-\x39\x39\0\x4c\x42\x42\x30\x5f\x37\x39\0\x4c\x42\x42\x30\x5f\x31\x30\x39\0\x4c\
1109
-\x42\x42\x30\x5f\x38\x38\0\x4c\x42\x42\x30\x5f\x34\x38\0\x4c\x42\x42\x30\x5f\
1110
-\x31\x38\0\x4c\x42\x42\x30\x5f\x31\x30\x38\0\x4c\x42\x42\x30\x5f\x39\x37\0\x4c\
1111
-\x42\x42\x30\x5f\x37\x37\0\x4c\x42\x42\x30\x5f\x36\x37\0\x4c\x42\x42\x30\x5f\
1112
-\x34\x37\0\x4c\x42\x42\x30\x5f\x31\x37\0\x4c\x42\x42\x30\x5f\x36\x36\0\x4c\x42\
1113
-\x42\x30\x5f\x34\x36\0\x4c\x42\x42\x30\x5f\x33\x36\0\x4c\x42\x42\x30\x5f\x31\
1114
-\x30\x36\0\x4c\x42\x42\x30\x5f\x35\x35\0\x4c\x42\x42\x30\x5f\x34\x35\0\x4c\x42\
1115
-\x42\x30\x5f\x33\x35\0\x4c\x42\x42\x30\x5f\x32\x35\0\x4c\x42\x42\x30\x5f\x31\
1116
-\x30\x35\0\x4c\x42\x42\x30\x5f\x34\0\x4c\x42\x42\x30\x5f\x39\x34\0\x4c\x42\x42\
1117
-\x30\x5f\x38\x34\0\x4c\x42\x42\x30\x5f\x35\x34\0\x4c\x42\x42\x30\x5f\x34\x34\0\
1118
+\x45\x5f\x49\x50\x76\x34\x29\x20\x7b\0\x20\x20\x20\x20\x5f\x5f\x62\x75\x69\x6c\
1119
+\x74\x69\x6e\x5f\x6d\x65\x6d\x63\x70\x79\x28\x26\x72\x73\x73\x5f\x69\x6e\x70\
1120
+\x75\x74\x5b\x2a\x62\x79\x74\x65\x73\x5f\x77\x72\x69\x74\x74\x65\x6e\x5d\x2c\
1121
+\x20\x70\x74\x72\x2c\x20\x73\x69\x7a\x65\x29\x3b\0\x20\x20\x20\x20\x20\x20\x20\
1122
+\x20\x20\x20\x20\x20\x69\x6e\x66\x6f\x2d\x3e\x69\x73\x5f\x75\x64\x70\x20\x3d\
1123
+\x20\x31\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x73\x74\x72\x75\
1124
+\x63\x74\x20\x75\x64\x70\x68\x64\x72\x20\x75\x64\x70\x20\x3d\x20\x7b\x7d\x3b\0\
1125
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x65\x72\x72\x20\x3d\x20\x62\
1126
+\x70\x66\x5f\x73\x6b\x62\x5f\x6c\x6f\x61\x64\x5f\x62\x79\x74\x65\x73\x5f\x72\
1127
+\x65\x6c\x61\x74\x69\x76\x65\x28\x73\x6b\x62\x2c\x20\x6c\x34\x5f\x6f\x66\x66\
1128
+\x73\x65\x74\x2c\x20\x26\x75\x64\x70\x2c\x20\x73\x69\x7a\x65\x6f\x66\x28\x75\
1129
+\x64\x70\x29\x2c\0\x20\x20\x20\x20\x20\x20\x20\x20\x7d\x20\x65\x6c\x73\x65\x20\
1130
+\x69\x66\x20\x28\x63\x6f\x6e\x66\x69\x67\x2d\x3e\x68\x61\x73\x68\x5f\x74\x79\
1131
+\x70\x65\x73\x20\x26\x20\x56\x49\x52\x54\x49\x4f\x5f\x4e\x45\x54\x5f\x52\x53\
1132
+\x53\x5f\x48\x41\x53\x48\x5f\x54\x59\x50\x45\x5f\x49\x50\x76\x36\x29\x20\x7b\0\
1133
+\x20\x20\x20\x20\x66\x6f\x72\x20\x28\x62\x79\x74\x65\x20\x3d\x20\x30\x3b\x20\
1134
+\x62\x79\x74\x65\x20\x3c\x20\x48\x41\x53\x48\x5f\x43\x41\x4c\x43\x55\x4c\x41\
1135
+\x54\x49\x4f\x4e\x5f\x42\x55\x46\x46\x45\x52\x5f\x53\x49\x5a\x45\x3b\x20\x62\
1136
+\x79\x74\x65\x2b\x2b\x29\x20\x7b\0\x20\x20\x20\x20\x5f\x5f\x75\x33\x32\x20\x6c\
1137
+\x65\x66\x74\x6d\x6f\x73\x74\x5f\x33\x32\x5f\x62\x69\x74\x73\x20\x3d\x20\x6b\
1138
+\x65\x79\x2d\x3e\x6c\x65\x66\x74\x6d\x6f\x73\x74\x5f\x33\x32\x5f\x62\x69\x74\
1139
+\x73\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x5f\x5f\x75\x38\x20\x69\x6e\x70\x75\
1140
+\x74\x5f\x62\x79\x74\x65\x20\x3d\x20\x69\x6e\x70\x75\x74\x5b\x62\x79\x74\x65\
1141
+\x5d\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x69\x66\x20\x28\x69\
1142
+\x6e\x70\x75\x74\x5f\x62\x79\x74\x65\x20\x26\x20\x28\x31\x20\x3c\x3c\x20\x37\
1143
+\x29\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\x5f\x5f\x75\x38\x20\x6b\x65\
1144
+\x79\x5f\x62\x79\x74\x65\x20\x3d\x20\x6b\x65\x79\x2d\x3e\x6e\x65\x78\x74\x5f\
1145
+\x62\x79\x74\x65\x5b\x62\x79\x74\x65\x5d\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\
1146
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x28\x6c\x65\x66\x74\x6d\x6f\
1147
+\x73\x74\x5f\x33\x32\x5f\x62\x69\x74\x73\x20\x3c\x3c\x20\x31\x29\x20\x7c\x20\
1148
+\x28\x28\x6b\x65\x79\x5f\x62\x79\x74\x65\x20\x26\x20\x28\x31\x20\x3c\x3c\x20\
1149
+\x37\x29\x29\x20\x3e\x3e\x20\x37\x29\x3b\0\x20\x20\x20\x20\x20\x20\x20\x20\x69\
1150
+\x66\x20\x28\x68\x61\x73\x68\x29\x20\x7b\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\
1151
+\x20\x20\x20\x5f\x5f\x75\x33\x32\x20\x74\x61\x62\x6c\x65\x5f\x69\x64\x78\x20\
1152
+\x3d\x20\x68\x61\x73\x68\x20\x25\x20\x63\x6f\x6e\x66\x69\x67\x2d\x3e\x69\x6e\
1153
+\x64\x69\x72\x65\x63\x74\x69\x6f\x6e\x73\x5f\x6c\x65\x6e\x3b\0\x20\x20\x20\x20\
1154
+\x20\x20\x20\x20\x20\x20\x20\x20\x71\x75\x65\x75\x65\x20\x3d\x20\x62\x70\x66\
1155
+\x5f\x6d\x61\x70\x5f\x6c\x6f\x6f\x6b\x75\x70\x5f\x65\x6c\x65\x6d\x28\x26\x74\
1156
+\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\x5f\x69\x6e\x64\x69\x72\x65\x63\x74\
1157
+\x69\x6f\x6e\x5f\x74\x61\x62\x6c\x65\x2c\0\x20\x20\x20\x20\x20\x20\x20\x20\x20\
1158
+\x20\x20\x20\x69\x66\x20\x28\x71\x75\x65\x75\x65\x29\x20\x7b\0\x7d\0\x20\x20\
1159
+\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\
1160
+\x6e\x20\x2a\x71\x75\x65\x75\x65\x3b\0\x63\x68\x61\x72\0\x5f\x6c\x69\x63\x65\
1161
+\x6e\x73\x65\0\x2e\x6d\x61\x70\x73\0\x6c\x69\x63\x65\x6e\x73\x65\0\x62\x70\x66\
1162
+\x5f\x66\x6c\x6f\x77\x5f\x6b\x65\x79\x73\0\x62\x70\x66\x5f\x73\x6f\x63\x6b\0\0\
1163
+\x9f\xeb\x01\0\x20\0\0\0\0\0\0\0\x14\0\0\0\x14\0\0\0\x1c\x0d\0\0\x30\x0d\0\0\0\
1164
+\0\0\0\x08\0\0\0\x30\x02\0\0\x01\0\0\0\0\0\0\0\x26\0\0\0\x10\0\0\0\x30\x02\0\0\
1165
+\xd1\0\0\0\0\0\0\0\x37\x02\0\0\x67\x02\0\0\0\x5c\x08\0\x10\0\0\0\x37\x02\0\0\
1166
+\x98\x02\0\0\x0b\x74\x08\0\x20\0\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x28\0\0\0\x37\
1167
+\x02\0\0\xab\x02\0\0\x0e\x80\x08\0\x50\0\0\0\x37\x02\0\0\xf0\x02\0\0\x0b\x84\
1168
+\x08\0\x88\0\0\0\x37\x02\0\0\x30\x03\0\0\x10\x8c\x08\0\x90\0\0\0\x37\x02\0\0\0\
1169
+\0\0\0\0\0\0\0\x98\0\0\0\x37\x02\0\0\x30\x03\0\0\x10\x8c\x08\0\xa0\0\0\0\x37\
1170
+\x02\0\0\x49\x03\0\0\x16\x90\x08\0\xa8\0\0\0\x37\x02\0\0\x49\x03\0\0\x0d\x90\
1171
+\x08\0\xc0\0\0\0\x37\x02\0\0\x6a\x03\0\0\x0a\x08\x06\0\xe8\0\0\0\x37\x02\0\0\
1172
+\xa1\x03\0\0\x1f\x18\x06\0\x38\x01\0\0\x37\x02\0\0\xd1\x03\0\0\x0f\xac\x04\0\
1173
+\x40\x01\0\0\x37\x02\0\0\xea\x03\0\0\x0c\x2c\x04\0\x50\x01\0\0\x37\x02\0\0\0\0\
1174
+\0\0\0\0\0\0\x58\x01\0\0\x37\x02\0\0\xfe\x03\0\0\x0b\x38\x04\0\x80\x01\0\0\x37\
1175
+\x02\0\0\x44\x04\0\0\x09\x40\x04\0\x90\x01\0\0\x37\x02\0\0\x44\x04\0\0\x09\x40\
1176
+\x04\0\xa0\x01\0\0\x37\x02\0\0\x53\x04\0\0\x0d\x50\x04\0\xb8\x01\0\0\x37\x02\0\
1177
+\0\x53\x04\0\0\x05\x50\x04\0\xd8\x01\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\xe0\x01\0\
1178
+\0\x37\x02\0\0\x71\x04\0\0\x0f\x64\x04\0\0\x02\0\0\x37\x02\0\0\x71\x04\0\0\x09\
1179
+\x64\x04\0\x10\x02\0\0\x37\x02\0\0\x44\x04\0\0\x09\x7c\x04\0\x18\x02\0\0\x37\
1180
+\x02\0\0\xbb\x04\0\0\x0c\x8c\x04\0\x20\x02\0\0\x37\x02\0\0\xcb\x04\0\0\x09\xc8\
1181
+\x04\0\x50\x02\0\0\x37\x02\0\0\xe7\x04\0\0\x17\xe0\x04\0\x60\x02\0\0\x37\x02\0\
1182
+\0\x02\x05\0\0\x16\xe8\x04\0\x80\x02\0\0\x37\x02\0\0\xe7\x04\0\0\x17\xe0\x04\0\
1183
+\x88\x02\0\0\x37\x02\0\0\x20\x05\0\0\x0f\xec\x04\0\xb0\x02\0\0\x37\x02\0\0\x63\
1184
+\x05\0\0\x0d\xf4\x04\0\xc0\x02\0\0\x37\x02\0\0\x63\x05\0\0\x0d\xf4\x04\0\xc8\
1185
+\x02\0\0\x37\x02\0\0\x76\x05\0\0\x24\x0c\x05\0\xd0\x02\0\0\x37\x02\0\0\x76\x05\
1186
+\0\0\x20\x0c\x05\0\xe0\x02\0\0\x37\x02\0\0\xa3\x05\0\0\x1b\x04\x05\0\xe8\x02\0\
1187
+\0\x37\x02\0\0\xa3\x05\0\0\x16\x04\x05\0\xf0\x02\0\0\x37\x02\0\0\xc4\x05\0\0\
1188
+\x1b\x08\x05\0\xf8\x02\0\0\x37\x02\0\0\xc4\x05\0\0\x16\x08\x05\0\0\x03\0\0\x37\
1189
+\x02\0\0\xe5\x05\0\0\x1a\x14\x05\0\x08\x03\0\0\x37\x02\0\0\x76\x05\0\0\x1d\x0c\
1190
+\x05\0\x10\x03\0\0\x37\x02\0\0\x08\x06\0\0\x18\x18\x05\0\x18\x03\0\0\x37\x02\0\
1191
+\0\x08\x06\0\0\x1c\x18\x05\0\x30\x03\0\0\x37\x02\0\0\x28\x06\0\0\x15\x74\x05\0\
1192
+\x40\x03\0\0\x37\x02\0\0\x28\x06\0\0\x1a\x74\x05\0\x58\x03\0\0\x37\x02\0\0\x5c\
1193
+\x06\0\0\x0d\x78\x05\0\x78\x03\0\0\x37\x02\0\0\x86\x06\0\0\x1a\x7c\x05\0\x88\
1194
+\x03\0\0\x37\x02\0\0\xa4\x06\0\0\x1b\x84\x05\0\xa8\x03\0\0\x37\x02\0\0\x86\x06\
1195
+\0\0\x1a\x7c\x05\0\xb0\x03\0\0\x37\x02\0\0\xc8\x06\0\0\x13\x88\x05\0\xd8\x03\0\
1196
+\0\x37\x02\0\0\x19\x07\0\0\x11\x90\x05\0\xe8\x03\0\0\x37\x02\0\0\x19\x07\0\0\
1197
+\x11\x90\x05\0\xf0\x03\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x10\x04\0\0\x37\x02\0\0\
1198
+\x30\x07\0\0\x15\x34\x06\0\x18\x04\0\0\x37\x02\0\0\x30\x07\0\0\x09\x34\x06\0\
1199
+\x20\x04\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x70\x04\0\0\x37\x02\0\0\x4f\x07\0\0\
1200
+\x19\x38\x06\0\x80\x04\0\0\x37\x02\0\0\x4f\x07\0\0\x20\x38\x06\0\xa0\x04\0\0\
1201
+\x37\x02\0\0\0\0\0\0\0\0\0\0\xf0\x04\0\0\x37\x02\0\0\x71\x07\0\0\x17\x20\x05\0\
1202
+\0\x05\0\0\x37\x02\0\0\x8c\x07\0\0\x18\x28\x05\0\x30\x05\0\0\x37\x02\0\0\x71\
1203
+\x07\0\0\x17\x20\x05\0\x48\x05\0\0\x37\x02\0\0\xad\x07\0\0\x0f\x2c\x05\0\x70\
1204
+\x05\0\0\x37\x02\0\0\x63\x05\0\0\x0d\x34\x05\0\x80\x05\0\0\x37\x02\0\0\x63\x05\
1205
+\0\0\x0d\x34\x05\0\x88\x05\0\0\x37\x02\0\0\xf2\x07\0\0\x1d\x44\x05\0\xc8\x05\0\
1206
+\0\x37\x02\0\0\x15\x08\0\0\x1d\x48\x05\0\x08\x06\0\0\x37\x02\0\0\x38\x08\0\0\
1207
+\x1b\x50\x05\0\x10\x06\0\0\x37\x02\0\0\x5b\x08\0\0\x05\x3c\x02\0\x58\x06\0\0\
1208
+\x37\x02\0\0\x73\x08\0\0\x19\xc4\x02\0\xd0\x06\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\
1209
+\xd8\x06\0\0\x37\x02\0\0\x99\x08\0\0\x0f\xd4\x02\0\0\x07\0\0\x37\x02\0\0\x63\
1210
+\x05\0\0\x0d\xdc\x02\0\x18\x07\0\0\x37\x02\0\0\x63\x05\0\0\x0d\xdc\x02\0\x20\
1211
+\x07\0\0\x37\x02\0\0\xde\x08\0\0\x0d\xec\x02\0\x40\x07\0\0\x37\x02\0\0\x0d\x09\
1212
+\0\0\x20\xf0\x02\0\x68\x07\0\0\x37\x02\0\0\x39\x09\0\0\x13\xf8\x02\0\x90\x07\0\
1213
+\0\x37\x02\0\0\x19\x07\0\0\x11\0\x03\0\xa8\x07\0\0\x37\x02\0\0\x19\x07\0\0\x11\
1214
+\0\x03\0\xb0\x07\0\0\x37\x02\0\0\x81\x09\0\0\x19\x10\x03\0\xb8\x07\0\0\x37\x02\
1215
+\0\0\x81\x09\0\0\x34\x10\x03\0\xe0\x07\0\0\x37\x02\0\0\xb7\x09\0\0\x15\x24\x03\
1216
+\0\xf0\x07\0\0\x37\x02\0\0\xf8\x09\0\0\x17\x20\x03\0\x18\x08\0\0\x37\x02\0\0\
1217
+\x2f\x0a\0\0\x15\x30\x03\0\x30\x08\0\0\x37\x02\0\0\x2f\x0a\0\0\x15\x30\x03\0\
1218
+\x38\x08\0\0\x37\x02\0\0\x4a\x0a\0\0\x27\x40\x03\0\x70\x08\0\0\x37\x02\0\0\x75\
1219
+\x0a\0\0\x27\x5c\x03\0\x80\x08\0\0\x37\x02\0\0\xa5\x0a\0\0\x1c\xc0\x03\0\x88\
1220
+\x08\0\0\x37\x02\0\0\xe1\x0a\0\0\x20\xcc\x03\0\x98\x08\0\0\x37\x02\0\0\xe1\x0a\
1221
+\0\0\x2f\xcc\x03\0\xa0\x08\0\0\x37\x02\0\0\xe1\x0a\0\0\x36\xcc\x03\0\xa8\x08\0\
1222
+\0\x37\x02\0\0\xe1\x0a\0\0\x15\xcc\x03\0\x18\x09\0\0\x37\x02\0\0\x1d\x0b\0\0\
1223
+\x43\x70\x03\0\x38\x09\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x40\x09\0\0\x37\x02\0\0\
1224
+\x1d\x0b\0\0\x17\x70\x03\0\x68\x09\0\0\x37\x02\0\0\x2f\x0a\0\0\x15\x78\x03\0\
1225
+\x80\x09\0\0\x37\x02\0\0\x2f\x0a\0\0\x15\x78\x03\0\x88\x09\0\0\x37\x02\0\0\x6d\
1226
+\x0b\0\0\x19\x88\x03\0\x90\x09\0\0\x37\x02\0\0\x6d\x0b\0\0\x15\x88\x03\0\x98\
1227
+\x09\0\0\x37\x02\0\0\x9d\x0b\0\0\x19\x90\x03\0\xa0\x09\0\0\x37\x02\0\0\xcd\x0b\
1228
+\0\0\x1b\x8c\x03\0\xd0\x09\0\0\x37\x02\0\0\x08\x0c\0\0\x19\xa0\x03\0\xe8\x09\0\
1229
+\0\x37\x02\0\0\x08\x0c\0\0\x19\xa0\x03\0\xf0\x09\0\0\x37\x02\0\0\x27\x0c\0\0\
1230
+\x2b\xb0\x03\0\x10\x0a\0\0\x37\x02\0\0\xa5\x0a\0\0\x1f\xc0\x03\0\x30\x0a\0\0\
1231
+\x37\x02\0\0\x56\x0c\0\0\x21\xe0\x03\0\x40\x0a\0\0\x37\x02\0\0\x7e\x0c\0\0\x20\
1232
+\xf0\x03\0\x48\x0a\0\0\x37\x02\0\0\x7e\x0c\0\0\x2c\xf0\x03\0\x60\x0a\0\0\x37\
1233
+\x02\0\0\x7e\x0c\0\0\x14\xf0\x03\0\x70\x0a\0\0\x37\x02\0\0\xae\x0c\0\0\x20\xec\
1234
+\x03\0\x80\x0a\0\0\x37\x02\0\0\x5b\x08\0\0\x05\x3c\x02\0\xb0\x0a\0\0\x37\x02\0\
1235
+\0\xd6\x0c\0\0\x38\xcc\x02\0\xd0\x0a\0\0\x37\x02\0\0\xd6\x0c\0\0\x05\xcc\x02\0\
1236
+\xe8\x0a\0\0\x37\x02\0\0\x5b\x08\0\0\x05\x3c\x02\0\xf8\x0a\0\0\x37\x02\0\0\x14\
1237
+\x0d\0\0\x1c\xd0\x06\0\x08\x0b\0\0\x37\x02\0\0\x14\x0d\0\0\x10\xd0\x06\0\x10\
1238
+\x0b\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x60\x0b\0\0\x37\x02\0\0\x4f\x07\0\0\x19\
1239
+\xd4\x06\0\x68\x0b\0\0\x37\x02\0\0\x4f\x07\0\0\x20\xd4\x06\0\xa0\x0b\0\0\x37\
1240
+\x02\0\0\x3a\x0d\0\0\x2d\x0c\x07\0\xb0\x0b\0\0\x37\x02\0\0\x3a\x0d\0\0\x1d\x0c\
1241
+\x07\0\xb8\x0b\0\0\x37\x02\0\0\x3a\x0d\0\0\x2d\x0c\x07\0\xc8\x0b\0\0\x37\x02\0\
1242
+\0\x69\x0d\0\0\x2d\xe0\x06\0\xf8\x0b\0\0\x37\x02\0\0\x69\x0d\0\0\x1d\xe0\x06\0\
1243
+\x08\x0c\0\0\x37\x02\0\0\x69\x0d\0\0\x2d\xe0\x06\0\x18\x0c\0\0\x37\x02\0\0\0\0\
1244
+\0\0\0\0\0\0\xe8\x0c\0\0\x37\x02\0\0\x98\x0d\0\0\x20\x74\x06\0\xf0\x0c\0\0\x37\
1245
+\x02\0\0\x98\x0d\0\0\x27\x74\x06\0\x18\x0d\0\0\x37\x02\0\0\xc1\x0d\0\0\x27\xb0\
1246
+\x06\0\x20\x0d\0\0\x37\x02\0\0\xc1\x0d\0\0\x14\xb0\x06\0\x28\x0d\0\0\x37\x02\0\
1247
+\0\x0a\x0e\0\0\x05\xa4\x01\0\x38\x0d\0\0\x37\x02\0\0\x0a\x0e\0\0\x05\xa4\x01\0\
1248
+\x60\x0d\0\0\x37\x02\0\0\x63\x05\0\0\x0d\x60\x05\0\x70\x0d\0\0\x37\x02\0\0\0\0\
1249
+\0\0\0\0\0\0\x80\x0d\0\0\x37\x02\0\0\x98\x0d\0\0\x20\x50\x07\0\x88\x0d\0\0\x37\
1250
+\x02\0\0\x98\x0d\0\0\x27\x50\x07\0\xc0\x0d\0\0\x37\x02\0\0\x3a\x0d\0\0\x2d\x88\
1251
+\x07\0\xd0\x0d\0\0\x37\x02\0\0\x3a\x0d\0\0\x1d\x88\x07\0\xd8\x0d\0\0\x37\x02\0\
1252
+\0\x3a\x0d\0\0\x2d\x88\x07\0\xe8\x0d\0\0\x37\x02\0\0\x69\x0d\0\0\x2d\x5c\x07\0\
1253
+\x18\x0e\0\0\x37\x02\0\0\x69\x0d\0\0\x1d\x5c\x07\0\x28\x0e\0\0\x37\x02\0\0\x69\
1254
+\x0d\0\0\x2d\x5c\x07\0\x40\x0e\0\0\x37\x02\0\0\x47\x0e\0\0\x1a\xac\x05\0\x50\
1255
+\x0e\0\0\x37\x02\0\0\x65\x0e\0\0\x1b\xb4\x05\0\x60\x0e\0\0\x37\x02\0\0\x47\x0e\
1256
+\0\0\x1a\xac\x05\0\x68\x0e\0\0\x37\x02\0\0\x89\x0e\0\0\x13\xb8\x05\0\x90\x0e\0\
1257
+\0\x37\x02\0\0\x19\x07\0\0\x11\xc0\x05\0\xa0\x0e\0\0\x37\x02\0\0\x19\x07\0\0\
1258
+\x11\xc0\x05\0\xb0\x0e\0\0\x37\x02\0\0\x5b\x08\0\0\x05\x3c\x02\0\xc0\x0e\0\0\
1259
+\x37\x02\0\0\xda\x0e\0\0\x27\xd4\x07\0\xd0\x0e\0\0\x37\x02\0\0\xda\x0e\0\0\x14\
1260
+\xd4\x07\0\xf0\x0e\0\0\x37\x02\0\0\x69\x0d\0\0\x2d\xd8\x07\0\0\x0f\0\0\x37\x02\
1261
+\0\0\x69\x0d\0\0\x1d\xd8\x07\0\x08\x0f\0\0\x37\x02\0\0\x69\x0d\0\0\x2d\xd8\x07\
1262
+\0\x30\x0f\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x80\x0f\0\0\x37\x02\0\0\x3a\x0d\0\0\
1263
+\x1d\x04\x08\0\x88\x0f\0\0\x37\x02\0\0\x3a\x0d\0\0\x2d\x04\x08\0\x98\x0f\0\0\
1264
+\x37\x02\0\0\x0a\x0e\0\0\x05\xa4\x01\0\xf0\x0f\0\0\x37\x02\0\0\x0a\x0e\0\0\x05\
1265
+\xa4\x01\0\x30\x10\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x48\x10\0\0\x37\x02\0\0\x23\
1266
+\x0f\0\0\x05\xdc\x01\0\x50\x10\0\0\x37\x02\0\0\x65\x0f\0\0\x23\xd0\x01\0\x68\
1267
+\x10\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\x70\x10\0\0\x37\x02\0\0\x99\x0f\0\0\x1b\
1268
+\xe0\x01\0\x90\x10\0\0\x37\x02\0\0\xc0\x0f\0\0\x11\xf4\x01\0\xa8\x10\0\0\x37\
1269
+\x02\0\0\xe9\x0f\0\0\x19\xe4\x01\0\xc0\x10\0\0\x37\x02\0\0\x17\x10\0\0\x27\x08\
1270
+\x02\0\xc8\x10\0\0\x37\x02\0\0\x17\x10\0\0\x46\x08\x02\0\xd8\x10\0\0\x37\x02\0\
1271
+\0\x17\x10\0\0\x2d\x08\x02\0\xe0\x10\0\0\x37\x02\0\0\xc0\x0f\0\0\x11\xf4\x01\0\
1272
+\x08\x11\0\0\x37\x02\0\0\x17\x10\0\0\x46\x08\x02\0\x20\x11\0\0\x37\x02\0\0\x17\
1273
+\x10\0\0\x27\x08\x02\0\x28\x11\0\0\x37\x02\0\0\x17\x10\0\0\x2d\x08\x02\0\x30\
1274
+\x11\0\0\x37\x02\0\0\xc0\x0f\0\0\x11\xf4\x01\0\x58\x11\0\0\x37\x02\0\0\x17\x10\
1275
+\0\0\x27\x08\x02\0\x60\x11\0\0\x37\x02\0\0\x17\x10\0\0\x46\x08\x02\0\x78\x11\0\
1276
+\0\x37\x02\0\0\x17\x10\0\0\x2d\x08\x02\0\x80\x11\0\0\x37\x02\0\0\xc0\x0f\0\0\
1277
+\x11\xf4\x01\0\xa8\x11\0\0\x37\x02\0\0\x17\x10\0\0\x27\x08\x02\0\xb0\x11\0\0\
1278
+\x37\x02\0\0\x17\x10\0\0\x46\x08\x02\0\xc8\x11\0\0\x37\x02\0\0\x17\x10\0\0\x2d\
1279
+\x08\x02\0\xd0\x11\0\0\x37\x02\0\0\xc0\x0f\0\0\x11\xf4\x01\0\xf8\x11\0\0\x37\
1280
+\x02\0\0\x17\x10\0\0\x46\x08\x02\0\x10\x12\0\0\x37\x02\0\0\x17\x10\0\0\x27\x08\
1281
+\x02\0\x18\x12\0\0\x37\x02\0\0\x17\x10\0\0\x2d\x08\x02\0\x20\x12\0\0\x37\x02\0\
1282
+\0\xc0\x0f\0\0\x11\xf4\x01\0\x48\x12\0\0\x37\x02\0\0\x17\x10\0\0\x46\x08\x02\0\
1283
+\x60\x12\0\0\x37\x02\0\0\x17\x10\0\0\x27\x08\x02\0\x68\x12\0\0\x37\x02\0\0\x17\
1284
+\x10\0\0\x2d\x08\x02\0\x70\x12\0\0\x37\x02\0\0\xc0\x0f\0\0\x11\xf4\x01\0\x98\
1285
+\x12\0\0\x37\x02\0\0\x17\x10\0\0\x46\x08\x02\0\xb0\x12\0\0\x37\x02\0\0\x17\x10\
1286
+\0\0\x27\x08\x02\0\xb8\x12\0\0\x37\x02\0\0\x17\x10\0\0\x2d\x08\x02\0\xc0\x12\0\
1287
+\0\x37\x02\0\0\xc0\x0f\0\0\x11\xf4\x01\0\xe0\x12\0\0\x37\x02\0\0\x17\x10\0\0\
1288
+\x46\x08\x02\0\xe8\x12\0\0\x37\x02\0\0\x17\x10\0\0\x27\x08\x02\0\xf0\x12\0\0\
1289
+\x37\x02\0\0\x17\x10\0\0\x2d\x08\x02\0\xf8\x12\0\0\x37\x02\0\0\x23\x0f\0\0\x3d\
1290
+\xdc\x01\0\x08\x13\0\0\x37\x02\0\0\x23\x0f\0\0\x05\xdc\x01\0\x18\x13\0\0\x37\
1291
+\x02\0\0\x63\x10\0\0\x0d\xa4\x08\0\x28\x13\0\0\x37\x02\0\0\x63\x10\0\0\x0d\xa4\
1292
+\x08\0\x30\x13\0\0\x37\x02\0\0\x77\x10\0\0\x2e\xa8\x08\0\x50\x13\0\0\x37\x02\0\
1293
+\0\x77\x10\0\0\x24\xa8\x08\0\x58\x13\0\0\x37\x02\0\0\x77\x10\0\0\x13\xa8\x08\0\
1294
+\x68\x13\0\0\x37\x02\0\0\x77\x10\0\0\x2e\xa8\x08\0\x70\x13\0\0\x37\x02\0\0\xb6\
1295
+\x10\0\0\x15\xb4\x08\0\x88\x13\0\0\x37\x02\0\0\xfe\x10\0\0\x11\xc0\x08\0\x90\
1296
+\x13\0\0\x37\x02\0\0\0\0\0\0\0\0\0\0\xb0\x13\0\0\x37\x02\0\0\x17\x11\0\0\x01\
1297
+\xe4\x08\0\xb8\x13\0\0\x37\x02\0\0\x19\x11\0\0\x18\xc4\x08\0\0\0\0\0\0\0\0\0\0\
1298
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x03\0\x03\0\0\0\0\0\0\0\0\0\0\0\
1299
+\0\0\0\0\0\0\x0d\x01\0\0\0\0\x03\0\xb0\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x78\x01\
1300
+\0\0\0\0\x03\0\xb8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2e\x01\0\0\0\0\x03\0\x90\x13\
1301
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xbd\0\0\0\0\0\x03\0\xd0\x01\0\0\0\0\0\0\0\0\0\0\0\
1302
+\0\0\0\x2a\x02\0\0\0\0\x03\0\x20\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x05\x01\0\0\0\
1303
+\0\x03\0\xe8\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x43\x02\0\0\0\0\x03\0\x10\x04\0\0\
1304
+\0\0\0\0\0\0\0\0\0\0\0\0\x26\x01\0\0\0\0\x03\0\xe0\x02\0\0\0\0\0\0\0\0\0\0\0\0\
1305
+\0\0\x1a\x02\0\0\0\0\x03\0\x30\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x12\x02\0\0\0\0\
1306
+\x03\0\x38\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd4\0\0\0\0\0\x03\0\xf0\x03\0\0\0\0\
1307
+\0\0\0\0\0\0\0\0\0\0\x0a\x02\0\0\0\0\x03\0\xf8\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
1308
+\x47\x01\0\0\0\0\x03\0\xe8\x0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x57\x01\0\0\0\0\x03\
1309
+\0\xa0\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd0\x01\0\0\0\0\x03\0\x40\x10\0\0\0\0\0\
1310
+\0\0\0\0\0\0\0\0\0\x7f\x01\0\0\0\0\x03\0\x78\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
1311
+\x53\x02\0\0\0\0\x03\0\xb0\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe9\x01\0\0\0\0\x03\
1312
+\0\x50\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc8\x01\0\0\0\0\x03\0\xc0\x06\0\0\0\0\0\
1313
+\0\0\0\0\0\0\0\0\0\xb0\x01\0\0\0\0\x03\0\x60\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
1314
+\x8f\x01\0\0\0\0\x03\0\x60\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5f\x01\0\0\0\0\x03\
1315
+\0\x30\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4f\x01\0\0\0\0\x03\0\x40\x0a\0\0\0\0\0\
1316
+\0\0\0\0\0\0\0\0\0\xe1\x01\0\0\0\0\x03\0\xe0\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
1317
+\xc0\x01\0\0\0\0\x03\0\x48\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x67\x01\0\0\0\0\x03\
1318
+\0\x18\x09\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x22\x02\0\0\0\0\x03\0\x80\x08\0\0\0\0\0\
1319
+\0\0\0\0\0\0\0\0\0\xb8\x01\0\0\0\0\x03\0\xf8\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
1320
+\x87\x01\0\0\0\0\x03\0\x50\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xe4\0\0\0\0\0\x03\0\
1321
+\x08\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1e\x01\0\0\0\0\x03\0\xe8\x0a\0\0\0\0\0\0\
1322
+\0\0\0\0\0\0\0\0\xdc\0\0\0\0\0\x03\0\xb0\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4b\
1323
+\x02\0\0\0\0\x03\0\xd8\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa8\x01\0\0\0\0\x03\0\
1324
+\x80\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3f\x01\0\0\0\0\x03\0\xb0\x0b\0\0\0\0\0\0\
1325
+\0\0\0\0\0\0\0\0\xfd\0\0\0\0\0\x03\0\xc8\x0b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3b\
1326
+\x02\0\0\0\0\x03\0\xf8\x0b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd9\x01\0\0\0\0\x03\0\
1327
+\x18\x0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x02\x02\0\0\0\0\x03\0\x10\x0c\0\0\0\0\0\0\
1328
+\0\0\0\0\0\0\0\0\xcc\0\0\0\0\0\x03\0\x18\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa0\
1329
+\x01\0\0\0\0\x03\0\xc0\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x01\0\0\0\0\x03\0\
1330
+\xd0\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc4\0\0\0\0\0\x03\0\xe8\x0d\0\0\0\0\0\0\0\
1331
+\0\0\0\0\0\0\0\xfa\x01\0\0\0\0\x03\0\x18\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x37\
1332
+\x01\0\0\0\0\x03\0\0\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xf5\0\0\0\0\0\x03\0\x18\
1333
+\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x32\x02\0\0\0\0\x03\0\xf0\x0f\0\0\0\0\0\0\0\0\
1334
+\0\0\0\0\0\0\xf1\x01\0\0\0\0\x03\0\x30\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x97\x01\
1335
+\0\0\0\0\x03\0\x60\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6f\x01\0\0\0\0\x03\0\x18\
1336
+\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xec\0\0\0\0\0\x03\0\xb8\x13\0\0\0\0\0\0\0\0\0\
1337
+\0\0\0\0\0\x59\0\0\0\x12\0\x03\0\0\0\0\0\0\0\0\0\xc8\x13\0\0\0\0\0\0\x3e\0\0\0\
1338
+\x11\0\x05\0\0\0\0\0\0\0\0\0\x28\0\0\0\0\0\0\0\x01\0\0\0\x11\0\x05\0\x28\0\0\0\
1339
+\0\0\0\0\x28\0\0\0\0\0\0\0\x86\0\0\0\x11\0\x05\0\x50\0\0\0\0\0\0\0\x28\0\0\0\0\
1340
+\0\0\0\x7d\0\0\0\x11\0\x06\0\0\0\0\0\0\0\0\0\x07\0\0\0\0\0\0\0\x28\0\0\0\0\0\0\
1341
+\0\x01\0\0\0\x36\0\0\0\x50\0\0\0\0\0\0\0\x01\0\0\0\x37\0\0\0\x70\x13\0\0\0\0\0\
1342
+\0\x01\0\0\0\x38\0\0\0\x20\x05\0\0\0\0\0\0\x04\0\0\0\x36\0\0\0\x2c\x05\0\0\0\0\
1343
+\0\0\x04\0\0\0\x37\0\0\0\x38\x05\0\0\0\0\0\0\x04\0\0\0\x38\0\0\0\x50\x05\0\0\0\
1344
+\0\0\0\x04\0\0\0\x39\0\0\0\x2c\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\0\0\0\0\0\
1345
+\0\0\x04\0\0\0\x01\0\0\0\x50\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\0\0\0\0\0\0\
1346
+\0\x04\0\0\0\x01\0\0\0\x70\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x80\0\0\0\0\0\0\0\
1347
+\x04\0\0\0\x01\0\0\0\x90\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xa0\0\0\0\0\0\0\0\
1348
+\x04\0\0\0\x01\0\0\0\xb0\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\0\0\0\0\0\0\0\
1349
+\x04\0\0\0\x01\0\0\0\xd0\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\0\0\0\0\0\0\0\
1350
+\x04\0\0\0\x01\0\0\0\xf0\0\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\x01\0\0\0\0\0\0\
1351
+\x04\0\0\0\x01\0\0\0\x10\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x20\x01\0\0\0\0\0\
1352
+\0\x04\0\0\0\x01\0\0\0\x30\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\x01\0\0\0\0\
1353
+\0\0\x04\0\0\0\x01\0\0\0\x50\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\x01\0\0\0\
1354
+\0\0\0\x04\0\0\0\x01\0\0\0\x70\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x80\x01\0\0\
1355
+\0\0\0\0\x04\0\0\0\x01\0\0\0\x90\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xa0\x01\0\
1356
+\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xb0\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\x01\
1357
+\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xd0\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\
1358
+\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xf0\x01\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\
1359
+\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x10\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\
1360
+\x20\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x30\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\
1361
+\0\x40\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x50\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\
1362
+\0\0\x60\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x70\x02\0\0\0\0\0\0\x04\0\0\0\x01\
1363
+\0\0\0\x80\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x90\x02\0\0\0\0\0\0\x04\0\0\0\
1364
+\x01\0\0\0\xa0\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xb0\x02\0\0\0\0\0\0\x04\0\0\
1365
+\0\x01\0\0\0\xc0\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xd0\x02\0\0\0\0\0\0\x04\0\
1366
+\0\0\x01\0\0\0\xe0\x02\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xf0\x02\0\0\0\0\0\0\x04\
1367
+\0\0\0\x01\0\0\0\0\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x10\x03\0\0\0\0\0\0\x04\
1368
+\0\0\0\x01\0\0\0\x20\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x30\x03\0\0\0\0\0\0\
1369
+\x04\0\0\0\x01\0\0\0\x40\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x50\x03\0\0\0\0\0\
1370
+\0\x04\0\0\0\x01\0\0\0\x60\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x70\x03\0\0\0\0\
1371
+\0\0\x04\0\0\0\x01\0\0\0\x80\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x90\x03\0\0\0\
1372
+\0\0\0\x04\0\0\0\x01\0\0\0\xa0\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xb0\x03\0\0\
1373
+\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xd0\x03\0\
1374
+\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\x03\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xf0\x03\
1375
+\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x10\x04\
1376
+\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x20\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x30\
1377
+\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\
1378
+\x50\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\
1379
+\0\x70\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x80\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\
1380
+\0\0\x90\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xa0\x04\0\0\0\0\0\0\x04\0\0\0\x01\
1381
+\0\0\0\xb0\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\x04\0\0\0\0\0\0\x04\0\0\0\
1382
+\x01\0\0\0\xd0\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\x04\0\0\0\0\0\0\x04\0\0\
1383
+\0\x01\0\0\0\xf0\x04\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\x05\0\0\0\0\0\0\x04\0\0\
1384
+\0\x01\0\0\0\x10\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x20\x05\0\0\0\0\0\0\x04\0\
1385
+\0\0\x01\0\0\0\x30\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\x05\0\0\0\0\0\0\x04\
1386
+\0\0\0\x01\0\0\0\x50\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\x05\0\0\0\0\0\0\
1387
+\x04\0\0\0\x01\0\0\0\x70\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x80\x05\0\0\0\0\0\
1388
+\0\x04\0\0\0\x01\0\0\0\x90\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xa0\x05\0\0\0\0\
1389
+\0\0\x04\0\0\0\x01\0\0\0\xb0\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\x05\0\0\0\
1390
+\0\0\0\x04\0\0\0\x01\0\0\0\xd0\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\x05\0\0\
1391
+\0\0\0\0\x04\0\0\0\x01\0\0\0\xf0\x05\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\x06\0\0\
1392
+\0\0\0\0\x04\0\0\0\x01\0\0\0\x10\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x20\x06\0\
1393
+\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x30\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\x06\
1394
+\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x50\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\
1395
+\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x70\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\
1396
+\x80\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x90\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\
1397
+\0\xa0\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xb0\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\
1398
+\0\0\xc0\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xd0\x06\0\0\0\0\0\0\x04\0\0\0\x01\
1399
+\0\0\0\xe0\x06\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xf0\x06\0\0\0\0\0\0\x04\0\0\0\
1400
+\x01\0\0\0\0\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x10\x07\0\0\0\0\0\0\x04\0\0\0\
1401
+\x01\0\0\0\x20\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x30\x07\0\0\0\0\0\0\x04\0\0\
1402
+\0\x01\0\0\0\x40\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x50\x07\0\0\0\0\0\0\x04\0\
1403
+\0\0\x01\0\0\0\x60\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x70\x07\0\0\0\0\0\0\x04\
1404
+\0\0\0\x01\0\0\0\x80\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x90\x07\0\0\0\0\0\0\
1405
+\x04\0\0\0\x01\0\0\0\xa0\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xb0\x07\0\0\0\0\0\
1406
+\0\x04\0\0\0\x01\0\0\0\xc0\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xd0\x07\0\0\0\0\
1407
+\0\0\x04\0\0\0\x01\0\0\0\xe0\x07\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xf0\x07\0\0\0\
1408
+\0\0\0\x04\0\0\0\x01\0\0\0\0\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x10\x08\0\0\0\
1409
+\0\0\0\x04\0\0\0\x01\0\0\0\x20\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x30\x08\0\0\
1410
+\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x50\x08\0\
1411
+\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x70\x08\
1412
+\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x80\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x90\
1413
+\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xa0\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\
1414
+\xb0\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\
1415
+\0\xd0\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\
1416
+\0\0\xf0\x08\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\
1417
+\0\0\x10\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x20\x09\0\0\0\0\0\0\x04\0\0\0\x01\
1418
+\0\0\0\x30\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\x09\0\0\0\0\0\0\x04\0\0\0\
1419
+\x01\0\0\0\x50\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\x09\0\0\0\0\0\0\x04\0\0\
1420
+\0\x01\0\0\0\x70\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x80\x09\0\0\0\0\0\0\x04\0\
1421
+\0\0\x01\0\0\0\x90\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xa0\x09\0\0\0\0\0\0\x04\
1422
+\0\0\0\x01\0\0\0\xb0\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\x09\0\0\0\0\0\0\
1423
+\x04\0\0\0\x01\0\0\0\xd0\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\x09\0\0\0\0\0\
1424
+\0\x04\0\0\0\x01\0\0\0\xf0\x09\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\x0a\0\0\0\0\0\
1425
+\0\x04\0\0\0\x01\0\0\0\x10\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x20\x0a\0\0\0\0\
1426
+\0\0\x04\0\0\0\x01\0\0\0\x30\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\x0a\0\0\0\
1427
+\0\0\0\x04\0\0\0\x01\0\0\0\x50\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x60\x0a\0\0\
1428
+\0\0\0\0\x04\0\0\0\x01\0\0\0\x70\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x80\x0a\0\
1429
+\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x90\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xa0\x0a\
1430
+\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xb0\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\
1431
+\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xd0\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\
1432
+\xe0\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xf0\x0a\0\0\0\0\0\0\x04\0\0\0\x01\0\0\
1433
+\0\0\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x10\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\
1434
+\0\x20\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x30\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\
1435
+\0\0\x40\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x50\x0b\0\0\0\0\0\0\x04\0\0\0\x01\
1436
+\0\0\0\x60\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x70\x0b\0\0\0\0\0\0\x04\0\0\0\
1437
+\x01\0\0\0\x80\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x90\x0b\0\0\0\0\0\0\x04\0\0\
1438
+\0\x01\0\0\0\xa0\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xb0\x0b\0\0\0\0\0\0\x04\0\
1439
+\0\0\x01\0\0\0\xc0\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xd0\x0b\0\0\0\0\0\0\x04\
1440
+\0\0\0\x01\0\0\0\xe0\x0b\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xf0\x0b\0\0\0\0\0\0\
1441
+\x04\0\0\0\x01\0\0\0\0\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x10\x0c\0\0\0\0\0\0\
1442
+\x04\0\0\0\x01\0\0\0\x20\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x30\x0c\0\0\0\0\0\
1443
+\0\x04\0\0\0\x01\0\0\0\x40\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x50\x0c\0\0\0\0\
1444
+\0\0\x04\0\0\0\x01\0\0\0\x60\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x70\x0c\0\0\0\
1445
+\0\0\0\x04\0\0\0\x01\0\0\0\x80\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x90\x0c\0\0\
1446
+\0\0\0\0\x04\0\0\0\x01\0\0\0\xa0\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xb0\x0c\0\
1447
+\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xc0\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xd0\x0c\
1448
+\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xe0\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\xf0\
1449
+\x0c\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\0\x0d\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x10\
1450
+\x0d\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x20\x0d\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\
1451
+\x30\x0d\0\0\0\0\0\0\x04\0\0\0\x01\0\0\0\x40\x0d\0\0\0\0\0\0\x04\0\0\0\x01\0\0\
1452
+\0\x3f\x40\x41\x42\x43\0\x74\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\x5f\x74\
1453
+\x6f\x65\x70\x6c\x69\x74\x7a\x5f\x6b\x65\x79\0\x2e\x74\x65\x78\x74\0\x2e\x72\
1454
+\x65\x6c\x2e\x42\x54\x46\x2e\x65\x78\x74\0\x2e\x72\x65\x6c\x73\x6f\x63\x6b\x65\
1455
+\x74\0\x2e\x6d\x61\x70\x73\0\x74\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\x5f\
1456
+\x63\x6f\x6e\x66\x69\x67\x75\x72\x61\x74\x69\x6f\x6e\x73\0\x74\x75\x6e\x5f\x72\
1457
+\x73\x73\x5f\x73\x74\x65\x65\x72\x69\x6e\x67\x5f\x70\x72\x6f\x67\0\x2e\x6c\x6c\
1458
+\x76\x6d\x5f\x61\x64\x64\x72\x73\x69\x67\0\x5f\x6c\x69\x63\x65\x6e\x73\x65\0\
1459
+\x74\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\x5f\x69\x6e\x64\x69\x72\x65\x63\
1460
+\x74\x69\x6f\x6e\x5f\x74\x61\x62\x6c\x65\0\x2e\x73\x74\x72\x74\x61\x62\0\x2e\
1461
+\x73\x79\x6d\x74\x61\x62\0\x2e\x72\x65\x6c\x2e\x42\x54\x46\0\x4c\x42\x42\x30\
1462
+\x5f\x39\0\x4c\x42\x42\x30\x5f\x38\x39\0\x4c\x42\x42\x30\x5f\x36\x39\0\x4c\x42\
1463
+\x42\x30\x5f\x35\x39\0\x4c\x42\x42\x30\x5f\x34\x39\0\x4c\x42\x42\x30\x5f\x33\
1464
+\x39\0\x4c\x42\x42\x30\x5f\x31\x30\x39\0\x4c\x42\x42\x30\x5f\x39\x38\0\x4c\x42\
1465
+\x42\x30\x5f\x37\x38\0\x4c\x42\x42\x30\x5f\x31\x38\0\x4c\x42\x42\x30\x5f\x31\
1466
+\x30\x38\0\x4c\x42\x42\x30\x5f\x38\x37\0\x4c\x42\x42\x30\x5f\x34\x37\0\x4c\x42\
1467
+\x42\x30\x5f\x31\x37\0\x4c\x42\x42\x30\x5f\x31\x30\x37\0\x4c\x42\x42\x30\x5f\
1468
+\x39\x36\0\x4c\x42\x42\x30\x5f\x37\x36\0\x4c\x42\x42\x30\x5f\x36\x36\0\x4c\x42\
1469
+\x42\x30\x5f\x34\x36\0\x4c\x42\x42\x30\x5f\x36\x35\0\x4c\x42\x42\x30\x5f\x34\
1470
+\x35\0\x4c\x42\x42\x30\x5f\x33\x35\0\x4c\x42\x42\x30\x5f\x31\x30\x35\0\x4c\x42\
1471
+\x42\x30\x5f\x34\0\x4c\x42\x42\x30\x5f\x35\x34\0\x4c\x42\x42\x30\x5f\x34\x34\0\
1472
\x4c\x42\x42\x30\x5f\x33\x34\0\x4c\x42\x42\x30\x5f\x31\x30\x34\0\x4c\x42\x42\
1473
-\x30\x5f\x38\x33\0\x4c\x42\x42\x30\x5f\x35\x33\0\x4c\x42\x42\x30\x5f\x32\x33\0\
1474
-\x4c\x42\x42\x30\x5f\x31\x30\x33\0\x4c\x42\x42\x30\x5f\x39\x32\0\x4c\x42\x42\
1475
-\x30\x5f\x38\x32\0\x4c\x42\x42\x30\x5f\x37\x32\0\x4c\x42\x42\x30\x5f\x36\x32\0\
1476
-\x4c\x42\x42\x30\x5f\x35\x32\0\x4c\x42\x42\x30\x5f\x34\x32\0\x4c\x42\x42\x30\
1477
-\x5f\x32\x32\0\x4c\x42\x42\x30\x5f\x31\x30\x32\0\x4c\x42\x42\x30\x5f\x38\x31\0\
1478
-\x4c\x42\x42\x30\x5f\x36\x31\0\x4c\x42\x42\x30\x5f\x35\x31\0\x4c\x42\x42\x30\
1479
-\x5f\x31\x31\0\x4c\x42\x42\x30\x5f\x39\x30\0\x4c\x42\x42\x30\x5f\x37\x30\0\x4c\
1480
-\x42\x42\x30\x5f\x36\x30\0\x4c\x42\x42\x30\x5f\x35\x30\0\x4c\x42\x42\x30\x5f\
1481
-\x34\x30\0\x4c\x42\x42\x30\x5f\x32\x30\0\x4c\x42\x42\x30\x5f\x31\x31\x30\0\0\0\
1482
+\x30\x5f\x39\x33\0\x4c\x42\x42\x30\x5f\x38\x33\0\x4c\x42\x42\x30\x5f\x35\x33\0\
1483
+\x4c\x42\x42\x30\x5f\x34\x33\0\x4c\x42\x42\x30\x5f\x33\x33\0\x4c\x42\x42\x30\
1484
+\x5f\x32\x33\0\x4c\x42\x42\x30\x5f\x31\x30\x33\0\x4c\x42\x42\x30\x5f\x38\x32\0\
1485
+\x4c\x42\x42\x30\x5f\x35\x32\0\x4c\x42\x42\x30\x5f\x32\x32\0\x4c\x42\x42\x30\
1486
+\x5f\x31\x30\x32\0\x4c\x42\x42\x30\x5f\x39\x31\0\x4c\x42\x42\x30\x5f\x38\x31\0\
1487
+\x4c\x42\x42\x30\x5f\x37\x31\0\x4c\x42\x42\x30\x5f\x36\x31\0\x4c\x42\x42\x30\
1488
+\x5f\x35\x31\0\x4c\x42\x42\x30\x5f\x34\x31\0\x4c\x42\x42\x30\x5f\x31\x31\0\x4c\
1489
+\x42\x42\x30\x5f\x31\x30\x31\0\x4c\x42\x42\x30\x5f\x38\x30\0\x4c\x42\x42\x30\
1490
+\x5f\x36\x30\0\x4c\x42\x42\x30\x5f\x35\x30\0\x4c\x42\x42\x30\x5f\x32\x30\0\0\0\
1491
\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\0\0\
1492
-\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\xae\0\0\0\x03\0\0\0\
1493
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x25\x4a\0\0\0\0\0\0\x6d\x02\0\0\0\0\0\0\0\0\0\
1494
-\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\0\x06\0\0\0\0\0\
1495
-\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\0\0\0\0\x04\0\0\
1496
-\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\0\0\0\x01\0\0\0\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
1497
-\0\x40\0\0\0\0\0\0\0\xe0\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\
1498
-\0\0\0\0\0\0\x64\0\0\0\x09\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x40\x3d\0\0\
1499
-\0\0\0\0\x30\0\0\0\0\0\0\0\x0c\0\0\0\x03\0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\0\0\
1500
-\0\0\x2d\0\0\0\x01\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x20\x14\0\0\0\0\0\0\
1501
-\x60\0\0\0\0\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\x88\0\0\0\
1502
-\x01\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\x14\0\0\0\0\0\0\x07\0\0\0\0\0\
1503
-\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\xc2\0\0\0\x01\0\0\0\0\0\
1504
-\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x88\x14\0\0\0\0\0\0\x8d\x16\0\0\0\0\0\0\0\0\0\0\0\
1505
-\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xbe\0\0\0\x09\0\0\0\x40\0\0\0\0\0\0\0\
1506
-\0\0\0\0\0\0\0\0\x70\x3d\0\0\0\0\0\0\x40\0\0\0\0\0\0\0\x0c\0\0\0\x07\0\0\0\x08\
1507
-\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x24\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
1508
-\0\0\0\x18\x2b\0\0\0\0\0\0\xa0\x0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\
1509
-\0\0\0\0\0\0\0\0\0\x20\0\0\0\x09\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb0\
1510
-\x3d\0\0\0\0\0\0\x70\x0c\0\0\0\0\0\0\x0c\0\0\0\x09\0\0\0\x08\0\0\0\0\0\0\0\x10\
1511
-\0\0\0\0\0\0\0\x79\0\0\0\x03\x4c\xff\x6f\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\0\0\x20\
1512
-\x4a\0\0\0\0\0\0\x05\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\
1513
-\0\0\0\xb6\0\0\0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb8\x37\0\0\0\0\0\0\
1514
-\x88\x05\0\0\0\0\0\0\x01\0\0\0\x36\0\0\0\x08\0\0\0\0\0\0\0\x18\0\0\0\0\0\0\0";
1515
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa4\0\0\0\x03\0\0\0\0\0\0\0\0\0\
1516
+\0\0\0\0\0\0\0\0\0\0\xbd\x4b\0\0\0\0\0\0\x5b\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
1517
+\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1a\0\0\0\x01\0\0\0\x06\0\0\0\0\0\0\0\0\0\0\
1518
+\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\0\0\0\0\x04\0\0\0\0\0\0\0\
1519
+\0\0\0\0\0\0\0\0\x31\0\0\0\x01\0\0\0\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x40\0\0\
1520
+\0\0\0\0\0\xc8\x13\0\0\0\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\
1521
+\0\x2d\0\0\0\x09\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x28\x3e\0\0\0\0\0\0\
1522
+\x30\0\0\0\0\0\0\0\x0c\0\0\0\x03\0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x38\
1523
+\0\0\0\x01\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08\x14\0\0\0\0\0\0\x78\0\0\
1524
+\0\0\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\x7e\0\0\0\x01\0\0\
1525
+\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\x14\0\0\0\0\0\0\x07\0\0\0\0\0\0\0\0\0\
1526
+\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb8\0\0\0\x01\0\0\0\0\0\0\0\0\0\
1527
+\0\0\0\0\0\0\0\0\0\0\x88\x14\0\0\0\0\0\0\xdb\x16\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
1528
+\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb4\0\0\0\x09\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\
1529
+\0\0\0\0\0\x58\x3e\0\0\0\0\0\0\x40\0\0\0\0\0\0\0\x0c\0\0\0\x07\0\0\0\x08\0\0\0\
1530
+\0\0\0\0\x10\0\0\0\0\0\0\0\x24\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
1531
+\x64\x2b\0\0\0\0\0\0\x50\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0\0\0\
1532
+\0\0\0\0\0\0\x20\0\0\0\x09\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x98\x3e\0\0\
1533
+\0\0\0\0\x20\x0d\0\0\0\0\0\0\x0c\0\0\0\x09\0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\0\
1534
+\0\0\0\x6f\0\0\0\x03\x4c\xff\x6f\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\0\0\xb8\x4b\0\0\
1535
+\0\0\0\0\x05\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\
1536
+\xac\0\0\0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xb8\x38\0\0\0\0\0\0\x70\
1537
+\x05\0\0\0\0\0\0\x01\0\0\0\x35\0\0\0\x08\0\0\0\0\0\0\0\x18\0\0\0\0\0\0\0";
1538
}
22
}
1539
23
1540
#ifdef __cplusplus
24
/**
1541
diff --git a/meson.build b/meson.build
25
+ * Get the shadow vq vring address.
26
+ * @svq: Shadow virtqueue
27
+ * @addr: Destination to store address
28
+ */
29
+void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq,
30
+ struct vhost_vring_addr *addr)
31
+{
32
+ addr->desc_user_addr = (uint64_t)(intptr_t)svq->vring.desc;
33
+ addr->avail_user_addr = (uint64_t)(intptr_t)svq->vring.avail;
34
+ addr->used_user_addr = (uint64_t)(intptr_t)svq->vring.used;
35
+}
36
+
37
+size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq)
38
+{
39
+ size_t desc_size = sizeof(vring_desc_t) * svq->vring.num;
40
+ size_t avail_size = offsetof(vring_avail_t, ring) +
41
+ sizeof(uint16_t) * svq->vring.num;
42
+
43
+ return ROUND_UP(desc_size + avail_size, qemu_real_host_page_size);
44
+}
45
+
46
+size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq)
47
+{
48
+ size_t used_size = offsetof(vring_used_t, ring) +
49
+ sizeof(vring_used_elem_t) * svq->vring.num;
50
+ return ROUND_UP(used_size, qemu_real_host_page_size);
51
+}
52
+
53
+/**
54
* Set a new file descriptor for the guest to kick the SVQ and notify for avail
55
*
56
* @svq: The svq
57
diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
1542
index XXXXXXX..XXXXXXX 100644
58
index XXXXXXX..XXXXXXX 100644
1543
--- a/meson.build
59
--- a/hw/virtio/vhost-shadow-virtqueue.h
1544
+++ b/meson.build
60
+++ b/hw/virtio/vhost-shadow-virtqueue.h
1545
@@ -XXX,XX +XXX,XX @@ elif get_option('vduse_blk_export').disabled()
61
@@ -XXX,XX +XXX,XX @@
1546
endif
62
#define VHOST_SHADOW_VIRTQUEUE_H
1547
63
1548
# libbpf
64
#include "qemu/event_notifier.h"
1549
-libbpf = dependency('libbpf', required: get_option('bpf'), method: 'pkg-config')
65
+#include "hw/virtio/virtio.h"
1550
+bpf_version = '1.1.0'
66
+#include "standard-headers/linux/vhost_types.h"
1551
+libbpf = dependency('libbpf', version: '>=' + bpf_version, required: get_option('bpf'), method: 'pkg-config')
67
1552
if libbpf.found() and not cc.links('''
68
/* Shadow virtqueue to relay notifications */
1553
#include <bpf/libbpf.h>
69
typedef struct VhostShadowVirtqueue {
1554
+ #include <linux/bpf.h>
70
+ /* Shadow vring */
1555
int main(void)
71
+ struct vring vring;
1556
{
72
+
1557
+ // check flag availability
73
/* Shadow kick notifier, sent to vhost */
1558
+ int flag = BPF_F_MMAPABLE;
74
EventNotifier hdev_kick;
1559
bpf_object__destroy_skeleton(NULL);
75
/* Shadow call notifier, sent to vhost */
1560
return 0;
76
@@ -XXX,XX +XXX,XX @@ bool vhost_svq_valid_features(uint64_t features, Error **errp);
1561
}''', dependencies: libbpf)
77
1562
libbpf = not_found
78
void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd);
1563
if get_option('bpf').enabled()
79
void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd);
1564
- error('libbpf skeleton test failed')
80
+void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq,
1565
+ error('libbpf skeleton/mmaping test failed')
81
+ struct vhost_vring_addr *addr);
1566
else
82
+size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq);
1567
- warning('libbpf skeleton test failed, disabling')
83
+size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq);
1568
+ warning('libbpf skeleton/mmaping test failed, disabling')
84
1569
endif
85
void vhost_svq_stop(VhostShadowVirtqueue *svq);
1570
endif
1571
1572
diff --git a/tools/ebpf/rss.bpf.c b/tools/ebpf/rss.bpf.c
1573
index XXXXXXX..XXXXXXX 100644
1574
--- a/tools/ebpf/rss.bpf.c
1575
+++ b/tools/ebpf/rss.bpf.c
1576
@@ -XXX,XX +XXX,XX @@ struct {
1577
__uint(key_size, sizeof(__u32));
1578
__uint(value_size, sizeof(struct rss_config_t));
1579
__uint(max_entries, 1);
1580
+ __uint(map_flags, BPF_F_MMAPABLE);
1581
} tap_rss_map_configurations SEC(".maps");
1582
1583
struct {
1584
@@ -XXX,XX +XXX,XX @@ struct {
1585
__uint(key_size, sizeof(__u32));
1586
__uint(value_size, sizeof(struct toeplitz_key_data_t));
1587
__uint(max_entries, 1);
1588
+ __uint(map_flags, BPF_F_MMAPABLE);
1589
} tap_rss_map_toeplitz_key SEC(".maps");
1590
1591
struct {
1592
@@ -XXX,XX +XXX,XX @@ struct {
1593
__uint(key_size, sizeof(__u32));
1594
__uint(value_size, sizeof(__u16));
1595
__uint(max_entries, INDIRECTION_TABLE_SIZE);
1596
+ __uint(map_flags, BPF_F_MMAPABLE);
1597
} tap_rss_map_indirection_table SEC(".maps");
1598
1599
static inline void net_rx_rss_add_chunk(__u8 *rss_input, size_t *bytes_written,
1600
@@ -XXX,XX +XXX,XX @@ static inline __u32 calculate_rss_hash(struct __sk_buff *skb,
1601
return result;
1602
}
1603
1604
-SEC("tun_rss_steering")
1605
+SEC("socket")
1606
int tun_rss_steering_prog(struct __sk_buff *skb)
1607
{
1608
86
1609
--
87
--
1610
2.7.4
88
2.7.4
89
90
diff view generated by jsdifflib
1
From: Tomasz Dzieciol <t.dzieciol@partner.samsung.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Refactoring is done in preparation for support of multiple advanced
3
First half of the buffers forwarding part, preparing vhost-vdpa
4
descriptors RX modes, especially packet-split modes.
4
callbacks to SVQ to offer it. QEMU cannot enable it at this moment, so
5
this is effectively dead code at the moment, but it helps to reduce
6
patch size.
5
7
6
Signed-off-by: Tomasz Dzieciol <t.dzieciol@partner.samsung.com>
8
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
7
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
9
Acked-by: Michael S. Tsirkin <mst@redhat.com>
8
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
---
11
---
11
hw/net/e1000e_core.c | 18 ++--
12
hw/virtio/vhost-vdpa.c | 48 +++++++++++++++++++++++++++++++++++++++++-------
12
hw/net/igb_core.c | 213 ++++++++++++++++++++++++++++++-----------------
13
1 file changed, 41 insertions(+), 7 deletions(-)
13
tests/qtest/libqos/igb.c | 5 ++
14
3 files changed, 150 insertions(+), 86 deletions(-)
15
14
16
diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
15
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
17
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/net/e1000e_core.c
17
--- a/hw/virtio/vhost-vdpa.c
19
+++ b/hw/net/e1000e_core.c
18
+++ b/hw/virtio/vhost-vdpa.c
20
@@ -XXX,XX +XXX,XX @@ e1000e_write_hdr_to_rx_buffers(E1000ECore *core,
19
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_get_config(struct vhost_dev *dev, uint8_t *config,
21
}
20
return ret;
22
21
}
23
static void
22
24
-e1000e_write_to_rx_buffers(E1000ECore *core,
23
+static int vhost_vdpa_set_dev_vring_base(struct vhost_dev *dev,
25
- hwaddr ba[MAX_PS_BUFFERS],
24
+ struct vhost_vring_state *ring)
26
- e1000e_ba_state *bastate,
27
- const char *data,
28
- dma_addr_t data_len)
29
+e1000e_write_payload_frag_to_rx_buffers(E1000ECore *core,
30
+ hwaddr ba[MAX_PS_BUFFERS],
31
+ e1000e_ba_state *bastate,
32
+ const char *data,
33
+ dma_addr_t data_len)
34
{
35
while (data_len > 0) {
36
uint32_t cur_buf_len = core->rxbuf_sizes[bastate->cur_idx];
37
@@ -XXX,XX +XXX,XX @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
38
while (copy_size) {
39
iov_copy = MIN(copy_size, iov->iov_len - iov_ofs);
40
41
- e1000e_write_to_rx_buffers(core, ba, &bastate,
42
- iov->iov_base + iov_ofs, iov_copy);
43
+ e1000e_write_payload_frag_to_rx_buffers(core, ba, &bastate,
44
+ iov->iov_base +
45
+ iov_ofs,
46
+ iov_copy);
47
48
copy_size -= iov_copy;
49
iov_ofs += iov_copy;
50
@@ -XXX,XX +XXX,XX @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
51
52
if (desc_offset + desc_size >= total_size) {
53
/* Simulate FCS checksum presence in the last descriptor */
54
- e1000e_write_to_rx_buffers(core, ba, &bastate,
55
+ e1000e_write_payload_frag_to_rx_buffers(core, ba, &bastate,
56
(const char *) &fcs_pad, e1000x_fcs_len(core->mac));
57
}
58
}
59
diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c
60
index XXXXXXX..XXXXXXX 100644
61
--- a/hw/net/igb_core.c
62
+++ b/hw/net/igb_core.c
63
@@ -XXX,XX +XXX,XX @@ igb_has_rxbufs(IGBCore *core, const E1000ERingInfo *r, size_t total_size)
64
bufsize;
65
}
66
67
+static uint32_t
68
+igb_rxhdrbufsize(IGBCore *core, const E1000ERingInfo *r)
69
+{
25
+{
70
+ uint32_t srrctl = core->mac[E1000_SRRCTL(r->idx) >> 2];
26
+ trace_vhost_vdpa_set_vring_base(dev, ring->index, ring->num);
71
+ return (srrctl & E1000_SRRCTL_BSIZEHDRSIZE_MASK) >>
27
+ return vhost_vdpa_call(dev, VHOST_SET_VRING_BASE, ring);
72
+ E1000_SRRCTL_BSIZEHDRSIZE_SHIFT;
73
+}
28
+}
74
+
29
+
75
void
30
static int vhost_vdpa_set_vring_dev_kick(struct vhost_dev *dev,
76
igb_start_recv(IGBCore *core)
31
struct vhost_vring_file *file)
77
{
32
{
78
@@ -XXX,XX +XXX,XX @@ igb_read_adv_rx_descr(IGBCore *core, union e1000_adv_rx_desc *desc,
33
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_vring_dev_call(struct vhost_dev *dev,
79
*buff_addr = le64_to_cpu(desc->read.pkt_addr);
34
return vhost_vdpa_call(dev, VHOST_SET_VRING_CALL, file);
80
}
35
}
81
36
82
+typedef struct IGBPacketRxDMAState {
37
+static int vhost_vdpa_set_vring_dev_addr(struct vhost_dev *dev,
83
+ size_t size;
38
+ struct vhost_vring_addr *addr)
84
+ size_t total_size;
39
+{
85
+ size_t ps_hdr_len;
40
+ trace_vhost_vdpa_set_vring_addr(dev, addr->index, addr->flags,
86
+ size_t desc_size;
41
+ addr->desc_user_addr, addr->used_user_addr,
87
+ size_t desc_offset;
42
+ addr->avail_user_addr,
88
+ uint32_t rx_desc_packet_buf_size;
43
+ addr->log_guest_addr);
89
+ uint32_t rx_desc_header_buf_size;
90
+ struct iovec *iov;
91
+ size_t iov_ofs;
92
+ bool is_first;
93
+ uint16_t written;
94
+ hwaddr ba;
95
+} IGBPacketRxDMAState;
96
+
44
+
97
static inline void
45
+ return vhost_vdpa_call(dev, VHOST_SET_VRING_ADDR, addr);
98
igb_read_rx_descr(IGBCore *core, union e1000_rx_desc_union *desc,
46
+
99
hwaddr *buff_addr)
100
@@ -XXX,XX +XXX,XX @@ igb_pci_dma_write_rx_desc(IGBCore *core, PCIDevice *dev, dma_addr_t addr,
101
}
102
103
static void
104
-igb_write_to_rx_buffers(IGBCore *core,
105
- PCIDevice *d,
106
- hwaddr ba,
107
- uint16_t *written,
108
- const char *data,
109
- dma_addr_t data_len)
110
-{
111
- trace_igb_rx_desc_buff_write(ba, *written, data, data_len);
112
- pci_dma_write(d, ba + *written, data, data_len);
113
- *written += data_len;
114
-}
115
-
116
-static void
117
igb_update_rx_stats(IGBCore *core, const E1000ERingInfo *rxi,
118
size_t pkt_size, size_t pkt_fcs_size)
119
{
120
@@ -XXX,XX +XXX,XX @@ igb_rx_descr_threshold_hit(IGBCore *core, const E1000ERingInfo *rxi)
121
}
122
123
static void
124
+igb_truncate_to_descriptor_size(IGBPacketRxDMAState *pdma_st, size_t *size)
125
+{
126
+ if (*size > pdma_st->rx_desc_packet_buf_size) {
127
+ *size = pdma_st->rx_desc_packet_buf_size;
128
+ }
129
+}
47
+}
130
+
48
+
131
+static void
49
/**
132
+igb_write_payload_frag_to_rx_buffers(IGBCore *core,
50
* Set the shadow virtqueue descriptors to the device
133
+ PCIDevice *d,
51
*
134
+ hwaddr ba,
52
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base,
135
+ uint16_t *written,
53
static int vhost_vdpa_set_vring_addr(struct vhost_dev *dev,
136
+ uint32_t cur_buf_len,
54
struct vhost_vring_addr *addr)
137
+ const char *data,
55
{
138
+ dma_addr_t data_len)
56
- trace_vhost_vdpa_set_vring_addr(dev, addr->index, addr->flags,
139
+{
57
- addr->desc_user_addr, addr->used_user_addr,
140
+ trace_igb_rx_desc_buff_write(ba, *written, data, data_len);
58
- addr->avail_user_addr,
141
+ pci_dma_write(d, ba + *written, data, data_len);
59
- addr->log_guest_addr);
142
+ *written += data_len;
60
- return vhost_vdpa_call(dev, VHOST_SET_VRING_ADDR, addr);
143
+}
61
+ struct vhost_vdpa *v = dev->opaque;
144
+
62
+
145
+static void
63
+ if (v->shadow_vqs_enabled) {
146
+igb_write_payload_to_rx_buffers(IGBCore *core,
64
+ /*
147
+ struct NetRxPkt *pkt,
65
+ * Device vring addr was set at device start. SVQ base is handled by
148
+ PCIDevice *d,
66
+ * VirtQueue code.
149
+ IGBPacketRxDMAState *pdma_st,
67
+ */
150
+ size_t *copy_size)
68
+ return 0;
151
+{
152
+ static const uint32_t fcs_pad;
153
+ size_t iov_copy;
154
+
155
+ /* Copy packet payload */
156
+ while (*copy_size) {
157
+ iov_copy = MIN(*copy_size, pdma_st->iov->iov_len - pdma_st->iov_ofs);
158
+ igb_write_payload_frag_to_rx_buffers(core, d,
159
+ pdma_st->ba,
160
+ &pdma_st->written,
161
+ pdma_st->rx_desc_packet_buf_size,
162
+ pdma_st->iov->iov_base +
163
+ pdma_st->iov_ofs,
164
+ iov_copy);
165
+
166
+ *copy_size -= iov_copy;
167
+ pdma_st->iov_ofs += iov_copy;
168
+ if (pdma_st->iov_ofs == pdma_st->iov->iov_len) {
169
+ pdma_st->iov++;
170
+ pdma_st->iov_ofs = 0;
171
+ }
172
+ }
69
+ }
173
+
70
+
174
+ if (pdma_st->desc_offset + pdma_st->desc_size >= pdma_st->total_size) {
71
+ return vhost_vdpa_set_vring_dev_addr(dev, addr);
175
+ /* Simulate FCS checksum presence in the last descriptor */
72
}
176
+ igb_write_payload_frag_to_rx_buffers(core, d,
73
177
+ pdma_st->ba,
74
static int vhost_vdpa_set_vring_num(struct vhost_dev *dev,
178
+ &pdma_st->written,
75
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_vring_num(struct vhost_dev *dev,
179
+ pdma_st->rx_desc_packet_buf_size,
76
static int vhost_vdpa_set_vring_base(struct vhost_dev *dev,
180
+ (const char *) &fcs_pad,
77
struct vhost_vring_state *ring)
181
+ e1000x_fcs_len(core->mac));
78
{
182
+ }
79
- trace_vhost_vdpa_set_vring_base(dev, ring->index, ring->num);
183
+}
80
- return vhost_vdpa_call(dev, VHOST_SET_VRING_BASE, ring);
81
+ struct vhost_vdpa *v = dev->opaque;
184
+
82
+
185
+static void
83
+ if (v->shadow_vqs_enabled) {
186
+igb_write_to_rx_buffers(IGBCore *core,
84
+ /*
187
+ struct NetRxPkt *pkt,
85
+ * Device vring base was set at device start. SVQ base is handled by
188
+ PCIDevice *d,
86
+ * VirtQueue code.
189
+ IGBPacketRxDMAState *pdma_st)
87
+ */
190
+{
88
+ return 0;
191
+ size_t copy_size;
192
+
193
+ if (!pdma_st->ba) {
194
+ /* as per intel docs; skip descriptors with null buf addr */
195
+ trace_e1000e_rx_null_descriptor();
196
+ return;
197
+ }
89
+ }
198
+
90
+
199
+ if (pdma_st->desc_offset >= pdma_st->size) {
91
+ return vhost_vdpa_set_dev_vring_base(dev, ring);
200
+ return;
201
+ }
202
+
203
+ pdma_st->desc_size = pdma_st->total_size - pdma_st->desc_offset;
204
+ igb_truncate_to_descriptor_size(pdma_st, &pdma_st->desc_size);
205
+ copy_size = pdma_st->size - pdma_st->desc_offset;
206
+ igb_truncate_to_descriptor_size(pdma_st, &copy_size);
207
+ igb_write_payload_to_rx_buffers(core, pkt, d, pdma_st, &copy_size);
208
+}
209
+
210
+static void
211
igb_write_packet_to_guest(IGBCore *core, struct NetRxPkt *pkt,
212
const E1000E_RxRing *rxr,
213
const E1000E_RSSInfo *rss_info,
214
@@ -XXX,XX +XXX,XX @@ igb_write_packet_to_guest(IGBCore *core, struct NetRxPkt *pkt,
215
PCIDevice *d;
216
dma_addr_t base;
217
union e1000_rx_desc_union desc;
218
- size_t desc_size;
219
- size_t desc_offset = 0;
220
- size_t iov_ofs = 0;
221
-
222
- struct iovec *iov = net_rx_pkt_get_iovec(pkt);
223
- size_t size = net_rx_pkt_get_total_len(pkt);
224
- size_t total_size = size + e1000x_fcs_len(core->mac);
225
- const E1000ERingInfo *rxi = rxr->i;
226
- size_t bufsize = igb_rxbufsize(core, rxi);
227
-
228
+ const E1000ERingInfo *rxi;
229
+ size_t rx_desc_len;
230
+
231
+ IGBPacketRxDMAState pdma_st = {0};
232
+ pdma_st.is_first = true;
233
+ pdma_st.size = net_rx_pkt_get_total_len(pkt);
234
+ pdma_st.total_size = pdma_st.size + e1000x_fcs_len(core->mac);
235
+
236
+ rxi = rxr->i;
237
+ rx_desc_len = core->rx_desc_len;
238
+ pdma_st.rx_desc_packet_buf_size = igb_rxbufsize(core, rxi);
239
+ pdma_st.rx_desc_header_buf_size = igb_rxhdrbufsize(core, rxi);
240
+ pdma_st.iov = net_rx_pkt_get_iovec(pkt);
241
d = pcie_sriov_get_vf_at_index(core->owner, rxi->idx % 8);
242
if (!d) {
243
d = core->owner;
244
}
245
246
do {
247
- hwaddr ba;
248
- uint16_t written = 0;
249
+ pdma_st.written = 0;
250
bool is_last = false;
251
252
- desc_size = total_size - desc_offset;
253
-
254
- if (desc_size > bufsize) {
255
- desc_size = bufsize;
256
- }
257
-
258
if (igb_ring_empty(core, rxi)) {
259
return;
260
}
261
262
base = igb_ring_head_descr(core, rxi);
263
+ pci_dma_read(d, base, &desc, rx_desc_len);
264
+ trace_e1000e_rx_descr(rxi->idx, base, rx_desc_len);
265
266
- pci_dma_read(d, base, &desc, core->rx_desc_len);
267
-
268
- trace_e1000e_rx_descr(rxi->idx, base, core->rx_desc_len);
269
-
270
- igb_read_rx_descr(core, &desc, &ba);
271
-
272
- if (ba) {
273
- if (desc_offset < size) {
274
- static const uint32_t fcs_pad;
275
- size_t iov_copy;
276
- size_t copy_size = size - desc_offset;
277
- if (copy_size > bufsize) {
278
- copy_size = bufsize;
279
- }
280
-
281
- /* Copy packet payload */
282
- while (copy_size) {
283
- iov_copy = MIN(copy_size, iov->iov_len - iov_ofs);
284
-
285
- igb_write_to_rx_buffers(core, d, ba, &written,
286
- iov->iov_base + iov_ofs, iov_copy);
287
+ igb_read_rx_descr(core, &desc, &pdma_st.ba);
288
289
- copy_size -= iov_copy;
290
- iov_ofs += iov_copy;
291
- if (iov_ofs == iov->iov_len) {
292
- iov++;
293
- iov_ofs = 0;
294
- }
295
- }
296
-
297
- if (desc_offset + desc_size >= total_size) {
298
- /* Simulate FCS checksum presence in the last descriptor */
299
- igb_write_to_rx_buffers(core, d, ba, &written,
300
- (const char *) &fcs_pad, e1000x_fcs_len(core->mac));
301
- }
302
- }
303
- } else { /* as per intel docs; skip descriptors with null buf addr */
304
- trace_e1000e_rx_null_descriptor();
305
- }
306
- desc_offset += desc_size;
307
- if (desc_offset >= total_size) {
308
+ igb_write_to_rx_buffers(core, pkt, d, &pdma_st);
309
+ pdma_st.desc_offset += pdma_st.desc_size;
310
+ if (pdma_st.desc_offset >= pdma_st.total_size) {
311
is_last = true;
312
}
313
314
igb_write_rx_descr(core, &desc, is_last ? core->rx_pkt : NULL,
315
- rss_info, etqf, ts, written);
316
- igb_pci_dma_write_rx_desc(core, d, base, &desc, core->rx_desc_len);
317
-
318
- igb_ring_advance(core, rxi, core->rx_desc_len / E1000_MIN_RX_DESC_LEN);
319
-
320
- } while (desc_offset < total_size);
321
+ rss_info, etqf, ts, pdma_st.written);
322
+ igb_pci_dma_write_rx_desc(core, d, base, &desc, rx_desc_len);
323
+ igb_ring_advance(core, rxi, rx_desc_len / E1000_MIN_RX_DESC_LEN);
324
+ } while (pdma_st.desc_offset < pdma_st.total_size);
325
326
- igb_update_rx_stats(core, rxi, size, total_size);
327
+ igb_update_rx_stats(core, rxi, pdma_st.size, pdma_st.total_size);
328
}
92
}
329
93
330
static bool
94
static int vhost_vdpa_get_vring_base(struct vhost_dev *dev,
331
diff --git a/tests/qtest/libqos/igb.c b/tests/qtest/libqos/igb.c
332
index XXXXXXX..XXXXXXX 100644
333
--- a/tests/qtest/libqos/igb.c
334
+++ b/tests/qtest/libqos/igb.c
335
@@ -XXX,XX +XXX,XX @@ static void igb_pci_start_hw(QOSGraphObject *obj)
336
E1000_RAH_AV | E1000_RAH_POOL_1 |
337
le16_to_cpu(*(uint16_t *)(address + 4)));
338
339
+ /* Set supported receive descriptor mode */
340
+ e1000e_macreg_write(&d->e1000e,
341
+ E1000_SRRCTL(0),
342
+ E1000_SRRCTL_DESCTYPE_ADV_ONEBUF);
343
+
344
/* Enable receive */
345
e1000e_macreg_write(&d->e1000e, E1000_RFCTL, E1000_RFCTL_EXTEN);
346
e1000e_macreg_write(&d->e1000e, E1000_RCTL, E1000_RCTL_EN);
347
--
95
--
348
2.7.4
96
2.7.4
97
98
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Changed eBPF map updates through mmaped array.
3
Initial version of shadow virtqueue that actually forward buffers. There
4
Mmaped arrays provide direct access to map data.
4
is no iommu support at the moment, and that will be addressed in future
5
It should omit using bpf_map_update_elem() call,
5
patches of this series. Since all vhost-vdpa devices use forced IOMMU,
6
which may require capabilities that are not present.
6
this means that SVQ is not usable at this point of the series on any
7
7
device.
8
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
8
9
For simplicity it only supports modern devices, that expects vring
10
in little endian, with split ring and no event idx or indirect
11
descriptors. Support for them will not be added in this series.
12
13
It reuses the VirtQueue code for the device part. The driver part is
14
based on Linux's virtio_ring driver, but with stripped functionality
15
and optimizations so it's easier to review.
16
17
However, forwarding buffers have some particular pieces: One of the most
18
unexpected ones is that a guest's buffer can expand through more than
19
one descriptor in SVQ. While this is handled gracefully by qemu's
20
emulated virtio devices, it may cause unexpected SVQ queue full. This
21
patch also solves it by checking for this condition at both guest's
22
kicks and device's calls. The code may be more elegant in the future if
23
SVQ code runs in its own iocontext.
24
25
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
26
Acked-by: Michael S. Tsirkin <mst@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
27
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
---
28
---
11
ebpf/ebpf_rss.c | 117 +++++++++++++++++++++++++++++++++++++++++++++-----------
29
hw/virtio/vhost-shadow-virtqueue.c | 352 ++++++++++++++++++++++++++++++++++++-
12
ebpf/ebpf_rss.h | 5 +++
30
hw/virtio/vhost-shadow-virtqueue.h | 26 +++
13
2 files changed, 99 insertions(+), 23 deletions(-)
31
hw/virtio/vhost-vdpa.c | 155 +++++++++++++++-
14
32
3 files changed, 522 insertions(+), 11 deletions(-)
15
diff --git a/ebpf/ebpf_rss.c b/ebpf/ebpf_rss.c
33
34
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
16
index XXXXXXX..XXXXXXX 100644
35
index XXXXXXX..XXXXXXX 100644
17
--- a/ebpf/ebpf_rss.c
36
--- a/hw/virtio/vhost-shadow-virtqueue.c
18
+++ b/ebpf/ebpf_rss.c
37
+++ b/hw/virtio/vhost-shadow-virtqueue.c
19
@@ -XXX,XX +XXX,XX @@ void ebpf_rss_init(struct EBPFRSSContext *ctx)
38
@@ -XXX,XX +XXX,XX @@
39
#include "qemu/error-report.h"
40
#include "qapi/error.h"
41
#include "qemu/main-loop.h"
42
+#include "qemu/log.h"
43
+#include "qemu/memalign.h"
44
#include "linux-headers/linux/vhost.h"
45
46
/**
47
@@ -XXX,XX +XXX,XX @@ bool vhost_svq_valid_features(uint64_t features, Error **errp)
48
}
49
50
/**
51
- * Forward guest notifications.
52
+ * Number of descriptors that the SVQ can make available from the guest.
53
+ *
54
+ * @svq: The svq
55
+ */
56
+static uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq)
57
+{
58
+ return svq->vring.num - (svq->shadow_avail_idx - svq->shadow_used_idx);
59
+}
60
+
61
+static void vhost_vring_write_descs(VhostShadowVirtqueue *svq,
62
+ const struct iovec *iovec, size_t num,
63
+ bool more_descs, bool write)
64
+{
65
+ uint16_t i = svq->free_head, last = svq->free_head;
66
+ unsigned n;
67
+ uint16_t flags = write ? cpu_to_le16(VRING_DESC_F_WRITE) : 0;
68
+ vring_desc_t *descs = svq->vring.desc;
69
+
70
+ if (num == 0) {
71
+ return;
72
+ }
73
+
74
+ for (n = 0; n < num; n++) {
75
+ if (more_descs || (n + 1 < num)) {
76
+ descs[i].flags = flags | cpu_to_le16(VRING_DESC_F_NEXT);
77
+ } else {
78
+ descs[i].flags = flags;
79
+ }
80
+ descs[i].addr = cpu_to_le64((hwaddr)(intptr_t)iovec[n].iov_base);
81
+ descs[i].len = cpu_to_le32(iovec[n].iov_len);
82
+
83
+ last = i;
84
+ i = cpu_to_le16(descs[i].next);
85
+ }
86
+
87
+ svq->free_head = le16_to_cpu(descs[last].next);
88
+}
89
+
90
+static bool vhost_svq_add_split(VhostShadowVirtqueue *svq,
91
+ VirtQueueElement *elem, unsigned *head)
92
+{
93
+ unsigned avail_idx;
94
+ vring_avail_t *avail = svq->vring.avail;
95
+
96
+ *head = svq->free_head;
97
+
98
+ /* We need some descriptors here */
99
+ if (unlikely(!elem->out_num && !elem->in_num)) {
100
+ qemu_log_mask(LOG_GUEST_ERROR,
101
+ "Guest provided element with no descriptors");
102
+ return false;
103
+ }
104
+
105
+ vhost_vring_write_descs(svq, elem->out_sg, elem->out_num, elem->in_num > 0,
106
+ false);
107
+ vhost_vring_write_descs(svq, elem->in_sg, elem->in_num, false, true);
108
+
109
+ /*
110
+ * Put the entry in the available array (but don't update avail->idx until
111
+ * they do sync).
112
+ */
113
+ avail_idx = svq->shadow_avail_idx & (svq->vring.num - 1);
114
+ avail->ring[avail_idx] = cpu_to_le16(*head);
115
+ svq->shadow_avail_idx++;
116
+
117
+ /* Update the avail index after write the descriptor */
118
+ smp_wmb();
119
+ avail->idx = cpu_to_le16(svq->shadow_avail_idx);
120
+
121
+ return true;
122
+}
123
+
124
+static bool vhost_svq_add(VhostShadowVirtqueue *svq, VirtQueueElement *elem)
125
+{
126
+ unsigned qemu_head;
127
+ bool ok = vhost_svq_add_split(svq, elem, &qemu_head);
128
+ if (unlikely(!ok)) {
129
+ return false;
130
+ }
131
+
132
+ svq->ring_id_maps[qemu_head] = elem;
133
+ return true;
134
+}
135
+
136
+static void vhost_svq_kick(VhostShadowVirtqueue *svq)
137
+{
138
+ /*
139
+ * We need to expose the available array entries before checking the used
140
+ * flags
141
+ */
142
+ smp_mb();
143
+ if (svq->vring.used->flags & VRING_USED_F_NO_NOTIFY) {
144
+ return;
145
+ }
146
+
147
+ event_notifier_set(&svq->hdev_kick);
148
+}
149
+
150
+/**
151
+ * Forward available buffers.
152
+ *
153
+ * @svq: Shadow VirtQueue
154
+ *
155
+ * Note that this function does not guarantee that all guest's available
156
+ * buffers are available to the device in SVQ avail ring. The guest may have
157
+ * exposed a GPA / GIOVA contiguous buffer, but it may not be contiguous in
158
+ * qemu vaddr.
159
+ *
160
+ * If that happens, guest's kick notifications will be disabled until the
161
+ * device uses some buffers.
162
+ */
163
+static void vhost_handle_guest_kick(VhostShadowVirtqueue *svq)
164
+{
165
+ /* Clear event notifier */
166
+ event_notifier_test_and_clear(&svq->svq_kick);
167
+
168
+ /* Forward to the device as many available buffers as possible */
169
+ do {
170
+ virtio_queue_set_notification(svq->vq, false);
171
+
172
+ while (true) {
173
+ VirtQueueElement *elem;
174
+ bool ok;
175
+
176
+ if (svq->next_guest_avail_elem) {
177
+ elem = g_steal_pointer(&svq->next_guest_avail_elem);
178
+ } else {
179
+ elem = virtqueue_pop(svq->vq, sizeof(*elem));
180
+ }
181
+
182
+ if (!elem) {
183
+ break;
184
+ }
185
+
186
+ if (elem->out_num + elem->in_num > vhost_svq_available_slots(svq)) {
187
+ /*
188
+ * This condition is possible since a contiguous buffer in GPA
189
+ * does not imply a contiguous buffer in qemu's VA
190
+ * scatter-gather segments. If that happens, the buffer exposed
191
+ * to the device needs to be a chain of descriptors at this
192
+ * moment.
193
+ *
194
+ * SVQ cannot hold more available buffers if we are here:
195
+ * queue the current guest descriptor and ignore further kicks
196
+ * until some elements are used.
197
+ */
198
+ svq->next_guest_avail_elem = elem;
199
+ return;
200
+ }
201
+
202
+ ok = vhost_svq_add(svq, elem);
203
+ if (unlikely(!ok)) {
204
+ /* VQ is broken, just return and ignore any other kicks */
205
+ return;
206
+ }
207
+ vhost_svq_kick(svq);
208
+ }
209
+
210
+ virtio_queue_set_notification(svq->vq, true);
211
+ } while (!virtio_queue_empty(svq->vq));
212
+}
213
+
214
+/**
215
+ * Handle guest's kick.
216
*
217
* @n: guest kick event notifier, the one that guest set to notify svq.
218
*/
219
-static void vhost_handle_guest_kick(EventNotifier *n)
220
+static void vhost_handle_guest_kick_notifier(EventNotifier *n)
20
{
221
{
21
if (ctx != NULL) {
222
VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue, svq_kick);
22
ctx->obj = NULL;
223
event_notifier_test_and_clear(n);
23
+ ctx->program_fd = -1;
224
- event_notifier_set(&svq->hdev_kick);
24
+ ctx->map_configuration = -1;
225
+ vhost_handle_guest_kick(svq);
25
+ ctx->map_toeplitz_key = -1;
226
+}
26
+ ctx->map_indirections_table = -1;
227
+
27
+
228
+static bool vhost_svq_more_used(VhostShadowVirtqueue *svq)
28
+ ctx->mmap_configuration = NULL;
229
+{
29
+ ctx->mmap_toeplitz_key = NULL;
230
+ if (svq->last_used_idx != svq->shadow_used_idx) {
30
+ ctx->mmap_indirections_table = NULL;
231
+ return true;
232
+ }
233
+
234
+ svq->shadow_used_idx = cpu_to_le16(svq->vring.used->idx);
235
+
236
+ return svq->last_used_idx != svq->shadow_used_idx;
237
}
238
239
/**
240
- * Forward vhost notifications
241
+ * Enable vhost device calls after disable them.
242
+ *
243
+ * @svq: The svq
244
+ *
245
+ * It returns false if there are pending used buffers from the vhost device,
246
+ * avoiding the possible races between SVQ checking for more work and enabling
247
+ * callbacks. True if SVQ used vring has no more pending buffers.
248
+ */
249
+static bool vhost_svq_enable_notification(VhostShadowVirtqueue *svq)
250
+{
251
+ svq->vring.avail->flags &= ~cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT);
252
+ /* Make sure the flag is written before the read of used_idx */
253
+ smp_mb();
254
+ return !vhost_svq_more_used(svq);
255
+}
256
+
257
+static void vhost_svq_disable_notification(VhostShadowVirtqueue *svq)
258
+{
259
+ svq->vring.avail->flags |= cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT);
260
+}
261
+
262
+static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq,
263
+ uint32_t *len)
264
+{
265
+ vring_desc_t *descs = svq->vring.desc;
266
+ const vring_used_t *used = svq->vring.used;
267
+ vring_used_elem_t used_elem;
268
+ uint16_t last_used;
269
+
270
+ if (!vhost_svq_more_used(svq)) {
271
+ return NULL;
272
+ }
273
+
274
+ /* Only get used array entries after they have been exposed by dev */
275
+ smp_rmb();
276
+ last_used = svq->last_used_idx & (svq->vring.num - 1);
277
+ used_elem.id = le32_to_cpu(used->ring[last_used].id);
278
+ used_elem.len = le32_to_cpu(used->ring[last_used].len);
279
+
280
+ svq->last_used_idx++;
281
+ if (unlikely(used_elem.id >= svq->vring.num)) {
282
+ qemu_log_mask(LOG_GUEST_ERROR, "Device %s says index %u is used",
283
+ svq->vdev->name, used_elem.id);
284
+ return NULL;
285
+ }
286
+
287
+ if (unlikely(!svq->ring_id_maps[used_elem.id])) {
288
+ qemu_log_mask(LOG_GUEST_ERROR,
289
+ "Device %s says index %u is used, but it was not available",
290
+ svq->vdev->name, used_elem.id);
291
+ return NULL;
292
+ }
293
+
294
+ descs[used_elem.id].next = svq->free_head;
295
+ svq->free_head = used_elem.id;
296
+
297
+ *len = used_elem.len;
298
+ return g_steal_pointer(&svq->ring_id_maps[used_elem.id]);
299
+}
300
+
301
+static void vhost_svq_flush(VhostShadowVirtqueue *svq,
302
+ bool check_for_avail_queue)
303
+{
304
+ VirtQueue *vq = svq->vq;
305
+
306
+ /* Forward as many used buffers as possible. */
307
+ do {
308
+ unsigned i = 0;
309
+
310
+ vhost_svq_disable_notification(svq);
311
+ while (true) {
312
+ uint32_t len;
313
+ g_autofree VirtQueueElement *elem = vhost_svq_get_buf(svq, &len);
314
+ if (!elem) {
315
+ break;
316
+ }
317
+
318
+ if (unlikely(i >= svq->vring.num)) {
319
+ qemu_log_mask(LOG_GUEST_ERROR,
320
+ "More than %u used buffers obtained in a %u size SVQ",
321
+ i, svq->vring.num);
322
+ virtqueue_fill(vq, elem, len, i);
323
+ virtqueue_flush(vq, i);
324
+ return;
325
+ }
326
+ virtqueue_fill(vq, elem, len, i++);
327
+ }
328
+
329
+ virtqueue_flush(vq, i);
330
+ event_notifier_set(&svq->svq_call);
331
+
332
+ if (check_for_avail_queue && svq->next_guest_avail_elem) {
333
+ /*
334
+ * Avail ring was full when vhost_svq_flush was called, so it's a
335
+ * good moment to make more descriptors available if possible.
336
+ */
337
+ vhost_handle_guest_kick(svq);
338
+ }
339
+ } while (!vhost_svq_enable_notification(svq));
340
+}
341
+
342
+/**
343
+ * Forward used buffers.
344
*
345
* @n: hdev call event notifier, the one that device set to notify svq.
346
+ *
347
+ * Note that we are not making any buffers available in the loop, there is no
348
+ * way that it runs more than virtqueue size times.
349
*/
350
static void vhost_svq_handle_call(EventNotifier *n)
351
{
352
VhostShadowVirtqueue *svq = container_of(n, VhostShadowVirtqueue,
353
hdev_call);
354
event_notifier_test_and_clear(n);
355
- event_notifier_set(&svq->svq_call);
356
+ vhost_svq_flush(svq, true);
357
}
358
359
/**
360
@@ -XXX,XX +XXX,XX @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd)
361
if (poll_start) {
362
event_notifier_init_fd(svq_kick, svq_kick_fd);
363
event_notifier_set(svq_kick);
364
- event_notifier_set_handler(svq_kick, vhost_handle_guest_kick);
365
+ event_notifier_set_handler(svq_kick, vhost_handle_guest_kick_notifier);
366
+ }
367
+}
368
+
369
+/**
370
+ * Start the shadow virtqueue operation.
371
+ *
372
+ * @svq: Shadow Virtqueue
373
+ * @vdev: VirtIO device
374
+ * @vq: Virtqueue to shadow
375
+ */
376
+void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev,
377
+ VirtQueue *vq)
378
+{
379
+ size_t desc_size, driver_size, device_size;
380
+
381
+ svq->next_guest_avail_elem = NULL;
382
+ svq->shadow_avail_idx = 0;
383
+ svq->shadow_used_idx = 0;
384
+ svq->last_used_idx = 0;
385
+ svq->vdev = vdev;
386
+ svq->vq = vq;
387
+
388
+ svq->vring.num = virtio_queue_get_num(vdev, virtio_get_queue_index(vq));
389
+ driver_size = vhost_svq_driver_area_size(svq);
390
+ device_size = vhost_svq_device_area_size(svq);
391
+ svq->vring.desc = qemu_memalign(qemu_real_host_page_size, driver_size);
392
+ desc_size = sizeof(vring_desc_t) * svq->vring.num;
393
+ svq->vring.avail = (void *)((char *)svq->vring.desc + desc_size);
394
+ memset(svq->vring.desc, 0, driver_size);
395
+ svq->vring.used = qemu_memalign(qemu_real_host_page_size, device_size);
396
+ memset(svq->vring.used, 0, device_size);
397
+ svq->ring_id_maps = g_new0(VirtQueueElement *, svq->vring.num);
398
+ for (unsigned i = 0; i < svq->vring.num - 1; i++) {
399
+ svq->vring.desc[i].next = cpu_to_le16(i + 1);
31
}
400
}
32
}
401
}
33
402
34
bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
403
@@ -XXX,XX +XXX,XX @@ void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd)
404
void vhost_svq_stop(VhostShadowVirtqueue *svq)
35
{
405
{
36
- return ctx != NULL && ctx->obj != NULL;
406
event_notifier_set_handler(&svq->svq_kick, NULL);
37
+ return ctx != NULL && (ctx->obj != NULL || ctx->program_fd != -1);
407
+ g_autofree VirtQueueElement *next_avail_elem = NULL;
38
+}
408
+
39
+
409
+ if (!svq->vq) {
40
+static bool ebpf_rss_mmap(struct EBPFRSSContext *ctx)
410
+ return;
41
+{
411
+ }
42
+ if (!ebpf_rss_is_loaded(ctx)) {
412
+
413
+ /* Send all pending used descriptors to guest */
414
+ vhost_svq_flush(svq, false);
415
+
416
+ for (unsigned i = 0; i < svq->vring.num; ++i) {
417
+ g_autofree VirtQueueElement *elem = NULL;
418
+ elem = g_steal_pointer(&svq->ring_id_maps[i]);
419
+ if (elem) {
420
+ virtqueue_detach_element(svq->vq, elem, 0);
421
+ }
422
+ }
423
+
424
+ next_avail_elem = g_steal_pointer(&svq->next_guest_avail_elem);
425
+ if (next_avail_elem) {
426
+ virtqueue_detach_element(svq->vq, next_avail_elem, 0);
427
+ }
428
+ svq->vq = NULL;
429
+ g_free(svq->ring_id_maps);
430
+ qemu_vfree(svq->vring.desc);
431
+ qemu_vfree(svq->vring.used);
432
}
433
434
/**
435
diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
436
index XXXXXXX..XXXXXXX 100644
437
--- a/hw/virtio/vhost-shadow-virtqueue.h
438
+++ b/hw/virtio/vhost-shadow-virtqueue.h
439
@@ -XXX,XX +XXX,XX @@ typedef struct VhostShadowVirtqueue {
440
441
/* Guest's call notifier, where the SVQ calls guest. */
442
EventNotifier svq_call;
443
+
444
+ /* Virtio queue shadowing */
445
+ VirtQueue *vq;
446
+
447
+ /* Virtio device */
448
+ VirtIODevice *vdev;
449
+
450
+ /* Map for use the guest's descriptors */
451
+ VirtQueueElement **ring_id_maps;
452
+
453
+ /* Next VirtQueue element that guest made available */
454
+ VirtQueueElement *next_guest_avail_elem;
455
+
456
+ /* Next head to expose to the device */
457
+ uint16_t shadow_avail_idx;
458
+
459
+ /* Next free descriptor */
460
+ uint16_t free_head;
461
+
462
+ /* Last seen used idx */
463
+ uint16_t shadow_used_idx;
464
+
465
+ /* Next head to consume from the device */
466
+ uint16_t last_used_idx;
467
} VhostShadowVirtqueue;
468
469
bool vhost_svq_valid_features(uint64_t features, Error **errp);
470
@@ -XXX,XX +XXX,XX @@ void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq,
471
size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq);
472
size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq);
473
474
+void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev,
475
+ VirtQueue *vq);
476
void vhost_svq_stop(VhostShadowVirtqueue *svq);
477
478
VhostShadowVirtqueue *vhost_svq_new(void);
479
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
480
index XXXXXXX..XXXXXXX 100644
481
--- a/hw/virtio/vhost-vdpa.c
482
+++ b/hw/virtio/vhost-vdpa.c
483
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_vring_dev_addr(struct vhost_dev *dev,
484
* Note that this function does not rewind kick file descriptor if cannot set
485
* call one.
486
*/
487
-static bool vhost_vdpa_svq_setup(struct vhost_dev *dev,
488
- VhostShadowVirtqueue *svq, unsigned idx,
489
- Error **errp)
490
+static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev,
491
+ VhostShadowVirtqueue *svq, unsigned idx,
492
+ Error **errp)
493
{
494
struct vhost_vring_file file = {
495
.index = dev->vq_index + idx,
496
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_svq_setup(struct vhost_dev *dev,
497
r = vhost_vdpa_set_vring_dev_kick(dev, &file);
498
if (unlikely(r != 0)) {
499
error_setg_errno(errp, -r, "Can't set device kick fd");
500
- return false;
501
+ return r;
502
}
503
504
event_notifier = &svq->hdev_call;
505
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_svq_setup(struct vhost_dev *dev,
506
error_setg_errno(errp, -r, "Can't set device call fd");
507
}
508
509
+ return r;
510
+}
511
+
512
+/**
513
+ * Unmap a SVQ area in the device
514
+ */
515
+static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, hwaddr iova,
516
+ hwaddr size)
517
+{
518
+ int r;
519
+
520
+ size = ROUND_UP(size, qemu_real_host_page_size);
521
+ r = vhost_vdpa_dma_unmap(v, iova, size);
522
+ return r == 0;
523
+}
524
+
525
+static bool vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev,
526
+ const VhostShadowVirtqueue *svq)
527
+{
528
+ struct vhost_vdpa *v = dev->opaque;
529
+ struct vhost_vring_addr svq_addr;
530
+ size_t device_size = vhost_svq_device_area_size(svq);
531
+ size_t driver_size = vhost_svq_driver_area_size(svq);
532
+ bool ok;
533
+
534
+ vhost_svq_get_vring_addr(svq, &svq_addr);
535
+
536
+ ok = vhost_vdpa_svq_unmap_ring(v, svq_addr.desc_user_addr, driver_size);
537
+ if (unlikely(!ok)) {
43
+ return false;
538
+ return false;
44
+ }
539
+ }
45
+
540
+
46
+ ctx->mmap_configuration = mmap(NULL, qemu_real_host_page_size(),
541
+ return vhost_vdpa_svq_unmap_ring(v, svq_addr.used_user_addr, device_size);
47
+ PROT_READ | PROT_WRITE, MAP_SHARED,
542
+}
48
+ ctx->map_configuration, 0);
543
+
49
+ if (ctx->mmap_configuration == MAP_FAILED) {
544
+/**
50
+ trace_ebpf_error("eBPF RSS", "can not mmap eBPF configuration array");
545
+ * Map the shadow virtqueue rings in the device
546
+ *
547
+ * @dev: The vhost device
548
+ * @svq: The shadow virtqueue
549
+ * @addr: Assigned IOVA addresses
550
+ * @errp: Error pointer
551
+ */
552
+static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev,
553
+ const VhostShadowVirtqueue *svq,
554
+ struct vhost_vring_addr *addr,
555
+ Error **errp)
556
+{
557
+ struct vhost_vdpa *v = dev->opaque;
558
+ size_t device_size = vhost_svq_device_area_size(svq);
559
+ size_t driver_size = vhost_svq_driver_area_size(svq);
560
+ int r;
561
+
562
+ ERRP_GUARD();
563
+ vhost_svq_get_vring_addr(svq, addr);
564
+
565
+ r = vhost_vdpa_dma_map(v, addr->desc_user_addr, driver_size,
566
+ (void *)(uintptr_t)addr->desc_user_addr, true);
567
+ if (unlikely(r != 0)) {
568
+ error_setg_errno(errp, -r, "Cannot create vq driver region: ");
51
+ return false;
569
+ return false;
52
+ }
570
+ }
53
+ ctx->mmap_toeplitz_key = mmap(NULL, qemu_real_host_page_size(),
571
+
54
+ PROT_READ | PROT_WRITE, MAP_SHARED,
572
+ r = vhost_vdpa_dma_map(v, addr->used_user_addr, device_size,
55
+ ctx->map_toeplitz_key, 0);
573
+ (void *)(intptr_t)addr->used_user_addr, false);
56
+ if (ctx->mmap_toeplitz_key == MAP_FAILED) {
574
+ if (unlikely(r != 0)) {
57
+ trace_ebpf_error("eBPF RSS", "can not mmap eBPF toeplitz key");
575
+ error_setg_errno(errp, -r, "Cannot create vq device region: ");
58
+ goto toeplitz_fail;
576
+ }
59
+ }
577
+
60
+ ctx->mmap_indirections_table = mmap(NULL, qemu_real_host_page_size(),
578
+ return r == 0;
61
+ PROT_READ | PROT_WRITE, MAP_SHARED,
579
+}
62
+ ctx->map_indirections_table, 0);
580
+
63
+ if (ctx->mmap_indirections_table == MAP_FAILED) {
581
+static bool vhost_vdpa_svq_setup(struct vhost_dev *dev,
64
+ trace_ebpf_error("eBPF RSS", "can not mmap eBPF indirection table");
582
+ VhostShadowVirtqueue *svq, unsigned idx,
65
+ goto indirection_fail;
583
+ Error **errp)
584
+{
585
+ uint16_t vq_index = dev->vq_index + idx;
586
+ struct vhost_vring_state s = {
587
+ .index = vq_index,
588
+ };
589
+ int r;
590
+
591
+ r = vhost_vdpa_set_dev_vring_base(dev, &s);
592
+ if (unlikely(r)) {
593
+ error_setg_errno(errp, -r, "Cannot set vring base");
594
+ return false;
595
+ }
596
+
597
+ r = vhost_vdpa_svq_set_fds(dev, svq, idx, errp);
598
return r == 0;
599
}
600
601
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_svqs_start(struct vhost_dev *dev)
602
}
603
604
for (i = 0; i < v->shadow_vqs->len; ++i) {
605
+ VirtQueue *vq = virtio_get_queue(dev->vdev, dev->vq_index + i);
606
VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i);
607
+ struct vhost_vring_addr addr = {
608
+ .index = i,
609
+ };
610
+ int r;
611
bool ok = vhost_vdpa_svq_setup(dev, svq, i, &err);
612
if (unlikely(!ok)) {
613
- error_reportf_err(err, "Cannot setup SVQ %u: ", i);
614
+ goto err;
615
+ }
616
+
617
+ vhost_svq_start(svq, dev->vdev, vq);
618
+ ok = vhost_vdpa_svq_map_rings(dev, svq, &addr, &err);
619
+ if (unlikely(!ok)) {
620
+ goto err_map;
621
+ }
622
+
623
+ /* Override vring GPA set by vhost subsystem */
624
+ r = vhost_vdpa_set_vring_dev_addr(dev, &addr);
625
+ if (unlikely(r != 0)) {
626
+ error_setg_errno(&err, -r, "Cannot set device address");
627
+ goto err_set_addr;
628
+ }
66
+ }
629
+ }
67
+
630
+
68
+ return true;
631
+ return true;
69
+
632
+
70
+indirection_fail:
633
+err_set_addr:
71
+ munmap(ctx->mmap_toeplitz_key, qemu_real_host_page_size());
634
+ vhost_vdpa_svq_unmap_rings(dev, g_ptr_array_index(v->shadow_vqs, i));
72
+toeplitz_fail:
635
+
73
+ munmap(ctx->mmap_configuration, qemu_real_host_page_size());
636
+err_map:
74
+
637
+ vhost_svq_stop(g_ptr_array_index(v->shadow_vqs, i));
75
+ ctx->mmap_configuration = NULL;
638
+
76
+ ctx->mmap_toeplitz_key = NULL;
639
+err:
77
+ ctx->mmap_indirections_table = NULL;
640
+ error_reportf_err(err, "Cannot setup SVQ %u: ", i);
641
+ for (unsigned j = 0; j < i; ++j) {
642
+ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, j);
643
+ vhost_vdpa_svq_unmap_rings(dev, svq);
644
+ vhost_svq_stop(svq);
645
+ }
646
+
78
+ return false;
647
+ return false;
79
+}
648
+}
80
+
649
+
81
+static void ebpf_rss_munmap(struct EBPFRSSContext *ctx)
650
+static bool vhost_vdpa_svqs_stop(struct vhost_dev *dev)
82
+{
651
+{
83
+ if (!ebpf_rss_is_loaded(ctx)) {
652
+ struct vhost_vdpa *v = dev->opaque;
84
+ return;
653
+
85
+ }
654
+ if (!v->shadow_vqs) {
86
+
655
+ return true;
87
+ munmap(ctx->mmap_indirections_table, qemu_real_host_page_size());
656
+ }
88
+ munmap(ctx->mmap_toeplitz_key, qemu_real_host_page_size());
657
+
89
+ munmap(ctx->mmap_configuration, qemu_real_host_page_size());
658
+ for (unsigned i = 0; i < v->shadow_vqs->len; ++i) {
90
+
659
+ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs, i);
91
+ ctx->mmap_configuration = NULL;
660
+ bool ok = vhost_vdpa_svq_unmap_rings(dev, svq);
92
+ ctx->mmap_toeplitz_key = NULL;
661
+ if (unlikely(!ok)) {
93
+ ctx->mmap_indirections_table = NULL;
662
return false;
94
}
663
}
95
96
bool ebpf_rss_load(struct EBPFRSSContext *ctx)
97
{
98
struct rss_bpf *rss_bpf_ctx;
99
100
- if (ctx == NULL) {
101
+ if (ctx == NULL || ebpf_rss_is_loaded(ctx)) {
102
return false;
103
}
664
}
104
665
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
105
@@ -XXX,XX +XXX,XX @@ bool ebpf_rss_load(struct EBPFRSSContext *ctx)
666
}
106
ctx->map_toeplitz_key = bpf_map__fd(
667
vhost_vdpa_set_vring_ready(dev);
107
rss_bpf_ctx->maps.tap_rss_map_toeplitz_key);
668
} else {
108
669
+ ok = vhost_vdpa_svqs_stop(dev);
109
+ if (!ebpf_rss_mmap(ctx)) {
670
+ if (unlikely(!ok)) {
110
+ goto error;
671
+ return -1;
111
+ }
672
+ }
112
+
673
vhost_vdpa_host_notifiers_uninit(dev, dev->nvqs);
113
return true;
114
error:
115
rss_bpf__destroy(rss_bpf_ctx);
116
ctx->obj = NULL;
117
+ ctx->program_fd = -1;
118
+ ctx->map_configuration = -1;
119
+ ctx->map_toeplitz_key = -1;
120
+ ctx->map_indirections_table = -1;
121
122
return false;
123
}
124
@@ -XXX,XX +XXX,XX @@ error:
125
static bool ebpf_rss_set_config(struct EBPFRSSContext *ctx,
126
struct EBPFRSSConfig *config)
127
{
128
- uint32_t map_key = 0;
129
-
130
if (!ebpf_rss_is_loaded(ctx)) {
131
return false;
132
}
674
}
133
- if (bpf_map_update_elem(ctx->map_configuration,
675
134
- &map_key, config, 0) < 0) {
135
- return false;
136
- }
137
+
138
+ memcpy(ctx->mmap_configuration, config, sizeof(*config));
139
return true;
140
}
141
142
@@ -XXX,XX +XXX,XX @@ static bool ebpf_rss_set_indirections_table(struct EBPFRSSContext *ctx,
143
uint16_t *indirections_table,
144
size_t len)
145
{
146
- uint32_t i = 0;
147
-
148
if (!ebpf_rss_is_loaded(ctx) || indirections_table == NULL ||
149
len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
150
return false;
151
}
152
153
- for (; i < len; ++i) {
154
- if (bpf_map_update_elem(ctx->map_indirections_table, &i,
155
- indirections_table + i, 0) < 0) {
156
- return false;
157
- }
158
- }
159
+ memcpy(ctx->mmap_indirections_table, indirections_table,
160
+ sizeof(*indirections_table) * len);
161
return true;
162
}
163
164
static bool ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx,
165
uint8_t *toeplitz_key)
166
{
167
- uint32_t map_key = 0;
168
-
169
/* prepare toeplitz key */
170
uint8_t toe[VIRTIO_NET_RSS_MAX_KEY_SIZE] = {};
171
172
@@ -XXX,XX +XXX,XX @@ static bool ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx,
173
memcpy(toe, toeplitz_key, VIRTIO_NET_RSS_MAX_KEY_SIZE);
174
*(uint32_t *)toe = ntohl(*(uint32_t *)toe);
175
176
- if (bpf_map_update_elem(ctx->map_toeplitz_key, &map_key, toe,
177
- 0) < 0) {
178
- return false;
179
- }
180
+ memcpy(ctx->mmap_toeplitz_key, toe, VIRTIO_NET_RSS_MAX_KEY_SIZE);
181
return true;
182
}
183
184
@@ -XXX,XX +XXX,XX @@ void ebpf_rss_unload(struct EBPFRSSContext *ctx)
185
return;
186
}
187
188
- rss_bpf__destroy(ctx->obj);
189
+ ebpf_rss_munmap(ctx);
190
+
191
+ if (ctx->obj) {
192
+ rss_bpf__destroy(ctx->obj);
193
+ } else {
194
+ close(ctx->program_fd);
195
+ close(ctx->map_configuration);
196
+ close(ctx->map_toeplitz_key);
197
+ close(ctx->map_indirections_table);
198
+ }
199
+
200
ctx->obj = NULL;
201
+ ctx->program_fd = -1;
202
+ ctx->map_configuration = -1;
203
+ ctx->map_toeplitz_key = -1;
204
+ ctx->map_indirections_table = -1;
205
}
206
diff --git a/ebpf/ebpf_rss.h b/ebpf/ebpf_rss.h
207
index XXXXXXX..XXXXXXX 100644
208
--- a/ebpf/ebpf_rss.h
209
+++ b/ebpf/ebpf_rss.h
210
@@ -XXX,XX +XXX,XX @@ struct EBPFRSSContext {
211
int map_configuration;
212
int map_toeplitz_key;
213
int map_indirections_table;
214
+
215
+ /* mapped eBPF maps for direct access to omit bpf_map_update_elem() */
216
+ void *mmap_configuration;
217
+ void *mmap_toeplitz_key;
218
+ void *mmap_indirections_table;
219
};
220
221
struct EBPFRSSConfig {
222
--
676
--
223
2.7.4
677
2.7.4
678
679
diff view generated by jsdifflib
1
From: Tomasz Dzieciol <t.dzieciol@partner.samsung.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Rename e1000e_ba_state according and e1000e_write_hdr_to_rx_buffers for
3
This iova tree function allows it to look for a hole in allocated
4
consistency with IGB.
4
regions and return a totally new translation for a given translated
5
5
address.
6
Signed-off-by: Tomasz Dzieciol <t.dzieciol@partner.samsung.com>
6
7
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
7
It's usage is mainly to allow devices to access qemu address space,
8
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
8
remapping guest's one into a new iova space where qemu can add chunks of
9
addresses.
10
11
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
12
Reviewed-by: Peter Xu <peterx@redhat.com>
13
Acked-by: Michael S. Tsirkin <mst@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
14
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
---
15
---
11
hw/net/e1000e_core.c | 28 +++++++++++++++-------------
16
include/qemu/iova-tree.h | 18 +++++++
12
1 file changed, 15 insertions(+), 13 deletions(-)
17
util/iova-tree.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++
13
18
2 files changed, 154 insertions(+)
14
diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
19
20
diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h
15
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/net/e1000e_core.c
22
--- a/include/qemu/iova-tree.h
17
+++ b/hw/net/e1000e_core.c
23
+++ b/include/qemu/iova-tree.h
18
@@ -XXX,XX +XXX,XX @@ e1000e_pci_dma_write_rx_desc(E1000ECore *core, dma_addr_t addr,
24
@@ -XXX,XX +XXX,XX @@
19
}
25
#define IOVA_OK (0)
26
#define IOVA_ERR_INVALID (-1) /* Invalid parameters */
27
#define IOVA_ERR_OVERLAP (-2) /* IOVA range overlapped */
28
+#define IOVA_ERR_NOMEM (-3) /* Cannot allocate */
29
30
typedef struct IOVATree IOVATree;
31
typedef struct DMAMap {
32
@@ -XXX,XX +XXX,XX @@ const DMAMap *iova_tree_find_address(const IOVATree *tree, hwaddr iova);
33
void iova_tree_foreach(IOVATree *tree, iova_tree_iterator iterator);
34
35
/**
36
+ * iova_tree_alloc_map:
37
+ *
38
+ * @tree: the iova tree to allocate from
39
+ * @map: the new map (as translated addr & size) to allocate in the iova region
40
+ * @iova_begin: the minimum address of the allocation
41
+ * @iova_end: the maximum addressable direction of the allocation
42
+ *
43
+ * Allocates a new region of a given size, between iova_min and iova_max.
44
+ *
45
+ * Return: Same as iova_tree_insert, but cannot overlap and can return error if
46
+ * iova tree is out of free contiguous range. The caller gets the assigned iova
47
+ * in map->iova.
48
+ */
49
+int iova_tree_alloc_map(IOVATree *tree, DMAMap *map, hwaddr iova_begin,
50
+ hwaddr iova_end);
51
+
52
+/**
53
* iova_tree_destroy:
54
*
55
* @tree: the iova tree to destroy
56
diff --git a/util/iova-tree.c b/util/iova-tree.c
57
index XXXXXXX..XXXXXXX 100644
58
--- a/util/iova-tree.c
59
+++ b/util/iova-tree.c
60
@@ -XXX,XX +XXX,XX @@ struct IOVATree {
61
GTree *tree;
62
};
63
64
+/* Args to pass to iova_tree_alloc foreach function. */
65
+struct IOVATreeAllocArgs {
66
+ /* Size of the desired allocation */
67
+ size_t new_size;
68
+
69
+ /* The minimum address allowed in the allocation */
70
+ hwaddr iova_begin;
71
+
72
+ /* Map at the left of the hole, can be NULL if "this" is first one */
73
+ const DMAMap *prev;
74
+
75
+ /* Map at the right of the hole, can be NULL if "prev" is the last one */
76
+ const DMAMap *this;
77
+
78
+ /* If found, we fill in the IOVA here */
79
+ hwaddr iova_result;
80
+
81
+ /* Whether have we found a valid IOVA */
82
+ bool iova_found;
83
+};
84
+
85
+/**
86
+ * Iterate args to the next hole
87
+ *
88
+ * @args: The alloc arguments
89
+ * @next: The next mapping in the tree. Can be NULL to signal the last one
90
+ */
91
+static void iova_tree_alloc_args_iterate(struct IOVATreeAllocArgs *args,
92
+ const DMAMap *next)
93
+{
94
+ args->prev = args->this;
95
+ args->this = next;
96
+}
97
+
98
static int iova_tree_compare(gconstpointer a, gconstpointer b, gpointer data)
99
{
100
const DMAMap *m1 = a, *m2 = b;
101
@@ -XXX,XX +XXX,XX @@ int iova_tree_remove(IOVATree *tree, const DMAMap *map)
102
return IOVA_OK;
20
}
103
}
21
104
22
-typedef struct e1000e_ba_state_st {
105
+/**
23
+typedef struct E1000EBAState {
106
+ * Try to find an unallocated IOVA range between prev and this elements.
24
uint16_t written[MAX_PS_BUFFERS];
107
+ *
25
uint8_t cur_idx;
108
+ * @args: Arguments to allocation
26
-} e1000e_ba_state;
109
+ *
27
+} E1000EBAState;
110
+ * Cases:
28
111
+ *
29
static inline void
112
+ * (1) !prev, !this: No entries allocated, always succeed
30
-e1000e_write_hdr_to_rx_buffers(E1000ECore *core,
113
+ *
31
- hwaddr ba[MAX_PS_BUFFERS],
114
+ * (2) !prev, this: We're iterating at the 1st element.
32
- e1000e_ba_state *bastate,
115
+ *
33
- const char *data,
116
+ * (3) prev, !this: We're iterating at the last element.
34
- dma_addr_t data_len)
117
+ *
35
+e1000e_write_hdr_frag_to_rx_buffers(E1000ECore *core,
118
+ * (4) prev, this: this is the most common case, we'll try to find a hole
36
+ hwaddr ba[MAX_PS_BUFFERS],
119
+ * between "prev" and "this" mapping.
37
+ E1000EBAState *bastate,
120
+ *
38
+ const char *data,
121
+ * Note that this function assumes the last valid iova is HWADDR_MAX, but it
39
+ dma_addr_t data_len)
122
+ * searches linearly so it's easy to discard the result if it's not the case.
123
+ */
124
+static void iova_tree_alloc_map_in_hole(struct IOVATreeAllocArgs *args)
125
+{
126
+ const DMAMap *prev = args->prev, *this = args->this;
127
+ uint64_t hole_start, hole_last;
128
+
129
+ if (this && this->iova + this->size < args->iova_begin) {
130
+ return;
131
+ }
132
+
133
+ hole_start = MAX(prev ? prev->iova + prev->size + 1 : 0, args->iova_begin);
134
+ hole_last = this ? this->iova : HWADDR_MAX;
135
+
136
+ if (hole_last - hole_start > args->new_size) {
137
+ args->iova_result = hole_start;
138
+ args->iova_found = true;
139
+ }
140
+}
141
+
142
+/**
143
+ * Foreach dma node in the tree, compare if there is a hole with its previous
144
+ * node (or minimum iova address allowed) and the node.
145
+ *
146
+ * @key: Node iterating
147
+ * @value: Node iterating
148
+ * @pargs: Struct to communicate with the outside world
149
+ *
150
+ * Return: false to keep iterating, true if needs break.
151
+ */
152
+static gboolean iova_tree_alloc_traverse(gpointer key, gpointer value,
153
+ gpointer pargs)
154
+{
155
+ struct IOVATreeAllocArgs *args = pargs;
156
+ DMAMap *node = value;
157
+
158
+ assert(key == value);
159
+
160
+ iova_tree_alloc_args_iterate(args, node);
161
+ iova_tree_alloc_map_in_hole(args);
162
+ return args->iova_found;
163
+}
164
+
165
+int iova_tree_alloc_map(IOVATree *tree, DMAMap *map, hwaddr iova_begin,
166
+ hwaddr iova_last)
167
+{
168
+ struct IOVATreeAllocArgs args = {
169
+ .new_size = map->size,
170
+ .iova_begin = iova_begin,
171
+ };
172
+
173
+ if (unlikely(iova_last < iova_begin)) {
174
+ return IOVA_ERR_INVALID;
175
+ }
176
+
177
+ /*
178
+ * Find a valid hole for the mapping
179
+ *
180
+ * Assuming low iova_begin, so no need to do a binary search to
181
+ * locate the first node.
182
+ *
183
+ * TODO: Replace all this with g_tree_node_first/next/last when available
184
+ * (from glib since 2.68). To do it with g_tree_foreach complicates the
185
+ * code a lot.
186
+ *
187
+ */
188
+ g_tree_foreach(tree->tree, iova_tree_alloc_traverse, &args);
189
+ if (!args.iova_found) {
190
+ /*
191
+ * Either tree is empty or the last hole is still not checked.
192
+ * g_tree_foreach does not compare (last, iova_last] range, so we check
193
+ * it here.
194
+ */
195
+ iova_tree_alloc_args_iterate(&args, NULL);
196
+ iova_tree_alloc_map_in_hole(&args);
197
+ }
198
+
199
+ if (!args.iova_found || args.iova_result + map->size > iova_last) {
200
+ return IOVA_ERR_NOMEM;
201
+ }
202
+
203
+ map->iova = args.iova_result;
204
+ return iova_tree_insert(tree, map);
205
+}
206
+
207
void iova_tree_destroy(IOVATree *tree)
40
{
208
{
41
assert(data_len <= core->rxbuf_sizes[0] - bastate->written[0]);
209
g_tree_destroy(tree->tree);
42
43
@@ -XXX,XX +XXX,XX @@ e1000e_write_hdr_to_rx_buffers(E1000ECore *core,
44
static void
45
e1000e_write_payload_frag_to_rx_buffers(E1000ECore *core,
46
hwaddr ba[MAX_PS_BUFFERS],
47
- e1000e_ba_state *bastate,
48
+ E1000EBAState *bastate,
49
const char *data,
50
dma_addr_t data_len)
51
{
52
@@ -XXX,XX +XXX,XX @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
53
54
do {
55
hwaddr ba[MAX_PS_BUFFERS];
56
- e1000e_ba_state bastate = { { 0 } };
57
+ E1000EBAState bastate = { { 0 } };
58
bool is_last = false;
59
60
desc_size = total_size - desc_offset;
61
@@ -XXX,XX +XXX,XX @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
62
iov_copy = MIN(ps_hdr_len - ps_hdr_copied,
63
iov->iov_len - iov_ofs);
64
65
- e1000e_write_hdr_to_rx_buffers(core, ba, &bastate,
66
- iov->iov_base, iov_copy);
67
+ e1000e_write_hdr_frag_to_rx_buffers(core, ba,
68
+ &bastate,
69
+ iov->iov_base,
70
+ iov_copy);
71
72
copy_size -= iov_copy;
73
ps_hdr_copied += iov_copy;
74
@@ -XXX,XX +XXX,XX @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
75
} else {
76
/* Leave buffer 0 of each descriptor except first */
77
/* empty as per spec 7.1.5.1 */
78
- e1000e_write_hdr_to_rx_buffers(core, ba, &bastate,
79
- NULL, 0);
80
+ e1000e_write_hdr_frag_to_rx_buffers(core, ba, &bastate,
81
+ NULL, 0);
82
}
83
}
84
85
--
210
--
86
2.7.4
211
2.7.4
212
213
diff view generated by jsdifflib
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Tap indicates support for USO features according to
3
This function does the reverse operation of iova_tree_find: To look for
4
capabilities of current kernel module.
4
a mapping that match a translated address so we can do the reverse.
5
5
6
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
6
This have linear complexity instead of logarithmic, but it supports
7
Signed-off-by: Andrew Melnychecnko <andrew@daynix.com>
7
overlapping HVA. Future developments could reduce it.
8
9
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
10
Acked-by: Michael S. Tsirkin <mst@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
12
---
10
include/net/net.h | 3 +++
13
include/qemu/iova-tree.h | 20 +++++++++++++++++++-
11
net/net.c | 9 +++++++++
14
util/iova-tree.c | 34 ++++++++++++++++++++++++++++++++++
12
net/tap-bsd.c | 5 +++++
15
2 files changed, 53 insertions(+), 1 deletion(-)
13
net/tap-linux.c | 12 ++++++++++++
14
net/tap-solaris.c | 5 +++++
15
net/tap-stub.c | 5 +++++
16
net/tap.c | 12 ++++++++++++
17
net/tap_int.h | 1 +
18
8 files changed, 52 insertions(+)
19
16
20
diff --git a/include/net/net.h b/include/net/net.h
17
diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h
21
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
22
--- a/include/net/net.h
19
--- a/include/qemu/iova-tree.h
23
+++ b/include/net/net.h
20
+++ b/include/qemu/iova-tree.h
24
@@ -XXX,XX +XXX,XX @@ typedef void (LinkStatusChanged)(NetClientState *);
21
@@ -XXX,XX +XXX,XX @@ int iova_tree_remove(IOVATree *tree, const DMAMap *map);
25
typedef void (NetClientDestructor)(NetClientState *);
22
* @tree: the iova tree to search from
26
typedef RxFilterInfo *(QueryRxFilter)(NetClientState *);
23
* @map: the mapping to search
27
typedef bool (HasUfo)(NetClientState *);
24
*
28
+typedef bool (HasUso)(NetClientState *);
25
- * Search for a mapping in the iova tree that overlaps with the
29
typedef bool (HasVnetHdr)(NetClientState *);
26
+ * Search for a mapping in the iova tree that iova overlaps with the
30
typedef bool (HasVnetHdrLen)(NetClientState *, int);
27
* mapping range specified. Only the first found mapping will be
31
typedef bool (GetUsingVnetHdr)(NetClientState *);
28
* returned.
32
@@ -XXX,XX +XXX,XX @@ typedef struct NetClientInfo {
29
*
33
QueryRxFilter *query_rx_filter;
30
@@ -XXX,XX +XXX,XX @@ int iova_tree_remove(IOVATree *tree, const DMAMap *map);
34
NetPoll *poll;
31
const DMAMap *iova_tree_find(const IOVATree *tree, const DMAMap *map);
35
HasUfo *has_ufo;
32
36
+ HasUso *has_uso;
33
/**
37
HasVnetHdr *has_vnet_hdr;
34
+ * iova_tree_find_iova:
38
HasVnetHdrLen *has_vnet_hdr_len;
35
+ *
39
GetUsingVnetHdr *get_using_vnet_hdr;
36
+ * @tree: the iova tree to search from
40
@@ -XXX,XX +XXX,XX @@ void qemu_set_info_str(NetClientState *nc,
37
+ * @map: the mapping to search
41
const char *fmt, ...) G_GNUC_PRINTF(2, 3);
38
+ *
42
void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]);
39
+ * Search for a mapping in the iova tree that translated_addr overlaps with the
43
bool qemu_has_ufo(NetClientState *nc);
40
+ * mapping range specified. Only the first found mapping will be
44
+bool qemu_has_uso(NetClientState *nc);
41
+ * returned.
45
bool qemu_has_vnet_hdr(NetClientState *nc);
42
+ *
46
bool qemu_has_vnet_hdr_len(NetClientState *nc, int len);
43
+ * Return: DMAMap pointer if found, or NULL if not found. Note that
47
bool qemu_get_using_vnet_hdr(NetClientState *nc);
44
+ * the returned DMAMap pointer is maintained internally. User should
48
diff --git a/net/net.c b/net/net.c
45
+ * only read the content but never modify or free the content. Also,
46
+ * user is responsible to make sure the pointer is valid (say, no
47
+ * concurrent deletion in progress).
48
+ */
49
+const DMAMap *iova_tree_find_iova(const IOVATree *tree, const DMAMap *map);
50
+
51
+/**
52
* iova_tree_find_address:
53
*
54
* @tree: the iova tree to search from
55
diff --git a/util/iova-tree.c b/util/iova-tree.c
49
index XXXXXXX..XXXXXXX 100644
56
index XXXXXXX..XXXXXXX 100644
50
--- a/net/net.c
57
--- a/util/iova-tree.c
51
+++ b/net/net.c
58
+++ b/util/iova-tree.c
52
@@ -XXX,XX +XXX,XX @@ bool qemu_has_ufo(NetClientState *nc)
59
@@ -XXX,XX +XXX,XX @@ struct IOVATreeAllocArgs {
53
return nc->info->has_ufo(nc);
60
bool iova_found;
61
};
62
63
+typedef struct IOVATreeFindIOVAArgs {
64
+ const DMAMap *needle;
65
+ const DMAMap *result;
66
+} IOVATreeFindIOVAArgs;
67
+
68
/**
69
* Iterate args to the next hole
70
*
71
@@ -XXX,XX +XXX,XX @@ const DMAMap *iova_tree_find(const IOVATree *tree, const DMAMap *map)
72
return g_tree_lookup(tree->tree, map);
54
}
73
}
55
74
56
+bool qemu_has_uso(NetClientState *nc)
75
+static gboolean iova_tree_find_address_iterator(gpointer key, gpointer value,
76
+ gpointer data)
57
+{
77
+{
58
+ if (!nc || !nc->info->has_uso) {
78
+ const DMAMap *map = key;
79
+ IOVATreeFindIOVAArgs *args = data;
80
+ const DMAMap *needle;
81
+
82
+ g_assert(key == value);
83
+
84
+ needle = args->needle;
85
+ if (map->translated_addr + map->size < needle->translated_addr ||
86
+ needle->translated_addr + needle->size < map->translated_addr) {
59
+ return false;
87
+ return false;
60
+ }
88
+ }
61
+
89
+
62
+ return nc->info->has_uso(nc);
90
+ args->result = map;
91
+ return true;
63
+}
92
+}
64
+
93
+
65
bool qemu_has_vnet_hdr(NetClientState *nc)
94
+const DMAMap *iova_tree_find_iova(const IOVATree *tree, const DMAMap *map)
66
{
67
if (!nc || !nc->info->has_vnet_hdr) {
68
diff --git a/net/tap-bsd.c b/net/tap-bsd.c
69
index XXXXXXX..XXXXXXX 100644
70
--- a/net/tap-bsd.c
71
+++ b/net/tap-bsd.c
72
@@ -XXX,XX +XXX,XX @@ int tap_probe_has_ufo(int fd)
73
return 0;
74
}
75
76
+int tap_probe_has_uso(int fd)
77
+{
95
+{
78
+ return 0;
96
+ IOVATreeFindIOVAArgs args = {
97
+ .needle = map,
98
+ };
99
+
100
+ g_tree_foreach(tree->tree, iova_tree_find_address_iterator, &args);
101
+ return args.result;
79
+}
102
+}
80
+
103
+
81
int tap_probe_vnet_hdr_len(int fd, int len)
104
const DMAMap *iova_tree_find_address(const IOVATree *tree, hwaddr iova)
82
{
105
{
83
return 0;
106
const DMAMap map = { .iova = iova, .size = 0 };
84
diff --git a/net/tap-linux.c b/net/tap-linux.c
85
index XXXXXXX..XXXXXXX 100644
86
--- a/net/tap-linux.c
87
+++ b/net/tap-linux.c
88
@@ -XXX,XX +XXX,XX @@ int tap_probe_has_ufo(int fd)
89
return 1;
90
}
91
92
+int tap_probe_has_uso(int fd)
93
+{
94
+ unsigned offload;
95
+
96
+ offload = TUN_F_CSUM | TUN_F_USO4 | TUN_F_USO6;
97
+
98
+ if (ioctl(fd, TUNSETOFFLOAD, offload) < 0) {
99
+ return 0;
100
+ }
101
+ return 1;
102
+}
103
+
104
/* Verify that we can assign given length */
105
int tap_probe_vnet_hdr_len(int fd, int len)
106
{
107
diff --git a/net/tap-solaris.c b/net/tap-solaris.c
108
index XXXXXXX..XXXXXXX 100644
109
--- a/net/tap-solaris.c
110
+++ b/net/tap-solaris.c
111
@@ -XXX,XX +XXX,XX @@ int tap_probe_has_ufo(int fd)
112
return 0;
113
}
114
115
+int tap_probe_has_uso(int fd)
116
+{
117
+ return 0;
118
+}
119
+
120
int tap_probe_vnet_hdr_len(int fd, int len)
121
{
122
return 0;
123
diff --git a/net/tap-stub.c b/net/tap-stub.c
124
index XXXXXXX..XXXXXXX 100644
125
--- a/net/tap-stub.c
126
+++ b/net/tap-stub.c
127
@@ -XXX,XX +XXX,XX @@ int tap_probe_has_ufo(int fd)
128
return 0;
129
}
130
131
+int tap_probe_has_uso(int fd)
132
+{
133
+ return 0;
134
+}
135
+
136
int tap_probe_vnet_hdr_len(int fd, int len)
137
{
138
return 0;
139
diff --git a/net/tap.c b/net/tap.c
140
index XXXXXXX..XXXXXXX 100644
141
--- a/net/tap.c
142
+++ b/net/tap.c
143
@@ -XXX,XX +XXX,XX @@ typedef struct TAPState {
144
bool write_poll;
145
bool using_vnet_hdr;
146
bool has_ufo;
147
+ bool has_uso;
148
bool enabled;
149
VHostNetState *vhost_net;
150
unsigned host_vnet_hdr_len;
151
@@ -XXX,XX +XXX,XX @@ static bool tap_has_ufo(NetClientState *nc)
152
return s->has_ufo;
153
}
154
155
+static bool tap_has_uso(NetClientState *nc)
156
+{
157
+ TAPState *s = DO_UPCAST(TAPState, nc, nc);
158
+
159
+ assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
160
+
161
+ return s->has_uso;
162
+}
163
+
164
static bool tap_has_vnet_hdr(NetClientState *nc)
165
{
166
TAPState *s = DO_UPCAST(TAPState, nc, nc);
167
@@ -XXX,XX +XXX,XX @@ static NetClientInfo net_tap_info = {
168
.poll = tap_poll,
169
.cleanup = tap_cleanup,
170
.has_ufo = tap_has_ufo,
171
+ .has_uso = tap_has_uso,
172
.has_vnet_hdr = tap_has_vnet_hdr,
173
.has_vnet_hdr_len = tap_has_vnet_hdr_len,
174
.get_using_vnet_hdr = tap_get_using_vnet_hdr,
175
@@ -XXX,XX +XXX,XX @@ static TAPState *net_tap_fd_init(NetClientState *peer,
176
s->host_vnet_hdr_len = vnet_hdr ? sizeof(struct virtio_net_hdr) : 0;
177
s->using_vnet_hdr = false;
178
s->has_ufo = tap_probe_has_ufo(s->fd);
179
+ s->has_uso = tap_probe_has_uso(s->fd);
180
s->enabled = true;
181
tap_set_offload(&s->nc, 0, 0, 0, 0, 0, 0, 0);
182
/*
183
diff --git a/net/tap_int.h b/net/tap_int.h
184
index XXXXXXX..XXXXXXX 100644
185
--- a/net/tap_int.h
186
+++ b/net/tap_int.h
187
@@ -XXX,XX +XXX,XX @@ void tap_set_sndbuf(int fd, const NetdevTapOptions *tap, Error **errp);
188
int tap_probe_vnet_hdr(int fd, Error **errp);
189
int tap_probe_vnet_hdr_len(int fd, int len);
190
int tap_probe_has_ufo(int fd);
191
+int tap_probe_has_uso(int fd);
192
void tap_fd_set_offload(int fd, int csum, int tso4, int tso6, int ecn, int ufo,
193
int uso4, int uso6);
194
void tap_fd_set_vnet_hdr_len(int fd, int len);
195
--
107
--
196
2.7.4
108
2.7.4
109
110
diff view generated by jsdifflib
Deleted patch
1
From: Andrew Melnychenko <andrew@daynix.com>
2
1
3
New features are subject to check with vhost-user and vdpa.
4
5
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
6
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
9
hw/net/vhost_net.c | 3 +++
10
net/vhost-vdpa.c | 3 +++
11
2 files changed, 6 insertions(+)
12
13
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/net/vhost_net.c
16
+++ b/hw/net/vhost_net.c
17
@@ -XXX,XX +XXX,XX @@ static const int user_feature_bits[] = {
18
VIRTIO_F_RING_RESET,
19
VIRTIO_NET_F_RSS,
20
VIRTIO_NET_F_HASH_REPORT,
21
+ VIRTIO_NET_F_GUEST_USO4,
22
+ VIRTIO_NET_F_GUEST_USO6,
23
+ VIRTIO_NET_F_HOST_USO,
24
25
/* This bit implies RARP isn't sent by QEMU out of band */
26
VIRTIO_NET_F_GUEST_ANNOUNCE,
27
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
28
index XXXXXXX..XXXXXXX 100644
29
--- a/net/vhost-vdpa.c
30
+++ b/net/vhost-vdpa.c
31
@@ -XXX,XX +XXX,XX @@ const int vdpa_feature_bits[] = {
32
VIRTIO_NET_F_GUEST_TSO4,
33
VIRTIO_NET_F_GUEST_TSO6,
34
VIRTIO_NET_F_GUEST_UFO,
35
+ VIRTIO_NET_F_GUEST_USO4,
36
+ VIRTIO_NET_F_GUEST_USO6,
37
VIRTIO_NET_F_HASH_REPORT,
38
VIRTIO_NET_F_HOST_ECN,
39
VIRTIO_NET_F_HOST_TSO4,
40
VIRTIO_NET_F_HOST_TSO6,
41
VIRTIO_NET_F_HOST_UFO,
42
+ VIRTIO_NET_F_HOST_USO,
43
VIRTIO_NET_F_MQ,
44
VIRTIO_NET_F_MRG_RXBUF,
45
VIRTIO_NET_F_MTU,
46
--
47
2.7.4
diff view generated by jsdifflib
1
From: Ilya Maximets <i.maximets@ovn.org>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
AF_XDP is a network socket family that allows communication directly
3
This tree is able to look for a translated address from an IOVA address.
4
with the network device driver in the kernel, bypassing most or all
5
of the kernel networking stack. In the essence, the technology is
6
pretty similar to netmap. But, unlike netmap, AF_XDP is Linux-native
7
and works with any network interfaces without driver modifications.
8
Unlike vhost-based backends (kernel, user, vdpa), AF_XDP doesn't
9
require access to character devices or unix sockets. Only access to
10
the network interface itself is necessary.
11
4
12
This patch implements a network backend that communicates with the
5
At first glance it is similar to util/iova-tree. However, SVQ working on
13
kernel by creating an AF_XDP socket. A chunk of userspace memory
6
devices with limited IOVA space need more capabilities, like allocating
14
is shared between QEMU and the host kernel. 4 ring buffers (Tx, Rx,
7
IOVA chunks or performing reverse translations (qemu addresses to iova).
15
Fill and Completion) are placed in that memory along with a pool of
16
memory buffers for the packet data. Data transmission is done by
17
allocating one of the buffers, copying packet data into it and
18
placing the pointer into Tx ring. After transmission, device will
19
return the buffer via Completion ring. On Rx, device will take
20
a buffer form a pre-populated Fill ring, write the packet data into
21
it and place the buffer into Rx ring.
22
8
23
AF_XDP network backend takes on the communication with the host
9
The allocation capability, as "assign a free IOVA address to this chunk
24
kernel and the network interface and forwards packets to/from the
10
of memory in qemu's address space" allows shadow virtqueue to create a
25
peer device in QEMU.
11
new address space that is not restricted by guest's addressable one, so
12
we can allocate shadow vqs vrings outside of it.
26
13
27
Usage example:
14
It duplicates the tree so it can search efficiently in both directions,
15
and it will signal overlap if iova or the translated address is present
16
in any tree.
28
17
29
-device virtio-net-pci,netdev=guest1,mac=00:16:35:AF:AA:5C
18
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
30
-netdev af-xdp,ifname=ens6f1np1,id=guest1,mode=native,queues=1
19
Acked-by: Michael S. Tsirkin <mst@redhat.com>
31
32
XDP program bridges the socket with a network interface. It can be
33
attached to the interface in 2 different modes:
34
35
1. skb - this mode should work for any interface and doesn't require
36
driver support. With a caveat of lower performance.
37
38
2. native - this does require support from the driver and allows to
39
bypass skb allocation in the kernel and potentially use
40
zero-copy while getting packets in/out userspace.
41
42
By default, QEMU will try to use native mode and fall back to skb.
43
Mode can be forced via 'mode' option. To force 'copy' even in native
44
mode, use 'force-copy=on' option. This might be useful if there is
45
some issue with the driver.
46
47
Option 'queues=N' allows to specify how many device queues should
48
be open. Note that all the queues that are not open are still
49
functional and can receive traffic, but it will not be delivered to
50
QEMU. So, the number of device queues should generally match the
51
QEMU configuration, unless the device is shared with something
52
else and the traffic re-direction to appropriate queues is correctly
53
configured on a device level (e.g. with ethtool -N).
54
'start-queue=M' option can be used to specify from which queue id
55
QEMU should start configuring 'N' queues. It might also be necessary
56
to use this option with certain NICs, e.g. MLX5 NICs. See the docs
57
for examples.
58
59
In a general case QEMU will need CAP_NET_ADMIN and CAP_SYS_ADMIN
60
or CAP_BPF capabilities in order to load default XSK/XDP programs to
61
the network interface and configure BPF maps. It is possible, however,
62
to run with no capabilities. For that to work, an external process
63
with enough capabilities will need to pre-load default XSK program,
64
create AF_XDP sockets and pass their file descriptors to QEMU process
65
on startup via 'sock-fds' option. Network backend will need to be
66
configured with 'inhibit=on' to avoid loading of the program.
67
QEMU will need 32 MB of locked memory (RLIMIT_MEMLOCK) per queue
68
or CAP_IPC_LOCK.
69
70
There are few performance challenges with the current network backends.
71
72
First is that they do not support IO threads. This means that data
73
path is handled by the main thread in QEMU and may slow down other
74
work or may be slowed down by some other work. This also means that
75
taking advantage of multi-queue is generally not possible today.
76
77
Another thing is that data path is going through the device emulation
78
code, which is not really optimized for performance. The fastest
79
"frontend" device is virtio-net. But it's not optimized for heavy
80
traffic either, because it expects such use-cases to be handled via
81
some implementation of vhost (user, kernel, vdpa). In practice, we
82
have virtio notifications and rcu lock/unlock on a per-packet basis
83
and not very efficient accesses to the guest memory. Communication
84
channels between backend and frontend devices do not allow passing
85
more than one packet at a time as well.
86
87
Some of these challenges can be avoided in the future by adding better
88
batching into device emulation or by implementing vhost-af-xdp variant.
89
90
There are also a few kernel limitations. AF_XDP sockets do not
91
support any kinds of checksum or segmentation offloading. Buffers
92
are limited to a page size (4K), i.e. MTU is limited. Multi-buffer
93
support implementation for AF_XDP is in progress, but not ready yet.
94
Also, transmission in all non-zero-copy modes is synchronous, i.e.
95
done in a syscall. That doesn't allow high packet rates on virtual
96
interfaces.
97
98
However, keeping in mind all of these challenges, current implementation
99
of the AF_XDP backend shows a decent performance while running on top
100
of a physical NIC with zero-copy support.
101
102
Test setup:
103
104
2 VMs running on 2 physical hosts connected via ConnectX6-Dx card.
105
Network backend is configured to open the NIC directly in native mode.
106
The driver supports zero-copy. NIC is configured to use 1 queue.
107
108
Inside a VM - iperf3 for basic TCP performance testing and dpdk-testpmd
109
for PPS testing.
110
111
iperf3 result:
112
TCP stream : 19.1 Gbps
113
114
dpdk-testpmd (single queue, single CPU core, 64 B packets) results:
115
Tx only : 3.4 Mpps
116
Rx only : 2.0 Mpps
117
L2 FWD Loopback : 1.5 Mpps
118
119
In skb mode the same setup shows much lower performance, similar to
120
the setup where pair of physical NICs is replaced with veth pair:
121
122
iperf3 result:
123
TCP stream : 9 Gbps
124
125
dpdk-testpmd (single queue, single CPU core, 64 B packets) results:
126
Tx only : 1.2 Mpps
127
Rx only : 1.0 Mpps
128
L2 FWD Loopback : 0.7 Mpps
129
130
Results in skb mode or over the veth are close to results of a tap
131
backend with vhost=on and disabled segmentation offloading bridged
132
with a NIC.
133
134
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
135
Signed-off-by: Jason Wang <jasowang@redhat.com>
20
Signed-off-by: Jason Wang <jasowang@redhat.com>
136
---
21
---
137
MAINTAINERS | 4 +
22
hw/virtio/meson.build | 2 +-
138
hmp-commands.hx | 3 +
23
hw/virtio/vhost-iova-tree.c | 110 ++++++++++++++++++++++++++++++++++++++++++++
139
meson.build | 9 +
24
hw/virtio/vhost-iova-tree.h | 27 +++++++++++
140
meson_options.txt | 2 +
25
3 files changed, 138 insertions(+), 1 deletion(-)
141
net/af-xdp.c | 526 ++++++++++++++++++++++++
26
create mode 100644 hw/virtio/vhost-iova-tree.c
142
net/clients.h | 5 +
27
create mode 100644 hw/virtio/vhost-iova-tree.h
143
net/meson.build | 3 +
144
net/net.c | 6 +
145
qapi/net.json | 58 +++
146
qemu-options.hx | 70 +++-
147
scripts/ci/org.centos/stream/8/x86_64/configure | 1 +
148
scripts/meson-buildoptions.sh | 3 +
149
tests/docker/dockerfiles/debian-amd64.docker | 1 +
150
13 files changed, 690 insertions(+), 1 deletion(-)
151
create mode 100644 net/af-xdp.c
152
28
153
diff --git a/MAINTAINERS b/MAINTAINERS
29
diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
154
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
155
--- a/MAINTAINERS
31
--- a/hw/virtio/meson.build
156
+++ b/MAINTAINERS
32
+++ b/hw/virtio/meson.build
157
@@ -XXX,XX +XXX,XX @@ W: http://info.iet.unipi.it/~luigi/netmap/
33
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-stub.c'))
158
S: Maintained
34
159
F: net/netmap.c
35
virtio_ss = ss.source_set()
160
36
virtio_ss.add(files('virtio.c'))
161
+AF_XDP network backend
37
-virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-shadow-virtqueue.c'))
162
+R: Ilya Maximets <i.maximets@ovn.org>
38
+virtio_ss.add(when: 'CONFIG_VHOST', if_true: files('vhost.c', 'vhost-backend.c', 'vhost-shadow-virtqueue.c', 'vhost-iova-tree.c'))
163
+F: net/af-xdp.c
39
virtio_ss.add(when: 'CONFIG_VHOST_USER', if_true: files('vhost-user.c'))
164
+
40
virtio_ss.add(when: 'CONFIG_VHOST_VDPA', if_true: files('vhost-vdpa.c'))
165
Host Memory Backends
41
virtio_ss.add(when: 'CONFIG_VIRTIO_BALLOON', if_true: files('virtio-balloon.c'))
166
M: David Hildenbrand <david@redhat.com>
42
diff --git a/hw/virtio/vhost-iova-tree.c b/hw/virtio/vhost-iova-tree.c
167
M: Igor Mammedov <imammedo@redhat.com>
168
diff --git a/hmp-commands.hx b/hmp-commands.hx
169
index XXXXXXX..XXXXXXX 100644
170
--- a/hmp-commands.hx
171
+++ b/hmp-commands.hx
172
@@ -XXX,XX +XXX,XX @@ ERST
173
.name = "netdev_add",
174
.args_type = "netdev:O",
175
.params = "[user|tap|socket|stream|dgram|vde|bridge|hubport|netmap|vhost-user"
176
+#ifdef CONFIG_AF_XDP
177
+ "|af-xdp"
178
+#endif
179
#ifdef CONFIG_VMNET
180
"|vmnet-host|vmnet-shared|vmnet-bridged"
181
#endif
182
diff --git a/meson.build b/meson.build
183
index XXXXXXX..XXXXXXX 100644
184
--- a/meson.build
185
+++ b/meson.build
186
@@ -XXX,XX +XXX,XX @@ if libbpf.found() and not cc.links('''
187
endif
188
endif
189
190
+# libxdp
191
+libxdp = not_found
192
+if not get_option('af_xdp').auto() or have_system
193
+ libxdp = dependency('libxdp', required: get_option('af_xdp'),
194
+ version: '>=1.4.0', method: 'pkg-config')
195
+endif
196
+
197
# libdw
198
libdw = not_found
199
if not get_option('libdw').auto() or \
200
@@ -XXX,XX +XXX,XX @@ config_host_data.set('CONFIG_HEXAGON_IDEF_PARSER', get_option('hexagon_idef_pars
201
config_host_data.set('CONFIG_LIBATTR', have_old_libattr)
202
config_host_data.set('CONFIG_LIBCAP_NG', libcap_ng.found())
203
config_host_data.set('CONFIG_EBPF', libbpf.found())
204
+config_host_data.set('CONFIG_AF_XDP', libxdp.found())
205
config_host_data.set('CONFIG_LIBDAXCTL', libdaxctl.found())
206
config_host_data.set('CONFIG_LIBISCSI', libiscsi.found())
207
config_host_data.set('CONFIG_LIBNFS', libnfs.found())
208
@@ -XXX,XX +XXX,XX @@ summary_info = {}
209
if targetos == 'darwin'
210
summary_info += {'vmnet.framework support': vmnet}
211
endif
212
+summary_info += {'AF_XDP support': libxdp}
213
summary_info += {'slirp support': slirp}
214
summary_info += {'vde support': vde}
215
summary_info += {'netmap support': have_netmap}
216
diff --git a/meson_options.txt b/meson_options.txt
217
index XXXXXXX..XXXXXXX 100644
218
--- a/meson_options.txt
219
+++ b/meson_options.txt
220
@@ -XXX,XX +XXX,XX @@ option('avx512bw', type: 'feature', value: 'auto',
221
option('keyring', type: 'feature', value: 'auto',
222
description: 'Linux keyring support')
223
224
+option('af_xdp', type : 'feature', value : 'auto',
225
+ description: 'AF_XDP network backend support')
226
option('attr', type : 'feature', value : 'auto',
227
description: 'attr/xattr support')
228
option('auth_pam', type : 'feature', value : 'auto',
229
diff --git a/net/af-xdp.c b/net/af-xdp.c
230
new file mode 100644
43
new file mode 100644
231
index XXXXXXX..XXXXXXX
44
index XXXXXXX..XXXXXXX
232
--- /dev/null
45
--- /dev/null
233
+++ b/net/af-xdp.c
46
+++ b/hw/virtio/vhost-iova-tree.c
234
@@ -XXX,XX +XXX,XX @@
47
@@ -XXX,XX +XXX,XX @@
235
+/*
48
+/*
236
+ * AF_XDP network backend.
49
+ * vhost software live migration iova tree
237
+ *
50
+ *
238
+ * Copyright (c) 2023 Red Hat, Inc.
51
+ * SPDX-FileCopyrightText: Red Hat, Inc. 2021
52
+ * SPDX-FileContributor: Author: Eugenio Pérez <eperezma@redhat.com>
239
+ *
53
+ *
240
+ * Authors:
54
+ * SPDX-License-Identifier: GPL-2.0-or-later
241
+ * Ilya Maximets <i.maximets@ovn.org>
242
+ *
243
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
244
+ * See the COPYING file in the top-level directory.
245
+ */
55
+ */
246
+
56
+
57
+#include "qemu/osdep.h"
58
+#include "qemu/iova-tree.h"
59
+#include "vhost-iova-tree.h"
247
+
60
+
248
+#include "qemu/osdep.h"
61
+#define iova_min_addr qemu_real_host_page_size
249
+#include <bpf/bpf.h>
250
+#include <inttypes.h>
251
+#include <linux/if_link.h>
252
+#include <linux/if_xdp.h>
253
+#include <net/if.h>
254
+#include <xdp/xsk.h>
255
+
62
+
256
+#include "clients.h"
63
+/**
257
+#include "monitor/monitor.h"
64
+ * VhostIOVATree, able to:
258
+#include "net/net.h"
65
+ * - Translate iova address
259
+#include "qapi/error.h"
66
+ * - Reverse translate iova address (from translated to iova)
260
+#include "qemu/cutils.h"
67
+ * - Allocate IOVA regions for translated range (linear operation)
261
+#include "qemu/error-report.h"
68
+ */
262
+#include "qemu/iov.h"
69
+struct VhostIOVATree {
263
+#include "qemu/main-loop.h"
70
+ /* First addressable iova address in the device */
264
+#include "qemu/memalign.h"
71
+ uint64_t iova_first;
265
+
72
+
73
+ /* Last addressable iova address in the device */
74
+ uint64_t iova_last;
266
+
75
+
267
+typedef struct AFXDPState {
76
+ /* IOVA address to qemu memory maps. */
268
+ NetClientState nc;
77
+ IOVATree *iova_taddr_map;
78
+};
269
+
79
+
270
+ struct xsk_socket *xsk;
80
+/**
271
+ struct xsk_ring_cons rx;
81
+ * Create a new IOVA tree
272
+ struct xsk_ring_prod tx;
82
+ *
273
+ struct xsk_ring_cons cq;
83
+ * Returns the new IOVA tree
274
+ struct xsk_ring_prod fq;
84
+ */
85
+VhostIOVATree *vhost_iova_tree_new(hwaddr iova_first, hwaddr iova_last)
86
+{
87
+ VhostIOVATree *tree = g_new(VhostIOVATree, 1);
275
+
88
+
276
+ char ifname[IFNAMSIZ];
89
+ /* Some devices do not like 0 addresses */
277
+ int ifindex;
90
+ tree->iova_first = MAX(iova_first, iova_min_addr);
278
+ bool read_poll;
91
+ tree->iova_last = iova_last;
279
+ bool write_poll;
280
+ uint32_t outstanding_tx;
281
+
92
+
282
+ uint64_t *pool;
93
+ tree->iova_taddr_map = iova_tree_new();
283
+ uint32_t n_pool;
94
+ return tree;
284
+ char *buffer;
285
+ struct xsk_umem *umem;
286
+
287
+ uint32_t n_queues;
288
+ uint32_t xdp_flags;
289
+ bool inhibit;
290
+} AFXDPState;
291
+
292
+#define AF_XDP_BATCH_SIZE 64
293
+
294
+static void af_xdp_send(void *opaque);
295
+static void af_xdp_writable(void *opaque);
296
+
297
+/* Set the event-loop handlers for the af-xdp backend. */
298
+static void af_xdp_update_fd_handler(AFXDPState *s)
299
+{
300
+ qemu_set_fd_handler(xsk_socket__fd(s->xsk),
301
+ s->read_poll ? af_xdp_send : NULL,
302
+ s->write_poll ? af_xdp_writable : NULL,
303
+ s);
304
+}
95
+}
305
+
96
+
306
+/* Update the read handler. */
97
+/**
307
+static void af_xdp_read_poll(AFXDPState *s, bool enable)
98
+ * Delete an iova tree
99
+ */
100
+void vhost_iova_tree_delete(VhostIOVATree *iova_tree)
308
+{
101
+{
309
+ if (s->read_poll != enable) {
102
+ iova_tree_destroy(iova_tree->iova_taddr_map);
310
+ s->read_poll = enable;
103
+ g_free(iova_tree);
311
+ af_xdp_update_fd_handler(s);
312
+ }
313
+}
104
+}
314
+
105
+
315
+/* Update the write handler. */
106
+/**
316
+static void af_xdp_write_poll(AFXDPState *s, bool enable)
107
+ * Find the IOVA address stored from a memory address
108
+ *
109
+ * @tree: The iova tree
110
+ * @map: The map with the memory address
111
+ *
112
+ * Return the stored mapping, or NULL if not found.
113
+ */
114
+const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *tree,
115
+ const DMAMap *map)
317
+{
116
+{
318
+ if (s->write_poll != enable) {
117
+ return iova_tree_find_iova(tree->iova_taddr_map, map);
319
+ s->write_poll = enable;
320
+ af_xdp_update_fd_handler(s);
321
+ }
322
+}
118
+}
323
+
119
+
324
+static void af_xdp_poll(NetClientState *nc, bool enable)
120
+/**
121
+ * Allocate a new mapping
122
+ *
123
+ * @tree: The iova tree
124
+ * @map: The iova map
125
+ *
126
+ * Returns:
127
+ * - IOVA_OK if the map fits in the container
128
+ * - IOVA_ERR_INVALID if the map does not make sense (like size overflow)
129
+ * - IOVA_ERR_NOMEM if tree cannot allocate more space.
130
+ *
131
+ * It returns assignated iova in map->iova if return value is VHOST_DMA_MAP_OK.
132
+ */
133
+int vhost_iova_tree_map_alloc(VhostIOVATree *tree, DMAMap *map)
325
+{
134
+{
326
+ AFXDPState *s = DO_UPCAST(AFXDPState, nc, nc);
135
+ /* Some vhost devices do not like addr 0. Skip first page */
136
+ hwaddr iova_first = tree->iova_first ?: qemu_real_host_page_size;
327
+
137
+
328
+ if (s->read_poll != enable || s->write_poll != enable) {
138
+ if (map->translated_addr + map->size < map->translated_addr ||
329
+ s->write_poll = enable;
139
+ map->perm == IOMMU_NONE) {
330
+ s->read_poll = enable;
140
+ return IOVA_ERR_INVALID;
331
+ af_xdp_update_fd_handler(s);
332
+ }
141
+ }
142
+
143
+ /* Allocate a node in IOVA address */
144
+ return iova_tree_alloc_map(tree->iova_taddr_map, map, iova_first,
145
+ tree->iova_last);
333
+}
146
+}
334
+
147
+
335
+static void af_xdp_complete_tx(AFXDPState *s)
148
+/**
149
+ * Remove existing mappings from iova tree
150
+ *
151
+ * @iova_tree: The vhost iova tree
152
+ * @map: The map to remove
153
+ */
154
+void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map)
336
+{
155
+{
337
+ uint32_t idx = 0;
156
+ iova_tree_remove(iova_tree->iova_taddr_map, map);
338
+ uint32_t done, i;
157
+}
339
+ uint64_t *addr;
158
diff --git a/hw/virtio/vhost-iova-tree.h b/hw/virtio/vhost-iova-tree.h
159
new file mode 100644
160
index XXXXXXX..XXXXXXX
161
--- /dev/null
162
+++ b/hw/virtio/vhost-iova-tree.h
163
@@ -XXX,XX +XXX,XX @@
164
+/*
165
+ * vhost software live migration iova tree
166
+ *
167
+ * SPDX-FileCopyrightText: Red Hat, Inc. 2021
168
+ * SPDX-FileContributor: Author: Eugenio Pérez <eperezma@redhat.com>
169
+ *
170
+ * SPDX-License-Identifier: GPL-2.0-or-later
171
+ */
340
+
172
+
341
+ done = xsk_ring_cons__peek(&s->cq, XSK_RING_CONS__DEFAULT_NUM_DESCS, &idx);
173
+#ifndef HW_VIRTIO_VHOST_IOVA_TREE_H
174
+#define HW_VIRTIO_VHOST_IOVA_TREE_H
342
+
175
+
343
+ for (i = 0; i < done; i++) {
176
+#include "qemu/iova-tree.h"
344
+ addr = (void *) xsk_ring_cons__comp_addr(&s->cq, idx++);
177
+#include "exec/memory.h"
345
+ s->pool[s->n_pool++] = *addr;
346
+ s->outstanding_tx--;
347
+ }
348
+
178
+
349
+ if (done) {
179
+typedef struct VhostIOVATree VhostIOVATree;
350
+ xsk_ring_cons__release(&s->cq, done);
351
+ }
352
+}
353
+
180
+
354
+/*
181
+VhostIOVATree *vhost_iova_tree_new(uint64_t iova_first, uint64_t iova_last);
355
+ * The fd_write() callback, invoked if the fd is marked as writable
182
+void vhost_iova_tree_delete(VhostIOVATree *iova_tree);
356
+ * after a poll.
183
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostIOVATree, vhost_iova_tree_delete);
357
+ */
358
+static void af_xdp_writable(void *opaque)
359
+{
360
+ AFXDPState *s = opaque;
361
+
184
+
362
+ /* Try to recover buffers that are already sent. */
185
+const DMAMap *vhost_iova_tree_find_iova(const VhostIOVATree *iova_tree,
363
+ af_xdp_complete_tx(s);
186
+ const DMAMap *map);
187
+int vhost_iova_tree_map_alloc(VhostIOVATree *iova_tree, DMAMap *map);
188
+void vhost_iova_tree_remove(VhostIOVATree *iova_tree, const DMAMap *map);
364
+
189
+
365
+ /*
366
+ * Unregister the handler, unless we still have packets to transmit
367
+ * and kernel needs a wake up.
368
+ */
369
+ if (!s->outstanding_tx || !xsk_ring_prod__needs_wakeup(&s->tx)) {
370
+ af_xdp_write_poll(s, false);
371
+ }
372
+
373
+ /* Flush any buffered packets. */
374
+ qemu_flush_queued_packets(&s->nc);
375
+}
376
+
377
+static ssize_t af_xdp_receive(NetClientState *nc,
378
+ const uint8_t *buf, size_t size)
379
+{
380
+ AFXDPState *s = DO_UPCAST(AFXDPState, nc, nc);
381
+ struct xdp_desc *desc;
382
+ uint32_t idx;
383
+ void *data;
384
+
385
+ /* Try to recover buffers that are already sent. */
386
+ af_xdp_complete_tx(s);
387
+
388
+ if (size > XSK_UMEM__DEFAULT_FRAME_SIZE) {
389
+ /* We can't transmit packet this size... */
390
+ return size;
391
+ }
392
+
393
+ if (!s->n_pool || !xsk_ring_prod__reserve(&s->tx, 1, &idx)) {
394
+ /*
395
+ * Out of buffers or space in tx ring. Poll until we can write.
396
+ * This will also kick the Tx, if it was waiting on CQ.
397
+ */
398
+ af_xdp_write_poll(s, true);
399
+ return 0;
400
+ }
401
+
402
+ desc = xsk_ring_prod__tx_desc(&s->tx, idx);
403
+ desc->addr = s->pool[--s->n_pool];
404
+ desc->len = size;
405
+
406
+ data = xsk_umem__get_data(s->buffer, desc->addr);
407
+ memcpy(data, buf, size);
408
+
409
+ xsk_ring_prod__submit(&s->tx, 1);
410
+ s->outstanding_tx++;
411
+
412
+ if (xsk_ring_prod__needs_wakeup(&s->tx)) {
413
+ af_xdp_write_poll(s, true);
414
+ }
415
+
416
+ return size;
417
+}
418
+
419
+/*
420
+ * Complete a previous send (backend --> guest) and enable the
421
+ * fd_read callback.
422
+ */
423
+static void af_xdp_send_completed(NetClientState *nc, ssize_t len)
424
+{
425
+ AFXDPState *s = DO_UPCAST(AFXDPState, nc, nc);
426
+
427
+ af_xdp_read_poll(s, true);
428
+}
429
+
430
+static void af_xdp_fq_refill(AFXDPState *s, uint32_t n)
431
+{
432
+ uint32_t i, idx = 0;
433
+
434
+ /* Leave one packet for Tx, just in case. */
435
+ if (s->n_pool < n + 1) {
436
+ n = s->n_pool;
437
+ }
438
+
439
+ if (!n || !xsk_ring_prod__reserve(&s->fq, n, &idx)) {
440
+ return;
441
+ }
442
+
443
+ for (i = 0; i < n; i++) {
444
+ *xsk_ring_prod__fill_addr(&s->fq, idx++) = s->pool[--s->n_pool];
445
+ }
446
+ xsk_ring_prod__submit(&s->fq, n);
447
+
448
+ if (xsk_ring_prod__needs_wakeup(&s->fq)) {
449
+ /* Receive was blocked by not having enough buffers. Wake it up. */
450
+ af_xdp_read_poll(s, true);
451
+ }
452
+}
453
+
454
+static void af_xdp_send(void *opaque)
455
+{
456
+ uint32_t i, n_rx, idx = 0;
457
+ AFXDPState *s = opaque;
458
+
459
+ n_rx = xsk_ring_cons__peek(&s->rx, AF_XDP_BATCH_SIZE, &idx);
460
+ if (!n_rx) {
461
+ return;
462
+ }
463
+
464
+ for (i = 0; i < n_rx; i++) {
465
+ const struct xdp_desc *desc;
466
+ struct iovec iov;
467
+
468
+ desc = xsk_ring_cons__rx_desc(&s->rx, idx++);
469
+
470
+ iov.iov_base = xsk_umem__get_data(s->buffer, desc->addr);
471
+ iov.iov_len = desc->len;
472
+
473
+ s->pool[s->n_pool++] = desc->addr;
474
+
475
+ if (!qemu_sendv_packet_async(&s->nc, &iov, 1,
476
+ af_xdp_send_completed)) {
477
+ /*
478
+ * The peer does not receive anymore. Packet is queued, stop
479
+ * reading from the backend until af_xdp_send_completed().
480
+ */
481
+ af_xdp_read_poll(s, false);
482
+
483
+ /* Return unused descriptors to not break the ring cache. */
484
+ xsk_ring_cons__cancel(&s->rx, n_rx - i - 1);
485
+ n_rx = i + 1;
486
+ break;
487
+ }
488
+ }
489
+
490
+ /* Release actually sent descriptors and try to re-fill. */
491
+ xsk_ring_cons__release(&s->rx, n_rx);
492
+ af_xdp_fq_refill(s, AF_XDP_BATCH_SIZE);
493
+}
494
+
495
+/* Flush and close. */
496
+static void af_xdp_cleanup(NetClientState *nc)
497
+{
498
+ AFXDPState *s = DO_UPCAST(AFXDPState, nc, nc);
499
+
500
+ qemu_purge_queued_packets(nc);
501
+
502
+ af_xdp_poll(nc, false);
503
+
504
+ xsk_socket__delete(s->xsk);
505
+ s->xsk = NULL;
506
+ g_free(s->pool);
507
+ s->pool = NULL;
508
+ xsk_umem__delete(s->umem);
509
+ s->umem = NULL;
510
+ qemu_vfree(s->buffer);
511
+ s->buffer = NULL;
512
+
513
+ /* Remove the program if it's the last open queue. */
514
+ if (!s->inhibit && nc->queue_index == s->n_queues - 1 && s->xdp_flags
515
+ && bpf_xdp_detach(s->ifindex, s->xdp_flags, NULL) != 0) {
516
+ fprintf(stderr,
517
+ "af-xdp: unable to remove XDP program from '%s', ifindex: %d\n",
518
+ s->ifname, s->ifindex);
519
+ }
520
+}
521
+
522
+static int af_xdp_umem_create(AFXDPState *s, int sock_fd, Error **errp)
523
+{
524
+ struct xsk_umem_config config = {
525
+ .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
526
+ .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS,
527
+ .frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE,
528
+ .frame_headroom = 0,
529
+ };
530
+ uint64_t n_descs;
531
+ uint64_t size;
532
+ int64_t i;
533
+ int ret;
534
+
535
+ /* Number of descriptors if all 4 queues (rx, tx, cq, fq) are full. */
536
+ n_descs = (XSK_RING_PROD__DEFAULT_NUM_DESCS
537
+ + XSK_RING_CONS__DEFAULT_NUM_DESCS) * 2;
538
+ size = n_descs * XSK_UMEM__DEFAULT_FRAME_SIZE;
539
+
540
+ s->buffer = qemu_memalign(qemu_real_host_page_size(), size);
541
+ memset(s->buffer, 0, size);
542
+
543
+ if (sock_fd < 0) {
544
+ ret = xsk_umem__create(&s->umem, s->buffer, size,
545
+ &s->fq, &s->cq, &config);
546
+ } else {
547
+ ret = xsk_umem__create_with_fd(&s->umem, sock_fd, s->buffer, size,
548
+ &s->fq, &s->cq, &config);
549
+ }
550
+
551
+ if (ret) {
552
+ qemu_vfree(s->buffer);
553
+ error_setg_errno(errp, errno,
554
+ "failed to create umem for %s queue_index: %d",
555
+ s->ifname, s->nc.queue_index);
556
+ return -1;
557
+ }
558
+
559
+ s->pool = g_new(uint64_t, n_descs);
560
+ /* Fill the pool in the opposite order, because it's a LIFO queue. */
561
+ for (i = n_descs; i >= 0; i--) {
562
+ s->pool[i] = i * XSK_UMEM__DEFAULT_FRAME_SIZE;
563
+ }
564
+ s->n_pool = n_descs;
565
+
566
+ af_xdp_fq_refill(s, XSK_RING_PROD__DEFAULT_NUM_DESCS);
567
+
568
+ return 0;
569
+}
570
+
571
+static int af_xdp_socket_create(AFXDPState *s,
572
+ const NetdevAFXDPOptions *opts, Error **errp)
573
+{
574
+ struct xsk_socket_config cfg = {
575
+ .rx_size = XSK_RING_CONS__DEFAULT_NUM_DESCS,
576
+ .tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
577
+ .libxdp_flags = 0,
578
+ .bind_flags = XDP_USE_NEED_WAKEUP,
579
+ .xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST,
580
+ };
581
+ int queue_id, error = 0;
582
+
583
+ s->inhibit = opts->has_inhibit && opts->inhibit;
584
+ if (s->inhibit) {
585
+ cfg.libxdp_flags |= XSK_LIBXDP_FLAGS__INHIBIT_PROG_LOAD;
586
+ }
587
+
588
+ if (opts->has_force_copy && opts->force_copy) {
589
+ cfg.bind_flags |= XDP_COPY;
590
+ }
591
+
592
+ queue_id = s->nc.queue_index;
593
+ if (opts->has_start_queue && opts->start_queue > 0) {
594
+ queue_id += opts->start_queue;
595
+ }
596
+
597
+ if (opts->has_mode) {
598
+ /* Specific mode requested. */
599
+ cfg.xdp_flags |= (opts->mode == AFXDP_MODE_NATIVE)
600
+ ? XDP_FLAGS_DRV_MODE : XDP_FLAGS_SKB_MODE;
601
+ if (xsk_socket__create(&s->xsk, s->ifname, queue_id,
602
+ s->umem, &s->rx, &s->tx, &cfg)) {
603
+ error = errno;
604
+ }
605
+ } else {
606
+ /* No mode requested, try native first. */
607
+ cfg.xdp_flags |= XDP_FLAGS_DRV_MODE;
608
+
609
+ if (xsk_socket__create(&s->xsk, s->ifname, queue_id,
610
+ s->umem, &s->rx, &s->tx, &cfg)) {
611
+ /* Can't use native mode, try skb. */
612
+ cfg.xdp_flags &= ~XDP_FLAGS_DRV_MODE;
613
+ cfg.xdp_flags |= XDP_FLAGS_SKB_MODE;
614
+
615
+ if (xsk_socket__create(&s->xsk, s->ifname, queue_id,
616
+ s->umem, &s->rx, &s->tx, &cfg)) {
617
+ error = errno;
618
+ }
619
+ }
620
+ }
621
+
622
+ if (error) {
623
+ error_setg_errno(errp, error,
624
+ "failed to create AF_XDP socket for %s queue_id: %d",
625
+ s->ifname, queue_id);
626
+ return -1;
627
+ }
628
+
629
+ s->xdp_flags = cfg.xdp_flags;
630
+
631
+ return 0;
632
+}
633
+
634
+/* NetClientInfo methods. */
635
+static NetClientInfo net_af_xdp_info = {
636
+ .type = NET_CLIENT_DRIVER_AF_XDP,
637
+ .size = sizeof(AFXDPState),
638
+ .receive = af_xdp_receive,
639
+ .poll = af_xdp_poll,
640
+ .cleanup = af_xdp_cleanup,
641
+};
642
+
643
+static int *parse_socket_fds(const char *sock_fds_str,
644
+ int64_t n_expected, Error **errp)
645
+{
646
+ gchar **substrings = g_strsplit(sock_fds_str, ":", -1);
647
+ int64_t i, n_sock_fds = g_strv_length(substrings);
648
+ int *sock_fds = NULL;
649
+
650
+ if (n_sock_fds != n_expected) {
651
+ error_setg(errp, "expected %"PRIi64" socket fds, got %"PRIi64,
652
+ n_expected, n_sock_fds);
653
+ goto exit;
654
+ }
655
+
656
+ sock_fds = g_new(int, n_sock_fds);
657
+
658
+ for (i = 0; i < n_sock_fds; i++) {
659
+ sock_fds[i] = monitor_fd_param(monitor_cur(), substrings[i], errp);
660
+ if (sock_fds[i] < 0) {
661
+ g_free(sock_fds);
662
+ sock_fds = NULL;
663
+ goto exit;
664
+ }
665
+ }
666
+
667
+exit:
668
+ g_strfreev(substrings);
669
+ return sock_fds;
670
+}
671
+
672
+/*
673
+ * The exported init function.
674
+ *
675
+ * ... -netdev af-xdp,ifname="..."
676
+ */
677
+int net_init_af_xdp(const Netdev *netdev,
678
+ const char *name, NetClientState *peer, Error **errp)
679
+{
680
+ const NetdevAFXDPOptions *opts = &netdev->u.af_xdp;
681
+ NetClientState *nc, *nc0 = NULL;
682
+ unsigned int ifindex;
683
+ uint32_t prog_id = 0;
684
+ int *sock_fds = NULL;
685
+ int64_t i, queues;
686
+ Error *err = NULL;
687
+ AFXDPState *s;
688
+
689
+ ifindex = if_nametoindex(opts->ifname);
690
+ if (!ifindex) {
691
+ error_setg_errno(errp, errno, "failed to get ifindex for '%s'",
692
+ opts->ifname);
693
+ return -1;
694
+ }
695
+
696
+ queues = opts->has_queues ? opts->queues : 1;
697
+ if (queues < 1) {
698
+ error_setg(errp, "invalid number of queues (%" PRIi64 ") for '%s'",
699
+ queues, opts->ifname);
700
+ return -1;
701
+ }
702
+
703
+ if ((opts->has_inhibit && opts->inhibit) != !!opts->sock_fds) {
704
+ error_setg(errp, "'inhibit=on' requires 'sock-fds' and vice versa");
705
+ return -1;
706
+ }
707
+
708
+ if (opts->sock_fds) {
709
+ sock_fds = parse_socket_fds(opts->sock_fds, queues, errp);
710
+ if (!sock_fds) {
711
+ return -1;
712
+ }
713
+ }
714
+
715
+ for (i = 0; i < queues; i++) {
716
+ nc = qemu_new_net_client(&net_af_xdp_info, peer, "af-xdp", name);
717
+ qemu_set_info_str(nc, "af-xdp%"PRIi64" to %s", i, opts->ifname);
718
+ nc->queue_index = i;
719
+
720
+ if (!nc0) {
721
+ nc0 = nc;
722
+ }
723
+
724
+ s = DO_UPCAST(AFXDPState, nc, nc);
725
+
726
+ pstrcpy(s->ifname, sizeof(s->ifname), opts->ifname);
727
+ s->ifindex = ifindex;
728
+ s->n_queues = queues;
729
+
730
+ if (af_xdp_umem_create(s, sock_fds ? sock_fds[i] : -1, errp)
731
+ || af_xdp_socket_create(s, opts, errp)) {
732
+ /* Make sure the XDP program will be removed. */
733
+ s->n_queues = i;
734
+ error_propagate(errp, err);
735
+ goto err;
736
+ }
737
+ }
738
+
739
+ if (nc0) {
740
+ s = DO_UPCAST(AFXDPState, nc, nc0);
741
+ if (bpf_xdp_query_id(s->ifindex, s->xdp_flags, &prog_id) || !prog_id) {
742
+ error_setg_errno(errp, errno,
743
+ "no XDP program loaded on '%s', ifindex: %d",
744
+ s->ifname, s->ifindex);
745
+ goto err;
746
+ }
747
+ }
748
+
749
+ af_xdp_read_poll(s, true); /* Initially only poll for reads. */
750
+
751
+ return 0;
752
+
753
+err:
754
+ g_free(sock_fds);
755
+ if (nc0) {
756
+ qemu_del_net_client(nc0);
757
+ }
758
+
759
+ return -1;
760
+}
761
diff --git a/net/clients.h b/net/clients.h
762
index XXXXXXX..XXXXXXX 100644
763
--- a/net/clients.h
764
+++ b/net/clients.h
765
@@ -XXX,XX +XXX,XX @@ int net_init_netmap(const Netdev *netdev, const char *name,
766
NetClientState *peer, Error **errp);
767
#endif
768
769
+#ifdef CONFIG_AF_XDP
770
+int net_init_af_xdp(const Netdev *netdev, const char *name,
771
+ NetClientState *peer, Error **errp);
772
+#endif
190
+#endif
773
+
774
int net_init_vhost_user(const Netdev *netdev, const char *name,
775
NetClientState *peer, Error **errp);
776
777
diff --git a/net/meson.build b/net/meson.build
778
index XXXXXXX..XXXXXXX 100644
779
--- a/net/meson.build
780
+++ b/net/meson.build
781
@@ -XXX,XX +XXX,XX @@ system_ss.add(when: vde, if_true: files('vde.c'))
782
if have_netmap
783
system_ss.add(files('netmap.c'))
784
endif
785
+
786
+system_ss.add(when: libxdp, if_true: files('af-xdp.c'))
787
+
788
if have_vhost_net_user
789
system_ss.add(when: 'CONFIG_VIRTIO_NET', if_true: files('vhost-user.c'), if_false: files('vhost-user-stub.c'))
790
system_ss.add(when: 'CONFIG_ALL', if_true: files('vhost-user-stub.c'))
791
diff --git a/net/net.c b/net/net.c
792
index XXXXXXX..XXXXXXX 100644
793
--- a/net/net.c
794
+++ b/net/net.c
795
@@ -XXX,XX +XXX,XX @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
796
#ifdef CONFIG_NETMAP
797
[NET_CLIENT_DRIVER_NETMAP] = net_init_netmap,
798
#endif
799
+#ifdef CONFIG_AF_XDP
800
+ [NET_CLIENT_DRIVER_AF_XDP] = net_init_af_xdp,
801
+#endif
802
#ifdef CONFIG_NET_BRIDGE
803
[NET_CLIENT_DRIVER_BRIDGE] = net_init_bridge,
804
#endif
805
@@ -XXX,XX +XXX,XX @@ void show_netdevs(void)
806
#ifdef CONFIG_NETMAP
807
"netmap",
808
#endif
809
+#ifdef CONFIG_AF_XDP
810
+ "af-xdp",
811
+#endif
812
#ifdef CONFIG_POSIX
813
"vhost-user",
814
#endif
815
diff --git a/qapi/net.json b/qapi/net.json
816
index XXXXXXX..XXXXXXX 100644
817
--- a/qapi/net.json
818
+++ b/qapi/net.json
819
@@ -XXX,XX +XXX,XX @@
820
'*devname': 'str' } }
821
822
##
823
+# @AFXDPMode:
824
+#
825
+# Attach mode for a default XDP program
826
+#
827
+# @skb: generic mode, no driver support necessary
828
+#
829
+# @native: DRV mode, program is attached to a driver, packets are passed to
830
+# the socket without allocation of skb.
831
+#
832
+# Since: 8.2
833
+##
834
+{ 'enum': 'AFXDPMode',
835
+ 'data': [ 'native', 'skb' ],
836
+ 'if': 'CONFIG_AF_XDP' }
837
+
838
+##
839
+# @NetdevAFXDPOptions:
840
+#
841
+# AF_XDP network backend
842
+#
843
+# @ifname: The name of an existing network interface.
844
+#
845
+# @mode: Attach mode for a default XDP program. If not specified, then
846
+# 'native' will be tried first, then 'skb'.
847
+#
848
+# @force-copy: Force XDP copy mode even if device supports zero-copy.
849
+# (default: false)
850
+#
851
+# @queues: number of queues to be used for multiqueue interfaces (default: 1).
852
+#
853
+# @start-queue: Use @queues starting from this queue number (default: 0).
854
+#
855
+# @inhibit: Don't load a default XDP program, use one already loaded to
856
+# the interface (default: false). Requires @sock-fds.
857
+#
858
+# @sock-fds: A colon (:) separated list of file descriptors for already open
859
+# but not bound AF_XDP sockets in the queue order. One fd per queue.
860
+# These descriptors should already be added into XDP socket map for
861
+# corresponding queues. Requires @inhibit.
862
+#
863
+# Since: 8.2
864
+##
865
+{ 'struct': 'NetdevAFXDPOptions',
866
+ 'data': {
867
+ 'ifname': 'str',
868
+ '*mode': 'AFXDPMode',
869
+ '*force-copy': 'bool',
870
+ '*queues': 'int',
871
+ '*start-queue': 'int',
872
+ '*inhibit': 'bool',
873
+ '*sock-fds': 'str' },
874
+ 'if': 'CONFIG_AF_XDP' }
875
+
876
+##
877
# @NetdevVhostUserOptions:
878
#
879
# Vhost-user network backend
880
@@ -XXX,XX +XXX,XX @@
881
# @vmnet-bridged: since 7.1
882
# @stream: since 7.2
883
# @dgram: since 7.2
884
+# @af-xdp: since 8.2
885
#
886
# Since: 2.7
887
##
888
@@ -XXX,XX +XXX,XX @@
889
'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'stream',
890
'dgram', 'vde', 'bridge', 'hubport', 'netmap', 'vhost-user',
891
'vhost-vdpa',
892
+ { 'name': 'af-xdp', 'if': 'CONFIG_AF_XDP' },
893
{ 'name': 'vmnet-host', 'if': 'CONFIG_VMNET' },
894
{ 'name': 'vmnet-shared', 'if': 'CONFIG_VMNET' },
895
{ 'name': 'vmnet-bridged', 'if': 'CONFIG_VMNET' }] }
896
@@ -XXX,XX +XXX,XX @@
897
'bridge': 'NetdevBridgeOptions',
898
'hubport': 'NetdevHubPortOptions',
899
'netmap': 'NetdevNetmapOptions',
900
+ 'af-xdp': { 'type': 'NetdevAFXDPOptions',
901
+ 'if': 'CONFIG_AF_XDP' },
902
'vhost-user': 'NetdevVhostUserOptions',
903
'vhost-vdpa': 'NetdevVhostVDPAOptions',
904
'vmnet-host': { 'type': 'NetdevVmnetHostOptions',
905
diff --git a/qemu-options.hx b/qemu-options.hx
906
index XXXXXXX..XXXXXXX 100644
907
--- a/qemu-options.hx
908
+++ b/qemu-options.hx
909
@@ -XXX,XX +XXX,XX @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
910
" VALE port (created on the fly) called 'name' ('nmname' is name of the \n"
911
" netmap device, defaults to '/dev/netmap')\n"
912
#endif
913
+#ifdef CONFIG_AF_XDP
914
+ "-netdev af-xdp,id=str,ifname=name[,mode=native|skb][,force-copy=on|off]\n"
915
+ " [,queues=n][,start-queue=m][,inhibit=on|off][,sock-fds=x:y:...:z]\n"
916
+ " attach to the existing network interface 'name' with AF_XDP socket\n"
917
+ " use 'mode=MODE' to specify an XDP program attach mode\n"
918
+ " use 'force-copy=on|off' to force XDP copy mode even if device supports zero-copy (default: off)\n"
919
+ " use 'inhibit=on|off' to inhibit loading of a default XDP program (default: off)\n"
920
+ " with inhibit=on,\n"
921
+ " use 'sock-fds' to provide file descriptors for already open AF_XDP sockets\n"
922
+ " added to a socket map in XDP program. One socket per queue.\n"
923
+ " use 'queues=n' to specify how many queues of a multiqueue interface should be used\n"
924
+ " use 'start-queue=m' to specify the first queue that should be used\n"
925
+#endif
926
#ifdef CONFIG_POSIX
927
"-netdev vhost-user,id=str,chardev=dev[,vhostforce=on|off]\n"
928
" configure a vhost-user network, backed by a chardev 'dev'\n"
929
@@ -XXX,XX +XXX,XX @@ DEF("nic", HAS_ARG, QEMU_OPTION_nic,
930
#ifdef CONFIG_NETMAP
931
"netmap|"
932
#endif
933
+#ifdef CONFIG_AF_XDP
934
+ "af-xdp|"
935
+#endif
936
#ifdef CONFIG_POSIX
937
"vhost-user|"
938
#endif
939
@@ -XXX,XX +XXX,XX @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
940
#ifdef CONFIG_NETMAP
941
"netmap|"
942
#endif
943
+#ifdef CONFIG_AF_XDP
944
+ "af-xdp|"
945
+#endif
946
#ifdef CONFIG_VMNET
947
"vmnet-host|vmnet-shared|vmnet-bridged|"
948
#endif
949
@@ -XXX,XX +XXX,XX @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
950
" old way to initialize a host network interface\n"
951
" (use the -netdev option if possible instead)\n", QEMU_ARCH_ALL)
952
SRST
953
-``-nic [tap|bridge|user|l2tpv3|vde|netmap|vhost-user|socket][,...][,mac=macaddr][,model=mn]``
954
+``-nic [tap|bridge|user|l2tpv3|vde|netmap|af-xdp|vhost-user|socket][,...][,mac=macaddr][,model=mn]``
955
This option is a shortcut for configuring both the on-board
956
(default) guest NIC hardware and the host network backend in one go.
957
The host backend options are the same as with the corresponding
958
@@ -XXX,XX +XXX,XX @@ SRST
959
# launch QEMU instance
960
|qemu_system| linux.img -nic vde,sock=/tmp/myswitch
961
962
+``-netdev af-xdp,id=str,ifname=name[,mode=native|skb][,force-copy=on|off][,queues=n][,start-queue=m][,inhibit=on|off][,sock-fds=x:y:...:z]``
963
+ Configure AF_XDP backend to connect to a network interface 'name'
964
+ using AF_XDP socket. A specific program attach mode for a default
965
+ XDP program can be forced with 'mode', defaults to best-effort,
966
+ where the likely most performant mode will be in use. Number of queues
967
+ 'n' should generally match the number or queues in the interface,
968
+ defaults to 1. Traffic arriving on non-configured device queues will
969
+ not be delivered to the network backend.
970
+
971
+ .. parsed-literal::
972
+
973
+ # set number of queues to 4
974
+ ethtool -L eth0 combined 4
975
+ # launch QEMU instance
976
+ |qemu_system| linux.img -device virtio-net-pci,netdev=n1 \\
977
+ -netdev af-xdp,id=n1,ifname=eth0,queues=4
978
+
979
+ 'start-queue' option can be specified if a particular range of queues
980
+ [m, m + n] should be in use. For example, this is may be necessary in
981
+ order to use certain NICs in native mode. Kernel allows the driver to
982
+ create a separate set of XDP queues on top of regular ones, and only
983
+ these queues can be used for AF_XDP sockets. NICs that work this way
984
+ may also require an additional traffic redirection with ethtool to these
985
+ special queues.
986
+
987
+ .. parsed-literal::
988
+
989
+ # set number of queues to 1
990
+ ethtool -L eth0 combined 1
991
+ # redirect all the traffic to the second queue (id: 1)
992
+ # note: drivers may require non-empty key/mask pair.
993
+ ethtool -N eth0 flow-type ether \\
994
+ dst 00:00:00:00:00:00 m FF:FF:FF:FF:FF:FE action 1
995
+ ethtool -N eth0 flow-type ether \\
996
+ dst 00:00:00:00:00:01 m FF:FF:FF:FF:FF:FE action 1
997
+ # launch QEMU instance
998
+ |qemu_system| linux.img -device virtio-net-pci,netdev=n1 \\
999
+ -netdev af-xdp,id=n1,ifname=eth0,queues=1,start-queue=1
1000
+
1001
+ XDP program can also be loaded externally. In this case 'inhibit' option
1002
+ should be set to 'on' and 'sock-fds' provided with file descriptors for
1003
+ already open but not bound XDP sockets already added to a socket map for
1004
+ corresponding queues. One socket per queue.
1005
+
1006
+ .. parsed-literal::
1007
+
1008
+ |qemu_system| linux.img -device virtio-net-pci,netdev=n1 \\
1009
+ -netdev af-xdp,id=n1,ifname=eth0,queues=3,inhibit=on,sock-fds=15:16:17
1010
+
1011
``-netdev vhost-user,chardev=id[,vhostforce=on|off][,queues=n]``
1012
Establish a vhost-user netdev, backed by a chardev id. The chardev
1013
should be a unix domain socket backed one. The vhost-user uses a
1014
diff --git a/scripts/ci/org.centos/stream/8/x86_64/configure b/scripts/ci/org.centos/stream/8/x86_64/configure
1015
index XXXXXXX..XXXXXXX 100755
1016
--- a/scripts/ci/org.centos/stream/8/x86_64/configure
1017
+++ b/scripts/ci/org.centos/stream/8/x86_64/configure
1018
@@ -XXX,XX +XXX,XX @@
1019
--block-drv-ro-whitelist="vmdk,vhdx,vpc,https,ssh" \
1020
--with-coroutine=ucontext \
1021
--tls-priority=@QEMU,SYSTEM \
1022
+--disable-af-xdp \
1023
--disable-attr \
1024
--disable-auth-pam \
1025
--disable-avx2 \
1026
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
1027
index XXXXXXX..XXXXXXX 100644
1028
--- a/scripts/meson-buildoptions.sh
1029
+++ b/scripts/meson-buildoptions.sh
1030
@@ -XXX,XX +XXX,XX @@ meson_options_help() {
1031
printf "%s\n" 'disabled with --disable-FEATURE, default is enabled if available'
1032
printf "%s\n" '(unless built with --without-default-features):'
1033
printf "%s\n" ''
1034
+ printf "%s\n" ' af-xdp AF_XDP network backend support'
1035
printf "%s\n" ' alsa ALSA sound support'
1036
printf "%s\n" ' attr attr/xattr support'
1037
printf "%s\n" ' auth-pam PAM access control'
1038
@@ -XXX,XX +XXX,XX @@ meson_options_help() {
1039
}
1040
_meson_option_parse() {
1041
case $1 in
1042
+ --enable-af-xdp) printf "%s" -Daf_xdp=enabled ;;
1043
+ --disable-af-xdp) printf "%s" -Daf_xdp=disabled ;;
1044
--enable-alsa) printf "%s" -Dalsa=enabled ;;
1045
--disable-alsa) printf "%s" -Dalsa=disabled ;;
1046
--enable-attr) printf "%s" -Dattr=enabled ;;
1047
diff --git a/tests/docker/dockerfiles/debian-amd64.docker b/tests/docker/dockerfiles/debian-amd64.docker
1048
index XXXXXXX..XXXXXXX 100644
1049
--- a/tests/docker/dockerfiles/debian-amd64.docker
1050
+++ b/tests/docker/dockerfiles/debian-amd64.docker
1051
@@ -XXX,XX +XXX,XX @@ RUN export DEBIAN_FRONTEND=noninteractive && \
1052
libvirglrenderer-dev \
1053
libvte-2.91-dev \
1054
libxen-dev \
1055
+ libxdp-dev \
1056
libzstd-dev \
1057
llvm \
1058
locales \
1059
--
191
--
1060
2.7.4
192
2.7.4
193
194
diff view generated by jsdifflib
1
From: Tomasz Dzieciol <t.dzieciol@partner.samsung.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Rename E1000E_RingInfo_st and E1000E_RingInfo according to qemu typdefs guide.
3
Use translations added in VhostIOVATree in SVQ.
4
4
5
Signed-off-by: Tomasz Dzieciol <t.dzieciol@partner.samsung.com>
5
Only introduce usage here, not allocation and deallocation. As with
6
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
6
previous patches, we use the dead code paths of shadow_vqs_enabled to
7
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
7
avoid commiting too many changes at once. These are impossible to take
8
at the moment.
9
10
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
11
Acked-by: Michael S. Tsirkin <mst@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
13
---
10
hw/net/e1000e_core.c | 34 +++++++++++++++++-----------------
14
hw/virtio/vhost-shadow-virtqueue.c | 86 +++++++++++++++++++++++---
11
hw/net/igb_core.c | 42 +++++++++++++++++++++---------------------
15
hw/virtio/vhost-shadow-virtqueue.h | 6 +-
12
2 files changed, 38 insertions(+), 38 deletions(-)
16
hw/virtio/vhost-vdpa.c | 122 +++++++++++++++++++++++++++++++------
13
17
include/hw/virtio/vhost-vdpa.h | 3 +
14
diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
18
4 files changed, 187 insertions(+), 30 deletions(-)
19
20
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
15
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/net/e1000e_core.c
22
--- a/hw/virtio/vhost-shadow-virtqueue.c
17
+++ b/hw/net/e1000e_core.c
23
+++ b/hw/virtio/vhost-shadow-virtqueue.c
18
@@ -XXX,XX +XXX,XX @@ e1000e_txdesc_writeback(E1000ECore *core, dma_addr_t base,
24
@@ -XXX,XX +XXX,XX @@ static uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq)
19
return e1000e_tx_wb_interrupt_cause(core, queue_idx);
25
return svq->vring.num - (svq->shadow_avail_idx - svq->shadow_used_idx);
20
}
26
}
21
27
22
-typedef struct E1000E_RingInfo_st {
28
-static void vhost_vring_write_descs(VhostShadowVirtqueue *svq,
23
+typedef struct E1000ERingInfo {
29
+/**
24
int dbah;
30
+ * Translate addresses between the qemu's virtual address and the SVQ IOVA
25
int dbal;
31
+ *
26
int dlen;
32
+ * @svq: Shadow VirtQueue
27
int dh;
33
+ * @vaddr: Translated IOVA addresses
28
int dt;
34
+ * @iovec: Source qemu's VA addresses
29
int idx;
35
+ * @num: Length of iovec and minimum length of vaddr
30
-} E1000E_RingInfo;
36
+ */
31
+} E1000ERingInfo;
37
+static bool vhost_svq_translate_addr(const VhostShadowVirtqueue *svq,
32
38
+ hwaddr *addrs, const struct iovec *iovec,
33
static inline bool
39
+ size_t num)
34
-e1000e_ring_empty(E1000ECore *core, const E1000E_RingInfo *r)
40
+{
35
+e1000e_ring_empty(E1000ECore *core, const E1000ERingInfo *r)
41
+ if (num == 0) {
36
{
42
+ return true;
37
return core->mac[r->dh] == core->mac[r->dt] ||
43
+ }
38
core->mac[r->dt] >= core->mac[r->dlen] / E1000_RING_DESC_LEN;
44
+
45
+ for (size_t i = 0; i < num; ++i) {
46
+ DMAMap needle = {
47
+ .translated_addr = (hwaddr)(uintptr_t)iovec[i].iov_base,
48
+ .size = iovec[i].iov_len,
49
+ };
50
+ Int128 needle_last, map_last;
51
+ size_t off;
52
+
53
+ const DMAMap *map = vhost_iova_tree_find_iova(svq->iova_tree, &needle);
54
+ /*
55
+ * Map cannot be NULL since iova map contains all guest space and
56
+ * qemu already has a physical address mapped
57
+ */
58
+ if (unlikely(!map)) {
59
+ qemu_log_mask(LOG_GUEST_ERROR,
60
+ "Invalid address 0x%"HWADDR_PRIx" given by guest",
61
+ needle.translated_addr);
62
+ return false;
63
+ }
64
+
65
+ off = needle.translated_addr - map->translated_addr;
66
+ addrs[i] = map->iova + off;
67
+
68
+ needle_last = int128_add(int128_make64(needle.translated_addr),
69
+ int128_make64(iovec[i].iov_len));
70
+ map_last = int128_make64(map->translated_addr + map->size);
71
+ if (unlikely(int128_gt(needle_last, map_last))) {
72
+ qemu_log_mask(LOG_GUEST_ERROR,
73
+ "Guest buffer expands over iova range");
74
+ return false;
75
+ }
76
+ }
77
+
78
+ return true;
79
+}
80
+
81
+static void vhost_vring_write_descs(VhostShadowVirtqueue *svq, hwaddr *sg,
82
const struct iovec *iovec, size_t num,
83
bool more_descs, bool write)
84
{
85
@@ -XXX,XX +XXX,XX @@ static void vhost_vring_write_descs(VhostShadowVirtqueue *svq,
86
} else {
87
descs[i].flags = flags;
88
}
89
- descs[i].addr = cpu_to_le64((hwaddr)(intptr_t)iovec[n].iov_base);
90
+ descs[i].addr = cpu_to_le64(sg[n]);
91
descs[i].len = cpu_to_le32(iovec[n].iov_len);
92
93
last = i;
94
@@ -XXX,XX +XXX,XX @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq,
95
{
96
unsigned avail_idx;
97
vring_avail_t *avail = svq->vring.avail;
98
+ bool ok;
99
+ g_autofree hwaddr *sgs = g_new(hwaddr, MAX(elem->out_num, elem->in_num));
100
101
*head = svq->free_head;
102
103
@@ -XXX,XX +XXX,XX @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq,
104
return false;
105
}
106
107
- vhost_vring_write_descs(svq, elem->out_sg, elem->out_num, elem->in_num > 0,
108
- false);
109
- vhost_vring_write_descs(svq, elem->in_sg, elem->in_num, false, true);
110
+ ok = vhost_svq_translate_addr(svq, sgs, elem->out_sg, elem->out_num);
111
+ if (unlikely(!ok)) {
112
+ return false;
113
+ }
114
+ vhost_vring_write_descs(svq, sgs, elem->out_sg, elem->out_num,
115
+ elem->in_num > 0, false);
116
+
117
+
118
+ ok = vhost_svq_translate_addr(svq, sgs, elem->in_sg, elem->in_num);
119
+ if (unlikely(!ok)) {
120
+ return false;
121
+ }
122
+
123
+ vhost_vring_write_descs(svq, sgs, elem->in_sg, elem->in_num, false, true);
124
125
/*
126
* Put the entry in the available array (but don't update avail->idx until
127
@@ -XXX,XX +XXX,XX @@ void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd)
128
void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq,
129
struct vhost_vring_addr *addr)
130
{
131
- addr->desc_user_addr = (uint64_t)(intptr_t)svq->vring.desc;
132
- addr->avail_user_addr = (uint64_t)(intptr_t)svq->vring.avail;
133
- addr->used_user_addr = (uint64_t)(intptr_t)svq->vring.used;
134
+ addr->desc_user_addr = (uint64_t)(uintptr_t)svq->vring.desc;
135
+ addr->avail_user_addr = (uint64_t)(uintptr_t)svq->vring.avail;
136
+ addr->used_user_addr = (uint64_t)(uintptr_t)svq->vring.used;
39
}
137
}
40
138
41
static inline uint64_t
139
size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq)
42
-e1000e_ring_base(E1000ECore *core, const E1000E_RingInfo *r)
140
@@ -XXX,XX +XXX,XX @@ void vhost_svq_stop(VhostShadowVirtqueue *svq)
43
+e1000e_ring_base(E1000ECore *core, const E1000ERingInfo *r)
141
* Creates vhost shadow virtqueue, and instructs the vhost device to use the
44
{
142
* shadow methods and file descriptors.
45
uint64_t bah = core->mac[r->dbah];
143
*
46
uint64_t bal = core->mac[r->dbal];
144
+ * @iova_tree: Tree to perform descriptors translations
47
@@ -XXX,XX +XXX,XX @@ e1000e_ring_base(E1000ECore *core, const E1000E_RingInfo *r)
145
+ *
146
* Returns the new virtqueue or NULL.
147
*
148
* In case of error, reason is reported through error_report.
149
*/
150
-VhostShadowVirtqueue *vhost_svq_new(void)
151
+VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree)
152
{
153
g_autofree VhostShadowVirtqueue *svq = g_new0(VhostShadowVirtqueue, 1);
154
int r;
155
@@ -XXX,XX +XXX,XX @@ VhostShadowVirtqueue *vhost_svq_new(void)
156
157
event_notifier_init_fd(&svq->svq_kick, VHOST_FILE_UNBIND);
158
event_notifier_set_handler(&svq->hdev_call, vhost_svq_handle_call);
159
+ svq->iova_tree = iova_tree;
160
return g_steal_pointer(&svq);
161
162
err_init_hdev_call:
163
diff --git a/hw/virtio/vhost-shadow-virtqueue.h b/hw/virtio/vhost-shadow-virtqueue.h
164
index XXXXXXX..XXXXXXX 100644
165
--- a/hw/virtio/vhost-shadow-virtqueue.h
166
+++ b/hw/virtio/vhost-shadow-virtqueue.h
167
@@ -XXX,XX +XXX,XX @@
168
#include "qemu/event_notifier.h"
169
#include "hw/virtio/virtio.h"
170
#include "standard-headers/linux/vhost_types.h"
171
+#include "hw/virtio/vhost-iova-tree.h"
172
173
/* Shadow virtqueue to relay notifications */
174
typedef struct VhostShadowVirtqueue {
175
@@ -XXX,XX +XXX,XX @@ typedef struct VhostShadowVirtqueue {
176
/* Virtio device */
177
VirtIODevice *vdev;
178
179
+ /* IOVA mapping */
180
+ VhostIOVATree *iova_tree;
181
+
182
/* Map for use the guest's descriptors */
183
VirtQueueElement **ring_id_maps;
184
185
@@ -XXX,XX +XXX,XX @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev,
186
VirtQueue *vq);
187
void vhost_svq_stop(VhostShadowVirtqueue *svq);
188
189
-VhostShadowVirtqueue *vhost_svq_new(void);
190
+VhostShadowVirtqueue *vhost_svq_new(VhostIOVATree *iova_tree);
191
192
void vhost_svq_free(gpointer vq);
193
G_DEFINE_AUTOPTR_CLEANUP_FUNC(VhostShadowVirtqueue, vhost_svq_free);
194
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
195
index XXXXXXX..XXXXXXX 100644
196
--- a/hw/virtio/vhost-vdpa.c
197
+++ b/hw/virtio/vhost-vdpa.c
198
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_listener_region_add(MemoryListener *listener,
199
vaddr, section->readonly);
200
201
llsize = int128_sub(llend, int128_make64(iova));
202
+ if (v->shadow_vqs_enabled) {
203
+ DMAMap mem_region = {
204
+ .translated_addr = (hwaddr)(uintptr_t)vaddr,
205
+ .size = int128_get64(llsize) - 1,
206
+ .perm = IOMMU_ACCESS_FLAG(true, section->readonly),
207
+ };
208
+
209
+ int r = vhost_iova_tree_map_alloc(v->iova_tree, &mem_region);
210
+ if (unlikely(r != IOVA_OK)) {
211
+ error_report("Can't allocate a mapping (%d)", r);
212
+ goto fail;
213
+ }
214
+
215
+ iova = mem_region.iova;
216
+ }
217
218
vhost_vdpa_iotlb_batch_begin_once(v);
219
ret = vhost_vdpa_dma_map(v, iova, int128_get64(llsize),
220
@@ -XXX,XX +XXX,XX @@ static void vhost_vdpa_listener_region_del(MemoryListener *listener,
221
222
llsize = int128_sub(llend, int128_make64(iova));
223
224
+ if (v->shadow_vqs_enabled) {
225
+ const DMAMap *result;
226
+ const void *vaddr = memory_region_get_ram_ptr(section->mr) +
227
+ section->offset_within_region +
228
+ (iova - section->offset_within_address_space);
229
+ DMAMap mem_region = {
230
+ .translated_addr = (hwaddr)(uintptr_t)vaddr,
231
+ .size = int128_get64(llsize) - 1,
232
+ };
233
+
234
+ result = vhost_iova_tree_find_iova(v->iova_tree, &mem_region);
235
+ iova = result->iova;
236
+ vhost_iova_tree_remove(v->iova_tree, &mem_region);
237
+ }
238
vhost_vdpa_iotlb_batch_begin_once(v);
239
ret = vhost_vdpa_dma_unmap(v, iova, int128_get64(llsize));
240
if (ret) {
241
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v,
242
243
shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free);
244
for (unsigned n = 0; n < hdev->nvqs; ++n) {
245
- g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new();
246
+ g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new(v->iova_tree);
247
248
if (unlikely(!svq)) {
249
error_setg(errp, "Cannot create svq %u", n);
250
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_svq_set_fds(struct vhost_dev *dev,
251
/**
252
* Unmap a SVQ area in the device
253
*/
254
-static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v, hwaddr iova,
255
- hwaddr size)
256
+static bool vhost_vdpa_svq_unmap_ring(struct vhost_vdpa *v,
257
+ const DMAMap *needle)
258
{
259
+ const DMAMap *result = vhost_iova_tree_find_iova(v->iova_tree, needle);
260
+ hwaddr size;
261
int r;
262
263
- size = ROUND_UP(size, qemu_real_host_page_size);
264
- r = vhost_vdpa_dma_unmap(v, iova, size);
265
+ if (unlikely(!result)) {
266
+ error_report("Unable to find SVQ address to unmap");
267
+ return false;
268
+ }
269
+
270
+ size = ROUND_UP(result->size, qemu_real_host_page_size);
271
+ r = vhost_vdpa_dma_unmap(v, result->iova, size);
272
return r == 0;
48
}
273
}
49
274
50
static inline uint64_t
275
static bool vhost_vdpa_svq_unmap_rings(struct vhost_dev *dev,
51
-e1000e_ring_head_descr(E1000ECore *core, const E1000E_RingInfo *r)
276
const VhostShadowVirtqueue *svq)
52
+e1000e_ring_head_descr(E1000ECore *core, const E1000ERingInfo *r)
277
{
53
{
278
+ DMAMap needle = {};
54
return e1000e_ring_base(core, r) + E1000_RING_DESC_LEN * core->mac[r->dh];
279
struct vhost_vdpa *v = dev->opaque;
280
struct vhost_vring_addr svq_addr;
281
- size_t device_size = vhost_svq_device_area_size(svq);
282
- size_t driver_size = vhost_svq_driver_area_size(svq);
283
bool ok;
284
285
vhost_svq_get_vring_addr(svq, &svq_addr);
286
287
- ok = vhost_vdpa_svq_unmap_ring(v, svq_addr.desc_user_addr, driver_size);
288
+ needle.translated_addr = svq_addr.desc_user_addr;
289
+ ok = vhost_vdpa_svq_unmap_ring(v, &needle);
290
if (unlikely(!ok)) {
291
return false;
292
}
293
294
- return vhost_vdpa_svq_unmap_ring(v, svq_addr.used_user_addr, device_size);
295
+ needle.translated_addr = svq_addr.used_user_addr;
296
+ return vhost_vdpa_svq_unmap_ring(v, &needle);
297
+}
298
+
299
+/**
300
+ * Map the SVQ area in the device
301
+ *
302
+ * @v: Vhost-vdpa device
303
+ * @needle: The area to search iova
304
+ * @errorp: Error pointer
305
+ */
306
+static bool vhost_vdpa_svq_map_ring(struct vhost_vdpa *v, DMAMap *needle,
307
+ Error **errp)
308
+{
309
+ int r;
310
+
311
+ r = vhost_iova_tree_map_alloc(v->iova_tree, needle);
312
+ if (unlikely(r != IOVA_OK)) {
313
+ error_setg(errp, "Cannot allocate iova (%d)", r);
314
+ return false;
315
+ }
316
+
317
+ r = vhost_vdpa_dma_map(v, needle->iova, needle->size + 1,
318
+ (void *)(uintptr_t)needle->translated_addr,
319
+ needle->perm == IOMMU_RO);
320
+ if (unlikely(r != 0)) {
321
+ error_setg_errno(errp, -r, "Cannot map region to device");
322
+ vhost_iova_tree_remove(v->iova_tree, needle);
323
+ }
324
+
325
+ return r == 0;
55
}
326
}
56
327
57
static inline void
328
/**
58
-e1000e_ring_advance(E1000ECore *core, const E1000E_RingInfo *r, uint32_t count)
329
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_svq_map_rings(struct vhost_dev *dev,
59
+e1000e_ring_advance(E1000ECore *core, const E1000ERingInfo *r, uint32_t count)
330
struct vhost_vring_addr *addr,
60
{
331
Error **errp)
61
core->mac[r->dh] += count;
332
{
62
333
+ DMAMap device_region, driver_region;
63
@@ -XXX,XX +XXX,XX @@ e1000e_ring_advance(E1000ECore *core, const E1000E_RingInfo *r, uint32_t count)
334
+ struct vhost_vring_addr svq_addr;
335
struct vhost_vdpa *v = dev->opaque;
336
size_t device_size = vhost_svq_device_area_size(svq);
337
size_t driver_size = vhost_svq_driver_area_size(svq);
338
- int r;
339
+ size_t avail_offset;
340
+ bool ok;
341
342
ERRP_GUARD();
343
- vhost_svq_get_vring_addr(svq, addr);
344
+ vhost_svq_get_vring_addr(svq, &svq_addr);
345
346
- r = vhost_vdpa_dma_map(v, addr->desc_user_addr, driver_size,
347
- (void *)(uintptr_t)addr->desc_user_addr, true);
348
- if (unlikely(r != 0)) {
349
- error_setg_errno(errp, -r, "Cannot create vq driver region: ");
350
+ driver_region = (DMAMap) {
351
+ .translated_addr = svq_addr.desc_user_addr,
352
+ .size = driver_size - 1,
353
+ .perm = IOMMU_RO,
354
+ };
355
+ ok = vhost_vdpa_svq_map_ring(v, &driver_region, errp);
356
+ if (unlikely(!ok)) {
357
+ error_prepend(errp, "Cannot create vq driver region: ");
358
return false;
359
}
360
+ addr->desc_user_addr = driver_region.iova;
361
+ avail_offset = svq_addr.avail_user_addr - svq_addr.desc_user_addr;
362
+ addr->avail_user_addr = driver_region.iova + avail_offset;
363
364
- r = vhost_vdpa_dma_map(v, addr->used_user_addr, device_size,
365
- (void *)(intptr_t)addr->used_user_addr, false);
366
- if (unlikely(r != 0)) {
367
- error_setg_errno(errp, -r, "Cannot create vq device region: ");
368
+ device_region = (DMAMap) {
369
+ .translated_addr = svq_addr.used_user_addr,
370
+ .size = device_size - 1,
371
+ .perm = IOMMU_RW,
372
+ };
373
+ ok = vhost_vdpa_svq_map_ring(v, &device_region, errp);
374
+ if (unlikely(!ok)) {
375
+ error_prepend(errp, "Cannot create vq device region: ");
376
+ vhost_vdpa_svq_unmap_ring(v, &driver_region);
377
}
378
+ addr->used_user_addr = device_region.iova;
379
380
- return r == 0;
381
+ return ok;
64
}
382
}
65
383
66
static inline uint32_t
384
static bool vhost_vdpa_svq_setup(struct vhost_dev *dev,
67
-e1000e_ring_free_descr_num(E1000ECore *core, const E1000E_RingInfo *r)
385
diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h
68
+e1000e_ring_free_descr_num(E1000ECore *core, const E1000ERingInfo *r)
69
{
70
trace_e1000e_ring_free_space(r->idx, core->mac[r->dlen],
71
core->mac[r->dh], core->mac[r->dt]);
72
@@ -XXX,XX +XXX,XX @@ e1000e_ring_free_descr_num(E1000ECore *core, const E1000E_RingInfo *r)
73
}
74
75
static inline bool
76
-e1000e_ring_enabled(E1000ECore *core, const E1000E_RingInfo *r)
77
+e1000e_ring_enabled(E1000ECore *core, const E1000ERingInfo *r)
78
{
79
return core->mac[r->dlen] > 0;
80
}
81
82
static inline uint32_t
83
-e1000e_ring_len(E1000ECore *core, const E1000E_RingInfo *r)
84
+e1000e_ring_len(E1000ECore *core, const E1000ERingInfo *r)
85
{
86
return core->mac[r->dlen];
87
}
88
89
typedef struct E1000E_TxRing_st {
90
- const E1000E_RingInfo *i;
91
+ const E1000ERingInfo *i;
92
struct e1000e_tx *tx;
93
} E1000E_TxRing;
94
95
@@ -XXX,XX +XXX,XX @@ e1000e_mq_queue_idx(int base_reg_idx, int reg_idx)
96
static inline void
97
e1000e_tx_ring_init(E1000ECore *core, E1000E_TxRing *txr, int idx)
98
{
99
- static const E1000E_RingInfo i[E1000E_NUM_QUEUES] = {
100
+ static const E1000ERingInfo i[E1000E_NUM_QUEUES] = {
101
{ TDBAH, TDBAL, TDLEN, TDH, TDT, 0 },
102
{ TDBAH1, TDBAL1, TDLEN1, TDH1, TDT1, 1 }
103
};
104
@@ -XXX,XX +XXX,XX @@ e1000e_tx_ring_init(E1000ECore *core, E1000E_TxRing *txr, int idx)
105
}
106
107
typedef struct E1000E_RxRing_st {
108
- const E1000E_RingInfo *i;
109
+ const E1000ERingInfo *i;
110
} E1000E_RxRing;
111
112
static inline void
113
e1000e_rx_ring_init(E1000ECore *core, E1000E_RxRing *rxr, int idx)
114
{
115
- static const E1000E_RingInfo i[E1000E_NUM_QUEUES] = {
116
+ static const E1000ERingInfo i[E1000E_NUM_QUEUES] = {
117
{ RDBAH0, RDBAL0, RDLEN0, RDH0, RDT0, 0 },
118
{ RDBAH1, RDBAL1, RDLEN1, RDH1, RDT1, 1 }
119
};
120
@@ -XXX,XX +XXX,XX @@ e1000e_start_xmit(E1000ECore *core, const E1000E_TxRing *txr)
121
dma_addr_t base;
122
struct e1000_tx_desc desc;
123
bool ide = false;
124
- const E1000E_RingInfo *txi = txr->i;
125
+ const E1000ERingInfo *txi = txr->i;
126
uint32_t cause = E1000_ICS_TXQE;
127
128
if (!(core->mac[TCTL] & E1000_TCTL_EN)) {
129
@@ -XXX,XX +XXX,XX @@ e1000e_start_xmit(E1000ECore *core, const E1000E_TxRing *txr)
130
}
131
132
static bool
133
-e1000e_has_rxbufs(E1000ECore *core, const E1000E_RingInfo *r,
134
+e1000e_has_rxbufs(E1000ECore *core, const E1000ERingInfo *r,
135
size_t total_size)
136
{
137
uint32_t bufs = e1000e_ring_free_descr_num(core, r);
138
@@ -XXX,XX +XXX,XX @@ e1000e_update_rx_stats(E1000ECore *core, size_t pkt_size, size_t pkt_fcs_size)
139
}
140
141
static inline bool
142
-e1000e_rx_descr_threshold_hit(E1000ECore *core, const E1000E_RingInfo *rxi)
143
+e1000e_rx_descr_threshold_hit(E1000ECore *core, const E1000ERingInfo *rxi)
144
{
145
return e1000e_ring_free_descr_num(core, rxi) ==
146
e1000e_ring_len(core, rxi) >> core->rxbuf_min_shift;
147
@@ -XXX,XX +XXX,XX @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
148
struct iovec *iov = net_rx_pkt_get_iovec(pkt);
149
size_t size = net_rx_pkt_get_total_len(pkt);
150
size_t total_size = size + e1000x_fcs_len(core->mac);
151
- const E1000E_RingInfo *rxi;
152
+ const E1000ERingInfo *rxi;
153
size_t ps_hdr_len = 0;
154
bool do_ps = e1000e_do_ps(core, pkt, &ps_hdr_len);
155
bool is_first = true;
156
diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c
157
index XXXXXXX..XXXXXXX 100644
386
index XXXXXXX..XXXXXXX 100644
158
--- a/hw/net/igb_core.c
387
--- a/include/hw/virtio/vhost-vdpa.h
159
+++ b/hw/net/igb_core.c
388
+++ b/include/hw/virtio/vhost-vdpa.h
160
@@ -XXX,XX +XXX,XX @@ static uint32_t igb_rx_wb_eic(IGBCore *core, int queue_idx)
389
@@ -XXX,XX +XXX,XX @@
161
return (ent & E1000_IVAR_VALID) ? BIT(ent & 0x1f) : 0;
390
162
}
391
#include <gmodule.h>
163
392
164
-typedef struct E1000E_RingInfo_st {
393
+#include "hw/virtio/vhost-iova-tree.h"
165
+typedef struct E1000ERingInfo {
394
#include "hw/virtio/virtio.h"
166
int dbah;
395
#include "standard-headers/linux/vhost_types.h"
167
int dbal;
396
168
int dlen;
397
@@ -XXX,XX +XXX,XX @@ typedef struct vhost_vdpa {
169
int dh;
398
MemoryListener listener;
170
int dt;
399
struct vhost_vdpa_iova_range iova_range;
171
int idx;
400
bool shadow_vqs_enabled;
172
-} E1000E_RingInfo;
401
+ /* IOVA mapping used by the Shadow Virtqueue */
173
+} E1000ERingInfo;
402
+ VhostIOVATree *iova_tree;
174
403
GPtrArray *shadow_vqs;
175
static inline bool
404
struct vhost_dev *dev;
176
-igb_ring_empty(IGBCore *core, const E1000E_RingInfo *r)
405
VhostVDPAHostNotifier notifier[VIRTIO_QUEUE_MAX];
177
+igb_ring_empty(IGBCore *core, const E1000ERingInfo *r)
178
{
179
return core->mac[r->dh] == core->mac[r->dt] ||
180
core->mac[r->dt] >= core->mac[r->dlen] / E1000_RING_DESC_LEN;
181
}
182
183
static inline uint64_t
184
-igb_ring_base(IGBCore *core, const E1000E_RingInfo *r)
185
+igb_ring_base(IGBCore *core, const E1000ERingInfo *r)
186
{
187
uint64_t bah = core->mac[r->dbah];
188
uint64_t bal = core->mac[r->dbal];
189
@@ -XXX,XX +XXX,XX @@ igb_ring_base(IGBCore *core, const E1000E_RingInfo *r)
190
}
191
192
static inline uint64_t
193
-igb_ring_head_descr(IGBCore *core, const E1000E_RingInfo *r)
194
+igb_ring_head_descr(IGBCore *core, const E1000ERingInfo *r)
195
{
196
return igb_ring_base(core, r) + E1000_RING_DESC_LEN * core->mac[r->dh];
197
}
198
199
static inline void
200
-igb_ring_advance(IGBCore *core, const E1000E_RingInfo *r, uint32_t count)
201
+igb_ring_advance(IGBCore *core, const E1000ERingInfo *r, uint32_t count)
202
{
203
core->mac[r->dh] += count;
204
205
@@ -XXX,XX +XXX,XX @@ igb_ring_advance(IGBCore *core, const E1000E_RingInfo *r, uint32_t count)
206
}
207
208
static inline uint32_t
209
-igb_ring_free_descr_num(IGBCore *core, const E1000E_RingInfo *r)
210
+igb_ring_free_descr_num(IGBCore *core, const E1000ERingInfo *r)
211
{
212
trace_e1000e_ring_free_space(r->idx, core->mac[r->dlen],
213
core->mac[r->dh], core->mac[r->dt]);
214
@@ -XXX,XX +XXX,XX @@ igb_ring_free_descr_num(IGBCore *core, const E1000E_RingInfo *r)
215
}
216
217
static inline bool
218
-igb_ring_enabled(IGBCore *core, const E1000E_RingInfo *r)
219
+igb_ring_enabled(IGBCore *core, const E1000ERingInfo *r)
220
{
221
return core->mac[r->dlen] > 0;
222
}
223
224
typedef struct IGB_TxRing_st {
225
- const E1000E_RingInfo *i;
226
+ const E1000ERingInfo *i;
227
struct igb_tx *tx;
228
} IGB_TxRing;
229
230
@@ -XXX,XX +XXX,XX @@ igb_mq_queue_idx(int base_reg_idx, int reg_idx)
231
static inline void
232
igb_tx_ring_init(IGBCore *core, IGB_TxRing *txr, int idx)
233
{
234
- static const E1000E_RingInfo i[IGB_NUM_QUEUES] = {
235
+ static const E1000ERingInfo i[IGB_NUM_QUEUES] = {
236
{ TDBAH0, TDBAL0, TDLEN0, TDH0, TDT0, 0 },
237
{ TDBAH1, TDBAL1, TDLEN1, TDH1, TDT1, 1 },
238
{ TDBAH2, TDBAL2, TDLEN2, TDH2, TDT2, 2 },
239
@@ -XXX,XX +XXX,XX @@ igb_tx_ring_init(IGBCore *core, IGB_TxRing *txr, int idx)
240
}
241
242
typedef struct E1000E_RxRing_st {
243
- const E1000E_RingInfo *i;
244
+ const E1000ERingInfo *i;
245
} E1000E_RxRing;
246
247
static inline void
248
igb_rx_ring_init(IGBCore *core, E1000E_RxRing *rxr, int idx)
249
{
250
- static const E1000E_RingInfo i[IGB_NUM_QUEUES] = {
251
+ static const E1000ERingInfo i[IGB_NUM_QUEUES] = {
252
{ RDBAH0, RDBAL0, RDLEN0, RDH0, RDT0, 0 },
253
{ RDBAH1, RDBAL1, RDLEN1, RDH1, RDT1, 1 },
254
{ RDBAH2, RDBAL2, RDLEN2, RDH2, RDT2, 2 },
255
@@ -XXX,XX +XXX,XX @@ igb_rx_ring_init(IGBCore *core, E1000E_RxRing *rxr, int idx)
256
static uint32_t
257
igb_txdesc_writeback(IGBCore *core, dma_addr_t base,
258
union e1000_adv_tx_desc *tx_desc,
259
- const E1000E_RingInfo *txi)
260
+ const E1000ERingInfo *txi)
261
{
262
PCIDevice *d;
263
uint32_t cmd_type_len = le32_to_cpu(tx_desc->read.cmd_type_len);
264
@@ -XXX,XX +XXX,XX @@ igb_txdesc_writeback(IGBCore *core, dma_addr_t base,
265
}
266
267
static inline bool
268
-igb_tx_enabled(IGBCore *core, const E1000E_RingInfo *txi)
269
+igb_tx_enabled(IGBCore *core, const E1000ERingInfo *txi)
270
{
271
bool vmdq = core->mac[MRQC] & 1;
272
uint16_t qn = txi->idx;
273
@@ -XXX,XX +XXX,XX @@ igb_start_xmit(IGBCore *core, const IGB_TxRing *txr)
274
PCIDevice *d;
275
dma_addr_t base;
276
union e1000_adv_tx_desc desc;
277
- const E1000E_RingInfo *txi = txr->i;
278
+ const E1000ERingInfo *txi = txr->i;
279
uint32_t eic = 0;
280
281
if (!igb_tx_enabled(core, txi)) {
282
@@ -XXX,XX +XXX,XX @@ igb_start_xmit(IGBCore *core, const IGB_TxRing *txr)
283
}
284
285
static uint32_t
286
-igb_rxbufsize(IGBCore *core, const E1000E_RingInfo *r)
287
+igb_rxbufsize(IGBCore *core, const E1000ERingInfo *r)
288
{
289
uint32_t srrctl = core->mac[E1000_SRRCTL(r->idx) >> 2];
290
uint32_t bsizepkt = srrctl & E1000_SRRCTL_BSIZEPKT_MASK;
291
@@ -XXX,XX +XXX,XX @@ igb_rxbufsize(IGBCore *core, const E1000E_RingInfo *r)
292
}
293
294
static bool
295
-igb_has_rxbufs(IGBCore *core, const E1000E_RingInfo *r, size_t total_size)
296
+igb_has_rxbufs(IGBCore *core, const E1000ERingInfo *r, size_t total_size)
297
{
298
uint32_t bufs = igb_ring_free_descr_num(core, r);
299
uint32_t bufsize = igb_rxbufsize(core, r);
300
@@ -XXX,XX +XXX,XX @@ igb_write_to_rx_buffers(IGBCore *core,
301
}
302
303
static void
304
-igb_update_rx_stats(IGBCore *core, const E1000E_RingInfo *rxi,
305
+igb_update_rx_stats(IGBCore *core, const E1000ERingInfo *rxi,
306
size_t pkt_size, size_t pkt_fcs_size)
307
{
308
eth_pkt_types_e pkt_type = net_rx_pkt_get_packet_type(core->rx_pkt);
309
@@ -XXX,XX +XXX,XX @@ igb_update_rx_stats(IGBCore *core, const E1000E_RingInfo *rxi,
310
}
311
312
static inline bool
313
-igb_rx_descr_threshold_hit(IGBCore *core, const E1000E_RingInfo *rxi)
314
+igb_rx_descr_threshold_hit(IGBCore *core, const E1000ERingInfo *rxi)
315
{
316
return igb_ring_free_descr_num(core, rxi) ==
317
((core->mac[E1000_SRRCTL(rxi->idx) >> 2] >> 20) & 31) * 16;
318
@@ -XXX,XX +XXX,XX @@ igb_write_packet_to_guest(IGBCore *core, struct NetRxPkt *pkt,
319
struct iovec *iov = net_rx_pkt_get_iovec(pkt);
320
size_t size = net_rx_pkt_get_total_len(pkt);
321
size_t total_size = size + e1000x_fcs_len(core->mac);
322
- const E1000E_RingInfo *rxi = rxr->i;
323
+ const E1000ERingInfo *rxi = rxr->i;
324
size_t bufsize = igb_rxbufsize(core, rxi);
325
326
d = pcie_sriov_get_vf_at_index(core->owner, rxi->idx % 8);
327
@@ -XXX,XX +XXX,XX @@ igb_write_packet_to_guest(IGBCore *core, struct NetRxPkt *pkt,
328
}
329
330
static bool
331
-igb_rx_strip_vlan(IGBCore *core, const E1000E_RingInfo *rxi)
332
+igb_rx_strip_vlan(IGBCore *core, const E1000ERingInfo *rxi)
333
{
334
if (core->mac[MRQC] & 1) {
335
uint16_t pool = rxi->idx % IGB_NUM_VM_POOLS;
336
--
406
--
337
2.7.4
407
2.7.4
408
409
diff view generated by jsdifflib
1
From: Tomasz Dzieciol <t.dzieciol@partner.samsung.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Signed-off-by: Tomasz Dzieciol <t.dzieciol@partner.samsung.com>
3
This is needed to achieve migration, so the destination can restore its
4
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
4
index.
5
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
5
6
Setting base as last used idx, so destination will see as available all
7
the entries that the device did not use, including the in-flight
8
processing ones.
9
10
This is ok for networking, but other kinds of devices might have
11
problems with these retransmissions.
12
13
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
14
Acked-by: Michael S. Tsirkin <mst@redhat.com>
6
Signed-off-by: Jason Wang <jasowang@redhat.com>
15
Signed-off-by: Jason Wang <jasowang@redhat.com>
7
---
16
---
8
hw/net/igb_core.c | 4 +++-
17
hw/virtio/vhost-vdpa.c | 17 +++++++++++++++++
9
hw/net/igb_regs.h | 1 +
18
1 file changed, 17 insertions(+)
10
2 files changed, 4 insertions(+), 1 deletion(-)
11
19
12
diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c
20
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
13
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/net/igb_core.c
22
--- a/hw/virtio/vhost-vdpa.c
15
+++ b/hw/net/igb_core.c
23
+++ b/hw/virtio/vhost-vdpa.c
16
@@ -XXX,XX +XXX,XX @@ igb_rx_desc_get_packet_type(IGBCore *core, struct NetRxPkt *pkt, uint16_t etqf)
24
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_vring_base(struct vhost_dev *dev,
17
net_rx_pkt_get_protocols(pkt, &hasip4, &hasip6, &l4hdr_proto);
25
static int vhost_vdpa_get_vring_base(struct vhost_dev *dev,
18
26
struct vhost_vring_state *ring)
19
if (hasip6 && !(core->mac[RFCTL] & E1000_RFCTL_IPV6_DIS)) {
27
{
20
- pkt_type = E1000_ADVRXD_PKT_IP6;
28
+ struct vhost_vdpa *v = dev->opaque;
21
+ eth_ip6_hdr_info *ip6hdr_info = net_rx_pkt_get_ip6_info(pkt);
29
int ret;
22
+ pkt_type = ip6hdr_info->has_ext_hdrs ? E1000_ADVRXD_PKT_IP6E :
30
23
+ E1000_ADVRXD_PKT_IP6;
31
+ if (v->shadow_vqs_enabled) {
24
} else if (hasip4) {
32
+ VhostShadowVirtqueue *svq = g_ptr_array_index(v->shadow_vqs,
25
pkt_type = E1000_ADVRXD_PKT_IP4;
33
+ ring->index);
26
} else {
34
+
27
diff --git a/hw/net/igb_regs.h b/hw/net/igb_regs.h
35
+ /*
28
index XXXXXXX..XXXXXXX 100644
36
+ * Setting base as last used idx, so destination will see as available
29
--- a/hw/net/igb_regs.h
37
+ * all the entries that the device did not use, including the in-flight
30
+++ b/hw/net/igb_regs.h
38
+ * processing ones.
31
@@ -XXX,XX +XXX,XX @@ union e1000_adv_rx_desc {
39
+ *
32
40
+ * TODO: This is ok for networking, but other kinds of devices might
33
#define E1000_ADVRXD_PKT_IP4 BIT(0)
41
+ * have problems with these retransmissions.
34
#define E1000_ADVRXD_PKT_IP6 BIT(2)
42
+ */
35
+#define E1000_ADVRXD_PKT_IP6E BIT(3)
43
+ ring->num = svq->last_used_idx;
36
#define E1000_ADVRXD_PKT_TCP BIT(4)
44
+ return 0;
37
#define E1000_ADVRXD_PKT_UDP BIT(5)
45
+ }
38
#define E1000_ADVRXD_PKT_SCTP BIT(6)
46
+
47
ret = vhost_vdpa_call(dev, VHOST_GET_VRING_BASE, ring);
48
trace_vhost_vdpa_get_vring_base(dev, ring->index, ring->num);
49
return ret;
39
--
50
--
40
2.7.4
51
2.7.4
52
53
diff view generated by jsdifflib
1
From: Tomasz Dzieciol <t.dzieciol@partner.samsung.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
TCP ACK detection is no longer present in igb.
3
Setting the log address would make the device start reporting invalid
4
dirty memory because the SVQ vrings are located in qemu's memory.
4
5
5
Signed-off-by: Tomasz Dzieciol <t.dzieciol@partner.samsung.com>
6
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
6
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
7
Acked-by: Michael S. Tsirkin <mst@redhat.com>
7
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
9
---
10
hw/net/igb_core.c | 5 -----
10
hw/virtio/vhost-vdpa.c | 3 ++-
11
1 file changed, 5 deletions(-)
11
1 file changed, 2 insertions(+), 1 deletion(-)
12
12
13
diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c
13
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
14
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/net/igb_core.c
15
--- a/hw/virtio/vhost-vdpa.c
16
+++ b/hw/net/igb_core.c
16
+++ b/hw/virtio/vhost-vdpa.c
17
@@ -XXX,XX +XXX,XX @@ igb_build_rx_metadata(IGBCore *core,
17
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started)
18
trace_e1000e_rx_metadata_ip_id(*ip_id);
18
static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base,
19
struct vhost_log *log)
20
{
21
- if (vhost_vdpa_one_time_request(dev)) {
22
+ struct vhost_vdpa *v = dev->opaque;
23
+ if (v->shadow_vqs_enabled || vhost_vdpa_one_time_request(dev)) {
24
return 0;
19
}
25
}
20
21
- if (l4hdr_proto == ETH_L4_HDR_PROTO_TCP && net_rx_pkt_is_tcp_ack(pkt)) {
22
- *status_flags |= E1000_RXD_STAT_ACK;
23
- trace_e1000e_rx_metadata_ack();
24
- }
25
-
26
if (pkt_info) {
27
*pkt_info = rss_info->enabled ? rss_info->type : 0;
28
26
29
--
27
--
30
2.7.4
28
2.7.4
29
30
diff view generated by jsdifflib
1
From: Tomasz Dzieciol <t.dzieciol@partner.samsung.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Refactoring is done in preparation for support of multiple advanced
3
SVQ is able to log the dirty bits by itself, so let's use it to not
4
descriptors RX modes, especially packet-split modes.
4
block migration.
5
5
6
Signed-off-by: Tomasz Dzieciol <t.dzieciol@partner.samsung.com>
6
Also, ignore set and clear of VHOST_F_LOG_ALL on set_features if SVQ is
7
Reviewed-by: Akihiko Odaki <akihiko.odaki@daynix.com>
7
enabled. Even if the device supports it, the reports would be nonsense
8
Tested-by: Akihiko Odaki <akihiko.odaki@daynix.com>
8
because SVQ memory is in the qemu region.
9
10
The log region is still allocated. Future changes might skip that, but
11
this series is already long enough.
12
13
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
14
Acked-by: Michael S. Tsirkin <mst@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
15
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
---
16
---
11
hw/net/igb_core.c | 170 +++++++++++++++++++++++++++-------------------------
17
hw/virtio/vhost-vdpa.c | 39 +++++++++++++++++++++++++++++++++++----
12
hw/net/igb_regs.h | 10 ++--
18
include/hw/virtio/vhost-vdpa.h | 1 +
13
hw/net/trace-events | 4 +-
19
2 files changed, 36 insertions(+), 4 deletions(-)
14
3 files changed, 96 insertions(+), 88 deletions(-)
15
20
16
diff --git a/hw/net/igb_core.c b/hw/net/igb_core.c
21
diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c
17
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
18
--- a/hw/net/igb_core.c
23
--- a/hw/virtio/vhost-vdpa.c
19
+++ b/hw/net/igb_core.c
24
+++ b/hw/virtio/vhost-vdpa.c
20
@@ -XXX,XX +XXX,XX @@ igb_verify_csum_in_sw(IGBCore *core,
25
@@ -XXX,XX +XXX,XX @@ static bool vhost_vdpa_one_time_request(struct vhost_dev *dev)
26
return v->index != 0;
21
}
27
}
22
28
23
static void
29
+static int vhost_vdpa_get_dev_features(struct vhost_dev *dev,
24
-igb_build_rx_metadata(IGBCore *core,
30
+ uint64_t *features)
25
- struct NetRxPkt *pkt,
31
+{
26
- bool is_eop,
32
+ int ret;
27
- const E1000E_RSSInfo *rss_info, uint16_t etqf, bool ts,
33
+
28
- uint16_t *pkt_info, uint16_t *hdr_info,
34
+ ret = vhost_vdpa_call(dev, VHOST_GET_FEATURES, features);
29
- uint32_t *rss,
35
+ trace_vhost_vdpa_get_features(dev, *features);
30
- uint32_t *status_flags,
36
+ return ret;
31
- uint16_t *ip_id,
37
+}
32
- uint16_t *vlan_tag)
38
+
33
+igb_build_rx_metadata_common(IGBCore *core,
39
static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v,
34
+ struct NetRxPkt *pkt,
40
Error **errp)
35
+ bool is_eop,
36
+ uint32_t *status_flags,
37
+ uint16_t *vlan_tag)
38
{
41
{
39
struct virtio_net_hdr *vhdr;
42
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v,
40
bool hasip4, hasip6, csum_valid;
43
return 0;
41
@@ -XXX,XX +XXX,XX @@ igb_build_rx_metadata(IGBCore *core,
42
*status_flags = E1000_RXD_STAT_DD;
43
44
/* No additional metadata needed for non-EOP descriptors */
45
- /* TODO: EOP apply only to status so don't skip whole function. */
46
if (!is_eop) {
47
goto func_exit;
48
}
44
}
49
@@ -XXX,XX +XXX,XX @@ igb_build_rx_metadata(IGBCore *core,
45
50
trace_e1000e_rx_metadata_vlan(*vlan_tag);
46
- r = hdev->vhost_ops->vhost_get_features(hdev, &dev_features);
47
+ r = vhost_vdpa_get_dev_features(hdev, &dev_features);
48
if (r != 0) {
49
error_setg_errno(errp, -r, "Can't get vdpa device features");
50
return r;
51
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_mem_table(struct vhost_dev *dev,
52
static int vhost_vdpa_set_features(struct vhost_dev *dev,
53
uint64_t features)
54
{
55
+ struct vhost_vdpa *v = dev->opaque;
56
int ret;
57
58
if (vhost_vdpa_one_time_request(dev)) {
59
return 0;
51
}
60
}
52
61
53
- /* Packet parsing results */
62
+ if (v->shadow_vqs_enabled) {
54
- if ((core->mac[RXCSUM] & E1000_RXCSUM_PCSD) != 0) {
63
+ if ((v->acked_features ^ features) == BIT_ULL(VHOST_F_LOG_ALL)) {
55
- if (rss_info->enabled) {
64
+ /*
56
- *rss = cpu_to_le32(rss_info->hash);
65
+ * QEMU is just trying to enable or disable logging. SVQ handles
57
- trace_igb_rx_metadata_rss(*rss);
66
+ * this sepparately, so no need to forward this.
58
- }
67
+ */
59
- } else if (hasip4) {
68
+ v->acked_features = features;
60
- *status_flags |= E1000_RXD_STAT_IPIDV;
69
+ return 0;
61
- *ip_id = cpu_to_le16(net_rx_pkt_get_ip_id(pkt));
70
+ }
62
- trace_e1000e_rx_metadata_ip_id(*ip_id);
63
- }
64
-
65
- if (pkt_info) {
66
- *pkt_info = rss_info->enabled ? rss_info->type : 0;
67
-
68
- if (etqf < 8) {
69
- *pkt_info |= (BIT(11) | etqf) << 4;
70
- } else {
71
- if (hasip4) {
72
- *pkt_info |= E1000_ADVRXD_PKT_IP4;
73
- }
74
-
75
- if (hasip6) {
76
- *pkt_info |= E1000_ADVRXD_PKT_IP6;
77
- }
78
-
79
- switch (l4hdr_proto) {
80
- case ETH_L4_HDR_PROTO_TCP:
81
- *pkt_info |= E1000_ADVRXD_PKT_TCP;
82
- break;
83
-
84
- case ETH_L4_HDR_PROTO_UDP:
85
- *pkt_info |= E1000_ADVRXD_PKT_UDP;
86
- break;
87
-
88
- case ETH_L4_HDR_PROTO_SCTP:
89
- *pkt_info |= E1000_ADVRXD_PKT_SCTP;
90
- break;
91
-
92
- default:
93
- break;
94
- }
95
- }
96
- }
97
-
98
- if (hdr_info) {
99
- *hdr_info = 0;
100
- }
101
-
102
- if (ts) {
103
- *status_flags |= BIT(16);
104
- }
105
-
106
/* RX CSO information */
107
if (hasip6 && (core->mac[RFCTL] & E1000_RFCTL_IPV6_XSUM_DIS)) {
108
trace_e1000e_rx_metadata_ipv6_sum_disabled();
109
@@ -XXX,XX +XXX,XX @@ func_exit:
110
static inline void
111
igb_write_lgcy_rx_descr(IGBCore *core, struct e1000_rx_desc *desc,
112
struct NetRxPkt *pkt,
113
- const E1000E_RSSInfo *rss_info, uint16_t etqf, bool ts,
114
+ const E1000E_RSSInfo *rss_info,
115
uint16_t length)
116
{
117
- uint32_t status_flags, rss;
118
- uint16_t ip_id;
119
+ uint32_t status_flags;
120
121
assert(!rss_info->enabled);
122
+
71
+
123
+ memset(desc, 0, sizeof(*desc));
72
+ v->acked_features = features;
124
desc->length = cpu_to_le16(length);
125
- desc->csum = 0;
126
+ igb_build_rx_metadata_common(core, pkt, pkt != NULL,
127
+ &status_flags,
128
+ &desc->special);
129
130
- igb_build_rx_metadata(core, pkt, pkt != NULL,
131
- rss_info, etqf, ts,
132
- NULL, NULL, &rss,
133
- &status_flags, &ip_id,
134
- &desc->special);
135
desc->errors = (uint8_t) (le32_to_cpu(status_flags) >> 24);
136
desc->status = (uint8_t) le32_to_cpu(status_flags);
137
}
138
139
+static uint16_t
140
+igb_rx_desc_get_packet_type(IGBCore *core, struct NetRxPkt *pkt, uint16_t etqf)
141
+{
142
+ uint16_t pkt_type;
143
+ bool hasip4, hasip6;
144
+ EthL4HdrProto l4hdr_proto;
145
+
73
+
146
+ if (etqf < 8) {
74
+ /* We must not ack _F_LOG if SVQ is enabled */
147
+ pkt_type = BIT(11) | etqf;
75
+ features &= ~BIT_ULL(VHOST_F_LOG_ALL);
148
+ return pkt_type;
149
+ }
76
+ }
150
+
77
+
151
+ net_rx_pkt_get_protocols(pkt, &hasip4, &hasip6, &l4hdr_proto);
78
trace_vhost_vdpa_set_features(dev, features);
79
ret = vhost_vdpa_call(dev, VHOST_SET_FEATURES, &features);
80
if (ret) {
81
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_set_vring_call(struct vhost_dev *dev,
82
static int vhost_vdpa_get_features(struct vhost_dev *dev,
83
uint64_t *features)
84
{
85
- int ret;
86
+ struct vhost_vdpa *v = dev->opaque;
87
+ int ret = vhost_vdpa_get_dev_features(dev, features);
152
+
88
+
153
+ if (hasip6 && !(core->mac[RFCTL] & E1000_RFCTL_IPV6_DIS)) {
89
+ if (ret == 0 && v->shadow_vqs_enabled) {
154
+ pkt_type = E1000_ADVRXD_PKT_IP6;
90
+ /* Add SVQ logging capabilities */
155
+ } else if (hasip4) {
91
+ *features |= BIT_ULL(VHOST_F_LOG_ALL);
156
+ pkt_type = E1000_ADVRXD_PKT_IP4;
157
+ } else {
158
+ pkt_type = 0;
159
+ }
92
+ }
160
+
93
161
+ switch (l4hdr_proto) {
94
- ret = vhost_vdpa_call(dev, VHOST_GET_FEATURES, features);
162
+ case ETH_L4_HDR_PROTO_TCP:
95
- trace_vhost_vdpa_get_features(dev, *features);
163
+ pkt_type |= E1000_ADVRXD_PKT_TCP;
96
return ret;
164
+ break;
165
+ case ETH_L4_HDR_PROTO_UDP:
166
+ pkt_type |= E1000_ADVRXD_PKT_UDP;
167
+ break;
168
+ case ETH_L4_HDR_PROTO_SCTP:
169
+ pkt_type |= E1000_ADVRXD_PKT_SCTP;
170
+ break;
171
+ default:
172
+ break;
173
+ }
174
+
175
+ return pkt_type;
176
+}
177
+
178
static inline void
179
igb_write_adv_rx_descr(IGBCore *core, union e1000_adv_rx_desc *desc,
180
struct NetRxPkt *pkt,
181
const E1000E_RSSInfo *rss_info, uint16_t etqf, bool ts,
182
uint16_t length)
183
{
184
+ bool hasip4, hasip6;
185
+ EthL4HdrProto l4hdr_proto;
186
+ uint16_t rss_type = 0, pkt_type;
187
+ bool eop = (pkt != NULL);
188
+ uint32_t adv_desc_status_error = 0;
189
memset(&desc->wb, 0, sizeof(desc->wb));
190
191
desc->wb.upper.length = cpu_to_le16(length);
192
+ igb_build_rx_metadata_common(core, pkt, eop,
193
+ &desc->wb.upper.status_error,
194
+ &desc->wb.upper.vlan);
195
+
196
+ if (!eop) {
197
+ return;
198
+ }
199
+
200
+ net_rx_pkt_get_protocols(pkt, &hasip4, &hasip6, &l4hdr_proto);
201
+
202
+ if ((core->mac[RXCSUM] & E1000_RXCSUM_PCSD) != 0) {
203
+ if (rss_info->enabled) {
204
+ desc->wb.lower.hi_dword.rss = cpu_to_le32(rss_info->hash);
205
+ rss_type = rss_info->type;
206
+ trace_igb_rx_metadata_rss(desc->wb.lower.hi_dword.rss, rss_type);
207
+ }
208
+ } else if (hasip4) {
209
+ adv_desc_status_error |= E1000_RXD_STAT_IPIDV;
210
+ desc->wb.lower.hi_dword.csum_ip.ip_id =
211
+ cpu_to_le16(net_rx_pkt_get_ip_id(pkt));
212
+ trace_e1000e_rx_metadata_ip_id(
213
+ desc->wb.lower.hi_dword.csum_ip.ip_id);
214
+ }
215
+
216
+ if (ts) {
217
+ adv_desc_status_error |= BIT(16);
218
+ }
219
220
- igb_build_rx_metadata(core, pkt, pkt != NULL,
221
- rss_info, etqf, ts,
222
- &desc->wb.lower.lo_dword.pkt_info,
223
- &desc->wb.lower.lo_dword.hdr_info,
224
- &desc->wb.lower.hi_dword.rss,
225
- &desc->wb.upper.status_error,
226
- &desc->wb.lower.hi_dword.csum_ip.ip_id,
227
- &desc->wb.upper.vlan);
228
+ pkt_type = igb_rx_desc_get_packet_type(core, pkt, etqf);
229
+ trace_e1000e_rx_metadata_pkt_type(pkt_type);
230
+ desc->wb.lower.lo_dword.pkt_info = cpu_to_le16(rss_type | (pkt_type << 4));
231
+ desc->wb.upper.status_error |= cpu_to_le32(adv_desc_status_error);
232
}
97
}
233
98
234
static inline void
99
diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h
235
@@ -XXX,XX +XXX,XX @@ igb_write_rx_descr(IGBCore *core, union e1000_rx_desc_union *desc,
236
uint16_t etqf, bool ts, uint16_t length)
237
{
238
if (igb_rx_use_legacy_descriptor(core)) {
239
- igb_write_lgcy_rx_descr(core, &desc->legacy, pkt, rss_info,
240
- etqf, ts, length);
241
+ igb_write_lgcy_rx_descr(core, &desc->legacy, pkt, rss_info, length);
242
} else {
243
igb_write_adv_rx_descr(core, &desc->adv, pkt, rss_info,
244
etqf, ts, length);
245
diff --git a/hw/net/igb_regs.h b/hw/net/igb_regs.h
246
index XXXXXXX..XXXXXXX 100644
100
index XXXXXXX..XXXXXXX 100644
247
--- a/hw/net/igb_regs.h
101
--- a/include/hw/virtio/vhost-vdpa.h
248
+++ b/hw/net/igb_regs.h
102
+++ b/include/hw/virtio/vhost-vdpa.h
249
@@ -XXX,XX +XXX,XX @@ union e1000_adv_rx_desc {
103
@@ -XXX,XX +XXX,XX @@ typedef struct vhost_vdpa {
250
104
bool iotlb_batch_begin_sent;
251
#define E1000_STATUS_NUM_VFS_SHIFT 14
105
MemoryListener listener;
252
106
struct vhost_vdpa_iova_range iova_range;
253
-#define E1000_ADVRXD_PKT_IP4 BIT(4)
107
+ uint64_t acked_features;
254
-#define E1000_ADVRXD_PKT_IP6 BIT(6)
108
bool shadow_vqs_enabled;
255
-#define E1000_ADVRXD_PKT_TCP BIT(8)
109
/* IOVA mapping used by the Shadow Virtqueue */
256
-#define E1000_ADVRXD_PKT_UDP BIT(9)
110
VhostIOVATree *iova_tree;
257
-#define E1000_ADVRXD_PKT_SCTP BIT(10)
258
+#define E1000_ADVRXD_PKT_IP4 BIT(0)
259
+#define E1000_ADVRXD_PKT_IP6 BIT(2)
260
+#define E1000_ADVRXD_PKT_TCP BIT(4)
261
+#define E1000_ADVRXD_PKT_UDP BIT(5)
262
+#define E1000_ADVRXD_PKT_SCTP BIT(6)
263
264
static inline uint8_t igb_ivar_entry_rx(uint8_t i)
265
{
266
diff --git a/hw/net/trace-events b/hw/net/trace-events
267
index XXXXXXX..XXXXXXX 100644
268
--- a/hw/net/trace-events
269
+++ b/hw/net/trace-events
270
@@ -XXX,XX +XXX,XX @@ igb_link_set_ext_params(bool asd_check, bool speed_select_bypass, bool pfrstd) "
271
igb_rx_desc_buff_size(uint32_t b) "buffer size: %u"
272
igb_rx_desc_buff_write(uint64_t addr, uint16_t offset, const void* source, uint32_t len) "addr: 0x%"PRIx64", offset: %u, from: %p, length: %u"
273
274
-igb_rx_metadata_rss(uint32_t rss) "RSS data: 0x%X"
275
+igb_rx_metadata_rss(uint32_t rss, uint16_t rss_pkt_type) "RSS data: rss: 0x%X, rss_pkt_type: 0x%X"
276
277
igb_irq_icr_clear_gpie_nsicr(void) "Clearing ICR on read due to GPIE.NSICR enabled"
278
igb_irq_set_iam(uint32_t icr) "Update IAM: 0x%x"
279
@@ -XXX,XX +XXX,XX @@ igb_irq_eitr_set(uint32_t eitr_num, uint32_t val) "EITR[%u] = 0x%x"
280
igb_set_pfmailbox(uint32_t vf_num, uint32_t val) "PFMailbox[%d]: 0x%x"
281
igb_set_vfmailbox(uint32_t vf_num, uint32_t val) "VFMailbox[%d]: 0x%x"
282
283
+igb_wrn_rx_desc_modes_not_supp(int desc_type) "Not supported descriptor type: %d"
284
+
285
# igbvf.c
286
igbvf_wrn_io_addr_unknown(uint64_t addr) "IO unknown register 0x%"PRIx64
287
288
--
111
--
289
2.7.4
112
2.7.4
113
114
diff view generated by jsdifflib