1
The following changes since commit e607bbee553cfe73072870cef458cfa4e78133e2:
1
The following changes since commit 13356edb87506c148b163b8c7eb0695647d00c2a:
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 'block-pull-request' of https://gitlab.com/stefanha/qemu into staging (2023-01-24 09:45:33 +0000)
4
4
5
are available in the git repository at:
5
are available in the git repository at:
6
6
7
https://github.com/jasowang/qemu.git tags/net-pull-request
7
https://github.com/jasowang/qemu.git tags/net-pull-request
8
8
9
for you to fetch changes up to bf4835a4d5338bb7424827715df22570a8adc67c:
9
for you to fetch changes up to 2bd492bca521ee8594f1d5db8dc9aac126fc4f85:
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-02 14:16:48 +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 (2):
29
tests/qtest: netdev: test stream and dgram backends
30
net: stream: add a new option to automatically reconnect
31
32
Qiang Liu (2):
33
hw/net/lan9118: log [read|write]b when mode_16bit is enabled rather than abort
34
hw/net/can/xlnx-zynqmp-can: fix assertion failures in transfer_fifo()
22
35
23
Thomas Huth (3):
36
Thomas Huth (3):
24
net: Allow hubports to connect to other netdevs
37
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'
38
net: Restore printing of the help text with "-nic help"
26
qemu-doc: Get rid of "vlan=X" example in the documentation
39
net: Replace "Supported NIC models" with "Available NIC models"
27
40
28
MAINTAINERS | 8 +-
41
hw/net/can/xlnx-zynqmp-can.c | 9 +-
29
hmp-commands.hx | 4 +-
42
hw/net/lan9118.c | 17 +-
30
net/colo-compare.c | 411 +++++++++++++++++++++++++++++++++--------------------
43
hw/net/vmxnet3.c | 2 +-
31
net/colo.c | 9 ++
44
hw/pci/pci.c | 29 +--
32
net/colo.h | 15 ++
45
include/net/net.h | 14 ++
33
net/hub.c | 27 +++-
46
net/l2tpv3.c | 2 +-
34
net/hub.h | 3 +-
47
net/net.c | 50 +++-
35
net/net.c | 2 +-
48
net/stream.c | 53 ++++-
36
net/slirp.c | 33 +++--
49
net/vhost-vdpa.c | 2 +-
37
net/trace-events | 2 +-
50
net/vmnet-common.m | 48 +++-
38
qapi/net.json | 4 +-
51
net/vmnet_int.h | 2 +
39
qemu-options.hx | 12 +-
52
qapi/net.json | 7 +-
40
12 files changed, 347 insertions(+), 183 deletions(-)
53
qemu-options.hx | 6 +-
54
tests/qtest/meson.build | 2 +
55
tests/qtest/netdev-socket.c | 549 +++++++++++++++++++++++++++++++++++++++++++
56
15 files changed, 730 insertions(+), 62 deletions(-)
57
create mode 100644 tests/qtest/netdev-socket.c
41
58
42
59
60
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
New patch
1
From: Thomas Huth <thuth@redhat.com>
1
2
3
Running QEMU with "-nic help" used to work in QEMU 5.2 and earlier versions
4
(it showed the available netdev backends), but this feature got broken during
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.
8
9
Fixes: ad6f932fe8 ("net: do not exit on "netdev_add help" monitor command")
10
Signed-off-by: Thomas Huth <thuth@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
13
net/net.c | 14 ++++++++++++--
14
1 file changed, 12 insertions(+), 2 deletions(-)
15
16
diff --git a/net/net.c b/net/net.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/net/net.c
19
+++ b/net/net.c
20
@@ -XXX,XX +XXX,XX @@ static int net_param_nic(void *dummy, QemuOpts *opts, Error **errp)
21
const char *type;
22
23
type = qemu_opt_get(opts, "type");
24
- if (type && g_str_equal(type, "none")) {
25
- return 0; /* Nothing to do, default_net is cleared in vl.c */
26
+ if (type) {
27
+ if (g_str_equal(type, "none")) {
28
+ return 0; /* Nothing to do, default_net is cleared in vl.c */
29
+ }
30
+ if (is_help_option(type)) {
31
+ GPtrArray *nic_models = qemu_get_nic_models(TYPE_DEVICE);
32
+ show_netdevs();
33
+ printf("\n");
34
+ qemu_show_nic_models(type, (const char **)nic_models->pdata);
35
+ g_ptr_array_free(nic_models, true);
36
+ exit(0);
37
+ }
38
}
39
40
idx = nic_get_free_idx();
41
--
42
2.7.4
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
Packet size some time different or when network is busy.
3
This patch replaces hw_error to guest error log for [read|write]b
4
Based on same payload size, but TCP protocol can not
4
accesses when mode_16bit is enabled. This avoids aborting qemu.
5
guarantee send the same one packet in the same way,
6
5
7
like that:
6
Fixes: 1248f8d4cbc3 ("hw/lan9118: Add basic 16-bit mode support.")
8
We send this payload:
7
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1433
9
------------------------------
8
Reported-by: Qiang Liu <cyruscyliu@gmail.com>
10
| header |1|2|3|4|5|6|7|8|9|0|
9
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
11
------------------------------
10
Signed-off-by: Qiang Liu <cyruscyliu@gmail.com>
12
11
Suggested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
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>
12
Signed-off-by: Jason Wang <jasowang@redhat.com>
70
---
13
---
71
net/colo-compare.c | 343 +++++++++++++++++++++++++++++++++++------------------
14
hw/net/lan9118.c | 17 ++++++++---------
72
net/colo.c | 9 ++
15
1 file changed, 8 insertions(+), 9 deletions(-)
73
net/colo.h | 15 +++
74
net/trace-events | 2 +-
75
4 files changed, 250 insertions(+), 119 deletions(-)
76
16
77
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
78
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
79
--- a/net/colo-compare.c
19
--- a/hw/net/lan9118.c
80
+++ b/net/colo-compare.c
20
+++ b/hw/net/lan9118.c
81
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@
82
#define COMPARE_READ_LEN_MAX NET_BUFSIZE
22
#include "migration/vmstate.h"
83
#define MAX_QUEUE_SIZE 1024
23
#include "net/net.h"
84
24
#include "net/eth.h"
85
+#define COLO_COMPARE_FREE_PRIMARY 0x01
25
-#include "hw/hw.h"
86
+#define COLO_COMPARE_FREE_SECONDARY 0x02
26
#include "hw/irq.h"
87
+
27
#include "hw/net/lan9118.h"
88
/* TODO: Should be configurable */
28
#include "hw/ptimer.h"
89
#define REGULAR_PACKET_CHECK_MS 3000
29
@@ -XXX,XX +XXX,XX @@
90
30
#ifdef DEBUG_LAN9118
91
@@ -XXX,XX +XXX,XX @@ static gint seq_sorter(Packet *a, Packet *b, gpointer data)
31
#define DPRINTF(fmt, ...) \
92
return ntohl(atcp->th_seq) - ntohl(btcp->th_seq);
32
do { printf("lan9118: " fmt , ## __VA_ARGS__); } while (0)
33
-#define BADF(fmt, ...) \
34
-do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
35
#else
36
#define DPRINTF(fmt, ...) do {} while(0)
37
-#define BADF(fmt, ...) \
38
-do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
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;
50
}
93
}
51
}
94
52
@@ -XXX,XX +XXX,XX @@ static void do_phy_write(lan9118_state *s, int reg, uint32_t val)
95
+static void fill_pkt_tcp_info(void *data, uint32_t *max_ack)
53
phy_update_irq(s);
96
+{
54
break;
97
+ Packet *pkt = data;
55
default:
98
+ struct tcphdr *tcphd;
56
- BADF("PHY write reg %d = 0x%04x\n", reg, val);
99
+
57
+ qemu_log_mask(LOG_GUEST_ERROR,
100
+ tcphd = (struct tcphdr *)pkt->transport_header;
58
+ "do_phy_write: PHY write reg %d = 0x%04x\n", reg, val);
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
}
59
}
127
60
}
128
if (mode == PRIMARY_IN) {
61
129
- if (!colo_insert_packet(&conn->primary_list, pkt)) {
62
@@ -XXX,XX +XXX,XX @@ static void lan9118_16bit_mode_write(void *opaque, hwaddr offset,
130
+ if (!colo_insert_packet(&conn->primary_list, pkt, &conn->pack)) {
63
return;
131
error_report("colo compare primary queue size too big,"
64
}
132
"drop packet");
65
133
}
66
- hw_error("lan9118_write: Bad size 0x%x\n", size);
134
} else {
67
+ qemu_log_mask(LOG_GUEST_ERROR,
135
- if (!colo_insert_packet(&conn->secondary_list, pkt)) {
68
+ "lan9118_16bit_mode_write: Bad size 0x%x\n", size);
136
+ if (!colo_insert_packet(&conn->secondary_list, pkt, &conn->sack)) {
69
}
137
error_report("colo compare secondary queue size too big,"
70
138
"drop packet");
71
static uint64_t lan9118_readl(void *opaque, hwaddr offset,
139
}
72
@@ -XXX,XX +XXX,XX @@ static uint64_t lan9118_16bit_mode_read(void *opaque, hwaddr offset,
140
@@ -XXX,XX +XXX,XX @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
73
return lan9118_readl(opaque, offset, size);
74
}
75
76
- hw_error("lan9118_read: Bad size 0x%x\n", size);
77
+ qemu_log_mask(LOG_GUEST_ERROR,
78
+ "lan9118_16bit_mode_read: Bad size 0x%x\n", size);
141
return 0;
79
return 0;
142
}
80
}
143
81
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
+ }
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
+ }
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
}
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
--
82
--
588
2.7.4
83
2.7.4
589
84
590
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: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
1
From: Laurent Vivier <lvivier@redhat.com>
2
2
3
Modified the function colo_packet_compare_common to prepare for the
3
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
4
tcp packet comparison in the next patch.
4
Acked-by: Michael S. Tsirkin <mst@redhat.com>
5
5
Acked-by: Thomas Huth <thuth@redhat.com>
6
Cc: Zhang Chen <zhangckid@gmail.com>
7
Cc: Li Zhijian <lizhijian@cn.fujitsu.com>
8
Cc: Jason Wang <jasowang@redhat.com>
9
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>
6
Signed-off-by: Jason Wang <jasowang@redhat.com>
15
---
7
---
16
net/colo-compare.c | 88 +++++++++++++++++++++++++++---------------------------
8
tests/qtest/meson.build | 2 +
17
1 file changed, 44 insertions(+), 44 deletions(-)
9
tests/qtest/netdev-socket.c | 448 ++++++++++++++++++++++++++++++++++++++++++++
10
2 files changed, 450 insertions(+)
11
create mode 100644 tests/qtest/netdev-socket.c
18
12
19
diff --git a/net/colo-compare.c b/net/colo-compare.c
13
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
20
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
21
--- a/net/colo-compare.c
15
--- a/tests/qtest/meson.build
22
+++ b/net/colo-compare.c
16
+++ b/tests/qtest/meson.build
23
@@ -XXX,XX +XXX,XX @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
17
@@ -XXX,XX +XXX,XX @@ qtests_generic = [
24
* return: 0 means packet same
18
'test-hmp',
25
* > 0 || < 0 means packet different
19
'qos-test',
26
*/
20
'readconfig-test',
27
-static int colo_packet_compare_common(Packet *ppkt,
21
+ 'netdev-socket',
28
- Packet *spkt,
22
]
29
- int poffset,
23
if config_host.has_key('CONFIG_MODULES')
30
- int soffset)
24
qtests_generic += [ 'modules-test' ]
31
+static int colo_compare_packet_payload(Packet *ppkt,
25
@@ -XXX,XX +XXX,XX @@ qtests = {
32
+ Packet *spkt,
26
'tpm-tis-device-swtpm-test': [io, tpmemu_files, 'tpm-tis-util.c'],
33
+ uint16_t poffset,
27
'tpm-tis-device-test': [io, tpmemu_files, 'tpm-tis-util.c'],
34
+ uint16_t soffset,
28
'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'),
35
+ uint16_t len)
29
+ 'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'),
36
+
37
{
38
if (trace_event_get_state_backends(TRACE_COLO_COMPARE_MISCOMPARE)) {
39
char pri_ip_src[20], pri_ip_dst[20], sec_ip_src[20], sec_ip_dst[20];
40
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_common(Packet *ppkt,
41
sec_ip_src, sec_ip_dst);
42
}
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
}
30
}
57
31
58
/*
32
gvnc = dependency('gvnc-1.0', required: false)
59
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt)
33
diff --git a/tests/qtest/netdev-socket.c b/tests/qtest/netdev-socket.c
60
* the secondary guest's timestamp. COLO just focus on payload,
34
new file mode 100644
61
* so we just need skip this field.
35
index XXXXXXX..XXXXXXX
62
*/
36
--- /dev/null
63
- if (ptcp->th_off > 5) {
37
+++ b/tests/qtest/netdev-socket.c
64
- ptrdiff_t ptcp_offset, stcp_offset;
38
@@ -XXX,XX +XXX,XX @@
65
39
+/*
66
- ptcp_offset = ppkt->transport_header - (uint8_t *)ppkt->data
40
+ * QTest testcase for netdev stream and dgram
67
- + (ptcp->th_off * 4) - ppkt->vnet_hdr_len;
41
+ *
68
- stcp_offset = spkt->transport_header - (uint8_t *)spkt->data
42
+ * Copyright (c) 2022 Red Hat, Inc.
69
- + (stcp->th_off * 4) - spkt->vnet_hdr_len;
43
+ *
70
+ ptrdiff_t ptcp_offset, stcp_offset;
44
+ * SPDX-License-Identifier: GPL-2.0-or-later
71
45
+ */
72
- /*
46
+
73
- * When network is busy, some tcp options(like sack) will unpredictable
47
+#include "qemu/osdep.h"
74
- * occur in primary side or secondary side. it will make packet size
48
+#include "qemu/sockets.h"
75
- * not same, but the two packet's payload is identical. colo just
49
+#include <glib/gstdio.h>
76
- * care about packet payload, so we skip the option field.
50
+#include "../unit/socket-helpers.h"
77
- */
51
+#include "libqtest.h"
78
- res = colo_packet_compare_common(ppkt, spkt, ptcp_offset, stcp_offset);
52
+
79
- } else if (ptcp->th_sum == stcp->th_sum) {
53
+#define CONNECTION_TIMEOUT 5
80
- res = colo_packet_compare_common(ppkt, spkt, ETH_HLEN, ETH_HLEN);
54
+
81
+ ptcp_offset = ppkt->transport_header - (uint8_t *)ppkt->data
55
+#define EXPECT_STATE(q, e, t) \
82
+ + (ptcp->th_off << 2) - ppkt->vnet_hdr_len;
56
+do { \
83
+ stcp_offset = spkt->transport_header - (uint8_t *)spkt->data
57
+ char *resp = NULL; \
84
+ + (stcp->th_off << 2) - spkt->vnet_hdr_len;
58
+ g_test_timer_start(); \
85
+ if (ppkt->size - ptcp_offset == spkt->size - stcp_offset) {
59
+ do { \
86
+ res = colo_compare_packet_payload(ppkt, spkt,
60
+ g_free(resp); \
87
+ ptcp_offset, stcp_offset,
61
+ resp = qtest_hmp(q, "info network"); \
88
+ ppkt->size - ptcp_offset);
62
+ if (t) { \
89
} else {
63
+ strrchr(resp, t)[0] = 0; \
90
+ trace_colo_compare_main("TCP: payload size of packets are different");
64
+ } \
91
res = -1;
65
+ if (g_str_equal(resp, e)) { \
92
}
66
+ break; \
93
67
+ } \
94
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt)
68
+ } while (g_test_timer_elapsed() < CONNECTION_TIMEOUT); \
95
*/
69
+ g_assert_cmpstr(resp, ==, e); \
96
static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
70
+ g_free(resp); \
97
{
71
+} while (0)
98
- int ret;
72
+
99
- int network_header_length = ppkt->ip->ip_hl * 4;
73
+static gchar *tmpdir;
100
+ uint16_t network_header_length = ppkt->ip->ip_hl << 2;
74
+
101
+ uint16_t offset = network_header_length + ETH_HLEN + ppkt->vnet_hdr_len;
75
+static int inet_get_free_port_socket_ipv4(int sock)
102
76
+{
103
trace_colo_compare_main("compare udp");
77
+ struct sockaddr_in addr;
104
78
+ socklen_t len;
105
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
79
+
106
* other field like TOS,TTL,IP Checksum. we only need to compare
80
+ memset(&addr, 0, sizeof(addr));
107
* the ip payload here.
81
+ addr.sin_family = AF_INET;
108
*/
82
+ addr.sin_addr.s_addr = INADDR_ANY;
109
- ret = colo_packet_compare_common(ppkt, spkt,
83
+ addr.sin_port = 0;
110
- network_header_length + ETH_HLEN,
84
+ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
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;
85
+ return -1;
117
+ }
86
+ }
118
+ if (colo_compare_packet_payload(ppkt, spkt, offset, offset,
87
+
119
+ ppkt->size - offset)) {
88
+ len = sizeof(addr);
120
trace_colo_compare_udp_miscompare("primary pkt size", ppkt->size);
89
+ if (getsockname(sock, (struct sockaddr *)&addr, &len) < 0) {
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;
90
+ return -1;
128
+ } else {
91
+ }
129
+ return 0;
92
+
130
}
93
+ return ntohs(addr.sin_port);
131
-
94
+}
132
- return ret;
95
+
133
}
96
+static int inet_get_free_port_socket_ipv6(int sock)
134
97
+{
135
/*
98
+ struct sockaddr_in6 addr;
136
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
99
+ socklen_t len;
137
*/
100
+
138
static int colo_packet_compare_icmp(Packet *spkt, Packet *ppkt)
101
+ memset(&addr, 0, sizeof(addr));
139
{
102
+ addr.sin6_family = AF_INET6;
140
- int network_header_length = ppkt->ip->ip_hl * 4;
103
+ addr.sin6_addr = in6addr_any;
141
+ uint16_t network_header_length = ppkt->ip->ip_hl << 2;
104
+ addr.sin6_port = 0;
142
+ uint16_t offset = network_header_length + ETH_HLEN + ppkt->vnet_hdr_len;
105
+ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
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;
106
+ return -1;
156
+ }
107
+ }
157
+ if (colo_compare_packet_payload(ppkt, spkt, offset, offset,
108
+
158
+ ppkt->size - offset)) {
109
+ len = sizeof(addr);
159
trace_colo_compare_icmp_miscompare("primary pkt size",
110
+ if (getsockname(sock, (struct sockaddr *)&addr, &len) < 0) {
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;
111
+ return -1;
179
+ }
112
+ }
180
+ return colo_compare_packet_payload(ppkt, spkt, offset, offset,
113
+
181
+ ppkt->size - offset);
114
+ return ntohs(addr.sin6_port);
182
}
115
+}
183
116
+
184
static int colo_old_packet_check_one(Packet *pkt, int64_t *check_time)
117
+static int inet_get_free_port_multiple(int nb, int *port, bool ipv6)
118
+{
119
+ int sock[nb];
120
+ int i;
121
+
122
+ for (i = 0; i < nb; i++) {
123
+ sock[i] = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
124
+ if (sock[i] < 0) {
125
+ break;
126
+ }
127
+ port[i] = ipv6 ? inet_get_free_port_socket_ipv6(sock[i]) :
128
+ inet_get_free_port_socket_ipv4(sock[i]);
129
+ if (port[i] == -1) {
130
+ break;
131
+ }
132
+ }
133
+
134
+ nb = i;
135
+ for (i = 0; i < nb; i++) {
136
+ closesocket(sock[i]);
137
+ }
138
+
139
+ return nb;
140
+}
141
+
142
+static int inet_get_free_port(bool ipv6)
143
+{
144
+ int nb, port;
145
+
146
+ nb = inet_get_free_port_multiple(1, &port, ipv6);
147
+ g_assert_cmpint(nb, ==, 1);
148
+
149
+ return port;
150
+}
151
+
152
+static void test_stream_inet_ipv4(void)
153
+{
154
+ QTestState *qts0, *qts1;
155
+ char *expect;
156
+ int port;
157
+
158
+ port = inet_get_free_port(false);
159
+ qts0 = qtest_initf("-nodefaults -M none "
160
+ "-netdev stream,id=st0,server=true,addr.type=inet,"
161
+ "addr.ipv4=on,addr.ipv6=off,"
162
+ "addr.host=127.0.0.1,addr.port=%d", port);
163
+
164
+ EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0);
165
+
166
+ qts1 = qtest_initf("-nodefaults -M none "
167
+ "-netdev stream,server=false,id=st0,addr.type=inet,"
168
+ "addr.ipv4=on,addr.ipv6=off,"
169
+ "addr.host=127.0.0.1,addr.port=%d", port);
170
+
171
+ expect = g_strdup_printf("st0: index=0,type=stream,tcp:127.0.0.1:%d\r\n",
172
+ port);
173
+ EXPECT_STATE(qts1, expect, 0);
174
+ g_free(expect);
175
+
176
+ /* the port is unknown, check only the address */
177
+ EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:127.0.0.1", ':');
178
+
179
+ qtest_quit(qts1);
180
+ qtest_quit(qts0);
181
+}
182
+
183
+static void test_stream_inet_ipv6(void)
184
+{
185
+ QTestState *qts0, *qts1;
186
+ char *expect;
187
+ int port;
188
+
189
+ port = inet_get_free_port(true);
190
+ qts0 = qtest_initf("-nodefaults -M none "
191
+ "-netdev stream,id=st0,server=true,addr.type=inet,"
192
+ "addr.ipv4=off,addr.ipv6=on,"
193
+ "addr.host=::1,addr.port=%d", port);
194
+
195
+ EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0);
196
+
197
+ qts1 = qtest_initf("-nodefaults -M none "
198
+ "-netdev stream,server=false,id=st0,addr.type=inet,"
199
+ "addr.ipv4=off,addr.ipv6=on,"
200
+ "addr.host=::1,addr.port=%d", port);
201
+
202
+ expect = g_strdup_printf("st0: index=0,type=stream,tcp:::1:%d\r\n",
203
+ port);
204
+ EXPECT_STATE(qts1, expect, 0);
205
+ g_free(expect);
206
+
207
+ /* the port is unknown, check only the address */
208
+ EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:::1", ':');
209
+
210
+ qtest_quit(qts1);
211
+ qtest_quit(qts0);
212
+}
213
+
214
+static void test_stream_unix(void)
215
+{
216
+ QTestState *qts0, *qts1;
217
+ char *expect;
218
+ gchar *path;
219
+
220
+ path = g_strconcat(tmpdir, "/stream_unix", NULL);
221
+
222
+ qts0 = qtest_initf("-nodefaults -M none "
223
+ "-netdev stream,id=st0,server=true,"
224
+ "addr.type=unix,addr.path=%s,",
225
+ path);
226
+
227
+ EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0);
228
+
229
+ qts1 = qtest_initf("-nodefaults -M none "
230
+ "-netdev stream,id=st0,server=false,"
231
+ "addr.type=unix,addr.path=%s",
232
+ path);
233
+
234
+ expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path);
235
+ EXPECT_STATE(qts1, expect, 0);
236
+ EXPECT_STATE(qts0, expect, 0);
237
+ g_free(expect);
238
+ g_free(path);
239
+
240
+ qtest_quit(qts1);
241
+ qtest_quit(qts0);
242
+}
243
+
244
+#ifdef CONFIG_LINUX
245
+static void test_stream_unix_abstract(void)
246
+{
247
+ QTestState *qts0, *qts1;
248
+ char *expect;
249
+ gchar *path;
250
+
251
+ path = g_strconcat(tmpdir, "/stream_unix_abstract", NULL);
252
+
253
+ qts0 = qtest_initf("-nodefaults -M none "
254
+ "-netdev stream,id=st0,server=true,"
255
+ "addr.type=unix,addr.path=%s,"
256
+ "addr.abstract=on",
257
+ path);
258
+
259
+ EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0);
260
+
261
+ qts1 = qtest_initf("-nodefaults -M none "
262
+ "-netdev stream,id=st0,server=false,"
263
+ "addr.type=unix,addr.path=%s,addr.abstract=on",
264
+ path);
265
+
266
+ expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path);
267
+ EXPECT_STATE(qts1, expect, 0);
268
+ EXPECT_STATE(qts0, expect, 0);
269
+ g_free(expect);
270
+ g_free(path);
271
+
272
+ qtest_quit(qts1);
273
+ qtest_quit(qts0);
274
+}
275
+#endif
276
+
277
+#ifndef _WIN32
278
+static void test_stream_fd(void)
279
+{
280
+ QTestState *qts0, *qts1;
281
+ int sock[2];
282
+ int ret;
283
+
284
+ ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, sock);
285
+ g_assert_true(ret == 0);
286
+
287
+ qts0 = qtest_initf("-nodefaults -M none "
288
+ "-netdev stream,id=st0,addr.type=fd,addr.str=%d",
289
+ sock[0]);
290
+
291
+ EXPECT_STATE(qts0, "st0: index=0,type=stream,unix:\r\n", 0);
292
+
293
+ qts1 = qtest_initf("-nodefaults -M none "
294
+ "-netdev stream,id=st0,addr.type=fd,addr.str=%d",
295
+ sock[1]);
296
+
297
+ EXPECT_STATE(qts1, "st0: index=0,type=stream,unix:\r\n", 0);
298
+ EXPECT_STATE(qts0, "st0: index=0,type=stream,unix:\r\n", 0);
299
+
300
+ qtest_quit(qts1);
301
+ qtest_quit(qts0);
302
+
303
+ closesocket(sock[0]);
304
+ closesocket(sock[1]);
305
+}
306
+#endif
307
+
308
+static void test_dgram_inet(void)
309
+{
310
+ QTestState *qts0, *qts1;
311
+ char *expect;
312
+ int port[2];
313
+ int nb;
314
+
315
+ nb = inet_get_free_port_multiple(2, port, false);
316
+ g_assert_cmpint(nb, ==, 2);
317
+
318
+ qts0 = qtest_initf("-nodefaults -M none "
319
+ "-netdev dgram,id=st0,"
320
+ "local.type=inet,local.host=127.0.0.1,local.port=%d,"
321
+ "remote.type=inet,remote.host=127.0.0.1,remote.port=%d",
322
+ port[0], port[1]);
323
+
324
+ expect = g_strdup_printf("st0: index=0,type=dgram,"
325
+ "udp=127.0.0.1:%d/127.0.0.1:%d\r\n",
326
+ port[0], port[1]);
327
+ EXPECT_STATE(qts0, expect, 0);
328
+ g_free(expect);
329
+
330
+ qts1 = qtest_initf("-nodefaults -M none "
331
+ "-netdev dgram,id=st0,"
332
+ "local.type=inet,local.host=127.0.0.1,local.port=%d,"
333
+ "remote.type=inet,remote.host=127.0.0.1,remote.port=%d",
334
+ port[1], port[0]);
335
+
336
+ expect = g_strdup_printf("st0: index=0,type=dgram,"
337
+ "udp=127.0.0.1:%d/127.0.0.1:%d\r\n",
338
+ port[1], port[0]);
339
+ EXPECT_STATE(qts1, expect, 0);
340
+ g_free(expect);
341
+
342
+ qtest_quit(qts1);
343
+ qtest_quit(qts0);
344
+}
345
+
346
+#ifndef _WIN32
347
+static void test_dgram_mcast(void)
348
+{
349
+ QTestState *qts;
350
+
351
+ qts = qtest_initf("-nodefaults -M none "
352
+ "-netdev dgram,id=st0,"
353
+ "remote.type=inet,remote.host=230.0.0.1,remote.port=1234");
354
+
355
+ EXPECT_STATE(qts, "st0: index=0,type=dgram,mcast=230.0.0.1:1234\r\n", 0);
356
+
357
+ qtest_quit(qts);
358
+}
359
+
360
+static void test_dgram_unix(void)
361
+{
362
+ QTestState *qts0, *qts1;
363
+ char *expect;
364
+ gchar *path0, *path1;
365
+
366
+ path0 = g_strconcat(tmpdir, "/dgram_unix0", NULL);
367
+ path1 = g_strconcat(tmpdir, "/dgram_unix1", NULL);
368
+
369
+ qts0 = qtest_initf("-nodefaults -M none "
370
+ "-netdev dgram,id=st0,local.type=unix,local.path=%s,"
371
+ "remote.type=unix,remote.path=%s",
372
+ path0, path1);
373
+
374
+ expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n",
375
+ path0, path1);
376
+ EXPECT_STATE(qts0, expect, 0);
377
+ g_free(expect);
378
+
379
+ qts1 = qtest_initf("-nodefaults -M none "
380
+ "-netdev dgram,id=st0,local.type=unix,local.path=%s,"
381
+ "remote.type=unix,remote.path=%s",
382
+ path1, path0);
383
+
384
+
385
+ expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n",
386
+ path1, path0);
387
+ EXPECT_STATE(qts1, expect, 0);
388
+ g_free(expect);
389
+
390
+ unlink(path0);
391
+ g_free(path0);
392
+ unlink(path1);
393
+ g_free(path1);
394
+
395
+ qtest_quit(qts1);
396
+ qtest_quit(qts0);
397
+}
398
+
399
+static void test_dgram_fd(void)
400
+{
401
+ QTestState *qts0, *qts1;
402
+ char *expect;
403
+ int ret;
404
+ int sv[2];
405
+
406
+ ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, sv);
407
+ g_assert_cmpint(ret, !=, -1);
408
+
409
+ qts0 = qtest_initf("-nodefaults -M none "
410
+ "-netdev dgram,id=st0,local.type=fd,local.str=%d",
411
+ sv[0]);
412
+
413
+ expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[0]);
414
+ EXPECT_STATE(qts0, expect, 0);
415
+ g_free(expect);
416
+
417
+ qts1 = qtest_initf("-nodefaults -M none "
418
+ "-netdev dgram,id=st0,local.type=fd,local.str=%d",
419
+ sv[1]);
420
+
421
+
422
+ expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[1]);
423
+ EXPECT_STATE(qts1, expect, 0);
424
+ g_free(expect);
425
+
426
+ qtest_quit(qts1);
427
+ qtest_quit(qts0);
428
+
429
+ closesocket(sv[0]);
430
+ closesocket(sv[1]);
431
+}
432
+#endif
433
+
434
+int main(int argc, char **argv)
435
+{
436
+ int ret;
437
+ bool has_ipv4, has_ipv6, has_afunix;
438
+ g_autoptr(GError) err = NULL;
439
+
440
+ socket_init();
441
+ g_test_init(&argc, &argv, NULL);
442
+
443
+ if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
444
+ g_error("socket_check_protocol_support() failed\n");
445
+ }
446
+
447
+ tmpdir = g_dir_make_tmp("netdev-socket.XXXXXX", &err);
448
+ if (tmpdir == NULL) {
449
+ g_error("Can't create temporary directory in %s: %s",
450
+ g_get_tmp_dir(), err->message);
451
+ }
452
+
453
+ if (has_ipv4) {
454
+ qtest_add_func("/netdev/stream/inet/ipv4", test_stream_inet_ipv4);
455
+ qtest_add_func("/netdev/dgram/inet", test_dgram_inet);
456
+#ifndef _WIN32
457
+ qtest_add_func("/netdev/dgram/mcast", test_dgram_mcast);
458
+#endif
459
+ }
460
+ if (has_ipv6) {
461
+ qtest_add_func("/netdev/stream/inet/ipv6", test_stream_inet_ipv6);
462
+ }
463
+
464
+ socket_check_afunix_support(&has_afunix);
465
+ if (has_afunix) {
466
+#ifndef _WIN32
467
+ qtest_add_func("/netdev/dgram/unix", test_dgram_unix);
468
+#endif
469
+ qtest_add_func("/netdev/stream/unix", test_stream_unix);
470
+#ifdef CONFIG_LINUX
471
+ qtest_add_func("/netdev/stream/unix/abstract",
472
+ test_stream_unix_abstract);
473
+#endif
474
+#ifndef _WIN32
475
+ qtest_add_func("/netdev/stream/fd", test_stream_fd);
476
+ qtest_add_func("/netdev/dgram/fd", test_dgram_fd);
477
+#endif
478
+ }
479
+
480
+ ret = g_test_run();
481
+
482
+ g_rmdir(tmpdir);
483
+ g_free(tmpdir);
484
+
485
+ return ret;
486
+}
185
--
487
--
186
2.7.4
488
2.7.4
187
188
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 5
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