1
The following changes since commit d90f154867ec0ec22fd719164b88716e8fd48672:
1
The following changes since commit 3f429a3400822141651486193d6af625eeab05a5:
2
2
3
Merge remote-tracking branch 'remotes/dg-gitlab/tags/ppc-for-6.1-20210504' into staging (2021-05-05 20:29:14 +0100)
3
Merge remote-tracking branch 'remotes/kraxel/tags/microvm-20200617-pull-request' into staging (2020-06-18 11:23:15 +0100)
4
4
5
are available in the git repository at:
5
are available in the git repository at:
6
6
7
https://github.com/jasowang/qemu.git tags/net-pull-request
7
https://github.com/jasowang/qemu.git tags/net-pull-request
8
8
9
for you to fetch changes up to 2bdeb0c2564c36b218ac73e21d7a6f6accb49091:
9
for you to fetch changes up to 71830d8430e65dd20aec4765d87e60336148e1a6:
10
10
11
tap-bsd: Remove special casing for older OpenBSD releases (2021-05-08 13:59:12 +0800)
11
net: Drop the NetLegacy structure, always use Netdev instead (2020-06-18 21:05:52 +0800)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
14
15
Changes from V1:
16
- Fix build failure for virtio-net
17
15
----------------------------------------------------------------
18
----------------------------------------------------------------
16
Andrew Melnychenko (7):
19
Derek Su (1):
17
net/tap: Added TUNSETSTEERINGEBPF code.
20
colo-compare: Fix memory leak in packet_enqueue()
18
net: Added SetSteeringEBPF method for NetClientState.
19
ebpf: Added eBPF RSS program.
20
ebpf: Added eBPF RSS loader.
21
virtio-net: Added eBPF RSS to virtio-net.
22
docs: Added eBPF documentation.
23
MAINTAINERS: Added eBPF maintainers information.
24
21
25
Brad Smith (1):
22
Helge Deller (1):
26
tap-bsd: Remove special casing for older OpenBSD releases
23
Fix tulip breakage
27
24
28
Guenter Roeck (1):
25
Jason Wang (1):
29
hw/net/imx_fec: return 0xffff when accessing non-existing PHY
26
net: use peer when purging queue in qemu_flush_or_purge_queue_packets()
30
27
31
Laurent Vivier (1):
28
Lukas Straub (6):
32
virtio-net: failover: add missing remove_migration_state_change_notifier()
29
net/colo-compare.c: Create event_bh with the right AioContext
30
chardev/char.c: Use qemu_co_sleep_ns if in coroutine
31
net/colo-compare.c: Fix deadlock in compare_chr_send
32
net/colo-compare.c: Only hexdump packets if tracing is enabled
33
net/colo-compare.c: Check that colo-compare is active
34
net/colo-compare.c: Correct ordering in complete and finalize
33
35
34
MAINTAINERS | 8 +
36
Philippe Mathieu-Daudé (3):
35
configure | 8 +-
37
hw/net/tulip: Fix 'Descriptor Error' definition
36
docs/devel/ebpf_rss.rst | 125 +++++++++
38
hw/net/tulip: Log descriptor overflows
37
docs/devel/index.rst | 1 +
39
hw/net/e1000e: Do not abort() on invalid PSRCTL register value
38
ebpf/ebpf_rss-stub.c | 40 +++
40
39
ebpf/ebpf_rss.c | 165 ++++++++++++
41
Sai Pavan Boddu (11):
40
ebpf/ebpf_rss.h | 44 ++++
42
net: cadence_gem: Fix debug statements
41
ebpf/meson.build | 1 +
43
net: cadence_gem: Fix the queue address update during wrap around
42
ebpf/rss.bpf.skeleton.h | 431 +++++++++++++++++++++++++++++++
44
net: cadence_gem: Fix irq update w.r.t queue
43
ebpf/trace-events | 4 +
45
net: cadence_gem: Define access permission for interrupt registers
44
ebpf/trace.h | 1 +
46
net: cadence_gem: Set ISR according to queue in use
45
hw/net/imx_fec.c | 8 +-
47
net: cadence_gem: Move tx/rx packet buffert to CadenceGEMState
46
hw/net/trace-events | 2 +
48
net: cadence_gem: Fix up code style
47
hw/net/vhost_net.c | 3 +
49
net: cadence_gem: Add support for jumbo frames
48
hw/net/virtio-net.c | 116 ++++++++-
50
net: cadnece_gem: Update irq_read_clear field of designcfg_debug1 reg
49
include/hw/virtio/virtio-net.h | 4 +
51
net: cadence_gem: Update the reset value for interrupt mask register
50
include/net/net.h | 2 +
52
net: cadence_gem: TX_LAST bit should be set by guest
51
meson.build | 23 ++
53
52
meson_options.txt | 2 +
54
Thomas Huth (2):
53
net/tap-bsd.c | 13 +-
55
net: Drop the legacy "name" parameter from the -net option
54
net/tap-linux.c | 13 +
56
net: Drop the NetLegacy structure, always use Netdev instead
55
net/tap-linux.h | 1 +
57
56
net/tap-solaris.c | 5 +
58
Tong Ho (1):
57
net/tap-stub.c | 5 +
59
net: cadence_gem: Fix RX address filtering
58
net/tap.c | 9 +
60
59
net/tap_int.h | 1 +
61
Yuri Benditovich (7):
60
net/vhost-vdpa.c | 2 +
62
virtio-net: implement RSS configuration command
61
tools/ebpf/Makefile.ebpf | 21 ++
63
virtio-net: implement RX RSS processing
62
tools/ebpf/rss.bpf.c | 569 +++++++++++++++++++++++++++++++++++++++++
64
tap: allow extended virtio header with hash info
63
29 files changed, 1610 insertions(+), 17 deletions(-)
65
virtio-net: reference implementation of hash report
64
create mode 100644 docs/devel/ebpf_rss.rst
66
vmstate.h: provide VMSTATE_VARRAY_UINT16_ALLOC macro
65
create mode 100644 ebpf/ebpf_rss-stub.c
67
virtio-net: add migration support for RSS and hash report
66
create mode 100644 ebpf/ebpf_rss.c
68
virtio-net: align RSC fields with updated virtio-net header
67
create mode 100644 ebpf/ebpf_rss.h
69
68
create mode 100644 ebpf/meson.build
70
chardev/char.c | 7 +-
69
create mode 100644 ebpf/rss.bpf.skeleton.h
71
docs/system/deprecated.rst | 15 +-
70
create mode 100644 ebpf/trace-events
72
hw/net/Makefile.objs | 1 +
71
create mode 100644 ebpf/trace.h
73
hw/net/cadence_gem.c | 458 +++++++++++++++++++++++------------------
72
create mode 100755 tools/ebpf/Makefile.ebpf
74
hw/net/e1000e_core.c | 10 +-
73
create mode 100644 tools/ebpf/rss.bpf.c
75
hw/net/trace-events | 3 +
76
hw/net/tulip.c | 12 +-
77
hw/net/tulip.h | 2 +-
78
hw/net/virtio-net.c | 387 ++++++++++++++++++++++++++++++----
79
include/hw/net/cadence_gem.h | 6 +
80
include/hw/virtio/virtio-net.h | 16 ++
81
include/migration/vmstate.h | 10 +
82
net/colo-compare.c | 277 ++++++++++++++++++-------
83
net/colo.c | 7 +
84
net/colo.h | 1 +
85
net/net.c | 89 ++------
86
net/tap.c | 3 +-
87
net/trace-events | 1 +
88
qapi/net.json | 49 -----
89
19 files changed, 905 insertions(+), 449 deletions(-)
74
90
75
91
76
diff view generated by jsdifflib
New patch
1
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
2
3
Optionally report RSS feature.
4
Handle RSS configuration command and keep RSS parameters
5
in virtio-net device context.
6
7
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
10
hw/net/trace-events | 3 +
11
hw/net/virtio-net.c | 167 ++++++++++++++++++++++++++++++++++++++---
12
include/hw/virtio/virtio-net.h | 13 ++++
13
3 files changed, 174 insertions(+), 9 deletions(-)
14
15
diff --git a/hw/net/trace-events b/hw/net/trace-events
16
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/net/trace-events
18
+++ b/hw/net/trace-events
19
@@ -XXX,XX +XXX,XX @@ virtio_net_announce_notify(void) ""
20
virtio_net_announce_timer(int round) "%d"
21
virtio_net_handle_announce(int round) "%d"
22
virtio_net_post_load_device(void)
23
+virtio_net_rss_disable(void)
24
+virtio_net_rss_error(const char *msg, uint32_t value) "%s, value 0x%08x"
25
+virtio_net_rss_enable(uint32_t p1, uint16_t p2, uint8_t p3) "hashes 0x%x, table of %d, key of %d"
26
27
# tulip.c
28
tulip_reg_write(uint64_t addr, const char *name, int size, uint64_t val) "addr 0x%02"PRIx64" (%s) size %d value 0x%08"PRIx64
29
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/hw/net/virtio-net.c
32
+++ b/hw/net/virtio-net.c
33
@@ -XXX,XX +XXX,XX @@
34
tso/gso/gro 'off'. */
35
#define VIRTIO_NET_RSC_DEFAULT_INTERVAL 300000
36
37
+#define VIRTIO_NET_RSS_SUPPORTED_HASHES (VIRTIO_NET_RSS_HASH_TYPE_IPv4 | \
38
+ VIRTIO_NET_RSS_HASH_TYPE_TCPv4 | \
39
+ VIRTIO_NET_RSS_HASH_TYPE_UDPv4 | \
40
+ VIRTIO_NET_RSS_HASH_TYPE_IPv6 | \
41
+ VIRTIO_NET_RSS_HASH_TYPE_TCPv6 | \
42
+ VIRTIO_NET_RSS_HASH_TYPE_UDPv6 | \
43
+ VIRTIO_NET_RSS_HASH_TYPE_IP_EX | \
44
+ VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \
45
+ VIRTIO_NET_RSS_HASH_TYPE_UDP_EX)
46
+
47
/* temporary until standard header include it */
48
#if !defined(VIRTIO_NET_HDR_F_RSC_INFO)
49
50
@@ -XXX,XX +XXX,XX @@ static VirtIOFeature feature_sizes[] = {
51
.end = endof(struct virtio_net_config, mtu)},
52
{.flags = 1ULL << VIRTIO_NET_F_SPEED_DUPLEX,
53
.end = endof(struct virtio_net_config, duplex)},
54
+ {.flags = 1ULL << VIRTIO_NET_F_RSS,
55
+ .end = endof(struct virtio_net_config, supported_hash_types)},
56
{}
57
};
58
59
@@ -XXX,XX +XXX,XX @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
60
memcpy(netcfg.mac, n->mac, ETH_ALEN);
61
virtio_stl_p(vdev, &netcfg.speed, n->net_conf.speed);
62
netcfg.duplex = n->net_conf.duplex;
63
+ netcfg.rss_max_key_size = VIRTIO_NET_RSS_MAX_KEY_SIZE;
64
+ virtio_stw_p(vdev, &netcfg.rss_max_indirection_table_length,
65
+ VIRTIO_NET_RSS_MAX_TABLE_LEN);
66
+ virtio_stl_p(vdev, &netcfg.supported_hash_types,
67
+ VIRTIO_NET_RSS_SUPPORTED_HASHES);
68
memcpy(config, &netcfg, n->config_size);
69
}
70
71
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
72
return features;
73
}
74
75
+ virtio_clear_feature(&features, VIRTIO_NET_F_RSS);
76
features = vhost_net_get_features(get_vhost_net(nc->peer), features);
77
vdev->backend_features = features;
78
79
@@ -XXX,XX +XXX,XX @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features)
80
}
81
82
virtio_net_set_multiqueue(n,
83
+ virtio_has_feature(features, VIRTIO_NET_F_RSS) ||
84
virtio_has_feature(features, VIRTIO_NET_F_MQ));
85
86
virtio_net_set_mrg_rx_bufs(n,
87
@@ -XXX,XX +XXX,XX @@ static int virtio_net_handle_announce(VirtIONet *n, uint8_t cmd,
88
}
89
}
90
91
+static void virtio_net_disable_rss(VirtIONet *n)
92
+{
93
+ if (n->rss_data.enabled) {
94
+ trace_virtio_net_rss_disable();
95
+ }
96
+ n->rss_data.enabled = false;
97
+}
98
+
99
+static uint16_t virtio_net_handle_rss(VirtIONet *n,
100
+ struct iovec *iov, unsigned int iov_cnt)
101
+{
102
+ VirtIODevice *vdev = VIRTIO_DEVICE(n);
103
+ struct virtio_net_rss_config cfg;
104
+ size_t s, offset = 0, size_get;
105
+ uint16_t queues, i;
106
+ struct {
107
+ uint16_t us;
108
+ uint8_t b;
109
+ } QEMU_PACKED temp;
110
+ const char *err_msg = "";
111
+ uint32_t err_value = 0;
112
+
113
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_RSS)) {
114
+ err_msg = "RSS is not negotiated";
115
+ goto error;
116
+ }
117
+ size_get = offsetof(struct virtio_net_rss_config, indirection_table);
118
+ s = iov_to_buf(iov, iov_cnt, offset, &cfg, size_get);
119
+ if (s != size_get) {
120
+ err_msg = "Short command buffer";
121
+ err_value = (uint32_t)s;
122
+ goto error;
123
+ }
124
+ n->rss_data.hash_types = virtio_ldl_p(vdev, &cfg.hash_types);
125
+ n->rss_data.indirections_len =
126
+ virtio_lduw_p(vdev, &cfg.indirection_table_mask);
127
+ n->rss_data.indirections_len++;
128
+ if (!is_power_of_2(n->rss_data.indirections_len)) {
129
+ err_msg = "Invalid size of indirection table";
130
+ err_value = n->rss_data.indirections_len;
131
+ goto error;
132
+ }
133
+ if (n->rss_data.indirections_len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
134
+ err_msg = "Too large indirection table";
135
+ err_value = n->rss_data.indirections_len;
136
+ goto error;
137
+ }
138
+ n->rss_data.default_queue =
139
+ virtio_lduw_p(vdev, &cfg.unclassified_queue);
140
+ if (n->rss_data.default_queue >= n->max_queues) {
141
+ err_msg = "Invalid default queue";
142
+ err_value = n->rss_data.default_queue;
143
+ goto error;
144
+ }
145
+ offset += size_get;
146
+ size_get = sizeof(uint16_t) * n->rss_data.indirections_len;
147
+ g_free(n->rss_data.indirections_table);
148
+ n->rss_data.indirections_table = g_malloc(size_get);
149
+ if (!n->rss_data.indirections_table) {
150
+ err_msg = "Can't allocate indirections table";
151
+ err_value = n->rss_data.indirections_len;
152
+ goto error;
153
+ }
154
+ s = iov_to_buf(iov, iov_cnt, offset,
155
+ n->rss_data.indirections_table, size_get);
156
+ if (s != size_get) {
157
+ err_msg = "Short indirection table buffer";
158
+ err_value = (uint32_t)s;
159
+ goto error;
160
+ }
161
+ for (i = 0; i < n->rss_data.indirections_len; ++i) {
162
+ uint16_t val = n->rss_data.indirections_table[i];
163
+ n->rss_data.indirections_table[i] = virtio_lduw_p(vdev, &val);
164
+ }
165
+ offset += size_get;
166
+ size_get = sizeof(temp);
167
+ s = iov_to_buf(iov, iov_cnt, offset, &temp, size_get);
168
+ if (s != size_get) {
169
+ err_msg = "Can't get queues";
170
+ err_value = (uint32_t)s;
171
+ goto error;
172
+ }
173
+ queues = virtio_lduw_p(vdev, &temp.us);
174
+ if (queues == 0 || queues > n->max_queues) {
175
+ err_msg = "Invalid number of queues";
176
+ err_value = queues;
177
+ goto error;
178
+ }
179
+ if (temp.b > VIRTIO_NET_RSS_MAX_KEY_SIZE) {
180
+ err_msg = "Invalid key size";
181
+ err_value = temp.b;
182
+ goto error;
183
+ }
184
+ if (!temp.b && n->rss_data.hash_types) {
185
+ err_msg = "No key provided";
186
+ err_value = 0;
187
+ goto error;
188
+ }
189
+ if (!temp.b && !n->rss_data.hash_types) {
190
+ virtio_net_disable_rss(n);
191
+ return queues;
192
+ }
193
+ offset += size_get;
194
+ size_get = temp.b;
195
+ s = iov_to_buf(iov, iov_cnt, offset, n->rss_data.key, size_get);
196
+ if (s != size_get) {
197
+ err_msg = "Can get key buffer";
198
+ err_value = (uint32_t)s;
199
+ goto error;
200
+ }
201
+ n->rss_data.enabled = true;
202
+ trace_virtio_net_rss_enable(n->rss_data.hash_types,
203
+ n->rss_data.indirections_len,
204
+ temp.b);
205
+ return queues;
206
+error:
207
+ trace_virtio_net_rss_error(err_msg, err_value);
208
+ virtio_net_disable_rss(n);
209
+ return 0;
210
+}
211
+
212
static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,
213
struct iovec *iov, unsigned int iov_cnt)
214
{
215
VirtIODevice *vdev = VIRTIO_DEVICE(n);
216
- struct virtio_net_ctrl_mq mq;
217
- size_t s;
218
uint16_t queues;
219
220
- s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq));
221
- if (s != sizeof(mq)) {
222
- return VIRTIO_NET_ERR;
223
- }
224
+ virtio_net_disable_rss(n);
225
+ if (cmd == VIRTIO_NET_CTRL_MQ_RSS_CONFIG) {
226
+ queues = virtio_net_handle_rss(n, iov, iov_cnt);
227
+ } else if (cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
228
+ struct virtio_net_ctrl_mq mq;
229
+ size_t s;
230
+ if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_MQ)) {
231
+ return VIRTIO_NET_ERR;
232
+ }
233
+ s = iov_to_buf(iov, iov_cnt, 0, &mq, sizeof(mq));
234
+ if (s != sizeof(mq)) {
235
+ return VIRTIO_NET_ERR;
236
+ }
237
+ queues = virtio_lduw_p(vdev, &mq.virtqueue_pairs);
238
239
- if (cmd != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
240
+ } else {
241
return VIRTIO_NET_ERR;
242
}
243
244
- queues = virtio_lduw_p(vdev, &mq.virtqueue_pairs);
245
-
246
if (queues < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
247
queues > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX ||
248
queues > n->max_queues ||
249
@@ -XXX,XX +XXX,XX @@ static void virtio_net_device_unrealize(DeviceState *dev)
250
g_free(n->vqs);
251
qemu_del_nic(n->nic);
252
virtio_net_rsc_cleanup(n);
253
+ g_free(n->rss_data.indirections_table);
254
virtio_cleanup(vdev);
255
}
256
257
@@ -XXX,XX +XXX,XX @@ static Property virtio_net_properties[] = {
258
DEFINE_PROP_BIT64("ctrl_guest_offloads", VirtIONet, host_features,
259
VIRTIO_NET_F_CTRL_GUEST_OFFLOADS, true),
260
DEFINE_PROP_BIT64("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ, false),
261
+ DEFINE_PROP_BIT64("rss", VirtIONet, host_features,
262
+ VIRTIO_NET_F_RSS, false),
263
DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features,
264
VIRTIO_NET_F_RSC_EXT, false),
265
DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout,
266
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
267
index XXXXXXX..XXXXXXX 100644
268
--- a/include/hw/virtio/virtio-net.h
269
+++ b/include/hw/virtio/virtio-net.h
270
@@ -XXX,XX +XXX,XX @@ typedef struct VirtioNetRscChain {
271
/* Maximum packet size we can receive from tap device: header + 64k */
272
#define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 * KiB))
273
274
+#define VIRTIO_NET_RSS_MAX_KEY_SIZE 40
275
+#define VIRTIO_NET_RSS_MAX_TABLE_LEN 128
276
+
277
+typedef struct VirtioNetRssData {
278
+ bool enabled;
279
+ uint32_t hash_types;
280
+ uint8_t key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
281
+ uint16_t indirections_len;
282
+ uint16_t *indirections_table;
283
+ uint16_t default_queue;
284
+} VirtioNetRssData;
285
+
286
typedef struct VirtIONetQueue {
287
VirtQueue *rx_vq;
288
VirtQueue *tx_vq;
289
@@ -XXX,XX +XXX,XX @@ struct VirtIONet {
290
bool failover;
291
DeviceListener primary_listener;
292
Notifier migration_state;
293
+ VirtioNetRssData rss_data;
294
};
295
296
void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
297
--
298
2.5.0
299
300
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
2
2
3
When RSS is enabled the device tries to load the eBPF program
3
If VIRTIO_NET_F_RSS negotiated and RSS is enabled, process
4
to select RX virtqueue in the TUN. If eBPF can be loaded
4
incoming packets, calculate packet's hash and place the
5
the RSS will function also with vhost (works with kernel 5.8 and later).
5
packet into respective RX virtqueue.
6
Software RSS is used as a fallback with vhost=off when eBPF can't be loaded
7
or when hash population requested by the guest.
8
6
9
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
7
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
10
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
9
---
13
hw/net/vhost_net.c | 3 ++
10
hw/net/Makefile.objs | 1 +
14
hw/net/virtio-net.c | 115 +++++++++++++++++++++++++++++++++++++++--
11
hw/net/virtio-net.c | 88 +++++++++++++++++++++++++++++++++++++++++-
15
include/hw/virtio/virtio-net.h | 4 ++
12
include/hw/virtio/virtio-net.h | 1 +
16
net/vhost-vdpa.c | 2 +
13
3 files changed, 88 insertions(+), 2 deletions(-)
17
4 files changed, 121 insertions(+), 3 deletions(-)
18
14
19
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
15
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
20
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/net/vhost_net.c
17
--- a/hw/net/Makefile.objs
22
+++ b/hw/net/vhost_net.c
18
+++ b/hw/net/Makefile.objs
23
@@ -XXX,XX +XXX,XX @@ static const int kernel_feature_bits[] = {
19
@@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_MILKYMIST) += milkymist-minimac2.o
24
VIRTIO_NET_F_MTU,
20
obj-$(CONFIG_PSERIES) += spapr_llan.o
25
VIRTIO_F_IOMMU_PLATFORM,
21
obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
26
VIRTIO_F_RING_PACKED,
22
27
+ VIRTIO_NET_F_HASH_REPORT,
23
+common-obj-$(CONFIG_VIRTIO_NET) += net_rx_pkt.o
28
VHOST_INVALID_FEATURE_BIT
24
obj-$(CONFIG_VIRTIO_NET) += virtio-net.o
29
};
25
common-obj-$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET)) += vhost_net.o
30
26
common-obj-$(call lnot,$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET))) += vhost_net-stub.o
31
@@ -XXX,XX +XXX,XX @@ static const int user_feature_bits[] = {
32
VIRTIO_NET_F_MTU,
33
VIRTIO_F_IOMMU_PLATFORM,
34
VIRTIO_F_RING_PACKED,
35
+ VIRTIO_NET_F_RSS,
36
+ VIRTIO_NET_F_HASH_REPORT,
37
38
/* This bit implies RARP isn't sent by QEMU out of band */
39
VIRTIO_NET_F_GUEST_ANNOUNCE,
40
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
27
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
41
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
42
--- a/hw/net/virtio-net.c
29
--- a/hw/net/virtio-net.c
43
+++ b/hw/net/virtio-net.c
30
+++ b/hw/net/virtio-net.c
44
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
31
@@ -XXX,XX +XXX,XX @@
45
return features;
32
#include "trace.h"
46
}
33
#include "monitor/qdev.h"
47
34
#include "hw/pci/pci.h"
48
- virtio_clear_feature(&features, VIRTIO_NET_F_RSS);
35
+#include "net_rx_pkt.h"
49
- virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT);
36
50
+ if (!ebpf_rss_is_loaded(&n->ebpf_rss)) {
37
#define VIRTIO_NET_VM_VERSION 11
51
+ virtio_clear_feature(&features, VIRTIO_NET_F_RSS);
38
39
@@ -XXX,XX +XXX,XX @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
40
return 0;
41
}
42
43
+static uint8_t virtio_net_get_hash_type(bool isip4,
44
+ bool isip6,
45
+ bool isudp,
46
+ bool istcp,
47
+ uint32_t types)
48
+{
49
+ if (isip4) {
50
+ if (istcp && (types & VIRTIO_NET_RSS_HASH_TYPE_TCPv4)) {
51
+ return NetPktRssIpV4Tcp;
52
+ }
53
+ if (isudp && (types & VIRTIO_NET_RSS_HASH_TYPE_UDPv4)) {
54
+ return NetPktRssIpV4Udp;
55
+ }
56
+ if (types & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
57
+ return NetPktRssIpV4;
58
+ }
59
+ } else if (isip6) {
60
+ uint32_t mask = VIRTIO_NET_RSS_HASH_TYPE_TCP_EX |
61
+ VIRTIO_NET_RSS_HASH_TYPE_TCPv6;
62
+
63
+ if (istcp && (types & mask)) {
64
+ return (types & VIRTIO_NET_RSS_HASH_TYPE_TCP_EX) ?
65
+ NetPktRssIpV6TcpEx : NetPktRssIpV6Tcp;
66
+ }
67
+ mask = VIRTIO_NET_RSS_HASH_TYPE_UDP_EX | VIRTIO_NET_RSS_HASH_TYPE_UDPv6;
68
+ if (isudp && (types & mask)) {
69
+ return (types & VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) ?
70
+ NetPktRssIpV6UdpEx : NetPktRssIpV6Udp;
71
+ }
72
+ mask = VIRTIO_NET_RSS_HASH_TYPE_IP_EX | VIRTIO_NET_RSS_HASH_TYPE_IPv6;
73
+ if (types & mask) {
74
+ return (types & VIRTIO_NET_RSS_HASH_TYPE_IP_EX) ?
75
+ NetPktRssIpV6Ex : NetPktRssIpV6;
76
+ }
52
+ }
77
+ }
53
features = vhost_net_get_features(get_vhost_net(nc->peer), features);
78
+ return 0xff;
54
vdev->backend_features = features;
55
56
@@ -XXX,XX +XXX,XX @@ static int virtio_net_handle_announce(VirtIONet *n, uint8_t cmd,
57
}
58
}
59
60
+static void virtio_net_detach_epbf_rss(VirtIONet *n);
61
+
62
static void virtio_net_disable_rss(VirtIONet *n)
63
{
64
if (n->rss_data.enabled) {
65
trace_virtio_net_rss_disable();
66
}
67
n->rss_data.enabled = false;
68
+
69
+ virtio_net_detach_epbf_rss(n);
70
+}
79
+}
71
+
80
+
72
+static bool virtio_net_attach_ebpf_to_backend(NICState *nic, int prog_fd)
81
+static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf,
82
+ size_t size)
73
+{
83
+{
74
+ NetClientState *nc = qemu_get_peer(qemu_get_queue(nic), 0);
84
+ VirtIONet *n = qemu_get_nic_opaque(nc);
75
+ if (nc == NULL || nc->info->set_steering_ebpf == NULL) {
85
+ unsigned int index = nc->queue_index, new_index;
76
+ return false;
86
+ struct NetRxPkt *pkt = n->rx_pkt;
87
+ uint8_t net_hash_type;
88
+ uint32_t hash;
89
+ bool isip4, isip6, isudp, istcp;
90
+
91
+ net_rx_pkt_set_protocols(pkt, buf + n->host_hdr_len,
92
+ size - n->host_hdr_len);
93
+ net_rx_pkt_get_protocols(pkt, &isip4, &isip6, &isudp, &istcp);
94
+ if (isip4 && (net_rx_pkt_get_ip4_info(pkt)->fragment)) {
95
+ istcp = isudp = false;
96
+ }
97
+ if (isip6 && (net_rx_pkt_get_ip6_info(pkt)->fragment)) {
98
+ istcp = isudp = false;
99
+ }
100
+ net_hash_type = virtio_net_get_hash_type(isip4, isip6, isudp, istcp,
101
+ n->rss_data.hash_types);
102
+ if (net_hash_type > NetPktRssIpV6UdpEx) {
103
+ return n->rss_data.default_queue;
77
+ }
104
+ }
78
+
105
+
79
+ return nc->info->set_steering_ebpf(nc, prog_fd);
106
+ hash = net_rx_pkt_calc_rss_hash(pkt, net_hash_type, n->rss_data.key);
107
+ new_index = hash & (n->rss_data.indirections_len - 1);
108
+ new_index = n->rss_data.indirections_table[new_index];
109
+ if (index == new_index) {
110
+ return -1;
111
+ }
112
+ return new_index;
80
+}
113
+}
81
+
114
+
82
+static void rss_data_to_rss_config(struct VirtioNetRssData *data,
115
static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
83
+ struct EBPFRSSConfig *config)
116
- size_t size)
84
+{
117
+ size_t size, bool no_rss)
85
+ config->redirect = data->redirect;
118
{
86
+ config->populate_hash = data->populate_hash;
119
VirtIONet *n = qemu_get_nic_opaque(nc);
87
+ config->hash_types = data->hash_types;
120
VirtIONetQueue *q = virtio_net_get_subqueue(nc);
88
+ config->indirections_len = data->indirections_len;
89
+ config->default_queue = data->default_queue;
90
+}
91
+
92
+static bool virtio_net_attach_epbf_rss(VirtIONet *n)
93
+{
94
+ struct EBPFRSSConfig config = {};
95
+
96
+ if (!ebpf_rss_is_loaded(&n->ebpf_rss)) {
97
+ return false;
98
+ }
99
+
100
+ rss_data_to_rss_config(&n->rss_data, &config);
101
+
102
+ if (!ebpf_rss_set_all(&n->ebpf_rss, &config,
103
+ n->rss_data.indirections_table, n->rss_data.key)) {
104
+ return false;
105
+ }
106
+
107
+ if (!virtio_net_attach_ebpf_to_backend(n->nic, n->ebpf_rss.program_fd)) {
108
+ return false;
109
+ }
110
+
111
+ return true;
112
+}
113
+
114
+static void virtio_net_detach_epbf_rss(VirtIONet *n)
115
+{
116
+ virtio_net_attach_ebpf_to_backend(n->nic, -1);
117
+}
118
+
119
+static bool virtio_net_load_ebpf(VirtIONet *n)
120
+{
121
+ if (!virtio_net_attach_ebpf_to_backend(n->nic, -1)) {
122
+ /* backend does't support steering ebpf */
123
+ return false;
124
+ }
125
+
126
+ return ebpf_rss_load(&n->ebpf_rss);
127
+}
128
+
129
+static void virtio_net_unload_ebpf(VirtIONet *n)
130
+{
131
+ virtio_net_attach_ebpf_to_backend(n->nic, -1);
132
+ ebpf_rss_unload(&n->ebpf_rss);
133
}
134
135
static uint16_t virtio_net_handle_rss(VirtIONet *n,
136
@@ -XXX,XX +XXX,XX @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
137
goto error;
138
}
139
n->rss_data.enabled = true;
140
+
141
+ if (!n->rss_data.populate_hash) {
142
+ if (!virtio_net_attach_epbf_rss(n)) {
143
+ /* EBPF must be loaded for vhost */
144
+ if (get_vhost_net(qemu_get_queue(n->nic)->peer)) {
145
+ warn_report("Can't load eBPF RSS for vhost");
146
+ goto error;
147
+ }
148
+ /* fallback to software RSS */
149
+ warn_report("Can't load eBPF RSS - fallback to software RSS");
150
+ n->rss_data.enabled_software_rss = true;
151
+ }
152
+ } else {
153
+ /* use software RSS for hash populating */
154
+ /* and detach eBPF if was loaded before */
155
+ virtio_net_detach_epbf_rss(n);
156
+ n->rss_data.enabled_software_rss = true;
157
+ }
158
+
159
trace_virtio_net_rss_enable(n->rss_data.hash_types,
160
n->rss_data.indirections_len,
161
temp.b);
162
@@ -XXX,XX +XXX,XX @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
121
@@ -XXX,XX +XXX,XX @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
163
return -1;
122
return -1;
164
}
123
}
165
124
166
- if (!no_rss && n->rss_data.enabled) {
125
+ if (!no_rss && n->rss_data.enabled) {
167
+ if (!no_rss && n->rss_data.enabled && n->rss_data.enabled_software_rss) {
126
+ int index = virtio_net_process_rss(nc, buf, size);
168
int index = virtio_net_process_rss(nc, buf, size);
127
+ if (index >= 0) {
169
if (index >= 0) {
128
+ NetClientState *nc2 = qemu_get_subqueue(n->nic, index);
170
NetClientState *nc2 = qemu_get_subqueue(n->nic, index);
129
+ return virtio_net_receive_rcu(nc2, buf, size, true);
171
@@ -XXX,XX +XXX,XX @@ static int virtio_net_post_load_device(void *opaque, int version_id)
172
}
173
174
if (n->rss_data.enabled) {
175
+ n->rss_data.enabled_software_rss = n->rss_data.populate_hash;
176
+ if (!n->rss_data.populate_hash) {
177
+ if (!virtio_net_attach_epbf_rss(n)) {
178
+ if (get_vhost_net(qemu_get_queue(n->nic)->peer)) {
179
+ warn_report("Can't post-load eBPF RSS for vhost");
180
+ } else {
181
+ warn_report("Can't post-load eBPF RSS - fallback to software RSS");
182
+ n->rss_data.enabled_software_rss = true;
183
+ }
184
+ }
185
+ }
130
+ }
131
+ }
186
+
132
+
187
trace_virtio_net_rss_enable(n->rss_data.hash_types,
133
/* hdr_len refers to the header we supply to the guest */
188
n->rss_data.indirections_len,
134
if (!virtio_net_has_buffers(q, size + n->guest_hdr_len - n->host_hdr_len)) {
189
sizeof(n->rss_data.key));
135
return 0;
136
@@ -XXX,XX +XXX,XX @@ static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf,
137
{
138
RCU_READ_LOCK_GUARD();
139
140
- return virtio_net_receive_rcu(nc, buf, size);
141
+ return virtio_net_receive_rcu(nc, buf, size, false);
142
}
143
144
static void virtio_net_rsc_extract_unit4(VirtioNetRscChain *chain,
190
@@ -XXX,XX +XXX,XX @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
145
@@ -XXX,XX +XXX,XX @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
146
147
QTAILQ_INIT(&n->rsc_chains);
191
n->qdev = dev;
148
n->qdev = dev;
192
193
net_rx_pkt_init(&n->rx_pkt, false);
194
+
149
+
195
+ if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
150
+ net_rx_pkt_init(&n->rx_pkt, false);
196
+ virtio_net_load_ebpf(n);
197
+ }
198
}
151
}
199
152
200
static void virtio_net_device_unrealize(DeviceState *dev)
153
static void virtio_net_device_unrealize(DeviceState *dev)
201
@@ -XXX,XX +XXX,XX @@ static void virtio_net_device_unrealize(DeviceState *dev)
154
@@ -XXX,XX +XXX,XX @@ static void virtio_net_device_unrealize(DeviceState *dev)
202
VirtIONet *n = VIRTIO_NET(dev);
155
qemu_del_nic(n->nic);
203
int i, max_queues;
156
virtio_net_rsc_cleanup(n);
204
157
g_free(n->rss_data.indirections_table);
205
+ if (virtio_has_feature(n->host_features, VIRTIO_NET_F_RSS)) {
158
+ net_rx_pkt_uninit(n->rx_pkt);
206
+ virtio_net_unload_ebpf(n);
159
virtio_cleanup(vdev);
207
+ }
208
+
209
/* This will stop vhost backend if appropriate. */
210
virtio_net_set_status(vdev, 0);
211
212
@@ -XXX,XX +XXX,XX @@ static void virtio_net_instance_init(Object *obj)
213
device_add_bootindex_property(obj, &n->nic_conf.bootindex,
214
"bootindex", "/ethernet-phy@0",
215
DEVICE(n));
216
+
217
+ ebpf_rss_init(&n->ebpf_rss);
218
}
160
}
219
161
220
static int virtio_net_pre_save(void *opaque)
221
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
162
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
222
index XXXXXXX..XXXXXXX 100644
163
index XXXXXXX..XXXXXXX 100644
223
--- a/include/hw/virtio/virtio-net.h
164
--- a/include/hw/virtio/virtio-net.h
224
+++ b/include/hw/virtio/virtio-net.h
165
+++ b/include/hw/virtio/virtio-net.h
225
@@ -XXX,XX +XXX,XX @@
226
#include "qemu/option_int.h"
227
#include "qom/object.h"
228
229
+#include "ebpf/ebpf_rss.h"
230
+
231
#define TYPE_VIRTIO_NET "virtio-net-device"
232
OBJECT_DECLARE_SIMPLE_TYPE(VirtIONet, VIRTIO_NET)
233
234
@@ -XXX,XX +XXX,XX @@ typedef struct VirtioNetRscChain {
235
236
typedef struct VirtioNetRssData {
237
bool enabled;
238
+ bool enabled_software_rss;
239
bool redirect;
240
bool populate_hash;
241
uint32_t hash_types;
242
@@ -XXX,XX +XXX,XX @@ struct VirtIONet {
166
@@ -XXX,XX +XXX,XX @@ struct VirtIONet {
167
DeviceListener primary_listener;
243
Notifier migration_state;
168
Notifier migration_state;
244
VirtioNetRssData rss_data;
169
VirtioNetRssData rss_data;
245
struct NetRxPkt *rx_pkt;
170
+ struct NetRxPkt *rx_pkt;
246
+ struct EBPFRSSContext ebpf_rss;
247
};
171
};
248
172
249
void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
173
void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
250
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
251
index XXXXXXX..XXXXXXX 100644
252
--- a/net/vhost-vdpa.c
253
+++ b/net/vhost-vdpa.c
254
@@ -XXX,XX +XXX,XX @@ const int vdpa_feature_bits[] = {
255
VIRTIO_NET_F_MTU,
256
VIRTIO_F_IOMMU_PLATFORM,
257
VIRTIO_F_RING_PACKED,
258
+ VIRTIO_NET_F_RSS,
259
+ VIRTIO_NET_F_HASH_REPORT,
260
VIRTIO_NET_F_GUEST_ANNOUNCE,
261
VIRTIO_NET_F_STATUS,
262
VHOST_INVALID_FEATURE_BIT
263
--
174
--
264
2.7.4
175
2.5.0
265
176
266
177
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
2
2
3
For now, that method supported only by Linux TAP.
3
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
4
Linux TAP uses TUNSETSTEERINGEBPF ioctl.
5
6
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
4
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
5
---
9
include/net/net.h | 2 ++
6
net/tap.c | 3 ++-
10
net/tap-bsd.c | 5 +++++
7
1 file changed, 2 insertions(+), 1 deletion(-)
11
net/tap-linux.c | 13 +++++++++++++
12
net/tap-solaris.c | 5 +++++
13
net/tap-stub.c | 5 +++++
14
net/tap.c | 9 +++++++++
15
net/tap_int.h | 1 +
16
7 files changed, 40 insertions(+)
17
8
18
diff --git a/include/net/net.h b/include/net/net.h
19
index XXXXXXX..XXXXXXX 100644
20
--- a/include/net/net.h
21
+++ b/include/net/net.h
22
@@ -XXX,XX +XXX,XX @@ typedef int (SetVnetBE)(NetClientState *, bool);
23
typedef struct SocketReadState SocketReadState;
24
typedef void (SocketReadStateFinalize)(SocketReadState *rs);
25
typedef void (NetAnnounce)(NetClientState *);
26
+typedef bool (SetSteeringEBPF)(NetClientState *, int);
27
28
typedef struct NetClientInfo {
29
NetClientDriver type;
30
@@ -XXX,XX +XXX,XX @@ typedef struct NetClientInfo {
31
SetVnetLE *set_vnet_le;
32
SetVnetBE *set_vnet_be;
33
NetAnnounce *announce;
34
+ SetSteeringEBPF *set_steering_ebpf;
35
} NetClientInfo;
36
37
struct NetClientState {
38
diff --git a/net/tap-bsd.c b/net/tap-bsd.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/net/tap-bsd.c
41
+++ b/net/tap-bsd.c
42
@@ -XXX,XX +XXX,XX @@ int tap_fd_get_ifname(int fd, char *ifname)
43
{
44
return -1;
45
}
46
+
47
+int tap_fd_set_steering_ebpf(int fd, int prog_fd)
48
+{
49
+ return -1;
50
+}
51
diff --git a/net/tap-linux.c b/net/tap-linux.c
52
index XXXXXXX..XXXXXXX 100644
53
--- a/net/tap-linux.c
54
+++ b/net/tap-linux.c
55
@@ -XXX,XX +XXX,XX @@ int tap_fd_get_ifname(int fd, char *ifname)
56
pstrcpy(ifname, sizeof(ifr.ifr_name), ifr.ifr_name);
57
return 0;
58
}
59
+
60
+int tap_fd_set_steering_ebpf(int fd, int prog_fd)
61
+{
62
+ if (ioctl(fd, TUNSETSTEERINGEBPF, (void *) &prog_fd) != 0) {
63
+ error_report("Issue while setting TUNSETSTEERINGEBPF:"
64
+ " %s with fd: %d, prog_fd: %d",
65
+ strerror(errno), fd, prog_fd);
66
+
67
+ return -1;
68
+ }
69
+
70
+ return 0;
71
+}
72
diff --git a/net/tap-solaris.c b/net/tap-solaris.c
73
index XXXXXXX..XXXXXXX 100644
74
--- a/net/tap-solaris.c
75
+++ b/net/tap-solaris.c
76
@@ -XXX,XX +XXX,XX @@ int tap_fd_get_ifname(int fd, char *ifname)
77
{
78
return -1;
79
}
80
+
81
+int tap_fd_set_steering_ebpf(int fd, int prog_fd)
82
+{
83
+ return -1;
84
+}
85
diff --git a/net/tap-stub.c b/net/tap-stub.c
86
index XXXXXXX..XXXXXXX 100644
87
--- a/net/tap-stub.c
88
+++ b/net/tap-stub.c
89
@@ -XXX,XX +XXX,XX @@ int tap_fd_get_ifname(int fd, char *ifname)
90
{
91
return -1;
92
}
93
+
94
+int tap_fd_set_steering_ebpf(int fd, int prog_fd)
95
+{
96
+ return -1;
97
+}
98
diff --git a/net/tap.c b/net/tap.c
9
diff --git a/net/tap.c b/net/tap.c
99
index XXXXXXX..XXXXXXX 100644
10
index XXXXXXX..XXXXXXX 100644
100
--- a/net/tap.c
11
--- a/net/tap.c
101
+++ b/net/tap.c
12
+++ b/net/tap.c
102
@@ -XXX,XX +XXX,XX @@ static void tap_poll(NetClientState *nc, bool enable)
13
@@ -XXX,XX +XXX,XX @@ static void tap_set_vnet_hdr_len(NetClientState *nc, int len)
103
tap_write_poll(s, enable);
14
104
}
15
assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
105
16
assert(len == sizeof(struct virtio_net_hdr_mrg_rxbuf) ||
106
+static bool tap_set_steering_ebpf(NetClientState *nc, int prog_fd)
17
- len == sizeof(struct virtio_net_hdr));
107
+{
18
+ len == sizeof(struct virtio_net_hdr) ||
108
+ TAPState *s = DO_UPCAST(TAPState, nc, nc);
19
+ len == sizeof(struct virtio_net_hdr_v1_hash));
109
+ assert(nc->info->type == NET_CLIENT_DRIVER_TAP);
20
110
+
21
tap_fd_set_vnet_hdr_len(s->fd, len);
111
+ return tap_fd_set_steering_ebpf(s->fd, prog_fd) == 0;
22
s->host_vnet_hdr_len = len;
112
+}
113
+
114
int tap_get_fd(NetClientState *nc)
115
{
116
TAPState *s = DO_UPCAST(TAPState, nc, nc);
117
@@ -XXX,XX +XXX,XX @@ static NetClientInfo net_tap_info = {
118
.set_vnet_hdr_len = tap_set_vnet_hdr_len,
119
.set_vnet_le = tap_set_vnet_le,
120
.set_vnet_be = tap_set_vnet_be,
121
+ .set_steering_ebpf = tap_set_steering_ebpf,
122
};
123
124
static TAPState *net_tap_fd_init(NetClientState *peer,
125
diff --git a/net/tap_int.h b/net/tap_int.h
126
index XXXXXXX..XXXXXXX 100644
127
--- a/net/tap_int.h
128
+++ b/net/tap_int.h
129
@@ -XXX,XX +XXX,XX @@ int tap_fd_set_vnet_be(int fd, int vnet_is_be);
130
int tap_fd_enable(int fd);
131
int tap_fd_disable(int fd);
132
int tap_fd_get_ifname(int fd, char *ifname);
133
+int tap_fd_set_steering_ebpf(int fd, int prog_fd);
134
135
#endif /* NET_TAP_INT_H */
136
--
23
--
137
2.7.4
24
2.5.0
138
25
139
26
diff view generated by jsdifflib
New patch
1
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
2
3
Suggest VIRTIO_NET_F_HASH_REPORT if specified in device
4
parameters.
5
If the VIRTIO_NET_F_HASH_REPORT is set,
6
the device extends configuration space. If the feature
7
is negotiated, the packet layout is extended to
8
accomodate the hash information. In this case deliver
9
packet's hash value and report type in virtio header
10
extension.
11
Use for configuration the same procedure as already
12
used for RSS. We add two fields in rss_data that
13
controls what the device does with the calculated hash
14
if rss_data.enabled is set. If field 'populate' is set
15
the hash is set in the packet, if field 'redirect' is
16
set the hash is used to decide the queue to place the
17
packet to.
18
19
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
20
Signed-off-by: Jason Wang <jasowang@redhat.com>
21
---
22
hw/net/virtio-net.c | 99 +++++++++++++++++++++++++++++++++---------
23
include/hw/virtio/virtio-net.h | 2 +
24
2 files changed, 81 insertions(+), 20 deletions(-)
25
26
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/hw/net/virtio-net.c
29
+++ b/hw/net/virtio-net.c
30
@@ -XXX,XX +XXX,XX @@ static VirtIOFeature feature_sizes[] = {
31
.end = endof(struct virtio_net_config, mtu)},
32
{.flags = 1ULL << VIRTIO_NET_F_SPEED_DUPLEX,
33
.end = endof(struct virtio_net_config, duplex)},
34
- {.flags = 1ULL << VIRTIO_NET_F_RSS,
35
+ {.flags = (1ULL << VIRTIO_NET_F_RSS) | (1ULL << VIRTIO_NET_F_HASH_REPORT),
36
.end = endof(struct virtio_net_config, supported_hash_types)},
37
{}
38
};
39
@@ -XXX,XX +XXX,XX @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config)
40
netcfg.duplex = n->net_conf.duplex;
41
netcfg.rss_max_key_size = VIRTIO_NET_RSS_MAX_KEY_SIZE;
42
virtio_stw_p(vdev, &netcfg.rss_max_indirection_table_length,
43
- VIRTIO_NET_RSS_MAX_TABLE_LEN);
44
+ virtio_host_has_feature(vdev, VIRTIO_NET_F_RSS) ?
45
+ VIRTIO_NET_RSS_MAX_TABLE_LEN : 1);
46
virtio_stl_p(vdev, &netcfg.supported_hash_types,
47
VIRTIO_NET_RSS_SUPPORTED_HASHES);
48
memcpy(config, &netcfg, n->config_size);
49
@@ -XXX,XX +XXX,XX @@ static int peer_has_ufo(VirtIONet *n)
50
}
51
52
static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs,
53
- int version_1)
54
+ int version_1, int hash_report)
55
{
56
int i;
57
NetClientState *nc;
58
@@ -XXX,XX +XXX,XX @@ static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs,
59
n->mergeable_rx_bufs = mergeable_rx_bufs;
60
61
if (version_1) {
62
- n->guest_hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
63
+ n->guest_hdr_len = hash_report ?
64
+ sizeof(struct virtio_net_hdr_v1_hash) :
65
+ sizeof(struct virtio_net_hdr_mrg_rxbuf);
66
+ n->rss_data.populate_hash = !!hash_report;
67
} else {
68
n->guest_hdr_len = n->mergeable_rx_bufs ?
69
sizeof(struct virtio_net_hdr_mrg_rxbuf) :
70
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
71
virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO4);
72
virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_TSO6);
73
virtio_clear_feature(&features, VIRTIO_NET_F_GUEST_ECN);
74
+
75
+ virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT);
76
}
77
78
if (!peer_has_vnet_hdr(n) || !peer_has_ufo(n)) {
79
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
80
}
81
82
virtio_clear_feature(&features, VIRTIO_NET_F_RSS);
83
+ virtio_clear_feature(&features, VIRTIO_NET_F_HASH_REPORT);
84
features = vhost_net_get_features(get_vhost_net(nc->peer), features);
85
vdev->backend_features = features;
86
87
@@ -XXX,XX +XXX,XX @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features)
88
virtio_has_feature(features,
89
VIRTIO_NET_F_MRG_RXBUF),
90
virtio_has_feature(features,
91
- VIRTIO_F_VERSION_1));
92
+ VIRTIO_F_VERSION_1),
93
+ virtio_has_feature(features,
94
+ VIRTIO_NET_F_HASH_REPORT));
95
96
n->rsc4_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) &&
97
virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO4);
98
n->rsc6_enabled = virtio_has_feature(features, VIRTIO_NET_F_RSC_EXT) &&
99
virtio_has_feature(features, VIRTIO_NET_F_GUEST_TSO6);
100
+ n->rss_data.redirect = virtio_has_feature(features, VIRTIO_NET_F_RSS);
101
102
if (n->has_vnet_hdr) {
103
n->curr_guest_offloads =
104
@@ -XXX,XX +XXX,XX @@ static void virtio_net_disable_rss(VirtIONet *n)
105
}
106
107
static uint16_t virtio_net_handle_rss(VirtIONet *n,
108
- struct iovec *iov, unsigned int iov_cnt)
109
+ struct iovec *iov,
110
+ unsigned int iov_cnt,
111
+ bool do_rss)
112
{
113
VirtIODevice *vdev = VIRTIO_DEVICE(n);
114
struct virtio_net_rss_config cfg;
115
@@ -XXX,XX +XXX,XX @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
116
const char *err_msg = "";
117
uint32_t err_value = 0;
118
119
- if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_RSS)) {
120
+ if (do_rss && !virtio_vdev_has_feature(vdev, VIRTIO_NET_F_RSS)) {
121
err_msg = "RSS is not negotiated";
122
goto error;
123
}
124
+ if (!do_rss && !virtio_vdev_has_feature(vdev, VIRTIO_NET_F_HASH_REPORT)) {
125
+ err_msg = "Hash report is not negotiated";
126
+ goto error;
127
+ }
128
size_get = offsetof(struct virtio_net_rss_config, indirection_table);
129
s = iov_to_buf(iov, iov_cnt, offset, &cfg, size_get);
130
if (s != size_get) {
131
@@ -XXX,XX +XXX,XX @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
132
n->rss_data.indirections_len =
133
virtio_lduw_p(vdev, &cfg.indirection_table_mask);
134
n->rss_data.indirections_len++;
135
+ if (!do_rss) {
136
+ n->rss_data.indirections_len = 1;
137
+ }
138
if (!is_power_of_2(n->rss_data.indirections_len)) {
139
err_msg = "Invalid size of indirection table";
140
err_value = n->rss_data.indirections_len;
141
@@ -XXX,XX +XXX,XX @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
142
err_value = n->rss_data.indirections_len;
143
goto error;
144
}
145
- n->rss_data.default_queue =
146
- virtio_lduw_p(vdev, &cfg.unclassified_queue);
147
+ n->rss_data.default_queue = do_rss ?
148
+ virtio_lduw_p(vdev, &cfg.unclassified_queue) : 0;
149
if (n->rss_data.default_queue >= n->max_queues) {
150
err_msg = "Invalid default queue";
151
err_value = n->rss_data.default_queue;
152
@@ -XXX,XX +XXX,XX @@ static uint16_t virtio_net_handle_rss(VirtIONet *n,
153
err_value = (uint32_t)s;
154
goto error;
155
}
156
- queues = virtio_lduw_p(vdev, &temp.us);
157
+ queues = do_rss ? virtio_lduw_p(vdev, &temp.us) : n->curr_queues;
158
if (queues == 0 || queues > n->max_queues) {
159
err_msg = "Invalid number of queues";
160
err_value = queues;
161
@@ -XXX,XX +XXX,XX @@ static int virtio_net_handle_mq(VirtIONet *n, uint8_t cmd,
162
uint16_t queues;
163
164
virtio_net_disable_rss(n);
165
+ if (cmd == VIRTIO_NET_CTRL_MQ_HASH_CONFIG) {
166
+ queues = virtio_net_handle_rss(n, iov, iov_cnt, false);
167
+ return queues ? VIRTIO_NET_OK : VIRTIO_NET_ERR;
168
+ }
169
if (cmd == VIRTIO_NET_CTRL_MQ_RSS_CONFIG) {
170
- queues = virtio_net_handle_rss(n, iov, iov_cnt);
171
+ queues = virtio_net_handle_rss(n, iov, iov_cnt, true);
172
} else if (cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
173
struct virtio_net_ctrl_mq mq;
174
size_t s;
175
@@ -XXX,XX +XXX,XX @@ static uint8_t virtio_net_get_hash_type(bool isip4,
176
return 0xff;
177
}
178
179
+static void virtio_set_packet_hash(const uint8_t *buf, uint8_t report,
180
+ uint32_t hash)
181
+{
182
+ struct virtio_net_hdr_v1_hash *hdr = (void *)buf;
183
+ hdr->hash_value = hash;
184
+ hdr->hash_report = report;
185
+}
186
+
187
static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf,
188
size_t size)
189
{
190
VirtIONet *n = qemu_get_nic_opaque(nc);
191
- unsigned int index = nc->queue_index, new_index;
192
+ unsigned int index = nc->queue_index, new_index = index;
193
struct NetRxPkt *pkt = n->rx_pkt;
194
uint8_t net_hash_type;
195
uint32_t hash;
196
bool isip4, isip6, isudp, istcp;
197
+ static const uint8_t reports[NetPktRssIpV6UdpEx + 1] = {
198
+ VIRTIO_NET_HASH_REPORT_IPv4,
199
+ VIRTIO_NET_HASH_REPORT_TCPv4,
200
+ VIRTIO_NET_HASH_REPORT_TCPv6,
201
+ VIRTIO_NET_HASH_REPORT_IPv6,
202
+ VIRTIO_NET_HASH_REPORT_IPv6_EX,
203
+ VIRTIO_NET_HASH_REPORT_TCPv6_EX,
204
+ VIRTIO_NET_HASH_REPORT_UDPv4,
205
+ VIRTIO_NET_HASH_REPORT_UDPv6,
206
+ VIRTIO_NET_HASH_REPORT_UDPv6_EX
207
+ };
208
209
net_rx_pkt_set_protocols(pkt, buf + n->host_hdr_len,
210
size - n->host_hdr_len);
211
@@ -XXX,XX +XXX,XX @@ static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf,
212
net_hash_type = virtio_net_get_hash_type(isip4, isip6, isudp, istcp,
213
n->rss_data.hash_types);
214
if (net_hash_type > NetPktRssIpV6UdpEx) {
215
- return n->rss_data.default_queue;
216
+ if (n->rss_data.populate_hash) {
217
+ virtio_set_packet_hash(buf, VIRTIO_NET_HASH_REPORT_NONE, 0);
218
+ }
219
+ return n->rss_data.redirect ? n->rss_data.default_queue : -1;
220
}
221
222
hash = net_rx_pkt_calc_rss_hash(pkt, net_hash_type, n->rss_data.key);
223
- new_index = hash & (n->rss_data.indirections_len - 1);
224
- new_index = n->rss_data.indirections_table[new_index];
225
- if (index == new_index) {
226
- return -1;
227
+
228
+ if (n->rss_data.populate_hash) {
229
+ virtio_set_packet_hash(buf, reports[net_hash_type], hash);
230
}
231
- return new_index;
232
+
233
+ if (n->rss_data.redirect) {
234
+ new_index = hash & (n->rss_data.indirections_len - 1);
235
+ new_index = n->rss_data.indirections_table[new_index];
236
+ }
237
+
238
+ return (index == new_index) ? -1 : new_index;
239
}
240
241
static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
242
@@ -XXX,XX +XXX,XX @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf,
243
}
244
245
receive_header(n, sg, elem->in_num, buf, size);
246
+ if (n->rss_data.populate_hash) {
247
+ offset = sizeof(mhdr);
248
+ iov_from_buf(sg, elem->in_num, offset,
249
+ buf + offset, n->host_hdr_len - sizeof(mhdr));
250
+ }
251
offset = n->host_hdr_len;
252
total += n->guest_hdr_len;
253
guest_offset = n->guest_hdr_len;
254
@@ -XXX,XX +XXX,XX @@ static int virtio_net_post_load_device(void *opaque, int version_id)
255
trace_virtio_net_post_load_device();
256
virtio_net_set_mrg_rx_bufs(n, n->mergeable_rx_bufs,
257
virtio_vdev_has_feature(vdev,
258
- VIRTIO_F_VERSION_1));
259
+ VIRTIO_F_VERSION_1),
260
+ virtio_vdev_has_feature(vdev,
261
+ VIRTIO_NET_F_HASH_REPORT));
262
263
/* MAC_TABLE_ENTRIES may be different from the saved image */
264
if (n->mac_table.in_use > MAC_TABLE_ENTRIES) {
265
@@ -XXX,XX +XXX,XX @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
266
267
n->vqs[0].tx_waiting = 0;
268
n->tx_burst = n->net_conf.txburst;
269
- virtio_net_set_mrg_rx_bufs(n, 0, 0);
270
+ virtio_net_set_mrg_rx_bufs(n, 0, 0, 0);
271
n->promisc = 1; /* for compatibility */
272
273
n->mac_table.macs = g_malloc0(MAC_TABLE_ENTRIES * ETH_ALEN);
274
@@ -XXX,XX +XXX,XX @@ static Property virtio_net_properties[] = {
275
DEFINE_PROP_BIT64("mq", VirtIONet, host_features, VIRTIO_NET_F_MQ, false),
276
DEFINE_PROP_BIT64("rss", VirtIONet, host_features,
277
VIRTIO_NET_F_RSS, false),
278
+ DEFINE_PROP_BIT64("hash", VirtIONet, host_features,
279
+ VIRTIO_NET_F_HASH_REPORT, false),
280
DEFINE_PROP_BIT64("guest_rsc_ext", VirtIONet, host_features,
281
VIRTIO_NET_F_RSC_EXT, false),
282
DEFINE_PROP_UINT32("rsc_interval", VirtIONet, rsc_timeout,
283
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
284
index XXXXXXX..XXXXXXX 100644
285
--- a/include/hw/virtio/virtio-net.h
286
+++ b/include/hw/virtio/virtio-net.h
287
@@ -XXX,XX +XXX,XX @@ typedef struct VirtioNetRscChain {
288
289
typedef struct VirtioNetRssData {
290
bool enabled;
291
+ bool redirect;
292
+ bool populate_hash;
293
uint32_t hash_types;
294
uint8_t key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
295
uint16_t indirections_len;
296
--
297
2.5.0
298
299
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
2
2
3
Similar to VMSTATE_VARRAY_UINT32_ALLOC, but the size is
4
16-bit field.
5
6
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
3
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
7
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
4
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
5
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
6
---
9
---
7
MAINTAINERS | 8 ++++++++
10
include/migration/vmstate.h | 10 ++++++++++
8
1 file changed, 8 insertions(+)
11
1 file changed, 10 insertions(+)
9
12
10
diff --git a/MAINTAINERS b/MAINTAINERS
13
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
11
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
12
--- a/MAINTAINERS
15
--- a/include/migration/vmstate.h
13
+++ b/MAINTAINERS
16
+++ b/include/migration/vmstate.h
14
@@ -XXX,XX +XXX,XX @@ F: include/hw/remote/proxy-memory-listener.h
17
@@ -XXX,XX +XXX,XX @@ extern const VMStateInfo vmstate_info_qlist;
15
F: hw/remote/iohub.c
18
.offset = vmstate_offset_pointer(_state, _field, _type), \
16
F: include/hw/remote/iohub.h
19
}
17
20
18
+EBPF:
21
+#define VMSTATE_VARRAY_UINT16_ALLOC(_field, _state, _field_num, _version, _info, _type) {\
19
+M: Jason Wang <jasowang@redhat.com>
22
+ .name = (stringify(_field)), \
20
+R: Andrew Melnychenko <andrew@daynix.com>
23
+ .version_id = (_version), \
21
+R: Yuri Benditovich <yuri.benditovich@daynix.com>
24
+ .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
22
+S: Maintained
25
+ .info = &(_info), \
23
+F: ebpf/*
26
+ .size = sizeof(_type), \
24
+F: tools/ebpf/*
27
+ .flags = VMS_VARRAY_UINT16 | VMS_POINTER | VMS_ALLOC, \
28
+ .offset = vmstate_offset_pointer(_state, _field, _type), \
29
+}
25
+
30
+
26
Build and test automation
31
#define VMSTATE_VARRAY_UINT16_UNSAFE(_field, _state, _field_num, _version, _info, _type) {\
27
-------------------------
32
.name = (stringify(_field)), \
28
Build and test automation, general continuous integration
33
.version_id = (_version), \
29
--
34
--
30
2.7.4
35
2.5.0
31
36
32
37
diff view generated by jsdifflib
1
From: Laurent Vivier <lvivier@redhat.com>
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
2
2
3
In the failover case configuration, virtio_net_device_realize() uses an
3
Save and restore RSS/hash report configuration.
4
add_migration_state_change_notifier() to add a state notifier, but this
5
notifier is not removed by the unrealize function when the virtio-net
6
card is unplugged.
7
4
8
If the card is unplugged and a migration is started, the notifier is
5
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
9
called and as it is not valid anymore QEMU crashes.
10
11
This patch fixes the problem by adding the
12
remove_migration_state_change_notifier() in virtio_net_device_unrealize().
13
14
The problem can be reproduced with:
15
16
$ qemu-system-x86_64 -enable-kvm -m 1g -M q35 \
17
-device pcie-root-port,slot=4,id=root1 \
18
-device pcie-root-port,slot=5,id=root2 \
19
-device virtio-net-pci,id=net1,mac=52:54:00:6f:55:cc,failover=on,bus=root1 \
20
-monitor stdio disk.qcow2
21
(qemu) device_del net1
22
(qemu) migrate "exec:gzip -c > STATEFILE.gz"
23
24
Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
25
0x0000000000000000 in ?? ()
26
(gdb) bt
27
#0 0x0000000000000000 in ()
28
#1 0x0000555555d726d7 in notifier_list_notify (...)
29
at .../util/notify.c:39
30
#2 0x0000555555842c1a in migrate_fd_connect (...)
31
at .../migration/migration.c:3975
32
#3 0x0000555555950f7d in migration_channel_connect (...)
33
error@entry=0x0) at .../migration/channel.c:107
34
#4 0x0000555555910922 in exec_start_outgoing_migration (...)
35
at .../migration/exec.c:42
36
37
Reported-by: Igor Mammedov <imammedo@redhat.com>
38
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
39
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
40
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
41
Signed-off-by: Jason Wang <jasowang@redhat.com>
6
Signed-off-by: Jason Wang <jasowang@redhat.com>
42
---
7
---
43
hw/net/virtio-net.c | 1 +
8
hw/net/virtio-net.c | 37 +++++++++++++++++++++++++++++++++++++
44
1 file changed, 1 insertion(+)
9
1 file changed, 37 insertions(+)
45
10
46
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
11
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
47
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
48
--- a/hw/net/virtio-net.c
13
--- a/hw/net/virtio-net.c
49
+++ b/hw/net/virtio-net.c
14
+++ b/hw/net/virtio-net.c
50
@@ -XXX,XX +XXX,XX @@ static void virtio_net_device_unrealize(DeviceState *dev)
15
@@ -XXX,XX +XXX,XX @@ static int virtio_net_post_load_device(void *opaque, int version_id)
51
16
}
52
if (n->failover) {
53
device_listener_unregister(&n->primary_listener);
54
+ remove_migration_state_change_notifier(&n->migration_state);
55
}
17
}
56
18
57
max_queues = n->multiqueue ? n->max_queues : 1;
19
+ if (n->rss_data.enabled) {
20
+ trace_virtio_net_rss_enable(n->rss_data.hash_types,
21
+ n->rss_data.indirections_len,
22
+ sizeof(n->rss_data.key));
23
+ } else {
24
+ trace_virtio_net_rss_disable();
25
+ }
26
return 0;
27
}
28
29
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_virtio_net_has_vnet = {
30
},
31
};
32
33
+static bool virtio_net_rss_needed(void *opaque)
34
+{
35
+ return VIRTIO_NET(opaque)->rss_data.enabled;
36
+}
37
+
38
+static const VMStateDescription vmstate_virtio_net_rss = {
39
+ .name = "virtio-net-device/rss",
40
+ .version_id = 1,
41
+ .minimum_version_id = 1,
42
+ .needed = virtio_net_rss_needed,
43
+ .fields = (VMStateField[]) {
44
+ VMSTATE_BOOL(rss_data.enabled, VirtIONet),
45
+ VMSTATE_BOOL(rss_data.redirect, VirtIONet),
46
+ VMSTATE_BOOL(rss_data.populate_hash, VirtIONet),
47
+ VMSTATE_UINT32(rss_data.hash_types, VirtIONet),
48
+ VMSTATE_UINT16(rss_data.indirections_len, VirtIONet),
49
+ VMSTATE_UINT16(rss_data.default_queue, VirtIONet),
50
+ VMSTATE_UINT8_ARRAY(rss_data.key, VirtIONet,
51
+ VIRTIO_NET_RSS_MAX_KEY_SIZE),
52
+ VMSTATE_VARRAY_UINT16_ALLOC(rss_data.indirections_table, VirtIONet,
53
+ rss_data.indirections_len, 0,
54
+ vmstate_info_uint16, uint16_t),
55
+ VMSTATE_END_OF_LIST()
56
+ },
57
+};
58
+
59
static const VMStateDescription vmstate_virtio_net_device = {
60
.name = "virtio-net-device",
61
.version_id = VIRTIO_NET_VM_VERSION,
62
@@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_virtio_net_device = {
63
has_ctrl_guest_offloads),
64
VMSTATE_END_OF_LIST()
65
},
66
+ .subsections = (const VMStateDescription * []) {
67
+ &vmstate_virtio_net_rss,
68
+ NULL
69
+ }
70
};
71
72
static NetClientInfo net_virtio_info = {
58
--
73
--
59
2.7.4
74
2.5.0
60
75
61
76
diff view generated by jsdifflib
1
From: Brad Smith <brad@comstyle.com>
1
From: Yuri Benditovich <yuri.benditovich@daynix.com>
2
2
3
OpenBSD added support for tap(4) 10 releases ago.
3
Removal of duplicated RSC definitions. Changing names of the
4
fields to ones defined in the Linux header.
4
5
5
Remove the special casing for older releases.
6
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
6
7
Signed-off-by: Brad Smith <brad@comstyle.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
8
---
10
net/tap-bsd.c | 8 --------
9
hw/net/virtio-net.c | 28 ++++------------------------
11
1 file changed, 8 deletions(-)
10
1 file changed, 4 insertions(+), 24 deletions(-)
12
11
13
diff --git a/net/tap-bsd.c b/net/tap-bsd.c
12
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
14
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
15
--- a/net/tap-bsd.c
14
--- a/hw/net/virtio-net.c
16
+++ b/net/tap-bsd.c
15
+++ b/hw/net/virtio-net.c
17
@@ -XXX,XX +XXX,XX @@
16
@@ -XXX,XX +XXX,XX @@
18
#include <net/if_tap.h>
17
VIRTIO_NET_RSS_HASH_TYPE_TCP_EX | \
19
#endif
18
VIRTIO_NET_RSS_HASH_TYPE_UDP_EX)
20
19
21
-#if defined(__OpenBSD__)
20
-/* temporary until standard header include it */
22
-#include <sys/param.h>
21
-#if !defined(VIRTIO_NET_HDR_F_RSC_INFO)
22
-
23
-#define VIRTIO_NET_HDR_F_RSC_INFO 4 /* rsc_ext data in csum_ fields */
24
-#define VIRTIO_NET_F_RSC_EXT 61
25
-
23
-#endif
26
-#endif
24
-
27
-
25
#ifndef __FreeBSD__
28
-static inline __virtio16 *virtio_net_rsc_ext_num_packets(
26
int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
29
- struct virtio_net_hdr *hdr)
27
int vnet_hdr_required, int mq_required, Error **errp)
30
-{
28
@@ -XXX,XX +XXX,XX @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
31
- return &hdr->csum_start;
29
if (*ifname) {
32
-}
30
snprintf(dname, sizeof dname, "/dev/%s", ifname);
33
-
31
} else {
34
-static inline __virtio16 *virtio_net_rsc_ext_num_dupacks(
32
-#if defined(__OpenBSD__) && OpenBSD < 201605
35
- struct virtio_net_hdr *hdr)
33
- snprintf(dname, sizeof dname, "/dev/tun%d", i);
36
-{
34
-#else
37
- return &hdr->csum_offset;
35
snprintf(dname, sizeof dname, "/dev/tap%d", i);
38
-}
36
-#endif
39
-
37
}
40
static VirtIOFeature feature_sizes[] = {
38
TFR(fd = open(dname, O_RDWR));
41
{.flags = 1ULL << VIRTIO_NET_F_MAC,
39
if (fd >= 0) {
42
.end = endof(struct virtio_net_config, mac)},
43
@@ -XXX,XX +XXX,XX @@ static size_t virtio_net_rsc_drain_seg(VirtioNetRscChain *chain,
44
VirtioNetRscSeg *seg)
45
{
46
int ret;
47
- struct virtio_net_hdr *h;
48
+ struct virtio_net_hdr_v1 *h;
49
50
- h = (struct virtio_net_hdr *)seg->buf;
51
+ h = (struct virtio_net_hdr_v1 *)seg->buf;
52
h->flags = 0;
53
h->gso_type = VIRTIO_NET_HDR_GSO_NONE;
54
55
if (seg->is_coalesced) {
56
- *virtio_net_rsc_ext_num_packets(h) = seg->packets;
57
- *virtio_net_rsc_ext_num_dupacks(h) = seg->dup_ack;
58
+ h->rsc.segments = seg->packets;
59
+ h->rsc.dup_acks = seg->dup_ack;
60
h->flags = VIRTIO_NET_HDR_F_RSC_INFO;
61
if (chain->proto == ETH_P_IP) {
62
h->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
40
--
63
--
41
2.7.4
64
2.5.0
42
65
43
66
diff view generated by jsdifflib
New patch
1
From: Helge Deller <deller@gmx.de>
1
2
3
The tulip network driver in a qemu-system-hppa emulation is broken in
4
the sense that bigger network packages aren't received any longer and
5
thus even running e.g. "apt update" inside the VM fails.
6
7
The breakage was introduced by commit 8ffb7265af ("check frame size and
8
r/w data length") which added checks to prevent accesses outside of the
9
rx/tx buffers.
10
11
But the new checks were implemented wrong. The variable rx_frame_len
12
counts backwards, from rx_frame_size down to zero, and the variable len
13
is never bigger than rx_frame_len, so accesses just can't happen and the
14
checks are unnecessary.
15
On the contrary the checks now prevented bigger packages to be moved
16
into the rx buffers.
17
18
This patch reverts the wrong checks and were sucessfully tested with a
19
qemu-system-hppa emulation.
20
21
Fixes: 8ffb7265af ("check frame size and r/w data length")
22
Buglink: https://bugs.launchpad.net/bugs/1874539
23
Signed-off-by: Helge Deller <deller@gmx.de>
24
Signed-off-by: Jason Wang <jasowang@redhat.com>
25
---
26
hw/net/tulip.c | 6 ------
27
1 file changed, 6 deletions(-)
28
29
diff --git a/hw/net/tulip.c b/hw/net/tulip.c
30
index XXXXXXX..XXXXXXX 100644
31
--- a/hw/net/tulip.c
32
+++ b/hw/net/tulip.c
33
@@ -XXX,XX +XXX,XX @@ static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc)
34
len = s->rx_frame_len;
35
}
36
37
- if (s->rx_frame_len + len > sizeof(s->rx_frame)) {
38
- return;
39
- }
40
pci_dma_write(&s->dev, desc->buf_addr1, s->rx_frame +
41
(s->rx_frame_size - s->rx_frame_len), len);
42
s->rx_frame_len -= len;
43
@@ -XXX,XX +XXX,XX @@ static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc)
44
len = s->rx_frame_len;
45
}
46
47
- if (s->rx_frame_len + len > sizeof(s->rx_frame)) {
48
- return;
49
- }
50
pci_dma_write(&s->dev, desc->buf_addr2, s->rx_frame +
51
(s->rx_frame_size - s->rx_frame_len), len);
52
s->rx_frame_len -= len;
53
--
54
2.5.0
55
56
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
Bit #14 is "DE" for 'Descriptor Error':
4
5
When set, indicates a frame truncation caused by a frame
6
that does not fit within the current descriptor buffers,
7
and that the 21143 does not own the next descriptor.
8
9
[Table 4-1. RDES0 Bit Fields Description]
10
11
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
12
Signed-off-by: Jason Wang <jasowang@redhat.com>
13
---
14
hw/net/tulip.h | 2 +-
15
1 file changed, 1 insertion(+), 1 deletion(-)
16
17
diff --git a/hw/net/tulip.h b/hw/net/tulip.h
18
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/net/tulip.h
20
+++ b/hw/net/tulip.h
21
@@ -XXX,XX +XXX,XX @@
22
#define RDES0_RF BIT(11)
23
#define RDES0_DT_SHIFT 12
24
#define RDES0_DT_MASK 3
25
-#define RDES0_LE BIT(14)
26
+#define RDES0_DE BIT(14)
27
#define RDES0_ES BIT(15)
28
#define RDES0_FL_SHIFT 16
29
#define RDES0_FL_MASK 0x3fff
30
--
31
2.5.0
32
33
diff view generated by jsdifflib
New patch
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
2
3
Log with GUEST_ERROR what the guest is doing wrong.
4
5
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Signed-off-by: Jason Wang <jasowang@redhat.com>
7
---
8
hw/net/tulip.c | 6 ++++++
9
1 file changed, 6 insertions(+)
10
11
diff --git a/hw/net/tulip.c b/hw/net/tulip.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/hw/net/tulip.c
14
+++ b/hw/net/tulip.c
15
@@ -XXX,XX +XXX,XX @@ static int tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc)
16
int len2 = (desc->control >> TDES1_BUF2_SIZE_SHIFT) & TDES1_BUF2_SIZE_MASK;
17
18
if (s->tx_frame_len + len1 > sizeof(s->tx_frame)) {
19
+ qemu_log_mask(LOG_GUEST_ERROR,
20
+ "%s: descriptor overflow (ofs: %u, len:%d, size:%zu)\n",
21
+ __func__, s->tx_frame_len, len1, sizeof(s->tx_frame));
22
return -1;
23
}
24
if (len1) {
25
@@ -XXX,XX +XXX,XX @@ static int tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc)
26
}
27
28
if (s->tx_frame_len + len2 > sizeof(s->tx_frame)) {
29
+ qemu_log_mask(LOG_GUEST_ERROR,
30
+ "%s: descriptor overflow (ofs: %u, len:%d, size:%zu)\n",
31
+ __func__, s->tx_frame_len, len2, sizeof(s->tx_frame));
32
return -1;
33
}
34
if (len2) {
35
--
36
2.5.0
37
38
diff view generated by jsdifflib
New patch
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
1
2
3
Enabling debug breaks the build, Fix them and make debug statements
4
always compilable. Fix few statements to use sized integer casting.
5
6
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
7
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
10
hw/net/cadence_gem.c | 27 +++++++++++++--------------
11
1 file changed, 13 insertions(+), 14 deletions(-)
12
13
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/net/cadence_gem.c
16
+++ b/hw/net/cadence_gem.c
17
@@ -XXX,XX +XXX,XX @@
18
#include "sysemu/dma.h"
19
#include "net/checksum.h"
20
21
-#ifdef CADENCE_GEM_ERR_DEBUG
22
-#define DB_PRINT(...) do { \
23
- fprintf(stderr, ": %s: ", __func__); \
24
- fprintf(stderr, ## __VA_ARGS__); \
25
- } while (0)
26
-#else
27
- #define DB_PRINT(...)
28
-#endif
29
+#define CADENCE_GEM_ERR_DEBUG 0
30
+#define DB_PRINT(...) do {\
31
+ if (CADENCE_GEM_ERR_DEBUG) { \
32
+ qemu_log(": %s: ", __func__); \
33
+ qemu_log(__VA_ARGS__); \
34
+ } \
35
+} while (0)
36
37
#define GEM_NWCTRL (0x00000000/4) /* Network Control reg */
38
#define GEM_NWCFG (0x00000004/4) /* Network Config reg */
39
@@ -XXX,XX +XXX,XX @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
40
size += 4;
41
}
42
43
- DB_PRINT("config bufsize: %d packet size: %ld\n", rxbufsize, size);
44
+ DB_PRINT("config bufsize: %u packet size: %zd\n", rxbufsize, size);
45
46
/* Find which queue we are targeting */
47
q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize);
48
@@ -XXX,XX +XXX,XX @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
49
return -1;
50
}
51
52
- DB_PRINT("copy %u bytes to 0x%" PRIx64 "\n",
53
- MIN(bytes_to_copy, rxbufsize),
54
- rx_desc_get_buffer(s, s->rx_desc[q]));
55
+ DB_PRINT("copy %" PRIu32 " bytes to 0x%" PRIx64 "\n",
56
+ MIN(bytes_to_copy, rxbufsize),
57
+ rx_desc_get_buffer(s, s->rx_desc[q]));
58
59
/* Copy packet data to emulated DMA buffer */
60
address_space_write(&s->dma_as, rx_desc_get_buffer(s, s->rx_desc[q]) +
61
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
62
*/
63
if ((tx_desc_get_buffer(s, desc) == 0) ||
64
(tx_desc_get_length(desc) == 0)) {
65
- DB_PRINT("Invalid TX descriptor @ 0x%x\n",
66
- (unsigned)packet_desc_addr);
67
+ DB_PRINT("Invalid TX descriptor @ 0x%" HWADDR_PRIx "\n",
68
+ packet_desc_addr);
69
break;
70
}
71
72
--
73
2.5.0
74
75
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
2
2
3
Added function that loads RSS eBPF program.
3
During wrap around and reset, queues are pointing to initial base
4
Added stub functions for RSS eBPF loader.
4
address of queue 0, irrespective of what queue we are dealing with.
5
Added meson and configuration options.
5
Fix it by assigning proper base address every time.
6
6
7
By default, eBPF feature enabled if libbpf is present in the build system.
7
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
8
libbpf checked in configuration shell script and meson script.
8
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
9
10
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
11
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
12
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
13
---
10
---
14
configure | 8 +-
11
hw/net/cadence_gem.c | 37 +++++++++++++++++++++++++++++++++----
15
ebpf/ebpf_rss-stub.c | 40 +++++
12
1 file changed, 33 insertions(+), 4 deletions(-)
16
ebpf/ebpf_rss.c | 165 ++++++++++++++++++
17
ebpf/ebpf_rss.h | 44 +++++
18
ebpf/meson.build | 1 +
19
ebpf/rss.bpf.skeleton.h | 431 ++++++++++++++++++++++++++++++++++++++++++++++++
20
ebpf/trace-events | 4 +
21
ebpf/trace.h | 1 +
22
meson.build | 23 +++
23
meson_options.txt | 2 +
24
10 files changed, 718 insertions(+), 1 deletion(-)
25
create mode 100644 ebpf/ebpf_rss-stub.c
26
create mode 100644 ebpf/ebpf_rss.c
27
create mode 100644 ebpf/ebpf_rss.h
28
create mode 100644 ebpf/meson.build
29
create mode 100644 ebpf/rss.bpf.skeleton.h
30
create mode 100644 ebpf/trace-events
31
create mode 100644 ebpf/trace.h
32
13
33
diff --git a/configure b/configure
14
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
34
index XXXXXXX..XXXXXXX 100755
15
index XXXXXXX..XXXXXXX 100644
35
--- a/configure
16
--- a/hw/net/cadence_gem.c
36
+++ b/configure
17
+++ b/hw/net/cadence_gem.c
37
@@ -XXX,XX +XXX,XX @@ vhost_vsock="$default_feature"
18
@@ -XXX,XX +XXX,XX @@ static int get_queue_from_screen(CadenceGEMState *s, uint8_t *rxbuf_ptr,
38
vhost_user="no"
19
return 0;
39
vhost_user_blk_server="auto"
20
}
40
vhost_user_fs="$default_feature"
21
41
+bpf="auto"
22
+static uint32_t gem_get_queue_base_addr(CadenceGEMState *s, bool tx, int q)
42
kvm="auto"
23
+{
43
hax="auto"
24
+ uint32_t base_addr = 0;
44
hvf="auto"
45
@@ -XXX,XX +XXX,XX @@ for opt do
46
;;
47
--enable-membarrier) membarrier="yes"
48
;;
49
+ --disable-bpf) bpf="disabled"
50
+ ;;
51
+ --enable-bpf) bpf="enabled"
52
+ ;;
53
--disable-blobs) blobs="false"
54
;;
55
--with-pkgversion=*) pkgversion="$optarg"
56
@@ -XXX,XX +XXX,XX @@ disabled with --disable-FEATURE, default is enabled if available
57
vhost-user vhost-user backend support
58
vhost-user-blk-server vhost-user-blk server support
59
vhost-vdpa vhost-vdpa kernel backend support
60
+ bpf BPF kernel support
61
spice spice
62
rbd rados block device (rbd)
63
libiscsi iscsi support
64
@@ -XXX,XX +XXX,XX @@ NINJA=$ninja $meson setup \
65
-Dattr=$attr -Ddefault_devices=$default_devices \
66
-Ddocs=$docs -Dsphinx_build=$sphinx_build -Dinstall_blobs=$blobs \
67
-Dvhost_user_blk_server=$vhost_user_blk_server -Dmultiprocess=$multiprocess \
68
- -Dfuse=$fuse -Dfuse_lseek=$fuse_lseek -Dguest_agent_msi=$guest_agent_msi \
69
+ -Dfuse=$fuse -Dfuse_lseek=$fuse_lseek -Dguest_agent_msi=$guest_agent_msi -Dbpf=$bpf\
70
$(if test "$default_features" = no; then echo "-Dauto_features=disabled"; fi) \
71
    -Dtcg_interpreter=$tcg_interpreter \
72
$cross_arg \
73
diff --git a/ebpf/ebpf_rss-stub.c b/ebpf/ebpf_rss-stub.c
74
new file mode 100644
75
index XXXXXXX..XXXXXXX
76
--- /dev/null
77
+++ b/ebpf/ebpf_rss-stub.c
78
@@ -XXX,XX +XXX,XX @@
79
+/*
80
+ * eBPF RSS stub file
81
+ *
82
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
83
+ *
84
+ * Authors:
85
+ * Yuri Benditovich <yuri.benditovich@daynix.com>
86
+ *
87
+ * This work is licensed under the terms of the GNU GPL, version 2. See
88
+ * the COPYING file in the top-level directory.
89
+ */
90
+
25
+
91
+#include "qemu/osdep.h"
26
+ switch (q) {
92
+#include "ebpf/ebpf_rss.h"
27
+ case 0:
28
+ base_addr = s->regs[tx ? GEM_TXQBASE : GEM_RXQBASE];
29
+ break;
30
+ case 1 ... (MAX_PRIORITY_QUEUES - 1):
31
+ base_addr = s->regs[(tx ? GEM_TRANSMIT_Q1_PTR :
32
+ GEM_RECEIVE_Q1_PTR) + q - 1];
33
+ break;
34
+ default:
35
+ g_assert_not_reached();
36
+ };
93
+
37
+
94
+void ebpf_rss_init(struct EBPFRSSContext *ctx)
38
+ return base_addr;
95
+{
96
+
97
+}
39
+}
98
+
40
+
99
+bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
41
+static inline uint32_t gem_get_tx_queue_base_addr(CadenceGEMState *s, int q)
100
+{
42
+{
101
+ return false;
43
+ return gem_get_queue_base_addr(s, true, q);
102
+}
44
+}
103
+
45
+
104
+bool ebpf_rss_load(struct EBPFRSSContext *ctx)
46
+static inline uint32_t gem_get_rx_queue_base_addr(CadenceGEMState *s, int q)
105
+{
47
+{
106
+ return false;
48
+ return gem_get_queue_base_addr(s, false, q);
107
+}
49
+}
108
+
50
+
109
+bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
51
static hwaddr gem_get_desc_addr(CadenceGEMState *s, bool tx, int q)
110
+ uint16_t *indirections_table, uint8_t *toeplitz_key)
52
{
111
+{
53
hwaddr desc_addr = 0;
112
+ return false;
54
@@ -XXX,XX +XXX,XX @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
113
+}
55
/* Next descriptor */
114
+
56
if (rx_desc_get_wrap(s->rx_desc[q])) {
115
+void ebpf_rss_unload(struct EBPFRSSContext *ctx)
57
DB_PRINT("wrapping RX descriptor list\n");
116
+{
58
- s->rx_desc_addr[q] = s->regs[GEM_RXQBASE];
117
+
59
+ s->rx_desc_addr[q] = gem_get_rx_queue_base_addr(s, q);
118
+}
60
} else {
119
diff --git a/ebpf/ebpf_rss.c b/ebpf/ebpf_rss.c
61
DB_PRINT("incrementing RX descriptor list\n");
120
new file mode 100644
62
s->rx_desc_addr[q] += 4 * gem_get_desc_len(s, true);
121
index XXXXXXX..XXXXXXX
63
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
122
--- /dev/null
64
sizeof(desc_first));
123
+++ b/ebpf/ebpf_rss.c
65
/* Advance the hardware current descriptor past this packet */
124
@@ -XXX,XX +XXX,XX @@
66
if (tx_desc_get_wrap(desc)) {
125
+/*
67
- s->tx_desc_addr[q] = s->regs[GEM_TXQBASE];
126
+ * eBPF RSS loader
68
+ s->tx_desc_addr[q] = gem_get_tx_queue_base_addr(s, q);
127
+ *
69
} else {
128
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
70
s->tx_desc_addr[q] = packet_desc_addr +
129
+ *
71
4 * gem_get_desc_len(s, false);
130
+ * Authors:
72
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
131
+ * Andrew Melnychenko <andrew@daynix.com>
73
} else {
132
+ * Yuri Benditovich <yuri.benditovich@daynix.com>
74
packet_desc_addr = 0;
133
+ *
75
}
134
+ * This work is licensed under the terms of the GNU GPL, version 2. See
76
- packet_desc_addr |= s->regs[GEM_TXQBASE];
135
+ * the COPYING file in the top-level directory.
77
+ packet_desc_addr |= gem_get_tx_queue_base_addr(s, q);
136
+ */
78
} else {
137
+
79
packet_desc_addr += 4 * gem_get_desc_len(s, false);
138
+#include "qemu/osdep.h"
80
}
139
+#include "qemu/error-report.h"
81
@@ -XXX,XX +XXX,XX @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
140
+
82
if (!(val & GEM_NWCTRL_TXENA)) {
141
+#include <bpf/libbpf.h>
83
/* Reset to start of Q when transmit disabled. */
142
+#include <bpf/bpf.h>
84
for (i = 0; i < s->num_priority_queues; i++) {
143
+
85
- s->tx_desc_addr[i] = s->regs[GEM_TXQBASE];
144
+#include "hw/virtio/virtio-net.h" /* VIRTIO_NET_RSS_MAX_TABLE_LEN */
86
+ s->tx_desc_addr[i] = gem_get_tx_queue_base_addr(s, i);
145
+
87
}
146
+#include "ebpf/ebpf_rss.h"
88
}
147
+#include "ebpf/rss.bpf.skeleton.h"
89
if (gem_can_receive(qemu_get_queue(s->nic))) {
148
+#include "trace.h"
149
+
150
+void ebpf_rss_init(struct EBPFRSSContext *ctx)
151
+{
152
+ if (ctx != NULL) {
153
+ ctx->obj = NULL;
154
+ }
155
+}
156
+
157
+bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx)
158
+{
159
+ return ctx != NULL && ctx->obj != NULL;
160
+}
161
+
162
+bool ebpf_rss_load(struct EBPFRSSContext *ctx)
163
+{
164
+ struct rss_bpf *rss_bpf_ctx;
165
+
166
+ if (ctx == NULL) {
167
+ return false;
168
+ }
169
+
170
+ rss_bpf_ctx = rss_bpf__open();
171
+ if (rss_bpf_ctx == NULL) {
172
+ trace_ebpf_error("eBPF RSS", "can not open eBPF RSS object");
173
+ goto error;
174
+ }
175
+
176
+ bpf_program__set_socket_filter(rss_bpf_ctx->progs.tun_rss_steering_prog);
177
+
178
+ if (rss_bpf__load(rss_bpf_ctx)) {
179
+ trace_ebpf_error("eBPF RSS", "can not load RSS program");
180
+ goto error;
181
+ }
182
+
183
+ ctx->obj = rss_bpf_ctx;
184
+ ctx->program_fd = bpf_program__fd(
185
+ rss_bpf_ctx->progs.tun_rss_steering_prog);
186
+ ctx->map_configuration = bpf_map__fd(
187
+ rss_bpf_ctx->maps.tap_rss_map_configurations);
188
+ ctx->map_indirections_table = bpf_map__fd(
189
+ rss_bpf_ctx->maps.tap_rss_map_indirection_table);
190
+ ctx->map_toeplitz_key = bpf_map__fd(
191
+ rss_bpf_ctx->maps.tap_rss_map_toeplitz_key);
192
+
193
+ return true;
194
+error:
195
+ rss_bpf__destroy(rss_bpf_ctx);
196
+ ctx->obj = NULL;
197
+
198
+ return false;
199
+}
200
+
201
+static bool ebpf_rss_set_config(struct EBPFRSSContext *ctx,
202
+ struct EBPFRSSConfig *config)
203
+{
204
+ uint32_t map_key = 0;
205
+
206
+ if (!ebpf_rss_is_loaded(ctx)) {
207
+ return false;
208
+ }
209
+ if (bpf_map_update_elem(ctx->map_configuration,
210
+ &map_key, config, 0) < 0) {
211
+ return false;
212
+ }
213
+ return true;
214
+}
215
+
216
+static bool ebpf_rss_set_indirections_table(struct EBPFRSSContext *ctx,
217
+ uint16_t *indirections_table,
218
+ size_t len)
219
+{
220
+ uint32_t i = 0;
221
+
222
+ if (!ebpf_rss_is_loaded(ctx) || indirections_table == NULL ||
223
+ len > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
224
+ return false;
225
+ }
226
+
227
+ for (; i < len; ++i) {
228
+ if (bpf_map_update_elem(ctx->map_indirections_table, &i,
229
+ indirections_table + i, 0) < 0) {
230
+ return false;
231
+ }
232
+ }
233
+ return true;
234
+}
235
+
236
+static bool ebpf_rss_set_toepliz_key(struct EBPFRSSContext *ctx,
237
+ uint8_t *toeplitz_key)
238
+{
239
+ uint32_t map_key = 0;
240
+
241
+ /* prepare toeplitz key */
242
+ uint8_t toe[VIRTIO_NET_RSS_MAX_KEY_SIZE] = {};
243
+
244
+ if (!ebpf_rss_is_loaded(ctx) || toeplitz_key == NULL) {
245
+ return false;
246
+ }
247
+ memcpy(toe, toeplitz_key, VIRTIO_NET_RSS_MAX_KEY_SIZE);
248
+ *(uint32_t *)toe = ntohl(*(uint32_t *)toe);
249
+
250
+ if (bpf_map_update_elem(ctx->map_toeplitz_key, &map_key, toe,
251
+ 0) < 0) {
252
+ return false;
253
+ }
254
+ return true;
255
+}
256
+
257
+bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
258
+ uint16_t *indirections_table, uint8_t *toeplitz_key)
259
+{
260
+ if (!ebpf_rss_is_loaded(ctx) || config == NULL ||
261
+ indirections_table == NULL || toeplitz_key == NULL) {
262
+ return false;
263
+ }
264
+
265
+ if (!ebpf_rss_set_config(ctx, config)) {
266
+ return false;
267
+ }
268
+
269
+ if (!ebpf_rss_set_indirections_table(ctx, indirections_table,
270
+ config->indirections_len)) {
271
+ return false;
272
+ }
273
+
274
+ if (!ebpf_rss_set_toepliz_key(ctx, toeplitz_key)) {
275
+ return false;
276
+ }
277
+
278
+ return true;
279
+}
280
+
281
+void ebpf_rss_unload(struct EBPFRSSContext *ctx)
282
+{
283
+ if (!ebpf_rss_is_loaded(ctx)) {
284
+ return;
285
+ }
286
+
287
+ rss_bpf__destroy(ctx->obj);
288
+ ctx->obj = NULL;
289
+}
290
diff --git a/ebpf/ebpf_rss.h b/ebpf/ebpf_rss.h
291
new file mode 100644
292
index XXXXXXX..XXXXXXX
293
--- /dev/null
294
+++ b/ebpf/ebpf_rss.h
295
@@ -XXX,XX +XXX,XX @@
296
+/*
297
+ * eBPF RSS header
298
+ *
299
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
300
+ *
301
+ * Authors:
302
+ * Andrew Melnychenko <andrew@daynix.com>
303
+ * Yuri Benditovich <yuri.benditovich@daynix.com>
304
+ *
305
+ * This work is licensed under the terms of the GNU GPL, version 2. See
306
+ * the COPYING file in the top-level directory.
307
+ */
308
+
309
+#ifndef QEMU_EBPF_RSS_H
310
+#define QEMU_EBPF_RSS_H
311
+
312
+struct EBPFRSSContext {
313
+ void *obj;
314
+ int program_fd;
315
+ int map_configuration;
316
+ int map_toeplitz_key;
317
+ int map_indirections_table;
318
+};
319
+
320
+struct EBPFRSSConfig {
321
+ uint8_t redirect;
322
+ uint8_t populate_hash;
323
+ uint32_t hash_types;
324
+ uint16_t indirections_len;
325
+ uint16_t default_queue;
326
+} __attribute__((packed));
327
+
328
+void ebpf_rss_init(struct EBPFRSSContext *ctx);
329
+
330
+bool ebpf_rss_is_loaded(struct EBPFRSSContext *ctx);
331
+
332
+bool ebpf_rss_load(struct EBPFRSSContext *ctx);
333
+
334
+bool ebpf_rss_set_all(struct EBPFRSSContext *ctx, struct EBPFRSSConfig *config,
335
+ uint16_t *indirections_table, uint8_t *toeplitz_key);
336
+
337
+void ebpf_rss_unload(struct EBPFRSSContext *ctx);
338
+
339
+#endif /* QEMU_EBPF_RSS_H */
340
diff --git a/ebpf/meson.build b/ebpf/meson.build
341
new file mode 100644
342
index XXXXXXX..XXXXXXX
343
--- /dev/null
344
+++ b/ebpf/meson.build
345
@@ -0,0 +1 @@
346
+common_ss.add(when: libbpf, if_true: files('ebpf_rss.c'), if_false: files('ebpf_rss-stub.c'))
347
diff --git a/ebpf/rss.bpf.skeleton.h b/ebpf/rss.bpf.skeleton.h
348
new file mode 100644
349
index XXXXXXX..XXXXXXX
350
--- /dev/null
351
+++ b/ebpf/rss.bpf.skeleton.h
352
@@ -XXX,XX +XXX,XX @@
353
+/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
354
+
355
+/* THIS FILE IS AUTOGENERATED! */
356
+#ifndef __RSS_BPF_SKEL_H__
357
+#define __RSS_BPF_SKEL_H__
358
+
359
+#include <stdlib.h>
360
+#include <bpf/libbpf.h>
361
+
362
+struct rss_bpf {
363
+    struct bpf_object_skeleton *skeleton;
364
+    struct bpf_object *obj;
365
+    struct {
366
+        struct bpf_map *tap_rss_map_configurations;
367
+        struct bpf_map *tap_rss_map_indirection_table;
368
+        struct bpf_map *tap_rss_map_toeplitz_key;
369
+    } maps;
370
+    struct {
371
+        struct bpf_program *tun_rss_steering_prog;
372
+    } progs;
373
+    struct {
374
+        struct bpf_link *tun_rss_steering_prog;
375
+    } links;
376
+};
377
+
378
+static void
379
+rss_bpf__destroy(struct rss_bpf *obj)
380
+{
381
+    if (!obj)
382
+        return;
383
+    if (obj->skeleton)
384
+        bpf_object__destroy_skeleton(obj->skeleton);
385
+    free(obj);
386
+}
387
+
388
+static inline int
389
+rss_bpf__create_skeleton(struct rss_bpf *obj);
390
+
391
+static inline struct rss_bpf *
392
+rss_bpf__open_opts(const struct bpf_object_open_opts *opts)
393
+{
394
+    struct rss_bpf *obj;
395
+
396
+    obj = (struct rss_bpf *)calloc(1, sizeof(*obj));
397
+    if (!obj)
398
+        return NULL;
399
+    if (rss_bpf__create_skeleton(obj))
400
+        goto err;
401
+    if (bpf_object__open_skeleton(obj->skeleton, opts))
402
+        goto err;
403
+
404
+    return obj;
405
+err:
406
+    rss_bpf__destroy(obj);
407
+    return NULL;
408
+}
409
+
410
+static inline struct rss_bpf *
411
+rss_bpf__open(void)
412
+{
413
+    return rss_bpf__open_opts(NULL);
414
+}
415
+
416
+static inline int
417
+rss_bpf__load(struct rss_bpf *obj)
418
+{
419
+    return bpf_object__load_skeleton(obj->skeleton);
420
+}
421
+
422
+static inline struct rss_bpf *
423
+rss_bpf__open_and_load(void)
424
+{
425
+    struct rss_bpf *obj;
426
+
427
+    obj = rss_bpf__open();
428
+    if (!obj)
429
+        return NULL;
430
+    if (rss_bpf__load(obj)) {
431
+        rss_bpf__destroy(obj);
432
+        return NULL;
433
+    }
434
+    return obj;
435
+}
436
+
437
+static inline int
438
+rss_bpf__attach(struct rss_bpf *obj)
439
+{
440
+    return bpf_object__attach_skeleton(obj->skeleton);
441
+}
442
+
443
+static inline void
444
+rss_bpf__detach(struct rss_bpf *obj)
445
+{
446
+    return bpf_object__detach_skeleton(obj->skeleton);
447
+}
448
+
449
+static inline int
450
+rss_bpf__create_skeleton(struct rss_bpf *obj)
451
+{
452
+    struct bpf_object_skeleton *s;
453
+
454
+    s = (struct bpf_object_skeleton *)calloc(1, sizeof(*s));
455
+    if (!s)
456
+        return -1;
457
+    obj->skeleton = s;
458
+
459
+    s->sz = sizeof(*s);
460
+    s->name = "rss_bpf";
461
+    s->obj = &obj->obj;
462
+
463
+    /* maps */
464
+    s->map_cnt = 3;
465
+    s->map_skel_sz = sizeof(*s->maps);
466
+    s->maps = (struct bpf_map_skeleton *)calloc(s->map_cnt, s->map_skel_sz);
467
+    if (!s->maps)
468
+        goto err;
469
+
470
+    s->maps[0].name = "tap_rss_map_configurations";
471
+    s->maps[0].map = &obj->maps.tap_rss_map_configurations;
472
+
473
+    s->maps[1].name = "tap_rss_map_indirection_table";
474
+    s->maps[1].map = &obj->maps.tap_rss_map_indirection_table;
475
+
476
+    s->maps[2].name = "tap_rss_map_toeplitz_key";
477
+    s->maps[2].map = &obj->maps.tap_rss_map_toeplitz_key;
478
+
479
+    /* programs */
480
+    s->prog_cnt = 1;
481
+    s->prog_skel_sz = sizeof(*s->progs);
482
+    s->progs = (struct bpf_prog_skeleton *)calloc(s->prog_cnt, s->prog_skel_sz);
483
+    if (!s->progs)
484
+        goto err;
485
+
486
+    s->progs[0].name = "tun_rss_steering_prog";
487
+    s->progs[0].prog = &obj->progs.tun_rss_steering_prog;
488
+    s->progs[0].link = &obj->links.tun_rss_steering_prog;
489
+
490
+    s->data_sz = 8088;
491
+    s->data = (void *)"\
492
+\x7f\x45\x4c\x46\x02\x01\x01\0\0\0\0\0\0\0\0\0\x01\0\xf7\0\x01\0\0\0\0\0\0\0\0\
493
+\0\0\0\0\0\0\0\0\0\0\0\x18\x1d\0\0\0\0\0\0\0\0\0\0\x40\0\0\0\0\0\x40\0\x0a\0\
494
+\x01\0\xbf\x18\0\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\x4c\xff\0\0\0\0\xbf\xa7\
495
+\0\0\0\0\0\0\x07\x07\0\0\x4c\xff\xff\xff\x18\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
496
+\xbf\x72\0\0\0\0\0\0\x85\0\0\0\x01\0\0\0\xbf\x06\0\0\0\0\0\0\x18\x01\0\0\0\0\0\
497
+\0\0\0\0\0\0\0\0\0\xbf\x72\0\0\0\0\0\0\x85\0\0\0\x01\0\0\0\xbf\x07\0\0\0\0\0\0\
498
+\x18\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0\x15\x06\x66\x02\0\0\0\0\xbf\x79\0\0\
499
+\0\0\0\0\x15\x09\x64\x02\0\0\0\0\x71\x61\0\0\0\0\0\0\x55\x01\x01\0\0\0\0\0\x05\
500
+\0\x5d\x02\0\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\xc0\xff\0\0\0\0\x7b\x1a\xb8\xff\
501
+\0\0\0\0\x7b\x1a\xb0\xff\0\0\0\0\x7b\x1a\xa8\xff\0\0\0\0\x7b\x1a\xa0\xff\0\0\0\
502
+\0\x63\x1a\x98\xff\0\0\0\0\x7b\x1a\x90\xff\0\0\0\0\x7b\x1a\x88\xff\0\0\0\0\x7b\
503
+\x1a\x80\xff\0\0\0\0\x7b\x1a\x78\xff\0\0\0\0\x7b\x1a\x70\xff\0\0\0\0\x7b\x1a\
504
+\x68\xff\0\0\0\0\x7b\x1a\x60\xff\0\0\0\0\x7b\x1a\x58\xff\0\0\0\0\x7b\x1a\x50\
505
+\xff\0\0\0\0\x15\x08\x4c\x02\0\0\0\0\x6b\x1a\xd0\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\
506
+\0\x07\x03\0\0\xd0\xff\xff\xff\xbf\x81\0\0\0\0\0\0\xb7\x02\0\0\x0c\0\0\0\xb7\
507
+\x04\0\0\x02\0\0\0\xb7\x05\0\0\0\0\0\0\x85\0\0\0\x44\0\0\0\x67\0\0\0\x20\0\0\0\
508
+\x77\0\0\0\x20\0\0\0\x55\0\x11\0\0\0\0\0\xb7\x02\0\0\x10\0\0\0\x69\xa1\xd0\xff\
509
+\0\0\0\0\xbf\x13\0\0\0\0\0\0\xdc\x03\0\0\x10\0\0\0\x15\x03\x02\0\0\x81\0\0\x55\
510
+\x03\x0c\0\xa8\x88\0\0\xb7\x02\0\0\x14\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\
511
+\xd0\xff\xff\xff\xbf\x81\0\0\0\0\0\0\xb7\x04\0\0\x02\0\0\0\xb7\x05\0\0\0\0\0\0\
512
+\x85\0\0\0\x44\0\0\0\x69\xa1\xd0\xff\0\0\0\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\
513
+\0\0\0\x15\0\x01\0\0\0\0\0\x05\0\x2f\x02\0\0\0\0\x15\x01\x2e\x02\0\0\0\0\x7b\
514
+\x9a\x30\xff\0\0\0\0\x15\x01\x57\0\x86\xdd\0\0\x55\x01\x3b\0\x08\0\0\0\x7b\x7a\
515
+\x20\xff\0\0\0\0\xb7\x07\0\0\x01\0\0\0\x73\x7a\x50\xff\0\0\0\0\xb7\x01\0\0\0\0\
516
+\0\0\x63\x1a\xe0\xff\0\0\0\0\x7b\x1a\xd8\xff\0\0\0\0\x7b\x1a\xd0\xff\0\0\0\0\
517
+\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xd0\xff\xff\xff\xbf\x81\0\0\0\0\0\0\xb7\x02\0\
518
+\0\0\0\0\0\xb7\x04\0\0\x14\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\x67\
519
+\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x55\0\x1a\x02\0\0\0\0\x69\xa1\xd6\xff\0\0\
520
+\0\0\x55\x01\x01\0\0\0\0\0\xb7\x07\0\0\0\0\0\0\x61\xa1\xdc\xff\0\0\0\0\x63\x1a\
521
+\x5c\xff\0\0\0\0\x61\xa1\xe0\xff\0\0\0\0\x63\x1a\x60\xff\0\0\0\0\x73\x7a\x56\
522
+\xff\0\0\0\0\x71\xa9\xd9\xff\0\0\0\0\x71\xa1\xd0\xff\0\0\0\0\x67\x01\0\0\x02\0\
523
+\0\0\x57\x01\0\0\x3c\0\0\0\x7b\x1a\x40\xff\0\0\0\0\x79\xa7\x20\xff\0\0\0\0\xbf\
524
+\x91\0\0\0\0\0\0\x57\x01\0\0\xff\0\0\0\x15\x01\x19\0\0\0\0\0\x71\xa1\x56\xff\0\
525
+\0\0\0\x55\x01\x17\0\0\0\0\0\x57\x09\0\0\xff\0\0\0\x15\x09\x7a\x01\x11\0\0\0\
526
+\x55\x09\x14\0\x06\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x53\xff\0\0\0\0\xb7\x01\
527
+\0\0\0\0\0\0\x63\x1a\xe0\xff\0\0\0\0\x7b\x1a\xd8\xff\0\0\0\0\x7b\x1a\xd0\xff\0\
528
+\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xd0\xff\xff\xff\xbf\x81\0\0\0\0\0\0\x79\
529
+\xa2\x40\xff\0\0\0\0\xb7\x04\0\0\x14\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\
530
+\0\0\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x55\0\xf4\x01\0\0\0\0\x69\xa1\
531
+\xd0\xff\0\0\0\0\x6b\x1a\x58\xff\0\0\0\0\x69\xa1\xd2\xff\0\0\0\0\x6b\x1a\x5a\
532
+\xff\0\0\0\0\x71\xa1\x50\xff\0\0\0\0\x15\x01\xd4\0\0\0\0\0\x71\x62\x03\0\0\0\0\
533
+\0\x67\x02\0\0\x08\0\0\0\x71\x61\x02\0\0\0\0\0\x4f\x12\0\0\0\0\0\0\x71\x63\x04\
534
+\0\0\0\0\0\x71\x61\x05\0\0\0\0\0\x67\x01\0\0\x08\0\0\0\x4f\x31\0\0\0\0\0\0\x67\
535
+\x01\0\0\x10\0\0\0\x4f\x21\0\0\0\0\0\0\x71\xa2\x53\xff\0\0\0\0\x79\xa0\x30\xff\
536
+\0\0\0\0\x15\x02\x06\x01\0\0\0\0\xbf\x12\0\0\0\0\0\0\x57\x02\0\0\x02\0\0\0\x15\
537
+\x02\x03\x01\0\0\0\0\x61\xa1\x5c\xff\0\0\0\0\x63\x1a\xa0\xff\0\0\0\0\x61\xa1\
538
+\x60\xff\0\0\0\0\x63\x1a\xa4\xff\0\0\0\0\x69\xa1\x58\xff\0\0\0\0\x6b\x1a\xa8\
539
+\xff\0\0\0\0\x69\xa1\x5a\xff\0\0\0\0\x6b\x1a\xaa\xff\0\0\0\0\x05\0\x65\x01\0\0\
540
+\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x51\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x7b\x1a\
541
+\xf0\xff\0\0\0\0\x7b\x1a\xe8\xff\0\0\0\0\x7b\x1a\xe0\xff\0\0\0\0\x7b\x1a\xd8\
542
+\xff\0\0\0\0\x7b\x1a\xd0\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xd0\xff\
543
+\xff\xff\xb7\x01\0\0\x28\0\0\0\x7b\x1a\x40\xff\0\0\0\0\xbf\x81\0\0\0\0\0\0\xb7\
544
+\x02\0\0\0\0\0\0\xb7\x04\0\0\x28\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\
545
+\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x55\0\x10\x01\0\0\0\0\x79\xa1\xe0\
546
+\xff\0\0\0\0\x63\x1a\x64\xff\0\0\0\0\x77\x01\0\0\x20\0\0\0\x63\x1a\x68\xff\0\0\
547
+\0\0\x79\xa1\xd8\xff\0\0\0\0\x63\x1a\x5c\xff\0\0\0\0\x77\x01\0\0\x20\0\0\0\x63\
548
+\x1a\x60\xff\0\0\0\0\x79\xa1\xe8\xff\0\0\0\0\x63\x1a\x6c\xff\0\0\0\0\x77\x01\0\
549
+\0\x20\0\0\0\x63\x1a\x70\xff\0\0\0\0\x79\xa1\xf0\xff\0\0\0\0\x63\x1a\x74\xff\0\
550
+\0\0\0\x77\x01\0\0\x20\0\0\0\x63\x1a\x78\xff\0\0\0\0\x71\xa9\xd6\xff\0\0\0\0\
551
+\x25\x09\xff\0\x3c\0\0\0\xb7\x01\0\0\x01\0\0\0\x6f\x91\0\0\0\0\0\0\x18\x02\0\0\
552
+\x01\0\0\0\0\0\0\0\0\x18\0\x1c\x5f\x21\0\0\0\0\0\0\x55\x01\x01\0\0\0\0\0\x05\0\
553
+\xf8\0\0\0\0\0\xb7\x01\0\0\0\0\0\0\x6b\x1a\xfe\xff\0\0\0\0\xb7\x01\0\0\x28\0\0\
554
+\0\x7b\x1a\x40\xff\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\x8c\xff\xff\xff\x7b\
555
+\x1a\x18\xff\0\0\0\0\xbf\xa1\0\0\0\0\0\0\x07\x01\0\0\x7c\xff\xff\xff\x7b\x1a\
556
+\x10\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x7b\x1a\x28\xff\0\0\0\0\x7b\x7a\x20\xff\0\
557
+\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xfe\xff\xff\xff\xbf\x81\0\0\0\0\0\0\x79\
558
+\xa2\x40\xff\0\0\0\0\xb7\x04\0\0\x02\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\
559
+\0\0\0\x67\0\0\0\x20\0\0\0\x77\0\0\0\x20\0\0\0\x15\0\x01\0\0\0\0\0\x05\0\x90\
560
+\x01\0\0\0\0\xbf\x91\0\0\0\0\0\0\x15\x01\x23\0\x3c\0\0\0\x15\x01\x59\0\x2c\0\0\
561
+\0\x55\x01\x5a\0\x2b\0\0\0\xb7\x01\0\0\0\0\0\0\x63\x1a\xf8\xff\0\0\0\0\xbf\xa3\
562
+\0\0\0\0\0\0\x07\x03\0\0\xf8\xff\xff\xff\xbf\x81\0\0\0\0\0\0\x79\xa2\x40\xff\0\
563
+\0\0\0\xb7\x04\0\0\x04\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\xbf\x01\
564
+\0\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\x03\x01\0\0\0\
565
+\0\x71\xa1\xfa\xff\0\0\0\0\x55\x01\x4b\0\x02\0\0\0\x71\xa1\xf9\xff\0\0\0\0\x55\
566
+\x01\x49\0\x02\0\0\0\x71\xa1\xfb\xff\0\0\0\0\x55\x01\x47\0\x01\0\0\0\x79\xa2\
567
+\x40\xff\0\0\0\0\x07\x02\0\0\x08\0\0\0\xbf\x81\0\0\0\0\0\0\x79\xa3\x18\xff\0\0\
568
+\0\0\xb7\x04\0\0\x10\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\xbf\x01\0\
569
+\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\xf2\0\0\0\0\0\
570
+\xb7\x01\0\0\x01\0\0\0\x73\x1a\x55\xff\0\0\0\0\x05\0\x39\0\0\0\0\0\xb7\x01\0\0\
571
+\0\0\0\0\x6b\x1a\xf8\xff\0\0\0\0\xb7\x09\0\0\x02\0\0\0\xb7\x07\0\0\x1e\0\0\0\
572
+\x05\0\x0e\0\0\0\0\0\x79\xa2\x38\xff\0\0\0\0\x0f\x29\0\0\0\0\0\0\xbf\x92\0\0\0\
573
+\0\0\0\x07\x02\0\0\x01\0\0\0\x71\xa3\xff\xff\0\0\0\0\x67\x03\0\0\x03\0\0\0\x2d\
574
+\x23\x02\0\0\0\0\0\x79\xa7\x20\xff\0\0\0\0\x05\0\x2b\0\0\0\0\0\x07\x07\0\0\xff\
575
+\xff\xff\xff\xbf\x72\0\0\0\0\0\0\x67\x02\0\0\x20\0\0\0\x77\x02\0\0\x20\0\0\0\
576
+\x15\x02\xf9\xff\0\0\0\0\x7b\x9a\x38\xff\0\0\0\0\x79\xa1\x40\xff\0\0\0\0\x0f\
577
+\x19\0\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\xf8\xff\xff\xff\xbf\x81\0\0\0\
578
+\0\0\0\xbf\x92\0\0\0\0\0\0\xb7\x04\0\0\x02\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\
579
+\0\x44\0\0\0\xbf\x01\0\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\
580
+\x55\x01\x94\0\0\0\0\0\x71\xa2\xf8\xff\0\0\0\0\x55\x02\x0f\0\xc9\0\0\0\x07\x09\
581
+\0\0\x02\0\0\0\xbf\x81\0\0\0\0\0\0\xbf\x92\0\0\0\0\0\0\x79\xa3\x10\xff\0\0\0\0\
582
+\xb7\x04\0\0\x10\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\xbf\x01\0\0\0\
583
+\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\x87\0\0\0\0\0\xb7\
584
+\x01\0\0\x01\0\0\0\x73\x1a\x54\xff\0\0\0\0\x79\xa7\x20\xff\0\0\0\0\x05\0\x07\0\
585
+\0\0\0\0\xb7\x09\0\0\x01\0\0\0\x15\x02\xd1\xff\0\0\0\0\x71\xa9\xf9\xff\0\0\0\0\
586
+\x07\x09\0\0\x02\0\0\0\x05\0\xce\xff\0\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x56\
587
+\xff\0\0\0\0\x71\xa1\xff\xff\0\0\0\0\x67\x01\0\0\x03\0\0\0\x79\xa2\x40\xff\0\0\
588
+\0\0\x0f\x12\0\0\0\0\0\0\x07\x02\0\0\x08\0\0\0\x7b\x2a\x40\xff\0\0\0\0\x71\xa9\
589
+\xfe\xff\0\0\0\0\x25\x09\x0e\0\x3c\0\0\0\xb7\x01\0\0\x01\0\0\0\x6f\x91\0\0\0\0\
590
+\0\0\x18\x02\0\0\x01\0\0\0\0\0\0\0\0\x18\0\x1c\x5f\x21\0\0\0\0\0\0\x55\x01\x01\
591
+\0\0\0\0\0\x05\0\x07\0\0\0\0\0\x79\xa1\x28\xff\0\0\0\0\x07\x01\0\0\x01\0\0\0\
592
+\x7b\x1a\x28\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x55\x01\
593
+\x82\xff\x0b\0\0\0\x05\0\x10\xff\0\0\0\0\x15\x09\xf8\xff\x87\0\0\0\x05\0\xfd\
594
+\xff\0\0\0\0\x71\xa1\x51\xff\0\0\0\0\x79\xa0\x30\xff\0\0\0\0\x15\x01\x17\x01\0\
595
+\0\0\0\x71\x62\x03\0\0\0\0\0\x67\x02\0\0\x08\0\0\0\x71\x61\x02\0\0\0\0\0\x4f\
596
+\x12\0\0\0\0\0\0\x71\x63\x04\0\0\0\0\0\x71\x61\x05\0\0\0\0\0\x67\x01\0\0\x08\0\
597
+\0\0\x4f\x31\0\0\0\0\0\0\x67\x01\0\0\x10\0\0\0\x4f\x21\0\0\0\0\0\0\x71\xa2\x53\
598
+\xff\0\0\0\0\x15\x02\x3d\0\0\0\0\0\xbf\x12\0\0\0\0\0\0\x57\x02\0\0\x10\0\0\0\
599
+\x15\x02\x3a\0\0\0\0\0\xbf\xa2\0\0\0\0\0\0\x07\x02\0\0\x5c\xff\xff\xff\x71\xa4\
600
+\x54\xff\0\0\0\0\xbf\x23\0\0\0\0\0\0\x15\x04\x02\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\
601
+\x07\x03\0\0\x7c\xff\xff\xff\x67\x01\0\0\x38\0\0\0\xc7\x01\0\0\x38\0\0\0\x65\
602
+\x01\x01\0\xff\xff\xff\xff\xbf\x32\0\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\
603
+\x6c\xff\xff\xff\x71\xa5\x55\xff\0\0\0\0\xbf\x34\0\0\0\0\0\0\x15\x05\x02\0\0\0\
604
+\0\0\xbf\xa4\0\0\0\0\0\0\x07\x04\0\0\x8c\xff\xff\xff\x65\x01\x01\0\xff\xff\xff\
605
+\xff\xbf\x43\0\0\0\0\0\0\x61\x21\x04\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\x24\0\
606
+\0\0\0\0\0\x4f\x41\0\0\0\0\0\0\x7b\x1a\xa0\xff\0\0\0\0\x61\x21\x08\0\0\0\0\0\
607
+\x61\x22\x0c\0\0\0\0\0\x67\x02\0\0\x20\0\0\0\x4f\x12\0\0\0\0\0\0\x7b\x2a\xa8\
608
+\xff\0\0\0\0\x61\x31\0\0\0\0\0\0\x61\x32\x04\0\0\0\0\0\x61\x34\x08\0\0\0\0\0\
609
+\x61\x33\x0c\0\0\0\0\0\x69\xa5\x5a\xff\0\0\0\0\x6b\x5a\xc2\xff\0\0\0\0\x69\xa5\
610
+\x58\xff\0\0\0\0\x6b\x5a\xc0\xff\0\0\0\0\x67\x03\0\0\x20\0\0\0\x4f\x43\0\0\0\0\
611
+\0\0\x7b\x3a\xb8\xff\0\0\0\0\x67\x02\0\0\x20\0\0\0\x4f\x12\0\0\0\0\0\0\x7b\x2a\
612
+\xb0\xff\0\0\0\0\x05\0\x6b\0\0\0\0\0\x71\xa2\x52\xff\0\0\0\0\x15\x02\x04\0\0\0\
613
+\0\0\xbf\x12\0\0\0\0\0\0\x57\x02\0\0\x04\0\0\0\x15\x02\x01\0\0\0\0\0\x05\0\xf7\
614
+\xfe\0\0\0\0\x57\x01\0\0\x01\0\0\0\x15\x01\xd3\0\0\0\0\0\x61\xa1\x5c\xff\0\0\0\
615
+\0\x63\x1a\xa0\xff\0\0\0\0\x61\xa1\x60\xff\0\0\0\0\x63\x1a\xa4\xff\0\0\0\0\x05\
616
+\0\x5e\0\0\0\0\0\x71\xa2\x52\xff\0\0\0\0\x15\x02\x1e\0\0\0\0\0\xbf\x12\0\0\0\0\
617
+\0\0\x57\x02\0\0\x20\0\0\0\x15\x02\x1b\0\0\0\0\0\xbf\xa2\0\0\0\0\0\0\x07\x02\0\
618
+\0\x5c\xff\xff\xff\x71\xa4\x54\xff\0\0\0\0\xbf\x23\0\0\0\0\0\0\x15\x04\x02\0\0\
619
+\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\x7c\xff\xff\xff\x57\x01\0\0\0\x01\0\0\
620
+\x15\x01\x01\0\0\0\0\0\xbf\x32\0\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\x03\0\0\x6c\
621
+\xff\xff\xff\x71\xa5\x55\xff\0\0\0\0\xbf\x34\0\0\0\0\0\0\x15\x05\x02\0\0\0\0\0\
622
+\xbf\xa4\0\0\0\0\0\0\x07\x04\0\0\x8c\xff\xff\xff\x15\x01\xc3\xff\0\0\0\0\x05\0\
623
+\xc1\xff\0\0\0\0\xb7\x09\0\0\x3c\0\0\0\x79\xa7\x20\xff\0\0\0\0\x67\0\0\0\x20\0\
624
+\0\0\x77\0\0\0\x20\0\0\0\x15\0\xa5\xfe\0\0\0\0\x05\0\xb0\0\0\0\0\0\x15\x09\x07\
625
+\xff\x87\0\0\0\x05\0\xa2\xfe\0\0\0\0\xbf\x12\0\0\0\0\0\0\x57\x02\0\0\x08\0\0\0\
626
+\x15\x02\xab\0\0\0\0\0\xbf\xa2\0\0\0\0\0\0\x07\x02\0\0\x5c\xff\xff\xff\x71\xa4\
627
+\x54\xff\0\0\0\0\xbf\x23\0\0\0\0\0\0\x15\x04\x02\0\0\0\0\0\xbf\xa3\0\0\0\0\0\0\
628
+\x07\x03\0\0\x7c\xff\xff\xff\x57\x01\0\0\x40\0\0\0\x15\x01\x01\0\0\0\0\0\xbf\
629
+\x32\0\0\0\0\0\0\x61\x23\x04\0\0\0\0\0\x67\x03\0\0\x20\0\0\0\x61\x24\0\0\0\0\0\
630
+\0\x4f\x43\0\0\0\0\0\0\x7b\x3a\xa0\xff\0\0\0\0\x61\x23\x08\0\0\0\0\0\x61\x22\
631
+\x0c\0\0\0\0\0\x67\x02\0\0\x20\0\0\0\x4f\x32\0\0\0\0\0\0\x7b\x2a\xa8\xff\0\0\0\
632
+\0\x15\x01\x1c\0\0\0\0\0\x71\xa1\x55\xff\0\0\0\0\x15\x01\x1a\0\0\0\0\0\x61\xa1\
633
+\x98\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\xa2\x94\xff\0\0\0\0\x4f\x21\0\0\0\0\
634
+\0\0\x7b\x1a\xb8\xff\0\0\0\0\x61\xa1\x90\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\
635
+\xa2\x8c\xff\0\0\0\0\x05\0\x19\0\0\0\0\0\xb7\x01\0\0\x01\0\0\0\x73\x1a\x52\xff\
636
+\0\0\0\0\xb7\x01\0\0\0\0\0\0\x7b\x1a\xd0\xff\0\0\0\0\xbf\xa3\0\0\0\0\0\0\x07\
637
+\x03\0\0\xd0\xff\xff\xff\xbf\x81\0\0\0\0\0\0\x79\xa2\x40\xff\0\0\0\0\xb7\x04\0\
638
+\0\x08\0\0\0\xb7\x05\0\0\x01\0\0\0\x85\0\0\0\x44\0\0\0\x67\0\0\0\x20\0\0\0\x77\
639
+\0\0\0\x20\0\0\0\x55\0\x7d\0\0\0\0\0\x05\0\x88\xfe\0\0\0\0\xb7\x09\0\0\x2b\0\0\
640
+\0\x05\0\xc6\xff\0\0\0\0\x61\xa1\x78\xff\0\0\0\0\x67\x01\0\0\x20\0\0\0\x61\xa2\
641
+\x74\xff\0\0\0\0\x4f\x21\0\0\0\0\0\0\x7b\x1a\xb8\xff\0\0\0\0\x61\xa1\x70\xff\0\
642
+\0\0\0\x67\x01\0\0\x20\0\0\0\x61\xa2\x6c\xff\0\0\0\0\x4f\x21\0\0\0\0\0\0\x7b\
643
+\x1a\xb0\xff\0\0\0\0\xb7\x01\0\0\0\0\0\0\x07\x07\0\0\x04\0\0\0\x61\x03\0\0\0\0\
644
+\0\0\xb7\x05\0\0\0\0\0\0\x05\0\x4e\0\0\0\0\0\xaf\x52\0\0\0\0\0\0\xbf\x75\0\0\0\
645
+\0\0\0\x0f\x15\0\0\0\0\0\0\x71\x55\0\0\0\0\0\0\x67\x03\0\0\x01\0\0\0\xbf\x50\0\
646
+\0\0\0\0\0\x77\0\0\0\x07\0\0\0\x4f\x03\0\0\0\0\0\0\xbf\x40\0\0\0\0\0\0\x67\0\0\
647
+\0\x39\0\0\0\xc7\0\0\0\x3f\0\0\0\x5f\x30\0\0\0\0\0\0\xaf\x02\0\0\0\0\0\0\xbf\
648
+\x50\0\0\0\0\0\0\x77\0\0\0\x06\0\0\0\x57\0\0\0\x01\0\0\0\x67\x03\0\0\x01\0\0\0\
649
+\x4f\x03\0\0\0\0\0\0\xbf\x40\0\0\0\0\0\0\x67\0\0\0\x3a\0\0\0\xc7\0\0\0\x3f\0\0\
650
+\0\x5f\x30\0\0\0\0\0\0\xaf\x02\0\0\0\0\0\0\x67\x03\0\0\x01\0\0\0\xbf\x50\0\0\0\
651
+\0\0\0\x77\0\0\0\x05\0\0\0\x57\0\0\0\x01\0\0\0\x4f\x03\0\0\0\0\0\0\xbf\x40\0\0\
652
+\0\0\0\0\x67\0\0\0\x3b\0\0\0\xc7\0\0\0\x3f\0\0\0\x5f\x30\0\0\0\0\0\0\xaf\x02\0\
653
+\0\0\0\0\0\x67\x03\0\0\x01\0\0\0\xbf\x50\0\0\0\0\0\0\x77\0\0\0\x04\0\0\0\x57\0\
654
+\0\0\x01\0\0\0\x4f\x03\0\0\0\0\0\0\xbf\x40\0\0\0\0\0\0\x67\0\0\0\x3c\0\0\0\xc7\
655
+\0\0\0\x3f\0\0\0\x5f\x30\0\0\0\0\0\0\xaf\x02\0\0\0\0\0\0\xbf\x50\0\0\0\0\0\0\
656
+\x77\0\0\0\x03\0\0\0\x57\0\0\0\x01\0\0\0\x67\x03\0\0\x01\0\0\0\x4f\x03\0\0\0\0\
657
+\0\0\xbf\x40\0\0\0\0\0\0\x67\0\0\0\x3d\0\0\0\xc7\0\0\0\x3f\0\0\0\x5f\x30\0\0\0\
658
+\0\0\0\xaf\x02\0\0\0\0\0\0\xbf\x50\0\0\0\0\0\0\x77\0\0\0\x02\0\0\0\x57\0\0\0\
659
+\x01\0\0\0\x67\x03\0\0\x01\0\0\0\x4f\x03\0\0\0\0\0\0\xbf\x40\0\0\0\0\0\0\x67\0\
660
+\0\0\x3e\0\0\0\xc7\0\0\0\x3f\0\0\0\x5f\x30\0\0\0\0\0\0\xaf\x02\0\0\0\0\0\0\xbf\
661
+\x50\0\0\0\0\0\0\x77\0\0\0\x01\0\0\0\x57\0\0\0\x01\0\0\0\x67\x03\0\0\x01\0\0\0\
662
+\x4f\x03\0\0\0\0\0\0\x57\x04\0\0\x01\0\0\0\x87\x04\0\0\0\0\0\0\x5f\x34\0\0\0\0\
663
+\0\0\xaf\x42\0\0\0\0\0\0\x57\x05\0\0\x01\0\0\0\x67\x03\0\0\x01\0\0\0\x4f\x53\0\
664
+\0\0\0\0\0\x07\x01\0\0\x01\0\0\0\xbf\x25\0\0\0\0\0\0\x15\x01\x0b\0\x24\0\0\0\
665
+\xbf\xa2\0\0\0\0\0\0\x07\x02\0\0\xa0\xff\xff\xff\x0f\x12\0\0\0\0\0\0\x71\x24\0\
666
+\0\0\0\0\0\xbf\x40\0\0\0\0\0\0\x67\0\0\0\x38\0\0\0\xc7\0\0\0\x38\0\0\0\xb7\x02\
667
+\0\0\0\0\0\0\x65\0\xa9\xff\xff\xff\xff\xff\xbf\x32\0\0\0\0\0\0\x05\0\xa7\xff\0\
668
+\0\0\0\xbf\x21\0\0\0\0\0\0\x67\x01\0\0\x20\0\0\0\x77\x01\0\0\x20\0\0\0\x15\x01\
669
+\x0e\0\0\0\0\0\x71\x63\x06\0\0\0\0\0\x71\x64\x07\0\0\0\0\0\x67\x04\0\0\x08\0\0\
670
+\0\x4f\x34\0\0\0\0\0\0\x3f\x41\0\0\0\0\0\0\x2f\x41\0\0\0\0\0\0\x1f\x12\0\0\0\0\
671
+\0\0\x63\x2a\x50\xff\0\0\0\0\xbf\xa2\0\0\0\0\0\0\x07\x02\0\0\x50\xff\xff\xff\
672
+\x18\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x85\0\0\0\x01\0\0\0\x55\0\x05\0\0\0\0\0\
673
+\x71\x61\x08\0\0\0\0\0\x71\x60\x09\0\0\0\0\0\x67\0\0\0\x08\0\0\0\x4f\x10\0\0\0\
674
+\0\0\0\x95\0\0\0\0\0\0\0\x69\0\0\0\0\0\0\0\x05\0\xfd\xff\0\0\0\0\x02\0\0\0\x04\
675
+\0\0\0\x0a\0\0\0\x01\0\0\0\0\0\0\0\x02\0\0\0\x04\0\0\0\x28\0\0\0\x01\0\0\0\0\0\
676
+\0\0\x02\0\0\0\x04\0\0\0\x02\0\0\0\x80\0\0\0\0\0\0\0\x47\x50\x4c\x20\x76\x32\0\
677
+\0\0\0\0\0\x10\0\0\0\0\0\0\0\x01\x7a\x52\0\x08\x7c\x0b\x01\x0c\0\0\0\x18\0\0\0\
678
+\x18\0\0\0\0\0\0\0\0\0\0\0\xd8\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
679
+\0\0\0\0\0\0\0\0\0\0\0\0\xa0\0\0\0\x04\0\xf1\xff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
680
+\0\x60\x02\0\0\0\0\x03\0\x20\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3f\x02\0\0\0\0\
681
+\x03\0\xd0\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xed\x01\0\0\0\0\x03\0\x10\x10\0\0\0\
682
+\0\0\0\0\0\0\0\0\0\0\0\xd4\x01\0\0\0\0\x03\0\x20\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\
683
+\0\xa3\x01\0\0\0\0\x03\0\xb8\x12\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x63\x01\0\0\0\0\
684
+\x03\0\x48\x10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2a\x01\0\0\0\0\x03\0\x10\x13\0\0\0\
685
+\0\0\0\0\0\0\0\0\0\0\0\xe1\0\0\0\0\0\x03\0\xa0\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
686
+\x2e\x02\0\0\0\0\x03\0\x28\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x68\x02\0\0\0\0\x03\
687
+\0\xc0\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x36\x02\0\0\0\0\x03\0\xc8\x13\0\0\0\0\0\
688
+\0\0\0\0\0\0\0\0\0\x22\x01\0\0\0\0\x03\0\xe8\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
689
+\x02\x01\0\0\0\0\x03\0\x40\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd9\0\0\0\0\0\x03\0\
690
+\xf8\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x26\x02\0\0\0\0\x03\0\x20\x0e\0\0\0\0\0\0\
691
+\0\0\0\0\0\0\0\0\xcc\x01\0\0\0\0\x03\0\x60\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x9b\
692
+\x01\0\0\0\0\x03\0\xc8\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5b\x01\0\0\0\0\x03\0\
693
+\x20\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x7c\x01\0\0\0\0\x03\0\x48\x08\0\0\0\0\0\0\
694
+\0\0\0\0\0\0\0\0\x53\x01\0\0\0\0\x03\0\xb8\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1a\
695
+\x01\0\0\0\0\x03\0\xe0\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x84\x01\0\0\0\0\x03\0\
696
+\xb8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1e\x02\0\0\0\0\x03\0\xd8\x09\0\0\0\0\0\0\0\
697
+\0\0\0\0\0\0\0\xc4\x01\0\0\0\0\x03\0\x70\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x93\
698
+\x01\0\0\0\0\x03\0\xa8\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x74\x01\0\0\0\0\x03\0\
699
+\xf0\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4b\x01\0\0\0\0\x03\0\0\x0a\0\0\0\0\0\0\0\
700
+\0\0\0\0\0\0\0\x12\x01\0\0\0\0\x03\0\x10\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xfa\0\
701
+\0\0\0\0\x03\0\xc0\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x58\x02\0\0\0\0\x03\0\x88\
702
+\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x16\x02\0\0\0\0\x03\0\xb8\x0a\0\0\0\0\0\0\0\0\
703
+\0\0\0\0\0\0\xe5\x01\0\0\0\0\x03\0\xc0\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xbc\x01\
704
+\0\0\0\0\x03\0\0\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x8b\x01\0\0\0\0\x03\0\x18\x0e\
705
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xd1\0\0\0\0\0\x03\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\
706
+\0\0\x50\x02\0\0\0\0\x03\0\x20\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0e\x02\0\0\0\0\
707
+\x03\0\x48\x0f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6c\x01\0\0\0\0\x03\0\xb0\x04\0\0\0\
708
+\0\0\0\0\0\0\0\0\0\0\0\x43\x01\0\0\0\0\x03\0\xc8\x0c\0\0\0\0\0\0\0\0\0\0\0\0\0\
709
+\0\xc9\0\0\0\0\0\x03\0\xf8\x0c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x06\x02\0\0\0\0\x03\
710
+\0\xd0\x0a\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3b\x01\0\0\0\0\x03\0\x98\x0b\0\0\0\0\0\
711
+\0\0\0\0\0\0\0\0\0\xf2\0\0\0\0\0\x03\0\xb8\x0b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x48\
712
+\x02\0\0\0\0\x03\0\xf0\x0b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xfe\x01\0\0\0\0\x03\0\
713
+\xf8\x0b\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xdd\x01\0\0\0\0\x03\0\0\x0c\0\0\0\0\0\0\0\
714
+\0\0\0\0\0\0\0\xb4\x01\0\0\0\0\x03\0\x30\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x0a\
715
+\x01\0\0\0\0\x03\0\x90\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xc1\0\0\0\0\0\x03\0\xa8\
716
+\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xba\0\0\0\0\0\x03\0\xd0\x01\0\0\0\0\0\0\0\0\0\
717
+\0\0\0\0\0\xf6\x01\0\0\0\0\x03\0\xe0\x0d\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xac\x01\0\
718
+\0\0\0\x03\0\x30\x0e\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x33\x01\0\0\0\0\x03\0\x80\x0e\
719
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xea\0\0\0\0\0\x03\0\x98\x0e\0\0\0\0\0\0\0\0\0\0\0\
720
+\0\0\0\0\0\0\0\x03\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x6b\0\0\0\x11\0\x06\
721
+\0\0\0\0\0\0\0\0\0\x07\0\0\0\0\0\0\0\x25\0\0\0\x11\0\x05\0\0\0\0\0\0\0\0\0\x14\
722
+\0\0\0\0\0\0\0\x82\0\0\0\x11\0\x05\0\x28\0\0\0\0\0\0\0\x14\0\0\0\0\0\0\0\x01\0\
723
+\0\0\x11\0\x05\0\x14\0\0\0\0\0\0\0\x14\0\0\0\0\0\0\0\x40\0\0\0\x12\0\x03\0\0\0\
724
+\0\0\0\0\0\0\xd8\x13\0\0\0\0\0\0\x28\0\0\0\0\0\0\0\x01\0\0\0\x3a\0\0\0\x50\0\0\
725
+\0\0\0\0\0\x01\0\0\0\x3c\0\0\0\x80\x13\0\0\0\0\0\0\x01\0\0\0\x3b\0\0\0\x1c\0\0\
726
+\0\0\0\0\0\x01\0\0\0\x38\0\0\0\0\x74\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\
727
+\x5f\x74\x6f\x65\x70\x6c\x69\x74\x7a\x5f\x6b\x65\x79\0\x2e\x74\x65\x78\x74\0\
728
+\x6d\x61\x70\x73\0\x74\x61\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\x5f\x63\x6f\x6e\
729
+\x66\x69\x67\x75\x72\x61\x74\x69\x6f\x6e\x73\0\x74\x75\x6e\x5f\x72\x73\x73\x5f\
730
+\x73\x74\x65\x65\x72\x69\x6e\x67\x5f\x70\x72\x6f\x67\0\x2e\x72\x65\x6c\x74\x75\
731
+\x6e\x5f\x72\x73\x73\x5f\x73\x74\x65\x65\x72\x69\x6e\x67\0\x5f\x6c\x69\x63\x65\
732
+\x6e\x73\x65\0\x2e\x72\x65\x6c\x2e\x65\x68\x5f\x66\x72\x61\x6d\x65\0\x74\x61\
733
+\x70\x5f\x72\x73\x73\x5f\x6d\x61\x70\x5f\x69\x6e\x64\x69\x72\x65\x63\x74\x69\
734
+\x6f\x6e\x5f\x74\x61\x62\x6c\x65\0\x72\x73\x73\x2e\x62\x70\x66\x2e\x63\0\x2e\
735
+\x73\x74\x72\x74\x61\x62\0\x2e\x73\x79\x6d\x74\x61\x62\0\x4c\x42\x42\x30\x5f\
736
+\x39\0\x4c\x42\x42\x30\x5f\x38\x39\0\x4c\x42\x42\x30\x5f\x36\x39\0\x4c\x42\x42\
737
+\x30\x5f\x35\x39\0\x4c\x42\x42\x30\x5f\x31\x39\0\x4c\x42\x42\x30\x5f\x31\x30\
738
+\x39\0\x4c\x42\x42\x30\x5f\x39\x38\0\x4c\x42\x42\x30\x5f\x37\x38\0\x4c\x42\x42\
739
+\x30\x5f\x34\x38\0\x4c\x42\x42\x30\x5f\x31\x38\0\x4c\x42\x42\x30\x5f\x38\x37\0\
740
+\x4c\x42\x42\x30\x5f\x34\x37\0\x4c\x42\x42\x30\x5f\x33\x37\0\x4c\x42\x42\x30\
741
+\x5f\x31\x37\0\x4c\x42\x42\x30\x5f\x31\x30\x37\0\x4c\x42\x42\x30\x5f\x39\x36\0\
742
+\x4c\x42\x42\x30\x5f\x37\x36\0\x4c\x42\x42\x30\x5f\x36\x36\0\x4c\x42\x42\x30\
743
+\x5f\x34\x36\0\x4c\x42\x42\x30\x5f\x33\x36\0\x4c\x42\x42\x30\x5f\x32\x36\0\x4c\
744
+\x42\x42\x30\x5f\x31\x30\x36\0\x4c\x42\x42\x30\x5f\x36\x35\0\x4c\x42\x42\x30\
745
+\x5f\x34\x35\0\x4c\x42\x42\x30\x5f\x33\x35\0\x4c\x42\x42\x30\x5f\x34\0\x4c\x42\
746
+\x42\x30\x5f\x35\x34\0\x4c\x42\x42\x30\x5f\x34\x34\0\x4c\x42\x42\x30\x5f\x32\
747
+\x34\0\x4c\x42\x42\x30\x5f\x31\x30\x34\0\x4c\x42\x42\x30\x5f\x39\x33\0\x4c\x42\
748
+\x42\x30\x5f\x38\x33\0\x4c\x42\x42\x30\x5f\x35\x33\0\x4c\x42\x42\x30\x5f\x34\
749
+\x33\0\x4c\x42\x42\x30\x5f\x32\x33\0\x4c\x42\x42\x30\x5f\x31\x30\x33\0\x4c\x42\
750
+\x42\x30\x5f\x38\x32\0\x4c\x42\x42\x30\x5f\x35\x32\0\x4c\x42\x42\x30\x5f\x31\
751
+\x30\x32\0\x4c\x42\x42\x30\x5f\x39\x31\0\x4c\x42\x42\x30\x5f\x38\x31\0\x4c\x42\
752
+\x42\x30\x5f\x37\x31\0\x4c\x42\x42\x30\x5f\x36\x31\0\x4c\x42\x42\x30\x5f\x35\
753
+\x31\0\x4c\x42\x42\x30\x5f\x34\x31\0\x4c\x42\x42\x30\x5f\x32\x31\0\x4c\x42\x42\
754
+\x30\x5f\x31\x31\0\x4c\x42\x42\x30\x5f\x31\x31\x31\0\x4c\x42\x42\x30\x5f\x31\
755
+\x30\x31\0\x4c\x42\x42\x30\x5f\x38\x30\0\x4c\x42\x42\x30\x5f\x36\x30\0\x4c\x42\
756
+\x42\x30\x5f\x35\x30\0\x4c\x42\x42\x30\x5f\x31\x30\0\x4c\x42\x42\x30\x5f\x31\
757
+\x31\x30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
758
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xaa\
759
+\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\xa0\x1a\0\0\0\0\0\0\x71\x02\0\
760
+\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1a\0\0\0\x01\0\0\
761
+\0\x06\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
762
+\0\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5a\0\0\0\x01\0\0\0\x06\0\0\0\0\0\0\
763
+\0\0\0\0\0\0\0\0\0\x40\0\0\0\0\0\0\0\xd8\x13\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x08\0\
764
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x56\0\0\0\x09\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
765
+\0\x60\x1a\0\0\0\0\0\0\x30\0\0\0\0\0\0\0\x09\0\0\0\x03\0\0\0\x08\0\0\0\0\0\0\0\
766
+\x10\0\0\0\0\0\0\0\x20\0\0\0\x01\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x18\
767
+\x14\0\0\0\0\0\0\x3c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0\0\0\0\0\0\
768
+\0\0\0\x6c\0\0\0\x01\0\0\0\x03\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x54\x14\0\0\0\0\0\
769
+\0\x07\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x78\0\0\
770
+\0\x01\0\0\0\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x60\x14\0\0\0\0\0\0\x30\0\0\0\0\
771
+\0\0\0\0\0\0\0\0\0\0\0\x08\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x74\0\0\0\x09\0\0\0\0\
772
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x90\x1a\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\x09\0\0\0\
773
+\x07\0\0\0\x08\0\0\0\0\0\0\0\x10\0\0\0\0\0\0\0\xb2\0\0\0\x02\0\0\0\0\0\0\0\0\0\
774
+\0\0\0\0\0\0\0\0\0\0\x90\x14\0\0\0\0\0\0\xd0\x05\0\0\0\0\0\0\x01\0\0\0\x39\0\0\
775
+\0\x08\0\0\0\0\0\0\0\x18\0\0\0\0\0\0\0";
776
+
777
+    return 0;
778
+err:
779
+    bpf_object__destroy_skeleton(s);
780
+    return -1;
781
+}
782
+
783
+#endif /* __RSS_BPF_SKEL_H__ */
784
diff --git a/ebpf/trace-events b/ebpf/trace-events
785
new file mode 100644
786
index XXXXXXX..XXXXXXX
787
--- /dev/null
788
+++ b/ebpf/trace-events
789
@@ -XXX,XX +XXX,XX @@
790
+# See docs/devel/tracing.txt for syntax documentation.
791
+
792
+# ebpf-rss.c
793
+ebpf_error(const char *s1, const char *s2) "error in %s: %s"
794
diff --git a/ebpf/trace.h b/ebpf/trace.h
795
new file mode 100644
796
index XXXXXXX..XXXXXXX
797
--- /dev/null
798
+++ b/ebpf/trace.h
799
@@ -0,0 +1 @@
800
+#include "trace/trace-ebpf.h"
801
diff --git a/meson.build b/meson.build
802
index XXXXXXX..XXXXXXX 100644
803
--- a/meson.build
804
+++ b/meson.build
805
@@ -XXX,XX +XXX,XX @@ if not get_option('fuse_lseek').disabled()
806
endif
807
endif
808
809
+# libbpf
810
+libbpf = dependency('libbpf', required: get_option('bpf'))
811
+if libbpf.found() and not cc.links('''
812
+ #include <bpf/libbpf.h>
813
+ int main(void)
814
+ {
815
+ bpf_object__destroy_skeleton(NULL);
816
+ return 0;
817
+ }''', dependencies: libbpf)
818
+ libbpf = not_found
819
+ if get_option('bpf').enabled()
820
+ error('libbpf skeleton test failed')
821
+ else
822
+ warning('libbpf skeleton test failed, disabling')
823
+ endif
824
+endif
825
+
826
if get_option('cfi')
827
cfi_flags=[]
828
# Check for dependency on LTO
829
@@ -XXX,XX +XXX,XX @@ endif
830
config_host_data.set('CONFIG_GTK', gtk.found())
831
config_host_data.set('CONFIG_LIBATTR', have_old_libattr)
832
config_host_data.set('CONFIG_LIBCAP_NG', libcap_ng.found())
833
+config_host_data.set('CONFIG_EBPF', libbpf.found())
834
config_host_data.set('CONFIG_LIBISCSI', libiscsi.found())
835
config_host_data.set('CONFIG_LIBNFS', libnfs.found())
836
config_host_data.set('CONFIG_RBD', rbd.found())
837
@@ -XXX,XX +XXX,XX @@ if have_system
838
'backends',
839
'backends/tpm',
840
'chardev',
841
+ 'ebpf',
842
'hw/9pfs',
843
'hw/acpi',
844
'hw/adc',
845
@@ -XXX,XX +XXX,XX @@ subdir('accel')
846
subdir('plugins')
847
subdir('bsd-user')
848
subdir('linux-user')
849
+subdir('ebpf')
850
+
851
+common_ss.add(libbpf)
852
853
bsd_user_ss.add(files('gdbstub.c'))
854
specific_ss.add_all(when: 'CONFIG_BSD_USER', if_true: bsd_user_ss)
855
@@ -XXX,XX +XXX,XX @@ summary_info += {'RDMA support': config_host.has_key('CONFIG_RDMA')}
856
summary_info += {'PVRDMA support': config_host.has_key('CONFIG_PVRDMA')}
857
summary_info += {'fdt support': fdt_opt == 'disabled' ? false : fdt_opt}
858
summary_info += {'libcap-ng support': libcap_ng.found()}
859
+summary_info += {'bpf support': libbpf.found()}
860
# TODO: add back protocol and server version
861
summary_info += {'spice support': config_host.has_key('CONFIG_SPICE')}
862
summary_info += {'rbd support': rbd.found()}
863
diff --git a/meson_options.txt b/meson_options.txt
864
index XXXXXXX..XXXXXXX 100644
865
--- a/meson_options.txt
866
+++ b/meson_options.txt
867
@@ -XXX,XX +XXX,XX @@ option('bzip2', type : 'feature', value : 'auto',
868
description: 'bzip2 support for DMG images')
869
option('cap_ng', type : 'feature', value : 'auto',
870
description: 'cap_ng support')
871
+option('bpf', type : 'feature', value : 'auto',
872
+ description: 'eBPF support')
873
option('cocoa', type : 'feature', value : 'auto',
874
description: 'Cocoa user interface (macOS only)')
875
option('curl', type : 'feature', value : 'auto',
876
--
90
--
877
2.7.4
91
2.5.0
878
92
879
93
diff view generated by jsdifflib
New patch
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
1
2
3
Set irq's specific to a queue, present implementation is setting q1 irq
4
based on q0 status.
5
6
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
7
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
10
hw/net/cadence_gem.c | 25 +++----------------------
11
1 file changed, 3 insertions(+), 22 deletions(-)
12
13
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/net/cadence_gem.c
16
+++ b/hw/net/cadence_gem.c
17
@@ -XXX,XX +XXX,XX @@ static void gem_update_int_status(CadenceGEMState *s)
18
{
19
int i;
20
21
- if (!s->regs[GEM_ISR]) {
22
- /* ISR isn't set, clear all the interrupts */
23
- for (i = 0; i < s->num_priority_queues; ++i) {
24
- qemu_set_irq(s->irq[i], 0);
25
- }
26
- return;
27
- }
28
+ qemu_set_irq(s->irq[0], !!s->regs[GEM_ISR]);
29
30
- /* If we get here we know s->regs[GEM_ISR] is set, so we don't need to
31
- * check it again.
32
- */
33
- if (s->num_priority_queues == 1) {
34
- /* No priority queues, just trigger the interrupt */
35
- DB_PRINT("asserting int.\n");
36
- qemu_set_irq(s->irq[0], 1);
37
- return;
38
- }
39
-
40
- for (i = 0; i < s->num_priority_queues; ++i) {
41
- if (s->regs[GEM_INT_Q1_STATUS + i]) {
42
- DB_PRINT("asserting int. (q=%d)\n", i);
43
- qemu_set_irq(s->irq[i], 1);
44
- }
45
+ for (i = 1; i < s->num_priority_queues; ++i) {
46
+ qemu_set_irq(s->irq[i], !!s->regs[GEM_INT_Q1_STATUS + i - 1]);
47
}
48
}
49
50
--
51
2.5.0
52
53
diff view generated by jsdifflib
New patch
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
1
2
3
Q1 to Q7 ISR's are clear-on-read, IER/IDR registers
4
are write-only, mask reg are read-only.
5
6
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
7
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
10
hw/net/cadence_gem.c | 14 ++++++++++++++
11
1 file changed, 14 insertions(+)
12
13
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/net/cadence_gem.c
16
+++ b/hw/net/cadence_gem.c
17
@@ -XXX,XX +XXX,XX @@ static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
18
*/
19
static void gem_init_register_masks(CadenceGEMState *s)
20
{
21
+ unsigned int i;
22
/* Mask of register bits which are read only */
23
memset(&s->regs_ro[0], 0, sizeof(s->regs_ro));
24
s->regs_ro[GEM_NWCTRL] = 0xFFF80000;
25
@@ -XXX,XX +XXX,XX @@ static void gem_init_register_masks(CadenceGEMState *s)
26
s->regs_ro[GEM_ISR] = 0xFFFFFFFF;
27
s->regs_ro[GEM_IMR] = 0xFFFFFFFF;
28
s->regs_ro[GEM_MODID] = 0xFFFFFFFF;
29
+ for (i = 0; i < s->num_priority_queues; i++) {
30
+ s->regs_ro[GEM_INT_Q1_STATUS + i] = 0xFFFFFFFF;
31
+ s->regs_ro[GEM_INT_Q1_ENABLE + i] = 0xFFFFF319;
32
+ s->regs_ro[GEM_INT_Q1_DISABLE + i] = 0xFFFFF319;
33
+ s->regs_ro[GEM_INT_Q1_MASK + i] = 0xFFFFFFFF;
34
+ }
35
36
/* Mask of register bits which are clear on read */
37
memset(&s->regs_rtc[0], 0, sizeof(s->regs_rtc));
38
s->regs_rtc[GEM_ISR] = 0xFFFFFFFF;
39
+ for (i = 0; i < s->num_priority_queues; i++) {
40
+ s->regs_rtc[GEM_INT_Q1_STATUS + i] = 0x00000CE6;
41
+ }
42
43
/* Mask of register bits which are write 1 to clear */
44
memset(&s->regs_w1c[0], 0, sizeof(s->regs_w1c));
45
@@ -XXX,XX +XXX,XX @@ static void gem_init_register_masks(CadenceGEMState *s)
46
s->regs_wo[GEM_NWCTRL] = 0x00073E60;
47
s->regs_wo[GEM_IER] = 0x07FFFFFF;
48
s->regs_wo[GEM_IDR] = 0x07FFFFFF;
49
+ for (i = 0; i < s->num_priority_queues; i++) {
50
+ s->regs_wo[GEM_INT_Q1_ENABLE + i] = 0x00000CE6;
51
+ s->regs_wo[GEM_INT_Q1_DISABLE + i] = 0x00000CE6;
52
+ }
53
}
54
55
/*
56
--
57
2.5.0
58
59
diff view generated by jsdifflib
New patch
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
1
2
3
Set ISR according to queue in use, added interrupt support for
4
all queues.
5
6
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
7
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
10
hw/net/cadence_gem.c | 27 +++++++++++++++++----------
11
1 file changed, 17 insertions(+), 10 deletions(-)
12
13
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/hw/net/cadence_gem.c
16
+++ b/hw/net/cadence_gem.c
17
@@ -XXX,XX +XXX,XX @@ static inline void rx_desc_set_sar(uint32_t *desc, int sar_idx)
18
/* The broadcast MAC address: 0xFFFFFFFFFFFF */
19
static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
20
21
+static void gem_set_isr(CadenceGEMState *s, int q, uint32_t flag)
22
+{
23
+ if (q == 0) {
24
+ s->regs[GEM_ISR] |= flag & ~(s->regs[GEM_IMR]);
25
+ } else {
26
+ s->regs[GEM_INT_Q1_STATUS + q - 1] |= flag &
27
+ ~(s->regs[GEM_INT_Q1_MASK + q - 1]);
28
+ }
29
+}
30
+
31
/*
32
* gem_init_register_masks:
33
* One time initialization.
34
@@ -XXX,XX +XXX,XX @@ static void gem_get_rx_desc(CadenceGEMState *s, int q)
35
if (rx_desc_get_ownership(s->rx_desc[q]) == 1) {
36
DB_PRINT("descriptor 0x%" HWADDR_PRIx " owned by sw.\n", desc_addr);
37
s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_NOBUF;
38
- s->regs[GEM_ISR] |= GEM_INT_RXUSED & ~(s->regs[GEM_IMR]);
39
+ gem_set_isr(s, q, GEM_INT_RXUSED);
40
/* Handle interrupt consequences */
41
gem_update_int_status(s);
42
}
43
@@ -XXX,XX +XXX,XX @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
44
gem_receive_updatestats(s, buf, size);
45
46
s->regs[GEM_RXSTATUS] |= GEM_RXSTATUS_FRMRCVD;
47
- s->regs[GEM_ISR] |= GEM_INT_RXCMPL & ~(s->regs[GEM_IMR]);
48
+ gem_set_isr(s, q, GEM_INT_RXCMPL);
49
50
/* Handle interrupt consequences */
51
gem_update_int_status(s);
52
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
53
DB_PRINT("TX descriptor next: 0x%08x\n", s->tx_desc_addr[q]);
54
55
s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_TXCMPL;
56
- s->regs[GEM_ISR] |= GEM_INT_TXCMPL & ~(s->regs[GEM_IMR]);
57
-
58
- /* Update queue interrupt status */
59
- if (s->num_priority_queues > 1) {
60
- s->regs[GEM_INT_Q1_STATUS + q] |=
61
- GEM_INT_TXCMPL & ~(s->regs[GEM_INT_Q1_MASK + q]);
62
- }
63
+ gem_set_isr(s, q, GEM_INT_TXCMPL);
64
65
/* Handle interrupt consequences */
66
gem_update_int_status(s);
67
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
68
69
if (tx_desc_get_used(desc)) {
70
s->regs[GEM_TXSTATUS] |= GEM_TXSTATUS_USED;
71
- s->regs[GEM_ISR] |= GEM_INT_TXUSED & ~(s->regs[GEM_IMR]);
72
+ /* IRQ TXUSED is defined only for queue 0 */
73
+ if (q == 0) {
74
+ gem_set_isr(s, 0, GEM_INT_TXUSED);
75
+ }
76
gem_update_int_status(s);
77
}
78
}
79
--
80
2.5.0
81
82
diff view generated by jsdifflib
New patch
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
1
2
3
Moving this buffers to CadenceGEMState, as their size will be increased
4
more when JUMBO frames support is added.
5
6
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
7
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
10
hw/net/cadence_gem.c | 38 +++++++++++++++++---------------------
11
include/hw/net/cadence_gem.h | 4 ++++
12
2 files changed, 21 insertions(+), 21 deletions(-)
13
14
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/net/cadence_gem.c
17
+++ b/hw/net/cadence_gem.c
18
@@ -XXX,XX +XXX,XX @@ static void gem_get_rx_desc(CadenceGEMState *s, int q)
19
*/
20
static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
21
{
22
- CadenceGEMState *s;
23
+ CadenceGEMState *s = qemu_get_nic_opaque(nc);
24
unsigned rxbufsize, bytes_to_copy;
25
unsigned rxbuf_offset;
26
- uint8_t rxbuf[2048];
27
uint8_t *rxbuf_ptr;
28
bool first_desc = true;
29
int maf;
30
int q = 0;
31
32
- s = qemu_get_nic_opaque(nc);
33
-
34
/* Is this destination MAC address "for us" ? */
35
maf = gem_mac_address_filter(s, buf);
36
if (maf == GEM_RX_REJECT) {
37
@@ -XXX,XX +XXX,XX @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
38
} else {
39
unsigned crc_val;
40
41
- if (size > sizeof(rxbuf) - sizeof(crc_val)) {
42
- size = sizeof(rxbuf) - sizeof(crc_val);
43
+ if (size > MAX_FRAME_SIZE - sizeof(crc_val)) {
44
+ size = MAX_FRAME_SIZE - sizeof(crc_val);
45
}
46
bytes_to_copy = size;
47
/* The application wants the FCS field, which QEMU does not provide.
48
* We must try and calculate one.
49
*/
50
51
- memcpy(rxbuf, buf, size);
52
- memset(rxbuf + size, 0, sizeof(rxbuf) - size);
53
- rxbuf_ptr = rxbuf;
54
- crc_val = cpu_to_le32(crc32(0, rxbuf, MAX(size, 60)));
55
- memcpy(rxbuf + size, &crc_val, sizeof(crc_val));
56
+ memcpy(s->rx_packet, buf, size);
57
+ memset(s->rx_packet + size, 0, MAX_FRAME_SIZE - size);
58
+ rxbuf_ptr = s->rx_packet;
59
+ crc_val = cpu_to_le32(crc32(0, s->rx_packet, MAX(size, 60)));
60
+ memcpy(s->rx_packet + size, &crc_val, sizeof(crc_val));
61
62
bytes_to_copy += 4;
63
size += 4;
64
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
65
{
66
uint32_t desc[DESC_MAX_NUM_WORDS];
67
hwaddr packet_desc_addr;
68
- uint8_t tx_packet[2048];
69
uint8_t *p;
70
unsigned total_bytes;
71
int q = 0;
72
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
73
* Packets scattered across multiple descriptors are gathered to this
74
* one contiguous buffer first.
75
*/
76
- p = tx_packet;
77
+ p = s->tx_packet;
78
total_bytes = 0;
79
80
for (q = s->num_priority_queues - 1; q >= 0; q--) {
81
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
82
break;
83
}
84
85
- if (tx_desc_get_length(desc) > sizeof(tx_packet) -
86
- (p - tx_packet)) {
87
+ if (tx_desc_get_length(desc) > MAX_FRAME_SIZE -
88
+ (p - s->tx_packet)) {
89
DB_PRINT("TX descriptor @ 0x%" HWADDR_PRIx \
90
" too large: size 0x%x space 0x%zx\n",
91
packet_desc_addr, tx_desc_get_length(desc),
92
- sizeof(tx_packet) - (p - tx_packet));
93
+ MAX_FRAME_SIZE - (p - s->tx_packet));
94
break;
95
}
96
97
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
98
99
/* Is checksum offload enabled? */
100
if (s->regs[GEM_DMACFG] & GEM_DMACFG_TXCSUM_OFFL) {
101
- net_checksum_calculate(tx_packet, total_bytes);
102
+ net_checksum_calculate(s->tx_packet, total_bytes);
103
}
104
105
/* Update MAC statistics */
106
- gem_transmit_updatestats(s, tx_packet, total_bytes);
107
+ gem_transmit_updatestats(s, s->tx_packet, total_bytes);
108
109
/* Send the packet somewhere */
110
if (s->phy_loop || (s->regs[GEM_NWCTRL] &
111
GEM_NWCTRL_LOCALLOOP)) {
112
- gem_receive(qemu_get_queue(s->nic), tx_packet,
113
+ gem_receive(qemu_get_queue(s->nic), s->tx_packet,
114
total_bytes);
115
} else {
116
- qemu_send_packet(qemu_get_queue(s->nic), tx_packet,
117
+ qemu_send_packet(qemu_get_queue(s->nic), s->tx_packet,
118
total_bytes);
119
}
120
121
/* Prepare for next packet */
122
- p = tx_packet;
123
+ p = s->tx_packet;
124
total_bytes = 0;
125
}
126
127
diff --git a/include/hw/net/cadence_gem.h b/include/hw/net/cadence_gem.h
128
index XXXXXXX..XXXXXXX 100644
129
--- a/include/hw/net/cadence_gem.h
130
+++ b/include/hw/net/cadence_gem.h
131
@@ -XXX,XX +XXX,XX @@
132
#define MAX_TYPE1_SCREENERS 16
133
#define MAX_TYPE2_SCREENERS 16
134
135
+#define MAX_FRAME_SIZE 2048
136
+
137
typedef struct CadenceGEMState {
138
/*< private >*/
139
SysBusDevice parent_obj;
140
@@ -XXX,XX +XXX,XX @@ typedef struct CadenceGEMState {
141
142
uint8_t can_rx_state; /* Debug only */
143
144
+ uint8_t tx_packet[MAX_FRAME_SIZE];
145
+ uint8_t rx_packet[MAX_FRAME_SIZE];
146
uint32_t rx_desc[MAX_PRIORITY_QUEUES][DESC_MAX_NUM_WORDS];
147
148
bool sar_active[4];
149
--
150
2.5.0
151
152
diff view generated by jsdifflib
New patch
1
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
2
3
Fix the code style for register definitions.
4
5
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
6
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
9
hw/net/cadence_gem.c | 204 ++++++++++++++++++++++++++-------------------------
10
1 file changed, 103 insertions(+), 101 deletions(-)
11
12
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/net/cadence_gem.c
15
+++ b/hw/net/cadence_gem.c
16
@@ -XXX,XX +XXX,XX @@
17
} \
18
} while (0)
19
20
-#define GEM_NWCTRL (0x00000000/4) /* Network Control reg */
21
-#define GEM_NWCFG (0x00000004/4) /* Network Config reg */
22
-#define GEM_NWSTATUS (0x00000008/4) /* Network Status reg */
23
-#define GEM_USERIO (0x0000000C/4) /* User IO reg */
24
-#define GEM_DMACFG (0x00000010/4) /* DMA Control reg */
25
-#define GEM_TXSTATUS (0x00000014/4) /* TX Status reg */
26
-#define GEM_RXQBASE (0x00000018/4) /* RX Q Base address reg */
27
-#define GEM_TXQBASE (0x0000001C/4) /* TX Q Base address reg */
28
-#define GEM_RXSTATUS (0x00000020/4) /* RX Status reg */
29
-#define GEM_ISR (0x00000024/4) /* Interrupt Status reg */
30
-#define GEM_IER (0x00000028/4) /* Interrupt Enable reg */
31
-#define GEM_IDR (0x0000002C/4) /* Interrupt Disable reg */
32
-#define GEM_IMR (0x00000030/4) /* Interrupt Mask reg */
33
-#define GEM_PHYMNTNC (0x00000034/4) /* Phy Maintenance reg */
34
-#define GEM_RXPAUSE (0x00000038/4) /* RX Pause Time reg */
35
-#define GEM_TXPAUSE (0x0000003C/4) /* TX Pause Time reg */
36
-#define GEM_TXPARTIALSF (0x00000040/4) /* TX Partial Store and Forward */
37
-#define GEM_RXPARTIALSF (0x00000044/4) /* RX Partial Store and Forward */
38
-#define GEM_HASHLO (0x00000080/4) /* Hash Low address reg */
39
-#define GEM_HASHHI (0x00000084/4) /* Hash High address reg */
40
-#define GEM_SPADDR1LO (0x00000088/4) /* Specific addr 1 low reg */
41
-#define GEM_SPADDR1HI (0x0000008C/4) /* Specific addr 1 high reg */
42
-#define GEM_SPADDR2LO (0x00000090/4) /* Specific addr 2 low reg */
43
-#define GEM_SPADDR2HI (0x00000094/4) /* Specific addr 2 high reg */
44
-#define GEM_SPADDR3LO (0x00000098/4) /* Specific addr 3 low reg */
45
-#define GEM_SPADDR3HI (0x0000009C/4) /* Specific addr 3 high reg */
46
-#define GEM_SPADDR4LO (0x000000A0/4) /* Specific addr 4 low reg */
47
-#define GEM_SPADDR4HI (0x000000A4/4) /* Specific addr 4 high reg */
48
-#define GEM_TIDMATCH1 (0x000000A8/4) /* Type ID1 Match reg */
49
-#define GEM_TIDMATCH2 (0x000000AC/4) /* Type ID2 Match reg */
50
-#define GEM_TIDMATCH3 (0x000000B0/4) /* Type ID3 Match reg */
51
-#define GEM_TIDMATCH4 (0x000000B4/4) /* Type ID4 Match reg */
52
-#define GEM_WOLAN (0x000000B8/4) /* Wake on LAN reg */
53
-#define GEM_IPGSTRETCH (0x000000BC/4) /* IPG Stretch reg */
54
-#define GEM_SVLAN (0x000000C0/4) /* Stacked VLAN reg */
55
-#define GEM_MODID (0x000000FC/4) /* Module ID reg */
56
-#define GEM_OCTTXLO (0x00000100/4) /* Octects transmitted Low reg */
57
-#define GEM_OCTTXHI (0x00000104/4) /* Octects transmitted High reg */
58
-#define GEM_TXCNT (0x00000108/4) /* Error-free Frames transmitted */
59
-#define GEM_TXBCNT (0x0000010C/4) /* Error-free Broadcast Frames */
60
-#define GEM_TXMCNT (0x00000110/4) /* Error-free Multicast Frame */
61
-#define GEM_TXPAUSECNT (0x00000114/4) /* Pause Frames Transmitted */
62
-#define GEM_TX64CNT (0x00000118/4) /* Error-free 64 TX */
63
-#define GEM_TX65CNT (0x0000011C/4) /* Error-free 65-127 TX */
64
-#define GEM_TX128CNT (0x00000120/4) /* Error-free 128-255 TX */
65
-#define GEM_TX256CNT (0x00000124/4) /* Error-free 256-511 */
66
-#define GEM_TX512CNT (0x00000128/4) /* Error-free 512-1023 TX */
67
-#define GEM_TX1024CNT (0x0000012C/4) /* Error-free 1024-1518 TX */
68
-#define GEM_TX1519CNT (0x00000130/4) /* Error-free larger than 1519 TX */
69
-#define GEM_TXURUNCNT (0x00000134/4) /* TX under run error counter */
70
-#define GEM_SINGLECOLLCNT (0x00000138/4) /* Single Collision Frames */
71
-#define GEM_MULTCOLLCNT (0x0000013C/4) /* Multiple Collision Frames */
72
-#define GEM_EXCESSCOLLCNT (0x00000140/4) /* Excessive Collision Frames */
73
-#define GEM_LATECOLLCNT (0x00000144/4) /* Late Collision Frames */
74
-#define GEM_DEFERTXCNT (0x00000148/4) /* Deferred Transmission Frames */
75
-#define GEM_CSENSECNT (0x0000014C/4) /* Carrier Sense Error Counter */
76
-#define GEM_OCTRXLO (0x00000150/4) /* Octects Received register Low */
77
-#define GEM_OCTRXHI (0x00000154/4) /* Octects Received register High */
78
-#define GEM_RXCNT (0x00000158/4) /* Error-free Frames Received */
79
-#define GEM_RXBROADCNT (0x0000015C/4) /* Error-free Broadcast Frames RX */
80
-#define GEM_RXMULTICNT (0x00000160/4) /* Error-free Multicast Frames RX */
81
-#define GEM_RXPAUSECNT (0x00000164/4) /* Pause Frames Received Counter */
82
-#define GEM_RX64CNT (0x00000168/4) /* Error-free 64 byte Frames RX */
83
-#define GEM_RX65CNT (0x0000016C/4) /* Error-free 65-127B Frames RX */
84
-#define GEM_RX128CNT (0x00000170/4) /* Error-free 128-255B Frames RX */
85
-#define GEM_RX256CNT (0x00000174/4) /* Error-free 256-512B Frames RX */
86
-#define GEM_RX512CNT (0x00000178/4) /* Error-free 512-1023B Frames RX */
87
-#define GEM_RX1024CNT (0x0000017C/4) /* Error-free 1024-1518B Frames RX */
88
-#define GEM_RX1519CNT (0x00000180/4) /* Error-free 1519-max Frames RX */
89
-#define GEM_RXUNDERCNT (0x00000184/4) /* Undersize Frames Received */
90
-#define GEM_RXOVERCNT (0x00000188/4) /* Oversize Frames Received */
91
-#define GEM_RXJABCNT (0x0000018C/4) /* Jabbers Received Counter */
92
-#define GEM_RXFCSCNT (0x00000190/4) /* Frame Check seq. Error Counter */
93
-#define GEM_RXLENERRCNT (0x00000194/4) /* Length Field Error Counter */
94
-#define GEM_RXSYMERRCNT (0x00000198/4) /* Symbol Error Counter */
95
-#define GEM_RXALIGNERRCNT (0x0000019C/4) /* Alignment Error Counter */
96
-#define GEM_RXRSCERRCNT (0x000001A0/4) /* Receive Resource Error Counter */
97
-#define GEM_RXORUNCNT (0x000001A4/4) /* Receive Overrun Counter */
98
-#define GEM_RXIPCSERRCNT (0x000001A8/4) /* IP header Checksum Error Counter */
99
-#define GEM_RXTCPCCNT (0x000001AC/4) /* TCP Checksum Error Counter */
100
-#define GEM_RXUDPCCNT (0x000001B0/4) /* UDP Checksum Error Counter */
101
-
102
-#define GEM_1588S (0x000001D0/4) /* 1588 Timer Seconds */
103
-#define GEM_1588NS (0x000001D4/4) /* 1588 Timer Nanoseconds */
104
-#define GEM_1588ADJ (0x000001D8/4) /* 1588 Timer Adjust */
105
-#define GEM_1588INC (0x000001DC/4) /* 1588 Timer Increment */
106
-#define GEM_PTPETXS (0x000001E0/4) /* PTP Event Frame Transmitted (s) */
107
-#define GEM_PTPETXNS (0x000001E4/4) /* PTP Event Frame Transmitted (ns) */
108
-#define GEM_PTPERXS (0x000001E8/4) /* PTP Event Frame Received (s) */
109
-#define GEM_PTPERXNS (0x000001EC/4) /* PTP Event Frame Received (ns) */
110
-#define GEM_PTPPTXS (0x000001E0/4) /* PTP Peer Frame Transmitted (s) */
111
-#define GEM_PTPPTXNS (0x000001E4/4) /* PTP Peer Frame Transmitted (ns) */
112
-#define GEM_PTPPRXS (0x000001E8/4) /* PTP Peer Frame Received (s) */
113
-#define GEM_PTPPRXNS (0x000001EC/4) /* PTP Peer Frame Received (ns) */
114
+#define GEM_NWCTRL (0x00000000 / 4) /* Network Control reg */
115
+#define GEM_NWCFG (0x00000004 / 4) /* Network Config reg */
116
+#define GEM_NWSTATUS (0x00000008 / 4) /* Network Status reg */
117
+#define GEM_USERIO (0x0000000C / 4) /* User IO reg */
118
+#define GEM_DMACFG (0x00000010 / 4) /* DMA Control reg */
119
+#define GEM_TXSTATUS (0x00000014 / 4) /* TX Status reg */
120
+#define GEM_RXQBASE (0x00000018 / 4) /* RX Q Base address reg */
121
+#define GEM_TXQBASE (0x0000001C / 4) /* TX Q Base address reg */
122
+#define GEM_RXSTATUS (0x00000020 / 4) /* RX Status reg */
123
+#define GEM_ISR (0x00000024 / 4) /* Interrupt Status reg */
124
+#define GEM_IER (0x00000028 / 4) /* Interrupt Enable reg */
125
+#define GEM_IDR (0x0000002C / 4) /* Interrupt Disable reg */
126
+#define GEM_IMR (0x00000030 / 4) /* Interrupt Mask reg */
127
+#define GEM_PHYMNTNC (0x00000034 / 4) /* Phy Maintenance reg */
128
+#define GEM_RXPAUSE (0x00000038 / 4) /* RX Pause Time reg */
129
+#define GEM_TXPAUSE (0x0000003C / 4) /* TX Pause Time reg */
130
+#define GEM_TXPARTIALSF (0x00000040 / 4) /* TX Partial Store and Forward */
131
+#define GEM_RXPARTIALSF (0x00000044 / 4) /* RX Partial Store and Forward */
132
+#define GEM_HASHLO (0x00000080 / 4) /* Hash Low address reg */
133
+#define GEM_HASHHI (0x00000084 / 4) /* Hash High address reg */
134
+#define GEM_SPADDR1LO (0x00000088 / 4) /* Specific addr 1 low reg */
135
+#define GEM_SPADDR1HI (0x0000008C / 4) /* Specific addr 1 high reg */
136
+#define GEM_SPADDR2LO (0x00000090 / 4) /* Specific addr 2 low reg */
137
+#define GEM_SPADDR2HI (0x00000094 / 4) /* Specific addr 2 high reg */
138
+#define GEM_SPADDR3LO (0x00000098 / 4) /* Specific addr 3 low reg */
139
+#define GEM_SPADDR3HI (0x0000009C / 4) /* Specific addr 3 high reg */
140
+#define GEM_SPADDR4LO (0x000000A0 / 4) /* Specific addr 4 low reg */
141
+#define GEM_SPADDR4HI (0x000000A4 / 4) /* Specific addr 4 high reg */
142
+#define GEM_TIDMATCH1 (0x000000A8 / 4) /* Type ID1 Match reg */
143
+#define GEM_TIDMATCH2 (0x000000AC / 4) /* Type ID2 Match reg */
144
+#define GEM_TIDMATCH3 (0x000000B0 / 4) /* Type ID3 Match reg */
145
+#define GEM_TIDMATCH4 (0x000000B4 / 4) /* Type ID4 Match reg */
146
+#define GEM_WOLAN (0x000000B8 / 4) /* Wake on LAN reg */
147
+#define GEM_IPGSTRETCH (0x000000BC / 4) /* IPG Stretch reg */
148
+#define GEM_SVLAN (0x000000C0 / 4) /* Stacked VLAN reg */
149
+#define GEM_MODID (0x000000FC / 4) /* Module ID reg */
150
+#define GEM_OCTTXLO (0x00000100 / 4) /* Octects transmitted Low reg */
151
+#define GEM_OCTTXHI (0x00000104 / 4) /* Octects transmitted High reg */
152
+#define GEM_TXCNT (0x00000108 / 4) /* Error-free Frames transmitted */
153
+#define GEM_TXBCNT (0x0000010C / 4) /* Error-free Broadcast Frames */
154
+#define GEM_TXMCNT (0x00000110 / 4) /* Error-free Multicast Frame */
155
+#define GEM_TXPAUSECNT (0x00000114 / 4) /* Pause Frames Transmitted */
156
+#define GEM_TX64CNT (0x00000118 / 4) /* Error-free 64 TX */
157
+#define GEM_TX65CNT (0x0000011C / 4) /* Error-free 65-127 TX */
158
+#define GEM_TX128CNT (0x00000120 / 4) /* Error-free 128-255 TX */
159
+#define GEM_TX256CNT (0x00000124 / 4) /* Error-free 256-511 */
160
+#define GEM_TX512CNT (0x00000128 / 4) /* Error-free 512-1023 TX */
161
+#define GEM_TX1024CNT (0x0000012C / 4) /* Error-free 1024-1518 TX */
162
+#define GEM_TX1519CNT (0x00000130 / 4) /* Error-free larger than 1519 TX */
163
+#define GEM_TXURUNCNT (0x00000134 / 4) /* TX under run error counter */
164
+#define GEM_SINGLECOLLCNT (0x00000138 / 4) /* Single Collision Frames */
165
+#define GEM_MULTCOLLCNT (0x0000013C / 4) /* Multiple Collision Frames */
166
+#define GEM_EXCESSCOLLCNT (0x00000140 / 4) /* Excessive Collision Frames */
167
+#define GEM_LATECOLLCNT (0x00000144 / 4) /* Late Collision Frames */
168
+#define GEM_DEFERTXCNT (0x00000148 / 4) /* Deferred Transmission Frames */
169
+#define GEM_CSENSECNT (0x0000014C / 4) /* Carrier Sense Error Counter */
170
+#define GEM_OCTRXLO (0x00000150 / 4) /* Octects Received register Low */
171
+#define GEM_OCTRXHI (0x00000154 / 4) /* Octects Received register High */
172
+#define GEM_RXCNT (0x00000158 / 4) /* Error-free Frames Received */
173
+#define GEM_RXBROADCNT (0x0000015C / 4) /* Error-free Broadcast Frames RX */
174
+#define GEM_RXMULTICNT (0x00000160 / 4) /* Error-free Multicast Frames RX */
175
+#define GEM_RXPAUSECNT (0x00000164 / 4) /* Pause Frames Received Counter */
176
+#define GEM_RX64CNT (0x00000168 / 4) /* Error-free 64 byte Frames RX */
177
+#define GEM_RX65CNT (0x0000016C / 4) /* Error-free 65-127B Frames RX */
178
+#define GEM_RX128CNT (0x00000170 / 4) /* Error-free 128-255B Frames RX */
179
+#define GEM_RX256CNT (0x00000174 / 4) /* Error-free 256-512B Frames RX */
180
+#define GEM_RX512CNT (0x00000178 / 4) /* Error-free 512-1023B Frames RX */
181
+#define GEM_RX1024CNT (0x0000017C / 4) /* Error-free 1024-1518B Frames RX */
182
+#define GEM_RX1519CNT (0x00000180 / 4) /* Error-free 1519-max Frames RX */
183
+#define GEM_RXUNDERCNT (0x00000184 / 4) /* Undersize Frames Received */
184
+#define GEM_RXOVERCNT (0x00000188 / 4) /* Oversize Frames Received */
185
+#define GEM_RXJABCNT (0x0000018C / 4) /* Jabbers Received Counter */
186
+#define GEM_RXFCSCNT (0x00000190 / 4) /* Frame Check seq. Error Counter */
187
+#define GEM_RXLENERRCNT (0x00000194 / 4) /* Length Field Error Counter */
188
+#define GEM_RXSYMERRCNT (0x00000198 / 4) /* Symbol Error Counter */
189
+#define GEM_RXALIGNERRCNT (0x0000019C / 4) /* Alignment Error Counter */
190
+#define GEM_RXRSCERRCNT (0x000001A0 / 4) /* Receive Resource Error Counter */
191
+#define GEM_RXORUNCNT (0x000001A4 / 4) /* Receive Overrun Counter */
192
+#define GEM_RXIPCSERRCNT (0x000001A8 / 4) /* IP header Checksum Err Counter */
193
+#define GEM_RXTCPCCNT (0x000001AC / 4) /* TCP Checksum Error Counter */
194
+#define GEM_RXUDPCCNT (0x000001B0 / 4) /* UDP Checksum Error Counter */
195
+
196
+#define GEM_1588S (0x000001D0 / 4) /* 1588 Timer Seconds */
197
+#define GEM_1588NS (0x000001D4 / 4) /* 1588 Timer Nanoseconds */
198
+#define GEM_1588ADJ (0x000001D8 / 4) /* 1588 Timer Adjust */
199
+#define GEM_1588INC (0x000001DC / 4) /* 1588 Timer Increment */
200
+#define GEM_PTPETXS (0x000001E0 / 4) /* PTP Event Frame Transmitted (s) */
201
+#define GEM_PTPETXNS (0x000001E4 / 4) /*
202
+ * PTP Event Frame Transmitted (ns)
203
+ */
204
+#define GEM_PTPERXS (0x000001E8 / 4) /* PTP Event Frame Received (s) */
205
+#define GEM_PTPERXNS (0x000001EC / 4) /* PTP Event Frame Received (ns) */
206
+#define GEM_PTPPTXS (0x000001E0 / 4) /* PTP Peer Frame Transmitted (s) */
207
+#define GEM_PTPPTXNS (0x000001E4 / 4) /* PTP Peer Frame Transmitted (ns) */
208
+#define GEM_PTPPRXS (0x000001E8 / 4) /* PTP Peer Frame Received (s) */
209
+#define GEM_PTPPRXNS (0x000001EC / 4) /* PTP Peer Frame Received (ns) */
210
211
/* Design Configuration Registers */
212
-#define GEM_DESCONF (0x00000280/4)
213
-#define GEM_DESCONF2 (0x00000284/4)
214
-#define GEM_DESCONF3 (0x00000288/4)
215
-#define GEM_DESCONF4 (0x0000028C/4)
216
-#define GEM_DESCONF5 (0x00000290/4)
217
-#define GEM_DESCONF6 (0x00000294/4)
218
+#define GEM_DESCONF (0x00000280 / 4)
219
+#define GEM_DESCONF2 (0x00000284 / 4)
220
+#define GEM_DESCONF3 (0x00000288 / 4)
221
+#define GEM_DESCONF4 (0x0000028C / 4)
222
+#define GEM_DESCONF5 (0x00000290 / 4)
223
+#define GEM_DESCONF6 (0x00000294 / 4)
224
#define GEM_DESCONF6_64B_MASK (1U << 23)
225
-#define GEM_DESCONF7 (0x00000298/4)
226
+#define GEM_DESCONF7 (0x00000298 / 4)
227
228
#define GEM_INT_Q1_STATUS (0x00000400 / 4)
229
#define GEM_INT_Q1_MASK (0x00000640 / 4)
230
--
231
2.5.0
232
233
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
2
2
3
RSS program and Makefile to build it.
3
Add a property "jumbo-max-len", which sets default value of jumbo frames
4
The bpftool used to generate '.h' file.
4
up to 16,383 bytes. Add Frame length checks for standard and jumbo
5
The data in that file may be loaded by libbpf.
5
frames.
6
EBPF compilation is not required for building qemu.
7
You can use Makefile if you need to regenerate rss.bpf.skeleton.h.
8
6
9
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
7
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
10
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
8
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
10
---
13
tools/ebpf/Makefile.ebpf | 21 ++
11
hw/net/cadence_gem.c | 51 +++++++++++++++++++++++++++++++++++++++-----
14
tools/ebpf/rss.bpf.c | 569 +++++++++++++++++++++++++++++++++++++++++++++++
12
include/hw/net/cadence_gem.h | 4 +++-
15
2 files changed, 590 insertions(+)
13
2 files changed, 49 insertions(+), 6 deletions(-)
16
create mode 100755 tools/ebpf/Makefile.ebpf
17
create mode 100644 tools/ebpf/rss.bpf.c
18
14
19
diff --git a/tools/ebpf/Makefile.ebpf b/tools/ebpf/Makefile.ebpf
15
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
20
new file mode 100755
16
index XXXXXXX..XXXXXXX 100644
21
index XXXXXXX..XXXXXXX
17
--- a/hw/net/cadence_gem.c
22
--- /dev/null
18
+++ b/hw/net/cadence_gem.c
23
+++ b/tools/ebpf/Makefile.ebpf
24
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
25
+OBJS = rss.bpf.o
20
#define GEM_TXPAUSE (0x0000003C / 4) /* TX Pause Time reg */
26
+
21
#define GEM_TXPARTIALSF (0x00000040 / 4) /* TX Partial Store and Forward */
27
+LLC ?= llc
22
#define GEM_RXPARTIALSF (0x00000044 / 4) /* RX Partial Store and Forward */
28
+CLANG ?= clang
23
+#define GEM_JUMBO_MAX_LEN (0x00000048 / 4) /* Max Jumbo Frame Size */
29
+INC_FLAGS = `$(CLANG) -print-file-name=include`
24
#define GEM_HASHLO (0x00000080 / 4) /* Hash Low address reg */
30
+EXTRA_CFLAGS ?= -O2 -emit-llvm -fno-stack-protector
25
#define GEM_HASHHI (0x00000084 / 4) /* Hash High address reg */
31
+
26
#define GEM_SPADDR1LO (0x00000088 / 4) /* Specific addr 1 low reg */
32
+all: $(OBJS)
33
+
34
+.PHONY: clean
35
+
36
+clean:
37
+    rm -f $(OBJS)
38
+
39
+$(OBJS): %.o:%.c
40
+    $(CLANG) $(INC_FLAGS) \
41
+ -D__KERNEL__ -D__ASM_SYSREG_H \
42
+ -I../include $(LINUXINCLUDE) \
43
+ $(EXTRA_CFLAGS) -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $@
44
+    bpftool gen skeleton rss.bpf.o > rss.bpf.skeleton.h
45
+    cp rss.bpf.skeleton.h ../../ebpf/
46
diff --git a/tools/ebpf/rss.bpf.c b/tools/ebpf/rss.bpf.c
47
new file mode 100644
48
index XXXXXXX..XXXXXXX
49
--- /dev/null
50
+++ b/tools/ebpf/rss.bpf.c
51
@@ -XXX,XX +XXX,XX @@
27
@@ -XXX,XX +XXX,XX @@
52
+/*
28
#define GEM_NWCFG_LERR_DISC 0x00010000 /* Discard RX frames with len err */
53
+ * eBPF RSS program
29
#define GEM_NWCFG_BUFF_OFST_M 0x0000C000 /* Receive buffer offset mask */
54
+ *
30
#define GEM_NWCFG_BUFF_OFST_S 14 /* Receive buffer offset shift */
55
+ * Developed by Daynix Computing LTD (http://www.daynix.com)
31
+#define GEM_NWCFG_RCV_1538 0x00000100 /* Receive 1538 bytes frame */
56
+ *
32
#define GEM_NWCFG_UCAST_HASH 0x00000080 /* accept unicast if hash match */
57
+ * Authors:
33
#define GEM_NWCFG_MCAST_HASH 0x00000040 /* accept multicast if hash match */
58
+ * Andrew Melnychenko <andrew@daynix.com>
34
#define GEM_NWCFG_BCAST_REJ 0x00000020 /* Reject broadcast packets */
59
+ * Yuri Benditovich <yuri.benditovich@daynix.com>
35
#define GEM_NWCFG_PROMISC 0x00000010 /* Accept all packets */
60
+ *
36
+#define GEM_NWCFG_JUMBO_FRAME 0x00000008 /* Jumbo Frames enable */
61
+ * This work is licensed under the terms of the GNU GPL, version 2. See
37
62
+ * the COPYING file in the top-level directory.
38
#define GEM_DMACFG_ADDR_64B (1U << 30)
63
+ *
39
#define GEM_DMACFG_TX_BD_EXT (1U << 29)
64
+ * Prepare:
40
@@ -XXX,XX +XXX,XX @@
65
+ * Requires llvm, clang, bpftool, linux kernel tree
41
66
+ *
42
/* GEM_ISR GEM_IER GEM_IDR GEM_IMR */
67
+ * Build rss.bpf.skeleton.h:
43
#define GEM_INT_TXCMPL 0x00000080 /* Transmit Complete */
68
+ * make -f Makefile.ebpf clean all
44
+#define GEM_INT_AMBA_ERR 0x00000040
69
+ */
45
#define GEM_INT_TXUSED 0x00000008
70
+
46
#define GEM_INT_RXUSED 0x00000004
71
+#include <stddef.h>
47
#define GEM_INT_RXCMPL 0x00000002
72
+#include <stdbool.h>
48
@@ -XXX,XX +XXX,XX @@ static inline void rx_desc_set_sar(uint32_t *desc, int sar_idx)
73
+#include <linux/bpf.h>
49
/* The broadcast MAC address: 0xFFFFFFFFFFFF */
74
+
50
static const uint8_t broadcast_addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
75
+#include <linux/in.h>
51
76
+#include <linux/if_ether.h>
52
+static uint32_t gem_get_max_buf_len(CadenceGEMState *s, bool tx)
77
+#include <linux/ip.h>
53
+{
78
+#include <linux/ipv6.h>
54
+ uint32_t size;
79
+
55
+ if (s->regs[GEM_NWCFG] & GEM_NWCFG_JUMBO_FRAME) {
80
+#include <linux/udp.h>
56
+ size = s->regs[GEM_JUMBO_MAX_LEN];
81
+#include <linux/tcp.h>
57
+ if (size > s->jumbo_max_len) {
82
+
58
+ size = s->jumbo_max_len;
83
+#include <bpf/bpf_helpers.h>
59
+ qemu_log_mask(LOG_GUEST_ERROR, "GEM_JUMBO_MAX_LEN reg cannot be"
84
+#include <bpf/bpf_endian.h>
60
+ " greater than 0x%" PRIx32 "\n", s->jumbo_max_len);
85
+#include <linux/virtio_net.h>
61
+ }
86
+
62
+ } else if (tx) {
87
+#define INDIRECTION_TABLE_SIZE 128
63
+ size = 1518;
88
+#define HASH_CALCULATION_BUFFER_SIZE 36
64
+ } else {
89
+
65
+ size = s->regs[GEM_NWCFG] & GEM_NWCFG_RCV_1538 ? 1538 : 1518;
90
+struct rss_config_t {
66
+ }
91
+ __u8 redirect;
67
+ return size;
92
+ __u8 populate_hash;
93
+ __u32 hash_types;
94
+ __u16 indirections_len;
95
+ __u16 default_queue;
96
+} __attribute__((packed));
97
+
98
+struct toeplitz_key_data_t {
99
+ __u32 leftmost_32_bits;
100
+ __u8 next_byte[HASH_CALCULATION_BUFFER_SIZE];
101
+};
102
+
103
+struct packet_hash_info_t {
104
+ __u8 is_ipv4;
105
+ __u8 is_ipv6;
106
+ __u8 is_udp;
107
+ __u8 is_tcp;
108
+ __u8 is_ipv6_ext_src;
109
+ __u8 is_ipv6_ext_dst;
110
+ __u8 is_fragmented;
111
+
112
+ __u16 src_port;
113
+ __u16 dst_port;
114
+
115
+ union {
116
+ struct {
117
+ __be32 in_src;
118
+ __be32 in_dst;
119
+ };
120
+
121
+ struct {
122
+ struct in6_addr in6_src;
123
+ struct in6_addr in6_dst;
124
+ struct in6_addr in6_ext_src;
125
+ struct in6_addr in6_ext_dst;
126
+ };
127
+ };
128
+};
129
+
130
+struct bpf_map_def SEC("maps")
131
+tap_rss_map_configurations = {
132
+ .type = BPF_MAP_TYPE_ARRAY,
133
+ .key_size = sizeof(__u32),
134
+ .value_size = sizeof(struct rss_config_t),
135
+ .max_entries = 1,
136
+};
137
+
138
+struct bpf_map_def SEC("maps")
139
+tap_rss_map_toeplitz_key = {
140
+ .type = BPF_MAP_TYPE_ARRAY,
141
+ .key_size = sizeof(__u32),
142
+ .value_size = sizeof(struct toeplitz_key_data_t),
143
+ .max_entries = 1,
144
+};
145
+
146
+struct bpf_map_def SEC("maps")
147
+tap_rss_map_indirection_table = {
148
+ .type = BPF_MAP_TYPE_ARRAY,
149
+ .key_size = sizeof(__u32),
150
+ .value_size = sizeof(__u16),
151
+ .max_entries = INDIRECTION_TABLE_SIZE,
152
+};
153
+
154
+static inline void net_rx_rss_add_chunk(__u8 *rss_input, size_t *bytes_written,
155
+ const void *ptr, size_t size) {
156
+ __builtin_memcpy(&rss_input[*bytes_written], ptr, size);
157
+ *bytes_written += size;
158
+}
68
+}
159
+
69
+
160
+static inline
70
static void gem_set_isr(CadenceGEMState *s, int q, uint32_t flag)
161
+void net_toeplitz_add(__u32 *result,
71
{
162
+ __u8 *input,
72
if (q == 0) {
163
+ __u32 len
73
@@ -XXX,XX +XXX,XX @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
164
+ , struct toeplitz_key_data_t *key) {
74
/* Find which queue we are targeting */
165
+
75
q = get_queue_from_screen(s, rxbuf_ptr, rxbufsize);
166
+ __u32 accumulator = *result;
76
167
+ __u32 leftmost_32_bits = key->leftmost_32_bits;
77
+ if (size > gem_get_max_buf_len(s, false)) {
168
+ __u32 byte;
78
+ qemu_log_mask(LOG_GUEST_ERROR, "rx frame too long\n");
169
+
79
+ gem_set_isr(s, q, GEM_INT_AMBA_ERR);
170
+ for (byte = 0; byte < HASH_CALCULATION_BUFFER_SIZE; byte++) {
171
+ __u8 input_byte = input[byte];
172
+ __u8 key_byte = key->next_byte[byte];
173
+ __u8 bit;
174
+
175
+ for (bit = 0; bit < 8; bit++) {
176
+ if (input_byte & (1 << 7)) {
177
+ accumulator ^= leftmost_32_bits;
178
+ }
179
+
180
+ leftmost_32_bits =
181
+ (leftmost_32_bits << 1) | ((key_byte & (1 << 7)) >> 7);
182
+
183
+ input_byte <<= 1;
184
+ key_byte <<= 1;
185
+ }
186
+ }
187
+
188
+ *result = accumulator;
189
+}
190
+
191
+
192
+static inline int ip6_extension_header_type(__u8 hdr_type)
193
+{
194
+ switch (hdr_type) {
195
+ case IPPROTO_HOPOPTS:
196
+ case IPPROTO_ROUTING:
197
+ case IPPROTO_FRAGMENT:
198
+ case IPPROTO_ICMPV6:
199
+ case IPPROTO_NONE:
200
+ case IPPROTO_DSTOPTS:
201
+ case IPPROTO_MH:
202
+ return 1;
203
+ default:
204
+ return 0;
205
+ }
206
+}
207
+/*
208
+ * According to https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml
209
+ * we suspect that there are would be no more than 11 extensions in IPv6 header,
210
+ * also there is 27 TLV options for Destination and Hop-by-hop extensions.
211
+ * Need to choose reasonable amount of maximum extensions/options we may check to find
212
+ * ext src/dst.
213
+ */
214
+#define IP6_EXTENSIONS_COUNT 11
215
+#define IP6_OPTIONS_COUNT 30
216
+
217
+static inline int parse_ipv6_ext(struct __sk_buff *skb,
218
+ struct packet_hash_info_t *info,
219
+ __u8 *l4_protocol, size_t *l4_offset)
220
+{
221
+ int err = 0;
222
+
223
+ if (!ip6_extension_header_type(*l4_protocol)) {
224
+ return 0;
225
+ }
226
+
227
+ struct ipv6_opt_hdr ext_hdr = {};
228
+
229
+ for (unsigned int i = 0; i < IP6_EXTENSIONS_COUNT; ++i) {
230
+
231
+ err = bpf_skb_load_bytes_relative(skb, *l4_offset, &ext_hdr,
232
+ sizeof(ext_hdr), BPF_HDR_START_NET);
233
+ if (err) {
234
+ goto error;
235
+ }
236
+
237
+ if (*l4_protocol == IPPROTO_ROUTING) {
238
+ struct ipv6_rt_hdr ext_rt = {};
239
+
240
+ err = bpf_skb_load_bytes_relative(skb, *l4_offset, &ext_rt,
241
+ sizeof(ext_rt), BPF_HDR_START_NET);
242
+ if (err) {
243
+ goto error;
244
+ }
245
+
246
+ if ((ext_rt.type == IPV6_SRCRT_TYPE_2) &&
247
+ (ext_rt.hdrlen == sizeof(struct in6_addr) / 8) &&
248
+ (ext_rt.segments_left == 1)) {
249
+
250
+ err = bpf_skb_load_bytes_relative(skb,
251
+ *l4_offset + offsetof(struct rt2_hdr, addr),
252
+ &info->in6_ext_dst, sizeof(info->in6_ext_dst),
253
+ BPF_HDR_START_NET);
254
+ if (err) {
255
+ goto error;
256
+ }
257
+
258
+ info->is_ipv6_ext_dst = 1;
259
+ }
260
+
261
+ } else if (*l4_protocol == IPPROTO_DSTOPTS) {
262
+ struct ipv6_opt_t {
263
+ __u8 type;
264
+ __u8 length;
265
+ } __attribute__((packed)) opt = {};
266
+
267
+ size_t opt_offset = sizeof(ext_hdr);
268
+
269
+ for (unsigned int j = 0; j < IP6_OPTIONS_COUNT; ++j) {
270
+ err = bpf_skb_load_bytes_relative(skb, *l4_offset + opt_offset,
271
+ &opt, sizeof(opt), BPF_HDR_START_NET);
272
+ if (err) {
273
+ goto error;
274
+ }
275
+
276
+ if (opt.type == IPV6_TLV_HAO) {
277
+ err = bpf_skb_load_bytes_relative(skb,
278
+ *l4_offset + opt_offset + offsetof(struct ipv6_destopt_hao, addr),
279
+ &info->in6_ext_src, sizeof(info->in6_ext_src),
280
+ BPF_HDR_START_NET);
281
+ if (err) {
282
+ goto error;
283
+ }
284
+
285
+ info->is_ipv6_ext_src = 1;
286
+ break;
287
+ }
288
+
289
+ opt_offset += (opt.type == IPV6_TLV_PAD1) ?
290
+ 1 : opt.length + sizeof(opt);
291
+
292
+ if (opt_offset + 1 >= ext_hdr.hdrlen * 8) {
293
+ break;
294
+ }
295
+ }
296
+ } else if (*l4_protocol == IPPROTO_FRAGMENT) {
297
+ info->is_fragmented = true;
298
+ }
299
+
300
+ *l4_protocol = ext_hdr.nexthdr;
301
+ *l4_offset += (ext_hdr.hdrlen + 1) * 8;
302
+
303
+ if (!ip6_extension_header_type(ext_hdr.nexthdr)) {
304
+ return 0;
305
+ }
306
+ }
307
+
308
+ return 0;
309
+error:
310
+ return err;
311
+}
312
+
313
+static __be16 parse_eth_type(struct __sk_buff *skb)
314
+{
315
+ unsigned int offset = 12;
316
+ __be16 ret = 0;
317
+ int err = 0;
318
+
319
+ err = bpf_skb_load_bytes_relative(skb, offset, &ret, sizeof(ret),
320
+ BPF_HDR_START_MAC);
321
+ if (err) {
322
+ return 0;
323
+ }
324
+
325
+ switch (bpf_ntohs(ret)) {
326
+ case ETH_P_8021AD:
327
+ offset += 4;
328
+ case ETH_P_8021Q:
329
+ offset += 4;
330
+ err = bpf_skb_load_bytes_relative(skb, offset, &ret, sizeof(ret),
331
+ BPF_HDR_START_MAC);
332
+ default:
333
+ break;
334
+ }
335
+
336
+ if (err) {
337
+ return 0;
338
+ }
339
+
340
+ return ret;
341
+}
342
+
343
+static inline int parse_packet(struct __sk_buff *skb,
344
+ struct packet_hash_info_t *info)
345
+{
346
+ int err = 0;
347
+
348
+ if (!info || !skb) {
349
+ return -1;
80
+ return -1;
350
+ }
81
+ }
351
+
82
+
352
+ size_t l4_offset = 0;
83
while (bytes_to_copy) {
353
+ __u8 l4_protocol = 0;
84
hwaddr desc_addr;
354
+ __u16 l3_protocol = bpf_ntohs(parse_eth_type(skb));
85
355
+ if (l3_protocol == 0) {
86
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
356
+ err = -1;
87
break;
357
+ goto error;
88
}
89
90
- if (tx_desc_get_length(desc) > MAX_FRAME_SIZE -
91
+ if (tx_desc_get_length(desc) > gem_get_max_buf_len(s, true) -
92
(p - s->tx_packet)) {
93
- DB_PRINT("TX descriptor @ 0x%" HWADDR_PRIx \
94
- " too large: size 0x%x space 0x%zx\n",
95
+ qemu_log_mask(LOG_GUEST_ERROR, "TX descriptor @ 0x%" \
96
+ HWADDR_PRIx " too large: size 0x%x space 0x%zx\n",
97
packet_desc_addr, tx_desc_get_length(desc),
98
- MAX_FRAME_SIZE - (p - s->tx_packet));
99
+ gem_get_max_buf_len(s, true) - (p - s->tx_packet));
100
+ gem_set_isr(s, q, GEM_INT_AMBA_ERR);
101
break;
102
}
103
104
@@ -XXX,XX +XXX,XX @@ static void gem_reset(DeviceState *d)
105
s->regs[GEM_RXPARTIALSF] = 0x000003ff;
106
s->regs[GEM_MODID] = s->revision;
107
s->regs[GEM_DESCONF] = 0x02500111;
108
- s->regs[GEM_DESCONF2] = 0x2ab13fff;
109
+ s->regs[GEM_DESCONF2] = 0x2ab10000 | s->jumbo_max_len;
110
s->regs[GEM_DESCONF5] = 0x002f2045;
111
s->regs[GEM_DESCONF6] = GEM_DESCONF6_64B_MASK;
112
+ s->regs[GEM_JUMBO_MAX_LEN] = s->jumbo_max_len;
113
114
if (s->num_priority_queues > 1) {
115
queues_mask = MAKE_64BIT_MASK(1, s->num_priority_queues - 1);
116
@@ -XXX,XX +XXX,XX @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
117
s->regs[GEM_IMR] &= ~val;
118
gem_update_int_status(s);
119
break;
120
+ case GEM_JUMBO_MAX_LEN:
121
+ s->regs[GEM_JUMBO_MAX_LEN] = val & MAX_JUMBO_FRAME_SIZE_MASK;
122
+ break;
123
case GEM_INT_Q1_ENABLE ... GEM_INT_Q7_ENABLE:
124
s->regs[GEM_INT_Q1_MASK + offset - GEM_INT_Q1_ENABLE] &= ~val;
125
gem_update_int_status(s);
126
@@ -XXX,XX +XXX,XX @@ static void gem_realize(DeviceState *dev, Error **errp)
127
128
s->nic = qemu_new_nic(&net_gem_info, &s->conf,
129
object_get_typename(OBJECT(dev)), dev->id, s);
130
+
131
+ if (s->jumbo_max_len > MAX_FRAME_SIZE) {
132
+ error_setg(errp, "jumbo-max-len is greater than %d",
133
+ MAX_FRAME_SIZE);
134
+ return;
358
+ }
135
+ }
359
+
136
}
360
+ if (l3_protocol == ETH_P_IP) {
137
361
+ info->is_ipv4 = 1;
138
static void gem_init(Object *obj)
362
+
139
@@ -XXX,XX +XXX,XX @@ static Property gem_properties[] = {
363
+ struct iphdr ip = {};
140
num_type1_screeners, 4),
364
+ err = bpf_skb_load_bytes_relative(skb, 0, &ip, sizeof(ip),
141
DEFINE_PROP_UINT8("num-type2-screeners", CadenceGEMState,
365
+ BPF_HDR_START_NET);
142
num_type2_screeners, 4),
366
+ if (err) {
143
+ DEFINE_PROP_UINT16("jumbo-max-len", CadenceGEMState,
367
+ goto error;
144
+ jumbo_max_len, 10240),
368
+ }
145
DEFINE_PROP_END_OF_LIST(),
369
+
146
};
370
+ info->in_src = ip.saddr;
147
371
+ info->in_dst = ip.daddr;
148
diff --git a/include/hw/net/cadence_gem.h b/include/hw/net/cadence_gem.h
372
+ info->is_fragmented = !!ip.frag_off;
149
index XXXXXXX..XXXXXXX 100644
373
+
150
--- a/include/hw/net/cadence_gem.h
374
+ l4_protocol = ip.protocol;
151
+++ b/include/hw/net/cadence_gem.h
375
+ l4_offset = ip.ihl * 4;
152
@@ -XXX,XX +XXX,XX @@
376
+ } else if (l3_protocol == ETH_P_IPV6) {
153
#define MAX_TYPE1_SCREENERS 16
377
+ info->is_ipv6 = 1;
154
#define MAX_TYPE2_SCREENERS 16
378
+
155
379
+ struct ipv6hdr ip6 = {};
156
-#define MAX_FRAME_SIZE 2048
380
+ err = bpf_skb_load_bytes_relative(skb, 0, &ip6, sizeof(ip6),
157
+#define MAX_JUMBO_FRAME_SIZE_MASK 0x3FFF
381
+ BPF_HDR_START_NET);
158
+#define MAX_FRAME_SIZE MAX_JUMBO_FRAME_SIZE_MASK
382
+ if (err) {
159
383
+ goto error;
160
typedef struct CadenceGEMState {
384
+ }
161
/*< private >*/
385
+
162
@@ -XXX,XX +XXX,XX @@ typedef struct CadenceGEMState {
386
+ info->in6_src = ip6.saddr;
163
uint8_t num_type1_screeners;
387
+ info->in6_dst = ip6.daddr;
164
uint8_t num_type2_screeners;
388
+
165
uint32_t revision;
389
+ l4_protocol = ip6.nexthdr;
166
+ uint16_t jumbo_max_len;
390
+ l4_offset = sizeof(ip6);
167
391
+
168
/* GEM registers backing store */
392
+ err = parse_ipv6_ext(skb, info, &l4_protocol, &l4_offset);
169
uint32_t regs[CADENCE_GEM_MAXREG];
393
+ if (err) {
394
+ goto error;
395
+ }
396
+ }
397
+
398
+ if (l4_protocol != 0 && !info->is_fragmented) {
399
+ if (l4_protocol == IPPROTO_TCP) {
400
+ info->is_tcp = 1;
401
+
402
+ struct tcphdr tcp = {};
403
+ err = bpf_skb_load_bytes_relative(skb, l4_offset, &tcp, sizeof(tcp),
404
+ BPF_HDR_START_NET);
405
+ if (err) {
406
+ goto error;
407
+ }
408
+
409
+ info->src_port = tcp.source;
410
+ info->dst_port = tcp.dest;
411
+ } else if (l4_protocol == IPPROTO_UDP) { /* TODO: add udplite? */
412
+ info->is_udp = 1;
413
+
414
+ struct udphdr udp = {};
415
+ err = bpf_skb_load_bytes_relative(skb, l4_offset, &udp, sizeof(udp),
416
+ BPF_HDR_START_NET);
417
+ if (err) {
418
+ goto error;
419
+ }
420
+
421
+ info->src_port = udp.source;
422
+ info->dst_port = udp.dest;
423
+ }
424
+ }
425
+
426
+ return 0;
427
+
428
+error:
429
+ return err;
430
+}
431
+
432
+static inline __u32 calculate_rss_hash(struct __sk_buff *skb,
433
+ struct rss_config_t *config, struct toeplitz_key_data_t *toe)
434
+{
435
+ __u8 rss_input[HASH_CALCULATION_BUFFER_SIZE] = {};
436
+ size_t bytes_written = 0;
437
+ __u32 result = 0;
438
+ int err = 0;
439
+ struct packet_hash_info_t packet_info = {};
440
+
441
+ err = parse_packet(skb, &packet_info);
442
+ if (err) {
443
+ return 0;
444
+ }
445
+
446
+ if (packet_info.is_ipv4) {
447
+ if (packet_info.is_tcp &&
448
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_TCPv4) {
449
+
450
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
451
+ &packet_info.in_src,
452
+ sizeof(packet_info.in_src));
453
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
454
+ &packet_info.in_dst,
455
+ sizeof(packet_info.in_dst));
456
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
457
+ &packet_info.src_port,
458
+ sizeof(packet_info.src_port));
459
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
460
+ &packet_info.dst_port,
461
+ sizeof(packet_info.dst_port));
462
+ } else if (packet_info.is_udp &&
463
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_UDPv4) {
464
+
465
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
466
+ &packet_info.in_src,
467
+ sizeof(packet_info.in_src));
468
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
469
+ &packet_info.in_dst,
470
+ sizeof(packet_info.in_dst));
471
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
472
+ &packet_info.src_port,
473
+ sizeof(packet_info.src_port));
474
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
475
+ &packet_info.dst_port,
476
+ sizeof(packet_info.dst_port));
477
+ } else if (config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_IPv4) {
478
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
479
+ &packet_info.in_src,
480
+ sizeof(packet_info.in_src));
481
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
482
+ &packet_info.in_dst,
483
+ sizeof(packet_info.in_dst));
484
+ }
485
+ } else if (packet_info.is_ipv6) {
486
+ if (packet_info.is_tcp &&
487
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_TCPv6) {
488
+
489
+ if (packet_info.is_ipv6_ext_src &&
490
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_TCP_EX) {
491
+
492
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
493
+ &packet_info.in6_ext_src,
494
+ sizeof(packet_info.in6_ext_src));
495
+ } else {
496
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
497
+ &packet_info.in6_src,
498
+ sizeof(packet_info.in6_src));
499
+ }
500
+ if (packet_info.is_ipv6_ext_dst &&
501
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_TCP_EX) {
502
+
503
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
504
+ &packet_info.in6_ext_dst,
505
+ sizeof(packet_info.in6_ext_dst));
506
+ } else {
507
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
508
+ &packet_info.in6_dst,
509
+ sizeof(packet_info.in6_dst));
510
+ }
511
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
512
+ &packet_info.src_port,
513
+ sizeof(packet_info.src_port));
514
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
515
+ &packet_info.dst_port,
516
+ sizeof(packet_info.dst_port));
517
+ } else if (packet_info.is_udp &&
518
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_UDPv6) {
519
+
520
+ if (packet_info.is_ipv6_ext_src &&
521
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) {
522
+
523
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
524
+ &packet_info.in6_ext_src,
525
+ sizeof(packet_info.in6_ext_src));
526
+ } else {
527
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
528
+ &packet_info.in6_src,
529
+ sizeof(packet_info.in6_src));
530
+ }
531
+ if (packet_info.is_ipv6_ext_dst &&
532
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_UDP_EX) {
533
+
534
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
535
+ &packet_info.in6_ext_dst,
536
+ sizeof(packet_info.in6_ext_dst));
537
+ } else {
538
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
539
+ &packet_info.in6_dst,
540
+ sizeof(packet_info.in6_dst));
541
+ }
542
+
543
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
544
+ &packet_info.src_port,
545
+ sizeof(packet_info.src_port));
546
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
547
+ &packet_info.dst_port,
548
+ sizeof(packet_info.dst_port));
549
+
550
+ } else if (config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_IPv6) {
551
+ if (packet_info.is_ipv6_ext_src &&
552
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_IP_EX) {
553
+
554
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
555
+ &packet_info.in6_ext_src,
556
+ sizeof(packet_info.in6_ext_src));
557
+ } else {
558
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
559
+ &packet_info.in6_src,
560
+ sizeof(packet_info.in6_src));
561
+ }
562
+ if (packet_info.is_ipv6_ext_dst &&
563
+ config->hash_types & VIRTIO_NET_RSS_HASH_TYPE_IP_EX) {
564
+
565
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
566
+ &packet_info.in6_ext_dst,
567
+ sizeof(packet_info.in6_ext_dst));
568
+ } else {
569
+ net_rx_rss_add_chunk(rss_input, &bytes_written,
570
+ &packet_info.in6_dst,
571
+ sizeof(packet_info.in6_dst));
572
+ }
573
+ }
574
+ }
575
+
576
+ if (bytes_written) {
577
+ net_toeplitz_add(&result, rss_input, bytes_written, toe);
578
+ }
579
+
580
+ return result;
581
+}
582
+
583
+SEC("tun_rss_steering")
584
+int tun_rss_steering_prog(struct __sk_buff *skb)
585
+{
586
+
587
+ struct rss_config_t *config;
588
+ struct toeplitz_key_data_t *toe;
589
+
590
+ __u32 key = 0;
591
+ __u32 hash = 0;
592
+
593
+ config = bpf_map_lookup_elem(&tap_rss_map_configurations, &key);
594
+ toe = bpf_map_lookup_elem(&tap_rss_map_toeplitz_key, &key);
595
+
596
+ if (config && toe) {
597
+ if (!config->redirect) {
598
+ return config->default_queue;
599
+ }
600
+
601
+ hash = calculate_rss_hash(skb, config, toe);
602
+ if (hash) {
603
+ __u32 table_idx = hash % config->indirections_len;
604
+ __u16 *queue = 0;
605
+
606
+ queue = bpf_map_lookup_elem(&tap_rss_map_indirection_table,
607
+ &table_idx);
608
+
609
+ if (queue) {
610
+ return *queue;
611
+ }
612
+ }
613
+
614
+ return config->default_queue;
615
+ }
616
+
617
+ return -1;
618
+}
619
+
620
+char _license[] SEC("license") = "GPL v2";
621
--
170
--
622
2.7.4
171
2.5.0
623
172
624
173
diff view generated by jsdifflib
New patch
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
1
2
3
Advertise support of clear-on-read for ISR registers.
4
5
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
6
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
9
hw/net/cadence_gem.c | 2 +-
10
1 file changed, 1 insertion(+), 1 deletion(-)
11
12
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/net/cadence_gem.c
15
+++ b/hw/net/cadence_gem.c
16
@@ -XXX,XX +XXX,XX @@ static void gem_reset(DeviceState *d)
17
s->regs[GEM_TXPARTIALSF] = 0x000003ff;
18
s->regs[GEM_RXPARTIALSF] = 0x000003ff;
19
s->regs[GEM_MODID] = s->revision;
20
- s->regs[GEM_DESCONF] = 0x02500111;
21
+ s->regs[GEM_DESCONF] = 0x02D00111;
22
s->regs[GEM_DESCONF2] = 0x2ab10000 | s->jumbo_max_len;
23
s->regs[GEM_DESCONF5] = 0x002f2045;
24
s->regs[GEM_DESCONF6] = GEM_DESCONF6_64B_MASK;
25
--
26
2.5.0
27
28
diff view generated by jsdifflib
New patch
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
1
2
3
Mask all interrupt on reset.
4
5
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
6
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
9
hw/net/cadence_gem.c | 1 +
10
1 file changed, 1 insertion(+)
11
12
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/net/cadence_gem.c
15
+++ b/hw/net/cadence_gem.c
16
@@ -XXX,XX +XXX,XX @@ static void gem_reset(DeviceState *d)
17
s->regs[GEM_DESCONF2] = 0x2ab10000 | s->jumbo_max_len;
18
s->regs[GEM_DESCONF5] = 0x002f2045;
19
s->regs[GEM_DESCONF6] = GEM_DESCONF6_64B_MASK;
20
+ s->regs[GEM_INT_Q1_MASK] = 0x00000CE6;
21
s->regs[GEM_JUMBO_MAX_LEN] = s->jumbo_max_len;
22
23
if (s->num_priority_queues > 1) {
24
--
25
2.5.0
26
27
diff view generated by jsdifflib
New patch
1
From: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
1
2
3
TX_LAST bit should not be set by hardware, its set by guest to inform
4
the last bd of the frame.
5
6
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
7
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
8
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
---
11
hw/net/cadence_gem.c | 6 ------
12
1 file changed, 6 deletions(-)
13
14
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/net/cadence_gem.c
17
+++ b/hw/net/cadence_gem.c
18
@@ -XXX,XX +XXX,XX @@ static inline unsigned tx_desc_get_last(uint32_t *desc)
19
return (desc[1] & DESC_1_TX_LAST) ? 1 : 0;
20
}
21
22
-static inline void tx_desc_set_last(uint32_t *desc)
23
-{
24
- desc[1] |= DESC_1_TX_LAST;
25
-}
26
-
27
static inline unsigned tx_desc_get_length(uint32_t *desc)
28
{
29
return desc[1] & DESC_1_LENGTH;
30
@@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s)
31
32
/* read next descriptor */
33
if (tx_desc_get_wrap(desc)) {
34
- tx_desc_set_last(desc);
35
36
if (s->regs[GEM_DMACFG] & GEM_DMACFG_ADDR_64B) {
37
packet_desc_addr = s->regs[GEM_TBQPH];
38
--
39
2.5.0
40
41
diff view generated by jsdifflib
New patch
1
From: Tong Ho <tong.ho@xilinx.com>
1
2
3
Two defects are fixed:
4
5
1/ Detection of multicast frames
6
2/ Treating drop of mis-addressed frames as non-error
7
8
Signed-off-by: Tong Ho <tong.ho@xilinx.com>
9
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
10
Signed-off-by: Sai Pavan Boddu <sai.pavan.boddu@xilinx.com>
11
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
12
Signed-off-by: Jason Wang <jasowang@redhat.com>
13
---
14
hw/net/cadence_gem.c | 26 +++++++++++---------------
15
1 file changed, 11 insertions(+), 15 deletions(-)
16
17
diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/hw/net/cadence_gem.c
20
+++ b/hw/net/cadence_gem.c
21
@@ -XXX,XX +XXX,XX @@
22
#include "qemu/module.h"
23
#include "sysemu/dma.h"
24
#include "net/checksum.h"
25
+#include "net/eth.h"
26
27
#define CADENCE_GEM_ERR_DEBUG 0
28
#define DB_PRINT(...) do {\
29
@@ -XXX,XX +XXX,XX @@ static unsigned calc_mac_hash(const uint8_t *mac)
30
static int gem_mac_address_filter(CadenceGEMState *s, const uint8_t *packet)
31
{
32
uint8_t *gem_spaddr;
33
- int i;
34
+ int i, is_mc;
35
36
/* Promiscuous mode? */
37
if (s->regs[GEM_NWCFG] & GEM_NWCFG_PROMISC) {
38
@@ -XXX,XX +XXX,XX @@ static int gem_mac_address_filter(CadenceGEMState *s, const uint8_t *packet)
39
}
40
41
/* Accept packets -w- hash match? */
42
- if ((packet[0] == 0x01 && (s->regs[GEM_NWCFG] & GEM_NWCFG_MCAST_HASH)) ||
43
- (packet[0] != 0x01 && (s->regs[GEM_NWCFG] & GEM_NWCFG_UCAST_HASH))) {
44
+ is_mc = is_multicast_ether_addr(packet);
45
+ if ((is_mc && (s->regs[GEM_NWCFG] & GEM_NWCFG_MCAST_HASH)) ||
46
+ (!is_mc && (s->regs[GEM_NWCFG] & GEM_NWCFG_UCAST_HASH))) {
47
+ uint64_t buckets;
48
unsigned hash_index;
49
50
hash_index = calc_mac_hash(packet);
51
- if (hash_index < 32) {
52
- if (s->regs[GEM_HASHLO] & (1<<hash_index)) {
53
- return packet[0] == 0x01 ? GEM_RX_MULTICAST_HASH_ACCEPT :
54
- GEM_RX_UNICAST_HASH_ACCEPT;
55
- }
56
- } else {
57
- hash_index -= 32;
58
- if (s->regs[GEM_HASHHI] & (1<<hash_index)) {
59
- return packet[0] == 0x01 ? GEM_RX_MULTICAST_HASH_ACCEPT :
60
- GEM_RX_UNICAST_HASH_ACCEPT;
61
- }
62
+ buckets = ((uint64_t)s->regs[GEM_HASHHI] << 32) | s->regs[GEM_HASHLO];
63
+ if ((buckets >> hash_index) & 1) {
64
+ return is_mc ? GEM_RX_MULTICAST_HASH_ACCEPT
65
+ : GEM_RX_UNICAST_HASH_ACCEPT;
66
}
67
}
68
69
@@ -XXX,XX +XXX,XX @@ static ssize_t gem_receive(NetClientState *nc, const uint8_t *buf, size_t size)
70
/* Is this destination MAC address "for us" ? */
71
maf = gem_mac_address_filter(s, buf);
72
if (maf == GEM_RX_REJECT) {
73
- return -1;
74
+ return size; /* no, drop siliently b/c it's not an error */
75
}
76
77
/* Discard packets with receive length error enabled ? */
78
--
79
2.5.0
80
81
diff view generated by jsdifflib
New patch
1
The sender of packet will be checked in the qemu_net_queue_purge() but
2
we use NetClientState not its peer when trying to purge the incoming
3
queue in qemu_flush_or_purge_packets(). This will trigger the assert
4
in virtio_net_reset since we can't pass the sender check:
1
5
6
hw/net/virtio-net.c:533: void virtio_net_reset(VirtIODevice *): Assertion
7
`!virtio_net_get_subqueue(nc)->async_tx.elem' failed.
8
#9 0x55a33fa31b78 in virtio_net_reset hw/net/virtio-net.c:533:13
9
#10 0x55a33fc88412 in virtio_reset hw/virtio/virtio.c:1919:9
10
#11 0x55a341d82764 in virtio_bus_reset hw/virtio/virtio-bus.c:95:9
11
#12 0x55a341dba2de in virtio_pci_reset hw/virtio/virtio-pci.c:1824:5
12
#13 0x55a341db3e02 in virtio_pci_common_write hw/virtio/virtio-pci.c:1252:13
13
#14 0x55a33f62117b in memory_region_write_accessor memory.c:496:5
14
#15 0x55a33f6205e4 in access_with_adjusted_size memory.c:557:18
15
#16 0x55a33f61e177 in memory_region_dispatch_write memory.c:1488:16
16
17
Reproducer:
18
https://www.mail-archive.com/qemu-devel@nongnu.org/msg701914.html
19
20
Fix by using the peer.
21
22
Reported-by: "Alexander Bulekov" <alxndr@bu.edu>
23
Acked-by: Alexander Bulekov <alxndr@bu.edu>
24
Fixes: ca77d85e1dbf9 ("net: complete all queued packets on VM stop")
25
Cc: qemu-stable@nongnu.org
26
Signed-off-by: Jason Wang <jasowang@redhat.com>
27
---
28
net/net.c | 2 +-
29
1 file changed, 1 insertion(+), 1 deletion(-)
30
31
diff --git a/net/net.c b/net/net.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/net/net.c
34
+++ b/net/net.c
35
@@ -XXX,XX +XXX,XX @@ void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge)
36
qemu_notify_event();
37
} else if (purge) {
38
/* Unable to empty the queue, purge remaining packets */
39
- qemu_net_queue_purge(nc->incoming_queue, nc);
40
+ qemu_net_queue_purge(nc->incoming_queue, nc->peer);
41
}
42
}
43
44
--
45
2.5.0
46
47
diff view generated by jsdifflib
New patch
1
From: Lukas Straub <lukasstraub2@web.de>
1
2
3
qemu_bh_new will set the bh to be executed in the main
4
loop. This causes crashes as colo_compare_handle_event assumes
5
that it has exclusive access the queues, which are also
6
concurrently accessed in the iothread.
7
8
Create the bh with the AioContext of the iothread to fulfill
9
these assumptions and fix the crashes. This is safe, because
10
the bh already takes the appropriate locks.
11
12
Signed-off-by: Lukas Straub <lukasstraub2@web.de>
13
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
14
Reviewed-by: Derek Su <dereksu@qnap.com>
15
Tested-by: Derek Su <dereksu@qnap.com>
16
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
17
Signed-off-by: Jason Wang <jasowang@redhat.com>
18
---
19
net/colo-compare.c | 3 ++-
20
1 file changed, 2 insertions(+), 1 deletion(-)
21
22
diff --git a/net/colo-compare.c b/net/colo-compare.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/net/colo-compare.c
25
+++ b/net/colo-compare.c
26
@@ -XXX,XX +XXX,XX @@ static void colo_compare_handle_event(void *opaque)
27
28
static void colo_compare_iothread(CompareState *s)
29
{
30
+ AioContext *ctx = iothread_get_aio_context(s->iothread);
31
object_ref(OBJECT(s->iothread));
32
s->worker_context = iothread_get_g_main_context(s->iothread);
33
34
@@ -XXX,XX +XXX,XX @@ static void colo_compare_iothread(CompareState *s)
35
}
36
37
colo_compare_timer_init(s);
38
- s->event_bh = qemu_bh_new(colo_compare_handle_event, s);
39
+ s->event_bh = aio_bh_new(ctx, colo_compare_handle_event, s);
40
}
41
42
static char *compare_get_pri_indev(Object *obj, Error **errp)
43
--
44
2.5.0
45
46
diff view generated by jsdifflib
New patch
1
From: Lukas Straub <lukasstraub2@web.de>
1
2
3
To be able to convert compare_chr_send to a coroutine in the
4
next commit, use qemu_co_sleep_ns if in coroutine.
5
6
Signed-off-by: Lukas Straub <lukasstraub2@web.de>
7
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
8
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
10
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
13
chardev/char.c | 7 ++++++-
14
1 file changed, 6 insertions(+), 1 deletion(-)
15
16
diff --git a/chardev/char.c b/chardev/char.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/chardev/char.c
19
+++ b/chardev/char.c
20
@@ -XXX,XX +XXX,XX @@
21
#include "qemu/module.h"
22
#include "qemu/option.h"
23
#include "qemu/id.h"
24
+#include "qemu/coroutine.h"
25
26
#include "chardev/char-mux.h"
27
28
@@ -XXX,XX +XXX,XX @@ static int qemu_chr_write_buffer(Chardev *s,
29
retry:
30
res = cc->chr_write(s, buf + *offset, len - *offset);
31
if (res < 0 && errno == EAGAIN && write_all) {
32
- g_usleep(100);
33
+ if (qemu_in_coroutine()) {
34
+ qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000);
35
+ } else {
36
+ g_usleep(100);
37
+ }
38
goto retry;
39
}
40
41
--
42
2.5.0
43
44
diff view generated by jsdifflib
New patch
1
1
From: Lukas Straub <lukasstraub2@web.de>
2
3
The chr_out chardev is connected to a filter-redirector
4
running in the main loop. qemu_chr_fe_write_all might block
5
here in compare_chr_send if the (socket-)buffer is full.
6
If another filter-redirector in the main loop want's to
7
send data to chr_pri_in it might also block if the buffer
8
is full. This leads to a deadlock because both event loops
9
get blocked.
10
11
Fix this by converting compare_chr_send to a coroutine and
12
putting the packets in a send queue.
13
14
Signed-off-by: Lukas Straub <lukasstraub2@web.de>
15
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
16
Tested-by: Zhang Chen <chen.zhang@intel.com>
17
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
18
Signed-off-by: Jason Wang <jasowang@redhat.com>
19
---
20
net/colo-compare.c | 193 ++++++++++++++++++++++++++++++++++++++++-------------
21
net/colo.c | 7 ++
22
net/colo.h | 1 +
23
3 files changed, 156 insertions(+), 45 deletions(-)
24
25
diff --git a/net/colo-compare.c b/net/colo-compare.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/net/colo-compare.c
28
+++ b/net/colo-compare.c
29
@@ -XXX,XX +XXX,XX @@
30
#include "migration/migration.h"
31
#include "util.h"
32
33
+#include "block/aio-wait.h"
34
+#include "qemu/coroutine.h"
35
+
36
#define TYPE_COLO_COMPARE "colo-compare"
37
#define COLO_COMPARE(obj) \
38
OBJECT_CHECK(CompareState, (obj), TYPE_COLO_COMPARE)
39
@@ -XXX,XX +XXX,XX @@ static int event_unhandled_count;
40
* |packet | |packet + |packet | |packet +
41
* +--------+ +--------+ +--------+ +--------+
42
*/
43
+
44
+typedef struct SendCo {
45
+ Coroutine *co;
46
+ struct CompareState *s;
47
+ CharBackend *chr;
48
+ GQueue send_list;
49
+ bool notify_remote_frame;
50
+ bool done;
51
+ int ret;
52
+} SendCo;
53
+
54
+typedef struct SendEntry {
55
+ uint32_t size;
56
+ uint32_t vnet_hdr_len;
57
+ uint8_t *buf;
58
+} SendEntry;
59
+
60
typedef struct CompareState {
61
Object parent;
62
63
@@ -XXX,XX +XXX,XX @@ typedef struct CompareState {
64
SocketReadState pri_rs;
65
SocketReadState sec_rs;
66
SocketReadState notify_rs;
67
+ SendCo out_sendco;
68
+ SendCo notify_sendco;
69
bool vnet_hdr;
70
uint32_t compare_timeout;
71
uint32_t expired_scan_cycle;
72
@@ -XXX,XX +XXX,XX @@ enum {
73
74
75
static int compare_chr_send(CompareState *s,
76
- const uint8_t *buf,
77
+ uint8_t *buf,
78
uint32_t size,
79
uint32_t vnet_hdr_len,
80
- bool notify_remote_frame);
81
+ bool notify_remote_frame,
82
+ bool zero_copy);
83
84
static bool packet_matches_str(const char *str,
85
const uint8_t *buf,
86
@@ -XXX,XX +XXX,XX @@ static void notify_remote_frame(CompareState *s)
87
char msg[] = "DO_CHECKPOINT";
88
int ret = 0;
89
90
- ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true);
91
+ ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true, false);
92
if (ret < 0) {
93
error_report("Notify Xen COLO-frame failed");
94
}
95
@@ -XXX,XX +XXX,XX @@ static void colo_release_primary_pkt(CompareState *s, Packet *pkt)
96
pkt->data,
97
pkt->size,
98
pkt->vnet_hdr_len,
99
- false);
100
+ false,
101
+ true);
102
if (ret < 0) {
103
error_report("colo send primary packet failed");
104
}
105
trace_colo_compare_main("packet same and release packet");
106
- packet_destroy(pkt, NULL);
107
+ packet_destroy_partial(pkt, NULL);
108
}
109
110
/*
111
@@ -XXX,XX +XXX,XX @@ static void colo_compare_connection(void *opaque, void *user_data)
112
}
113
}
114
115
-static int compare_chr_send(CompareState *s,
116
- const uint8_t *buf,
117
- uint32_t size,
118
- uint32_t vnet_hdr_len,
119
- bool notify_remote_frame)
120
+static void coroutine_fn _compare_chr_send(void *opaque)
121
{
122
+ SendCo *sendco = opaque;
123
+ CompareState *s = sendco->s;
124
int ret = 0;
125
- uint32_t len = htonl(size);
126
127
- if (!size) {
128
- return 0;
129
- }
130
+ while (!g_queue_is_empty(&sendco->send_list)) {
131
+ SendEntry *entry = g_queue_pop_tail(&sendco->send_list);
132
+ uint32_t len = htonl(entry->size);
133
134
- if (notify_remote_frame) {
135
- ret = qemu_chr_fe_write_all(&s->chr_notify_dev,
136
- (uint8_t *)&len,
137
- sizeof(len));
138
- } else {
139
- ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len));
140
- }
141
+ ret = qemu_chr_fe_write_all(sendco->chr, (uint8_t *)&len, sizeof(len));
142
143
- if (ret != sizeof(len)) {
144
- goto err;
145
- }
146
+ if (ret != sizeof(len)) {
147
+ g_free(entry->buf);
148
+ g_slice_free(SendEntry, entry);
149
+ goto err;
150
+ }
151
152
- if (s->vnet_hdr) {
153
- /*
154
- * We send vnet header len make other module(like filter-redirector)
155
- * know how to parse net packet correctly.
156
- */
157
- len = htonl(vnet_hdr_len);
158
+ if (!sendco->notify_remote_frame && s->vnet_hdr) {
159
+ /*
160
+ * We send vnet header len make other module(like filter-redirector)
161
+ * know how to parse net packet correctly.
162
+ */
163
+ len = htonl(entry->vnet_hdr_len);
164
165
- if (!notify_remote_frame) {
166
- ret = qemu_chr_fe_write_all(&s->chr_out,
167
+ ret = qemu_chr_fe_write_all(sendco->chr,
168
(uint8_t *)&len,
169
sizeof(len));
170
+
171
+ if (ret != sizeof(len)) {
172
+ g_free(entry->buf);
173
+ g_slice_free(SendEntry, entry);
174
+ goto err;
175
+ }
176
}
177
178
- if (ret != sizeof(len)) {
179
+ ret = qemu_chr_fe_write_all(sendco->chr,
180
+ (uint8_t *)entry->buf,
181
+ entry->size);
182
+
183
+ if (ret != entry->size) {
184
+ g_free(entry->buf);
185
+ g_slice_free(SendEntry, entry);
186
goto err;
187
}
188
+
189
+ g_free(entry->buf);
190
+ g_slice_free(SendEntry, entry);
191
}
192
193
+ sendco->ret = 0;
194
+ goto out;
195
+
196
+err:
197
+ while (!g_queue_is_empty(&sendco->send_list)) {
198
+ SendEntry *entry = g_queue_pop_tail(&sendco->send_list);
199
+ g_free(entry->buf);
200
+ g_slice_free(SendEntry, entry);
201
+ }
202
+ sendco->ret = ret < 0 ? ret : -EIO;
203
+out:
204
+ sendco->co = NULL;
205
+ sendco->done = true;
206
+ aio_wait_kick();
207
+}
208
+
209
+static int compare_chr_send(CompareState *s,
210
+ uint8_t *buf,
211
+ uint32_t size,
212
+ uint32_t vnet_hdr_len,
213
+ bool notify_remote_frame,
214
+ bool zero_copy)
215
+{
216
+ SendCo *sendco;
217
+ SendEntry *entry;
218
+
219
if (notify_remote_frame) {
220
- ret = qemu_chr_fe_write_all(&s->chr_notify_dev,
221
- (uint8_t *)buf,
222
- size);
223
+ sendco = &s->notify_sendco;
224
} else {
225
- ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size);
226
+ sendco = &s->out_sendco;
227
}
228
229
- if (ret != size) {
230
- goto err;
231
+ if (!size) {
232
+ return 0;
233
}
234
235
- return 0;
236
+ entry = g_slice_new(SendEntry);
237
+ entry->size = size;
238
+ entry->vnet_hdr_len = vnet_hdr_len;
239
+ if (zero_copy) {
240
+ entry->buf = buf;
241
+ } else {
242
+ entry->buf = g_malloc(size);
243
+ memcpy(entry->buf, buf, size);
244
+ }
245
+ g_queue_push_head(&sendco->send_list, entry);
246
+
247
+ if (sendco->done) {
248
+ sendco->co = qemu_coroutine_create(_compare_chr_send, sendco);
249
+ sendco->done = false;
250
+ qemu_coroutine_enter(sendco->co);
251
+ if (sendco->done) {
252
+ /* report early errors */
253
+ return sendco->ret;
254
+ }
255
+ }
256
257
-err:
258
- return ret < 0 ? ret : -EIO;
259
+ /* assume success */
260
+ return 0;
261
}
262
263
static int compare_chr_can_read(void *opaque)
264
@@ -XXX,XX +XXX,XX @@ static void compare_pri_rs_finalize(SocketReadState *pri_rs)
265
pri_rs->buf,
266
pri_rs->packet_len,
267
pri_rs->vnet_hdr_len,
268
+ false,
269
false);
270
} else {
271
/* compare packet in the specified connection */
272
@@ -XXX,XX +XXX,XX @@ static void compare_notify_rs_finalize(SocketReadState *notify_rs)
273
if (packet_matches_str("COLO_USERSPACE_PROXY_INIT",
274
notify_rs->buf,
275
notify_rs->packet_len)) {
276
- ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true);
277
+ ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true, false);
278
if (ret < 0) {
279
error_report("Notify Xen COLO-frame INIT failed");
280
}
281
@@ -XXX,XX +XXX,XX @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
282
283
QTAILQ_INSERT_TAIL(&net_compares, s, next);
284
285
+ s->out_sendco.s = s;
286
+ s->out_sendco.chr = &s->chr_out;
287
+ s->out_sendco.notify_remote_frame = false;
288
+ s->out_sendco.done = true;
289
+ g_queue_init(&s->out_sendco.send_list);
290
+
291
+ if (s->notify_dev) {
292
+ s->notify_sendco.s = s;
293
+ s->notify_sendco.chr = &s->chr_notify_dev;
294
+ s->notify_sendco.notify_remote_frame = true;
295
+ s->notify_sendco.done = true;
296
+ g_queue_init(&s->notify_sendco.send_list);
297
+ }
298
+
299
g_queue_init(&s->conn_list);
300
301
qemu_mutex_init(&event_mtx);
302
@@ -XXX,XX +XXX,XX @@ static void colo_flush_packets(void *opaque, void *user_data)
303
pkt->data,
304
pkt->size,
305
pkt->vnet_hdr_len,
306
- false);
307
- packet_destroy(pkt, NULL);
308
+ false,
309
+ true);
310
+ packet_destroy_partial(pkt, NULL);
311
}
312
while (!g_queue_is_empty(&conn->secondary_list)) {
313
pkt = g_queue_pop_head(&conn->secondary_list);
314
@@ -XXX,XX +XXX,XX @@ static void colo_compare_finalize(Object *obj)
315
}
316
}
317
318
+ AioContext *ctx = iothread_get_aio_context(s->iothread);
319
+ aio_context_acquire(ctx);
320
+ AIO_WAIT_WHILE(ctx, !s->out_sendco.done);
321
+ if (s->notify_dev) {
322
+ AIO_WAIT_WHILE(ctx, !s->notify_sendco.done);
323
+ }
324
+ aio_context_release(ctx);
325
+
326
/* Release all unhandled packets after compare thead exited */
327
g_queue_foreach(&s->conn_list, colo_flush_packets, s);
328
+ AIO_WAIT_WHILE(NULL, !s->out_sendco.done);
329
330
g_queue_clear(&s->conn_list);
331
+ g_queue_clear(&s->out_sendco.send_list);
332
+ if (s->notify_dev) {
333
+ g_queue_clear(&s->notify_sendco.send_list);
334
+ }
335
336
if (s->connection_track_table) {
337
g_hash_table_destroy(s->connection_track_table);
338
diff --git a/net/colo.c b/net/colo.c
339
index XXXXXXX..XXXXXXX 100644
340
--- a/net/colo.c
341
+++ b/net/colo.c
342
@@ -XXX,XX +XXX,XX @@ void packet_destroy(void *opaque, void *user_data)
343
g_slice_free(Packet, pkt);
344
}
345
346
+void packet_destroy_partial(void *opaque, void *user_data)
347
+{
348
+ Packet *pkt = opaque;
349
+
350
+ g_slice_free(Packet, pkt);
351
+}
352
+
353
/*
354
* Clear hashtable, stop this hash growing really huge
355
*/
356
diff --git a/net/colo.h b/net/colo.h
357
index XXXXXXX..XXXXXXX 100644
358
--- a/net/colo.h
359
+++ b/net/colo.h
360
@@ -XXX,XX +XXX,XX @@ bool connection_has_tracked(GHashTable *connection_track_table,
361
void connection_hashtable_reset(GHashTable *connection_track_table);
362
Packet *packet_new(const void *data, int size, int vnet_hdr_len);
363
void packet_destroy(void *opaque, void *user_data);
364
+void packet_destroy_partial(void *opaque, void *user_data);
365
366
#endif /* NET_COLO_H */
367
--
368
2.5.0
369
370
diff view generated by jsdifflib
New patch
1
From: Lukas Straub <lukasstraub2@web.de>
1
2
3
Else the log will be flooded if there is a lot of network
4
traffic.
5
6
Signed-off-by: Lukas Straub <lukasstraub2@web.de>
7
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
10
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
13
net/colo-compare.c | 10 ++++++----
14
1 file changed, 6 insertions(+), 4 deletions(-)
15
16
diff --git a/net/colo-compare.c b/net/colo-compare.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/net/colo-compare.c
19
+++ b/net/colo-compare.c
20
@@ -XXX,XX +XXX,XX @@ sec:
21
g_queue_push_head(&conn->primary_list, ppkt);
22
g_queue_push_head(&conn->secondary_list, spkt);
23
24
- qemu_hexdump((char *)ppkt->data, stderr,
25
- "colo-compare ppkt", ppkt->size);
26
- qemu_hexdump((char *)spkt->data, stderr,
27
- "colo-compare spkt", spkt->size);
28
+ if (trace_event_get_state_backends(TRACE_COLO_COMPARE_MISCOMPARE)) {
29
+ qemu_hexdump((char *)ppkt->data, stderr,
30
+ "colo-compare ppkt", ppkt->size);
31
+ qemu_hexdump((char *)spkt->data, stderr,
32
+ "colo-compare spkt", spkt->size);
33
+ }
34
35
colo_compare_inconsistency_notify(s);
36
}
37
--
38
2.5.0
39
40
diff view generated by jsdifflib
1
From: Guenter Roeck <linux@roeck-us.net>
1
From: Lukas Straub <lukasstraub2@web.de>
2
2
3
If a PHY does not exist, attempts to read from it should return 0xffff.
3
If the colo-compare object is removed before failover and a
4
Otherwise the Linux kernel will believe that a PHY is there and select
4
checkpoint happens, qemu crashes because it tries to lock
5
the non-existing PHY. This in turn will result in network errors later
5
the destroyed event_mtx in colo_notify_compares_event.
6
on since the real PHY is not selected or configured.
7
6
8
Since reading from or writing to a non-existing PHY is not an emulation
7
Fix this by checking if everything is initialized by
9
error, replace guest error messages with traces.
8
introducing a new variable colo_compare_active which
9
is protected by a new mutex colo_compare_mutex. The new mutex
10
also protects against concurrent access of the net_compares
11
list and makes sure that colo_notify_compares_event isn't
12
active while we destroy event_mtx and event_complete_cond.
10
13
11
Fixes: 461c51ad4275 ("Add a phy-num property to the i.MX FEC emulator")
14
With this it also is again possible to use colo without
12
Cc: Jean-Christophe Dubois <jcd@tribudubois.net>
15
colo-compare (periodic mode) and to use multiple colo-compare
13
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
16
for multiple network interfaces.
14
Tested-by: Bin Meng <bmeng.cn@gmail.com>
17
15
Reviewed-by: Philippe Mathieu-Daud茅 <f4bug@amsat.org>
18
Signed-off-by: Lukas Straub <lukasstraub2@web.de>
16
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
19
Tested-by: Lukas Straub <lukasstraub2@web.de>
20
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
21
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
17
Signed-off-by: Jason Wang <jasowang@redhat.com>
22
Signed-off-by: Jason Wang <jasowang@redhat.com>
18
---
23
---
19
hw/net/imx_fec.c | 8 +++-----
24
net/colo-compare.c | 35 +++++++++++++++++++++++++++++------
20
hw/net/trace-events | 2 ++
25
1 file changed, 29 insertions(+), 6 deletions(-)
21
2 files changed, 5 insertions(+), 5 deletions(-)
22
26
23
diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c
27
diff --git a/net/colo-compare.c b/net/colo-compare.c
24
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
25
--- a/hw/net/imx_fec.c
29
--- a/net/colo-compare.c
26
+++ b/hw/net/imx_fec.c
30
+++ b/net/colo-compare.c
27
@@ -XXX,XX +XXX,XX @@ static uint32_t imx_phy_read(IMXFECState *s, int reg)
31
@@ -XXX,XX +XXX,XX @@ static NotifierList colo_compare_notifiers =
28
uint32_t phy = reg / 32;
32
#define REGULAR_PACKET_CHECK_MS 3000
29
33
#define DEFAULT_TIME_OUT_MS 3000
30
if (phy != s->phy_num) {
34
31
- qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad phy num %u\n",
35
+static QemuMutex colo_compare_mutex;
32
- TYPE_IMX_FEC, __func__, phy);
36
+static bool colo_compare_active;
33
- return 0;
37
static QemuMutex event_mtx;
34
+ trace_imx_phy_read_num(phy, s->phy_num);
38
static QemuCond event_complete_cond;
35
+ return 0xffff;
39
static int event_unhandled_count;
40
@@ -XXX,XX +XXX,XX @@ static void check_old_packet_regular(void *opaque)
41
void colo_notify_compares_event(void *opaque, int event, Error **errp)
42
{
43
CompareState *s;
44
+ qemu_mutex_lock(&colo_compare_mutex);
45
+
46
+ if (!colo_compare_active) {
47
+ qemu_mutex_unlock(&colo_compare_mutex);
48
+ return;
49
+ }
50
51
qemu_mutex_lock(&event_mtx);
52
QTAILQ_FOREACH(s, &net_compares, next) {
53
@@ -XXX,XX +XXX,XX @@ void colo_notify_compares_event(void *opaque, int event, Error **errp)
36
}
54
}
37
55
38
reg %= 32;
56
qemu_mutex_unlock(&event_mtx);
39
@@ -XXX,XX +XXX,XX @@ static void imx_phy_write(IMXFECState *s, int reg, uint32_t val)
57
+ qemu_mutex_unlock(&colo_compare_mutex);
40
uint32_t phy = reg / 32;
58
}
41
59
42
if (phy != s->phy_num) {
60
static void colo_compare_timer_init(CompareState *s)
43
- qemu_log_mask(LOG_GUEST_ERROR, "[%s.phy]%s: Bad phy num %u\n",
61
@@ -XXX,XX +XXX,XX @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
44
- TYPE_IMX_FEC, __func__, phy);
62
s->vnet_hdr);
45
+ trace_imx_phy_write_num(phy, s->phy_num);
46
return;
47
}
63
}
48
64
49
diff --git a/hw/net/trace-events b/hw/net/trace-events
65
+ qemu_mutex_lock(&colo_compare_mutex);
50
index XXXXXXX..XXXXXXX 100644
66
+ if (!colo_compare_active) {
51
--- a/hw/net/trace-events
67
+ qemu_mutex_init(&event_mtx);
52
+++ b/hw/net/trace-events
68
+ qemu_cond_init(&event_complete_cond);
53
@@ -XXX,XX +XXX,XX @@ i82596_channel_attention(void *s) "%p: Received CHANNEL ATTENTION"
69
+ colo_compare_active = true;
54
70
+ }
55
# imx_fec.c
71
QTAILQ_INSERT_TAIL(&net_compares, s, next);
56
imx_phy_read(uint32_t val, int phy, int reg) "0x%04"PRIx32" <= phy[%d].reg[%d]"
72
+ qemu_mutex_unlock(&colo_compare_mutex);
57
+imx_phy_read_num(int phy, int configured) "read request from unconfigured phy %d (configured %d)"
73
58
imx_phy_write(uint32_t val, int phy, int reg) "0x%04"PRIx32" => phy[%d].reg[%d]"
74
s->out_sendco.s = s;
59
+imx_phy_write_num(int phy, int configured) "write request to unconfigured phy %d (configured %d)"
75
s->out_sendco.chr = &s->chr_out;
60
imx_phy_update_link(const char *s) "%s"
76
@@ -XXX,XX +XXX,XX @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
61
imx_phy_reset(void) ""
77
62
imx_fec_read_bd(uint64_t addr, int flags, int len, int data) "tx_bd 0x%"PRIx64" flags 0x%04x len %d data 0x%08x"
78
g_queue_init(&s->conn_list);
79
80
- qemu_mutex_init(&event_mtx);
81
- qemu_cond_init(&event_complete_cond);
82
-
83
s->connection_track_table = g_hash_table_new_full(connection_key_hash,
84
connection_key_equal,
85
g_free,
86
@@ -XXX,XX +XXX,XX @@ static void colo_compare_finalize(Object *obj)
87
88
qemu_bh_delete(s->event_bh);
89
90
+ qemu_mutex_lock(&colo_compare_mutex);
91
QTAILQ_FOREACH(tmp, &net_compares, next) {
92
if (tmp == s) {
93
QTAILQ_REMOVE(&net_compares, s, next);
94
break;
95
}
96
}
97
+ if (QTAILQ_EMPTY(&net_compares)) {
98
+ colo_compare_active = false;
99
+ qemu_mutex_destroy(&event_mtx);
100
+ qemu_cond_destroy(&event_complete_cond);
101
+ }
102
+ qemu_mutex_unlock(&colo_compare_mutex);
103
104
AioContext *ctx = iothread_get_aio_context(s->iothread);
105
aio_context_acquire(ctx);
106
@@ -XXX,XX +XXX,XX @@ static void colo_compare_finalize(Object *obj)
107
object_unref(OBJECT(s->iothread));
108
}
109
110
- qemu_mutex_destroy(&event_mtx);
111
- qemu_cond_destroy(&event_complete_cond);
112
-
113
g_free(s->pri_indev);
114
g_free(s->sec_indev);
115
g_free(s->outdev);
116
g_free(s->notify_dev);
117
}
118
119
+static void __attribute__((__constructor__)) colo_compare_init_globals(void)
120
+{
121
+ colo_compare_active = false;
122
+ qemu_mutex_init(&colo_compare_mutex);
123
+}
124
+
125
static const TypeInfo colo_compare_info = {
126
.name = TYPE_COLO_COMPARE,
127
.parent = TYPE_OBJECT,
63
--
128
--
64
2.7.4
129
2.5.0
65
130
66
131
diff view generated by jsdifflib
New patch
1
From: Lukas Straub <lukasstraub2@web.de>
1
2
3
In colo_compare_complete, insert CompareState into net_compares
4
only after everything has been initialized.
5
In colo_compare_finalize, remove CompareState from net_compares
6
before anything is deinitialized.
7
8
Signed-off-by: Lukas Straub <lukasstraub2@web.de>
9
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
10
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
13
net/colo-compare.c | 45 +++++++++++++++++++++++----------------------
14
1 file changed, 23 insertions(+), 22 deletions(-)
15
16
diff --git a/net/colo-compare.c b/net/colo-compare.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/net/colo-compare.c
19
+++ b/net/colo-compare.c
20
@@ -XXX,XX +XXX,XX @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
21
s->vnet_hdr);
22
}
23
24
- qemu_mutex_lock(&colo_compare_mutex);
25
- if (!colo_compare_active) {
26
- qemu_mutex_init(&event_mtx);
27
- qemu_cond_init(&event_complete_cond);
28
- colo_compare_active = true;
29
- }
30
- QTAILQ_INSERT_TAIL(&net_compares, s, next);
31
- qemu_mutex_unlock(&colo_compare_mutex);
32
-
33
s->out_sendco.s = s;
34
s->out_sendco.chr = &s->chr_out;
35
s->out_sendco.notify_remote_frame = false;
36
@@ -XXX,XX +XXX,XX @@ static void colo_compare_complete(UserCreatable *uc, Error **errp)
37
connection_destroy);
38
39
colo_compare_iothread(s);
40
+
41
+ qemu_mutex_lock(&colo_compare_mutex);
42
+ if (!colo_compare_active) {
43
+ qemu_mutex_init(&event_mtx);
44
+ qemu_cond_init(&event_complete_cond);
45
+ colo_compare_active = true;
46
+ }
47
+ QTAILQ_INSERT_TAIL(&net_compares, s, next);
48
+ qemu_mutex_unlock(&colo_compare_mutex);
49
+
50
return;
51
}
52
53
@@ -XXX,XX +XXX,XX @@ static void colo_compare_finalize(Object *obj)
54
CompareState *s = COLO_COMPARE(obj);
55
CompareState *tmp = NULL;
56
57
- qemu_chr_fe_deinit(&s->chr_pri_in, false);
58
- qemu_chr_fe_deinit(&s->chr_sec_in, false);
59
- qemu_chr_fe_deinit(&s->chr_out, false);
60
- if (s->notify_dev) {
61
- qemu_chr_fe_deinit(&s->chr_notify_dev, false);
62
- }
63
-
64
- if (s->iothread) {
65
- colo_compare_timer_del(s);
66
- }
67
-
68
- qemu_bh_delete(s->event_bh);
69
-
70
qemu_mutex_lock(&colo_compare_mutex);
71
QTAILQ_FOREACH(tmp, &net_compares, next) {
72
if (tmp == s) {
73
@@ -XXX,XX +XXX,XX @@ static void colo_compare_finalize(Object *obj)
74
}
75
qemu_mutex_unlock(&colo_compare_mutex);
76
77
+ qemu_chr_fe_deinit(&s->chr_pri_in, false);
78
+ qemu_chr_fe_deinit(&s->chr_sec_in, false);
79
+ qemu_chr_fe_deinit(&s->chr_out, false);
80
+ if (s->notify_dev) {
81
+ qemu_chr_fe_deinit(&s->chr_notify_dev, false);
82
+ }
83
+
84
+ if (s->iothread) {
85
+ colo_compare_timer_del(s);
86
+ }
87
+
88
+ qemu_bh_delete(s->event_bh);
89
+
90
AioContext *ctx = iothread_get_aio_context(s->iothread);
91
aio_context_acquire(ctx);
92
AIO_WAIT_WHILE(ctx, !s->out_sendco.done);
93
--
94
2.5.0
95
96
diff view generated by jsdifflib
New patch
1
From: Derek Su <dereksu@qnap.com>
1
2
3
The patch is to fix the "pkt" memory leak in packet_enqueue().
4
The allocated "pkt" needs to be freed if the colo compare
5
primary or secondary queue is too big.
6
7
Replace the error_report of full queue with a trace event.
8
9
Signed-off-by: Derek Su <dereksu@qnap.com>
10
Reviewed-by: Zhang Chen <chen.zhang@intel.com>
11
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
12
Signed-off-by: Zhang Chen <chen.zhang@intel.com>
13
Signed-off-by: Jason Wang <jasowang@redhat.com>
14
---
15
net/colo-compare.c | 23 +++++++++++++++--------
16
net/trace-events | 1 +
17
2 files changed, 16 insertions(+), 8 deletions(-)
18
19
diff --git a/net/colo-compare.c b/net/colo-compare.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/net/colo-compare.c
22
+++ b/net/colo-compare.c
23
@@ -XXX,XX +XXX,XX @@ enum {
24
SECONDARY_IN,
25
};
26
27
+static const char *colo_mode[] = {
28
+ [PRIMARY_IN] = "primary",
29
+ [SECONDARY_IN] = "secondary",
30
+};
31
32
static int compare_chr_send(CompareState *s,
33
uint8_t *buf,
34
@@ -XXX,XX +XXX,XX @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
35
ConnectionKey key;
36
Packet *pkt = NULL;
37
Connection *conn;
38
+ int ret;
39
40
if (mode == PRIMARY_IN) {
41
pkt = packet_new(s->pri_rs.buf,
42
@@ -XXX,XX +XXX,XX @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
43
}
44
45
if (mode == PRIMARY_IN) {
46
- if (!colo_insert_packet(&conn->primary_list, pkt, &conn->pack)) {
47
- error_report("colo compare primary queue size too big,"
48
- "drop packet");
49
- }
50
+ ret = colo_insert_packet(&conn->primary_list, pkt, &conn->pack);
51
} else {
52
- if (!colo_insert_packet(&conn->secondary_list, pkt, &conn->sack)) {
53
- error_report("colo compare secondary queue size too big,"
54
- "drop packet");
55
- }
56
+ ret = colo_insert_packet(&conn->secondary_list, pkt, &conn->sack);
57
}
58
+
59
+ if (!ret) {
60
+ trace_colo_compare_drop_packet(colo_mode[mode],
61
+ "queue size too big, drop packet");
62
+ packet_destroy(pkt, NULL);
63
+ pkt = NULL;
64
+ }
65
+
66
*con = conn;
67
68
return 0;
69
diff --git a/net/trace-events b/net/trace-events
70
index XXXXXXX..XXXXXXX 100644
71
--- a/net/trace-events
72
+++ b/net/trace-events
73
@@ -XXX,XX +XXX,XX @@ colo_proxy_main(const char *chr) ": %s"
74
75
# colo-compare.c
76
colo_compare_main(const char *chr) ": %s"
77
+colo_compare_drop_packet(const char *queue, const char *chr) ": %s: %s"
78
colo_compare_udp_miscompare(const char *sta, int size) ": %s = %d"
79
colo_compare_icmp_miscompare(const char *sta, int size) ": %s = %d"
80
colo_compare_ip_info(int psize, const char *sta, const char *stb, int ssize, const char *stc, const char *std) "ppkt size = %d, ip_src = %s, ip_dst = %s, spkt size = %d, ip_src = %s, ip_dst = %s"
81
--
82
2.5.0
83
84
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
2
2
3
Additional code that will be used for eBPF setting steering routine.
3
libFuzzer found using 'qemu-system-i386 -M q35':
4
4
5
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
5
qemu: hardware error: e1000e: PSRCTL.BSIZE0 cannot be zero
6
CPU #0:
7
EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000663
8
ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000
9
EIP=0000fff0 EFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
10
ES =0000 00000000 0000ffff 00009300
11
CS =f000 ffff0000 0000ffff 00009b00
12
SS =0000 00000000 0000ffff 00009300
13
DS =0000 00000000 0000ffff 00009300
14
FS =0000 00000000 0000ffff 00009300
15
GS =0000 00000000 0000ffff 00009300
16
LDT=0000 00000000 0000ffff 00008200
17
TR =0000 00000000 0000ffff 00008b00
18
GDT= 00000000 0000ffff
19
IDT= 00000000 0000ffff
20
CR0=60000010 CR2=00000000 CR3=00000000 CR4=00000000
21
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000
22
DR6=ffff0ff0 DR7=00000400
23
EFER=0000000000000000
24
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
25
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
26
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
27
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
28
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
29
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
30
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
31
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
32
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000
33
==1988== ERROR: libFuzzer: deadly signal
34
#6 0x7fae4d3ea894 in __GI_abort (/lib64/libc.so.6+0x22894)
35
#7 0x563f4cc59a1d in hw_error (qemu-fuzz-i386+0xe8ca1d)
36
#8 0x563f4d7c93f2 in e1000e_set_psrctl (qemu-fuzz-i386+0x19fc3f2)
37
#9 0x563f4d7b798f in e1000e_core_write (qemu-fuzz-i386+0x19ea98f)
38
#10 0x563f4d7afc46 in e1000e_mmio_write (qemu-fuzz-i386+0x19e2c46)
39
#11 0x563f4cc9a0a7 in memory_region_write_accessor (qemu-fuzz-i386+0xecd0a7)
40
#12 0x563f4cc99c13 in access_with_adjusted_size (qemu-fuzz-i386+0xeccc13)
41
#13 0x563f4cc987b4 in memory_region_dispatch_write (qemu-fuzz-i386+0xecb7b4)
42
43
It simply sent the following 2 I/O command to the e1000e
44
PCI BAR #2 I/O region:
45
46
writew 0x0100 0x0c00 # RCTL = E1000_RCTL_DTYP_MASK
47
writeb 0x2170 0x00 # PSRCTL = 0
48
49
2813 static void
50
2814 e1000e_set_psrctl(E1000ECore *core, int index, uint32_t val)
51
2815 {
52
2816 if (core->mac[RCTL] & E1000_RCTL_DTYP_MASK) {
53
2817
54
2818 if ((val & E1000_PSRCTL_BSIZE0_MASK) == 0) {
55
2819 hw_error("e1000e: PSRCTL.BSIZE0 cannot be zero");
56
2820 }
57
58
Instead of calling hw_error() which abort the process (it is
59
meant for CPU fatal error condition, not for device logging),
60
log the invalid request with qemu_log_mask(LOG_GUEST_ERROR)
61
and return, ignoring the request.
62
63
Cc: qemu-stable@nongnu.org
64
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
6
Signed-off-by: Jason Wang <jasowang@redhat.com>
65
Signed-off-by: Jason Wang <jasowang@redhat.com>
7
---
66
---
8
net/tap-linux.h | 1 +
67
hw/net/e1000e_core.c | 10 +++++++---
9
1 file changed, 1 insertion(+)
68
1 file changed, 7 insertions(+), 3 deletions(-)
10
69
11
diff --git a/net/tap-linux.h b/net/tap-linux.h
70
diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
12
index XXXXXXX..XXXXXXX 100644
71
index XXXXXXX..XXXXXXX 100644
13
--- a/net/tap-linux.h
72
--- a/hw/net/e1000e_core.c
14
+++ b/net/tap-linux.h
73
+++ b/hw/net/e1000e_core.c
15
@@ -XXX,XX +XXX,XX @@
74
@@ -XXX,XX +XXX,XX @@
16
#define TUNSETQUEUE _IOW('T', 217, int)
75
*/
17
#define TUNSETVNETLE _IOW('T', 220, int)
76
18
#define TUNSETVNETBE _IOW('T', 222, int)
77
#include "qemu/osdep.h"
19
+#define TUNSETSTEERINGEBPF _IOR('T', 224, int)
78
+#include "qemu/log.h"
20
79
#include "net/net.h"
21
#endif
80
#include "net/tap.h"
81
-#include "hw/hw.h"
82
#include "hw/pci/msi.h"
83
#include "hw/pci/msix.h"
84
#include "sysemu/runstate.h"
85
@@ -XXX,XX +XXX,XX @@ e1000e_set_psrctl(E1000ECore *core, int index, uint32_t val)
86
if (core->mac[RCTL] & E1000_RCTL_DTYP_MASK) {
87
88
if ((val & E1000_PSRCTL_BSIZE0_MASK) == 0) {
89
- hw_error("e1000e: PSRCTL.BSIZE0 cannot be zero");
90
+ qemu_log_mask(LOG_GUEST_ERROR,
91
+ "e1000e: PSRCTL.BSIZE0 cannot be zero");
92
+ return;
93
}
94
95
if ((val & E1000_PSRCTL_BSIZE1_MASK) == 0) {
96
- hw_error("e1000e: PSRCTL.BSIZE1 cannot be zero");
97
+ qemu_log_mask(LOG_GUEST_ERROR,
98
+ "e1000e: PSRCTL.BSIZE1 cannot be zero");
99
+ return;
100
}
101
}
22
102
23
--
103
--
24
2.7.4
104
2.5.0
25
105
26
106
diff view generated by jsdifflib
1
From: Andrew Melnychenko <andrew@daynix.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
3
It's been deprecated since QEMU v3.1, so it's time to finally
4
Signed-off-by: Andrew Melnychenko <andrew@daynix.com>
4
remove it. The "id" parameter can simply be used instead.
5
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Thomas Huth <thuth@redhat.com>
5
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
6
---
9
---
7
docs/devel/ebpf_rss.rst | 125 ++++++++++++++++++++++++++++++++++++++++++++++++
10
docs/system/deprecated.rst | 15 +++++++++------
8
docs/devel/index.rst | 1 +
11
net/net.c | 10 +---------
9
2 files changed, 126 insertions(+)
12
qapi/net.json | 3 ---
10
create mode 100644 docs/devel/ebpf_rss.rst
13
3 files changed, 10 insertions(+), 18 deletions(-)
11
14
12
diff --git a/docs/devel/ebpf_rss.rst b/docs/devel/ebpf_rss.rst
15
diff --git a/docs/system/deprecated.rst b/docs/system/deprecated.rst
13
new file mode 100644
16
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX
17
--- a/docs/system/deprecated.rst
15
--- /dev/null
18
+++ b/docs/system/deprecated.rst
16
+++ b/docs/devel/ebpf_rss.rst
19
@@ -XXX,XX +XXX,XX @@ The 'file' driver for drives is no longer appropriate for character or host
20
devices and will only accept regular files (S_IFREG). The correct driver
21
for these file types is 'host_cdrom' or 'host_device' as appropriate.
22
23
-``-net ...,name=``\ *name* (since 3.1)
24
-''''''''''''''''''''''''''''''''''''''
25
-
26
-The ``name`` parameter of the ``-net`` option is a synonym
27
-for the ``id`` parameter, which should now be used instead.
28
-
29
``-smp`` (invalid topologies) (since 3.1)
30
'''''''''''''''''''''''''''''''''''''''''
31
32
@@ -XXX,XX +XXX,XX @@ What follows is a record of recently removed, formerly deprecated
33
features that serves as a record for users who have encountered
34
trouble after a recent upgrade.
35
36
+System emulator command line arguments
37
+--------------------------------------
38
+
39
+``-net ...,name=``\ *name* (removed in 5.1)
40
+'''''''''''''''''''''''''''''''''''''''''''
41
+
42
+The ``name`` parameter of the ``-net`` option was a synonym
43
+for the ``id`` parameter, which should now be used instead.
44
+
45
QEMU Machine Protocol (QMP) commands
46
------------------------------------
47
48
diff --git a/net/net.c b/net/net.c
49
index XXXXXXX..XXXXXXX 100644
50
--- a/net/net.c
51
+++ b/net/net.c
52
@@ -XXX,XX +XXX,XX @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
53
{
54
Netdev legacy = {0};
55
const Netdev *netdev;
56
- const char *name;
57
NetClientState *peer = NULL;
58
59
if (is_netdev) {
60
netdev = object;
61
- name = netdev->id;
62
63
if (netdev->type == NET_CLIENT_DRIVER_NIC ||
64
!net_client_init_fun[netdev->type]) {
65
@@ -XXX,XX +XXX,XX @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
66
const NetLegacyOptions *opts = net->opts;
67
legacy.id = net->id;
68
netdev = &legacy;
69
- /* missing optional values have been initialized to "all bits zero" */
70
- name = net->has_id ? net->id : net->name;
71
-
72
- if (net->has_name) {
73
- warn_report("The 'name' parameter is deprecated, use 'id' instead");
74
- }
75
76
/* Map the old options to the new flat type */
77
switch (opts->type) {
78
@@ -XXX,XX +XXX,XX @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
79
}
80
}
81
82
- if (net_client_init_fun[netdev->type](netdev, name, peer, errp) < 0) {
83
+ if (net_client_init_fun[netdev->type](netdev, netdev->id, peer, errp) < 0) {
84
/* FIXME drop when all init functions store an Error */
85
if (errp && !*errp) {
86
error_setg(errp, QERR_DEVICE_INIT_FAILED,
87
diff --git a/qapi/net.json b/qapi/net.json
88
index XXXXXXX..XXXXXXX 100644
89
--- a/qapi/net.json
90
+++ b/qapi/net.json
17
@@ -XXX,XX +XXX,XX @@
91
@@ -XXX,XX +XXX,XX @@
18
+===========================
92
#
19
+eBPF RSS virtio-net support
93
# @id: identifier for monitor commands
20
+===========================
94
#
21
+
95
-# @name: identifier for monitor commands, ignored if @id is present
22
+RSS(Receive Side Scaling) is used to distribute network packets to guest virtqueues
96
-#
23
+by calculating packet hash. Usually every queue is processed then by a specific guest CPU core.
97
# @opts: device type specific properties (legacy)
24
+
98
#
25
+For now there are 2 RSS implementations in qemu:
99
# Since: 1.2
26
+- 'in-qemu' RSS (functions if qemu receives network packets, i.e. vhost=off)
100
@@ -XXX,XX +XXX,XX @@
27
+- eBPF RSS (can function with also with vhost=on)
101
{ 'struct': 'NetLegacy',
28
+
102
'data': {
29
+eBPF support (CONFIG_EBPF) is enabled by 'configure' script.
103
'*id': 'str',
30
+To enable eBPF RSS support use './configure --enable-bpf'.
104
- '*name': 'str',
31
+
105
'opts': 'NetLegacyOptions' } }
32
+If steering BPF is not set for kernel's TUN module, the TUN uses automatic selection
106
33
+of rx virtqueue based on lookup table built according to calculated symmetric hash
107
##
34
+of transmitted packets.
35
+If steering BPF is set for TUN the BPF code calculates the hash of packet header and
36
+returns the virtqueue number to place the packet to.
37
+
38
+Simplified decision formula:
39
+
40
+.. code:: C
41
+
42
+ queue_index = indirection_table[hash(<packet data>)%<indirection_table size>]
43
+
44
+
45
+Not for all packets, the hash can/should be calculated.
46
+
47
+Note: currently, eBPF RSS does not support hash reporting.
48
+
49
+eBPF RSS turned on by different combinations of vhost-net, vitrio-net and tap configurations:
50
+
51
+- eBPF is used:
52
+
53
+ tap,vhost=off & virtio-net-pci,rss=on,hash=off
54
+
55
+- eBPF is used:
56
+
57
+ tap,vhost=on & virtio-net-pci,rss=on,hash=off
58
+
59
+- 'in-qemu' RSS is used:
60
+
61
+ tap,vhost=off & virtio-net-pci,rss=on,hash=on
62
+
63
+- eBPF is used, hash population feature is not reported to the guest:
64
+
65
+ tap,vhost=on & virtio-net-pci,rss=on,hash=on
66
+
67
+If CONFIG_EBPF is not set then only 'in-qemu' RSS is supported.
68
+Also 'in-qemu' RSS, as a fallback, is used if the eBPF program failed to load or set to TUN.
69
+
70
+RSS eBPF program
71
+----------------
72
+
73
+RSS program located in ebpf/rss.bpf.skeleton.h generated by bpftool.
74
+So the program is part of the qemu binary.
75
+Initially, the eBPF program was compiled by clang and source code located at tools/ebpf/rss.bpf.c.
76
+Prerequisites to recompile the eBPF program (regenerate ebpf/rss.bpf.skeleton.h):
77
+
78
+ llvm, clang, kernel source tree, bpftool
79
+ Adjust Makefile.ebpf to reflect the location of the kernel source tree
80
+
81
+ $ cd tools/ebpf
82
+ $ make -f Makefile.ebpf
83
+
84
+Current eBPF RSS implementation uses 'bounded loops' with 'backward jump instructions' which present in the last kernels.
85
+Overall eBPF RSS works on kernels 5.8+.
86
+
87
+eBPF RSS implementation
88
+-----------------------
89
+
90
+eBPF RSS loading functionality located in ebpf/ebpf_rss.c and ebpf/ebpf_rss.h.
91
+
92
+The `struct EBPFRSSContext` structure that holds 4 file descriptors:
93
+
94
+- ctx - pointer of the libbpf context.
95
+- program_fd - file descriptor of the eBPF RSS program.
96
+- map_configuration - file descriptor of the 'configuration' map. This map contains one element of 'struct EBPFRSSConfig'. This configuration determines eBPF program behavior.
97
+- map_toeplitz_key - file descriptor of the 'Toeplitz key' map. One element of the 40byte key prepared for the hashing algorithm.
98
+- map_indirections_table - 128 elements of queue indexes.
99
+
100
+`struct EBPFRSSConfig` fields:
101
+
102
+- redirect - "boolean" value, should the hash be calculated, on false - `default_queue` would be used as the final decision.
103
+- populate_hash - for now, not used. eBPF RSS doesn't support hash reporting.
104
+- hash_types - binary mask of different hash types. See `VIRTIO_NET_RSS_HASH_TYPE_*` defines. If for packet hash should not be calculated - `default_queue` would be used.
105
+- indirections_len - length of the indirections table, maximum 128.
106
+- default_queue - the queue index that used for packet that shouldn't be hashed. For some packets, the hash can't be calculated(g.e ARP).
107
+
108
+Functions:
109
+
110
+- `ebpf_rss_init()` - sets ctx to NULL, which indicates that EBPFRSSContext is not loaded.
111
+- `ebpf_rss_load()` - creates 3 maps and loads eBPF program from the rss.bpf.skeleton.h. Returns 'true' on success. After that, program_fd can be used to set steering for TAP.
112
+- `ebpf_rss_set_all()` - sets values for eBPF maps. `indirections_table` length is in EBPFRSSConfig. `toeplitz_key` is VIRTIO_NET_RSS_MAX_KEY_SIZE aka 40 bytes array.
113
+- `ebpf_rss_unload()` - close all file descriptors and set ctx to NULL.
114
+
115
+Simplified eBPF RSS workflow:
116
+
117
+.. code:: C
118
+
119
+ struct EBPFRSSConfig config;
120
+ config.redirect = 1;
121
+ config.hash_types = VIRTIO_NET_RSS_HASH_TYPE_UDPv4 | VIRTIO_NET_RSS_HASH_TYPE_TCPv4;
122
+ config.indirections_len = VIRTIO_NET_RSS_MAX_TABLE_LEN;
123
+ config.default_queue = 0;
124
+
125
+ uint16_t table[VIRTIO_NET_RSS_MAX_TABLE_LEN] = {...};
126
+ uint8_t key[VIRTIO_NET_RSS_MAX_KEY_SIZE] = {...};
127
+
128
+ struct EBPFRSSContext ctx;
129
+ ebpf_rss_init(&ctx);
130
+ ebpf_rss_load(&ctx);
131
+ ebpf_rss_set_all(&ctx, &config, table, key);
132
+ if (net_client->info->set_steering_ebpf != NULL) {
133
+ net_client->info->set_steering_ebpf(net_client, ctx->program_fd);
134
+ }
135
+ ...
136
+ ebpf_unload(&ctx);
137
+
138
+
139
+NetClientState SetSteeringEBPF()
140
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
141
+
142
+For now, `set_steering_ebpf()` method supported by Linux TAP NetClientState. The method requires an eBPF program file descriptor as an argument.
143
diff --git a/docs/devel/index.rst b/docs/devel/index.rst
144
index XXXXXXX..XXXXXXX 100644
145
--- a/docs/devel/index.rst
146
+++ b/docs/devel/index.rst
147
@@ -XXX,XX +XXX,XX @@ Contents:
148
qom
149
block-coroutine-wrapper
150
multi-process
151
+ ebpf_rss
152
--
108
--
153
2.7.4
109
2.5.0
154
110
155
111
diff view generated by jsdifflib
New patch
1
1
From: Thomas Huth <thuth@redhat.com>
2
3
Now that the "name" parameter is gone, there is hardly any difference
4
between NetLegacy and Netdev anymore, so we can drop NetLegacy and always
5
use Netdev to simplify the code quite a bit.
6
7
The only two differences that were really left between Netdev and NetLegacy:
8
9
1) NetLegacy does not allow a "hubport" type. We can continue to block
10
this with a simple check in net_client_init1() for this type.
11
12
2) The "id" parameter was optional in NetLegacy (and an internal id
13
was chosen via assign_name() during initialization), but it is mandatory
14
for Netdev. To avoid that the visitor code bails out here, we have to
15
add an internal id to the QemuOpts already earlier now.
16
17
Signed-off-by: Thomas Huth <thuth@redhat.com>
18
Reviewed-by: Eric Blake <eblake@redhat.com>
19
Signed-off-by: Jason Wang <jasowang@redhat.com>
20
---
21
net/net.c | 77 ++++++++++-------------------------------------------------
22
qapi/net.json | 46 -----------------------------------
23
2 files changed, 13 insertions(+), 110 deletions(-)
24
25
diff --git a/net/net.c b/net/net.c
26
index XXXXXXX..XXXXXXX 100644
27
--- a/net/net.c
28
+++ b/net/net.c
29
@@ -XXX,XX +XXX,XX @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
30
};
31
32
33
-static int net_client_init1(const void *object, bool is_netdev, Error **errp)
34
+static int net_client_init1(const Netdev *netdev, bool is_netdev, Error **errp)
35
{
36
- Netdev legacy = {0};
37
- const Netdev *netdev;
38
NetClientState *peer = NULL;
39
40
if (is_netdev) {
41
- netdev = object;
42
-
43
if (netdev->type == NET_CLIENT_DRIVER_NIC ||
44
!net_client_init_fun[netdev->type]) {
45
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
46
@@ -XXX,XX +XXX,XX @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
47
return -1;
48
}
49
} else {
50
- const NetLegacy *net = object;
51
- const NetLegacyOptions *opts = net->opts;
52
- legacy.id = net->id;
53
- netdev = &legacy;
54
-
55
- /* Map the old options to the new flat type */
56
- switch (opts->type) {
57
- case NET_LEGACY_OPTIONS_TYPE_NONE:
58
+ if (netdev->type == NET_CLIENT_DRIVER_NONE) {
59
return 0; /* nothing to do */
60
- case NET_LEGACY_OPTIONS_TYPE_NIC:
61
- legacy.type = NET_CLIENT_DRIVER_NIC;
62
- legacy.u.nic = opts->u.nic;
63
- break;
64
- case NET_LEGACY_OPTIONS_TYPE_USER:
65
- legacy.type = NET_CLIENT_DRIVER_USER;
66
- legacy.u.user = opts->u.user;
67
- break;
68
- case NET_LEGACY_OPTIONS_TYPE_TAP:
69
- legacy.type = NET_CLIENT_DRIVER_TAP;
70
- legacy.u.tap = opts->u.tap;
71
- break;
72
- case NET_LEGACY_OPTIONS_TYPE_L2TPV3:
73
- legacy.type = NET_CLIENT_DRIVER_L2TPV3;
74
- legacy.u.l2tpv3 = opts->u.l2tpv3;
75
- break;
76
- case NET_LEGACY_OPTIONS_TYPE_SOCKET:
77
- legacy.type = NET_CLIENT_DRIVER_SOCKET;
78
- legacy.u.socket = opts->u.socket;
79
- break;
80
- case NET_LEGACY_OPTIONS_TYPE_VDE:
81
- legacy.type = NET_CLIENT_DRIVER_VDE;
82
- legacy.u.vde = opts->u.vde;
83
- break;
84
- case NET_LEGACY_OPTIONS_TYPE_BRIDGE:
85
- legacy.type = NET_CLIENT_DRIVER_BRIDGE;
86
- legacy.u.bridge = opts->u.bridge;
87
- break;
88
- case NET_LEGACY_OPTIONS_TYPE_NETMAP:
89
- legacy.type = NET_CLIENT_DRIVER_NETMAP;
90
- legacy.u.netmap = opts->u.netmap;
91
- break;
92
- case NET_LEGACY_OPTIONS_TYPE_VHOST_USER:
93
- legacy.type = NET_CLIENT_DRIVER_VHOST_USER;
94
- legacy.u.vhost_user = opts->u.vhost_user;
95
- break;
96
- default:
97
- abort();
98
}
99
-
100
- if (!net_client_init_fun[netdev->type]) {
101
+ if (netdev->type == NET_CLIENT_DRIVER_HUBPORT ||
102
+ !net_client_init_fun[netdev->type]) {
103
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
104
"a net backend type (maybe it is not compiled "
105
"into this binary)");
106
@@ -XXX,XX +XXX,XX @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
107
108
/* Do not add to a hub if it's a nic with a netdev= parameter. */
109
if (netdev->type != NET_CLIENT_DRIVER_NIC ||
110
- !opts->u.nic.has_netdev) {
111
+ !netdev->u.nic.has_netdev) {
112
peer = net_hub_add_port(0, NULL, NULL);
113
}
114
}
115
@@ -XXX,XX +XXX,XX @@ static void show_netdevs(void)
116
static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp)
117
{
118
gchar **substrings = NULL;
119
- void *object = NULL;
120
+ Netdev *object = NULL;
121
Error *err = NULL;
122
int ret = -1;
123
Visitor *v = opts_visitor_new(opts);
124
@@ -XXX,XX +XXX,XX @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp)
125
}
126
}
127
128
- if (is_netdev) {
129
- visit_type_Netdev(v, NULL, (Netdev **)&object, &err);
130
- } else {
131
- visit_type_NetLegacy(v, NULL, (NetLegacy **)&object, &err);
132
+ /* Create an ID for -net if the user did not specify one */
133
+ if (!is_netdev && !qemu_opts_id(opts)) {
134
+ static int idx;
135
+ qemu_opts_set_id(opts, g_strdup_printf("__org.qemu.net%i", idx++));
136
}
137
138
+ visit_type_Netdev(v, NULL, &object, &err);
139
+
140
if (!err) {
141
ret = net_client_init1(object, is_netdev, &err);
142
}
143
144
- if (is_netdev) {
145
- qapi_free_Netdev(object);
146
- } else {
147
- qapi_free_NetLegacy(object);
148
- }
149
+ qapi_free_Netdev(object);
150
151
out:
152
error_propagate(errp, err);
153
diff --git a/qapi/net.json b/qapi/net.json
154
index XXXXXXX..XXXXXXX 100644
155
--- a/qapi/net.json
156
+++ b/qapi/net.json
157
@@ -XXX,XX +XXX,XX @@
158
'vhost-user': 'NetdevVhostUserOptions' } }
159
160
##
161
-# @NetLegacy:
162
-#
163
-# Captures the configuration of a network device; legacy.
164
-#
165
-# @id: identifier for monitor commands
166
-#
167
-# @opts: device type specific properties (legacy)
168
-#
169
-# Since: 1.2
170
-##
171
-{ 'struct': 'NetLegacy',
172
- 'data': {
173
- '*id': 'str',
174
- 'opts': 'NetLegacyOptions' } }
175
-
176
-##
177
-# @NetLegacyOptionsType:
178
-#
179
-# Since: 1.2
180
-##
181
-{ 'enum': 'NetLegacyOptionsType',
182
- 'data': ['none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'vde',
183
- 'bridge', 'netmap', 'vhost-user'] }
184
-
185
-##
186
-# @NetLegacyOptions:
187
-#
188
-# Like Netdev, but for use only by the legacy command line options
189
-#
190
-# Since: 1.2
191
-##
192
-{ 'union': 'NetLegacyOptions',
193
- 'base': { 'type': 'NetLegacyOptionsType' },
194
- 'discriminator': 'type',
195
- 'data': {
196
- 'nic': 'NetLegacyNicOptions',
197
- 'user': 'NetdevUserOptions',
198
- 'tap': 'NetdevTapOptions',
199
- 'l2tpv3': 'NetdevL2TPv3Options',
200
- 'socket': 'NetdevSocketOptions',
201
- 'vde': 'NetdevVdeOptions',
202
- 'bridge': 'NetdevBridgeOptions',
203
- 'netmap': 'NetdevNetmapOptions',
204
- 'vhost-user': 'NetdevVhostUserOptions' } }
205
-
206
-##
207
# @NetFilterDirection:
208
#
209
# Indicates whether a netfilter is attached to a netdev's transmit queue or
210
--
211
2.5.0
212
213
diff view generated by jsdifflib