1
The following changes since commit e607bbee553cfe73072870cef458cfa4e78133e2:
1
The following changes since commit 187f35512106501fe9a11057f4d8705431e0026d:
2
2
3
Merge remote-tracking branch 'remotes/edgar/tags/edgar/xilinx-next-2018-01-26.for-upstream' into staging (2018-01-26 14:24:25 +0000)
3
Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-next-251019-3' into staging (2019-10-26 10:13:48 +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 bf4835a4d5338bb7424827715df22570a8adc67c:
9
for you to fetch changes up to 1e907a32b77e5d418538453df5945242e43224fa:
10
10
11
MAINTAINERS: update Dmitry Fleytman email (2018-01-29 16:05:38 +0800)
11
COLO-compare: Fix incorrect `if` logic (2019-10-29 10:28:07 +0800)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
14
15
Changes from V1:
16
17
- Fix compling issue
18
15
----------------------------------------------------------------
19
----------------------------------------------------------------
16
Mao Zhongyi (2):
20
Fan Yang (1):
17
colo: modified the payload compare function
21
COLO-compare: Fix incorrect `if` logic
18
colo: compare the packet based on the tcp sequence number
19
22
20
Philippe Mathieu-Daudé (1):
23
Michael S. Tsirkin (1):
21
MAINTAINERS: update Dmitry Fleytman email
24
virtio: new post_load hook
22
25
23
Thomas Huth (3):
26
Mikhail Sennikovsky (1):
24
net: Allow hubports to connect to other netdevs
27
virtio-net: prevent offloads reset on migration
25
net: Allow netdevs to be used with 'hostfwd_add' and 'hostfwd_remove'
26
qemu-doc: Get rid of "vlan=X" example in the documentation
27
28
28
MAINTAINERS | 8 +-
29
Sven Schnelle (1):
29
hmp-commands.hx | 4 +-
30
net: add tulip (dec21143) driver
30
net/colo-compare.c | 411 +++++++++++++++++++++++++++++++++--------------------
31
31
net/colo.c | 9 ++
32
MAINTAINERS | 6 +
32
net/colo.h | 15 ++
33
hw/net/Kconfig | 5 +
33
net/hub.c | 27 +++-
34
hw/net/Makefile.objs | 1 +
34
net/hub.h | 3 +-
35
hw/net/trace-events | 14 +
35
net/net.c | 2 +-
36
hw/net/tulip.c | 1029 ++++++++++++++++++++++++++++++++++++++++
36
net/slirp.c | 33 +++--
37
hw/net/tulip.h | 267 +++++++++++
37
net/trace-events | 2 +-
38
hw/net/virtio-net.c | 27 +-
38
qapi/net.json | 4 +-
39
hw/virtio/virtio.c | 7 +
39
qemu-options.hx | 12 +-
40
include/hw/pci/pci_ids.h | 1 +
40
12 files changed, 347 insertions(+), 183 deletions(-)
41
include/hw/virtio/virtio-net.h | 2 +
42
include/hw/virtio/virtio.h | 6 +
43
net/colo-compare.c | 6 +-
44
12 files changed, 1365 insertions(+), 6 deletions(-)
45
create mode 100644 hw/net/tulip.c
46
create mode 100644 hw/net/tulip.h
41
47
42
48
49
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
From: Sven Schnelle <svens@stackframe.org>
2
2
3
gently asked by his automatic reply :)
3
This adds the basic functionality to emulate a Tulip NIC.
4
4
5
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
5
Implemented are:
6
7
- RX and TX functionality
8
- Perfect Frame Filtering
9
- Big/Little Endian descriptor support
10
- 93C46 EEPROM support
11
- LXT970 PHY
12
13
Not implemented, mostly because i had no OS using these functions:
14
15
- Imperfect frame filtering
16
- General Purpose Timer
17
- Transmit automatic polling
18
- Boot ROM support
19
- SIA interface
20
- Big/Little Endian data buffer conversion
21
22
Successfully tested with the following Operating Systems:
23
24
- MSDOS with Microsoft Network Client 3.0 and DEC ODI drivers
25
- HPPA Linux
26
- Windows XP
27
- HP-UX
28
29
Signed-off-by: Sven Schnelle <svens@stackframe.org>
30
Message-Id: <20191022155413.4619-1-svens@stackframe.org>
31
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
6
Signed-off-by: Jason Wang <jasowang@redhat.com>
32
Signed-off-by: Jason Wang <jasowang@redhat.com>
7
---
33
---
8
MAINTAINERS | 8 ++++----
34
MAINTAINERS | 6 +
9
1 file changed, 4 insertions(+), 4 deletions(-)
35
hw/net/Kconfig | 5 +
36
hw/net/Makefile.objs | 1 +
37
hw/net/trace-events | 14 +
38
hw/net/tulip.c | 1029 ++++++++++++++++++++++++++++++++++++++++++++++
39
hw/net/tulip.h | 267 ++++++++++++
40
include/hw/pci/pci_ids.h | 1 +
41
7 files changed, 1323 insertions(+)
42
create mode 100644 hw/net/tulip.c
43
create mode 100644 hw/net/tulip.h
10
44
11
diff --git a/MAINTAINERS b/MAINTAINERS
45
diff --git a/MAINTAINERS b/MAINTAINERS
12
index XXXXXXX..XXXXXXX 100644
46
index XXXXXXX..XXXXXXX 100644
13
--- a/MAINTAINERS
47
--- a/MAINTAINERS
14
+++ b/MAINTAINERS
48
+++ b/MAINTAINERS
15
@@ -XXX,XX +XXX,XX @@ F: hw/scsi/mfi.h
49
@@ -XXX,XX +XXX,XX @@ M: Stefan Weil <sw@weilnetz.de>
16
F: tests/megasas-test.c
17
18
Network packet abstractions
19
-M: Dmitry Fleytman <dmitry@daynix.com>
20
+M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
21
S: Maintained
50
S: Maintained
22
F: include/net/eth.h
51
F: hw/net/eepro100.c
23
F: net/eth.c
52
24
@@ -XXX,XX +XXX,XX @@ F: hw/net/net_rx_pkt*
53
+tulip
25
F: hw/net/net_tx_pkt*
54
+M: Sven Schnelle <svens@stackframe.org>
26
55
+S: Maintained
27
Vmware
56
+F: hw/net/tulip.c
28
-M: Dmitry Fleytman <dmitry@daynix.com>
57
+F: hw/net/tulip.h
29
+M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
58
+
59
Generic Loader
60
M: Alistair Francis <alistair@alistair23.me>
30
S: Maintained
61
S: Maintained
31
F: hw/net/vmxnet*
62
diff --git a/hw/net/Kconfig b/hw/net/Kconfig
32
F: hw/scsi/vmw_pvscsi*
63
index XXXXXXX..XXXXXXX 100644
33
@@ -XXX,XX +XXX,XX @@ F: hw/mem/nvdimm.c
64
--- a/hw/net/Kconfig
34
F: include/hw/mem/nvdimm.h
65
+++ b/hw/net/Kconfig
35
66
@@ -XXX,XX +XXX,XX @@ config PCNET_PCI
36
e1000x
67
config PCNET_COMMON
37
-M: Dmitry Fleytman <dmitry@daynix.com>
68
bool
38
+M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
69
39
S: Maintained
70
+config TULIP
40
F: hw/net/e1000x*
71
+ bool
41
72
+ default y if PCI_DEVICES
42
e1000e
73
+ depends on PCI
43
-M: Dmitry Fleytman <dmitry@daynix.com>
74
+
44
+M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
75
config E1000_PCI
45
S: Maintained
76
bool
46
F: hw/net/e1000e*
77
default y if PCI_DEVICES
47
78
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
79
index XXXXXXX..XXXXXXX 100644
80
--- a/hw/net/Makefile.objs
81
+++ b/hw/net/Makefile.objs
82
@@ -XXX,XX +XXX,XX @@ common-obj-$(CONFIG_E1000E_PCI_EXPRESS) += e1000e.o e1000e_core.o e1000x_common.
83
common-obj-$(CONFIG_RTL8139_PCI) += rtl8139.o
84
common-obj-$(CONFIG_VMXNET3_PCI) += net_tx_pkt.o net_rx_pkt.o
85
common-obj-$(CONFIG_VMXNET3_PCI) += vmxnet3.o
86
+common-obj-$(CONFIG_TULIP) += tulip.o
87
88
common-obj-$(CONFIG_SMC91C111) += smc91c111.o
89
common-obj-$(CONFIG_LAN9118) += lan9118.o
90
diff --git a/hw/net/trace-events b/hw/net/trace-events
91
index XXXXXXX..XXXXXXX 100644
92
--- a/hw/net/trace-events
93
+++ b/hw/net/trace-events
94
@@ -XXX,XX +XXX,XX @@ virtio_net_announce_notify(void) ""
95
virtio_net_announce_timer(int round) "%d"
96
virtio_net_handle_announce(int round) "%d"
97
virtio_net_post_load_device(void)
98
+
99
+# tulip.c
100
+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
101
+tulip_reg_read(uint64_t addr, const char *name, int size, uint64_t val) "addr 0x%02"PRIx64" (%s) size %d value 0x%08"PRIx64
102
+tulip_receive(const uint8_t *buf, size_t len) "buf %p size %zu"
103
+tulip_descriptor(const char *prefix, uint32_t addr, uint32_t status, uint32_t control, uint32_t len1, uint32_t len2, uint32_t buf1, uint32_t buf2) "%s 0x%08x: status 0x%08x control 0x%03x len1 %4d len2 %4d buf1 0x%08x buf2 0x%08x"
104
+tulip_rx_state(const char *state) "RX %s"
105
+tulip_tx_state(const char *state) "TX %s"
106
+tulip_irq(uint32_t mask, uint32_t en, const char *state) "mask 0x%08x ie 0x%08x %s"
107
+tulip_mii_write(int phy, int reg, uint16_t data) "phy 0x%x reg 0x%x data 0x%04x"
108
+tulip_mii_read(int phy, int reg, uint16_t data) "phy 0x%x, reg 0x%x data 0x%04x"
109
+tulip_reset(void) ""
110
+tulip_setup_frame(void) ""
111
+tulip_setup_filter(int n, uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint8_t e, uint8_t f) "%d: %02x:%02x:%02x:%02x:%02x:%02x"
112
diff --git a/hw/net/tulip.c b/hw/net/tulip.c
113
new file mode 100644
114
index XXXXXXX..XXXXXXX
115
--- /dev/null
116
+++ b/hw/net/tulip.c
117
@@ -XXX,XX +XXX,XX @@
118
+/*
119
+ * QEMU TULIP Emulation
120
+ *
121
+ * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
122
+ *
123
+ * This work is licensed under the GNU GPL license version 2 or later.
124
+ */
125
+
126
+#include "qemu/osdep.h"
127
+#include "qemu/log.h"
128
+#include "hw/irq.h"
129
+#include "hw/pci/pci.h"
130
+#include "hw/qdev-properties.h"
131
+#include "hw/nvram/eeprom93xx.h"
132
+#include "migration/vmstate.h"
133
+#include "sysemu/sysemu.h"
134
+#include "tulip.h"
135
+#include "trace.h"
136
+#include "net/eth.h"
137
+
138
+typedef struct TULIPState {
139
+ PCIDevice dev;
140
+ MemoryRegion io;
141
+ MemoryRegion memory;
142
+ NICConf c;
143
+ qemu_irq irq;
144
+ NICState *nic;
145
+ eeprom_t *eeprom;
146
+ uint32_t csr[16];
147
+
148
+ /* state for MII */
149
+ uint32_t old_csr9;
150
+ uint32_t mii_word;
151
+ uint32_t mii_bitcnt;
152
+
153
+ hwaddr current_rx_desc;
154
+ hwaddr current_tx_desc;
155
+
156
+ uint8_t rx_frame[2048];
157
+ uint8_t tx_frame[2048];
158
+ uint16_t tx_frame_len;
159
+ uint16_t rx_frame_len;
160
+ uint16_t rx_frame_size;
161
+
162
+ uint32_t rx_status;
163
+ uint8_t filter[16][6];
164
+} TULIPState;
165
+
166
+static const VMStateDescription vmstate_pci_tulip = {
167
+ .name = "tulip",
168
+ .fields = (VMStateField[]) {
169
+ VMSTATE_PCI_DEVICE(dev, TULIPState),
170
+ VMSTATE_UINT32_ARRAY(csr, TULIPState, 16),
171
+ VMSTATE_UINT32(old_csr9, TULIPState),
172
+ VMSTATE_UINT32(mii_word, TULIPState),
173
+ VMSTATE_UINT32(mii_bitcnt, TULIPState),
174
+ VMSTATE_UINT64(current_rx_desc, TULIPState),
175
+ VMSTATE_UINT64(current_tx_desc, TULIPState),
176
+ VMSTATE_BUFFER(rx_frame, TULIPState),
177
+ VMSTATE_BUFFER(tx_frame, TULIPState),
178
+ VMSTATE_UINT16(rx_frame_len, TULIPState),
179
+ VMSTATE_UINT16(tx_frame_len, TULIPState),
180
+ VMSTATE_UINT16(rx_frame_size, TULIPState),
181
+ VMSTATE_UINT32(rx_status, TULIPState),
182
+ VMSTATE_UINT8_2DARRAY(filter, TULIPState, 16, 6),
183
+ VMSTATE_END_OF_LIST()
184
+ }
185
+};
186
+
187
+static void tulip_desc_read(TULIPState *s, hwaddr p,
188
+ struct tulip_descriptor *desc)
189
+{
190
+ if (s->csr[0] & CSR0_DBO) {
191
+ desc->status = ldl_be_pci_dma(&s->dev, p);
192
+ desc->control = ldl_be_pci_dma(&s->dev, p + 4);
193
+ desc->buf_addr1 = ldl_be_pci_dma(&s->dev, p + 8);
194
+ desc->buf_addr2 = ldl_be_pci_dma(&s->dev, p + 12);
195
+ } else {
196
+ desc->status = ldl_le_pci_dma(&s->dev, p);
197
+ desc->control = ldl_le_pci_dma(&s->dev, p + 4);
198
+ desc->buf_addr1 = ldl_le_pci_dma(&s->dev, p + 8);
199
+ desc->buf_addr2 = ldl_le_pci_dma(&s->dev, p + 12);
200
+ }
201
+}
202
+
203
+static void tulip_desc_write(TULIPState *s, hwaddr p,
204
+ struct tulip_descriptor *desc)
205
+{
206
+ if (s->csr[0] & CSR0_DBO) {
207
+ stl_be_pci_dma(&s->dev, p, desc->status);
208
+ stl_be_pci_dma(&s->dev, p + 4, desc->control);
209
+ stl_be_pci_dma(&s->dev, p + 8, desc->buf_addr1);
210
+ stl_be_pci_dma(&s->dev, p + 12, desc->buf_addr2);
211
+ } else {
212
+ stl_le_pci_dma(&s->dev, p, desc->status);
213
+ stl_le_pci_dma(&s->dev, p + 4, desc->control);
214
+ stl_le_pci_dma(&s->dev, p + 8, desc->buf_addr1);
215
+ stl_le_pci_dma(&s->dev, p + 12, desc->buf_addr2);
216
+ }
217
+}
218
+
219
+static void tulip_update_int(TULIPState *s)
220
+{
221
+ uint32_t ie = s->csr[5] & s->csr[7];
222
+ bool assert = false;
223
+
224
+ s->csr[5] &= ~(CSR5_AIS | CSR5_NIS);
225
+
226
+ if (ie & (CSR5_TI | CSR5_TU | CSR5_RI | CSR5_GTE | CSR5_ERI)) {
227
+ s->csr[5] |= CSR5_NIS;
228
+ }
229
+
230
+ if (ie & (CSR5_LC | CSR5_GPI | CSR5_FBE | CSR5_LNF | CSR5_ETI | CSR5_RWT |
231
+ CSR5_RPS | CSR5_RU | CSR5_UNF | CSR5_LNP_ANC | CSR5_TJT |
232
+ CSR5_TPS)) {
233
+ s->csr[5] |= CSR5_AIS;
234
+ }
235
+
236
+ assert = s->csr[5] & s->csr[7] & (CSR5_AIS | CSR5_NIS);
237
+ trace_tulip_irq(s->csr[5], s->csr[7], assert ? "assert" : "deassert");
238
+ qemu_set_irq(s->irq, assert);
239
+}
240
+
241
+static bool tulip_rx_stopped(TULIPState *s)
242
+{
243
+ return ((s->csr[5] >> CSR5_RS_SHIFT) & CSR5_RS_MASK) == CSR5_RS_STOPPED;
244
+}
245
+
246
+static void tulip_dump_tx_descriptor(TULIPState *s,
247
+ struct tulip_descriptor *desc)
248
+{
249
+ trace_tulip_descriptor("TX ", s->current_tx_desc,
250
+ desc->status, desc->control >> 22,
251
+ desc->control & 0x7ff, (desc->control >> 11) & 0x7ff,
252
+ desc->buf_addr1, desc->buf_addr2);
253
+}
254
+
255
+static void tulip_dump_rx_descriptor(TULIPState *s,
256
+ struct tulip_descriptor *desc)
257
+{
258
+ trace_tulip_descriptor("RX ", s->current_rx_desc,
259
+ desc->status, desc->control >> 22,
260
+ desc->control & 0x7ff, (desc->control >> 11) & 0x7ff,
261
+ desc->buf_addr1, desc->buf_addr2);
262
+}
263
+
264
+static void tulip_next_rx_descriptor(TULIPState *s,
265
+ struct tulip_descriptor *desc)
266
+{
267
+ if (desc->control & RDES1_RER) {
268
+ s->current_rx_desc = s->csr[3];
269
+ } else if (desc->control & RDES1_RCH) {
270
+ s->current_rx_desc = desc->buf_addr2;
271
+ } else {
272
+ s->current_rx_desc += sizeof(struct tulip_descriptor) +
273
+ (((s->csr[0] >> CSR0_DSL_SHIFT) & CSR0_DSL_MASK) << 2);
274
+ }
275
+ s->current_rx_desc &= ~3ULL;
276
+}
277
+
278
+static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc)
279
+{
280
+ int len1 = (desc->control >> RDES1_BUF1_SIZE_SHIFT) & RDES1_BUF1_SIZE_MASK;
281
+ int len2 = (desc->control >> RDES1_BUF2_SIZE_SHIFT) & RDES1_BUF2_SIZE_MASK;
282
+ int len;
283
+
284
+ if (s->rx_frame_len && len1) {
285
+ if (s->rx_frame_len > len1) {
286
+ len = len1;
287
+ } else {
288
+ len = s->rx_frame_len;
289
+ }
290
+ pci_dma_write(&s->dev, desc->buf_addr1, s->rx_frame +
291
+ (s->rx_frame_size - s->rx_frame_len), len);
292
+ s->rx_frame_len -= len;
293
+ }
294
+
295
+ if (s->rx_frame_len && len2) {
296
+ if (s->rx_frame_len > len2) {
297
+ len = len2;
298
+ } else {
299
+ len = s->rx_frame_len;
300
+ }
301
+ pci_dma_write(&s->dev, desc->buf_addr2, s->rx_frame +
302
+ (s->rx_frame_size - s->rx_frame_len), len);
303
+ s->rx_frame_len -= len;
304
+ }
305
+}
306
+
307
+static bool tulip_filter_address(TULIPState *s, const uint8_t *addr)
308
+{
309
+ static const char broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
310
+ bool ret = false;
311
+ int i;
312
+
313
+ for (i = 0; i < 16 && ret == false; i++) {
314
+ if (!memcmp(&s->filter[i], addr, ETH_ALEN)) {
315
+ ret = true;
316
+ }
317
+ }
318
+
319
+ if (!memcmp(addr, broadcast, ETH_ALEN)) {
320
+ return true;
321
+ }
322
+
323
+ if (s->csr[6] & (CSR6_PR | CSR6_RA)) {
324
+ /* Promiscuous mode enabled */
325
+ s->rx_status |= RDES0_FF;
326
+ return true;
327
+ }
328
+
329
+ if ((s->csr[6] & CSR6_PM) && (addr[0] & 1)) {
330
+ /* Pass all Multicast enabled */
331
+ s->rx_status |= RDES0_MF;
332
+ return true;
333
+ }
334
+
335
+ if (s->csr[6] & CSR6_IF) {
336
+ ret ^= true;
337
+ }
338
+ return ret;
339
+}
340
+
341
+static ssize_t tulip_receive(TULIPState *s, const uint8_t *buf, size_t size)
342
+{
343
+ struct tulip_descriptor desc;
344
+
345
+ trace_tulip_receive(buf, size);
346
+
347
+ if (size < 14 || size > 2048 || s->rx_frame_len || tulip_rx_stopped(s)) {
348
+ return 0;
349
+ }
350
+
351
+ if (!tulip_filter_address(s, buf)) {
352
+ return size;
353
+ }
354
+
355
+ do {
356
+ tulip_desc_read(s, s->current_rx_desc, &desc);
357
+ tulip_dump_rx_descriptor(s, &desc);
358
+
359
+ if (!(desc.status & RDES0_OWN)) {
360
+ s->csr[5] |= CSR5_RU;
361
+ tulip_update_int(s);
362
+ return s->rx_frame_size - s->rx_frame_len;
363
+ }
364
+ desc.status = 0;
365
+
366
+ if (!s->rx_frame_len) {
367
+ s->rx_frame_size = size + 4;
368
+ s->rx_status = RDES0_LS |
369
+ ((s->rx_frame_size & RDES0_FL_MASK) << RDES0_FL_SHIFT);
370
+ desc.status |= RDES0_FS;
371
+ memcpy(s->rx_frame, buf, size);
372
+ s->rx_frame_len = s->rx_frame_size;
373
+ }
374
+
375
+ tulip_copy_rx_bytes(s, &desc);
376
+
377
+ if (!s->rx_frame_len) {
378
+ desc.status |= s->rx_status;
379
+ s->csr[5] |= CSR5_RI;
380
+ tulip_update_int(s);
381
+ }
382
+ tulip_dump_rx_descriptor(s, &desc);
383
+ tulip_desc_write(s, s->current_rx_desc, &desc);
384
+ tulip_next_rx_descriptor(s, &desc);
385
+ } while (s->rx_frame_len);
386
+ return size;
387
+}
388
+
389
+static ssize_t tulip_receive_nc(NetClientState *nc,
390
+ const uint8_t *buf, size_t size)
391
+{
392
+ return tulip_receive(qemu_get_nic_opaque(nc), buf, size);
393
+}
394
+
395
+
396
+static NetClientInfo net_tulip_info = {
397
+ .type = NET_CLIENT_DRIVER_NIC,
398
+ .size = sizeof(NICState),
399
+ .receive = tulip_receive_nc,
400
+};
401
+
402
+static const char *tulip_reg_name(const hwaddr addr)
403
+{
404
+ switch (addr) {
405
+ case CSR(0):
406
+ return "CSR0";
407
+
408
+ case CSR(1):
409
+ return "CSR1";
410
+
411
+ case CSR(2):
412
+ return "CSR2";
413
+
414
+ case CSR(3):
415
+ return "CSR3";
416
+
417
+ case CSR(4):
418
+ return "CSR4";
419
+
420
+ case CSR(5):
421
+ return "CSR5";
422
+
423
+ case CSR(6):
424
+ return "CSR6";
425
+
426
+ case CSR(7):
427
+ return "CSR7";
428
+
429
+ case CSR(8):
430
+ return "CSR8";
431
+
432
+ case CSR(9):
433
+ return "CSR9";
434
+
435
+ case CSR(10):
436
+ return "CSR10";
437
+
438
+ case CSR(11):
439
+ return "CSR11";
440
+
441
+ case CSR(12):
442
+ return "CSR12";
443
+
444
+ case CSR(13):
445
+ return "CSR13";
446
+
447
+ case CSR(14):
448
+ return "CSR14";
449
+
450
+ case CSR(15):
451
+ return "CSR15";
452
+
453
+ default:
454
+ break;
455
+ }
456
+ return "";
457
+}
458
+
459
+static const char *tulip_rx_state_name(int state)
460
+{
461
+ switch (state) {
462
+ case CSR5_RS_STOPPED:
463
+ return "STOPPED";
464
+
465
+ case CSR5_RS_RUNNING_FETCH:
466
+ return "RUNNING/FETCH";
467
+
468
+ case CSR5_RS_RUNNING_CHECK_EOR:
469
+ return "RUNNING/CHECK EOR";
470
+
471
+ case CSR5_RS_RUNNING_WAIT_RECEIVE:
472
+ return "WAIT RECEIVE";
473
+
474
+ case CSR5_RS_SUSPENDED:
475
+ return "SUSPENDED";
476
+
477
+ case CSR5_RS_RUNNING_CLOSE:
478
+ return "RUNNING/CLOSE";
479
+
480
+ case CSR5_RS_RUNNING_FLUSH:
481
+ return "RUNNING/FLUSH";
482
+
483
+ case CSR5_RS_RUNNING_QUEUE:
484
+ return "RUNNING/QUEUE";
485
+
486
+ default:
487
+ break;
488
+ }
489
+ return "";
490
+}
491
+
492
+static const char *tulip_tx_state_name(int state)
493
+{
494
+ switch (state) {
495
+ case CSR5_TS_STOPPED:
496
+ return "STOPPED";
497
+
498
+ case CSR5_TS_RUNNING_FETCH:
499
+ return "RUNNING/FETCH";
500
+
501
+ case CSR5_TS_RUNNING_WAIT_EOT:
502
+ return "RUNNING/WAIT EOT";
503
+
504
+ case CSR5_TS_RUNNING_READ_BUF:
505
+ return "RUNNING/READ BUF";
506
+
507
+ case CSR5_TS_RUNNING_SETUP:
508
+ return "RUNNING/SETUP";
509
+
510
+ case CSR5_TS_SUSPENDED:
511
+ return "SUSPENDED";
512
+
513
+ case CSR5_TS_RUNNING_CLOSE:
514
+ return "RUNNING/CLOSE";
515
+
516
+ default:
517
+ break;
518
+ }
519
+ return "";
520
+}
521
+
522
+static void tulip_update_rs(TULIPState *s, int state)
523
+{
524
+ s->csr[5] &= ~(CSR5_RS_MASK << CSR5_RS_SHIFT);
525
+ s->csr[5] |= (state & CSR5_RS_MASK) << CSR5_RS_SHIFT;
526
+ trace_tulip_rx_state(tulip_rx_state_name(state));
527
+}
528
+
529
+static uint16_t tulip_mdi_default[] = {
530
+ /* MDI Registers 0 - 6, 7 */
531
+ 0x3100, 0xf02c, 0x7810, 0x0000, 0x0501, 0x4181, 0x0000, 0x0000,
532
+ /* MDI Registers 8 - 15 */
533
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
534
+ /* MDI Registers 16 - 31 */
535
+ 0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
536
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
537
+};
538
+
539
+/* Readonly mask for MDI (PHY) registers */
540
+static const uint16_t tulip_mdi_mask[] = {
541
+ 0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000,
542
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
543
+ 0x0fff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
544
+ 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
545
+};
546
+
547
+static uint16_t tulip_mii_read(TULIPState *s, int phy, int reg)
548
+{
549
+ uint16_t ret = 0;
550
+ if (phy == 1) {
551
+ ret = tulip_mdi_default[reg];
552
+ }
553
+ trace_tulip_mii_read(phy, reg, ret);
554
+ return ret;
555
+}
556
+
557
+static void tulip_mii_write(TULIPState *s, int phy, int reg, uint16_t data)
558
+{
559
+ trace_tulip_mii_write(phy, reg, data);
560
+
561
+ if (phy != 1) {
562
+ return;
563
+ }
564
+
565
+ tulip_mdi_default[reg] &= ~tulip_mdi_mask[reg];
566
+ tulip_mdi_default[reg] |= (data & tulip_mdi_mask[reg]);
567
+}
568
+
569
+static void tulip_mii(TULIPState *s)
570
+{
571
+ uint32_t changed = s->old_csr9 ^ s->csr[9];
572
+ uint16_t data;
573
+ int op, phy, reg;
574
+
575
+ if (!(changed & CSR9_MDC)) {
576
+ return;
577
+ }
578
+
579
+ if (!(s->csr[9] & CSR9_MDC)) {
580
+ return;
581
+ }
582
+
583
+ s->mii_bitcnt++;
584
+ s->mii_word <<= 1;
585
+
586
+ if (s->csr[9] & CSR9_MDO && (s->mii_bitcnt < 16 ||
587
+ !(s->csr[9] & CSR9_MII))) {
588
+ /* write op or address bits */
589
+ s->mii_word |= 1;
590
+ }
591
+
592
+ if (s->mii_bitcnt >= 16 && (s->csr[9] & CSR9_MII)) {
593
+ if (s->mii_word & 0x8000) {
594
+ s->csr[9] |= CSR9_MDI;
595
+ } else {
596
+ s->csr[9] &= ~CSR9_MDI;
597
+ }
598
+ }
599
+
600
+ if (s->mii_word == 0xffffffff) {
601
+ s->mii_bitcnt = 0;
602
+ } else if (s->mii_bitcnt == 16) {
603
+ op = (s->mii_word >> 12) & 0x0f;
604
+ phy = (s->mii_word >> 7) & 0x1f;
605
+ reg = (s->mii_word >> 2) & 0x1f;
606
+
607
+ if (op == 6) {
608
+ s->mii_word = tulip_mii_read(s, phy, reg);
609
+ }
610
+ } else if (s->mii_bitcnt == 32) {
611
+ op = (s->mii_word >> 28) & 0x0f;
612
+ phy = (s->mii_word >> 23) & 0x1f;
613
+ reg = (s->mii_word >> 18) & 0x1f;
614
+ data = s->mii_word & 0xffff;
615
+
616
+ if (op == 5) {
617
+ tulip_mii_write(s, phy, reg, data);
618
+ }
619
+ }
620
+}
621
+
622
+static uint32_t tulip_csr9_read(TULIPState *s)
623
+{
624
+ if (s->csr[9] & CSR9_SR) {
625
+ if (eeprom93xx_read(s->eeprom)) {
626
+ s->csr[9] |= CSR9_SR_DO;
627
+ } else {
628
+ s->csr[9] &= ~CSR9_SR_DO;
629
+ }
630
+ }
631
+
632
+ tulip_mii(s);
633
+ return s->csr[9];
634
+}
635
+
636
+static void tulip_update_ts(TULIPState *s, int state)
637
+{
638
+ s->csr[5] &= ~(CSR5_TS_MASK << CSR5_TS_SHIFT);
639
+ s->csr[5] |= (state & CSR5_TS_MASK) << CSR5_TS_SHIFT;
640
+ trace_tulip_tx_state(tulip_tx_state_name(state));
641
+}
642
+
643
+static uint64_t tulip_read(void *opaque, hwaddr addr,
644
+ unsigned size)
645
+{
646
+ TULIPState *s = opaque;
647
+ uint64_t data = 0;
648
+
649
+ switch (addr) {
650
+ case CSR(9):
651
+ data = tulip_csr9_read(s);
652
+ break;
653
+
654
+ case CSR(12):
655
+ /* Fake autocompletion complete until we have PHY emulation */
656
+ data = 5 << CSR12_ANS_SHIFT;
657
+ break;
658
+
659
+ default:
660
+ if (addr & 7) {
661
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: read access at unknown address"
662
+ " 0x%"PRIx64"\n", __func__, addr);
663
+ } else {
664
+ data = s->csr[addr >> 3];
665
+ }
666
+ break;
667
+ }
668
+ trace_tulip_reg_read(addr, tulip_reg_name(addr), size, data);
669
+ return data;
670
+}
671
+
672
+static void tulip_tx(TULIPState *s, struct tulip_descriptor *desc)
673
+{
674
+ if (s->tx_frame_len) {
675
+ if ((s->csr[6] >> CSR6_OM_SHIFT) & CSR6_OM_MASK) {
676
+ /* Internal or external Loopback */
677
+ tulip_receive(s, s->tx_frame, s->tx_frame_len);
678
+ } else {
679
+ qemu_send_packet(qemu_get_queue(s->nic),
680
+ s->tx_frame, s->tx_frame_len);
681
+ }
682
+ }
683
+
684
+ if (desc->control & TDES1_IC) {
685
+ s->csr[5] |= CSR5_TI;
686
+ tulip_update_int(s);
687
+ }
688
+}
689
+
690
+static void tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc)
691
+{
692
+ int len1 = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK;
693
+ int len2 = (desc->control >> TDES1_BUF2_SIZE_SHIFT) & TDES1_BUF2_SIZE_MASK;
694
+
695
+ if (len1) {
696
+ pci_dma_read(&s->dev, desc->buf_addr1,
697
+ s->tx_frame + s->tx_frame_len, len1);
698
+ s->tx_frame_len += len1;
699
+ }
700
+
701
+ if (len2) {
702
+ pci_dma_read(&s->dev, desc->buf_addr2,
703
+ s->tx_frame + s->tx_frame_len, len2);
704
+ s->tx_frame_len += len2;
705
+ }
706
+ desc->status = (len1 + len2) ? 0 : 0x7fffffff;
707
+}
708
+
709
+static void tulip_setup_filter_addr(TULIPState *s, uint8_t *buf, int n)
710
+{
711
+ int offset = n * 12;
712
+
713
+ s->filter[n][0] = buf[offset];
714
+ s->filter[n][1] = buf[offset + 1];
715
+
716
+ s->filter[n][2] = buf[offset + 4];
717
+ s->filter[n][3] = buf[offset + 5];
718
+
719
+ s->filter[n][4] = buf[offset + 8];
720
+ s->filter[n][5] = buf[offset + 9];
721
+
722
+ trace_tulip_setup_filter(n, s->filter[n][5], s->filter[n][4],
723
+ s->filter[n][3], s->filter[n][2], s->filter[n][1], s->filter[n][0]);
724
+}
725
+
726
+static void tulip_setup_frame(TULIPState *s,
727
+ struct tulip_descriptor *desc)
728
+{
729
+ uint8_t buf[4096];
730
+ int len = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK;
731
+ int i;
732
+
733
+ trace_tulip_setup_frame();
734
+
735
+ if (len == 192) {
736
+ pci_dma_read(&s->dev, desc->buf_addr1, buf, len);
737
+ for (i = 0; i < 16; i++) {
738
+ tulip_setup_filter_addr(s, buf, i);
739
+ }
740
+ }
741
+
742
+ desc->status = 0x7fffffff;
743
+
744
+ if (desc->control & TDES1_IC) {
745
+ s->csr[5] |= CSR5_TI;
746
+ tulip_update_int(s);
747
+ }
748
+}
749
+
750
+static void tulip_next_tx_descriptor(TULIPState *s,
751
+ struct tulip_descriptor *desc)
752
+{
753
+ if (desc->control & TDES1_TER) {
754
+ s->current_tx_desc = s->csr[4];
755
+ } else if (desc->control & TDES1_TCH) {
756
+ s->current_tx_desc = desc->buf_addr2;
757
+ } else {
758
+ s->current_tx_desc += sizeof(struct tulip_descriptor) +
759
+ (((s->csr[0] >> CSR0_DSL_SHIFT) & CSR0_DSL_MASK) << 2);
760
+ }
761
+ s->current_tx_desc &= ~3ULL;
762
+}
763
+
764
+static uint32_t tulip_ts(TULIPState *s)
765
+{
766
+ return (s->csr[5] >> CSR5_TS_SHIFT) & CSR5_TS_MASK;
767
+}
768
+
769
+static void tulip_xmit_list_update(TULIPState *s)
770
+{
771
+ struct tulip_descriptor desc;
772
+
773
+ if (tulip_ts(s) != CSR5_TS_SUSPENDED) {
774
+ return;
775
+ }
776
+
777
+ for (;;) {
778
+ tulip_desc_read(s, s->current_tx_desc, &desc);
779
+ tulip_dump_tx_descriptor(s, &desc);
780
+
781
+ if (!(desc.status & TDES0_OWN)) {
782
+ tulip_update_ts(s, CSR5_TS_SUSPENDED);
783
+ s->csr[5] |= CSR5_TU;
784
+ tulip_update_int(s);
785
+ return;
786
+ }
787
+
788
+ if (desc.control & TDES1_SET) {
789
+ tulip_setup_frame(s, &desc);
790
+ } else {
791
+ if (desc.control & TDES1_FS) {
792
+ s->tx_frame_len = 0;
793
+ }
794
+
795
+ tulip_copy_tx_buffers(s, &desc);
796
+
797
+ if (desc.control & TDES1_LS) {
798
+ tulip_tx(s, &desc);
799
+ }
800
+ }
801
+ tulip_desc_write(s, s->current_tx_desc, &desc);
802
+ tulip_next_tx_descriptor(s, &desc);
803
+ }
804
+}
805
+
806
+static void tulip_csr9_write(TULIPState *s, uint32_t old_val,
807
+ uint32_t new_val)
808
+{
809
+ if (new_val & CSR9_SR) {
810
+ eeprom93xx_write(s->eeprom,
811
+ !!(new_val & CSR9_SR_CS),
812
+ !!(new_val & CSR9_SR_SK),
813
+ !!(new_val & CSR9_SR_DI));
814
+ }
815
+}
816
+
817
+static void tulip_reset(TULIPState *s)
818
+{
819
+ trace_tulip_reset();
820
+
821
+ s->csr[0] = 0xfe000000;
822
+ s->csr[1] = 0xffffffff;
823
+ s->csr[2] = 0xffffffff;
824
+ s->csr[5] = 0xf0000000;
825
+ s->csr[6] = 0x32000040;
826
+ s->csr[7] = 0xf3fe0000;
827
+ s->csr[8] = 0xe0000000;
828
+ s->csr[9] = 0xfff483ff;
829
+ s->csr[11] = 0xfffe0000;
830
+ s->csr[12] = 0x000000c6;
831
+ s->csr[13] = 0xffff0000;
832
+ s->csr[14] = 0xffffffff;
833
+ s->csr[15] = 0x8ff00000;
834
+}
835
+
836
+static void tulip_qdev_reset(DeviceState *dev)
837
+{
838
+ PCIDevice *d = PCI_DEVICE(dev);
839
+ TULIPState *s = TULIP(d);
840
+
841
+ tulip_reset(s);
842
+}
843
+
844
+static void tulip_write(void *opaque, hwaddr addr,
845
+ uint64_t data, unsigned size)
846
+{
847
+ TULIPState *s = opaque;
848
+ trace_tulip_reg_write(addr, tulip_reg_name(addr), size, data);
849
+
850
+ switch (addr) {
851
+ case CSR(0):
852
+ s->csr[0] = data;
853
+ if (data & CSR0_SWR) {
854
+ tulip_reset(s);
855
+ tulip_update_int(s);
856
+ }
857
+ break;
858
+
859
+ case CSR(1):
860
+ tulip_xmit_list_update(s);
861
+ break;
862
+
863
+ case CSR(2):
864
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
865
+ break;
866
+
867
+ case CSR(3):
868
+ s->csr[3] = data & ~3ULL;
869
+ s->current_rx_desc = s->csr[3];
870
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
871
+ break;
872
+
873
+ case CSR(4):
874
+ s->csr[4] = data & ~3ULL;
875
+ s->current_tx_desc = s->csr[4];
876
+ tulip_xmit_list_update(s);
877
+ break;
878
+
879
+ case CSR(5):
880
+ /* Status register, write clears bit */
881
+ s->csr[5] &= ~(data & (CSR5_TI | CSR5_TPS | CSR5_TU | CSR5_TJT |
882
+ CSR5_LNP_ANC | CSR5_UNF | CSR5_RI | CSR5_RU |
883
+ CSR5_RPS | CSR5_RWT | CSR5_ETI | CSR5_GTE |
884
+ CSR5_LNF | CSR5_FBE | CSR5_ERI | CSR5_AIS |
885
+ CSR5_NIS | CSR5_GPI | CSR5_LC));
886
+ tulip_update_int(s);
887
+ break;
888
+
889
+ case CSR(6):
890
+ s->csr[6] = data;
891
+ if (s->csr[6] & CSR6_SR) {
892
+ tulip_update_rs(s, CSR5_RS_RUNNING_WAIT_RECEIVE);
893
+ qemu_flush_queued_packets(qemu_get_queue(s->nic));
894
+ } else {
895
+ tulip_update_rs(s, CSR5_RS_STOPPED);
896
+ }
897
+
898
+ if (s->csr[6] & CSR6_ST) {
899
+ tulip_update_ts(s, CSR5_TS_SUSPENDED);
900
+ tulip_xmit_list_update(s);
901
+ } else {
902
+ tulip_update_ts(s, CSR5_TS_STOPPED);
903
+ }
904
+ break;
905
+
906
+ case CSR(7):
907
+ s->csr[7] = data;
908
+ tulip_update_int(s);
909
+ break;
910
+
911
+ case CSR(8):
912
+ s->csr[9] = data;
913
+ break;
914
+
915
+ case CSR(9):
916
+ tulip_csr9_write(s, s->csr[9], data);
917
+ /* don't clear MII read data */
918
+ s->csr[9] &= CSR9_MDI;
919
+ s->csr[9] |= (data & ~CSR9_MDI);
920
+ tulip_mii(s);
921
+ s->old_csr9 = s->csr[9];
922
+ break;
923
+
924
+ case CSR(10):
925
+ s->csr[10] = data;
926
+ break;
927
+
928
+ case CSR(11):
929
+ s->csr[11] = data;
930
+ break;
931
+
932
+ case CSR(12):
933
+ /* SIA Status register, some bits are cleared by writing 1 */
934
+ s->csr[12] &= ~(data & (CSR12_MRA | CSR12_TRA | CSR12_ARA));
935
+ break;
936
+
937
+ case CSR(13):
938
+ s->csr[13] = data;
939
+ break;
940
+
941
+ case CSR(14):
942
+ s->csr[14] = data;
943
+ break;
944
+
945
+ case CSR(15):
946
+ s->csr[15] = data;
947
+ break;
948
+
949
+ default:
950
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: write to CSR at unknown address "
951
+ "0x%"PRIx64"\n", __func__, addr);
952
+ break;
953
+ }
954
+}
955
+
956
+static const MemoryRegionOps tulip_ops = {
957
+ .read = tulip_read,
958
+ .write = tulip_write,
959
+ .endianness = DEVICE_LITTLE_ENDIAN,
960
+ .impl = {
961
+ .min_access_size = 4,
962
+ .max_access_size = 4,
963
+ },
964
+};
965
+
966
+static void tulip_idblock_crc(TULIPState *s, uint16_t *srom)
967
+{
968
+ int word, n;
969
+ int bit;
970
+ unsigned char bitval, crc;
971
+ const int len = 9;
972
+ n = 0;
973
+ crc = -1;
974
+
975
+ for (word = 0; word < len; word++) {
976
+ for (bit = 15; bit >= 0; bit--) {
977
+ if ((word == (len - 1)) && (bit == 7)) {
978
+ /*
979
+ * Insert the correct CRC result into input data stream
980
+ * in place.
981
+ */
982
+ srom[len - 1] = (srom[len - 1] & 0xff00) | (unsigned short)crc;
983
+ break;
984
+ }
985
+ n++;
986
+ bitval = ((srom[word] >> bit) & 1) ^ ((crc >> 7) & 1);
987
+ crc = crc << 1;
988
+ if (bitval == 1) {
989
+ crc ^= 6;
990
+ crc |= 0x01;
991
+ }
992
+ }
993
+ }
994
+}
995
+
996
+static uint16_t tulip_srom_crc(TULIPState *s, uint8_t *eeprom, size_t len)
997
+{
998
+ unsigned long crc = 0xffffffff;
999
+ unsigned long flippedcrc = 0;
1000
+ unsigned char currentbyte;
1001
+ unsigned int msb, bit, i;
1002
+
1003
+ for (i = 0; i < len; i++) {
1004
+ currentbyte = eeprom[i];
1005
+ for (bit = 0; bit < 8; bit++) {
1006
+ msb = (crc >> 31) & 1;
1007
+ crc <<= 1;
1008
+ if (msb ^ (currentbyte & 1)) {
1009
+ crc ^= 0x04c11db6;
1010
+ crc |= 0x00000001;
1011
+ }
1012
+ currentbyte >>= 1;
1013
+ }
1014
+ }
1015
+
1016
+ for (i = 0; i < 32; i++) {
1017
+ flippedcrc <<= 1;
1018
+ bit = crc & 1;
1019
+ crc >>= 1;
1020
+ flippedcrc += bit;
1021
+ }
1022
+ return (flippedcrc ^ 0xffffffff) & 0xffff;
1023
+}
1024
+
1025
+static const uint8_t eeprom_default[128] = {
1026
+ 0x3c, 0x10, 0x4f, 0x10, 0x00, 0x00, 0x00, 0x00,
1027
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1028
+ 0x56, 0x08, 0x04, 0x01, 0x00, 0x80, 0x48, 0xb3,
1029
+ 0x0e, 0xa7, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x08,
1030
+ 0x01, 0x8d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x78,
1031
+ 0xe0, 0x01, 0x00, 0x50, 0x00, 0x18, 0x00, 0x00,
1032
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1033
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1034
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1035
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1036
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1037
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x6b,
1038
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
1039
+ 0x48, 0xb3, 0x0e, 0xa7, 0x40, 0x00, 0x00, 0x00,
1040
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1041
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1042
+};
1043
+
1044
+static void tulip_fill_eeprom(TULIPState *s)
1045
+{
1046
+ uint16_t *eeprom = eeprom93xx_data(s->eeprom);
1047
+ memcpy(eeprom, eeprom_default, 128);
1048
+
1049
+ /* patch in our mac address */
1050
+ eeprom[10] = cpu_to_le16(s->c.macaddr.a[0] | (s->c.macaddr.a[1] << 8));
1051
+ eeprom[11] = cpu_to_le16(s->c.macaddr.a[2] | (s->c.macaddr.a[3] << 8));
1052
+ eeprom[12] = cpu_to_le16(s->c.macaddr.a[4] | (s->c.macaddr.a[5] << 8));
1053
+ tulip_idblock_crc(s, eeprom);
1054
+ eeprom[63] = cpu_to_le16(tulip_srom_crc(s, (uint8_t *)eeprom, 126));
1055
+}
1056
+
1057
+static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp)
1058
+{
1059
+ TULIPState *s = DO_UPCAST(TULIPState, dev, pci_dev);
1060
+ uint8_t *pci_conf;
1061
+
1062
+ pci_conf = s->dev.config;
1063
+ pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
1064
+
1065
+ s->eeprom = eeprom93xx_new(&pci_dev->qdev, 64);
1066
+ tulip_fill_eeprom(s);
1067
+
1068
+ memory_region_init_io(&s->io, OBJECT(&s->dev), &tulip_ops, s,
1069
+ "tulip-io", 128);
1070
+
1071
+ memory_region_init_io(&s->memory, OBJECT(&s->dev), &tulip_ops, s,
1072
+ "tulip-mem", 128);
1073
+
1074
+ pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
1075
+ pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->memory);
1076
+
1077
+ s->irq = pci_allocate_irq(&s->dev);
1078
+
1079
+ qemu_macaddr_default_if_unset(&s->c.macaddr);
1080
+
1081
+ s->nic = qemu_new_nic(&net_tulip_info, &s->c,
1082
+ object_get_typename(OBJECT(pci_dev)),
1083
+ pci_dev->qdev.id, s);
1084
+ qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a);
1085
+}
1086
+
1087
+static void pci_tulip_exit(PCIDevice *pci_dev)
1088
+{
1089
+ TULIPState *s = DO_UPCAST(TULIPState, dev, pci_dev);
1090
+
1091
+ qemu_del_nic(s->nic);
1092
+ qemu_free_irq(s->irq);
1093
+ eeprom93xx_free(&pci_dev->qdev, s->eeprom);
1094
+}
1095
+
1096
+static void tulip_instance_init(Object *obj)
1097
+{
1098
+ PCIDevice *pci_dev = PCI_DEVICE(obj);
1099
+ TULIPState *d = DO_UPCAST(TULIPState, dev, pci_dev);
1100
+
1101
+ device_add_bootindex_property(obj, &d->c.bootindex,
1102
+ "bootindex", "/ethernet-phy@0",
1103
+ &pci_dev->qdev, NULL);
1104
+}
1105
+
1106
+static Property tulip_properties[] = {
1107
+ DEFINE_NIC_PROPERTIES(TULIPState, c),
1108
+ DEFINE_PROP_END_OF_LIST(),
1109
+};
1110
+
1111
+static void tulip_class_init(ObjectClass *klass, void *data)
1112
+{
1113
+ DeviceClass *dc = DEVICE_CLASS(klass);
1114
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
1115
+
1116
+ k->realize = pci_tulip_realize;
1117
+ k->exit = pci_tulip_exit;
1118
+ k->vendor_id = PCI_VENDOR_ID_DEC;
1119
+ k->device_id = PCI_DEVICE_ID_DEC_21143;
1120
+ k->subsystem_vendor_id = 0x103c;
1121
+ k->subsystem_id = 0x104f;
1122
+ k->class_id = PCI_CLASS_NETWORK_ETHERNET;
1123
+ dc->vmsd = &vmstate_pci_tulip;
1124
+ dc->props = tulip_properties;
1125
+ dc->reset = tulip_qdev_reset;
1126
+ set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
1127
+}
1128
+
1129
+static const TypeInfo tulip_info = {
1130
+ .name = TYPE_TULIP,
1131
+ .parent = TYPE_PCI_DEVICE,
1132
+ .instance_size = sizeof(TULIPState),
1133
+ .class_init = tulip_class_init,
1134
+ .instance_init = tulip_instance_init,
1135
+ .interfaces = (InterfaceInfo[]) {
1136
+ { INTERFACE_CONVENTIONAL_PCI_DEVICE },
1137
+ { },
1138
+ },
1139
+};
1140
+
1141
+static void tulip_register_types(void)
1142
+{
1143
+ type_register_static(&tulip_info);
1144
+}
1145
+
1146
+type_init(tulip_register_types)
1147
diff --git a/hw/net/tulip.h b/hw/net/tulip.h
1148
new file mode 100644
1149
index XXXXXXX..XXXXXXX
1150
--- /dev/null
1151
+++ b/hw/net/tulip.h
1152
@@ -XXX,XX +XXX,XX @@
1153
+#ifndef HW_TULIP_H
1154
+#define HW_TULIP_H
1155
+
1156
+#include "qemu/units.h"
1157
+#include "net/net.h"
1158
+
1159
+#define TYPE_TULIP "tulip"
1160
+#define TULIP(obj) OBJECT_CHECK(TULIPState, (obj), TYPE_TULIP)
1161
+
1162
+#define CSR(_x) ((_x) << 3)
1163
+
1164
+#define CSR0_SWR BIT(0)
1165
+#define CSR0_BAR BIT(1)
1166
+#define CSR0_DSL_SHIFT 2
1167
+#define CSR0_DSL_MASK 0x1f
1168
+#define CSR0_BLE BIT(7)
1169
+#define CSR0_PBL_SHIFT 8
1170
+#define CSR0_PBL_MASK 0x3f
1171
+#define CSR0_CAC_SHIFT 14
1172
+#define CSR0_CAC_MASK 0x3
1173
+#define CSR0_DAS 0x10000
1174
+#define CSR0_TAP_SHIFT 17
1175
+#define CSR0_TAP_MASK 0x7
1176
+#define CSR0_DBO 0x100000
1177
+#define CSR1_TPD 0x01
1178
+#define CSR0_RLE BIT(23)
1179
+#define CSR0_WIE BIT(24)
1180
+
1181
+#define CSR2_RPD 0x01
1182
+
1183
+#define CSR5_TI BIT(0)
1184
+#define CSR5_TPS BIT(1)
1185
+#define CSR5_TU BIT(2)
1186
+#define CSR5_TJT BIT(3)
1187
+#define CSR5_LNP_ANC BIT(4)
1188
+#define CSR5_UNF BIT(5)
1189
+#define CSR5_RI BIT(6)
1190
+#define CSR5_RU BIT(7)
1191
+#define CSR5_RPS BIT(8)
1192
+#define CSR5_RWT BIT(9)
1193
+#define CSR5_ETI BIT(10)
1194
+#define CSR5_GTE BIT(11)
1195
+#define CSR5_LNF BIT(12)
1196
+#define CSR5_FBE BIT(13)
1197
+#define CSR5_ERI BIT(14)
1198
+#define CSR5_AIS BIT(15)
1199
+#define CSR5_NIS BIT(16)
1200
+#define CSR5_RS_SHIFT 17
1201
+#define CSR5_RS_MASK 7
1202
+#define CSR5_TS_SHIFT 20
1203
+#define CSR5_TS_MASK 7
1204
+
1205
+#define CSR5_TS_STOPPED 0
1206
+#define CSR5_TS_RUNNING_FETCH 1
1207
+#define CSR5_TS_RUNNING_WAIT_EOT 2
1208
+#define CSR5_TS_RUNNING_READ_BUF 3
1209
+#define CSR5_TS_RUNNING_SETUP 5
1210
+#define CSR5_TS_SUSPENDED 6
1211
+#define CSR5_TS_RUNNING_CLOSE 7
1212
+
1213
+#define CSR5_RS_STOPPED 0
1214
+#define CSR5_RS_RUNNING_FETCH 1
1215
+#define CSR5_RS_RUNNING_CHECK_EOR 2
1216
+#define CSR5_RS_RUNNING_WAIT_RECEIVE 3
1217
+#define CSR5_RS_SUSPENDED 4
1218
+#define CSR5_RS_RUNNING_CLOSE 5
1219
+#define CSR5_RS_RUNNING_FLUSH 6
1220
+#define CSR5_RS_RUNNING_QUEUE 7
1221
+
1222
+#define CSR5_EB_SHIFT 23
1223
+#define CSR5_EB_MASK 7
1224
+
1225
+#define CSR5_GPI BIT(26)
1226
+#define CSR5_LC BIT(27)
1227
+
1228
+#define CSR6_HP BIT(0)
1229
+#define CSR6_SR BIT(1)
1230
+#define CSR6_HO BIT(2)
1231
+#define CSR6_PB BIT(3)
1232
+#define CSR6_IF BIT(4)
1233
+#define CSR6_SB BIT(5)
1234
+#define CSR6_PR BIT(6)
1235
+#define CSR6_PM BIT(7)
1236
+#define CSR6_FKD BIT(8)
1237
+#define CSR6_FD BIT(9)
1238
+
1239
+#define CSR6_OM_SHIFT 10
1240
+#define CSR6_OM_MASK 3
1241
+#define CSR6_OM_NORMAL 0
1242
+#define CSR6_OM_INT_LOOPBACK 1
1243
+#define CSR6_OM_EXT_LOOPBACK 2
1244
+
1245
+#define CSR6_FC BIT(12)
1246
+#define CSR6_ST BIT(13)
1247
+
1248
+
1249
+#define CSR6_TR_SHIFT 14
1250
+#define CSR6_TR_MASK 3
1251
+#define CSR6_TR_72 0
1252
+#define CSR6_TR_96 1
1253
+#define CSR6_TR_128 2
1254
+#define CSR6_TR_160 3
1255
+
1256
+#define CSR6_CA BIT(17)
1257
+#define CSR6_RA BIT(30)
1258
+#define CSR6_SC BIT(31)
1259
+
1260
+#define CSR7_TIM BIT(0)
1261
+#define CSR7_TSM BIT(1)
1262
+#define CSR7_TUM BIT(2)
1263
+#define CSR7_TJM BIT(3)
1264
+#define CSR7_LPM BIT(4)
1265
+#define CSR7_UNM BIT(5)
1266
+#define CSR7_RIM BIT(6)
1267
+#define CSR7_RUM BIT(7)
1268
+#define CSR7_RSM BIT(8)
1269
+#define CSR7_RWM BIT(9)
1270
+#define CSR7_TMM BIT(11)
1271
+#define CSR7_LFM BIT(12)
1272
+#define CSR7_SEM BIT(13)
1273
+#define CSR7_ERM BIT(14)
1274
+#define CSR7_AIM BIT(15)
1275
+#define CSR7_NIM BIT(16)
1276
+
1277
+#define CSR8_MISSED_FRAME_OVL BIT(16)
1278
+#define CSR8_MISSED_FRAME_CNT_MASK 0xffff
1279
+
1280
+#define CSR9_DATA_MASK 0xff
1281
+#define CSR9_SR_CS BIT(0)
1282
+#define CSR9_SR_SK BIT(1)
1283
+#define CSR9_SR_DI BIT(2)
1284
+#define CSR9_SR_DO BIT(3)
1285
+#define CSR9_REG BIT(10)
1286
+#define CSR9_SR BIT(11)
1287
+#define CSR9_BR BIT(12)
1288
+#define CSR9_WR BIT(13)
1289
+#define CSR9_RD BIT(14)
1290
+#define CSR9_MOD BIT(15)
1291
+#define CSR9_MDC BIT(16)
1292
+#define CSR9_MDO BIT(17)
1293
+#define CSR9_MII BIT(18)
1294
+#define CSR9_MDI BIT(19)
1295
+
1296
+#define CSR11_CON BIT(16)
1297
+#define CSR11_TIMER_MASK 0xffff
1298
+
1299
+#define CSR12_MRA BIT(0)
1300
+#define CSR12_LS100 BIT(1)
1301
+#define CSR12_LS10 BIT(2)
1302
+#define CSR12_APS BIT(3)
1303
+#define CSR12_ARA BIT(8)
1304
+#define CSR12_TRA BIT(9)
1305
+#define CSR12_NSN BIT(10)
1306
+#define CSR12_TRF BIT(11)
1307
+#define CSR12_ANS_SHIFT 12
1308
+#define CSR12_ANS_MASK 7
1309
+#define CSR12_LPN BIT(15)
1310
+#define CSR12_LPC_SHIFT 16
1311
+#define CSR12_LPC_MASK 0xffff
1312
+
1313
+#define CSR13_SRL BIT(0)
1314
+#define CSR13_CAC BIT(2)
1315
+#define CSR13_AUI BIT(3)
1316
+#define CSR13_SDM_SHIFT 4
1317
+#define CSR13_SDM_MASK 0xfff
1318
+
1319
+#define CSR14_ECEN BIT(0)
1320
+#define CSR14_LBK BIT(1)
1321
+#define CSR14_DREN BIT(2)
1322
+#define CSR14_LSE BIT(3)
1323
+#define CSR14_CPEN_SHIFT 4
1324
+#define CSR14_CPEN_MASK 3
1325
+#define CSR14_MBO BIT(6)
1326
+#define CSR14_ANE BIT(7)
1327
+#define CSR14_RSQ BIT(8)
1328
+#define CSR14_CSQ BIT(9)
1329
+#define CSR14_CLD BIT(10)
1330
+#define CSR14_SQE BIT(11)
1331
+#define CSR14_LTE BIT(12)
1332
+#define CSR14_APE BIT(13)
1333
+#define CSR14_SPP BIT(14)
1334
+#define CSR14_TAS BIT(15)
1335
+
1336
+#define CSR15_JBD BIT(0)
1337
+#define CSR15_HUJ BIT(1)
1338
+#define CSR15_JCK BIT(2)
1339
+#define CSR15_ABM BIT(3)
1340
+#define CSR15_RWD BIT(4)
1341
+#define CSR15_RWR BIT(5)
1342
+#define CSR15_LE1 BIT(6)
1343
+#define CSR15_LV1 BIT(7)
1344
+#define CSR15_TSCK BIT(8)
1345
+#define CSR15_FUSQ BIT(9)
1346
+#define CSR15_FLF BIT(10)
1347
+#define CSR15_LSD BIT(11)
1348
+#define CSR15_DPST BIT(12)
1349
+#define CSR15_FRL BIT(13)
1350
+#define CSR15_LE2 BIT(14)
1351
+#define CSR15_LV2 BIT(15)
1352
+
1353
+#define RDES0_OF BIT(0)
1354
+#define RDES0_CE BIT(1)
1355
+#define RDES0_DB BIT(2)
1356
+#define RDES0_RJ BIT(4)
1357
+#define RDES0_FT BIT(5)
1358
+#define RDES0_CS BIT(6)
1359
+#define RDES0_TL BIT(7)
1360
+#define RDES0_LS BIT(8)
1361
+#define RDES0_FS BIT(9)
1362
+#define RDES0_MF BIT(10)
1363
+#define RDES0_RF BIT(11)
1364
+#define RDES0_DT_SHIFT 12
1365
+#define RDES0_DT_MASK 3
1366
+#define RDES0_LE BIT(14)
1367
+#define RDES0_ES BIT(15)
1368
+#define RDES0_FL_SHIFT 16
1369
+#define RDES0_FL_MASK 0x3fff
1370
+#define RDES0_FF BIT(30)
1371
+#define RDES0_OWN BIT(31)
1372
+
1373
+#define RDES1_BUF1_SIZE_SHIFT 0
1374
+#define RDES1_BUF1_SIZE_MASK 0x7ff
1375
+
1376
+#define RDES1_BUF2_SIZE_SHIFT 11
1377
+#define RDES1_BUF2_SIZE_MASK 0x7ff
1378
+#define RDES1_RCH BIT(24)
1379
+#define RDES1_RER BIT(25)
1380
+
1381
+#define TDES0_DE BIT(0)
1382
+#define TDES0_UF BIT(1)
1383
+#define TDES0_LF BIT(2)
1384
+#define TDES0_CC_SHIFT 3
1385
+#define TDES0_CC_MASK 0xf
1386
+#define TDES0_HF BIT(7)
1387
+#define TDES0_EC BIT(8)
1388
+#define TDES0_LC BIT(9)
1389
+#define TDES0_NC BIT(10)
1390
+#define TDES0_LO BIT(11)
1391
+#define TDES0_TO BIT(14)
1392
+#define TDES0_ES BIT(15)
1393
+#define TDES0_OWN BIT(31)
1394
+
1395
+#define TDES1_BUF1_SIZE_SHIFT 0
1396
+#define TDES1_BUF1_SIZE_MASK 0x7ff
1397
+
1398
+#define TDES1_BUF2_SIZE_SHIFT 11
1399
+#define TDES1_BUF2_SIZE_MASK 0x7ff
1400
+
1401
+#define TDES1_FT0 BIT(22)
1402
+#define TDES1_DPD BIT(23)
1403
+#define TDES1_TCH BIT(24)
1404
+#define TDES1_TER BIT(25)
1405
+#define TDES1_AC BIT(26)
1406
+#define TDES1_SET BIT(27)
1407
+#define TDES1_FT1 BIT(28)
1408
+#define TDES1_FS BIT(29)
1409
+#define TDES1_LS BIT(30)
1410
+#define TDES1_IC BIT(31)
1411
+
1412
+struct tulip_descriptor {
1413
+ uint32_t status;
1414
+ uint32_t control;
1415
+ uint32_t buf_addr1;
1416
+ uint32_t buf_addr2;
1417
+};
1418
+
1419
+#endif
1420
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
1421
index XXXXXXX..XXXXXXX 100644
1422
--- a/include/hw/pci/pci_ids.h
1423
+++ b/include/hw/pci/pci_ids.h
1424
@@ -XXX,XX +XXX,XX @@
1425
#define PCI_DEVICE_ID_LSI_SAS0079 0x0079
1426
1427
#define PCI_VENDOR_ID_DEC 0x1011
1428
+#define PCI_DEVICE_ID_DEC_21143 0x0019
1429
#define PCI_DEVICE_ID_DEC_21154 0x0026
1430
1431
#define PCI_VENDOR_ID_CIRRUS 0x1013
48
--
1432
--
49
2.7.4
1433
2.5.0
50
1434
51
1435
diff view generated by jsdifflib
1
From: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
1
From: "Michael S. Tsirkin" <mst@redhat.com>
2
2
3
Packet size some time different or when network is busy.
3
Post load hook in virtio vmsd is called early while device is processed,
4
Based on same payload size, but TCP protocol can not
4
and when VirtIODevice core isn't fully initialized. Most device
5
guarantee send the same one packet in the same way,
5
specific code isn't ready to deal with a device in such state, and
6
behaves weirdly.
6
7
7
like that:
8
Add a new post_load hook in a device class instead. Devices should use
8
We send this payload:
9
this unless they specifically want to verify the migration stream as
9
------------------------------
10
it's processed, e.g. for bounds checking.
10
| header |1|2|3|4|5|6|7|8|9|0|
11
------------------------------
12
11
13
primary:
12
Cc: qemu-stable@nongnu.org
14
ppkt1:
13
Suggested-by: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
15
----------------
14
Cc: Mikhail Sennikovsky <mikhail.sennikovskii@cloud.ionos.com>
16
| header |1|2|3|
15
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
17
----------------
18
ppkt2:
19
------------------------
20
| header |4|5|6|7|8|9|0|
21
------------------------
22
23
secondary:
24
spkt1:
25
------------------------------
26
| header |1|2|3|4|5|6|7|8|9|0|
27
------------------------------
28
29
In the original method, ppkt1 and ppkt2 are different in size and
30
spkt1, so they can't compare and trigger the checkpoint.
31
32
I have tested FTP get 200M and 1G file many times, I found that
33
the performance was less than 1% of the native.
34
35
Now I reconstructed the comparison of TCP packets based on the
36
TCP sequence number. first of all, ppkt1 and spkt1 have the same
37
starting sequence number, so they can compare, even though their
38
length is different. And then ppkt1 with a smaller payload length
39
is used as the comparison length, if the payload is same, send
40
out the ppkt1 and record the offset(the length of ppkt1 payload)
41
in spkt1. The next comparison, ppkt2 and spkt1 can be compared
42
from the recorded position of spkt1.
43
44
like that:
45
----------------
46
| header |1|2|3| ppkt1
47
---------|-----|
48
| |
49
---------v-----v--------------
50
| header |1|2|3|4|5|6|7|8|9|0| spkt1
51
---------------|\------------|
52
| \offset |
53
---------v-------------v
54
| header |4|5|6|7|8|9|0| ppkt2
55
------------------------
56
57
In this way, the performance can reach native 20% in my multiple
58
tests.
59
60
Cc: Zhang Chen <zhangckid@gmail.com>
61
Cc: Li Zhijian <lizhijian@cn.fujitsu.com>
62
Cc: Jason Wang <jasowang@redhat.com>
63
64
Signed-off-by: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
65
Signed-off-by: Li Zhijian <lizhijian@cn.fujitsu.com>
66
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
67
Reviewed-by: Zhang Chen <zhangckid@gmail.com>
68
Tested-by: Zhang Chen <zhangckid@gmail.com>
69
Signed-off-by: Jason Wang <jasowang@redhat.com>
16
Signed-off-by: Jason Wang <jasowang@redhat.com>
70
---
17
---
71
net/colo-compare.c | 343 +++++++++++++++++++++++++++++++++++------------------
18
hw/virtio/virtio.c | 7 +++++++
72
net/colo.c | 9 ++
19
include/hw/virtio/virtio.h | 6 ++++++
73
net/colo.h | 15 +++
20
2 files changed, 13 insertions(+)
74
net/trace-events | 2 +-
75
4 files changed, 250 insertions(+), 119 deletions(-)
76
21
77
diff --git a/net/colo-compare.c b/net/colo-compare.c
22
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
78
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
79
--- a/net/colo-compare.c
24
--- a/hw/virtio/virtio.c
80
+++ b/net/colo-compare.c
25
+++ b/hw/virtio/virtio.c
81
@@ -XXX,XX +XXX,XX @@
26
@@ -XXX,XX +XXX,XX @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
82
#define COMPARE_READ_LEN_MAX NET_BUFSIZE
83
#define MAX_QUEUE_SIZE 1024
84
85
+#define COLO_COMPARE_FREE_PRIMARY 0x01
86
+#define COLO_COMPARE_FREE_SECONDARY 0x02
87
+
88
/* TODO: Should be configurable */
89
#define REGULAR_PACKET_CHECK_MS 3000
90
91
@@ -XXX,XX +XXX,XX @@ static gint seq_sorter(Packet *a, Packet *b, gpointer data)
92
return ntohl(atcp->th_seq) - ntohl(btcp->th_seq);
93
}
94
95
+static void fill_pkt_tcp_info(void *data, uint32_t *max_ack)
96
+{
97
+ Packet *pkt = data;
98
+ struct tcphdr *tcphd;
99
+
100
+ tcphd = (struct tcphdr *)pkt->transport_header;
101
+
102
+ pkt->tcp_seq = ntohl(tcphd->th_seq);
103
+ pkt->tcp_ack = ntohl(tcphd->th_ack);
104
+ *max_ack = *max_ack > pkt->tcp_ack ? *max_ack : pkt->tcp_ack;
105
+ pkt->header_size = pkt->transport_header - (uint8_t *)pkt->data
106
+ + (tcphd->th_off << 2) - pkt->vnet_hdr_len;
107
+ pkt->payload_size = pkt->size - pkt->header_size;
108
+ pkt->seq_end = pkt->tcp_seq + pkt->payload_size;
109
+ pkt->flags = tcphd->th_flags;
110
+}
111
+
112
/*
113
* Return 1 on success, if return 0 means the
114
* packet will be dropped
115
*/
116
-static int colo_insert_packet(GQueue *queue, Packet *pkt)
117
+static int colo_insert_packet(GQueue *queue, Packet *pkt, uint32_t *max_ack)
118
{
119
if (g_queue_get_length(queue) <= MAX_QUEUE_SIZE) {
120
if (pkt->ip->ip_p == IPPROTO_TCP) {
121
+ fill_pkt_tcp_info(pkt, max_ack);
122
g_queue_insert_sorted(queue,
123
pkt,
124
(GCompareDataFunc)seq_sorter,
125
@@ -XXX,XX +XXX,XX @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
126
}
27
}
127
28
rcu_read_unlock();
128
if (mode == PRIMARY_IN) {
29
129
- if (!colo_insert_packet(&conn->primary_list, pkt)) {
30
+ if (vdc->post_load) {
130
+ if (!colo_insert_packet(&conn->primary_list, pkt, &conn->pack)) {
31
+ ret = vdc->post_load(vdev);
131
error_report("colo compare primary queue size too big,"
32
+ if (ret) {
132
"drop packet");
33
+ return ret;
133
}
134
} else {
135
- if (!colo_insert_packet(&conn->secondary_list, pkt)) {
136
+ if (!colo_insert_packet(&conn->secondary_list, pkt, &conn->sack)) {
137
error_report("colo compare secondary queue size too big,"
138
"drop packet");
139
}
140
@@ -XXX,XX +XXX,XX @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
141
return 0;
142
}
143
144
+static inline bool after(uint32_t seq1, uint32_t seq2)
145
+{
146
+ return (int32_t)(seq1 - seq2) > 0;
147
+}
148
+
149
+static void colo_release_primary_pkt(CompareState *s, Packet *pkt)
150
+{
151
+ int ret;
152
+ ret = compare_chr_send(s,
153
+ pkt->data,
154
+ pkt->size,
155
+ pkt->vnet_hdr_len);
156
+ if (ret < 0) {
157
+ error_report("colo send primary packet failed");
158
+ }
159
+ trace_colo_compare_main("packet same and release packet");
160
+ packet_destroy(pkt, NULL);
161
+}
162
+
163
/*
164
* The IP packets sent by primary and secondary
165
* will be compared in here
166
@@ -XXX,XX +XXX,XX @@ static int colo_compare_packet_payload(Packet *ppkt,
167
}
168
169
/*
170
- * Called from the compare thread on the primary
171
- * for compare tcp packet
172
- * compare_tcp copied from Dr. David Alan Gilbert's branch
173
- */
174
-static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt)
175
+ * return true means that the payload is consist and
176
+ * need to make the next comparison, false means do
177
+ * the checkpoint
178
+*/
179
+static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt,
180
+ int8_t *mark, uint32_t max_ack)
181
{
182
- struct tcphdr *ptcp, *stcp;
183
- int res;
184
+ *mark = 0;
185
+
186
+ if (ppkt->tcp_seq == spkt->tcp_seq && ppkt->seq_end == spkt->seq_end) {
187
+ if (colo_compare_packet_payload(ppkt, spkt,
188
+ ppkt->header_size, spkt->header_size,
189
+ ppkt->payload_size)) {
190
+ *mark = COLO_COMPARE_FREE_SECONDARY | COLO_COMPARE_FREE_PRIMARY;
191
+ return true;
192
+ }
193
+ }
194
+ if (ppkt->tcp_seq == spkt->tcp_seq && ppkt->seq_end == spkt->seq_end) {
195
+ if (colo_compare_packet_payload(ppkt, spkt,
196
+ ppkt->header_size, spkt->header_size,
197
+ ppkt->payload_size)) {
198
+ *mark = COLO_COMPARE_FREE_SECONDARY | COLO_COMPARE_FREE_PRIMARY;
199
+ return true;
200
+ }
34
+ }
201
+ }
35
+ }
202
+
36
+
203
+ /* one part of secondary packet payload still need to be compared */
37
return 0;
204
+ if (!after(ppkt->seq_end, spkt->seq_end)) {
205
+ if (colo_compare_packet_payload(ppkt, spkt,
206
+ ppkt->header_size + ppkt->offset,
207
+ spkt->header_size + spkt->offset,
208
+ ppkt->payload_size - ppkt->offset)) {
209
+ if (!after(ppkt->tcp_ack, max_ack)) {
210
+ *mark = COLO_COMPARE_FREE_PRIMARY;
211
+ spkt->offset += ppkt->payload_size - ppkt->offset;
212
+ return true;
213
+ } else {
214
+ /* secondary guest hasn't ack the data, don't send
215
+ * out this packet
216
+ */
217
+ return false;
218
+ }
219
+ }
220
+ } else {
221
+ /* primary packet is longer than secondary packet, compare
222
+ * the same part and mark the primary packet offset
223
+ */
224
+ if (colo_compare_packet_payload(ppkt, spkt,
225
+ ppkt->header_size + ppkt->offset,
226
+ spkt->header_size + spkt->offset,
227
+ spkt->payload_size - spkt->offset)) {
228
+ *mark = COLO_COMPARE_FREE_SECONDARY;
229
+ ppkt->offset += spkt->payload_size - spkt->offset;
230
+ return true;
231
+ }
232
+ }
233
234
- trace_colo_compare_main("compare tcp");
235
+ return false;
236
+}
237
238
- ptcp = (struct tcphdr *)ppkt->transport_header;
239
- stcp = (struct tcphdr *)spkt->transport_header;
240
+static void colo_compare_tcp(CompareState *s, Connection *conn)
241
+{
242
+ Packet *ppkt = NULL, *spkt = NULL;
243
+ int8_t mark;
244
245
/*
246
- * The 'identification' field in the IP header is *very* random
247
- * it almost never matches. Fudge this by ignoring differences in
248
- * unfragmented packets; they'll normally sort themselves out if different
249
- * anyway, and it should recover at the TCP level.
250
- * An alternative would be to get both the primary and secondary to rewrite
251
- * somehow; but that would need some sync traffic to sync the state
252
- */
253
- if (ntohs(ppkt->ip->ip_off) & IP_DF) {
254
- spkt->ip->ip_id = ppkt->ip->ip_id;
255
- /* and the sum will be different if the IDs were different */
256
- spkt->ip->ip_sum = ppkt->ip->ip_sum;
257
+ * If ppkt and spkt have the same payload, but ppkt's ACK
258
+ * is greater than spkt's ACK, in this case we can not
259
+ * send the ppkt because it will cause the secondary guest
260
+ * to miss sending some data in the next. Therefore, we
261
+ * record the maximum ACK in the current queue at both
262
+ * primary side and secondary side. Only when the ack is
263
+ * less than the smaller of the two maximum ack, then we
264
+ * can ensure that the packet's payload is acknowledged by
265
+ * primary and secondary.
266
+ */
267
+ uint32_t min_ack = conn->pack > conn->sack ? conn->sack : conn->pack;
268
+
269
+pri:
270
+ if (g_queue_is_empty(&conn->primary_list)) {
271
+ return;
272
}
273
+ ppkt = g_queue_pop_head(&conn->primary_list);
274
+sec:
275
+ if (g_queue_is_empty(&conn->secondary_list)) {
276
+ g_queue_push_head(&conn->primary_list, ppkt);
277
+ return;
278
+ }
279
+ spkt = g_queue_pop_head(&conn->secondary_list);
280
281
- /*
282
- * Check tcp header length for tcp option field.
283
- * th_off > 5 means this tcp packet have options field.
284
- * The tcp options maybe always different.
285
- * for example:
286
- * From RFC 7323.
287
- * TCP Timestamps option (TSopt):
288
- * Kind: 8
289
- *
290
- * Length: 10 bytes
291
- *
292
- * +-------+-------+---------------------+---------------------+
293
- * |Kind=8 | 10 | TS Value (TSval) |TS Echo Reply (TSecr)|
294
- * +-------+-------+---------------------+---------------------+
295
- * 1 1 4 4
296
- *
297
- * In this case the primary guest's timestamp always different with
298
- * the secondary guest's timestamp. COLO just focus on payload,
299
- * so we just need skip this field.
300
- */
301
+ if (ppkt->tcp_seq == ppkt->seq_end) {
302
+ colo_release_primary_pkt(s, ppkt);
303
+ ppkt = NULL;
304
+ }
305
306
- ptrdiff_t ptcp_offset, stcp_offset;
307
+ if (ppkt && conn->compare_seq && !after(ppkt->seq_end, conn->compare_seq)) {
308
+ trace_colo_compare_main("pri: this packet has compared");
309
+ colo_release_primary_pkt(s, ppkt);
310
+ ppkt = NULL;
311
+ }
312
313
- ptcp_offset = ppkt->transport_header - (uint8_t *)ppkt->data
314
- + (ptcp->th_off << 2) - ppkt->vnet_hdr_len;
315
- stcp_offset = spkt->transport_header - (uint8_t *)spkt->data
316
- + (stcp->th_off << 2) - spkt->vnet_hdr_len;
317
- if (ppkt->size - ptcp_offset == spkt->size - stcp_offset) {
318
- res = colo_compare_packet_payload(ppkt, spkt,
319
- ptcp_offset, stcp_offset,
320
- ppkt->size - ptcp_offset);
321
+ if (spkt->tcp_seq == spkt->seq_end) {
322
+ packet_destroy(spkt, NULL);
323
+ if (!ppkt) {
324
+ goto pri;
325
+ } else {
326
+ goto sec;
327
+ }
328
} else {
329
- trace_colo_compare_main("TCP: payload size of packets are different");
330
- res = -1;
331
+ if (conn->compare_seq && !after(spkt->seq_end, conn->compare_seq)) {
332
+ trace_colo_compare_main("sec: this packet has compared");
333
+ packet_destroy(spkt, NULL);
334
+ if (!ppkt) {
335
+ goto pri;
336
+ } else {
337
+ goto sec;
338
+ }
339
+ }
340
+ if (!ppkt) {
341
+ g_queue_push_head(&conn->secondary_list, spkt);
342
+ goto pri;
343
+ }
344
}
345
346
- if (res != 0 &&
347
- trace_event_get_state_backends(TRACE_COLO_COMPARE_MISCOMPARE)) {
348
- char pri_ip_src[20], pri_ip_dst[20], sec_ip_src[20], sec_ip_dst[20];
349
-
350
- strcpy(pri_ip_src, inet_ntoa(ppkt->ip->ip_src));
351
- strcpy(pri_ip_dst, inet_ntoa(ppkt->ip->ip_dst));
352
- strcpy(sec_ip_src, inet_ntoa(spkt->ip->ip_src));
353
- strcpy(sec_ip_dst, inet_ntoa(spkt->ip->ip_dst));
354
-
355
- trace_colo_compare_ip_info(ppkt->size, pri_ip_src,
356
- pri_ip_dst, spkt->size,
357
- sec_ip_src, sec_ip_dst);
358
-
359
- trace_colo_compare_tcp_info("pri tcp packet",
360
- ntohl(ptcp->th_seq),
361
- ntohl(ptcp->th_ack),
362
- res, ptcp->th_flags,
363
- ppkt->size);
364
-
365
- trace_colo_compare_tcp_info("sec tcp packet",
366
- ntohl(stcp->th_seq),
367
- ntohl(stcp->th_ack),
368
- res, stcp->th_flags,
369
- spkt->size);
370
+ if (colo_mark_tcp_pkt(ppkt, spkt, &mark, min_ack)) {
371
+ trace_colo_compare_tcp_info("pri",
372
+ ppkt->tcp_seq, ppkt->tcp_ack,
373
+ ppkt->header_size, ppkt->payload_size,
374
+ ppkt->offset, ppkt->flags);
375
+
376
+ trace_colo_compare_tcp_info("sec",
377
+ spkt->tcp_seq, spkt->tcp_ack,
378
+ spkt->header_size, spkt->payload_size,
379
+ spkt->offset, spkt->flags);
380
+
381
+ if (mark == COLO_COMPARE_FREE_PRIMARY) {
382
+ conn->compare_seq = ppkt->seq_end;
383
+ colo_release_primary_pkt(s, ppkt);
384
+ g_queue_push_head(&conn->secondary_list, spkt);
385
+ goto pri;
386
+ }
387
+ if (mark == COLO_COMPARE_FREE_SECONDARY) {
388
+ conn->compare_seq = spkt->seq_end;
389
+ packet_destroy(spkt, NULL);
390
+ goto sec;
391
+ }
392
+ if (mark == (COLO_COMPARE_FREE_PRIMARY | COLO_COMPARE_FREE_SECONDARY)) {
393
+ conn->compare_seq = ppkt->seq_end;
394
+ colo_release_primary_pkt(s, ppkt);
395
+ packet_destroy(spkt, NULL);
396
+ goto pri;
397
+ }
398
+ } else {
399
+ g_queue_push_head(&conn->primary_list, ppkt);
400
+ g_queue_push_head(&conn->secondary_list, spkt);
401
402
qemu_hexdump((char *)ppkt->data, stderr,
403
"colo-compare ppkt", ppkt->size);
404
qemu_hexdump((char *)spkt->data, stderr,
405
"colo-compare spkt", spkt->size);
406
- }
407
408
- return res;
409
+ /*
410
+ * colo_compare_inconsistent_notify();
411
+ * TODO: notice to checkpoint();
412
+ */
413
+ }
414
}
38
}
415
39
416
+
40
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
417
/*
418
* Called from the compare thread on the primary
419
* for compare udp packet
420
@@ -XXX,XX +XXX,XX @@ static void colo_old_packet_check(void *opaque)
421
(GCompareFunc)colo_old_packet_check_one_conn);
422
}
423
424
-/*
425
- * Called from the compare thread on the primary
426
- * for compare packet with secondary list of the
427
- * specified connection when a new packet was
428
- * queued to it.
429
- */
430
-static void colo_compare_connection(void *opaque, void *user_data)
431
+static void colo_compare_packet(CompareState *s, Connection *conn,
432
+ int (*HandlePacket)(Packet *spkt,
433
+ Packet *ppkt))
434
{
435
- CompareState *s = user_data;
436
- Connection *conn = opaque;
437
Packet *pkt = NULL;
438
GList *result = NULL;
439
- int ret;
440
441
while (!g_queue_is_empty(&conn->primary_list) &&
442
!g_queue_is_empty(&conn->secondary_list)) {
443
pkt = g_queue_pop_head(&conn->primary_list);
444
- switch (conn->ip_proto) {
445
- case IPPROTO_TCP:
446
- result = g_queue_find_custom(&conn->secondary_list,
447
- pkt, (GCompareFunc)colo_packet_compare_tcp);
448
- break;
449
- case IPPROTO_UDP:
450
- result = g_queue_find_custom(&conn->secondary_list,
451
- pkt, (GCompareFunc)colo_packet_compare_udp);
452
- break;
453
- case IPPROTO_ICMP:
454
- result = g_queue_find_custom(&conn->secondary_list,
455
- pkt, (GCompareFunc)colo_packet_compare_icmp);
456
- break;
457
- default:
458
- result = g_queue_find_custom(&conn->secondary_list,
459
- pkt, (GCompareFunc)colo_packet_compare_other);
460
- break;
461
- }
462
+ result = g_queue_find_custom(&conn->secondary_list,
463
+ pkt, (GCompareFunc)HandlePacket);
464
465
if (result) {
466
- ret = compare_chr_send(s,
467
- pkt->data,
468
- pkt->size,
469
- pkt->vnet_hdr_len);
470
- if (ret < 0) {
471
- error_report("colo_send_primary_packet failed");
472
- }
473
- trace_colo_compare_main("packet same and release packet");
474
+ colo_release_primary_pkt(s, pkt);
475
g_queue_remove(&conn->secondary_list, result->data);
476
- packet_destroy(pkt, NULL);
477
} else {
478
/*
479
* If one packet arrive late, the secondary_list or
480
@@ -XXX,XX +XXX,XX @@ static void colo_compare_connection(void *opaque, void *user_data)
481
}
482
}
483
484
+/*
485
+ * Called from the compare thread on the primary
486
+ * for compare packet with secondary list of the
487
+ * specified connection when a new packet was
488
+ * queued to it.
489
+ */
490
+static void colo_compare_connection(void *opaque, void *user_data)
491
+{
492
+ CompareState *s = user_data;
493
+ Connection *conn = opaque;
494
+
495
+ switch (conn->ip_proto) {
496
+ case IPPROTO_TCP:
497
+ colo_compare_tcp(s, conn);
498
+ break;
499
+ case IPPROTO_UDP:
500
+ colo_compare_packet(s, conn, colo_packet_compare_udp);
501
+ break;
502
+ case IPPROTO_ICMP:
503
+ colo_compare_packet(s, conn, colo_packet_compare_icmp);
504
+ break;
505
+ default:
506
+ colo_compare_packet(s, conn, colo_packet_compare_other);
507
+ break;
508
+ }
509
+}
510
+
511
static int compare_chr_send(CompareState *s,
512
const uint8_t *buf,
513
uint32_t size,
514
diff --git a/net/colo.c b/net/colo.c
515
index XXXXXXX..XXXXXXX 100644
41
index XXXXXXX..XXXXXXX 100644
516
--- a/net/colo.c
42
--- a/include/hw/virtio/virtio.h
517
+++ b/net/colo.c
43
+++ b/include/hw/virtio/virtio.h
518
@@ -XXX,XX +XXX,XX @@ Connection *connection_new(ConnectionKey *key)
44
@@ -XXX,XX +XXX,XX @@ typedef struct VirtioDeviceClass {
519
conn->processing = false;
45
*/
520
conn->offset = 0;
46
void (*save)(VirtIODevice *vdev, QEMUFile *f);
521
conn->syn_flag = 0;
47
int (*load)(VirtIODevice *vdev, QEMUFile *f, int version_id);
522
+ conn->pack = 0;
48
+ /* Post load hook in vmsd is called early while device is processed, and
523
+ conn->sack = 0;
49
+ * when VirtIODevice isn't fully initialized. Devices should use this instead,
524
g_queue_init(&conn->primary_list);
50
+ * unless they specifically want to verify the migration stream as it's
525
g_queue_init(&conn->secondary_list);
51
+ * processed, e.g. for bounds checking.
526
52
+ */
527
@@ -XXX,XX +XXX,XX @@ Packet *packet_new(const void *data, int size, int vnet_hdr_len)
53
+ int (*post_load)(VirtIODevice *vdev);
528
pkt->size = size;
54
const VMStateDescription *vmsd;
529
pkt->creation_ms = qemu_clock_get_ms(QEMU_CLOCK_HOST);
55
} VirtioDeviceClass;
530
pkt->vnet_hdr_len = vnet_hdr_len;
56
531
+ pkt->tcp_seq = 0;
532
+ pkt->tcp_ack = 0;
533
+ pkt->seq_end = 0;
534
+ pkt->header_size = 0;
535
+ pkt->payload_size = 0;
536
+ pkt->offset = 0;
537
+ pkt->flags = 0;
538
539
return pkt;
540
}
541
diff --git a/net/colo.h b/net/colo.h
542
index XXXXXXX..XXXXXXX 100644
543
--- a/net/colo.h
544
+++ b/net/colo.h
545
@@ -XXX,XX +XXX,XX @@ typedef struct Packet {
546
int64_t creation_ms;
547
/* Get vnet_hdr_len from filter */
548
uint32_t vnet_hdr_len;
549
+ uint32_t tcp_seq; /* sequence number */
550
+ uint32_t tcp_ack; /* acknowledgement number */
551
+ /* the sequence number of the last byte of the packet */
552
+ uint32_t seq_end;
553
+ uint8_t header_size; /* the header length */
554
+ uint16_t payload_size; /* the payload length */
555
+ /* record the payload offset(the length that has been compared) */
556
+ uint16_t offset;
557
+ uint8_t flags; /* Flags(aka Control bits) */
558
} Packet;
559
560
typedef struct ConnectionKey {
561
@@ -XXX,XX +XXX,XX @@ typedef struct Connection {
562
/* flag to enqueue unprocessed_connections */
563
bool processing;
564
uint8_t ip_proto;
565
+ /* record the sequence number that has been compared */
566
+ uint32_t compare_seq;
567
+ /* the maximum of acknowledgement number in primary_list queue */
568
+ uint32_t pack;
569
+ /* the maximum of acknowledgement number in secondary_list queue */
570
+ uint32_t sack;
571
/* offset = secondary_seq - primary_seq */
572
tcp_seq offset;
573
/*
574
diff --git a/net/trace-events b/net/trace-events
575
index XXXXXXX..XXXXXXX 100644
576
--- a/net/trace-events
577
+++ b/net/trace-events
578
@@ -XXX,XX +XXX,XX @@ colo_compare_icmp_miscompare(const char *sta, int size) ": %s = %d"
579
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"
580
colo_old_packet_check_found(int64_t old_time) "%" PRId64
581
colo_compare_miscompare(void) ""
582
-colo_compare_tcp_info(const char *pkt, uint32_t seq, uint32_t ack, int res, uint32_t flag, int size) "side: %s seq/ack= %u/%u res= %d flags= 0x%x pkt_size: %d\n"
583
+colo_compare_tcp_info(const char *pkt, uint32_t seq, uint32_t ack, int hdlen, int pdlen, int offset, int flags) "%s: seq/ack= %u/%u hdlen= %d pdlen= %d offset= %d flags=%d\n"
584
585
# net/filter-rewriter.c
586
colo_filter_rewriter_debug(void) ""
587
--
57
--
588
2.7.4
58
2.5.0
589
59
590
60
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Mikhail Sennikovsky <mikhail.sennikovskii@cloud.ionos.com>
2
2
3
QEMU can emulate hubs to connect NICs and netdevs. This is currently
3
Currently offloads disabled by guest via the VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET
4
primarily used for the mis-named 'vlan' feature of the networking
4
command are not preserved on VM migration.
5
subsystem. Now the 'vlan' feature has been marked as deprecated, since
5
Instead all offloads reported by guest features (via VIRTIO_PCI_GUEST_FEATURES)
6
its name is rather confusing and the users often rather mis-configure
6
get enabled.
7
their network when trying to use it. But while the 'vlan' parameter
7
What happens is: first the VirtIONet::curr_guest_offloads gets restored and offloads
8
should be removed at one point in time, the basic idea of emulating
8
are getting set correctly:
9
a hub in QEMU is still good: It's useful for bundling up the output of
10
multiple NICs into one single l2tp netdev for example.
11
9
12
Now to be able to use the hubport feature without 'vlan's, there is one
10
#0 qemu_set_offload (nc=0x555556a11400, csum=1, tso4=0, tso6=0, ecn=0, ufo=0) at net/net.c:474
13
missing piece: The possibility to connect a hubport to a netdev, too.
11
#1 virtio_net_apply_guest_offloads (n=0x555557701ca0) at hw/net/virtio-net.c:720
14
This patch adds this possibility by introducing a new "netdev=..."
12
#2 virtio_net_post_load_device (opaque=0x555557701ca0, version_id=11) at hw/net/virtio-net.c:2334
15
parameter to the hubports.
13
#3 vmstate_load_state (f=0x5555569dc010, vmsd=0x555556577c80 <vmstate_virtio_net_device>, opaque=0x555557701ca0, version_id=11)
14
at migration/vmstate.c:168
15
#4 virtio_load (vdev=0x555557701ca0, f=0x5555569dc010, version_id=11) at hw/virtio/virtio.c:2197
16
#5 virtio_device_get (f=0x5555569dc010, opaque=0x555557701ca0, size=0, field=0x55555668cd00 <__compound_literal.5>) at hw/virtio/virtio.c:2036
17
#6 vmstate_load_state (f=0x5555569dc010, vmsd=0x555556577ce0 <vmstate_virtio_net>, opaque=0x555557701ca0, version_id=11) at migration/vmstate.c:143
18
#7 vmstate_load (f=0x5555569dc010, se=0x5555578189e0) at migration/savevm.c:829
19
#8 qemu_loadvm_section_start_full (f=0x5555569dc010, mis=0x5555569eee20) at migration/savevm.c:2211
20
#9 qemu_loadvm_state_main (f=0x5555569dc010, mis=0x5555569eee20) at migration/savevm.c:2395
21
#10 qemu_loadvm_state (f=0x5555569dc010) at migration/savevm.c:2467
22
#11 process_incoming_migration_co (opaque=0x0) at migration/migration.c:449
16
23
17
To bundle up the output of multiple NICs into one socket netdev, you can
24
However later on the features are getting restored, and offloads get reset to
18
now run QEMU with these parameters for example:
25
everything supported by features:
19
26
20
qemu-system-ppc64 ... -netdev socket,id=s1,connect=:11122 \
27
#0 qemu_set_offload (nc=0x555556a11400, csum=1, tso4=1, tso6=1, ecn=0, ufo=0) at net/net.c:474
21
-netdev hubport,hubid=1,id=h1,netdev=s1 \
28
#1 virtio_net_apply_guest_offloads (n=0x555557701ca0) at hw/net/virtio-net.c:720
22
-netdev hubport,hubid=1,id=h2 -device e1000,netdev=h2 \
29
#2 virtio_net_set_features (vdev=0x555557701ca0, features=5104441767) at hw/net/virtio-net.c:773
23
-netdev hubport,hubid=1,id=h3 -device virtio-net-pci,netdev=h3
30
#3 virtio_set_features_nocheck (vdev=0x555557701ca0, val=5104441767) at hw/virtio/virtio.c:2052
31
#4 virtio_load (vdev=0x555557701ca0, f=0x5555569dc010, version_id=11) at hw/virtio/virtio.c:2220
32
#5 virtio_device_get (f=0x5555569dc010, opaque=0x555557701ca0, size=0, field=0x55555668cd00 <__compound_literal.5>) at hw/virtio/virtio.c:2036
33
#6 vmstate_load_state (f=0x5555569dc010, vmsd=0x555556577ce0 <vmstate_virtio_net>, opaque=0x555557701ca0, version_id=11) at migration/vmstate.c:143
34
#7 vmstate_load (f=0x5555569dc010, se=0x5555578189e0) at migration/savevm.c:829
35
#8 qemu_loadvm_section_start_full (f=0x5555569dc010, mis=0x5555569eee20) at migration/savevm.c:2211
36
#9 qemu_loadvm_state_main (f=0x5555569dc010, mis=0x5555569eee20) at migration/savevm.c:2395
37
#10 qemu_loadvm_state (f=0x5555569dc010) at migration/savevm.c:2467
38
#11 process_incoming_migration_co (opaque=0x0) at migration/migration.c:449
24
39
25
For using the socket netdev, you have got to start another QEMU as the
40
Fix this by preserving the state in saved_guest_offloads field and
26
receiving side first, for example with network dumping enabled:
41
pushing out offload initialization to the new post load hook.
27
42
28
qemu-system-x86_64 -M isapc -netdev socket,id=s0,listen=:11122 \
43
Cc: qemu-stable@nongnu.org
29
-device ne2k_isa,netdev=s0 \
44
Signed-off-by: Mikhail Sennikovsky <mikhail.sennikovskii@cloud.ionos.com>
30
-object filter-dump,id=f1,netdev=s0,file=/tmp/dump.dat
31
32
After the ppc64 guest tried to boot from both NICs, you can see in the
33
dump file (using Wireshark, for example), that the output of both NICs
34
(the e1000 and the virtio-net-pci) has been successfully transfered
35
via the socket netdev in this case.
36
37
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
38
Signed-off-by: Thomas Huth <thuth@redhat.com>
39
Signed-off-by: Jason Wang <jasowang@redhat.com>
45
Signed-off-by: Jason Wang <jasowang@redhat.com>
40
---
46
---
41
net/hub.c | 27 +++++++++++++++++++++------
47
hw/net/virtio-net.c | 27 ++++++++++++++++++++++++---
42
net/hub.h | 3 ++-
48
include/hw/virtio/virtio-net.h | 2 ++
43
net/net.c | 2 +-
49
2 files changed, 26 insertions(+), 3 deletions(-)
44
qapi/net.json | 4 +++-
45
qemu-options.hx | 8 +++++---
46
5 files changed, 32 insertions(+), 12 deletions(-)
47
50
48
diff --git a/net/hub.c b/net/hub.c
51
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
49
index XXXXXXX..XXXXXXX 100644
52
index XXXXXXX..XXXXXXX 100644
50
--- a/net/hub.c
53
--- a/hw/net/virtio-net.c
51
+++ b/net/hub.c
54
+++ b/hw/net/virtio-net.c
52
@@ -XXX,XX +XXX,XX @@
55
@@ -XXX,XX +XXX,XX @@ static int virtio_net_post_load_device(void *opaque, int version_id)
53
*/
56
n->curr_guest_offloads = virtio_net_supported_guest_offloads(n);
54
55
#include "qemu/osdep.h"
56
+#include "qapi/error.h"
57
#include "monitor/monitor.h"
58
#include "net/net.h"
59
#include "clients.h"
60
@@ -XXX,XX +XXX,XX @@ static NetClientInfo net_hub_port_info = {
61
.cleanup = net_hub_port_cleanup,
62
};
63
64
-static NetHubPort *net_hub_port_new(NetHub *hub, const char *name)
65
+static NetHubPort *net_hub_port_new(NetHub *hub, const char *name,
66
+ NetClientState *hubpeer)
67
{
68
NetClientState *nc;
69
NetHubPort *port;
70
@@ -XXX,XX +XXX,XX @@ static NetHubPort *net_hub_port_new(NetHub *hub, const char *name)
71
name = default_name;
72
}
57
}
73
58
74
- nc = qemu_new_net_client(&net_hub_port_info, NULL, "hub", name);
59
- if (peer_has_vnet_hdr(n)) {
75
+ nc = qemu_new_net_client(&net_hub_port_info, hubpeer, "hub", name);
60
- virtio_net_apply_guest_offloads(n);
76
port = DO_UPCAST(NetHubPort, nc, nc);
61
- }
77
port->id = id;
62
+ /*
78
port->hub = hub;
63
+ * curr_guest_offloads will be later overwritten by the
79
@@ -XXX,XX +XXX,XX @@ static NetHubPort *net_hub_port_new(NetHub *hub, const char *name)
64
+ * virtio_set_features_nocheck call done from the virtio_load.
80
65
+ * Here we make sure it is preserved and restored accordingly
81
/**
66
+ * in the virtio_net_post_load_virtio callback.
82
* Create a port on a given hub
67
+ */
83
+ * @hub_id: Number of the hub
68
+ n->saved_guest_offloads = n->curr_guest_offloads;
84
* @name: Net client name or NULL for default name.
69
85
+ * @hubpeer: Peer to use (if "netdev=id" has been specified)
70
virtio_net_set_queues(n);
86
*
71
87
* If there is no existing hub with the given id then a new hub is created.
72
@@ -XXX,XX +XXX,XX @@ static int virtio_net_post_load_device(void *opaque, int version_id)
88
*/
73
return 0;
89
-NetClientState *net_hub_add_port(int hub_id, const char *name)
90
+NetClientState *net_hub_add_port(int hub_id, const char *name,
91
+ NetClientState *hubpeer)
92
{
93
NetHub *hub;
94
NetHubPort *port;
95
@@ -XXX,XX +XXX,XX @@ NetClientState *net_hub_add_port(int hub_id, const char *name)
96
hub = net_hub_new(hub_id);
97
}
98
99
- port = net_hub_port_new(hub, name);
100
+ port = net_hub_port_new(hub, name, hubpeer);
101
return &port->nc;
102
}
74
}
103
75
104
@@ -XXX,XX +XXX,XX @@ NetClientState *net_hub_port_find(int hub_id)
76
+static int virtio_net_post_load_virtio(VirtIODevice *vdev)
105
}
77
+{
106
}
78
+ VirtIONet *n = VIRTIO_NET(vdev);
107
79
+ /*
108
- nc = net_hub_add_port(hub_id, NULL);
80
+ * The actual needed state is now in saved_guest_offloads,
109
+ nc = net_hub_add_port(hub_id, NULL, NULL);
81
+ * see virtio_net_post_load_device for detail.
110
return nc;
82
+ * Restore it back and apply the desired offloads.
111
}
83
+ */
112
84
+ n->curr_guest_offloads = n->saved_guest_offloads;
113
@@ -XXX,XX +XXX,XX @@ int net_init_hubport(const Netdev *netdev, const char *name,
85
+ if (peer_has_vnet_hdr(n)) {
114
NetClientState *peer, Error **errp)
86
+ virtio_net_apply_guest_offloads(n);
115
{
116
const NetdevHubPortOptions *hubport;
117
+ NetClientState *hubpeer = NULL;
118
119
assert(netdev->type == NET_CLIENT_DRIVER_HUBPORT);
120
assert(!peer);
121
hubport = &netdev->u.hubport;
122
123
- net_hub_add_port(hubport->hubid, name);
124
+ if (hubport->has_netdev) {
125
+ hubpeer = qemu_find_netdev(hubport->netdev);
126
+ if (!hubpeer) {
127
+ error_setg(errp, "netdev '%s' not found", hubport->netdev);
128
+ return -1;
129
+ }
130
+ }
87
+ }
131
+
88
+
132
+ net_hub_add_port(hubport->hubid, name, hubpeer);
89
+ return 0;
90
+}
133
+
91
+
134
return 0;
92
/* tx_waiting field of a VirtIONetQueue */
93
static const VMStateDescription vmstate_virtio_net_queue_tx_waiting = {
94
.name = "virtio-net-queue-tx_waiting",
95
@@ -XXX,XX +XXX,XX @@ static void virtio_net_class_init(ObjectClass *klass, void *data)
96
vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
97
vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;
98
vdc->legacy_features |= (0x1 << VIRTIO_NET_F_GSO);
99
+ vdc->post_load = virtio_net_post_load_virtio;
100
vdc->vmsd = &vmstate_virtio_net_device;
135
}
101
}
136
102
137
diff --git a/net/hub.h b/net/hub.h
103
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
138
index XXXXXXX..XXXXXXX 100644
104
index XXXXXXX..XXXXXXX 100644
139
--- a/net/hub.h
105
--- a/include/hw/virtio/virtio-net.h
140
+++ b/net/hub.h
106
+++ b/include/hw/virtio/virtio-net.h
141
@@ -XXX,XX +XXX,XX @@
107
@@ -XXX,XX +XXX,XX @@ struct VirtIONet {
142
108
char *netclient_name;
143
#include "qemu-common.h"
109
char *netclient_type;
144
110
uint64_t curr_guest_offloads;
145
-NetClientState *net_hub_add_port(int hub_id, const char *name);
111
+ /* used on saved state restore phase to preserve the curr_guest_offloads */
146
+NetClientState *net_hub_add_port(int hub_id, const char *name,
112
+ uint64_t saved_guest_offloads;
147
+ NetClientState *hubpeer);
113
AnnounceTimer announce_timer;
148
NetClientState *net_hub_find_client_by_name(int hub_id, const char *name);
114
bool needs_vnet_hdr_swap;
149
void net_hub_info(Monitor *mon);
115
bool mtu_bypass_backend;
150
void net_hub_check_clients(void);
151
diff --git a/net/net.c b/net/net.c
152
index XXXXXXX..XXXXXXX 100644
153
--- a/net/net.c
154
+++ b/net/net.c
155
@@ -XXX,XX +XXX,XX @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
156
/* Do not add to a vlan if it's a nic with a netdev= parameter. */
157
if (netdev->type != NET_CLIENT_DRIVER_NIC ||
158
!opts->u.nic.has_netdev) {
159
- peer = net_hub_add_port(net->has_vlan ? net->vlan : 0, NULL);
160
+ peer = net_hub_add_port(net->has_vlan ? net->vlan : 0, NULL, NULL);
161
}
162
163
if (net->has_vlan && !vlan_warned) {
164
diff --git a/qapi/net.json b/qapi/net.json
165
index XXXXXXX..XXXXXXX 100644
166
--- a/qapi/net.json
167
+++ b/qapi/net.json
168
@@ -XXX,XX +XXX,XX @@
169
# Connect two or more net clients through a software hub.
170
#
171
# @hubid: hub identifier number
172
+# @netdev: used to connect hub to a netdev instead of a device (since 2.12)
173
#
174
# Since: 1.2
175
##
176
{ 'struct': 'NetdevHubPortOptions',
177
'data': {
178
- 'hubid': 'int32' } }
179
+ 'hubid': 'int32',
180
+ '*netdev': 'str' } }
181
182
##
183
# @NetdevNetmapOptions:
184
diff --git a/qemu-options.hx b/qemu-options.hx
185
index XXXXXXX..XXXXXXX 100644
186
--- a/qemu-options.hx
187
+++ b/qemu-options.hx
188
@@ -XXX,XX +XXX,XX @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
189
#endif
190
"-netdev vhost-user,id=str,chardev=dev[,vhostforce=on|off]\n"
191
" configure a vhost-user network, backed by a chardev 'dev'\n"
192
- "-netdev hubport,id=str,hubid=n\n"
193
+ "-netdev hubport,id=str,hubid=n[,netdev=nd]\n"
194
" configure a hub port on QEMU VLAN 'n'\n", QEMU_ARCH_ALL)
195
DEF("net", HAS_ARG, QEMU_OPTION_net,
196
"-net nic[,vlan=n][,netdev=nd][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n"
197
@@ -XXX,XX +XXX,XX @@ vde_switch -F -sock /tmp/myswitch
198
qemu-system-i386 linux.img -net nic -net vde,sock=/tmp/myswitch
199
@end example
200
201
-@item -netdev hubport,id=@var{id},hubid=@var{hubid}
202
+@item -netdev hubport,id=@var{id},hubid=@var{hubid}[,netdev=@var{nd}]
203
204
Create a hub port on QEMU "vlan" @var{hubid}.
205
206
The hubport netdev lets you connect a NIC to a QEMU "vlan" instead of a single
207
netdev. @code{-net} and @code{-device} with parameter @option{vlan} create the
208
-required hub automatically.
209
+required hub automatically. Alternatively, you can also connect the hubport
210
+to another netdev with ID @var{nd} by using the @option{netdev=@var{nd}}
211
+option.
212
213
@item -netdev vhost-user,chardev=@var{id}[,vhostforce=on|off][,queues=n]
214
215
--
116
--
216
2.7.4
117
2.5.0
217
118
218
119
diff view generated by jsdifflib
1
From: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
1
From: Fan Yang <Fan_Yang@sjtu.edu.cn>
2
2
3
Modified the function colo_packet_compare_common to prepare for the
3
'colo_mark_tcp_pkt' should return 'true' when packets are the same, and
4
tcp packet comparison in the next patch.
4
'false' otherwise. However, it returns 'true' when
5
'colo_compare_packet_payload' returns non-zero while
6
'colo_compare_packet_payload' is just a 'memcmp'. The result is that
7
COLO-compare reports inconsistent TCP packets when they are actually
8
the same.
5
9
6
Cc: Zhang Chen <zhangckid@gmail.com>
10
Fixes: f449c9e549c ("colo: compare the packet based on the tcp sequence number")
7
Cc: Li Zhijian <lizhijian@cn.fujitsu.com>
11
Cc: qemu-stable@nongnu.org
8
Cc: Jason Wang <jasowang@redhat.com>
12
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
9
13
Signed-off-by: Fan Yang <Fan_Yang@sjtu.edu.cn>
10
Signed-off-by: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
11
Signed-off-by: Li Zhijian <lizhijian@cn.fujitsu.com>
12
Signed-off-by: Zhang Chen <zhangckid@gmail.com>
13
Reviewed-by: Zhang Chen <zhangckid@gmail.com>
14
Signed-off-by: Jason Wang <jasowang@redhat.com>
14
Signed-off-by: Jason Wang <jasowang@redhat.com>
15
---
15
---
16
net/colo-compare.c | 88 +++++++++++++++++++++++++++---------------------------
16
net/colo-compare.c | 6 +++---
17
1 file changed, 44 insertions(+), 44 deletions(-)
17
1 file changed, 3 insertions(+), 3 deletions(-)
18
18
19
diff --git a/net/colo-compare.c b/net/colo-compare.c
19
diff --git a/net/colo-compare.c b/net/colo-compare.c
20
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
21
--- a/net/colo-compare.c
21
--- a/net/colo-compare.c
22
+++ b/net/colo-compare.c
22
+++ b/net/colo-compare.c
23
@@ -XXX,XX +XXX,XX @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
23
@@ -XXX,XX +XXX,XX @@ static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt,
24
* return: 0 means packet same
24
*mark = 0;
25
* > 0 || < 0 means packet different
25
26
*/
26
if (ppkt->tcp_seq == spkt->tcp_seq && ppkt->seq_end == spkt->seq_end) {
27
-static int colo_packet_compare_common(Packet *ppkt,
27
- if (colo_compare_packet_payload(ppkt, spkt,
28
- Packet *spkt,
28
+ if (!colo_compare_packet_payload(ppkt, spkt,
29
- int poffset,
29
ppkt->header_size, spkt->header_size,
30
- int soffset)
30
ppkt->payload_size)) {
31
+static int colo_compare_packet_payload(Packet *ppkt,
31
*mark = COLO_COMPARE_FREE_SECONDARY | COLO_COMPARE_FREE_PRIMARY;
32
+ Packet *spkt,
32
@@ -XXX,XX +XXX,XX @@ static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt,
33
+ uint16_t poffset,
33
34
+ uint16_t soffset,
34
/* one part of secondary packet payload still need to be compared */
35
+ uint16_t len)
35
if (!after(ppkt->seq_end, spkt->seq_end)) {
36
+
36
- if (colo_compare_packet_payload(ppkt, spkt,
37
{
37
+ if (!colo_compare_packet_payload(ppkt, spkt,
38
if (trace_event_get_state_backends(TRACE_COLO_COMPARE_MISCOMPARE)) {
38
ppkt->header_size + ppkt->offset,
39
char pri_ip_src[20], pri_ip_dst[20], sec_ip_src[20], sec_ip_dst[20];
39
spkt->header_size + spkt->offset,
40
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_common(Packet *ppkt,
40
ppkt->payload_size - ppkt->offset)) {
41
sec_ip_src, sec_ip_dst);
41
@@ -XXX,XX +XXX,XX @@ static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt,
42
}
42
/* primary packet is longer than secondary packet, compare
43
43
* the same part and mark the primary packet offset
44
- poffset = ppkt->vnet_hdr_len + poffset;
44
*/
45
- soffset = ppkt->vnet_hdr_len + soffset;
45
- if (colo_compare_packet_payload(ppkt, spkt,
46
-
46
+ if (!colo_compare_packet_payload(ppkt, spkt,
47
- if (ppkt->size - poffset == spkt->size - soffset) {
47
ppkt->header_size + ppkt->offset,
48
- return memcmp(ppkt->data + poffset,
48
spkt->header_size + spkt->offset,
49
- spkt->data + soffset,
49
spkt->payload_size - spkt->offset)) {
50
- spkt->size - soffset);
51
- } else {
52
- trace_colo_compare_main("Net packet size are not the same");
53
- return -1;
54
- }
55
+ return memcmp(ppkt->data + poffset, spkt->data + soffset, len);
56
}
57
58
/*
59
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt)
60
* the secondary guest's timestamp. COLO just focus on payload,
61
* so we just need skip this field.
62
*/
63
- if (ptcp->th_off > 5) {
64
- ptrdiff_t ptcp_offset, stcp_offset;
65
66
- ptcp_offset = ppkt->transport_header - (uint8_t *)ppkt->data
67
- + (ptcp->th_off * 4) - ppkt->vnet_hdr_len;
68
- stcp_offset = spkt->transport_header - (uint8_t *)spkt->data
69
- + (stcp->th_off * 4) - spkt->vnet_hdr_len;
70
+ ptrdiff_t ptcp_offset, stcp_offset;
71
72
- /*
73
- * When network is busy, some tcp options(like sack) will unpredictable
74
- * occur in primary side or secondary side. it will make packet size
75
- * not same, but the two packet's payload is identical. colo just
76
- * care about packet payload, so we skip the option field.
77
- */
78
- res = colo_packet_compare_common(ppkt, spkt, ptcp_offset, stcp_offset);
79
- } else if (ptcp->th_sum == stcp->th_sum) {
80
- res = colo_packet_compare_common(ppkt, spkt, ETH_HLEN, ETH_HLEN);
81
+ ptcp_offset = ppkt->transport_header - (uint8_t *)ppkt->data
82
+ + (ptcp->th_off << 2) - ppkt->vnet_hdr_len;
83
+ stcp_offset = spkt->transport_header - (uint8_t *)spkt->data
84
+ + (stcp->th_off << 2) - spkt->vnet_hdr_len;
85
+ if (ppkt->size - ptcp_offset == spkt->size - stcp_offset) {
86
+ res = colo_compare_packet_payload(ppkt, spkt,
87
+ ptcp_offset, stcp_offset,
88
+ ppkt->size - ptcp_offset);
89
} else {
90
+ trace_colo_compare_main("TCP: payload size of packets are different");
91
res = -1;
92
}
93
94
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt)
95
*/
96
static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
97
{
98
- int ret;
99
- int network_header_length = ppkt->ip->ip_hl * 4;
100
+ uint16_t network_header_length = ppkt->ip->ip_hl << 2;
101
+ uint16_t offset = network_header_length + ETH_HLEN + ppkt->vnet_hdr_len;
102
103
trace_colo_compare_main("compare udp");
104
105
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
106
* other field like TOS,TTL,IP Checksum. we only need to compare
107
* the ip payload here.
108
*/
109
- ret = colo_packet_compare_common(ppkt, spkt,
110
- network_header_length + ETH_HLEN,
111
- network_header_length + ETH_HLEN);
112
-
113
- if (ret) {
114
+ if (ppkt->size != spkt->size) {
115
+ trace_colo_compare_main("UDP: payload size of packets are different");
116
+ return -1;
117
+ }
118
+ if (colo_compare_packet_payload(ppkt, spkt, offset, offset,
119
+ ppkt->size - offset)) {
120
trace_colo_compare_udp_miscompare("primary pkt size", ppkt->size);
121
trace_colo_compare_udp_miscompare("Secondary pkt size", spkt->size);
122
if (trace_event_get_state_backends(TRACE_COLO_COMPARE_MISCOMPARE)) {
123
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
124
qemu_hexdump((char *)spkt->data, stderr, "colo-compare sec pkt",
125
spkt->size);
126
}
127
+ return -1;
128
+ } else {
129
+ return 0;
130
}
131
-
132
- return ret;
133
}
134
135
/*
136
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
137
*/
138
static int colo_packet_compare_icmp(Packet *spkt, Packet *ppkt)
139
{
140
- int network_header_length = ppkt->ip->ip_hl * 4;
141
+ uint16_t network_header_length = ppkt->ip->ip_hl << 2;
142
+ uint16_t offset = network_header_length + ETH_HLEN + ppkt->vnet_hdr_len;
143
144
trace_colo_compare_main("compare icmp");
145
146
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_icmp(Packet *spkt, Packet *ppkt)
147
* other field like TOS,TTL,IP Checksum. we only need to compare
148
* the ip payload here.
149
*/
150
- if (colo_packet_compare_common(ppkt, spkt,
151
- network_header_length + ETH_HLEN,
152
- network_header_length + ETH_HLEN)) {
153
+ if (ppkt->size != spkt->size) {
154
+ trace_colo_compare_main("ICMP: payload size of packets are different");
155
+ return -1;
156
+ }
157
+ if (colo_compare_packet_payload(ppkt, spkt, offset, offset,
158
+ ppkt->size - offset)) {
159
trace_colo_compare_icmp_miscompare("primary pkt size",
160
ppkt->size);
161
trace_colo_compare_icmp_miscompare("Secondary pkt size",
162
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_icmp(Packet *spkt, Packet *ppkt)
163
*/
164
static int colo_packet_compare_other(Packet *spkt, Packet *ppkt)
165
{
166
+ uint16_t offset = ppkt->vnet_hdr_len;
167
+
168
trace_colo_compare_main("compare other");
169
if (trace_event_get_state_backends(TRACE_COLO_COMPARE_MISCOMPARE)) {
170
char pri_ip_src[20], pri_ip_dst[20], sec_ip_src[20], sec_ip_dst[20];
171
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_other(Packet *spkt, Packet *ppkt)
172
sec_ip_src, sec_ip_dst);
173
}
174
175
- return colo_packet_compare_common(ppkt, spkt, 0, 0);
176
+ if (ppkt->size != spkt->size) {
177
+ trace_colo_compare_main("Other: payload size of packets are different");
178
+ return -1;
179
+ }
180
+ return colo_compare_packet_payload(ppkt, spkt, offset, offset,
181
+ ppkt->size - offset);
182
}
183
184
static int colo_old_packet_check_one(Packet *pkt, int64_t *check_time)
185
--
50
--
186
2.7.4
51
2.5.0
187
52
188
53
diff view generated by jsdifflib
Deleted patch
1
From: Thomas Huth <thuth@redhat.com>
2
1
3
It does not make much sense to limit these commands to the legacy 'vlan'
4
concept only, they should work with the modern netdevs, too. So now
5
it is possible to use this command with one, two or three parameters.
6
7
With one parameter, the command installs a hostfwd rule on the default
8
"user" network:
9
hostfwd_add tcp:...
10
11
With two parameters, the command installs a hostfwd rule on a netdev
12
(that's the new way of using this command):
13
hostfwd_add netdev_id tcp:...
14
15
With three parameters, the command installs a rule on a 'vlan' (aka hub):
16
hostfwd_add hub_id name tcp:...
17
18
Same applies to the hostfwd_remove command now.
19
20
Signed-off-by: Thomas Huth <thuth@redhat.com>
21
Signed-off-by: Jason Wang <jasowang@redhat.com>
22
---
23
hmp-commands.hx | 4 ++--
24
net/slirp.c | 33 +++++++++++++++++++++++----------
25
2 files changed, 25 insertions(+), 12 deletions(-)
26
27
diff --git a/hmp-commands.hx b/hmp-commands.hx
28
index XXXXXXX..XXXXXXX 100644
29
--- a/hmp-commands.hx
30
+++ b/hmp-commands.hx
31
@@ -XXX,XX +XXX,XX @@ ETEXI
32
{
33
.name = "hostfwd_add",
34
.args_type = "arg1:s,arg2:s?,arg3:s?",
35
- .params = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport",
36
+ .params = "[hub_id name]|[netdev_id] [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport",
37
.help = "redirect TCP or UDP connections from host to guest (requires -net user)",
38
.cmd = hmp_hostfwd_add,
39
},
40
@@ -XXX,XX +XXX,XX @@ ETEXI
41
{
42
.name = "hostfwd_remove",
43
.args_type = "arg1:s,arg2:s?,arg3:s?",
44
- .params = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport",
45
+ .params = "[hub_id name]|[netdev_id] [tcp|udp]:[hostaddr]:hostport",
46
.help = "remove host-to-guest TCP or UDP redirection",
47
.cmd = hmp_hostfwd_remove,
48
},
49
diff --git a/net/slirp.c b/net/slirp.c
50
index XXXXXXX..XXXXXXX 100644
51
--- a/net/slirp.c
52
+++ b/net/slirp.c
53
@@ -XXX,XX +XXX,XX @@ error:
54
return -1;
55
}
56
57
-static SlirpState *slirp_lookup(Monitor *mon, const char *vlan,
58
- const char *stack)
59
+static SlirpState *slirp_lookup(Monitor *mon, const char *hub_id,
60
+ const char *name)
61
{
62
-
63
- if (vlan) {
64
+ if (name) {
65
NetClientState *nc;
66
- nc = net_hub_find_client_by_name(strtol(vlan, NULL, 0), stack);
67
- if (!nc) {
68
- monitor_printf(mon, "unrecognized (vlan-id, stackname) pair\n");
69
- return NULL;
70
+ if (hub_id) {
71
+ nc = net_hub_find_client_by_name(strtol(hub_id, NULL, 0), name);
72
+ if (!nc) {
73
+ monitor_printf(mon, "unrecognized (vlan-id, stackname) pair\n");
74
+ return NULL;
75
+ }
76
+ } else {
77
+ nc = qemu_find_netdev(name);
78
+ if (!nc) {
79
+ monitor_printf(mon, "unrecognized netdev id '%s'\n", name);
80
+ return NULL;
81
+ }
82
}
83
if (strcmp(nc->model, "user")) {
84
monitor_printf(mon, "invalid device specified\n");
85
@@ -XXX,XX +XXX,XX @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
86
const char *arg2 = qdict_get_try_str(qdict, "arg2");
87
const char *arg3 = qdict_get_try_str(qdict, "arg3");
88
89
- if (arg2) {
90
+ if (arg3) {
91
s = slirp_lookup(mon, arg1, arg2);
92
src_str = arg3;
93
+ } else if (arg2) {
94
+ s = slirp_lookup(mon, NULL, arg1);
95
+ src_str = arg2;
96
} else {
97
s = slirp_lookup(mon, NULL, NULL);
98
src_str = arg1;
99
@@ -XXX,XX +XXX,XX @@ void hmp_hostfwd_add(Monitor *mon, const QDict *qdict)
100
const char *arg2 = qdict_get_try_str(qdict, "arg2");
101
const char *arg3 = qdict_get_try_str(qdict, "arg3");
102
103
- if (arg2) {
104
+ if (arg3) {
105
s = slirp_lookup(mon, arg1, arg2);
106
redir_str = arg3;
107
+ } else if (arg2) {
108
+ s = slirp_lookup(mon, NULL, arg1);
109
+ redir_str = arg2;
110
} else {
111
s = slirp_lookup(mon, NULL, NULL);
112
redir_str = arg1;
113
--
114
2.7.4
115
116
diff view generated by jsdifflib
Deleted patch
1
From: Thomas Huth <thuth@redhat.com>
2
1
3
The vlan concept is marked as deprecated, so we should not use
4
this for examples in the documentation anymore.
5
6
Signed-off-by: Thomas Huth <thuth@redhat.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
9
qemu-options.hx | 4 ++--
10
1 file changed, 2 insertions(+), 2 deletions(-)
11
12
diff --git a/qemu-options.hx b/qemu-options.hx
13
index XXXXXXX..XXXXXXX 100644
14
--- a/qemu-options.hx
15
+++ b/qemu-options.hx
16
@@ -XXX,XX +XXX,XX @@ qemu-system-i386 linux.img -net nic -net tap
17
#launch a QEMU instance with two NICs, each one connected
18
#to a TAP device
19
qemu-system-i386 linux.img \
20
- -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
21
- -net nic,vlan=1 -net tap,vlan=1,ifname=tap1
22
+ -netdev tap,id=nd0,ifname=tap0 -device e1000,netdev=nd0 \
23
+ -netdev tap,id=nd1,ifname=tap1 -device rtl8139,netdev=nd1
24
@end example
25
26
@example
27
--
28
2.7.4
29
30
diff view generated by jsdifflib