1
The following changes since commit e607bbee553cfe73072870cef458cfa4e78133e2:
1
The following changes since commit f670b3eec7f5d1ed8c4573ef244e7b8c6b32001b:
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 tag 'migration-20230213-pull-request' of https://gitlab.com/juan.quintela/qemu into staging (2023-02-13 11:54:05 +0000)
4
4
5
are available in the git repository at:
5
are available in the git repository at:
6
6
7
https://github.com/jasowang/qemu.git tags/net-pull-request
7
https://github.com/jasowang/qemu.git tags/net-pull-request
8
8
9
for you to fetch changes up to bf4835a4d5338bb7424827715df22570a8adc67c:
9
for you to fetch changes up to e4b953a26da11d214f91516cb9b0542eab5afaa0:
10
10
11
MAINTAINERS: update Dmitry Fleytman email (2018-01-29 16:05:38 +0800)
11
vdpa: fix VHOST_BACKEND_F_IOTLB_ASID flag check (2023-02-14 14:00:30 +0800)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
14
15
----------------------------------------------------------------
15
----------------------------------------------------------------
16
Mao Zhongyi (2):
16
Christian Svensson (1):
17
colo: modified the payload compare function
17
net: Increase L2TPv3 buffer to fit jumboframes
18
colo: compare the packet based on the tcp sequence number
19
18
20
Philippe Mathieu-Daudé (1):
19
Eugenio Pérez (1):
21
MAINTAINERS: update Dmitry Fleytman email
20
vdpa: fix VHOST_BACKEND_F_IOTLB_ASID flag check
21
22
Fiona Ebner (1):
23
hw/net/vmxnet3: allow VMXNET3_MAX_MTU itself as a value
24
25
Joelle van Dyne (1):
26
vmnet: stop recieving events when VM is stopped
27
28
Laurent Vivier (1):
29
net: stream: add a new option to automatically reconnect
30
31
Qiang Liu (2):
32
hw/net/lan9118: log [read|write]b when mode_16bit is enabled rather than abort
33
hw/net/can/xlnx-zynqmp-can: fix assertion failures in transfer_fifo()
22
34
23
Thomas Huth (3):
35
Thomas Huth (3):
24
net: Allow hubports to connect to other netdevs
36
net: Move the code to collect available NIC models to a separate function
25
net: Allow netdevs to be used with 'hostfwd_add' and 'hostfwd_remove'
37
net: Restore printing of the help text with "-nic help"
26
qemu-doc: Get rid of "vlan=X" example in the documentation
38
net: Replace "Supported NIC models" with "Available NIC models"
27
39
28
MAINTAINERS | 8 +-
40
hw/net/can/xlnx-zynqmp-can.c | 9 +++-
29
hmp-commands.hx | 4 +-
41
hw/net/lan9118.c | 17 ++++----
30
net/colo-compare.c | 411 +++++++++++++++++++++++++++++++++--------------------
42
hw/net/vmxnet3.c | 2 +-
31
net/colo.c | 9 ++
43
hw/pci/pci.c | 29 +------------
32
net/colo.h | 15 ++
44
include/net/net.h | 14 ++++++
33
net/hub.c | 27 +++-
45
net/l2tpv3.c | 2 +-
34
net/hub.h | 3 +-
46
net/net.c | 50 +++++++++++++++++++--
35
net/net.c | 2 +-
47
net/stream.c | 53 ++++++++++++++++++++++-
36
net/slirp.c | 33 +++--
48
net/vhost-vdpa.c | 2 +-
37
net/trace-events | 2 +-
49
net/vmnet-common.m | 48 ++++++++++++++------
38
qapi/net.json | 4 +-
50
net/vmnet_int.h | 2 +
39
qemu-options.hx | 12 +-
51
qapi/net.json | 7 ++-
40
12 files changed, 347 insertions(+), 183 deletions(-)
52
qemu-options.hx | 6 +--
53
tests/qtest/netdev-socket.c | 101 +++++++++++++++++++++++++++++++++++++++++++
54
14 files changed, 280 insertions(+), 62 deletions(-)
41
55
42
56
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
It does not make much sense to limit these commands to the legacy 'vlan'
3
The code that collects the available NIC models is not really specific
4
concept only, they should work with the modern netdevs, too. So now
4
to PCI anymore and will be required in the next patch, too, so let's
5
it is possible to use this command with one, two or three parameters.
5
move this into a new separate function in net.c instead.
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
6
20
Signed-off-by: Thomas Huth <thuth@redhat.com>
7
Signed-off-by: Thomas Huth <thuth@redhat.com>
21
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
22
---
9
---
23
hmp-commands.hx | 4 ++--
10
hw/pci/pci.c | 29 +----------------------------
24
net/slirp.c | 33 +++++++++++++++++++++++----------
11
include/net/net.h | 14 ++++++++++++++
25
2 files changed, 25 insertions(+), 12 deletions(-)
12
net/net.c | 34 ++++++++++++++++++++++++++++++++++
13
3 files changed, 49 insertions(+), 28 deletions(-)
26
14
27
diff --git a/hmp-commands.hx b/hmp-commands.hx
15
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
28
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
29
--- a/hmp-commands.hx
17
--- a/hw/pci/pci.c
30
+++ b/hmp-commands.hx
18
+++ b/hw/pci/pci.c
31
@@ -XXX,XX +XXX,XX @@ ETEXI
19
@@ -XXX,XX +XXX,XX @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
32
{
20
const char *default_devaddr)
33
.name = "hostfwd_add",
21
{
34
.args_type = "arg1:s,arg2:s?,arg3:s?",
22
const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr;
35
- .params = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport",
23
- GSList *list;
36
+ .params = "[hub_id name]|[netdev_id] [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport",
24
GPtrArray *pci_nic_models;
37
.help = "redirect TCP or UDP connections from host to guest (requires -net user)",
25
PCIBus *bus;
38
.cmd = hmp_hostfwd_add,
26
PCIDevice *pci_dev;
39
},
27
@@ -XXX,XX +XXX,XX @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
40
@@ -XXX,XX +XXX,XX @@ ETEXI
28
nd->model = g_strdup("virtio-net-pci");
41
{
29
}
42
.name = "hostfwd_remove",
30
43
.args_type = "arg1:s,arg2:s?,arg3:s?",
31
- list = object_class_get_list_sorted(TYPE_PCI_DEVICE, false);
44
- .params = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport",
32
- pci_nic_models = g_ptr_array_new();
45
+ .params = "[hub_id name]|[netdev_id] [tcp|udp]:[hostaddr]:hostport",
33
- while (list) {
46
.help = "remove host-to-guest TCP or UDP redirection",
34
- DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, list->data,
47
.cmd = hmp_hostfwd_remove,
35
- TYPE_DEVICE);
48
},
36
- GSList *next;
49
diff --git a/net/slirp.c b/net/slirp.c
37
- if (test_bit(DEVICE_CATEGORY_NETWORK, dc->categories) &&
38
- dc->user_creatable) {
39
- const char *name = object_class_get_name(list->data);
40
- /*
41
- * A network device might also be something else than a NIC, see
42
- * e.g. the "rocker" device. Thus we have to look for the "netdev"
43
- * property, too. Unfortunately, some devices like virtio-net only
44
- * create this property during instance_init, so we have to create
45
- * a temporary instance here to be able to check it.
46
- */
47
- Object *obj = object_new_with_class(OBJECT_CLASS(dc));
48
- if (object_property_find(obj, "netdev")) {
49
- g_ptr_array_add(pci_nic_models, (gpointer)name);
50
- }
51
- object_unref(obj);
52
- }
53
- next = list->next;
54
- g_slist_free_1(list);
55
- list = next;
56
- }
57
- g_ptr_array_add(pci_nic_models, NULL);
58
+ pci_nic_models = qemu_get_nic_models(TYPE_PCI_DEVICE);
59
60
if (qemu_show_nic_models(nd->model, (const char **)pci_nic_models->pdata)) {
61
exit(0);
62
diff --git a/include/net/net.h b/include/net/net.h
50
index XXXXXXX..XXXXXXX 100644
63
index XXXXXXX..XXXXXXX 100644
51
--- a/net/slirp.c
64
--- a/include/net/net.h
52
+++ b/net/slirp.c
65
+++ b/include/net/net.h
53
@@ -XXX,XX +XXX,XX @@ error:
66
@@ -XXX,XX +XXX,XX @@ void net_socket_rs_init(SocketReadState *rs,
67
bool vnet_hdr);
68
NetClientState *qemu_get_peer(NetClientState *nc, int queue_index);
69
70
+/**
71
+ * qemu_get_nic_models:
72
+ * @device_type: Defines which devices should be taken into consideration
73
+ * (e.g. TYPE_DEVICE for all devices, or TYPE_PCI_DEVICE for PCI)
74
+ *
75
+ * Get an array of pointers to names of NIC devices that are available in
76
+ * the QEMU binary. The array is terminated with a NULL pointer entry.
77
+ * The caller is responsible for freeing the memory when it is not required
78
+ * anymore, e.g. with g_ptr_array_free(..., true).
79
+ *
80
+ * Returns: Pointer to the array that contains the pointers to the names.
81
+ */
82
+GPtrArray *qemu_get_nic_models(const char *device_type);
83
+
84
/* NIC info */
85
86
#define MAX_NICS 8
87
diff --git a/net/net.c b/net/net.c
88
index XXXXXXX..XXXXXXX 100644
89
--- a/net/net.c
90
+++ b/net/net.c
91
@@ -XXX,XX +XXX,XX @@ static int nic_get_free_idx(void)
54
return -1;
92
return -1;
55
}
93
}
56
94
57
-static SlirpState *slirp_lookup(Monitor *mon, const char *vlan,
95
+GPtrArray *qemu_get_nic_models(const char *device_type)
58
- const char *stack)
96
+{
59
+static SlirpState *slirp_lookup(Monitor *mon, const char *hub_id,
97
+ GPtrArray *nic_models = g_ptr_array_new();
60
+ const char *name)
98
+ GSList *list = object_class_get_list_sorted(device_type, false);
99
+
100
+ while (list) {
101
+ DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, list->data,
102
+ TYPE_DEVICE);
103
+ GSList *next;
104
+ if (test_bit(DEVICE_CATEGORY_NETWORK, dc->categories) &&
105
+ dc->user_creatable) {
106
+ const char *name = object_class_get_name(list->data);
107
+ /*
108
+ * A network device might also be something else than a NIC, see
109
+ * e.g. the "rocker" device. Thus we have to look for the "netdev"
110
+ * property, too. Unfortunately, some devices like virtio-net only
111
+ * create this property during instance_init, so we have to create
112
+ * a temporary instance here to be able to check it.
113
+ */
114
+ Object *obj = object_new_with_class(OBJECT_CLASS(dc));
115
+ if (object_property_find(obj, "netdev")) {
116
+ g_ptr_array_add(nic_models, (gpointer)name);
117
+ }
118
+ object_unref(obj);
119
+ }
120
+ next = list->next;
121
+ g_slist_free_1(list);
122
+ list = next;
123
+ }
124
+ g_ptr_array_add(nic_models, NULL);
125
+
126
+ return nic_models;
127
+}
128
+
129
int qemu_show_nic_models(const char *arg, const char *const *models)
61
{
130
{
62
-
131
int i;
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
--
132
--
114
2.7.4
133
2.7.4
115
116
diff view generated by jsdifflib
1
From: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
Packet size some time different or when network is busy.
3
Running QEMU with "-nic help" used to work in QEMU 5.2 and earlier versions
4
Based on same payload size, but TCP protocol can not
4
(it showed the available netdev backends), but this feature got broken during
5
guarantee send the same one packet in the same way,
5
some refactoring in version 6.0. Let's restore the old behavior, and while
6
we're at it, let's also print the available NIC models here now since this
7
option can be used to configure both, netdev backend and model in one go.
6
8
7
like that:
9
Fixes: ad6f932fe8 ("net: do not exit on "netdev_add help" monitor command")
8
We send this payload:
10
Signed-off-by: Thomas Huth <thuth@redhat.com>
9
------------------------------
10
| header |1|2|3|4|5|6|7|8|9|0|
11
------------------------------
12
13
primary:
14
ppkt1:
15
----------------
16
| header |1|2|3|
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>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
70
---
12
---
71
net/colo-compare.c | 343 +++++++++++++++++++++++++++++++++++------------------
13
net/net.c | 14 ++++++++++++--
72
net/colo.c | 9 ++
14
1 file changed, 12 insertions(+), 2 deletions(-)
73
net/colo.h | 15 +++
74
net/trace-events | 2 +-
75
4 files changed, 250 insertions(+), 119 deletions(-)
76
15
77
diff --git a/net/colo-compare.c b/net/colo-compare.c
16
diff --git a/net/net.c b/net/net.c
78
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
79
--- a/net/colo-compare.c
18
--- a/net/net.c
80
+++ b/net/colo-compare.c
19
+++ b/net/net.c
81
@@ -XXX,XX +XXX,XX @@
20
@@ -XXX,XX +XXX,XX @@ static int net_param_nic(void *dummy, QemuOpts *opts, Error **errp)
82
#define COMPARE_READ_LEN_MAX NET_BUFSIZE
21
const char *type;
83
#define MAX_QUEUE_SIZE 1024
22
84
23
type = qemu_opt_get(opts, "type");
85
+#define COLO_COMPARE_FREE_PRIMARY 0x01
24
- if (type && g_str_equal(type, "none")) {
86
+#define COLO_COMPARE_FREE_SECONDARY 0x02
25
- return 0; /* Nothing to do, default_net is cleared in vl.c */
87
+
26
+ if (type) {
88
/* TODO: Should be configurable */
27
+ if (g_str_equal(type, "none")) {
89
#define REGULAR_PACKET_CHECK_MS 3000
28
+ return 0; /* Nothing to do, default_net is cleared in vl.c */
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
}
127
128
if (mode == PRIMARY_IN) {
129
- if (!colo_insert_packet(&conn->primary_list, pkt)) {
130
+ if (!colo_insert_packet(&conn->primary_list, pkt, &conn->pack)) {
131
error_report("colo compare primary queue size too big,"
132
"drop packet");
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
+ }
29
+ }
193
+ }
30
+ if (is_help_option(type)) {
194
+ if (ppkt->tcp_seq == spkt->tcp_seq && ppkt->seq_end == spkt->seq_end) {
31
+ GPtrArray *nic_models = qemu_get_nic_models(TYPE_DEVICE);
195
+ if (colo_compare_packet_payload(ppkt, spkt,
32
+ show_netdevs();
196
+ ppkt->header_size, spkt->header_size,
33
+ printf("\n");
197
+ ppkt->payload_size)) {
34
+ qemu_show_nic_models(type, (const char **)nic_models->pdata);
198
+ *mark = COLO_COMPARE_FREE_SECONDARY | COLO_COMPARE_FREE_PRIMARY;
35
+ g_ptr_array_free(nic_models, true);
199
+ return true;
36
+ exit(0);
200
+ }
201
+ }
202
+
203
+ /* one part of secondary packet payload still need to be compared */
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
+ }
37
+ }
344
}
38
}
345
39
346
- if (res != 0 &&
40
idx = nic_get_free_idx();
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
}
415
416
+
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
516
--- a/net/colo.c
517
+++ b/net/colo.c
518
@@ -XXX,XX +XXX,XX @@ Connection *connection_new(ConnectionKey *key)
519
conn->processing = false;
520
conn->offset = 0;
521
conn->syn_flag = 0;
522
+ conn->pack = 0;
523
+ conn->sack = 0;
524
g_queue_init(&conn->primary_list);
525
g_queue_init(&conn->secondary_list);
526
527
@@ -XXX,XX +XXX,XX @@ Packet *packet_new(const void *data, int size, int vnet_hdr_len)
528
pkt->size = size;
529
pkt->creation_ms = qemu_clock_get_ms(QEMU_CLOCK_HOST);
530
pkt->vnet_hdr_len = vnet_hdr_len;
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
--
41
--
588
2.7.4
42
2.7.4
589
590
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Thomas Huth <thuth@redhat.com>
2
2
3
The vlan concept is marked as deprecated, so we should not use
3
Just because a NIC model is compiled into the QEMU binary does not
4
this for examples in the documentation anymore.
4
necessary mean that it can be used with each and every machine.
5
So let's rather talk about "available" models instead of "supported"
6
models, just to avoid confusion.
5
7
8
Reviewed-by: Claudio Fontana <cfontana@suse.de>
6
Signed-off-by: Thomas Huth <thuth@redhat.com>
9
Signed-off-by: Thomas Huth <thuth@redhat.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
11
---
9
qemu-options.hx | 4 ++--
12
net/net.c | 2 +-
10
1 file changed, 2 insertions(+), 2 deletions(-)
13
1 file changed, 1 insertion(+), 1 deletion(-)
11
14
12
diff --git a/qemu-options.hx b/qemu-options.hx
15
diff --git a/net/net.c b/net/net.c
13
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
14
--- a/qemu-options.hx
17
--- a/net/net.c
15
+++ b/qemu-options.hx
18
+++ b/net/net.c
16
@@ -XXX,XX +XXX,XX @@ qemu-system-i386 linux.img -net nic -net tap
19
@@ -XXX,XX +XXX,XX @@ int qemu_show_nic_models(const char *arg, const char *const *models)
17
#launch a QEMU instance with two NICs, each one connected
20
return 0;
18
#to a TAP device
21
}
19
qemu-system-i386 linux.img \
22
20
- -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
23
- printf("Supported NIC models:\n");
21
- -net nic,vlan=1 -net tap,vlan=1,ifname=tap1
24
+ printf("Available NIC models:\n");
22
+ -netdev tap,id=nd0,ifname=tap0 -device e1000,netdev=nd0 \
25
for (i = 0 ; models[i]; i++) {
23
+ -netdev tap,id=nd1,ifname=tap1 -device rtl8139,netdev=nd1
26
printf("%s\n", models[i]);
24
@end example
27
}
25
26
@example
27
--
28
--
28
2.7.4
29
2.7.4
29
30
diff view generated by jsdifflib
1
From: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
1
From: Qiang Liu <cyruscyliu@gmail.com>
2
2
3
Modified the function colo_packet_compare_common to prepare for the
3
This patch replaces hw_error to guest error log for [read|write]b
4
tcp packet comparison in the next patch.
4
accesses when mode_16bit is enabled. This avoids aborting qemu.
5
5
6
Cc: Zhang Chen <zhangckid@gmail.com>
6
Fixes: 1248f8d4cbc3 ("hw/lan9118: Add basic 16-bit mode support.")
7
Cc: Li Zhijian <lizhijian@cn.fujitsu.com>
7
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1433
8
Cc: Jason Wang <jasowang@redhat.com>
8
Reported-by: Qiang Liu <cyruscyliu@gmail.com>
9
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
10
Signed-off-by: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
10
Signed-off-by: Qiang Liu <cyruscyliu@gmail.com>
11
Signed-off-by: Li Zhijian <lizhijian@cn.fujitsu.com>
11
Suggested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
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>
12
Signed-off-by: Jason Wang <jasowang@redhat.com>
15
---
13
---
16
net/colo-compare.c | 88 +++++++++++++++++++++++++++---------------------------
14
hw/net/lan9118.c | 17 ++++++++---------
17
1 file changed, 44 insertions(+), 44 deletions(-)
15
1 file changed, 8 insertions(+), 9 deletions(-)
18
16
19
diff --git a/net/colo-compare.c b/net/colo-compare.c
17
diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c
20
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
21
--- a/net/colo-compare.c
19
--- a/hw/net/lan9118.c
22
+++ b/net/colo-compare.c
20
+++ b/hw/net/lan9118.c
23
@@ -XXX,XX +XXX,XX @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
21
@@ -XXX,XX +XXX,XX @@
24
* return: 0 means packet same
22
#include "migration/vmstate.h"
25
* > 0 || < 0 means packet different
23
#include "net/net.h"
26
*/
24
#include "net/eth.h"
27
-static int colo_packet_compare_common(Packet *ppkt,
25
-#include "hw/hw.h"
28
- Packet *spkt,
26
#include "hw/irq.h"
29
- int poffset,
27
#include "hw/net/lan9118.h"
30
- int soffset)
28
#include "hw/ptimer.h"
31
+static int colo_compare_packet_payload(Packet *ppkt,
29
@@ -XXX,XX +XXX,XX @@
32
+ Packet *spkt,
30
#ifdef DEBUG_LAN9118
33
+ uint16_t poffset,
31
#define DPRINTF(fmt, ...) \
34
+ uint16_t soffset,
32
do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0)
35
+ uint16_t len)
33
-#define BADF(fmt, ...) \
36
+
34
-do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
37
{
35
#else
38
if (trace_event_get_state_backends(TRACE_COLO_COMPARE_MISCOMPARE)) {
36
#define DPRINTF(fmt, ...) do {} while(0)
39
char pri_ip_src[20], pri_ip_dst[20], sec_ip_src[20], sec_ip_dst[20];
37
-#define BADF(fmt, ...) \
40
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_common(Packet *ppkt,
38
-do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
41
sec_ip_src, sec_ip_dst);
39
#endif
40
41
/* The tx and rx fifo ports are a range of aliased 32-bit registers */
42
@@ -XXX,XX +XXX,XX @@ static uint32_t do_phy_read(lan9118_state *s, int reg)
43
case 30: /* Interrupt mask */
44
return s->phy_int_mask;
45
default:
46
- BADF("PHY read reg %d\n", reg);
47
+ qemu_log_mask(LOG_GUEST_ERROR,
48
+ "do_phy_read: PHY read reg %d\n", reg);
49
return 0;
42
}
50
}
43
44
- poffset = ppkt->vnet_hdr_len + poffset;
45
- soffset = ppkt->vnet_hdr_len + soffset;
46
-
47
- if (ppkt->size - poffset == spkt->size - soffset) {
48
- return memcmp(ppkt->data + poffset,
49
- spkt->data + soffset,
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
}
51
}
57
52
@@ -XXX,XX +XXX,XX @@ static void do_phy_write(lan9118_state *s, int reg, uint32_t val)
58
/*
53
phy_update_irq(s);
59
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt)
54
break;
60
* the secondary guest's timestamp. COLO just focus on payload,
55
default:
61
* so we just need skip this field.
56
- BADF("PHY write reg %d = 0x%04x\n", reg, val);
62
*/
57
+ qemu_log_mask(LOG_GUEST_ERROR,
63
- if (ptcp->th_off > 5) {
58
+ "do_phy_write: PHY write reg %d = 0x%04x\n", reg, val);
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
}
59
}
93
60
}
94
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt)
61
95
*/
62
@@ -XXX,XX +XXX,XX @@ static void lan9118_16bit_mode_write(void *opaque, hwaddr offset,
96
static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
63
return;
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
}
64
}
131
-
65
132
- return ret;
66
- hw_error("lan9118_write: Bad size 0x%x\n", size);
67
+ qemu_log_mask(LOG_GUEST_ERROR,
68
+ "lan9118_16bit_mode_write: Bad size 0x%x\n", size);
133
}
69
}
134
70
135
/*
71
static uint64_t lan9118_readl(void *opaque, hwaddr offset,
136
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
72
@@ -XXX,XX +XXX,XX @@ static uint64_t lan9118_16bit_mode_read(void *opaque, hwaddr offset,
137
*/
73
return lan9118_readl(opaque, offset, size);
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
}
74
}
174
75
175
- return colo_packet_compare_common(ppkt, spkt, 0, 0);
76
- hw_error("lan9118_read: Bad size 0x%x\n", size);
176
+ if (ppkt->size != spkt->size) {
77
+ qemu_log_mask(LOG_GUEST_ERROR,
177
+ trace_colo_compare_main("Other: payload size of packets are different");
78
+ "lan9118_16bit_mode_read: Bad size 0x%x\n", size);
178
+ return -1;
79
return 0;
179
+ }
180
+ return colo_compare_packet_payload(ppkt, spkt, offset, offset,
181
+ ppkt->size - offset);
182
}
80
}
183
81
184
static int colo_old_packet_check_one(Packet *pkt, int64_t *check_time)
185
--
82
--
186
2.7.4
83
2.7.4
187
84
188
85
diff view generated by jsdifflib
New patch
1
From: Fiona Ebner <f.ebner@proxmox.com>
1
2
3
Currently, VMXNET3_MAX_MTU itself (being 9000) is not considered a
4
valid value for the MTU, but a guest running ESXi 7.0 might try to
5
set it and fail the assert [0].
6
7
In the Linux kernel, dev->max_mtu itself is a valid value for the MTU
8
and for the vmxnet3 driver it's 9000, so a guest running Linux will
9
also fail the assert when trying to set an MTU of 9000.
10
11
VMXNET3_MAX_MTU and s->mtu don't seem to be used in relation to buffer
12
allocations/accesses, so allowing the upper limit itself as a value
13
should be fine.
14
15
[0]: https://forum.proxmox.com/threads/114011/
16
17
Fixes: d05dcd94ae ("net: vmxnet3: validate configuration values during activate (CVE-2021-20203)")
18
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
19
Signed-off-by: Jason Wang <jasowang@redhat.com>
20
---
21
hw/net/vmxnet3.c | 2 +-
22
1 file changed, 1 insertion(+), 1 deletion(-)
23
24
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/hw/net/vmxnet3.c
27
+++ b/hw/net/vmxnet3.c
28
@@ -XXX,XX +XXX,XX @@ static void vmxnet3_activate_device(VMXNET3State *s)
29
vmxnet3_setup_rx_filtering(s);
30
/* Cache fields from shared memory */
31
s->mtu = VMXNET3_READ_DRV_SHARED32(d, s->drv_shmem, devRead.misc.mtu);
32
- assert(VMXNET3_MIN_MTU <= s->mtu && s->mtu < VMXNET3_MAX_MTU);
33
+ assert(VMXNET3_MIN_MTU <= s->mtu && s->mtu <= VMXNET3_MAX_MTU);
34
VMW_CFPRN("MTU is %u", s->mtu);
35
36
s->max_rx_frags =
37
--
38
2.7.4
diff view generated by jsdifflib
New patch
1
From: Christian Svensson <blue@cmd.nu>
1
2
3
Increase the allocated buffer size to fit larger packets.
4
Given that jumboframes can commonly be up to 9000 bytes the closest suitable
5
value seems to be 16 KiB.
6
7
Tested by running qemu towards a Linux L2TPv3 endpoint and pushing
8
jumboframe traffic through the interfaces.
9
10
Signed-off-by: Christian Svensson <blue@cmd.nu>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
13
net/l2tpv3.c | 2 +-
14
1 file changed, 1 insertion(+), 1 deletion(-)
15
16
diff --git a/net/l2tpv3.c b/net/l2tpv3.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/net/l2tpv3.c
19
+++ b/net/l2tpv3.c
20
@@ -XXX,XX +XXX,XX @@
21
*/
22
23
#define BUFFER_ALIGN sysconf(_SC_PAGESIZE)
24
-#define BUFFER_SIZE 2048
25
+#define BUFFER_SIZE 16384
26
#define IOVSIZE 2
27
#define MAX_L2TPV3_MSGCNT 64
28
#define MAX_L2TPV3_IOVCNT (MAX_L2TPV3_MSGCNT * IOVSIZE)
29
--
30
2.7.4
diff view generated by jsdifflib
New patch
1
From: Joelle van Dyne <j@getutm.app>
1
2
3
When the VM is stopped using the HMP command "stop", soon the handler will
4
stop reading from the vmnet interface. This causes a flood of
5
`VMNET_INTERFACE_PACKETS_AVAILABLE` events to arrive and puts the host CPU
6
at 100%. We fix this by removing the event handler from vmnet when the VM
7
is no longer in a running state and restore it when we return to a running
8
state.
9
10
Signed-off-by: Joelle van Dyne <j@getutm.app>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
13
net/vmnet-common.m | 48 +++++++++++++++++++++++++++++++++++-------------
14
net/vmnet_int.h | 2 ++
15
2 files changed, 37 insertions(+), 13 deletions(-)
16
17
diff --git a/net/vmnet-common.m b/net/vmnet-common.m
18
index XXXXXXX..XXXXXXX 100644
19
--- a/net/vmnet-common.m
20
+++ b/net/vmnet-common.m
21
@@ -XXX,XX +XXX,XX @@
22
#include "clients.h"
23
#include "qemu/error-report.h"
24
#include "qapi/error.h"
25
+#include "sysemu/runstate.h"
26
27
#include <vmnet/vmnet.h>
28
#include <dispatch/dispatch.h>
29
@@ -XXX,XX +XXX,XX @@ static void vmnet_bufs_init(VmnetState *s)
30
}
31
}
32
33
+/**
34
+ * Called on state change to un-register/re-register handlers
35
+ */
36
+static void vmnet_vm_state_change_cb(void *opaque, bool running, RunState state)
37
+{
38
+ VmnetState *s = opaque;
39
+
40
+ if (running) {
41
+ vmnet_interface_set_event_callback(
42
+ s->vmnet_if,
43
+ VMNET_INTERFACE_PACKETS_AVAILABLE,
44
+ s->if_queue,
45
+ ^(interface_event_t event_id, xpc_object_t event) {
46
+ assert(event_id == VMNET_INTERFACE_PACKETS_AVAILABLE);
47
+ /*
48
+ * This function is being called from a non qemu thread, so
49
+ * we only schedule a BH, and do the rest of the io completion
50
+ * handling from vmnet_send_bh() which runs in a qemu context.
51
+ */
52
+ qemu_bh_schedule(s->send_bh);
53
+ });
54
+ } else {
55
+ vmnet_interface_set_event_callback(
56
+ s->vmnet_if,
57
+ VMNET_INTERFACE_PACKETS_AVAILABLE,
58
+ NULL,
59
+ NULL);
60
+ }
61
+}
62
63
int vmnet_if_create(NetClientState *nc,
64
xpc_object_t if_desc,
65
@@ -XXX,XX +XXX,XX @@ int vmnet_if_create(NetClientState *nc,
66
s->packets_send_current_pos = 0;
67
s->packets_send_end_pos = 0;
68
69
- vmnet_interface_set_event_callback(
70
- s->vmnet_if,
71
- VMNET_INTERFACE_PACKETS_AVAILABLE,
72
- s->if_queue,
73
- ^(interface_event_t event_id, xpc_object_t event) {
74
- assert(event_id == VMNET_INTERFACE_PACKETS_AVAILABLE);
75
- /*
76
- * This function is being called from a non qemu thread, so
77
- * we only schedule a BH, and do the rest of the io completion
78
- * handling from vmnet_send_bh() which runs in a qemu context.
79
- */
80
- qemu_bh_schedule(s->send_bh);
81
- });
82
+ vmnet_vm_state_change_cb(s, 1, RUN_STATE_RUNNING);
83
+
84
+ s->change = qemu_add_vm_change_state_handler(vmnet_vm_state_change_cb, s);
85
86
return 0;
87
}
88
@@ -XXX,XX +XXX,XX @@ void vmnet_cleanup_common(NetClientState *nc)
89
return;
90
}
91
92
+ vmnet_vm_state_change_cb(s, 0, RUN_STATE_SHUTDOWN);
93
+ qemu_del_vm_change_state_handler(s->change);
94
if_stopped_sem = dispatch_semaphore_create(0);
95
vmnet_stop_interface(
96
s->vmnet_if,
97
diff --git a/net/vmnet_int.h b/net/vmnet_int.h
98
index XXXXXXX..XXXXXXX 100644
99
--- a/net/vmnet_int.h
100
+++ b/net/vmnet_int.h
101
@@ -XXX,XX +XXX,XX @@ typedef struct VmnetState {
102
int packets_send_end_pos;
103
104
struct iovec iov_buf[VMNET_PACKETS_LIMIT];
105
+
106
+ VMChangeStateEntry *change;
107
} VmnetState;
108
109
const char *vmnet_status_map_str(vmnet_return_t status);
110
--
111
2.7.4
diff view generated by jsdifflib
New patch
1
From: Qiang Liu <cyruscyliu@gmail.com>
1
2
3
Check fifos before poping data from and pushing data into it.
4
5
Fixes: 98e5d7a2b726 ("hw/net/can: Introduce Xilinx ZynqMP CAN controller")
6
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1425
7
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1427
8
Reported-by: Qiang Liu <cyruscyliu@gmail.com>
9
Signed-off-by: Qiang Liu <cyruscyliu@gmail.com>
10
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
---
12
hw/net/can/xlnx-zynqmp-can.c | 9 ++++++++-
13
1 file changed, 8 insertions(+), 1 deletion(-)
14
15
diff --git a/hw/net/can/xlnx-zynqmp-can.c b/hw/net/can/xlnx-zynqmp-can.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/hw/net/can/xlnx-zynqmp-can.c
18
+++ b/hw/net/can/xlnx-zynqmp-can.c
19
@@ -XXX,XX +XXX,XX @@ static void transfer_fifo(XlnxZynqMPCANState *s, Fifo32 *fifo)
20
}
21
22
while (!fifo32_is_empty(fifo)) {
23
+ if (fifo32_num_used(fifo) < (4 * CAN_FRAME_SIZE)) {
24
+ g_autofree char *path = object_get_canonical_path(OBJECT(s));
25
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: data left in the fifo is not"
26
+ " enough for transfer.\n", path);
27
+ break;
28
+ }
29
for (i = 0; i < CAN_FRAME_SIZE; i++) {
30
data[i] = fifo32_pop(fifo);
31
}
32
@@ -XXX,XX +XXX,XX @@ static void transfer_fifo(XlnxZynqMPCANState *s, Fifo32 *fifo)
33
* acknowledged. The XlnxZynqMPCAN core receives any message
34
* that it transmits.
35
*/
36
- if (fifo32_is_full(&s->rx_fifo)) {
37
+ if (fifo32_is_full(&s->rx_fifo) ||
38
+ (fifo32_num_free(&s->rx_fifo) < (4 * CAN_FRAME_SIZE))) {
39
ARRAY_FIELD_DP32(s->regs, INTERRUPT_STATUS_REGISTER, RXOFLW, 1);
40
} else {
41
for (i = 0; i < CAN_FRAME_SIZE; i++) {
42
--
43
2.7.4
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Laurent Vivier <lvivier@redhat.com>
2
2
3
QEMU can emulate hubs to connect NICs and netdevs. This is currently
3
In stream mode, if the server shuts down there is currently
4
primarily used for the mis-named 'vlan' feature of the networking
4
no way to reconnect the client to a new server without removing
5
subsystem. Now the 'vlan' feature has been marked as deprecated, since
5
the NIC device and the netdev backend (or to reboot).
6
its name is rather confusing and the users often rather mis-configure
6
7
their network when trying to use it. But while the 'vlan' parameter
7
This patch introduces a reconnect option that specifies a delay
8
should be removed at one point in time, the basic idea of emulating
8
to try to reconnect with the same parameters.
9
a hub in QEMU is still good: It's useful for bundling up the output of
9
10
multiple NICs into one single l2tp netdev for example.
10
Add a new test in qtest to test the reconnect option and the
11
11
connect/disconnect events.
12
Now to be able to use the hubport feature without 'vlan's, there is one
12
13
missing piece: The possibility to connect a hubport to a netdev, too.
13
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
14
This patch adds this possibility by introducing a new "netdev=..."
15
parameter to the hubports.
16
17
To bundle up the output of multiple NICs into one socket netdev, you can
18
now run QEMU with these parameters for example:
19
20
qemu-system-ppc64 ... -netdev socket,id=s1,connect=:11122 \
21
-netdev hubport,hubid=1,id=h1,netdev=s1 \
22
-netdev hubport,hubid=1,id=h2 -device e1000,netdev=h2 \
23
-netdev hubport,hubid=1,id=h3 -device virtio-net-pci,netdev=h3
24
25
For using the socket netdev, you have got to start another QEMU as the
26
receiving side first, for example with network dumping enabled:
27
28
qemu-system-x86_64 -M isapc -netdev socket,id=s0,listen=:11122 \
29
-device ne2k_isa,netdev=s0 \
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>
14
Signed-off-by: Jason Wang <jasowang@redhat.com>
40
---
15
---
41
net/hub.c | 27 +++++++++++++++++++++------
16
net/stream.c | 53 ++++++++++++++++++++++-
42
net/hub.h | 3 ++-
17
qapi/net.json | 7 ++-
43
net/net.c | 2 +-
18
qemu-options.hx | 6 +--
44
qapi/net.json | 4 +++-
19
tests/qtest/netdev-socket.c | 101 ++++++++++++++++++++++++++++++++++++++++++++
45
qemu-options.hx | 8 +++++---
20
4 files changed, 162 insertions(+), 5 deletions(-)
46
5 files changed, 32 insertions(+), 12 deletions(-)
21
47
22
diff --git a/net/stream.c b/net/stream.c
48
diff --git a/net/hub.c b/net/hub.c
49
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
50
--- a/net/hub.c
24
--- a/net/stream.c
51
+++ b/net/hub.c
25
+++ b/net/stream.c
52
@@ -XXX,XX +XXX,XX @@
26
@@ -XXX,XX +XXX,XX @@
53
*/
27
#include "io/channel-socket.h"
54
28
#include "io/net-listener.h"
55
#include "qemu/osdep.h"
29
#include "qapi/qapi-events-net.h"
56
+#include "qapi/error.h"
30
+#include "qapi/qapi-visit-sockets.h"
57
#include "monitor/monitor.h"
31
+#include "qapi/clone-visitor.h"
58
#include "net/net.h"
32
59
#include "clients.h"
33
typedef struct NetStreamState {
60
@@ -XXX,XX +XXX,XX @@ static NetClientInfo net_hub_port_info = {
34
NetClientState nc;
61
.cleanup = net_hub_port_cleanup,
35
@@ -XXX,XX +XXX,XX @@ typedef struct NetStreamState {
62
};
36
guint ioc_write_tag;
63
37
SocketReadState rs;
64
-static NetHubPort *net_hub_port_new(NetHub *hub, const char *name)
38
unsigned int send_index; /* number of bytes sent*/
65
+static NetHubPort *net_hub_port_new(NetHub *hub, const char *name,
39
+ uint32_t reconnect;
66
+ NetClientState *hubpeer)
40
+ guint timer_tag;
41
+ SocketAddress *addr;
42
} NetStreamState;
43
44
static void net_stream_listen(QIONetListener *listener,
45
QIOChannelSocket *cioc,
46
void *opaque);
47
+static void net_stream_arm_reconnect(NetStreamState *s);
48
49
static gboolean net_stream_writable(QIOChannel *ioc,
50
GIOCondition condition,
51
@@ -XXX,XX +XXX,XX @@ static gboolean net_stream_send(QIOChannel *ioc,
52
qemu_set_info_str(&s->nc, "%s", "");
53
54
qapi_event_send_netdev_stream_disconnected(s->nc.name);
55
+ net_stream_arm_reconnect(s);
56
57
return G_SOURCE_REMOVE;
58
}
59
@@ -XXX,XX +XXX,XX @@ static gboolean net_stream_send(QIOChannel *ioc,
60
static void net_stream_cleanup(NetClientState *nc)
67
{
61
{
68
NetClientState *nc;
62
NetStreamState *s = DO_UPCAST(NetStreamState, nc, nc);
69
NetHubPort *port;
63
+ if (s->timer_tag) {
70
@@ -XXX,XX +XXX,XX @@ static NetHubPort *net_hub_port_new(NetHub *hub, const char *name)
64
+ g_source_remove(s->timer_tag);
71
name = default_name;
65
+ s->timer_tag = 0;
66
+ }
67
+ if (s->addr) {
68
+ qapi_free_SocketAddress(s->addr);
69
+ s->addr = NULL;
70
+ }
71
if (s->ioc) {
72
if (QIO_CHANNEL_SOCKET(s->ioc)->fd != -1) {
73
if (s->ioc_read_tag) {
74
@@ -XXX,XX +XXX,XX @@ static void net_stream_client_connected(QIOTask *task, gpointer opaque)
75
error:
76
object_unref(OBJECT(s->ioc));
77
s->ioc = NULL;
78
+ net_stream_arm_reconnect(s);
79
+}
80
+
81
+static gboolean net_stream_reconnect(gpointer data)
82
+{
83
+ NetStreamState *s = data;
84
+ QIOChannelSocket *sioc;
85
+
86
+ s->timer_tag = 0;
87
+
88
+ sioc = qio_channel_socket_new();
89
+ s->ioc = QIO_CHANNEL(sioc);
90
+ qio_channel_socket_connect_async(sioc, s->addr,
91
+ net_stream_client_connected, s,
92
+ NULL, NULL);
93
+ return G_SOURCE_REMOVE;
94
+}
95
+
96
+static void net_stream_arm_reconnect(NetStreamState *s)
97
+{
98
+ if (s->reconnect && s->timer_tag == 0) {
99
+ s->timer_tag = g_timeout_add_seconds(s->reconnect,
100
+ net_stream_reconnect, s);
101
+ }
102
}
103
104
static int net_stream_client_init(NetClientState *peer,
105
const char *model,
106
const char *name,
107
SocketAddress *addr,
108
+ uint32_t reconnect,
109
Error **errp)
110
{
111
NetStreamState *s;
112
@@ -XXX,XX +XXX,XX @@ static int net_stream_client_init(NetClientState *peer,
113
s->ioc = QIO_CHANNEL(sioc);
114
s->nc.link_down = true;
115
116
+ s->reconnect = reconnect;
117
+ if (reconnect) {
118
+ s->addr = QAPI_CLONE(SocketAddress, addr);
119
+ }
120
qio_channel_socket_connect_async(sioc, addr,
121
net_stream_client_connected, s,
122
NULL, NULL);
123
@@ -XXX,XX +XXX,XX @@ int net_init_stream(const Netdev *netdev, const char *name,
124
sock = &netdev->u.stream;
125
126
if (!sock->has_server || !sock->server) {
127
- return net_stream_client_init(peer, "stream", name, sock->addr, errp);
128
+ return net_stream_client_init(peer, "stream", name, sock->addr,
129
+ sock->has_reconnect ? sock->reconnect : 0,
130
+ errp);
131
+ }
132
+ if (sock->has_reconnect) {
133
+ error_setg(errp, "'reconnect' option is incompatible with "
134
+ "socket in server mode");
135
+ return -1;
72
}
136
}
73
137
return net_stream_server_init(peer, "stream", name, sock->addr, errp);
74
- nc = qemu_new_net_client(&net_hub_port_info, NULL, "hub", name);
75
+ nc = qemu_new_net_client(&net_hub_port_info, hubpeer, "hub", name);
76
port = DO_UPCAST(NetHubPort, nc, nc);
77
port->id = id;
78
port->hub = hub;
79
@@ -XXX,XX +XXX,XX @@ static NetHubPort *net_hub_port_new(NetHub *hub, const char *name)
80
81
/**
82
* Create a port on a given hub
83
+ * @hub_id: Number of the hub
84
* @name: Net client name or NULL for default name.
85
+ * @hubpeer: Peer to use (if "netdev=id" has been specified)
86
*
87
* If there is no existing hub with the given id then a new hub is created.
88
*/
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
}
138
}
103
104
@@ -XXX,XX +XXX,XX @@ NetClientState *net_hub_port_find(int hub_id)
105
}
106
}
107
108
- nc = net_hub_add_port(hub_id, NULL);
109
+ nc = net_hub_add_port(hub_id, NULL, NULL);
110
return nc;
111
}
112
113
@@ -XXX,XX +XXX,XX @@ int net_init_hubport(const Netdev *netdev, const char *name,
114
NetClientState *peer, Error **errp)
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
+ }
131
+
132
+ net_hub_add_port(hubport->hubid, name, hubpeer);
133
+
134
return 0;
135
}
136
137
diff --git a/net/hub.h b/net/hub.h
138
index XXXXXXX..XXXXXXX 100644
139
--- a/net/hub.h
140
+++ b/net/hub.h
141
@@ -XXX,XX +XXX,XX @@
142
143
#include "qemu-common.h"
144
145
-NetClientState *net_hub_add_port(int hub_id, const char *name);
146
+NetClientState *net_hub_add_port(int hub_id, const char *name,
147
+ NetClientState *hubpeer);
148
NetClientState *net_hub_find_client_by_name(int hub_id, const char *name);
149
void net_hub_info(Monitor *mon);
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
139
diff --git a/qapi/net.json b/qapi/net.json
165
index XXXXXXX..XXXXXXX 100644
140
index XXXXXXX..XXXXXXX 100644
166
--- a/qapi/net.json
141
--- a/qapi/net.json
167
+++ b/qapi/net.json
142
+++ b/qapi/net.json
168
@@ -XXX,XX +XXX,XX @@
143
@@ -XXX,XX +XXX,XX @@
169
# Connect two or more net clients through a software hub.
144
# @addr: socket address to listen on (server=true)
145
# or connect to (server=false)
146
# @server: create server socket (default: false)
147
+# @reconnect: For a client socket, if a socket is disconnected,
148
+# then attempt a reconnect after the given number of seconds.
149
+# Setting this to zero disables this function. (default: 0)
150
+# (since 8.0)
170
#
151
#
171
# @hubid: hub identifier number
152
# Only SocketAddress types 'unix', 'inet' and 'fd' are supported.
172
+# @netdev: used to connect hub to a netdev instead of a device (since 2.12)
173
#
153
#
174
# Since: 1.2
154
@@ -XXX,XX +XXX,XX @@
155
{ 'struct': 'NetdevStreamOptions',
156
'data': {
157
'addr': 'SocketAddress',
158
- '*server': 'bool' } }
159
+ '*server': 'bool',
160
+ '*reconnect': 'uint32' } }
161
175
##
162
##
176
{ 'struct': 'NetdevHubPortOptions',
163
# @NetdevDgramOptions:
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
164
diff --git a/qemu-options.hx b/qemu-options.hx
185
index XXXXXXX..XXXXXXX 100644
165
index XXXXXXX..XXXXXXX 100644
186
--- a/qemu-options.hx
166
--- a/qemu-options.hx
187
+++ b/qemu-options.hx
167
+++ b/qemu-options.hx
188
@@ -XXX,XX +XXX,XX @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
168
@@ -XXX,XX +XXX,XX @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
169
"-netdev socket,id=str[,fd=h][,udp=host:port][,localaddr=host:port]\n"
170
" configure a network backend to connect to another network\n"
171
" using an UDP tunnel\n"
172
- "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off]\n"
173
- "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off]\n"
174
- "-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor\n"
175
+ "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off][,reconnect=seconds]\n"
176
+ "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off][,reconnect=seconds]\n"
177
+ "-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor[,reconnect=seconds]\n"
178
" configure a network backend to connect to another network\n"
179
" using a socket connection in stream mode.\n"
180
"-netdev dgram,id=str,remote.type=inet,remote.host=maddr,remote.port=port[,local.type=inet,local.host=addr]\n"
181
diff --git a/tests/qtest/netdev-socket.c b/tests/qtest/netdev-socket.c
182
index XXXXXXX..XXXXXXX 100644
183
--- a/tests/qtest/netdev-socket.c
184
+++ b/tests/qtest/netdev-socket.c
185
@@ -XXX,XX +XXX,XX @@
186
#include <glib/gstdio.h>
187
#include "../unit/socket-helpers.h"
188
#include "libqtest.h"
189
+#include "qapi/qmp/qstring.h"
190
+#include "qemu/sockets.h"
191
+#include "qapi/qobject-input-visitor.h"
192
+#include "qapi/qapi-visit-sockets.h"
193
194
#define CONNECTION_TIMEOUT 60
195
196
@@ -XXX,XX +XXX,XX @@ static void test_stream_inet_ipv4(void)
197
qtest_quit(qts0);
198
}
199
200
+static void wait_stream_connected(QTestState *qts, const char *id,
201
+ SocketAddress **addr)
202
+{
203
+ QDict *resp, *data;
204
+ QString *qstr;
205
+ QObject *obj;
206
+ Visitor *v = NULL;
207
+
208
+ resp = qtest_qmp_eventwait_ref(qts, "NETDEV_STREAM_CONNECTED");
209
+ g_assert_nonnull(resp);
210
+ data = qdict_get_qdict(resp, "data");
211
+ g_assert_nonnull(data);
212
+
213
+ qstr = qobject_to(QString, qdict_get(data, "netdev-id"));
214
+ g_assert_nonnull(data);
215
+
216
+ g_assert(!strcmp(qstring_get_str(qstr), id));
217
+
218
+ obj = qdict_get(data, "addr");
219
+
220
+ v = qobject_input_visitor_new(obj);
221
+ visit_type_SocketAddress(v, NULL, addr, NULL);
222
+ visit_free(v);
223
+ qobject_unref(resp);
224
+}
225
+
226
+static void wait_stream_disconnected(QTestState *qts, const char *id)
227
+{
228
+ QDict *resp, *data;
229
+ QString *qstr;
230
+
231
+ resp = qtest_qmp_eventwait_ref(qts, "NETDEV_STREAM_DISCONNECTED");
232
+ g_assert_nonnull(resp);
233
+ data = qdict_get_qdict(resp, "data");
234
+ g_assert_nonnull(data);
235
+
236
+ qstr = qobject_to(QString, qdict_get(data, "netdev-id"));
237
+ g_assert_nonnull(data);
238
+
239
+ g_assert(!strcmp(qstring_get_str(qstr), id));
240
+ qobject_unref(resp);
241
+}
242
+
243
+static void test_stream_inet_reconnect(void)
244
+{
245
+ QTestState *qts0, *qts1;
246
+ int port;
247
+ SocketAddress *addr;
248
+
249
+ port = inet_get_free_port(false);
250
+ qts0 = qtest_initf("-nodefaults -M none "
251
+ "-netdev stream,id=st0,server=true,addr.type=inet,"
252
+ "addr.ipv4=on,addr.ipv6=off,"
253
+ "addr.host=127.0.0.1,addr.port=%d", port);
254
+
255
+ EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0);
256
+
257
+ qts1 = qtest_initf("-nodefaults -M none "
258
+ "-netdev stream,server=false,id=st0,addr.type=inet,"
259
+ "addr.ipv4=on,addr.ipv6=off,reconnect=1,"
260
+ "addr.host=127.0.0.1,addr.port=%d", port);
261
+
262
+ wait_stream_connected(qts0, "st0", &addr);
263
+ g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_INET);
264
+ g_assert_cmpstr(addr->u.inet.host, ==, "127.0.0.1");
265
+ qapi_free_SocketAddress(addr);
266
+
267
+ /* kill server */
268
+ qtest_quit(qts0);
269
+
270
+ /* check client has been disconnected */
271
+ wait_stream_disconnected(qts1, "st0");
272
+
273
+ /* restart server */
274
+ qts0 = qtest_initf("-nodefaults -M none "
275
+ "-netdev stream,id=st0,server=true,addr.type=inet,"
276
+ "addr.ipv4=on,addr.ipv6=off,"
277
+ "addr.host=127.0.0.1,addr.port=%d", port);
278
+
279
+ /* wait connection events*/
280
+ wait_stream_connected(qts0, "st0", &addr);
281
+ g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_INET);
282
+ g_assert_cmpstr(addr->u.inet.host, ==, "127.0.0.1");
283
+ qapi_free_SocketAddress(addr);
284
+
285
+ wait_stream_connected(qts1, "st0", &addr);
286
+ g_assert_cmpint(addr->type, ==, SOCKET_ADDRESS_TYPE_INET);
287
+ g_assert_cmpstr(addr->u.inet.host, ==, "127.0.0.1");
288
+ g_assert_cmpint(atoi(addr->u.inet.port), ==, port);
289
+ qapi_free_SocketAddress(addr);
290
+
291
+ qtest_quit(qts1);
292
+ qtest_quit(qts0);
293
+}
294
+
295
static void test_stream_inet_ipv6(void)
296
{
297
QTestState *qts0, *qts1;
298
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
299
#ifndef _WIN32
300
qtest_add_func("/netdev/dgram/mcast", test_dgram_mcast);
189
#endif
301
#endif
190
"-netdev vhost-user,id=str,chardev=dev[,vhostforce=on|off]\n"
302
+ qtest_add_func("/netdev/stream/inet/reconnect",
191
" configure a vhost-user network, backed by a chardev 'dev'\n"
303
+ test_stream_inet_reconnect);
192
- "-netdev hubport,id=str,hubid=n\n"
304
}
193
+ "-netdev hubport,id=str,hubid=n[,netdev=nd]\n"
305
if (has_ipv6) {
194
" configure a hub port on QEMU VLAN 'n'\n", QEMU_ARCH_ALL)
306
qtest_add_func("/netdev/stream/inet/ipv6", test_stream_inet_ipv6);
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
--
307
--
216
2.7.4
308
2.7.4
217
218
diff view generated by jsdifflib
1
From: Philippe Mathieu-Daudé <f4bug@amsat.org>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
gently asked by his automatic reply :)
3
VHOST_BACKEND_F_IOTLB_ASID is the feature bit, not the bitmask. Since
4
the device under test also provided VHOST_BACKEND_F_IOTLB_MSG_V2 and
5
VHOST_BACKEND_F_IOTLB_BATCH, this went unnoticed.
4
6
5
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
7
Fixes: c1a1008685 ("vdpa: always start CVQ in SVQ mode if possible")
8
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
9
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
10
Acked-by: Jason Wang <jasowang@redhat.com>
6
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
7
---
12
---
8
MAINTAINERS | 8 ++++----
13
net/vhost-vdpa.c | 2 +-
9
1 file changed, 4 insertions(+), 4 deletions(-)
14
1 file changed, 1 insertion(+), 1 deletion(-)
10
15
11
diff --git a/MAINTAINERS b/MAINTAINERS
16
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
12
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
13
--- a/MAINTAINERS
18
--- a/net/vhost-vdpa.c
14
+++ b/MAINTAINERS
19
+++ b/net/vhost-vdpa.c
15
@@ -XXX,XX +XXX,XX @@ F: hw/scsi/mfi.h
20
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_net_cvq_start(NetClientState *nc)
16
F: tests/megasas-test.c
21
g_strerror(errno), errno);
17
22
return -1;
18
Network packet abstractions
23
}
19
-M: Dmitry Fleytman <dmitry@daynix.com>
24
- if (!(backend_features & VHOST_BACKEND_F_IOTLB_ASID) ||
20
+M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
25
+ if (!(backend_features & BIT_ULL(VHOST_BACKEND_F_IOTLB_ASID)) ||
21
S: Maintained
26
!vhost_vdpa_net_valid_svq_features(v->dev->features, NULL)) {
22
F: include/net/eth.h
27
return 0;
23
F: net/eth.c
28
}
24
@@ -XXX,XX +XXX,XX @@ F: hw/net/net_rx_pkt*
25
F: hw/net/net_tx_pkt*
26
27
Vmware
28
-M: Dmitry Fleytman <dmitry@daynix.com>
29
+M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
30
S: Maintained
31
F: hw/net/vmxnet*
32
F: hw/scsi/vmw_pvscsi*
33
@@ -XXX,XX +XXX,XX @@ F: hw/mem/nvdimm.c
34
F: include/hw/mem/nvdimm.h
35
36
e1000x
37
-M: Dmitry Fleytman <dmitry@daynix.com>
38
+M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
39
S: Maintained
40
F: hw/net/e1000x*
41
42
e1000e
43
-M: Dmitry Fleytman <dmitry@daynix.com>
44
+M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
45
S: Maintained
46
F: hw/net/e1000e*
47
48
--
29
--
49
2.7.4
30
2.7.4
50
31
51
32
diff view generated by jsdifflib