1
The following changes since commit e607bbee553cfe73072870cef458cfa4e78133e2:
1
The following changes since commit 344744e148e6e865f5a57e745b02a87e5ea534ad:
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 'dump-pull-request' of https://gitlab.com/marcandre.lureau/qemu into staging (2022-10-26 10:53:49 -0400)
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 e506fee8b1e092f6ac6f9459bf6a35b807644ad2:
10
10
11
MAINTAINERS: update Dmitry Fleytman email (2018-01-29 16:05:38 +0800)
11
net: stream: add QAPI events to report connection state (2022-10-28 13:28:52 +0800)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
14
15
----------------------------------------------------------------
15
----------------------------------------------------------------
16
Mao Zhongyi (2):
16
Daniel P. Berrangé (1):
17
colo: modified the payload compare function
17
net: improve error message for missing netdev backend
18
colo: compare the packet based on the tcp sequence number
19
18
20
Philippe Mathieu-Daudé (1):
19
Eugenio Pérez (6):
21
MAINTAINERS: update Dmitry Fleytman email
20
vdpa: Delete duplicated vdpa_feature_bits entry
21
vdpa: Remove shadow CVQ command check
22
vhost: allocate event_idx fields on vring
23
vhost: toggle device callbacks using used event idx
24
vhost: use avail event idx on vhost_svq_kick
25
vhost: Accept event idx flag
22
26
23
Thomas Huth (3):
27
Laurent Vivier (16):
24
net: Allow hubports to connect to other netdevs
28
virtio-net: fix bottom-half packet TX on asynchronous completion
25
net: Allow netdevs to be used with 'hostfwd_add' and 'hostfwd_remove'
29
virtio-net: fix TX timer with tx_burst
26
qemu-doc: Get rid of "vlan=X" example in the documentation
30
net: introduce convert_host_port()
31
net: remove the @errp argument of net_client_inits()
32
net: simplify net_client_parse() error management
33
qapi: net: introduce a way to bypass qemu_opts_parse_noisily()
34
net: introduce qemu_set_info_str() function
35
qapi: net: add stream and dgram netdevs
36
net: stream: add unix socket
37
net: dgram: make dgram_dst generic
38
net: dgram: move mcast specific code from net_socket_fd_init_dgram()
39
net: dgram: add unix socket
40
qemu-sockets: move and rename SocketAddress_to_str()
41
qemu-sockets: update socket_uri() and socket_parse() to be consistent
42
net: stream: move to QIO to enable additional parameters
43
net: stream: add QAPI events to report connection state
27
44
28
MAINTAINERS | 8 +-
45
Si-Wei Liu (1):
29
hmp-commands.hx | 4 +-
46
vhost-vdpa: allow passing opened vhostfd to vhost-vdpa
30
net/colo-compare.c | 411 +++++++++++++++++++++++++++++++++--------------------
47
31
net/colo.c | 9 ++
48
Stefano Brivio (2):
32
net/colo.h | 15 ++
49
net: socket: Don't ignore EINVAL on netdev socket connection
33
net/hub.c | 27 +++-
50
net: stream: Don't ignore EINVAL on netdev socket connection
34
net/hub.h | 3 +-
51
35
net/net.c | 2 +-
52
hmp-commands.hx | 2 +-
36
net/slirp.c | 33 +++--
53
hw/net/virtio-net.c | 59 +++-
37
net/trace-events | 2 +-
54
hw/net/xen_nic.c | 5 +-
38
qapi/net.json | 4 +-
55
hw/virtio/vhost-shadow-virtqueue.c | 39 ++-
39
qemu-options.hx | 12 +-
56
include/net/net.h | 7 +-
40
12 files changed, 347 insertions(+), 183 deletions(-)
57
include/qemu/sockets.h | 4 +-
58
monitor/hmp-cmds.c | 23 +-
59
net/clients.h | 6 +
60
net/dgram.c | 623 +++++++++++++++++++++++++++++++++++++
61
net/hub.c | 2 +
62
net/l2tpv3.c | 3 +-
63
net/meson.build | 2 +
64
net/net.c | 204 ++++++++----
65
net/slirp.c | 5 +-
66
net/socket.c | 36 +--
67
net/stream.c | 386 +++++++++++++++++++++++
68
net/tap-win32.c | 3 +-
69
net/tap.c | 13 +-
70
net/vde.c | 3 +-
71
net/vhost-user.c | 3 +-
72
net/vhost-vdpa.c | 76 ++---
73
qapi/net.json | 118 ++++++-
74
qemu-options.hx | 20 +-
75
softmmu/vl.c | 16 +-
76
util/qemu-sockets.c | 25 ++
77
25 files changed, 1473 insertions(+), 210 deletions(-)
78
create mode 100644 net/dgram.c
79
create mode 100644 net/stream.c
41
80
42
81
diff view generated by jsdifflib
New patch
1
From: Laurent Vivier <lvivier@redhat.com>
1
2
3
When virtio-net is used with the socket netdev backend, the backend
4
can be busy and not able to collect new packets.
5
6
In this case, net_socket_receive() returns 0 and registers a poll function
7
to detect when the socket is ready again.
8
9
In virtio_net_tx_bh(), virtio_net_flush_tx() forwards the 0, the virtio
10
notifications are disabled and the function is not re-scheduled, waiting
11
for the backend to be ready.
12
13
When the socket netdev backend is again able to send packets, the poll
14
function re-starts to flush remaining packets. This is done by
15
calling virtio_net_tx_complete(). It re-enables notifications and calls
16
again virtio_net_flush_tx().
17
18
But it seems if virtio_net_flush_tx() reaches the tx_burst value all
19
the queue is not flushed and no new notification is sent to re-schedule
20
virtio_net_tx_bh(). Nothing re-start to flush the queue and remaining
21
packets are stuck in the queue.
22
23
To fix that, detect in virtio_net_tx_complete() if virtio_net_flush_tx()
24
has been stopped by tx_burst and if yes re-schedule the bottom half
25
function virtio_net_tx_bh() to flush the remaining packets.
26
27
This is what is done in virtio_net_tx_bh() when the virtio_net_flush_tx()
28
is synchronous, and completly by-passed when the operation needs to be
29
asynchronous.
30
31
Fixes: a697a334b3c4 ("virtio-net: Introduce a new bottom half packet TX")
32
Cc: alex.williamson@redhat.com
33
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
34
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
35
Acked-by: Michael S. Tsirkin <mst@redhat.com>
36
Signed-off-by: Jason Wang <jasowang@redhat.com>
37
---
38
hw/net/virtio-net.c | 13 ++++++++++++-
39
1 file changed, 12 insertions(+), 1 deletion(-)
40
41
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/hw/net/virtio-net.c
44
+++ b/hw/net/virtio-net.c
45
@@ -XXX,XX +XXX,XX @@ static void virtio_net_tx_complete(NetClientState *nc, ssize_t len)
46
VirtIONet *n = qemu_get_nic_opaque(nc);
47
VirtIONetQueue *q = virtio_net_get_subqueue(nc);
48
VirtIODevice *vdev = VIRTIO_DEVICE(n);
49
+ int ret;
50
51
virtqueue_push(q->tx_vq, q->async_tx.elem, 0);
52
virtio_notify(vdev, q->tx_vq);
53
@@ -XXX,XX +XXX,XX @@ static void virtio_net_tx_complete(NetClientState *nc, ssize_t len)
54
q->async_tx.elem = NULL;
55
56
virtio_queue_set_notification(q->tx_vq, 1);
57
- virtio_net_flush_tx(q);
58
+ ret = virtio_net_flush_tx(q);
59
+ if (q->tx_bh && ret >= n->tx_burst) {
60
+ /*
61
+ * the flush has been stopped by tx_burst
62
+ * we will not receive notification for the
63
+ * remainining part, so re-schedule
64
+ */
65
+ virtio_queue_set_notification(q->tx_vq, 0);
66
+ qemu_bh_schedule(q->tx_bh);
67
+ q->tx_waiting = 1;
68
+ }
69
}
70
71
/* TX */
72
--
73
2.7.4
diff view generated by jsdifflib
New patch
1
From: Laurent Vivier <lvivier@redhat.com>
1
2
3
When virtio_net_flush_tx() reaches the tx_burst value all
4
the queue is not flushed and nothing restart the timer.
5
6
Fix that by doing for TX timer as we do for bottom half TX:
7
rearming the timer if we find any packet to send during the
8
virtio_net_flush_tx() call.
9
10
Fixes: e3f30488e5f8 ("virtio-net: Limit number of packets sent per TX flush")
11
Cc: alex.williamson@redhat.com
12
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
13
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
14
Signed-off-by: Jason Wang <jasowang@redhat.com>
15
---
16
hw/net/virtio-net.c | 50 +++++++++++++++++++++++++++++++++++++++++---------
17
1 file changed, 41 insertions(+), 9 deletions(-)
18
19
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/hw/net/virtio-net.c
22
+++ b/hw/net/virtio-net.c
23
@@ -XXX,XX +XXX,XX @@ static void virtio_net_tx_complete(NetClientState *nc, ssize_t len)
24
25
virtio_queue_set_notification(q->tx_vq, 1);
26
ret = virtio_net_flush_tx(q);
27
- if (q->tx_bh && ret >= n->tx_burst) {
28
+ if (ret >= n->tx_burst) {
29
/*
30
* the flush has been stopped by tx_burst
31
* we will not receive notification for the
32
* remainining part, so re-schedule
33
*/
34
virtio_queue_set_notification(q->tx_vq, 0);
35
- qemu_bh_schedule(q->tx_bh);
36
+ if (q->tx_bh) {
37
+ qemu_bh_schedule(q->tx_bh);
38
+ } else {
39
+ timer_mod(q->tx_timer,
40
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
41
+ }
42
q->tx_waiting = 1;
43
}
44
}
45
@@ -XXX,XX +XXX,XX @@ drop:
46
return num_packets;
47
}
48
49
+static void virtio_net_tx_timer(void *opaque);
50
+
51
static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
52
{
53
VirtIONet *n = VIRTIO_NET(vdev);
54
@@ -XXX,XX +XXX,XX @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
55
}
56
57
if (q->tx_waiting) {
58
- virtio_queue_set_notification(vq, 1);
59
+ /* We already have queued packets, immediately flush */
60
timer_del(q->tx_timer);
61
- q->tx_waiting = 0;
62
- if (virtio_net_flush_tx(q) == -EINVAL) {
63
- return;
64
- }
65
+ virtio_net_tx_timer(q);
66
} else {
67
+ /* re-arm timer to flush it (and more) on next tick */
68
timer_mod(q->tx_timer,
69
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
70
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
71
q->tx_waiting = 1;
72
virtio_queue_set_notification(vq, 0);
73
}
74
@@ -XXX,XX +XXX,XX @@ static void virtio_net_tx_timer(void *opaque)
75
VirtIONetQueue *q = opaque;
76
VirtIONet *n = q->n;
77
VirtIODevice *vdev = VIRTIO_DEVICE(n);
78
+ int ret;
79
+
80
/* This happens when device was stopped but BH wasn't. */
81
if (!vdev->vm_running) {
82
/* Make sure tx waiting is set, so we'll run when restarted. */
83
@@ -XXX,XX +XXX,XX @@ static void virtio_net_tx_timer(void *opaque)
84
return;
85
}
86
87
+ ret = virtio_net_flush_tx(q);
88
+ if (ret == -EBUSY || ret == -EINVAL) {
89
+ return;
90
+ }
91
+ /*
92
+ * If we flush a full burst of packets, assume there are
93
+ * more coming and immediately rearm
94
+ */
95
+ if (ret >= n->tx_burst) {
96
+ q->tx_waiting = 1;
97
+ timer_mod(q->tx_timer,
98
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
99
+ return;
100
+ }
101
+ /*
102
+ * If less than a full burst, re-enable notification and flush
103
+ * anything that may have come in while we weren't looking. If
104
+ * we find something, assume the guest is still active and rearm
105
+ */
106
virtio_queue_set_notification(q->tx_vq, 1);
107
- virtio_net_flush_tx(q);
108
+ ret = virtio_net_flush_tx(q);
109
+ if (ret > 0) {
110
+ virtio_queue_set_notification(q->tx_vq, 0);
111
+ q->tx_waiting = 1;
112
+ timer_mod(q->tx_timer,
113
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + n->tx_timeout);
114
+ }
115
}
116
117
static void virtio_net_tx_bh(void *opaque)
118
--
119
2.7.4
diff view generated by jsdifflib
New patch
1
From: Eugenio Pérez <eperezma@redhat.com>
1
2
3
This entry was duplicated on referenced commit. Removing it.
4
5
Fixes: 402378407dbd ("vhost-vdpa: multiqueue support")
6
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
7
Acked-by: Jason Wang <jasowang@redhat.com>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
10
net/vhost-vdpa.c | 1 -
11
1 file changed, 1 deletion(-)
12
13
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/net/vhost-vdpa.c
16
+++ b/net/vhost-vdpa.c
17
@@ -XXX,XX +XXX,XX @@ const int vdpa_feature_bits[] = {
18
VIRTIO_NET_F_CTRL_RX,
19
VIRTIO_NET_F_CTRL_RX_EXTRA,
20
VIRTIO_NET_F_CTRL_VLAN,
21
- VIRTIO_NET_F_GUEST_ANNOUNCE,
22
VIRTIO_NET_F_CTRL_MAC_ADDR,
23
VIRTIO_NET_F_RSS,
24
VIRTIO_NET_F_MQ,
25
--
26
2.7.4
27
28
diff view generated by jsdifflib
New patch
1
From: Eugenio Pérez <eperezma@redhat.com>
1
2
3
The guest will see undefined behavior if it issue not negotiate
4
commands, bit it is expected somehow.
5
6
Simplify code deleting this check.
7
8
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
9
Acked-by: Jason Wang <jasowang@redhat.com>
10
Signed-off-by: Jason Wang <jasowang@redhat.com>
11
---
12
net/vhost-vdpa.c | 48 ------------------------------------------------
13
1 file changed, 48 deletions(-)
14
15
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/net/vhost-vdpa.c
18
+++ b/net/vhost-vdpa.c
19
@@ -XXX,XX +XXX,XX @@ static NetClientInfo net_vhost_vdpa_cvq_info = {
20
};
21
22
/**
23
- * Do not forward commands not supported by SVQ. Otherwise, the device could
24
- * accept it and qemu would not know how to update the device model.
25
- */
26
-static bool vhost_vdpa_net_cvq_validate_cmd(const void *out_buf, size_t len)
27
-{
28
- struct virtio_net_ctrl_hdr ctrl;
29
-
30
- if (unlikely(len < sizeof(ctrl))) {
31
- qemu_log_mask(LOG_GUEST_ERROR,
32
- "%s: invalid legnth of out buffer %zu\n", __func__, len);
33
- return false;
34
- }
35
-
36
- memcpy(&ctrl, out_buf, sizeof(ctrl));
37
- switch (ctrl.class) {
38
- case VIRTIO_NET_CTRL_MAC:
39
- switch (ctrl.cmd) {
40
- case VIRTIO_NET_CTRL_MAC_ADDR_SET:
41
- return true;
42
- default:
43
- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid mac cmd %u\n",
44
- __func__, ctrl.cmd);
45
- };
46
- break;
47
- case VIRTIO_NET_CTRL_MQ:
48
- switch (ctrl.cmd) {
49
- case VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET:
50
- return true;
51
- default:
52
- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid mq cmd %u\n",
53
- __func__, ctrl.cmd);
54
- };
55
- break;
56
- default:
57
- qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid control class %u\n",
58
- __func__, ctrl.class);
59
- };
60
-
61
- return false;
62
-}
63
-
64
-/**
65
* Validate and copy control virtqueue commands.
66
*
67
* Following QEMU guidelines, we offer a copy of the buffers to the device to
68
@@ -XXX,XX +XXX,XX @@ static int vhost_vdpa_net_handle_ctrl_avail(VhostShadowVirtqueue *svq,
69
.iov_len = sizeof(status),
70
};
71
ssize_t dev_written = -EINVAL;
72
- bool ok;
73
74
out.iov_len = iov_to_buf(elem->out_sg, elem->out_num, 0,
75
s->cvq_cmd_out_buffer,
76
vhost_vdpa_net_cvq_cmd_len());
77
- ok = vhost_vdpa_net_cvq_validate_cmd(s->cvq_cmd_out_buffer, out.iov_len);
78
- if (unlikely(!ok)) {
79
- goto out;
80
- }
81
-
82
dev_written = vhost_vdpa_net_cvq_add(s, out.iov_len, sizeof(status));
83
if (unlikely(dev_written < 0)) {
84
goto out;
85
--
86
2.7.4
87
88
diff view generated by jsdifflib
1
From: Thomas Huth <thuth@redhat.com>
1
From: Si-Wei Liu <si-wei.liu@oracle.com>
2
2
3
The vlan concept is marked as deprecated, so we should not use
3
Similar to other vhost backends, vhostfd can be passed to vhost-vdpa
4
this for examples in the documentation anymore.
4
backend as another parameter to instantiate vhost-vdpa net client.
5
This would benefit the use case where only open file descriptors, as
6
opposed to raw vhost-vdpa device paths, are accessible from the QEMU
7
process.
5
8
6
Signed-off-by: Thomas Huth <thuth@redhat.com>
9
(qemu) netdev_add type=vhost-vdpa,vhostfd=61,id=vhost-vdpa1
10
11
Signed-off-by: Si-Wei Liu <si-wei.liu@oracle.com>
12
Acked-by: Eugenio Pérez <eperezma@redhat.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
13
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
14
---
9
qemu-options.hx | 4 ++--
15
net/vhost-vdpa.c | 25 ++++++++++++++++++++-----
10
1 file changed, 2 insertions(+), 2 deletions(-)
16
qapi/net.json | 3 +++
17
qemu-options.hx | 6 ++++--
18
3 files changed, 27 insertions(+), 7 deletions(-)
11
19
20
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/net/vhost-vdpa.c
23
+++ b/net/vhost-vdpa.c
24
@@ -XXX,XX +XXX,XX @@ int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
25
26
assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA);
27
opts = &netdev->u.vhost_vdpa;
28
- if (!opts->vhostdev) {
29
- error_setg(errp, "vdpa character device not specified with vhostdev");
30
+ if (!opts->has_vhostdev && !opts->has_vhostfd) {
31
+ error_setg(errp,
32
+ "vhost-vdpa: neither vhostdev= nor vhostfd= was specified");
33
return -1;
34
}
35
36
- vdpa_device_fd = qemu_open(opts->vhostdev, O_RDWR, errp);
37
- if (vdpa_device_fd == -1) {
38
- return -errno;
39
+ if (opts->has_vhostdev && opts->has_vhostfd) {
40
+ error_setg(errp,
41
+ "vhost-vdpa: vhostdev= and vhostfd= are mutually exclusive");
42
+ return -1;
43
+ }
44
+
45
+ if (opts->has_vhostdev) {
46
+ vdpa_device_fd = qemu_open(opts->vhostdev, O_RDWR, errp);
47
+ if (vdpa_device_fd == -1) {
48
+ return -errno;
49
+ }
50
+ } else if (opts->has_vhostfd) {
51
+ vdpa_device_fd = monitor_fd_param(monitor_cur(), opts->vhostfd, errp);
52
+ if (vdpa_device_fd == -1) {
53
+ error_prepend(errp, "vhost-vdpa: unable to parse vhostfd: ");
54
+ return -1;
55
+ }
56
}
57
58
r = vhost_vdpa_get_features(vdpa_device_fd, &features, errp);
59
diff --git a/qapi/net.json b/qapi/net.json
60
index XXXXXXX..XXXXXXX 100644
61
--- a/qapi/net.json
62
+++ b/qapi/net.json
63
@@ -XXX,XX +XXX,XX @@
64
# @vhostdev: path of vhost-vdpa device
65
# (default:'/dev/vhost-vdpa-0')
66
#
67
+# @vhostfd: file descriptor of an already opened vhost vdpa device
68
+#
69
# @queues: number of queues to be created for multiqueue vhost-vdpa
70
# (default: 1)
71
#
72
@@ -XXX,XX +XXX,XX @@
73
{ 'struct': 'NetdevVhostVDPAOptions',
74
'data': {
75
'*vhostdev': 'str',
76
+ '*vhostfd': 'str',
77
'*queues': 'int',
78
'*x-svq': {'type': 'bool', 'features' : [ 'unstable'] } } }
79
12
diff --git a/qemu-options.hx b/qemu-options.hx
80
diff --git a/qemu-options.hx b/qemu-options.hx
13
index XXXXXXX..XXXXXXX 100644
81
index XXXXXXX..XXXXXXX 100644
14
--- a/qemu-options.hx
82
--- a/qemu-options.hx
15
+++ b/qemu-options.hx
83
+++ b/qemu-options.hx
16
@@ -XXX,XX +XXX,XX @@ qemu-system-i386 linux.img -net nic -net tap
84
@@ -XXX,XX +XXX,XX @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
17
#launch a QEMU instance with two NICs, each one connected
85
" configure a vhost-user network, backed by a chardev 'dev'\n"
18
#to a TAP device
86
#endif
19
qemu-system-i386 linux.img \
87
#ifdef __linux__
20
- -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
88
- "-netdev vhost-vdpa,id=str,vhostdev=/path/to/dev\n"
21
- -net nic,vlan=1 -net tap,vlan=1,ifname=tap1
89
+ "-netdev vhost-vdpa,id=str[,vhostdev=/path/to/dev][,vhostfd=h]\n"
22
+ -netdev tap,id=nd0,ifname=tap0 -device e1000,netdev=nd0 \
90
" configure a vhost-vdpa network,Establish a vhost-vdpa netdev\n"
23
+ -netdev tap,id=nd1,ifname=tap1 -device rtl8139,netdev=nd1
91
+ " use 'vhostdev=/path/to/dev' to open a vhost vdpa device\n"
24
@end example
92
+ " use 'vhostfd=h' to connect to an already opened vhost vdpa device\n"
25
93
#endif
26
@example
94
#ifdef CONFIG_VMNET
95
"-netdev vmnet-host,id=str[,isolated=on|off][,net-uuid=uuid]\n"
96
@@ -XXX,XX +XXX,XX @@ SRST
97
-netdev type=vhost-user,id=net0,chardev=chr0 \
98
-device virtio-net-pci,netdev=net0
99
100
-``-netdev vhost-vdpa,vhostdev=/path/to/dev``
101
+``-netdev vhost-vdpa[,vhostdev=/path/to/dev][,vhostfd=h]``
102
Establish a vhost-vdpa netdev.
103
104
vDPA device is a device that uses a datapath which complies with
27
--
105
--
28
2.7.4
106
2.7.4
29
107
30
108
diff view generated by jsdifflib
New patch
1
From: Daniel P. Berrangé <berrange@redhat.com>
1
2
3
The current message when using '-net user...' with SLIRP disabled at
4
compile time is:
5
6
qemu-system-x86_64: -net user: Parameter 'type' expects a net backend type (maybe it is not compiled into this binary)
7
8
An observation is that we're using the 'netdev->type' field here which
9
is an enum value, produced after QAPI has converted from its string
10
form.
11
12
IOW, at this point in the code, we know that the user's specified
13
type name was a valid network backend. The only possible scenario that
14
can make the backend init function be NULL, is if support for that
15
backend was disabled at build time. Given this, we don't need to caveat
16
our error message with a 'maybe' hint, we can be totally explicit.
17
18
The use of QERR_INVALID_PARAMETER_VALUE doesn't really lend itself to
19
user friendly error message text. Since this is not used to set a
20
specific QAPI error class, we can simply stop using this pre-formatted
21
error text and provide something better.
22
23
Thus the new message is:
24
25
qemu-system-x86_64: -net user: network backend 'user' is not compiled into this binary
26
27
The case of passing 'hubport' for -net is also given a message reminding
28
people they should have used -netdev/-nic instead, as this backend type
29
is only valid for the modern syntax.
30
31
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
32
Reviewed-by: Thomas Huth <thuth@redhat.com>
33
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
34
Signed-off-by: Jason Wang <jasowang@redhat.com>
35
---
36
net/net.c | 18 +++++++++++-------
37
1 file changed, 11 insertions(+), 7 deletions(-)
38
39
diff --git a/net/net.c b/net/net.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/net/net.c
42
+++ b/net/net.c
43
@@ -XXX,XX +XXX,XX @@ static int net_client_init1(const Netdev *netdev, bool is_netdev, Error **errp)
44
if (is_netdev) {
45
if (netdev->type == NET_CLIENT_DRIVER_NIC ||
46
!net_client_init_fun[netdev->type]) {
47
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
48
- "a netdev backend type");
49
+ error_setg(errp, "network backend '%s' is not compiled into this binary",
50
+ NetClientDriver_str(netdev->type));
51
return -1;
52
}
53
} else {
54
if (netdev->type == NET_CLIENT_DRIVER_NONE) {
55
return 0; /* nothing to do */
56
}
57
- if (netdev->type == NET_CLIENT_DRIVER_HUBPORT ||
58
- !net_client_init_fun[netdev->type]) {
59
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "type",
60
- "a net backend type (maybe it is not compiled "
61
- "into this binary)");
62
+ if (netdev->type == NET_CLIENT_DRIVER_HUBPORT) {
63
+ error_setg(errp, "network backend '%s' is only supported with -netdev/-nic",
64
+ NetClientDriver_str(netdev->type));
65
+ return -1;
66
+ }
67
+
68
+ if (!net_client_init_fun[netdev->type]) {
69
+ error_setg(errp, "network backend '%s' is not compiled into this binary",
70
+ NetClientDriver_str(netdev->type));
71
return -1;
72
}
73
74
--
75
2.7.4
76
77
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
There was not enough room to accomodate them.
4
4
5
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
5
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
6
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
6
Signed-off-by: Jason Wang <jasowang@redhat.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
7
---
8
---
8
MAINTAINERS | 8 ++++----
9
hw/virtio/vhost-shadow-virtqueue.c | 8 ++++----
9
1 file changed, 4 insertions(+), 4 deletions(-)
10
1 file changed, 4 insertions(+), 4 deletions(-)
10
11
11
diff --git a/MAINTAINERS b/MAINTAINERS
12
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
12
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
13
--- a/MAINTAINERS
14
--- a/hw/virtio/vhost-shadow-virtqueue.c
14
+++ b/MAINTAINERS
15
+++ b/hw/virtio/vhost-shadow-virtqueue.c
15
@@ -XXX,XX +XXX,XX @@ F: hw/scsi/mfi.h
16
@@ -XXX,XX +XXX,XX @@ void vhost_svq_get_vring_addr(const VhostShadowVirtqueue *svq,
16
F: tests/megasas-test.c
17
size_t vhost_svq_driver_area_size(const VhostShadowVirtqueue *svq)
17
18
{
18
Network packet abstractions
19
size_t desc_size = sizeof(vring_desc_t) * svq->vring.num;
19
-M: Dmitry Fleytman <dmitry@daynix.com>
20
- size_t avail_size = offsetof(vring_avail_t, ring) +
20
+M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
21
- sizeof(uint16_t) * svq->vring.num;
21
S: Maintained
22
+ size_t avail_size = offsetof(vring_avail_t, ring[svq->vring.num]) +
22
F: include/net/eth.h
23
+ sizeof(uint16_t);
23
F: net/eth.c
24
24
@@ -XXX,XX +XXX,XX @@ F: hw/net/net_rx_pkt*
25
return ROUND_UP(desc_size + avail_size, qemu_real_host_page_size());
25
F: hw/net/net_tx_pkt*
26
}
26
27
27
Vmware
28
size_t vhost_svq_device_area_size(const VhostShadowVirtqueue *svq)
28
-M: Dmitry Fleytman <dmitry@daynix.com>
29
{
29
+M: Dmitry Fleytman <dmitry.fleytman@gmail.com>
30
- size_t used_size = offsetof(vring_used_t, ring) +
30
S: Maintained
31
- sizeof(vring_used_elem_t) * svq->vring.num;
31
F: hw/net/vmxnet*
32
+ size_t used_size = offsetof(vring_used_t, ring[svq->vring.num]) +
32
F: hw/scsi/vmw_pvscsi*
33
+ sizeof(uint16_t);
33
@@ -XXX,XX +XXX,XX @@ F: hw/mem/nvdimm.c
34
return ROUND_UP(used_size, qemu_real_host_page_size());
34
F: include/hw/mem/nvdimm.h
35
}
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
36
48
--
37
--
49
2.7.4
38
2.7.4
50
39
51
40
diff view generated by jsdifflib
1
From: Mao Zhongyi <maozy.fnst@cn.fujitsu.com>
1
From: Eugenio Pérez <eperezma@redhat.com>
2
2
3
Packet size some time different or when network is busy.
3
Actually use the new field of the used ring and tell the device if SVQ
4
Based on same payload size, but TCP protocol can not
4
wants to be notified.
5
guarantee send the same one packet in the same way,
6
5
7
like that:
6
The code is not reachable at the moment.
8
We send this payload:
9
------------------------------
10
| header |1|2|3|4|5|6|7|8|9|0|
11
------------------------------
12
7
13
primary:
8
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
14
ppkt1:
9
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
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>
10
Signed-off-by: Jason Wang <jasowang@redhat.com>
70
---
11
---
71
net/colo-compare.c | 343 +++++++++++++++++++++++++++++++++++------------------
12
hw/virtio/vhost-shadow-virtqueue.c | 18 +++++++++++++++---
72
net/colo.c | 9 ++
13
1 file changed, 15 insertions(+), 3 deletions(-)
73
net/colo.h | 15 +++
74
net/trace-events | 2 +-
75
4 files changed, 250 insertions(+), 119 deletions(-)
76
14
77
diff --git a/net/colo-compare.c b/net/colo-compare.c
15
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
78
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
79
--- a/net/colo-compare.c
17
--- a/hw/virtio/vhost-shadow-virtqueue.c
80
+++ b/net/colo-compare.c
18
+++ b/hw/virtio/vhost-shadow-virtqueue.c
81
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@ static bool vhost_svq_more_used(VhostShadowVirtqueue *svq)
82
#define COMPARE_READ_LEN_MAX NET_BUFSIZE
83
#define MAX_QUEUE_SIZE 1024
84
85
+#define COLO_COMPARE_FREE_PRIMARY 0x01
86
+#define COLO_COMPARE_FREE_SECONDARY 0x02
87
+
88
/* TODO: Should be configurable */
89
#define REGULAR_PACKET_CHECK_MS 3000
90
91
@@ -XXX,XX +XXX,XX @@ static gint seq_sorter(Packet *a, Packet *b, gpointer data)
92
return ntohl(atcp->th_seq) - ntohl(btcp->th_seq);
93
}
94
95
+static void fill_pkt_tcp_info(void *data, uint32_t *max_ack)
96
+{
97
+ Packet *pkt = data;
98
+ struct tcphdr *tcphd;
99
+
100
+ tcphd = (struct tcphdr *)pkt->transport_header;
101
+
102
+ pkt->tcp_seq = ntohl(tcphd->th_seq);
103
+ pkt->tcp_ack = ntohl(tcphd->th_ack);
104
+ *max_ack = *max_ack > pkt->tcp_ack ? *max_ack : pkt->tcp_ack;
105
+ pkt->header_size = pkt->transport_header - (uint8_t *)pkt->data
106
+ + (tcphd->th_off << 2) - pkt->vnet_hdr_len;
107
+ pkt->payload_size = pkt->size - pkt->header_size;
108
+ pkt->seq_end = pkt->tcp_seq + pkt->payload_size;
109
+ pkt->flags = tcphd->th_flags;
110
+}
111
+
112
/*
113
* Return 1 on success, if return 0 means the
114
* packet will be dropped
115
*/
20
*/
116
-static int colo_insert_packet(GQueue *queue, Packet *pkt)
21
static bool vhost_svq_enable_notification(VhostShadowVirtqueue *svq)
117
+static int colo_insert_packet(GQueue *queue, Packet *pkt, uint32_t *max_ack)
118
{
22
{
119
if (g_queue_get_length(queue) <= MAX_QUEUE_SIZE) {
23
- svq->vring.avail->flags &= ~cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT);
120
if (pkt->ip->ip_p == IPPROTO_TCP) {
24
- /* Make sure the flag is written before the read of used_idx */
121
+ fill_pkt_tcp_info(pkt, max_ack);
25
+ if (virtio_vdev_has_feature(svq->vdev, VIRTIO_RING_F_EVENT_IDX)) {
122
g_queue_insert_sorted(queue,
26
+ uint16_t *used_event = (uint16_t *)&svq->vring.avail->ring[svq->vring.num];
123
pkt,
27
+ *used_event = svq->shadow_used_idx;
124
(GCompareDataFunc)seq_sorter,
28
+ } else {
125
@@ -XXX,XX +XXX,XX @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
29
+ svq->vring.avail->flags &= ~cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT);
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
+ }
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
+ }
30
+ }
202
+
31
+
203
+ /* one part of secondary packet payload still need to be compared */
32
+ /* Make sure the event is enabled before the read of used_idx */
204
+ if (!after(ppkt->seq_end, spkt->seq_end)) {
33
smp_mb();
205
+ if (colo_compare_packet_payload(ppkt, spkt,
34
return !vhost_svq_more_used(svq);
206
+ ppkt->header_size + ppkt->offset,
35
}
207
+ spkt->header_size + spkt->offset,
36
208
+ ppkt->payload_size - ppkt->offset)) {
37
static void vhost_svq_disable_notification(VhostShadowVirtqueue *svq)
209
+ if (!after(ppkt->tcp_ack, max_ack)) {
38
{
210
+ *mark = COLO_COMPARE_FREE_PRIMARY;
39
- svq->vring.avail->flags |= cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT);
211
+ spkt->offset += ppkt->payload_size - ppkt->offset;
40
+ /*
212
+ return true;
41
+ * No need to disable notification in the event idx case, since used event
213
+ } else {
42
+ * index is already an index too far away.
214
+ /* secondary guest hasn't ack the data, don't send
43
+ */
215
+ * out this packet
44
+ if (!virtio_vdev_has_feature(svq->vdev, VIRTIO_RING_F_EVENT_IDX)) {
216
+ */
45
+ svq->vring.avail->flags |= cpu_to_le16(VRING_AVAIL_F_NO_INTERRUPT);
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
+ }
46
+ }
414
}
47
}
415
48
416
+
49
static uint16_t vhost_svq_last_desc_of_chain(const VhostShadowVirtqueue *svq,
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
--
50
--
588
2.7.4
51
2.7.4
589
52
590
53
diff view generated by jsdifflib
New patch
1
From: Eugenio Pérez <eperezma@redhat.com>
1
2
3
So SVQ code knows if an event is needed.
4
5
The code is not reachable at the moment.
6
7
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
8
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
---
11
hw/virtio/vhost-shadow-virtqueue.c | 12 +++++++++++-
12
1 file changed, 11 insertions(+), 1 deletion(-)
13
14
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/virtio/vhost-shadow-virtqueue.c
17
+++ b/hw/virtio/vhost-shadow-virtqueue.c
18
@@ -XXX,XX +XXX,XX @@ static bool vhost_svq_add_split(VhostShadowVirtqueue *svq,
19
20
static void vhost_svq_kick(VhostShadowVirtqueue *svq)
21
{
22
+ bool needs_kick;
23
+
24
/*
25
* We need to expose the available array entries before checking the used
26
* flags
27
*/
28
smp_mb();
29
- if (svq->vring.used->flags & VRING_USED_F_NO_NOTIFY) {
30
+
31
+ if (virtio_vdev_has_feature(svq->vdev, VIRTIO_RING_F_EVENT_IDX)) {
32
+ uint16_t avail_event = *(uint16_t *)(&svq->vring.used->ring[svq->vring.num]);
33
+ needs_kick = vring_need_event(avail_event, svq->shadow_avail_idx, svq->shadow_avail_idx - 1);
34
+ } else {
35
+ needs_kick = !(svq->vring.used->flags & VRING_USED_F_NO_NOTIFY);
36
+ }
37
+
38
+ if (!needs_kick) {
39
return;
40
}
41
42
--
43
2.7.4
44
45
diff view generated by jsdifflib
New patch
1
From: Eugenio Pérez <eperezma@redhat.com>
1
2
3
Enabling all the code path created before.
4
5
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
6
Signed-off-by: Eugenio Pérez <eperezma@redhat.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
9
hw/virtio/vhost-shadow-virtqueue.c | 1 +
10
1 file changed, 1 insertion(+)
11
12
diff --git a/hw/virtio/vhost-shadow-virtqueue.c b/hw/virtio/vhost-shadow-virtqueue.c
13
index XXXXXXX..XXXXXXX 100644
14
--- a/hw/virtio/vhost-shadow-virtqueue.c
15
+++ b/hw/virtio/vhost-shadow-virtqueue.c
16
@@ -XXX,XX +XXX,XX @@ bool vhost_svq_valid_features(uint64_t features, Error **errp)
17
++b) {
18
switch (b) {
19
case VIRTIO_F_ANY_LAYOUT:
20
+ case VIRTIO_RING_F_EVENT_IDX:
21
continue;
22
23
case VIRTIO_F_ACCESS_PLATFORM:
24
--
25
2.7.4
26
27
diff view generated by jsdifflib
New patch
1
From: Laurent Vivier <lvivier@redhat.com>
1
2
3
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
4
Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
5
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
6
Acked-by: Michael S. Tsirkin <mst@redhat.com>
7
Signed-off-by: Jason Wang <jasowang@redhat.com>
8
---
9
include/qemu/sockets.h | 2 ++
10
net/net.c | 62 ++++++++++++++++++++++++++------------------------
11
2 files changed, 34 insertions(+), 30 deletions(-)
12
13
diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
14
index XXXXXXX..XXXXXXX 100644
15
--- a/include/qemu/sockets.h
16
+++ b/include/qemu/sockets.h
17
@@ -XXX,XX +XXX,XX @@ void socket_listen_cleanup(int fd, Error **errp);
18
int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp);
19
20
/* Old, ipv4 only bits. Don't use for new code. */
21
+int convert_host_port(struct sockaddr_in *saddr, const char *host,
22
+ const char *port, Error **errp);
23
int parse_host_port(struct sockaddr_in *saddr, const char *str,
24
Error **errp);
25
int socket_init(void);
26
diff --git a/net/net.c b/net/net.c
27
index XXXXXXX..XXXXXXX 100644
28
--- a/net/net.c
29
+++ b/net/net.c
30
@@ -XXX,XX +XXX,XX @@ static QTAILQ_HEAD(, NetClientState) net_clients;
31
/***********************************************************/
32
/* network device redirectors */
33
34
-int parse_host_port(struct sockaddr_in *saddr, const char *str,
35
- Error **errp)
36
+int convert_host_port(struct sockaddr_in *saddr, const char *host,
37
+ const char *port, Error **errp)
38
{
39
- gchar **substrings;
40
struct hostent *he;
41
- const char *addr, *p, *r;
42
- int port, ret = 0;
43
+ const char *r;
44
+ long p;
45
46
memset(saddr, 0, sizeof(*saddr));
47
48
- substrings = g_strsplit(str, ":", 2);
49
- if (!substrings || !substrings[0] || !substrings[1]) {
50
- error_setg(errp, "host address '%s' doesn't contain ':' "
51
- "separating host from port", str);
52
- ret = -1;
53
- goto out;
54
- }
55
-
56
- addr = substrings[0];
57
- p = substrings[1];
58
-
59
saddr->sin_family = AF_INET;
60
- if (addr[0] == '\0') {
61
+ if (host[0] == '\0') {
62
saddr->sin_addr.s_addr = 0;
63
} else {
64
- if (qemu_isdigit(addr[0])) {
65
- if (!inet_aton(addr, &saddr->sin_addr)) {
66
+ if (qemu_isdigit(host[0])) {
67
+ if (!inet_aton(host, &saddr->sin_addr)) {
68
error_setg(errp, "host address '%s' is not a valid "
69
- "IPv4 address", addr);
70
- ret = -1;
71
- goto out;
72
+ "IPv4 address", host);
73
+ return -1;
74
}
75
} else {
76
- he = gethostbyname(addr);
77
+ he = gethostbyname(host);
78
if (he == NULL) {
79
- error_setg(errp, "can't resolve host address '%s'", addr);
80
- ret = -1;
81
- goto out;
82
+ error_setg(errp, "can't resolve host address '%s'", host);
83
+ return -1;
84
}
85
saddr->sin_addr = *(struct in_addr *)he->h_addr;
86
}
87
}
88
- port = strtol(p, (char **)&r, 0);
89
- if (r == p) {
90
- error_setg(errp, "port number '%s' is invalid", p);
91
+ if (qemu_strtol(port, &r, 0, &p) != 0) {
92
+ error_setg(errp, "port number '%s' is invalid", port);
93
+ return -1;
94
+ }
95
+ saddr->sin_port = htons(p);
96
+ return 0;
97
+}
98
+
99
+int parse_host_port(struct sockaddr_in *saddr, const char *str,
100
+ Error **errp)
101
+{
102
+ gchar **substrings;
103
+ int ret;
104
+
105
+ substrings = g_strsplit(str, ":", 2);
106
+ if (!substrings || !substrings[0] || !substrings[1]) {
107
+ error_setg(errp, "host address '%s' doesn't contain ':' "
108
+ "separating host from port", str);
109
ret = -1;
110
goto out;
111
}
112
- saddr->sin_port = htons(port);
113
+
114
+ ret = convert_host_port(saddr, substrings[0], substrings[1], errp);
115
116
out:
117
g_strfreev(substrings);
118
--
119
2.7.4
diff view generated by jsdifflib
New patch
1
From: Laurent Vivier <lvivier@redhat.com>
1
2
3
The only caller passes &error_fatal, so use this directly in the function.
4
5
It's what we do for -blockdev, -device, and -object.
6
7
Suggested-by: Markus Armbruster <armbru@redhat.com>
8
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
9
Reviewed-by: Markus Armbruster <armbru@redhat.com>
10
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
11
Acked-by: Michael S. Tsirkin <mst@redhat.com>
12
Signed-off-by: Jason Wang <jasowang@redhat.com>
13
---
14
include/net/net.h | 2 +-
15
net/net.c | 20 +++++++-------------
16
softmmu/vl.c | 2 +-
17
3 files changed, 9 insertions(+), 15 deletions(-)
18
19
diff --git a/include/net/net.h b/include/net/net.h
20
index XXXXXXX..XXXXXXX 100644
21
--- a/include/net/net.h
22
+++ b/include/net/net.h
23
@@ -XXX,XX +XXX,XX @@ extern const char *host_net_devices[];
24
/* from net.c */
25
int net_client_parse(QemuOptsList *opts_list, const char *str);
26
void show_netdevs(void);
27
-int net_init_clients(Error **errp);
28
+void net_init_clients(void);
29
void net_check_clients(void);
30
void net_cleanup(void);
31
void hmp_host_net_add(Monitor *mon, const QDict *qdict);
32
diff --git a/net/net.c b/net/net.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/net/net.c
35
+++ b/net/net.c
36
@@ -XXX,XX +XXX,XX @@ out:
37
return ret;
38
}
39
40
-int net_init_clients(Error **errp)
41
+void net_init_clients(void)
42
{
43
net_change_state_entry =
44
qemu_add_vm_change_state_handler(net_vm_change_state_handler, NULL);
45
46
QTAILQ_INIT(&net_clients);
47
48
- if (qemu_opts_foreach(qemu_find_opts("netdev"),
49
- net_init_netdev, NULL, errp)) {
50
- return -1;
51
- }
52
-
53
- if (qemu_opts_foreach(qemu_find_opts("nic"), net_param_nic, NULL, errp)) {
54
- return -1;
55
- }
56
+ qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL,
57
+ &error_fatal);
58
59
- if (qemu_opts_foreach(qemu_find_opts("net"), net_init_client, NULL, errp)) {
60
- return -1;
61
- }
62
+ qemu_opts_foreach(qemu_find_opts("nic"), net_param_nic, NULL,
63
+ &error_fatal);
64
65
- return 0;
66
+ qemu_opts_foreach(qemu_find_opts("net"), net_init_client, NULL,
67
+ &error_fatal);
68
}
69
70
int net_client_parse(QemuOptsList *opts_list, const char *optarg)
71
diff --git a/softmmu/vl.c b/softmmu/vl.c
72
index XXXXXXX..XXXXXXX 100644
73
--- a/softmmu/vl.c
74
+++ b/softmmu/vl.c
75
@@ -XXX,XX +XXX,XX @@ static void qemu_create_late_backends(void)
76
qtest_server_init(qtest_chrdev, qtest_log, &error_fatal);
77
}
78
79
- net_init_clients(&error_fatal);
80
+ net_init_clients();
81
82
object_option_foreach_add(object_create_late);
83
84
--
85
2.7.4
diff view generated by jsdifflib
New patch
1
From: Laurent Vivier <lvivier@redhat.com>
1
2
3
All net_client_parse() callers exit in case of error.
4
5
Move exit(1) to net_client_parse() and remove error checking from
6
the callers.
7
8
Suggested-by: Markus Armbruster <armbru@redhat.com>
9
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
10
Reviewed-by: Markus Armbruster <armbru@redhat.com>
11
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
12
Acked-by: Michael S. Tsirkin <mst@redhat.com>
13
Signed-off-by: Jason Wang <jasowang@redhat.com>
14
---
15
include/net/net.h | 2 +-
16
net/net.c | 6 ++----
17
softmmu/vl.c | 12 +++---------
18
3 files changed, 6 insertions(+), 14 deletions(-)
19
20
diff --git a/include/net/net.h b/include/net/net.h
21
index XXXXXXX..XXXXXXX 100644
22
--- a/include/net/net.h
23
+++ b/include/net/net.h
24
@@ -XXX,XX +XXX,XX @@ extern NICInfo nd_table[MAX_NICS];
25
extern const char *host_net_devices[];
26
27
/* from net.c */
28
-int net_client_parse(QemuOptsList *opts_list, const char *str);
29
+void net_client_parse(QemuOptsList *opts_list, const char *str);
30
void show_netdevs(void);
31
void net_init_clients(void);
32
void net_check_clients(void);
33
diff --git a/net/net.c b/net/net.c
34
index XXXXXXX..XXXXXXX 100644
35
--- a/net/net.c
36
+++ b/net/net.c
37
@@ -XXX,XX +XXX,XX @@ void net_init_clients(void)
38
&error_fatal);
39
}
40
41
-int net_client_parse(QemuOptsList *opts_list, const char *optarg)
42
+void net_client_parse(QemuOptsList *opts_list, const char *optarg)
43
{
44
if (!qemu_opts_parse_noisily(opts_list, optarg, true)) {
45
- return -1;
46
+ exit(1);
47
}
48
-
49
- return 0;
50
}
51
52
/* From FreeBSD */
53
diff --git a/softmmu/vl.c b/softmmu/vl.c
54
index XXXXXXX..XXXXXXX 100644
55
--- a/softmmu/vl.c
56
+++ b/softmmu/vl.c
57
@@ -XXX,XX +XXX,XX @@ void qemu_init(int argc, char **argv)
58
break;
59
case QEMU_OPTION_netdev:
60
default_net = 0;
61
- if (net_client_parse(qemu_find_opts("netdev"), optarg) == -1) {
62
- exit(1);
63
- }
64
+ net_client_parse(qemu_find_opts("netdev"), optarg);
65
break;
66
case QEMU_OPTION_nic:
67
default_net = 0;
68
- if (net_client_parse(qemu_find_opts("nic"), optarg) == -1) {
69
- exit(1);
70
- }
71
+ net_client_parse(qemu_find_opts("nic"), optarg);
72
break;
73
case QEMU_OPTION_net:
74
default_net = 0;
75
- if (net_client_parse(qemu_find_opts("net"), optarg) == -1) {
76
- exit(1);
77
- }
78
+ net_client_parse(qemu_find_opts("net"), optarg);
79
break;
80
#ifdef CONFIG_LIBISCSI
81
case QEMU_OPTION_iscsi:
82
--
83
2.7.4
diff view generated by jsdifflib
New patch
1
From: Laurent Vivier <lvivier@redhat.com>
1
2
3
As qemu_opts_parse_noisily() flattens the QAPI structures ("type" field
4
of Netdev structure can collides with "type" field of SocketAddress),
5
we introduce a way to bypass qemu_opts_parse_noisily() and use directly
6
visit_type_Netdev() to parse the backend parameters.
7
8
More details from Markus:
9
10
qemu_init() passes the argument of -netdev, -nic, and -net to
11
net_client_parse().
12
13
net_client_parse() parses with qemu_opts_parse_noisily(), passing
14
QemuOptsList qemu_netdev_opts for -netdev, qemu_nic_opts for -nic, and
15
qemu_net_opts for -net. Their desc[] are all empty, which means any
16
keys are accepted. The result of the parse (a QemuOpts) is stored in
17
the QemuOptsList.
18
19
Note that QemuOpts is flat by design. In some places, we layer non-flat
20
on top using dotted keys convention, but not here.
21
22
net_init_clients() iterates over the stored QemuOpts, and passes them to
23
net_init_netdev(), net_param_nic(), or net_init_client(), respectively.
24
25
These functions pass the QemuOpts to net_client_init(). They also do
26
other things with the QemuOpts, which we can ignore here.
27
28
net_client_init() uses the opts visitor to convert the (flat) QemOpts to
29
a (non-flat) QAPI object Netdev. Netdev is also the argument of QMP
30
command netdev_add.
31
32
The opts visitor was an early attempt to support QAPI in
33
(QemuOpts-based) CLI. It restricts QAPI types to a certain shape; see
34
commit eb7ee2cbeb "qapi: introduce OptsVisitor".
35
36
A more modern way to support QAPI is qobject_input_visitor_new_str().
37
It uses keyval_parse() instead of QemuOpts for KEY=VALUE,... syntax, and
38
it also supports JSON syntax. The former isn't quite as expressive as
39
JSON, but it's a lot closer than QemuOpts + opts visitor.
40
41
This commit paves the way to use of the modern way instead.
42
43
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
44
Reviewed-by: Markus Armbruster <armbru@redhat.com>
45
Acked-by: Michael S. Tsirkin <mst@redhat.com>
46
Signed-off-by: Jason Wang <jasowang@redhat.com>
47
---
48
include/net/net.h | 2 ++
49
net/net.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
50
softmmu/vl.c | 6 +++++-
51
3 files changed, 64 insertions(+), 1 deletion(-)
52
53
diff --git a/include/net/net.h b/include/net/net.h
54
index XXXXXXX..XXXXXXX 100644
55
--- a/include/net/net.h
56
+++ b/include/net/net.h
57
@@ -XXX,XX +XXX,XX @@ extern NICInfo nd_table[MAX_NICS];
58
extern const char *host_net_devices[];
59
60
/* from net.c */
61
+bool netdev_is_modern(const char *optarg);
62
+void netdev_parse_modern(const char *optarg);
63
void net_client_parse(QemuOptsList *opts_list, const char *str);
64
void show_netdevs(void);
65
void net_init_clients(void);
66
diff --git a/net/net.c b/net/net.c
67
index XXXXXXX..XXXXXXX 100644
68
--- a/net/net.c
69
+++ b/net/net.c
70
@@ -XXX,XX +XXX,XX @@
71
#include "net/colo-compare.h"
72
#include "net/filter.h"
73
#include "qapi/string-output-visitor.h"
74
+#include "qapi/qobject-input-visitor.h"
75
76
/* Net bridge is currently not supported for W32. */
77
#if !defined(_WIN32)
78
@@ -XXX,XX +XXX,XX @@
79
static VMChangeStateEntry *net_change_state_entry;
80
static QTAILQ_HEAD(, NetClientState) net_clients;
81
82
+typedef struct NetdevQueueEntry {
83
+ Netdev *nd;
84
+ Location loc;
85
+ QSIMPLEQ_ENTRY(NetdevQueueEntry) entry;
86
+} NetdevQueueEntry;
87
+
88
+typedef QSIMPLEQ_HEAD(, NetdevQueueEntry) NetdevQueue;
89
+
90
+static NetdevQueue nd_queue = QSIMPLEQ_HEAD_INITIALIZER(nd_queue);
91
+
92
/***********************************************************/
93
/* network device redirectors */
94
95
@@ -XXX,XX +XXX,XX @@ out:
96
return ret;
97
}
98
99
+static void netdev_init_modern(void)
100
+{
101
+ while (!QSIMPLEQ_EMPTY(&nd_queue)) {
102
+ NetdevQueueEntry *nd = QSIMPLEQ_FIRST(&nd_queue);
103
+
104
+ QSIMPLEQ_REMOVE_HEAD(&nd_queue, entry);
105
+ loc_push_restore(&nd->loc);
106
+ net_client_init1(nd->nd, true, &error_fatal);
107
+ loc_pop(&nd->loc);
108
+ qapi_free_Netdev(nd->nd);
109
+ g_free(nd);
110
+ }
111
+}
112
+
113
void net_init_clients(void)
114
{
115
net_change_state_entry =
116
@@ -XXX,XX +XXX,XX @@ void net_init_clients(void)
117
118
QTAILQ_INIT(&net_clients);
119
120
+ netdev_init_modern();
121
+
122
qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL,
123
&error_fatal);
124
125
@@ -XXX,XX +XXX,XX @@ void net_init_clients(void)
126
&error_fatal);
127
}
128
129
+/*
130
+ * Does this -netdev argument use modern rather than traditional syntax?
131
+ * Modern syntax is to be parsed with netdev_parse_modern().
132
+ * Traditional syntax is to be parsed with net_client_parse().
133
+ */
134
+bool netdev_is_modern(const char *optarg)
135
+{
136
+ return false;
137
+}
138
+
139
+/*
140
+ * netdev_parse_modern() uses modern, more expressive syntax than
141
+ * net_client_parse(), but supports only the -netdev option.
142
+ * netdev_parse_modern() appends to @nd_queue, whereas net_client_parse()
143
+ * appends to @qemu_netdev_opts.
144
+ */
145
+void netdev_parse_modern(const char *optarg)
146
+{
147
+ Visitor *v;
148
+ NetdevQueueEntry *nd;
149
+
150
+ v = qobject_input_visitor_new_str(optarg, "type", &error_fatal);
151
+ nd = g_new(NetdevQueueEntry, 1);
152
+ visit_type_Netdev(v, NULL, &nd->nd, &error_fatal);
153
+ visit_free(v);
154
+ loc_save(&nd->loc);
155
+
156
+ QSIMPLEQ_INSERT_TAIL(&nd_queue, nd, entry);
157
+}
158
+
159
void net_client_parse(QemuOptsList *opts_list, const char *optarg)
160
{
161
if (!qemu_opts_parse_noisily(opts_list, optarg, true)) {
162
diff --git a/softmmu/vl.c b/softmmu/vl.c
163
index XXXXXXX..XXXXXXX 100644
164
--- a/softmmu/vl.c
165
+++ b/softmmu/vl.c
166
@@ -XXX,XX +XXX,XX @@ void qemu_init(int argc, char **argv)
167
break;
168
case QEMU_OPTION_netdev:
169
default_net = 0;
170
- net_client_parse(qemu_find_opts("netdev"), optarg);
171
+ if (netdev_is_modern(optarg)) {
172
+ netdev_parse_modern(optarg);
173
+ } else {
174
+ net_client_parse(qemu_find_opts("netdev"), optarg);
175
+ }
176
break;
177
case QEMU_OPTION_nic:
178
default_net = 0;
179
--
180
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
It does not make much sense to limit these commands to the legacy 'vlan'
3
Embed the setting of info_str in a function.
4
concept only, they should work with the modern netdevs, too. So now
4
5
it is possible to use this command with one, two or three parameters.
5
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
6
6
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
7
With one parameter, the command installs a hostfwd rule on the default
7
Acked-by: Michael S. Tsirkin <mst@redhat.com>
8
"user" network:
8
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
9
hostfwd_add tcp:...
10
11
With two parameters, the command installs a hostfwd rule on a netdev
12
(that's the new way of using this command):
13
hostfwd_add netdev_id tcp:...
14
15
With three parameters, the command installs a rule on a 'vlan' (aka hub):
16
hostfwd_add hub_id name tcp:...
17
18
Same applies to the hostfwd_remove command now.
19
20
Signed-off-by: Thomas Huth <thuth@redhat.com>
21
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
22
---
10
---
23
hmp-commands.hx | 4 ++--
11
hw/net/xen_nic.c | 5 ++---
24
net/slirp.c | 33 +++++++++++++++++++++++----------
12
include/net/net.h | 1 +
25
2 files changed, 25 insertions(+), 12 deletions(-)
13
net/l2tpv3.c | 3 +--
26
14
net/net.c | 17 ++++++++++++-----
27
diff --git a/hmp-commands.hx b/hmp-commands.hx
15
net/slirp.c | 5 ++---
28
index XXXXXXX..XXXXXXX 100644
16
net/socket.c | 33 ++++++++++++++-------------------
29
--- a/hmp-commands.hx
17
net/tap-win32.c | 3 +--
30
+++ b/hmp-commands.hx
18
net/tap.c | 13 +++++--------
31
@@ -XXX,XX +XXX,XX @@ ETEXI
19
net/vde.c | 3 +--
32
{
20
net/vhost-user.c | 3 +--
33
.name = "hostfwd_add",
21
net/vhost-vdpa.c | 2 +-
34
.args_type = "arg1:s,arg2:s?,arg3:s?",
22
11 files changed, 41 insertions(+), 47 deletions(-)
35
- .params = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport",
23
36
+ .params = "[hub_id name]|[netdev_id] [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport",
24
diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c
37
.help = "redirect TCP or UDP connections from host to guest (requires -net user)",
25
index XXXXXXX..XXXXXXX 100644
38
.cmd = hmp_hostfwd_add,
26
--- a/hw/net/xen_nic.c
39
},
27
+++ b/hw/net/xen_nic.c
40
@@ -XXX,XX +XXX,XX @@ ETEXI
28
@@ -XXX,XX +XXX,XX @@ static int net_init(struct XenLegacyDevice *xendev)
41
{
29
netdev->nic = qemu_new_nic(&net_xen_info, &netdev->conf,
42
.name = "hostfwd_remove",
30
"xen", NULL, netdev);
43
.args_type = "arg1:s,arg2:s?,arg3:s?",
31
44
- .params = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport",
32
- snprintf(qemu_get_queue(netdev->nic)->info_str,
45
+ .params = "[hub_id name]|[netdev_id] [tcp|udp]:[hostaddr]:hostport",
33
- sizeof(qemu_get_queue(netdev->nic)->info_str),
46
.help = "remove host-to-guest TCP or UDP redirection",
34
- "nic: xenbus vif macaddr=%s", netdev->mac);
47
.cmd = hmp_hostfwd_remove,
35
+ qemu_set_info_str(qemu_get_queue(netdev->nic),
48
},
36
+ "nic: xenbus vif macaddr=%s", netdev->mac);
37
38
/* fill info */
39
xenstore_write_be_int(&netdev->xendev, "feature-rx-copy", 1);
40
diff --git a/include/net/net.h b/include/net/net.h
41
index XXXXXXX..XXXXXXX 100644
42
--- a/include/net/net.h
43
+++ b/include/net/net.h
44
@@ -XXX,XX +XXX,XX @@ ssize_t qemu_send_packet_async(NetClientState *nc, const uint8_t *buf,
45
void qemu_purge_queued_packets(NetClientState *nc);
46
void qemu_flush_queued_packets(NetClientState *nc);
47
void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge);
48
+void qemu_set_info_str(NetClientState *nc, const char *fmt, ...);
49
void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]);
50
bool qemu_has_ufo(NetClientState *nc);
51
bool qemu_has_vnet_hdr(NetClientState *nc);
52
diff --git a/net/l2tpv3.c b/net/l2tpv3.c
53
index XXXXXXX..XXXXXXX 100644
54
--- a/net/l2tpv3.c
55
+++ b/net/l2tpv3.c
56
@@ -XXX,XX +XXX,XX @@ int net_init_l2tpv3(const Netdev *netdev,
57
58
l2tpv3_read_poll(s, true);
59
60
- snprintf(s->nc.info_str, sizeof(s->nc.info_str),
61
- "l2tpv3: connected");
62
+ qemu_set_info_str(&s->nc, "l2tpv3: connected");
63
return 0;
64
outerr:
65
qemu_del_net_client(nc);
66
diff --git a/net/net.c b/net/net.c
67
index XXXXXXX..XXXXXXX 100644
68
--- a/net/net.c
69
+++ b/net/net.c
70
@@ -XXX,XX +XXX,XX @@ char *qemu_mac_strdup_printf(const uint8_t *macaddr)
71
macaddr[3], macaddr[4], macaddr[5]);
72
}
73
74
+void qemu_set_info_str(NetClientState *nc, const char *fmt, ...)
75
+{
76
+ va_list ap;
77
+
78
+ va_start(ap, fmt);
79
+ vsnprintf(nc->info_str, sizeof(nc->info_str), fmt, ap);
80
+ va_end(ap);
81
+}
82
+
83
void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6])
84
{
85
- snprintf(nc->info_str, sizeof(nc->info_str),
86
- "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
87
- nc->model,
88
- macaddr[0], macaddr[1], macaddr[2],
89
- macaddr[3], macaddr[4], macaddr[5]);
90
+ qemu_set_info_str(nc, "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
91
+ nc->model, macaddr[0], macaddr[1], macaddr[2],
92
+ macaddr[3], macaddr[4], macaddr[5]);
93
}
94
95
static int mac_table[256] = {0};
49
diff --git a/net/slirp.c b/net/slirp.c
96
diff --git a/net/slirp.c b/net/slirp.c
50
index XXXXXXX..XXXXXXX 100644
97
index XXXXXXX..XXXXXXX 100644
51
--- a/net/slirp.c
98
--- a/net/slirp.c
52
+++ b/net/slirp.c
99
+++ b/net/slirp.c
53
@@ -XXX,XX +XXX,XX @@ error:
100
@@ -XXX,XX +XXX,XX @@ static int net_slirp_init(NetClientState *peer, const char *model,
54
return -1;
101
55
}
102
nc = qemu_new_net_client(&net_slirp_info, peer, model, name);
56
103
57
-static SlirpState *slirp_lookup(Monitor *mon, const char *vlan,
104
- snprintf(nc->info_str, sizeof(nc->info_str),
58
- const char *stack)
105
- "net=%s,restrict=%s", inet_ntoa(net),
59
+static SlirpState *slirp_lookup(Monitor *mon, const char *hub_id,
106
- restricted ? "on" : "off");
60
+ const char *name)
107
+ qemu_set_info_str(nc, "net=%s,restrict=%s", inet_ntoa(net),
61
{
108
+ restricted ? "on" : "off");
62
-
109
63
- if (vlan) {
110
s = DO_UPCAST(SlirpState, nc, nc);
64
+ if (name) {
111
65
NetClientState *nc;
112
diff --git a/net/socket.c b/net/socket.c
66
- nc = net_hub_find_client_by_name(strtol(vlan, NULL, 0), stack);
113
index XXXXXXX..XXXXXXX 100644
67
- if (!nc) {
114
--- a/net/socket.c
68
- monitor_printf(mon, "unrecognized (vlan-id, stackname) pair\n");
115
+++ b/net/socket.c
69
- return NULL;
116
@@ -XXX,XX +XXX,XX @@ static void net_socket_send(void *opaque)
70
+ if (hub_id) {
117
s->fd = -1;
71
+ nc = net_hub_find_client_by_name(strtol(hub_id, NULL, 0), name);
118
net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
72
+ if (!nc) {
119
s->nc.link_down = true;
73
+ monitor_printf(mon, "unrecognized (vlan-id, stackname) pair\n");
120
- memset(s->nc.info_str, 0, sizeof(s->nc.info_str));
74
+ return NULL;
121
+ qemu_set_info_str(&s->nc, "");
75
+ }
122
76
+ } else {
123
return;
77
+ nc = qemu_find_netdev(name);
124
}
78
+ if (!nc) {
125
@@ -XXX,XX +XXX,XX @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
79
+ monitor_printf(mon, "unrecognized netdev id '%s'\n", name);
126
/* mcast: save bound address as dst */
80
+ return NULL;
127
if (is_connected && mcast != NULL) {
81
+ }
128
s->dgram_dst = saddr;
129
- snprintf(nc->info_str, sizeof(nc->info_str),
130
- "socket: fd=%d (cloned mcast=%s:%d)",
131
- fd, inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
132
+ qemu_set_info_str(nc, "socket: fd=%d (cloned mcast=%s:%d)", fd,
133
+ inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
134
} else {
135
if (sa_type == SOCKET_ADDRESS_TYPE_UNIX) {
136
s->dgram_dst.sin_family = AF_UNIX;
82
}
137
}
83
if (strcmp(nc->model, "user")) {
138
84
monitor_printf(mon, "invalid device specified\n");
139
- snprintf(nc->info_str, sizeof(nc->info_str),
85
@@ -XXX,XX +XXX,XX @@ void hmp_hostfwd_remove(Monitor *mon, const QDict *qdict)
140
- "socket: fd=%d %s", fd, SocketAddressType_str(sa_type));
86
const char *arg2 = qdict_get_try_str(qdict, "arg2");
141
+ qemu_set_info_str(nc, "socket: fd=%d %s", fd,
87
const char *arg3 = qdict_get_try_str(qdict, "arg3");
142
+ SocketAddressType_str(sa_type));
88
143
}
89
- if (arg2) {
144
90
+ if (arg3) {
145
return s;
91
s = slirp_lookup(mon, arg1, arg2);
146
@@ -XXX,XX +XXX,XX @@ static NetSocketState *net_socket_fd_init_stream(NetClientState *peer,
92
src_str = arg3;
147
93
+ } else if (arg2) {
148
nc = qemu_new_net_client(&net_socket_info, peer, model, name);
94
+ s = slirp_lookup(mon, NULL, arg1);
149
95
+ src_str = arg2;
150
- snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd);
151
+ qemu_set_info_str(nc, "socket: fd=%d", fd);
152
153
s = DO_UPCAST(NetSocketState, nc, nc);
154
155
@@ -XXX,XX +XXX,XX @@ static void net_socket_accept(void *opaque)
156
s->fd = fd;
157
s->nc.link_down = false;
158
net_socket_connect(s);
159
- snprintf(s->nc.info_str, sizeof(s->nc.info_str),
160
- "socket: connection from %s:%d",
161
- inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
162
+ qemu_set_info_str(&s->nc, "socket: connection from %s:%d",
163
+ inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
164
}
165
166
static int net_socket_listen_init(NetClientState *peer,
167
@@ -XXX,XX +XXX,XX @@ static int net_socket_connect_init(NetClientState *peer,
168
return -1;
169
}
170
171
- snprintf(s->nc.info_str, sizeof(s->nc.info_str),
172
- "socket: connect to %s:%d",
173
- inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
174
+ qemu_set_info_str(&s->nc, "socket: connect to %s:%d",
175
+ inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
176
return 0;
177
}
178
179
@@ -XXX,XX +XXX,XX @@ static int net_socket_mcast_init(NetClientState *peer,
180
181
s->dgram_dst = saddr;
182
183
- snprintf(s->nc.info_str, sizeof(s->nc.info_str),
184
- "socket: mcast=%s:%d",
185
- inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
186
+ qemu_set_info_str(&s->nc, "socket: mcast=%s:%d",
187
+ inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
188
return 0;
189
190
}
191
@@ -XXX,XX +XXX,XX @@ static int net_socket_udp_init(NetClientState *peer,
192
193
s->dgram_dst = raddr;
194
195
- snprintf(s->nc.info_str, sizeof(s->nc.info_str),
196
- "socket: udp=%s:%d",
197
- inet_ntoa(raddr.sin_addr), ntohs(raddr.sin_port));
198
+ qemu_set_info_str(&s->nc, "socket: udp=%s:%d", inet_ntoa(raddr.sin_addr),
199
+ ntohs(raddr.sin_port));
200
return 0;
201
}
202
203
diff --git a/net/tap-win32.c b/net/tap-win32.c
204
index XXXXXXX..XXXXXXX 100644
205
--- a/net/tap-win32.c
206
+++ b/net/tap-win32.c
207
@@ -XXX,XX +XXX,XX @@ static int tap_win32_init(NetClientState *peer, const char *model,
208
209
s = DO_UPCAST(TAPState, nc, nc);
210
211
- snprintf(s->nc.info_str, sizeof(s->nc.info_str),
212
- "tap: ifname=%s", ifname);
213
+ qemu_set_info_str(&s->nc, "tap: ifname=%s", ifname);
214
215
s->handle = handle;
216
217
diff --git a/net/tap.c b/net/tap.c
218
index XXXXXXX..XXXXXXX 100644
219
--- a/net/tap.c
220
+++ b/net/tap.c
221
@@ -XXX,XX +XXX,XX @@ int net_init_bridge(const Netdev *netdev, const char *name,
222
}
223
s = net_tap_fd_init(peer, "bridge", name, fd, vnet_hdr);
224
225
- snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s,br=%s", helper,
226
- br);
227
+ qemu_set_info_str(&s->nc, "helper=%s,br=%s", helper, br);
228
229
return 0;
230
}
231
@@ -XXX,XX +XXX,XX @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
232
}
233
234
if (tap->has_fd || tap->has_fds) {
235
- snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd);
236
+ qemu_set_info_str(&s->nc, "fd=%d", fd);
237
} else if (tap->has_helper) {
238
- snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s",
239
- tap->helper);
240
+ qemu_set_info_str(&s->nc, "helper=%s", tap->helper);
96
} else {
241
} else {
97
s = slirp_lookup(mon, NULL, NULL);
242
- snprintf(s->nc.info_str, sizeof(s->nc.info_str),
98
src_str = arg1;
243
- "ifname=%s,script=%s,downscript=%s", ifname, script,
99
@@ -XXX,XX +XXX,XX @@ void hmp_hostfwd_add(Monitor *mon, const QDict *qdict)
244
- downscript);
100
const char *arg2 = qdict_get_try_str(qdict, "arg2");
245
+ qemu_set_info_str(&s->nc, "ifname=%s,script=%s,downscript=%s", ifname,
101
const char *arg3 = qdict_get_try_str(qdict, "arg3");
246
+ script, downscript);
102
247
103
- if (arg2) {
248
if (strcmp(downscript, "no") != 0) {
104
+ if (arg3) {
249
snprintf(s->down_script, sizeof(s->down_script), "%s", downscript);
105
s = slirp_lookup(mon, arg1, arg2);
250
diff --git a/net/vde.c b/net/vde.c
106
redir_str = arg3;
251
index XXXXXXX..XXXXXXX 100644
107
+ } else if (arg2) {
252
--- a/net/vde.c
108
+ s = slirp_lookup(mon, NULL, arg1);
253
+++ b/net/vde.c
109
+ redir_str = arg2;
254
@@ -XXX,XX +XXX,XX @@ static int net_vde_init(NetClientState *peer, const char *model,
110
} else {
255
111
s = slirp_lookup(mon, NULL, NULL);
256
nc = qemu_new_net_client(&net_vde_info, peer, model, name);
112
redir_str = arg1;
257
258
- snprintf(nc->info_str, sizeof(nc->info_str), "sock=%s,fd=%d",
259
- sock, vde_datafd(vde));
260
+ qemu_set_info_str(nc, "sock=%s,fd=%d", sock, vde_datafd(vde));
261
262
s = DO_UPCAST(VDEState, nc, nc);
263
264
diff --git a/net/vhost-user.c b/net/vhost-user.c
265
index XXXXXXX..XXXXXXX 100644
266
--- a/net/vhost-user.c
267
+++ b/net/vhost-user.c
268
@@ -XXX,XX +XXX,XX @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
269
user = g_new0(struct VhostUserState, 1);
270
for (i = 0; i < queues; i++) {
271
nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name);
272
- snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s",
273
- i, chr->label);
274
+ qemu_set_info_str(nc, "vhost-user%d to %s", i, chr->label);
275
nc->queue_index = i;
276
if (!nc0) {
277
nc0 = nc;
278
diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c
279
index XXXXXXX..XXXXXXX 100644
280
--- a/net/vhost-vdpa.c
281
+++ b/net/vhost-vdpa.c
282
@@ -XXX,XX +XXX,XX @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer,
283
nc = qemu_new_net_control_client(&net_vhost_vdpa_cvq_info, peer,
284
device, name);
285
}
286
- snprintf(nc->info_str, sizeof(nc->info_str), TYPE_VHOST_VDPA);
287
+ qemu_set_info_str(nc, TYPE_VHOST_VDPA);
288
s = DO_UPCAST(VhostVDPAState, nc, nc);
289
290
s->vhost_vdpa.device_fd = vdpa_device_fd;
113
--
291
--
114
2.7.4
292
2.7.4
115
293
116
294
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
Copied from socket netdev file and modified to use SocketAddress
4
primarily used for the mis-named 'vlan' feature of the networking
4
to be able to introduce new features like unix socket.
5
subsystem. Now the 'vlan' feature has been marked as deprecated, since
6
its name is rather confusing and the users often rather mis-configure
7
their network when trying to use it. But while the 'vlan' parameter
8
should be removed at one point in time, the basic idea of emulating
9
a hub in QEMU is still good: It's useful for bundling up the output of
10
multiple NICs into one single l2tp netdev for example.
11
5
12
Now to be able to use the hubport feature without 'vlan's, there is one
6
"udp" and "mcast" are squashed into dgram netdev, multicast is detected
13
missing piece: The possibility to connect a hubport to a netdev, too.
7
according to the IP address type.
14
This patch adds this possibility by introducing a new "netdev=..."
8
"listen" and "connect" modes are managed by stream netdev. An optional
15
parameter to the hubports.
9
parameter "server" defines the mode (off by default)
16
10
17
To bundle up the output of multiple NICs into one socket netdev, you can
11
The two new types need to be parsed the modern way with -netdev, because
18
now run QEMU with these parameters for example:
12
with the traditional way, the "type" field of netdev structure collides with
13
the "type" field of SocketAddress and prevents the correct evaluation of the
14
command line option. Moreover the traditional way doesn't allow to use
15
the same type (SocketAddress) several times with the -netdev option
16
(needed to specify "local" and "remote" addresses).
19
17
20
qemu-system-ppc64 ... -netdev socket,id=s1,connect=:11122 \
18
The previous commit paved the way for parsing the modern way, but
21
-netdev hubport,hubid=1,id=h1,netdev=s1 \
19
omitted one detail: how to pick modern vs. traditional, in
22
-netdev hubport,hubid=1,id=h2 -device e1000,netdev=h2 \
20
netdev_is_modern().
23
-netdev hubport,hubid=1,id=h3 -device virtio-net-pci,netdev=h3
24
21
25
For using the socket netdev, you have got to start another QEMU as the
22
We want to pick based on the value of parameter "type". But how to
26
receiving side first, for example with network dumping enabled:
23
extract it from the option argument?
27
24
28
qemu-system-x86_64 -M isapc -netdev socket,id=s0,listen=:11122 \
25
Parsing the option argument, either the modern or the traditional way,
29
-device ne2k_isa,netdev=s0 \
26
extracts it for us, but only if parsing succeeds.
30
-object filter-dump,id=f1,netdev=s0,file=/tmp/dump.dat
31
27
32
After the ppc64 guest tried to boot from both NICs, you can see in the
28
If parsing fails, there is no good option. No matter which parser we
33
dump file (using Wireshark, for example), that the output of both NICs
29
pick, it'll be the wrong one for some arguments, and the error
34
(the e1000 and the virtio-net-pci) has been successfully transfered
30
reporting will be confusing.
35
via the socket netdev in this case.
36
31
37
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
32
Fortunately, the traditional parser accepts *anything* when called in
38
Signed-off-by: Thomas Huth <thuth@redhat.com>
33
a certain way. This maximizes our chance to extract the value of
34
"type", and in turn minimizes the risk of confusing error reporting.
35
36
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
37
Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
38
Acked-by: Markus Armbruster <armbru@redhat.com>
39
Acked-by: Michael S. Tsirkin <mst@redhat.com>
39
Signed-off-by: Jason Wang <jasowang@redhat.com>
40
Signed-off-by: Jason Wang <jasowang@redhat.com>
40
---
41
---
41
net/hub.c | 27 +++++++++++++++++++++------
42
hmp-commands.hx | 2 +-
42
net/hub.h | 3 ++-
43
net/clients.h | 6 +
43
net/net.c | 2 +-
44
net/dgram.c | 537 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
44
qapi/net.json | 4 +++-
45
net/hub.c | 2 +
45
qemu-options.hx | 8 +++++---
46
net/meson.build | 2 +
46
5 files changed, 32 insertions(+), 12 deletions(-)
47
net/net.c | 30 +++-
48
net/stream.c | 425 ++++++++++++++++++++++++++++++++++++++++++++
49
qapi/net.json | 66 ++++++-
50
qemu-options.hx | 12 ++
51
9 files changed, 1078 insertions(+), 4 deletions(-)
52
create mode 100644 net/dgram.c
53
create mode 100644 net/stream.c
47
54
55
diff --git a/hmp-commands.hx b/hmp-commands.hx
56
index XXXXXXX..XXXXXXX 100644
57
--- a/hmp-commands.hx
58
+++ b/hmp-commands.hx
59
@@ -XXX,XX +XXX,XX @@ ERST
60
{
61
.name = "netdev_add",
62
.args_type = "netdev:O",
63
- .params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user"
64
+ .params = "[user|tap|socket|stream|dgram|vde|bridge|hubport|netmap|vhost-user"
65
#ifdef CONFIG_VMNET
66
"|vmnet-host|vmnet-shared|vmnet-bridged"
67
#endif
68
diff --git a/net/clients.h b/net/clients.h
69
index XXXXXXX..XXXXXXX 100644
70
--- a/net/clients.h
71
+++ b/net/clients.h
72
@@ -XXX,XX +XXX,XX @@ int net_init_hubport(const Netdev *netdev, const char *name,
73
int net_init_socket(const Netdev *netdev, const char *name,
74
NetClientState *peer, Error **errp);
75
76
+int net_init_stream(const Netdev *netdev, const char *name,
77
+ NetClientState *peer, Error **errp);
78
+
79
+int net_init_dgram(const Netdev *netdev, const char *name,
80
+ NetClientState *peer, Error **errp);
81
+
82
int net_init_tap(const Netdev *netdev, const char *name,
83
NetClientState *peer, Error **errp);
84
85
diff --git a/net/dgram.c b/net/dgram.c
86
new file mode 100644
87
index XXXXXXX..XXXXXXX
88
--- /dev/null
89
+++ b/net/dgram.c
90
@@ -XXX,XX +XXX,XX @@
91
+/*
92
+ * QEMU System Emulator
93
+ *
94
+ * Copyright (c) 2003-2008 Fabrice Bellard
95
+ * Copyright (c) 2022 Red Hat, Inc.
96
+ *
97
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
98
+ * of this software and associated documentation files (the "Software"), to deal
99
+ * in the Software without restriction, including without limitation the rights
100
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
101
+ * copies of the Software, and to permit persons to whom the Software is
102
+ * furnished to do so, subject to the following conditions:
103
+ *
104
+ * The above copyright notice and this permission notice shall be included in
105
+ * all copies or substantial portions of the Software.
106
+ *
107
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
108
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
109
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
110
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
111
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
112
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
113
+ * THE SOFTWARE.
114
+ */
115
+
116
+#include "qemu/osdep.h"
117
+
118
+#include "net/net.h"
119
+#include "clients.h"
120
+#include "monitor/monitor.h"
121
+#include "qapi/error.h"
122
+#include "qemu/error-report.h"
123
+#include "qemu/option.h"
124
+#include "qemu/sockets.h"
125
+#include "qemu/iov.h"
126
+#include "qemu/main-loop.h"
127
+#include "qemu/cutils.h"
128
+
129
+typedef struct NetDgramState {
130
+ NetClientState nc;
131
+ int fd;
132
+ SocketReadState rs;
133
+ struct sockaddr_in dgram_dst; /* contains destination iff connectionless */
134
+ bool read_poll; /* waiting to receive data? */
135
+ bool write_poll; /* waiting to transmit data? */
136
+} NetDgramState;
137
+
138
+static void net_dgram_send(void *opaque);
139
+static void net_dgram_writable(void *opaque);
140
+
141
+static void net_dgram_update_fd_handler(NetDgramState *s)
142
+{
143
+ qemu_set_fd_handler(s->fd,
144
+ s->read_poll ? net_dgram_send : NULL,
145
+ s->write_poll ? net_dgram_writable : NULL,
146
+ s);
147
+}
148
+
149
+static void net_dgram_read_poll(NetDgramState *s, bool enable)
150
+{
151
+ s->read_poll = enable;
152
+ net_dgram_update_fd_handler(s);
153
+}
154
+
155
+static void net_dgram_write_poll(NetDgramState *s, bool enable)
156
+{
157
+ s->write_poll = enable;
158
+ net_dgram_update_fd_handler(s);
159
+}
160
+
161
+static void net_dgram_writable(void *opaque)
162
+{
163
+ NetDgramState *s = opaque;
164
+
165
+ net_dgram_write_poll(s, false);
166
+
167
+ qemu_flush_queued_packets(&s->nc);
168
+}
169
+
170
+static ssize_t net_dgram_receive(NetClientState *nc,
171
+ const uint8_t *buf, size_t size)
172
+{
173
+ NetDgramState *s = DO_UPCAST(NetDgramState, nc, nc);
174
+ ssize_t ret;
175
+
176
+ do {
177
+ if (s->dgram_dst.sin_family != AF_UNIX) {
178
+ ret = sendto(s->fd, buf, size, 0,
179
+ (struct sockaddr *)&s->dgram_dst,
180
+ sizeof(s->dgram_dst));
181
+ } else {
182
+ ret = send(s->fd, buf, size, 0);
183
+ }
184
+ } while (ret == -1 && errno == EINTR);
185
+
186
+ if (ret == -1 && errno == EAGAIN) {
187
+ net_dgram_write_poll(s, true);
188
+ return 0;
189
+ }
190
+ return ret;
191
+}
192
+
193
+static void net_dgram_send_completed(NetClientState *nc, ssize_t len)
194
+{
195
+ NetDgramState *s = DO_UPCAST(NetDgramState, nc, nc);
196
+
197
+ if (!s->read_poll) {
198
+ net_dgram_read_poll(s, true);
199
+ }
200
+}
201
+
202
+static void net_dgram_rs_finalize(SocketReadState *rs)
203
+{
204
+ NetDgramState *s = container_of(rs, NetDgramState, rs);
205
+
206
+ if (qemu_send_packet_async(&s->nc, rs->buf,
207
+ rs->packet_len,
208
+ net_dgram_send_completed) == 0) {
209
+ net_dgram_read_poll(s, false);
210
+ }
211
+}
212
+
213
+static void net_dgram_send(void *opaque)
214
+{
215
+ NetDgramState *s = opaque;
216
+ int size;
217
+
218
+ size = recv(s->fd, s->rs.buf, sizeof(s->rs.buf), 0);
219
+ if (size < 0) {
220
+ return;
221
+ }
222
+ if (size == 0) {
223
+ /* end of connection */
224
+ net_dgram_read_poll(s, false);
225
+ net_dgram_write_poll(s, false);
226
+ return;
227
+ }
228
+ if (qemu_send_packet_async(&s->nc, s->rs.buf, size,
229
+ net_dgram_send_completed) == 0) {
230
+ net_dgram_read_poll(s, false);
231
+ }
232
+}
233
+
234
+static int net_dgram_mcast_create(struct sockaddr_in *mcastaddr,
235
+ struct in_addr *localaddr,
236
+ Error **errp)
237
+{
238
+ struct ip_mreq imr;
239
+ int fd;
240
+ int val, ret;
241
+#ifdef __OpenBSD__
242
+ unsigned char loop;
243
+#else
244
+ int loop;
245
+#endif
246
+
247
+ if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
248
+ error_setg(errp, "specified mcastaddr %s (0x%08x) "
249
+ "does not contain a multicast address",
250
+ inet_ntoa(mcastaddr->sin_addr),
251
+ (int)ntohl(mcastaddr->sin_addr.s_addr));
252
+ return -1;
253
+ }
254
+
255
+ fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
256
+ if (fd < 0) {
257
+ error_setg_errno(errp, errno, "can't create datagram socket");
258
+ return -1;
259
+ }
260
+
261
+ /*
262
+ * Allow multiple sockets to bind the same multicast ip and port by setting
263
+ * SO_REUSEADDR. This is the only situation where SO_REUSEADDR should be set
264
+ * on windows. Use socket_set_fast_reuse otherwise as it sets SO_REUSEADDR
265
+ * only on posix systems.
266
+ */
267
+ val = 1;
268
+ ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
269
+ if (ret < 0) {
270
+ error_setg_errno(errp, errno, "can't set socket option SO_REUSEADDR");
271
+ goto fail;
272
+ }
273
+
274
+ ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
275
+ if (ret < 0) {
276
+ error_setg_errno(errp, errno, "can't bind ip=%s to socket",
277
+ inet_ntoa(mcastaddr->sin_addr));
278
+ goto fail;
279
+ }
280
+
281
+ /* Add host to multicast group */
282
+ imr.imr_multiaddr = mcastaddr->sin_addr;
283
+ if (localaddr) {
284
+ imr.imr_interface = *localaddr;
285
+ } else {
286
+ imr.imr_interface.s_addr = htonl(INADDR_ANY);
287
+ }
288
+
289
+ ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
290
+ &imr, sizeof(struct ip_mreq));
291
+ if (ret < 0) {
292
+ error_setg_errno(errp, errno,
293
+ "can't add socket to multicast group %s",
294
+ inet_ntoa(imr.imr_multiaddr));
295
+ goto fail;
296
+ }
297
+
298
+ /* Force mcast msgs to loopback (eg. several QEMUs in same host */
299
+ loop = 1;
300
+ ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
301
+ &loop, sizeof(loop));
302
+ if (ret < 0) {
303
+ error_setg_errno(errp, errno,
304
+ "can't force multicast message to loopback");
305
+ goto fail;
306
+ }
307
+
308
+ /* If a bind address is given, only send packets from that address */
309
+ if (localaddr != NULL) {
310
+ ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
311
+ localaddr, sizeof(*localaddr));
312
+ if (ret < 0) {
313
+ error_setg_errno(errp, errno,
314
+ "can't set the default network send interface");
315
+ goto fail;
316
+ }
317
+ }
318
+
319
+ qemu_socket_set_nonblock(fd);
320
+ return fd;
321
+fail:
322
+ if (fd >= 0) {
323
+ closesocket(fd);
324
+ }
325
+ return -1;
326
+}
327
+
328
+static void net_dgram_cleanup(NetClientState *nc)
329
+{
330
+ NetDgramState *s = DO_UPCAST(NetDgramState, nc, nc);
331
+ if (s->fd != -1) {
332
+ net_dgram_read_poll(s, false);
333
+ net_dgram_write_poll(s, false);
334
+ close(s->fd);
335
+ s->fd = -1;
336
+ }
337
+}
338
+
339
+static NetClientInfo net_dgram_socket_info = {
340
+ .type = NET_CLIENT_DRIVER_DGRAM,
341
+ .size = sizeof(NetDgramState),
342
+ .receive = net_dgram_receive,
343
+ .cleanup = net_dgram_cleanup,
344
+};
345
+
346
+static NetDgramState *net_dgram_fd_init(NetClientState *peer,
347
+ const char *model,
348
+ const char *name,
349
+ int fd, int is_fd,
350
+ SocketAddress *mcast,
351
+ Error **errp)
352
+{
353
+ struct sockaddr_in saddr;
354
+ int newfd;
355
+ NetClientState *nc;
356
+ NetDgramState *s;
357
+ SocketAddress *sa;
358
+ SocketAddressType sa_type;
359
+
360
+ sa = socket_local_address(fd, errp);
361
+ if (!sa) {
362
+ return NULL;
363
+ }
364
+ sa_type = sa->type;
365
+ qapi_free_SocketAddress(sa);
366
+
367
+ /*
368
+ * fd passed: multicast: "learn" dgram_dst address from bound address and
369
+ * save it. Because this may be "shared" socket from a "master" process,
370
+ * datagrams would be recv() by ONLY ONE process: we must "clone" this
371
+ * dgram socket --jjo
372
+ */
373
+
374
+ if (is_fd && mcast != NULL) {
375
+ if (convert_host_port(&saddr, mcast->u.inet.host,
376
+ mcast->u.inet.port, errp) < 0) {
377
+ goto err;
378
+ }
379
+ /* must be bound */
380
+ if (saddr.sin_addr.s_addr == 0) {
381
+ error_setg(errp, "can't setup multicast destination address");
382
+ goto err;
383
+ }
384
+ /* clone dgram socket */
385
+ newfd = net_dgram_mcast_create(&saddr, NULL, errp);
386
+ if (newfd < 0) {
387
+ goto err;
388
+ }
389
+ /* clone newfd to fd, close newfd */
390
+ dup2(newfd, fd);
391
+ close(newfd);
392
+
393
+ }
394
+
395
+ nc = qemu_new_net_client(&net_dgram_socket_info, peer, model, name);
396
+
397
+ s = DO_UPCAST(NetDgramState, nc, nc);
398
+
399
+ s->fd = fd;
400
+ net_socket_rs_init(&s->rs, net_dgram_rs_finalize, false);
401
+ net_dgram_read_poll(s, true);
402
+
403
+ /* mcast: save bound address as dst */
404
+ if (is_fd && mcast != NULL) {
405
+ s->dgram_dst = saddr;
406
+ qemu_set_info_str(nc, "fd=%d (cloned mcast=%s:%d)", fd,
407
+ inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
408
+ } else {
409
+ if (sa_type == SOCKET_ADDRESS_TYPE_UNIX) {
410
+ s->dgram_dst.sin_family = AF_UNIX;
411
+ }
412
+
413
+ qemu_set_info_str(nc, "fd=%d %s", fd, SocketAddressType_str(sa_type));
414
+ }
415
+
416
+ return s;
417
+
418
+err:
419
+ closesocket(fd);
420
+ return NULL;
421
+}
422
+
423
+static int net_dgram_mcast_init(NetClientState *peer,
424
+ const char *model,
425
+ const char *name,
426
+ SocketAddress *remote,
427
+ SocketAddress *local,
428
+ Error **errp)
429
+{
430
+ NetDgramState *s;
431
+ int fd, ret;
432
+ struct sockaddr_in saddr;
433
+
434
+ if (remote->type != SOCKET_ADDRESS_TYPE_INET) {
435
+ error_setg(errp, "multicast only support inet type");
436
+ return -1;
437
+ }
438
+
439
+ if (convert_host_port(&saddr, remote->u.inet.host, remote->u.inet.port,
440
+ errp) < 0) {
441
+ return -1;
442
+ }
443
+
444
+ if (!local) {
445
+ fd = net_dgram_mcast_create(&saddr, NULL, errp);
446
+ if (fd < 0) {
447
+ return -1;
448
+ }
449
+ } else {
450
+ switch (local->type) {
451
+ case SOCKET_ADDRESS_TYPE_INET: {
452
+ struct in_addr localaddr;
453
+
454
+ if (inet_aton(local->u.inet.host, &localaddr) == 0) {
455
+ error_setg(errp, "localaddr '%s' is not a valid IPv4 address",
456
+ local->u.inet.host);
457
+ return -1;
458
+ }
459
+
460
+ fd = net_dgram_mcast_create(&saddr, &localaddr, errp);
461
+ if (fd < 0) {
462
+ return -1;
463
+ }
464
+ break;
465
+ }
466
+ case SOCKET_ADDRESS_TYPE_FD:
467
+ fd = monitor_fd_param(monitor_cur(), local->u.fd.str, errp);
468
+ if (fd == -1) {
469
+ return -1;
470
+ }
471
+ ret = qemu_socket_try_set_nonblock(fd);
472
+ if (ret < 0) {
473
+ error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
474
+ name, fd);
475
+ return -1;
476
+ }
477
+ break;
478
+ default:
479
+ error_setg(errp, "only support inet or fd type for local");
480
+ return -1;
481
+ }
482
+ }
483
+
484
+ s = net_dgram_fd_init(peer, model, name, fd,
485
+ local->type == SOCKET_ADDRESS_TYPE_FD,
486
+ remote, errp);
487
+ if (!s) {
488
+ return -1;
489
+ }
490
+
491
+ s->dgram_dst = saddr;
492
+
493
+ qemu_set_info_str(&s->nc, "mcast=%s:%d", inet_ntoa(saddr.sin_addr),
494
+ ntohs(saddr.sin_port));
495
+ return 0;
496
+
497
+}
498
+
499
+
500
+int net_init_dgram(const Netdev *netdev, const char *name,
501
+ NetClientState *peer, Error **errp)
502
+{
503
+ NetDgramState *s;
504
+ int fd, ret;
505
+ struct sockaddr_in raddr_in;
506
+ struct sockaddr_in laddr_in;
507
+ SocketAddress *remote, *local;
508
+
509
+ assert(netdev->type == NET_CLIENT_DRIVER_DGRAM);
510
+
511
+ remote = netdev->u.dgram.remote;
512
+ local = netdev->u.dgram.local;
513
+
514
+ /* detect multicast address */
515
+ if (remote && remote->type == SOCKET_ADDRESS_TYPE_INET) {
516
+ struct sockaddr_in mcastaddr;
517
+
518
+ if (convert_host_port(&mcastaddr, remote->u.inet.host,
519
+ remote->u.inet.port, errp) < 0) {
520
+ return -1;
521
+ }
522
+
523
+ if (IN_MULTICAST(ntohl(mcastaddr.sin_addr.s_addr))) {
524
+ return net_dgram_mcast_init(peer, "dram", name, remote, local,
525
+ errp);
526
+ }
527
+ }
528
+
529
+ /* unicast address */
530
+ if (!local) {
531
+ error_setg(errp, "dgram requires local= parameter");
532
+ return -1;
533
+ }
534
+
535
+ if (remote) {
536
+ if (local->type == SOCKET_ADDRESS_TYPE_FD) {
537
+ error_setg(errp, "don't set remote with local.fd");
538
+ return -1;
539
+ }
540
+ if (remote->type != local->type) {
541
+ error_setg(errp, "remote and local types must be the same");
542
+ return -1;
543
+ }
544
+ } else {
545
+ if (local->type != SOCKET_ADDRESS_TYPE_FD) {
546
+ error_setg(errp, "type=inet requires remote parameter");
547
+ return -1;
548
+ }
549
+ }
550
+
551
+ switch (local->type) {
552
+ case SOCKET_ADDRESS_TYPE_INET:
553
+ if (convert_host_port(&laddr_in, local->u.inet.host, local->u.inet.port,
554
+ errp) < 0) {
555
+ return -1;
556
+ }
557
+
558
+ if (convert_host_port(&raddr_in, remote->u.inet.host,
559
+ remote->u.inet.port, errp) < 0) {
560
+ return -1;
561
+ }
562
+
563
+ fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
564
+ if (fd < 0) {
565
+ error_setg_errno(errp, errno, "can't create datagram socket");
566
+ return -1;
567
+ }
568
+
569
+ ret = socket_set_fast_reuse(fd);
570
+ if (ret < 0) {
571
+ error_setg_errno(errp, errno,
572
+ "can't set socket option SO_REUSEADDR");
573
+ closesocket(fd);
574
+ return -1;
575
+ }
576
+ ret = bind(fd, (struct sockaddr *)&laddr_in, sizeof(laddr_in));
577
+ if (ret < 0) {
578
+ error_setg_errno(errp, errno, "can't bind ip=%s to socket",
579
+ inet_ntoa(laddr_in.sin_addr));
580
+ closesocket(fd);
581
+ return -1;
582
+ }
583
+ qemu_socket_set_nonblock(fd);
584
+ break;
585
+ case SOCKET_ADDRESS_TYPE_FD:
586
+ fd = monitor_fd_param(monitor_cur(), local->u.fd.str, errp);
587
+ if (fd == -1) {
588
+ return -1;
589
+ }
590
+ ret = qemu_socket_try_set_nonblock(fd);
591
+ if (ret < 0) {
592
+ error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
593
+ name, fd);
594
+ return -1;
595
+ }
596
+ break;
597
+ default:
598
+ error_setg(errp, "only support inet or fd type for local");
599
+ return -1;
600
+ }
601
+
602
+ s = net_dgram_fd_init(peer, "dgram", name, fd, 0, NULL, errp);
603
+ if (!s) {
604
+ return -1;
605
+ }
606
+
607
+ if (remote) {
608
+ s->dgram_dst = raddr_in;
609
+ }
610
+
611
+ switch (local->type) {
612
+ case SOCKET_ADDRESS_TYPE_INET:
613
+ qemu_set_info_str(&s->nc, "udp=%s:%d/%s:%d",
614
+ inet_ntoa(laddr_in.sin_addr),
615
+ ntohs(laddr_in.sin_port),
616
+ inet_ntoa(raddr_in.sin_addr),
617
+ ntohs(raddr_in.sin_port));
618
+ break;
619
+ case SOCKET_ADDRESS_TYPE_FD:
620
+ qemu_set_info_str(&s->nc, "fd=%d", fd);
621
+ break;
622
+ default:
623
+ g_assert_not_reached();
624
+ }
625
+
626
+ return 0;
627
+}
48
diff --git a/net/hub.c b/net/hub.c
628
diff --git a/net/hub.c b/net/hub.c
49
index XXXXXXX..XXXXXXX 100644
629
index XXXXXXX..XXXXXXX 100644
50
--- a/net/hub.c
630
--- a/net/hub.c
51
+++ b/net/hub.c
631
+++ b/net/hub.c
52
@@ -XXX,XX +XXX,XX @@
632
@@ -XXX,XX +XXX,XX @@ void net_hub_check_clients(void)
53
*/
633
case NET_CLIENT_DRIVER_USER:
54
634
case NET_CLIENT_DRIVER_TAP:
55
#include "qemu/osdep.h"
635
case NET_CLIENT_DRIVER_SOCKET:
56
+#include "qapi/error.h"
636
+ case NET_CLIENT_DRIVER_STREAM:
57
#include "monitor/monitor.h"
637
+ case NET_CLIENT_DRIVER_DGRAM:
58
#include "net/net.h"
638
case NET_CLIENT_DRIVER_VDE:
59
#include "clients.h"
639
case NET_CLIENT_DRIVER_VHOST_USER:
60
@@ -XXX,XX +XXX,XX @@ static NetClientInfo net_hub_port_info = {
640
has_host_dev = 1;
61
.cleanup = net_hub_port_cleanup,
641
diff --git a/net/meson.build b/net/meson.build
62
};
63
64
-static NetHubPort *net_hub_port_new(NetHub *hub, const char *name)
65
+static NetHubPort *net_hub_port_new(NetHub *hub, const char *name,
66
+ NetClientState *hubpeer)
67
{
68
NetClientState *nc;
69
NetHubPort *port;
70
@@ -XXX,XX +XXX,XX @@ static NetHubPort *net_hub_port_new(NetHub *hub, const char *name)
71
name = default_name;
72
}
73
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
}
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
642
index XXXXXXX..XXXXXXX 100644
139
--- a/net/hub.h
643
--- a/net/meson.build
140
+++ b/net/hub.h
644
+++ b/net/meson.build
141
@@ -XXX,XX +XXX,XX @@
645
@@ -XXX,XX +XXX,XX @@ softmmu_ss.add(files(
142
646
'net.c',
143
#include "qemu-common.h"
647
'queue.c',
144
648
'socket.c',
145
-NetClientState *net_hub_add_port(int hub_id, const char *name);
649
+ 'stream.c',
146
+NetClientState *net_hub_add_port(int hub_id, const char *name,
650
+ 'dgram.c',
147
+ NetClientState *hubpeer);
651
'util.c',
148
NetClientState *net_hub_find_client_by_name(int hub_id, const char *name);
652
))
149
void net_hub_info(Monitor *mon);
653
150
void net_hub_check_clients(void);
151
diff --git a/net/net.c b/net/net.c
654
diff --git a/net/net.c b/net/net.c
152
index XXXXXXX..XXXXXXX 100644
655
index XXXXXXX..XXXXXXX 100644
153
--- a/net/net.c
656
--- a/net/net.c
154
+++ b/net/net.c
657
+++ b/net/net.c
155
@@ -XXX,XX +XXX,XX @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp)
658
@@ -XXX,XX +XXX,XX @@
156
/* Do not add to a vlan if it's a nic with a netdev= parameter. */
659
#include "qemu/qemu-print.h"
157
if (netdev->type != NET_CLIENT_DRIVER_NIC ||
660
#include "qemu/main-loop.h"
158
!opts->u.nic.has_netdev) {
661
#include "qemu/option.h"
159
- peer = net_hub_add_port(net->has_vlan ? net->vlan : 0, NULL);
662
+#include "qemu/keyval.h"
160
+ peer = net_hub_add_port(net->has_vlan ? net->vlan : 0, NULL, NULL);
663
#include "qapi/error.h"
161
}
664
#include "qapi/opts-visitor.h"
162
665
#include "sysemu/runstate.h"
163
if (net->has_vlan && !vlan_warned) {
666
@@ -XXX,XX +XXX,XX @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
667
#endif
668
[NET_CLIENT_DRIVER_TAP] = net_init_tap,
669
[NET_CLIENT_DRIVER_SOCKET] = net_init_socket,
670
+ [NET_CLIENT_DRIVER_STREAM] = net_init_stream,
671
+ [NET_CLIENT_DRIVER_DGRAM] = net_init_dgram,
672
#ifdef CONFIG_VDE
673
[NET_CLIENT_DRIVER_VDE] = net_init_vde,
674
#endif
675
@@ -XXX,XX +XXX,XX @@ void show_netdevs(void)
676
int idx;
677
const char *available_netdevs[] = {
678
"socket",
679
+ "stream",
680
+ "dgram",
681
"hubport",
682
"tap",
683
#ifdef CONFIG_SLIRP
684
@@ -XXX,XX +XXX,XX @@ void net_init_clients(void)
685
*/
686
bool netdev_is_modern(const char *optarg)
687
{
688
- return false;
689
+ QemuOpts *opts;
690
+ bool is_modern;
691
+ const char *type;
692
+ static QemuOptsList dummy_opts = {
693
+ .name = "netdev",
694
+ .implied_opt_name = "type",
695
+ .head = QTAILQ_HEAD_INITIALIZER(dummy_opts.head),
696
+ .desc = { { } },
697
+ };
698
+
699
+ if (optarg[0] == '{') {
700
+ /* This is JSON, which means it's modern syntax */
701
+ return true;
702
+ }
703
+
704
+ opts = qemu_opts_create(&dummy_opts, NULL, false, &error_abort);
705
+ qemu_opts_do_parse(opts, optarg, dummy_opts.implied_opt_name,
706
+ &error_abort);
707
+ type = qemu_opt_get(opts, "type");
708
+ is_modern = !g_strcmp0(type, "stream") || !g_strcmp0(type, "dgram");
709
+
710
+ qemu_opts_reset(&dummy_opts);
711
+
712
+ return is_modern;
713
}
714
715
/*
716
diff --git a/net/stream.c b/net/stream.c
717
new file mode 100644
718
index XXXXXXX..XXXXXXX
719
--- /dev/null
720
+++ b/net/stream.c
721
@@ -XXX,XX +XXX,XX @@
722
+/*
723
+ * QEMU System Emulator
724
+ *
725
+ * Copyright (c) 2003-2008 Fabrice Bellard
726
+ * Copyright (c) 2022 Red Hat, Inc.
727
+ *
728
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
729
+ * of this software and associated documentation files (the "Software"), to deal
730
+ * in the Software without restriction, including without limitation the rights
731
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
732
+ * copies of the Software, and to permit persons to whom the Software is
733
+ * furnished to do so, subject to the following conditions:
734
+ *
735
+ * The above copyright notice and this permission notice shall be included in
736
+ * all copies or substantial portions of the Software.
737
+ *
738
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
739
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
740
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
741
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
742
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
743
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
744
+ * THE SOFTWARE.
745
+ */
746
+
747
+#include "qemu/osdep.h"
748
+
749
+#include "net/net.h"
750
+#include "clients.h"
751
+#include "monitor/monitor.h"
752
+#include "qapi/error.h"
753
+#include "qemu/error-report.h"
754
+#include "qemu/option.h"
755
+#include "qemu/sockets.h"
756
+#include "qemu/iov.h"
757
+#include "qemu/main-loop.h"
758
+#include "qemu/cutils.h"
759
+
760
+typedef struct NetStreamState {
761
+ NetClientState nc;
762
+ int listen_fd;
763
+ int fd;
764
+ SocketReadState rs;
765
+ unsigned int send_index; /* number of bytes sent*/
766
+ bool read_poll; /* waiting to receive data? */
767
+ bool write_poll; /* waiting to transmit data? */
768
+} NetStreamState;
769
+
770
+static void net_stream_send(void *opaque);
771
+static void net_stream_accept(void *opaque);
772
+static void net_stream_writable(void *opaque);
773
+
774
+static void net_stream_update_fd_handler(NetStreamState *s)
775
+{
776
+ qemu_set_fd_handler(s->fd,
777
+ s->read_poll ? net_stream_send : NULL,
778
+ s->write_poll ? net_stream_writable : NULL,
779
+ s);
780
+}
781
+
782
+static void net_stream_read_poll(NetStreamState *s, bool enable)
783
+{
784
+ s->read_poll = enable;
785
+ net_stream_update_fd_handler(s);
786
+}
787
+
788
+static void net_stream_write_poll(NetStreamState *s, bool enable)
789
+{
790
+ s->write_poll = enable;
791
+ net_stream_update_fd_handler(s);
792
+}
793
+
794
+static void net_stream_writable(void *opaque)
795
+{
796
+ NetStreamState *s = opaque;
797
+
798
+ net_stream_write_poll(s, false);
799
+
800
+ qemu_flush_queued_packets(&s->nc);
801
+}
802
+
803
+static ssize_t net_stream_receive(NetClientState *nc, const uint8_t *buf,
804
+ size_t size)
805
+{
806
+ NetStreamState *s = DO_UPCAST(NetStreamState, nc, nc);
807
+ uint32_t len = htonl(size);
808
+ struct iovec iov[] = {
809
+ {
810
+ .iov_base = &len,
811
+ .iov_len = sizeof(len),
812
+ }, {
813
+ .iov_base = (void *)buf,
814
+ .iov_len = size,
815
+ },
816
+ };
817
+ size_t remaining;
818
+ ssize_t ret;
819
+
820
+ remaining = iov_size(iov, 2) - s->send_index;
821
+ ret = iov_send(s->fd, iov, 2, s->send_index, remaining);
822
+
823
+ if (ret == -1 && errno == EAGAIN) {
824
+ ret = 0; /* handled further down */
825
+ }
826
+ if (ret == -1) {
827
+ s->send_index = 0;
828
+ return -errno;
829
+ }
830
+ if (ret < (ssize_t)remaining) {
831
+ s->send_index += ret;
832
+ net_stream_write_poll(s, true);
833
+ return 0;
834
+ }
835
+ s->send_index = 0;
836
+ return size;
837
+}
838
+
839
+static void net_stream_send_completed(NetClientState *nc, ssize_t len)
840
+{
841
+ NetStreamState *s = DO_UPCAST(NetStreamState, nc, nc);
842
+
843
+ if (!s->read_poll) {
844
+ net_stream_read_poll(s, true);
845
+ }
846
+}
847
+
848
+static void net_stream_rs_finalize(SocketReadState *rs)
849
+{
850
+ NetStreamState *s = container_of(rs, NetStreamState, rs);
851
+
852
+ if (qemu_send_packet_async(&s->nc, rs->buf,
853
+ rs->packet_len,
854
+ net_stream_send_completed) == 0) {
855
+ net_stream_read_poll(s, false);
856
+ }
857
+}
858
+
859
+static void net_stream_send(void *opaque)
860
+{
861
+ NetStreamState *s = opaque;
862
+ int size;
863
+ int ret;
864
+ uint8_t buf1[NET_BUFSIZE];
865
+ const uint8_t *buf;
866
+
867
+ size = recv(s->fd, buf1, sizeof(buf1), 0);
868
+ if (size < 0) {
869
+ if (errno != EWOULDBLOCK) {
870
+ goto eoc;
871
+ }
872
+ } else if (size == 0) {
873
+ /* end of connection */
874
+ eoc:
875
+ net_stream_read_poll(s, false);
876
+ net_stream_write_poll(s, false);
877
+ if (s->listen_fd != -1) {
878
+ qemu_set_fd_handler(s->listen_fd, net_stream_accept, NULL, s);
879
+ }
880
+ closesocket(s->fd);
881
+
882
+ s->fd = -1;
883
+ net_socket_rs_init(&s->rs, net_stream_rs_finalize, false);
884
+ s->nc.link_down = true;
885
+ qemu_set_info_str(&s->nc, "");
886
+
887
+ return;
888
+ }
889
+ buf = buf1;
890
+
891
+ ret = net_fill_rstate(&s->rs, buf, size);
892
+
893
+ if (ret == -1) {
894
+ goto eoc;
895
+ }
896
+}
897
+
898
+static void net_stream_cleanup(NetClientState *nc)
899
+{
900
+ NetStreamState *s = DO_UPCAST(NetStreamState, nc, nc);
901
+ if (s->fd != -1) {
902
+ net_stream_read_poll(s, false);
903
+ net_stream_write_poll(s, false);
904
+ close(s->fd);
905
+ s->fd = -1;
906
+ }
907
+ if (s->listen_fd != -1) {
908
+ qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
909
+ closesocket(s->listen_fd);
910
+ s->listen_fd = -1;
911
+ }
912
+}
913
+
914
+static void net_stream_connect(void *opaque)
915
+{
916
+ NetStreamState *s = opaque;
917
+ net_stream_read_poll(s, true);
918
+}
919
+
920
+static NetClientInfo net_stream_info = {
921
+ .type = NET_CLIENT_DRIVER_STREAM,
922
+ .size = sizeof(NetStreamState),
923
+ .receive = net_stream_receive,
924
+ .cleanup = net_stream_cleanup,
925
+};
926
+
927
+static NetStreamState *net_stream_fd_init(NetClientState *peer,
928
+ const char *model,
929
+ const char *name,
930
+ int fd, int is_connected)
931
+{
932
+ NetClientState *nc;
933
+ NetStreamState *s;
934
+
935
+ nc = qemu_new_net_client(&net_stream_info, peer, model, name);
936
+
937
+ qemu_set_info_str(nc, "fd=%d", fd);
938
+
939
+ s = DO_UPCAST(NetStreamState, nc, nc);
940
+
941
+ s->fd = fd;
942
+ s->listen_fd = -1;
943
+ net_socket_rs_init(&s->rs, net_stream_rs_finalize, false);
944
+
945
+ /* Disable Nagle algorithm on TCP sockets to reduce latency */
946
+ socket_set_nodelay(fd);
947
+
948
+ if (is_connected) {
949
+ net_stream_connect(s);
950
+ } else {
951
+ qemu_set_fd_handler(s->fd, NULL, net_stream_connect, s);
952
+ }
953
+ return s;
954
+}
955
+
956
+static void net_stream_accept(void *opaque)
957
+{
958
+ NetStreamState *s = opaque;
959
+ struct sockaddr_in saddr;
960
+ socklen_t len;
961
+ int fd;
962
+
963
+ for (;;) {
964
+ len = sizeof(saddr);
965
+ fd = qemu_accept(s->listen_fd, (struct sockaddr *)&saddr, &len);
966
+ if (fd < 0 && errno != EINTR) {
967
+ return;
968
+ } else if (fd >= 0) {
969
+ qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
970
+ break;
971
+ }
972
+ }
973
+
974
+ s->fd = fd;
975
+ s->nc.link_down = false;
976
+ net_stream_connect(s);
977
+ qemu_set_info_str(&s->nc, "connection from %s:%d",
978
+ inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
979
+}
980
+
981
+static int net_stream_server_init(NetClientState *peer,
982
+ const char *model,
983
+ const char *name,
984
+ SocketAddress *addr,
985
+ Error **errp)
986
+{
987
+ NetClientState *nc;
988
+ NetStreamState *s;
989
+ int fd, ret;
990
+
991
+ switch (addr->type) {
992
+ case SOCKET_ADDRESS_TYPE_INET: {
993
+ struct sockaddr_in saddr_in;
994
+
995
+ if (convert_host_port(&saddr_in, addr->u.inet.host, addr->u.inet.port,
996
+ errp) < 0) {
997
+ return -1;
998
+ }
999
+
1000
+ fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
1001
+ if (fd < 0) {
1002
+ error_setg_errno(errp, errno, "can't create stream socket");
1003
+ return -1;
1004
+ }
1005
+ qemu_socket_set_nonblock(fd);
1006
+
1007
+ socket_set_fast_reuse(fd);
1008
+
1009
+ ret = bind(fd, (struct sockaddr *)&saddr_in, sizeof(saddr_in));
1010
+ if (ret < 0) {
1011
+ error_setg_errno(errp, errno, "can't bind ip=%s to socket",
1012
+ inet_ntoa(saddr_in.sin_addr));
1013
+ closesocket(fd);
1014
+ return -1;
1015
+ }
1016
+ break;
1017
+ }
1018
+ case SOCKET_ADDRESS_TYPE_FD:
1019
+ fd = monitor_fd_param(monitor_cur(), addr->u.fd.str, errp);
1020
+ if (fd == -1) {
1021
+ return -1;
1022
+ }
1023
+ ret = qemu_socket_try_set_nonblock(fd);
1024
+ if (ret < 0) {
1025
+ error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
1026
+ name, fd);
1027
+ return -1;
1028
+ }
1029
+ break;
1030
+ default:
1031
+ error_setg(errp, "only support inet or fd type");
1032
+ return -1;
1033
+ }
1034
+
1035
+ ret = listen(fd, 0);
1036
+ if (ret < 0) {
1037
+ error_setg_errno(errp, errno, "can't listen on socket");
1038
+ closesocket(fd);
1039
+ return -1;
1040
+ }
1041
+
1042
+ nc = qemu_new_net_client(&net_stream_info, peer, model, name);
1043
+ s = DO_UPCAST(NetStreamState, nc, nc);
1044
+ s->fd = -1;
1045
+ s->listen_fd = fd;
1046
+ s->nc.link_down = true;
1047
+ net_socket_rs_init(&s->rs, net_stream_rs_finalize, false);
1048
+
1049
+ qemu_set_fd_handler(s->listen_fd, net_stream_accept, NULL, s);
1050
+ return 0;
1051
+}
1052
+
1053
+static int net_stream_client_init(NetClientState *peer,
1054
+ const char *model,
1055
+ const char *name,
1056
+ SocketAddress *addr,
1057
+ Error **errp)
1058
+{
1059
+ NetStreamState *s;
1060
+ struct sockaddr_in saddr_in;
1061
+ int fd, connected, ret;
1062
+
1063
+ switch (addr->type) {
1064
+ case SOCKET_ADDRESS_TYPE_INET:
1065
+ if (convert_host_port(&saddr_in, addr->u.inet.host, addr->u.inet.port,
1066
+ errp) < 0) {
1067
+ return -1;
1068
+ }
1069
+
1070
+ fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
1071
+ if (fd < 0) {
1072
+ error_setg_errno(errp, errno, "can't create stream socket");
1073
+ return -1;
1074
+ }
1075
+ qemu_socket_set_nonblock(fd);
1076
+
1077
+ connected = 0;
1078
+ for (;;) {
1079
+ ret = connect(fd, (struct sockaddr *)&saddr_in, sizeof(saddr_in));
1080
+ if (ret < 0) {
1081
+ if (errno == EINTR || errno == EWOULDBLOCK) {
1082
+ /* continue */
1083
+ } else if (errno == EINPROGRESS ||
1084
+ errno == EALREADY ||
1085
+ errno == EINVAL) {
1086
+ break;
1087
+ } else {
1088
+ error_setg_errno(errp, errno, "can't connect socket");
1089
+ closesocket(fd);
1090
+ return -1;
1091
+ }
1092
+ } else {
1093
+ connected = 1;
1094
+ break;
1095
+ }
1096
+ }
1097
+ break;
1098
+ case SOCKET_ADDRESS_TYPE_FD:
1099
+ fd = monitor_fd_param(monitor_cur(), addr->u.fd.str, errp);
1100
+ if (fd == -1) {
1101
+ return -1;
1102
+ }
1103
+ ret = qemu_socket_try_set_nonblock(fd);
1104
+ if (ret < 0) {
1105
+ error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
1106
+ name, fd);
1107
+ return -1;
1108
+ }
1109
+ connected = 1;
1110
+ break;
1111
+ default:
1112
+ error_setg(errp, "only support inet or fd type");
1113
+ return -1;
1114
+ }
1115
+
1116
+ s = net_stream_fd_init(peer, model, name, fd, connected);
1117
+
1118
+ switch (addr->type) {
1119
+ case SOCKET_ADDRESS_TYPE_INET:
1120
+ qemu_set_info_str(&s->nc, "connect to %s:%d",
1121
+ inet_ntoa(saddr_in.sin_addr),
1122
+ ntohs(saddr_in.sin_port));
1123
+ break;
1124
+ case SOCKET_ADDRESS_TYPE_FD:
1125
+ qemu_set_info_str(&s->nc, "connect to fd %d", fd);
1126
+ break;
1127
+ default:
1128
+ g_assert_not_reached();
1129
+ }
1130
+
1131
+ return 0;
1132
+}
1133
+
1134
+int net_init_stream(const Netdev *netdev, const char *name,
1135
+ NetClientState *peer, Error **errp)
1136
+{
1137
+ const NetdevStreamOptions *sock;
1138
+
1139
+ assert(netdev->type == NET_CLIENT_DRIVER_STREAM);
1140
+ sock = &netdev->u.stream;
1141
+
1142
+ if (!sock->has_server || !sock->server) {
1143
+ return net_stream_client_init(peer, "stream", name, sock->addr, errp);
1144
+ }
1145
+ return net_stream_server_init(peer, "stream", name, sock->addr, errp);
1146
+}
164
diff --git a/qapi/net.json b/qapi/net.json
1147
diff --git a/qapi/net.json b/qapi/net.json
165
index XXXXXXX..XXXXXXX 100644
1148
index XXXXXXX..XXXXXXX 100644
166
--- a/qapi/net.json
1149
--- a/qapi/net.json
167
+++ b/qapi/net.json
1150
+++ b/qapi/net.json
168
@@ -XXX,XX +XXX,XX @@
1151
@@ -XXX,XX +XXX,XX @@
169
# Connect two or more net clients through a software hub.
1152
##
1153
1154
{ 'include': 'common.json' }
1155
+{ 'include': 'sockets.json' }
1156
1157
##
1158
# @set_link:
1159
@@ -XXX,XX +XXX,XX @@
1160
'if': 'CONFIG_VMNET' }
1161
1162
##
1163
+# @NetdevStreamOptions:
1164
+#
1165
+# Configuration info for stream socket netdev
1166
+#
1167
+# @addr: socket address to listen on (server=true)
1168
+# or connect to (server=false)
1169
+# @server: create server socket (default: false)
1170
+#
1171
+# Only SocketAddress types 'inet' and 'fd' are supported.
1172
+#
1173
+# Since: 7.2
1174
+##
1175
+{ 'struct': 'NetdevStreamOptions',
1176
+ 'data': {
1177
+ 'addr': 'SocketAddress',
1178
+ '*server': 'bool' } }
1179
+
1180
+##
1181
+# @NetdevDgramOptions:
1182
+#
1183
+# Configuration info for datagram socket netdev.
1184
+#
1185
+# @remote: remote address
1186
+# @local: local address
1187
+#
1188
+# Only SocketAddress types 'inet' and 'fd' are supported.
1189
+#
1190
+# If remote address is present and it's a multicast address, local address
1191
+# is optional. Otherwise local address is required and remote address is
1192
+# optional.
1193
+#
1194
+# .. table:: Valid parameters combination table
1195
+# :widths: auto
1196
+#
1197
+# ============= ======== =====
1198
+# remote local okay?
1199
+# ============= ======== =====
1200
+# absent absent no
1201
+# absent not fd no
1202
+# absent fd yes
1203
+# multicast absent yes
1204
+# multicast present yes
1205
+# not multicast absent no
1206
+# not multicast present yes
1207
+# ============= ======== =====
1208
+#
1209
+# Since: 7.2
1210
+##
1211
+{ 'struct': 'NetdevDgramOptions',
1212
+ 'data': {
1213
+ '*local': 'SocketAddress',
1214
+ '*remote': 'SocketAddress' } }
1215
+
1216
+##
1217
# @NetClientDriver:
170
#
1218
#
171
# @hubid: hub identifier number
1219
# Available netdev drivers.
172
+# @netdev: used to connect hub to a netdev instead of a device (since 2.12)
1220
@@ -XXX,XX +XXX,XX @@
173
#
1221
# @vmnet-host since 7.1
174
# Since: 1.2
1222
# @vmnet-shared since 7.1
1223
# @vmnet-bridged since 7.1
1224
+# @stream since 7.2
1225
+# @dgram since 7.2
175
##
1226
##
176
{ 'struct': 'NetdevHubPortOptions',
1227
{ 'enum': 'NetClientDriver',
177
'data': {
1228
- 'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'vde',
178
- 'hubid': 'int32' } }
1229
- 'bridge', 'hubport', 'netmap', 'vhost-user', 'vhost-vdpa',
179
+ 'hubid': 'int32',
1230
+ 'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'stream',
180
+ '*netdev': 'str' } }
1231
+ 'dgram', 'vde', 'bridge', 'hubport', 'netmap', 'vhost-user',
181
1232
+ 'vhost-vdpa',
1233
{ 'name': 'vmnet-host', 'if': 'CONFIG_VMNET' },
1234
{ 'name': 'vmnet-shared', 'if': 'CONFIG_VMNET' },
1235
{ 'name': 'vmnet-bridged', 'if': 'CONFIG_VMNET' }] }
1236
@@ -XXX,XX +XXX,XX @@
1237
# 'vmnet-host' - since 7.1
1238
# 'vmnet-shared' - since 7.1
1239
# 'vmnet-bridged' - since 7.1
1240
+# 'stream' since 7.2
1241
+# 'dgram' since 7.2
182
##
1242
##
183
# @NetdevNetmapOptions:
1243
{ 'union': 'Netdev',
1244
'base': { 'id': 'str', 'type': 'NetClientDriver' },
1245
@@ -XXX,XX +XXX,XX @@
1246
'tap': 'NetdevTapOptions',
1247
'l2tpv3': 'NetdevL2TPv3Options',
1248
'socket': 'NetdevSocketOptions',
1249
+ 'stream': 'NetdevStreamOptions',
1250
+ 'dgram': 'NetdevDgramOptions',
1251
'vde': 'NetdevVdeOptions',
1252
'bridge': 'NetdevBridgeOptions',
1253
'hubport': 'NetdevHubPortOptions',
184
diff --git a/qemu-options.hx b/qemu-options.hx
1254
diff --git a/qemu-options.hx b/qemu-options.hx
185
index XXXXXXX..XXXXXXX 100644
1255
index XXXXXXX..XXXXXXX 100644
186
--- a/qemu-options.hx
1256
--- a/qemu-options.hx
187
+++ b/qemu-options.hx
1257
+++ b/qemu-options.hx
188
@@ -XXX,XX +XXX,XX @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
1258
@@ -XXX,XX +XXX,XX @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
189
#endif
1259
"-netdev socket,id=str[,fd=h][,udp=host:port][,localaddr=host:port]\n"
190
"-netdev vhost-user,id=str,chardev=dev[,vhostforce=on|off]\n"
1260
" configure a network backend to connect to another network\n"
191
" configure a vhost-user network, backed by a chardev 'dev'\n"
1261
" using an UDP tunnel\n"
192
- "-netdev hubport,id=str,hubid=n\n"
1262
+ "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port\n"
193
+ "-netdev hubport,id=str,hubid=n[,netdev=nd]\n"
1263
+ "-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor\n"
194
" configure a hub port on QEMU VLAN 'n'\n", QEMU_ARCH_ALL)
1264
+ " configure a network backend to connect to another network\n"
195
DEF("net", HAS_ARG, QEMU_OPTION_net,
1265
+ " using a socket connection in stream mode.\n"
196
"-net nic[,vlan=n][,netdev=nd][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n"
1266
+ "-netdev dgram,id=str,remote.type=inet,remote.host=maddr,remote.port=port[,local.type=inet,local.host=addr]\n"
197
@@ -XXX,XX +XXX,XX @@ vde_switch -F -sock /tmp/myswitch
1267
+ "-netdev dgram,id=str,remote.type=inet,remote.host=maddr,remote.port=port[,local.type=fd,local.str=file-descriptor]\n"
198
qemu-system-i386 linux.img -net nic -net vde,sock=/tmp/myswitch
1268
+ " configure a network backend to connect to a multicast maddr and port\n"
199
@end example
1269
+ " use ``local.host=addr`` to specify the host address to send packets from\n"
200
1270
+ "-netdev dgram,id=str,local.type=inet,local.host=addr,local.port=port[,remote.type=inet,remote.host=addr,remote.port=port]\n"
201
-@item -netdev hubport,id=@var{id},hubid=@var{hubid}
1271
+ "-netdev dgram,id=str,local.type=fd,local.str=file-descriptor\n"
202
+@item -netdev hubport,id=@var{id},hubid=@var{hubid}[,netdev=@var{nd}]
1272
+ " configure a network backend to connect to another network\n"
203
1273
+ " using an UDP tunnel\n"
204
Create a hub port on QEMU "vlan" @var{hubid}.
1274
#ifdef CONFIG_VDE
205
1275
"-netdev vde,id=str[,sock=socketpath][,port=n][,group=groupname][,mode=octalmode]\n"
206
The hubport netdev lets you connect a NIC to a QEMU "vlan" instead of a single
1276
" configure a network backend to connect to port 'n' of a vde switch\n"
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
--
1277
--
216
2.7.4
1278
2.7.4
217
218
diff view generated by jsdifflib
New patch
1
From: Stefano Brivio <sbrivio@redhat.com>
1
2
3
Other errors are treated as failure by net_socket_connect_init(),
4
but if connect() returns EINVAL, we'll fail silently. Remove the
5
related exception.
6
7
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
8
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
9
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
10
Acked-by: Michael S. Tsirkin <mst@redhat.com>
11
Signed-off-by: Jason Wang <jasowang@redhat.com>
12
---
13
net/socket.c | 3 +--
14
1 file changed, 1 insertion(+), 2 deletions(-)
15
16
diff --git a/net/socket.c b/net/socket.c
17
index XXXXXXX..XXXXXXX 100644
18
--- a/net/socket.c
19
+++ b/net/socket.c
20
@@ -XXX,XX +XXX,XX @@ static int net_socket_connect_init(NetClientState *peer,
21
if (errno == EINTR || errno == EWOULDBLOCK) {
22
/* continue */
23
} else if (errno == EINPROGRESS ||
24
- errno == EALREADY ||
25
- errno == EINVAL) {
26
+ errno == EALREADY) {
27
break;
28
} else {
29
error_setg_errno(errp, errno, "can't connect socket");
30
--
31
2.7.4
diff view generated by jsdifflib
New patch
1
From: Stefano Brivio <sbrivio@redhat.com>
1
2
3
Other errors are treated as failure by net_stream_client_init(),
4
but if connect() returns EINVAL, we'll fail silently. Remove the
5
related exception.
6
7
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
8
[lvivier: applied to net/stream.c]
9
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
10
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
11
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
12
Acked-by: Michael S. Tsirkin <mst@redhat.com>
13
Signed-off-by: Jason Wang <jasowang@redhat.com>
14
---
15
net/stream.c | 3 +--
16
1 file changed, 1 insertion(+), 2 deletions(-)
17
18
diff --git a/net/stream.c b/net/stream.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/net/stream.c
21
+++ b/net/stream.c
22
@@ -XXX,XX +XXX,XX @@ static int net_stream_client_init(NetClientState *peer,
23
if (errno == EINTR || errno == EWOULDBLOCK) {
24
/* continue */
25
} else if (errno == EINPROGRESS ||
26
- errno == EALREADY ||
27
- errno == EINVAL) {
28
+ errno == EALREADY) {
29
break;
30
} else {
31
error_setg_errno(errp, errno, "can't connect socket");
32
--
33
2.7.4
34
35
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
Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
5
5
Acked-by: Michael S. Tsirkin <mst@redhat.com>
6
Cc: Zhang Chen <zhangckid@gmail.com>
6
Acked-by: Markus Armbruster <armbru@redhat.com> (QAPI schema)
7
Cc: Li Zhijian <lizhijian@cn.fujitsu.com>
7
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
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>
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
15
---
9
---
16
net/colo-compare.c | 88 +++++++++++++++++++++++++++---------------------------
10
net/stream.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
17
1 file changed, 44 insertions(+), 44 deletions(-)
11
qapi/net.json | 2 +-
18
12
qemu-options.hx | 1 +
19
diff --git a/net/colo-compare.c b/net/colo-compare.c
13
3 files changed, 104 insertions(+), 6 deletions(-)
14
15
diff --git a/net/stream.c b/net/stream.c
20
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
21
--- a/net/colo-compare.c
17
--- a/net/stream.c
22
+++ b/net/colo-compare.c
18
+++ b/net/stream.c
23
@@ -XXX,XX +XXX,XX @@ static int packet_enqueue(CompareState *s, int mode, Connection **con)
19
@@ -XXX,XX +XXX,XX @@ static NetStreamState *net_stream_fd_init(NetClientState *peer,
24
* return: 0 means packet same
20
static void net_stream_accept(void *opaque)
25
* > 0 || < 0 means packet different
26
*/
27
-static int colo_packet_compare_common(Packet *ppkt,
28
- Packet *spkt,
29
- int poffset,
30
- int soffset)
31
+static int colo_compare_packet_payload(Packet *ppkt,
32
+ Packet *spkt,
33
+ uint16_t poffset,
34
+ uint16_t soffset,
35
+ uint16_t len)
36
+
37
{
21
{
38
if (trace_event_get_state_backends(TRACE_COLO_COMPARE_MISCOMPARE)) {
22
NetStreamState *s = opaque;
39
char pri_ip_src[20], pri_ip_dst[20], sec_ip_src[20], sec_ip_dst[20];
23
- struct sockaddr_in saddr;
40
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_common(Packet *ppkt,
24
+ struct sockaddr_storage saddr;
41
sec_ip_src, sec_ip_dst);
25
socklen_t len;
26
int fd;
27
28
@@ -XXX,XX +XXX,XX @@ static void net_stream_accept(void *opaque)
29
s->fd = fd;
30
s->nc.link_down = false;
31
net_stream_connect(s);
32
- qemu_set_info_str(&s->nc, "connection from %s:%d",
33
- inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
34
+ switch (saddr.ss_family) {
35
+ case AF_INET: {
36
+ struct sockaddr_in *saddr_in = (struct sockaddr_in *)&saddr;
37
+
38
+ qemu_set_info_str(&s->nc, "connection from %s:%d",
39
+ inet_ntoa(saddr_in->sin_addr),
40
+ ntohs(saddr_in->sin_port));
41
+ break;
42
+ }
43
+ case AF_UNIX: {
44
+ struct sockaddr_un saddr_un;
45
+
46
+ len = sizeof(saddr_un);
47
+ getsockname(s->listen_fd, (struct sockaddr *)&saddr_un, &len);
48
+ qemu_set_info_str(&s->nc, "connect from %s", saddr_un.sun_path);
49
+ break;
50
+ }
51
+ default:
52
+ g_assert_not_reached();
53
+ }
54
}
55
56
static int net_stream_server_init(NetClientState *peer,
57
@@ -XXX,XX +XXX,XX @@ static int net_stream_server_init(NetClientState *peer,
58
}
59
break;
42
}
60
}
43
61
+ case SOCKET_ADDRESS_TYPE_UNIX: {
44
- poffset = ppkt->vnet_hdr_len + poffset;
62
+ struct sockaddr_un saddr_un;
45
- soffset = ppkt->vnet_hdr_len + soffset;
63
+
46
-
64
+ ret = unlink(addr->u.q_unix.path);
47
- if (ppkt->size - poffset == spkt->size - soffset) {
65
+ if (ret < 0 && errno != ENOENT) {
48
- return memcmp(ppkt->data + poffset,
66
+ error_setg_errno(errp, errno, "failed to unlink socket %s",
49
- spkt->data + soffset,
67
+ addr->u.q_unix.path);
50
- spkt->size - soffset);
68
+ return -1;
51
- } else {
69
+ }
52
- trace_colo_compare_main("Net packet size are not the same");
70
+
53
- return -1;
71
+ saddr_un.sun_family = PF_UNIX;
54
- }
72
+ ret = snprintf(saddr_un.sun_path, sizeof(saddr_un.sun_path), "%s",
55
+ return memcmp(ppkt->data + poffset, spkt->data + soffset, len);
73
+ addr->u.q_unix.path);
56
}
74
+ if (ret < 0 || ret >= sizeof(saddr_un.sun_path)) {
57
75
+ error_setg(errp, "UNIX socket path '%s' is too long",
58
/*
76
+ addr->u.q_unix.path);
59
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt)
77
+ error_append_hint(errp, "Path must be less than %zu bytes\n",
60
* the secondary guest's timestamp. COLO just focus on payload,
78
+ sizeof(saddr_un.sun_path));
61
* so we just need skip this field.
79
+ return -1;
62
*/
80
+ }
63
- if (ptcp->th_off > 5) {
81
+
64
- ptrdiff_t ptcp_offset, stcp_offset;
82
+ fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
65
83
+ if (fd < 0) {
66
- ptcp_offset = ppkt->transport_header - (uint8_t *)ppkt->data
84
+ error_setg_errno(errp, errno, "can't create stream socket");
67
- + (ptcp->th_off * 4) - ppkt->vnet_hdr_len;
85
+ return -1;
68
- stcp_offset = spkt->transport_header - (uint8_t *)spkt->data
86
+ }
69
- + (stcp->th_off * 4) - spkt->vnet_hdr_len;
87
+ qemu_socket_set_nonblock(fd);
70
+ ptrdiff_t ptcp_offset, stcp_offset;
88
+
71
89
+ ret = bind(fd, (struct sockaddr *)&saddr_un, sizeof(saddr_un));
72
- /*
90
+ if (ret < 0) {
73
- * When network is busy, some tcp options(like sack) will unpredictable
91
+ error_setg_errno(errp, errno, "can't create socket with path: %s",
74
- * occur in primary side or secondary side. it will make packet size
92
+ saddr_un.sun_path);
75
- * not same, but the two packet's payload is identical. colo just
93
+ closesocket(fd);
76
- * care about packet payload, so we skip the option field.
94
+ return -1;
77
- */
95
+ }
78
- res = colo_packet_compare_common(ppkt, spkt, ptcp_offset, stcp_offset);
96
+ break;
79
- } else if (ptcp->th_sum == stcp->th_sum) {
97
+ }
80
- res = colo_packet_compare_common(ppkt, spkt, ETH_HLEN, ETH_HLEN);
98
case SOCKET_ADDRESS_TYPE_FD:
81
+ ptcp_offset = ppkt->transport_header - (uint8_t *)ppkt->data
99
fd = monitor_fd_param(monitor_cur(), addr->u.fd.str, errp);
82
+ + (ptcp->th_off << 2) - ppkt->vnet_hdr_len;
100
if (fd == -1) {
83
+ stcp_offset = spkt->transport_header - (uint8_t *)spkt->data
101
@@ -XXX,XX +XXX,XX @@ static int net_stream_client_init(NetClientState *peer,
84
+ + (stcp->th_off << 2) - spkt->vnet_hdr_len;
102
{
85
+ if (ppkt->size - ptcp_offset == spkt->size - stcp_offset) {
103
NetStreamState *s;
86
+ res = colo_compare_packet_payload(ppkt, spkt,
104
struct sockaddr_in saddr_in;
87
+ ptcp_offset, stcp_offset,
105
+ struct sockaddr_un saddr_un;
88
+ ppkt->size - ptcp_offset);
106
int fd, connected, ret;
89
} else {
107
90
+ trace_colo_compare_main("TCP: payload size of packets are different");
108
switch (addr->type) {
91
res = -1;
109
@@ -XXX,XX +XXX,XX @@ static int net_stream_client_init(NetClientState *peer,
110
}
111
}
112
break;
113
+ case SOCKET_ADDRESS_TYPE_UNIX:
114
+ saddr_un.sun_family = PF_UNIX;
115
+ ret = snprintf(saddr_un.sun_path, sizeof(saddr_un.sun_path), "%s",
116
+ addr->u.q_unix.path);
117
+ if (ret < 0 || ret >= sizeof(saddr_un.sun_path)) {
118
+ error_setg(errp, "UNIX socket path '%s' is too long",
119
+ addr->u.q_unix.path);
120
+ error_append_hint(errp, "Path must be less than %zu bytes\n",
121
+ sizeof(saddr_un.sun_path));
122
+ return -1;
123
+ }
124
+
125
+ fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
126
+ if (fd < 0) {
127
+ error_setg_errno(errp, errno, "can't create stream socket");
128
+ return -1;
129
+ }
130
+ qemu_socket_set_nonblock(fd);
131
+
132
+ connected = 0;
133
+ for (;;) {
134
+ ret = connect(fd, (struct sockaddr *)&saddr_un, sizeof(saddr_un));
135
+ if (ret < 0) {
136
+ if (errno == EINTR || errno == EWOULDBLOCK) {
137
+ /* continue */
138
+ } else if (errno == EAGAIN ||
139
+ errno == EALREADY) {
140
+ break;
141
+ } else {
142
+ error_setg_errno(errp, errno, "can't connect socket");
143
+ closesocket(fd);
144
+ return -1;
145
+ }
146
+ } else {
147
+ connected = 1;
148
+ break;
149
+ }
150
+ }
151
+ break;
152
case SOCKET_ADDRESS_TYPE_FD:
153
fd = monitor_fd_param(monitor_cur(), addr->u.fd.str, errp);
154
if (fd == -1) {
155
@@ -XXX,XX +XXX,XX @@ static int net_stream_client_init(NetClientState *peer,
156
connected = 1;
157
break;
158
default:
159
- error_setg(errp, "only support inet or fd type");
160
+ error_setg(errp, "only support inet, unix or fd type");
161
return -1;
92
}
162
}
93
163
94
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_tcp(Packet *spkt, Packet *ppkt)
164
@@ -XXX,XX +XXX,XX @@ static int net_stream_client_init(NetClientState *peer,
95
*/
165
inet_ntoa(saddr_in.sin_addr),
96
static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
166
ntohs(saddr_in.sin_port));
97
{
167
break;
98
- int ret;
168
+ case SOCKET_ADDRESS_TYPE_UNIX:
99
- int network_header_length = ppkt->ip->ip_hl * 4;
169
+ qemu_set_info_str(&s->nc, " connect to %s", saddr_un.sun_path);
100
+ uint16_t network_header_length = ppkt->ip->ip_hl << 2;
170
+ break;
101
+ uint16_t offset = network_header_length + ETH_HLEN + ppkt->vnet_hdr_len;
171
case SOCKET_ADDRESS_TYPE_FD:
102
172
qemu_set_info_str(&s->nc, "connect to fd %d", fd);
103
trace_colo_compare_main("compare udp");
173
break;
104
174
default:
105
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
175
g_assert_not_reached();
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
}
176
}
131
-
177
-
132
- return ret;
178
return 0;
133
}
179
}
134
180
135
/*
181
diff --git a/qapi/net.json b/qapi/net.json
136
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_udp(Packet *spkt, Packet *ppkt)
182
index XXXXXXX..XXXXXXX 100644
137
*/
183
--- a/qapi/net.json
138
static int colo_packet_compare_icmp(Packet *spkt, Packet *ppkt)
184
+++ b/qapi/net.json
139
{
185
@@ -XXX,XX +XXX,XX @@
140
- int network_header_length = ppkt->ip->ip_hl * 4;
186
# or connect to (server=false)
141
+ uint16_t network_header_length = ppkt->ip->ip_hl << 2;
187
# @server: create server socket (default: false)
142
+ uint16_t offset = network_header_length + ETH_HLEN + ppkt->vnet_hdr_len;
188
#
143
189
-# Only SocketAddress types 'inet' and 'fd' are supported.
144
trace_colo_compare_main("compare icmp");
190
+# Only SocketAddress types 'unix', 'inet' and 'fd' are supported.
145
191
#
146
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_icmp(Packet *spkt, Packet *ppkt)
192
# Since: 7.2
147
* other field like TOS,TTL,IP Checksum. we only need to compare
193
##
148
* the ip payload here.
194
diff --git a/qemu-options.hx b/qemu-options.hx
149
*/
195
index XXXXXXX..XXXXXXX 100644
150
- if (colo_packet_compare_common(ppkt, spkt,
196
--- a/qemu-options.hx
151
- network_header_length + ETH_HLEN,
197
+++ b/qemu-options.hx
152
- network_header_length + ETH_HLEN)) {
198
@@ -XXX,XX +XXX,XX @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
153
+ if (ppkt->size != spkt->size) {
199
" configure a network backend to connect to another network\n"
154
+ trace_colo_compare_main("ICMP: payload size of packets are different");
200
" using an UDP tunnel\n"
155
+ return -1;
201
"-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port\n"
156
+ }
202
+ "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path\n"
157
+ if (colo_compare_packet_payload(ppkt, spkt, offset, offset,
203
"-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor\n"
158
+ ppkt->size - offset)) {
204
" configure a network backend to connect to another network\n"
159
trace_colo_compare_icmp_miscompare("primary pkt size",
205
" using a socket connection in stream mode.\n"
160
ppkt->size);
161
trace_colo_compare_icmp_miscompare("Secondary pkt size",
162
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_icmp(Packet *spkt, Packet *ppkt)
163
*/
164
static int colo_packet_compare_other(Packet *spkt, Packet *ppkt)
165
{
166
+ uint16_t offset = ppkt->vnet_hdr_len;
167
+
168
trace_colo_compare_main("compare other");
169
if (trace_event_get_state_backends(TRACE_COLO_COMPARE_MISCOMPARE)) {
170
char pri_ip_src[20], pri_ip_dst[20], sec_ip_src[20], sec_ip_dst[20];
171
@@ -XXX,XX +XXX,XX @@ static int colo_packet_compare_other(Packet *spkt, Packet *ppkt)
172
sec_ip_src, sec_ip_dst);
173
}
174
175
- return colo_packet_compare_common(ppkt, spkt, 0, 0);
176
+ if (ppkt->size != spkt->size) {
177
+ trace_colo_compare_main("Other: payload size of packets are different");
178
+ return -1;
179
+ }
180
+ return colo_compare_packet_payload(ppkt, spkt, offset, offset,
181
+ ppkt->size - offset);
182
}
183
184
static int colo_old_packet_check_one(Packet *pkt, int64_t *check_time)
185
--
206
--
186
2.7.4
207
2.7.4
187
208
188
209
diff view generated by jsdifflib
New patch
1
1
From: Laurent Vivier <lvivier@redhat.com>
2
3
dgram_dst is a sockaddr_in structure. To be able to use it with
4
unix socket, use a pointer to a generic sockaddr structure.
5
6
Rename it dest_addr, and store socket length in dest_len.
7
8
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
9
Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
10
Acked-by: Michael S. Tsirkin <mst@redhat.com>
11
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
12
Signed-off-by: Jason Wang <jasowang@redhat.com>
13
---
14
net/dgram.c | 82 +++++++++++++++++++++++++++++++++++++++----------------------
15
1 file changed, 53 insertions(+), 29 deletions(-)
16
17
diff --git a/net/dgram.c b/net/dgram.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/net/dgram.c
20
+++ b/net/dgram.c
21
@@ -XXX,XX +XXX,XX @@ typedef struct NetDgramState {
22
NetClientState nc;
23
int fd;
24
SocketReadState rs;
25
- struct sockaddr_in dgram_dst; /* contains destination iff connectionless */
26
bool read_poll; /* waiting to receive data? */
27
bool write_poll; /* waiting to transmit data? */
28
+ /* contains destination iff connectionless */
29
+ struct sockaddr *dest_addr;
30
+ socklen_t dest_len;
31
} NetDgramState;
32
33
static void net_dgram_send(void *opaque);
34
@@ -XXX,XX +XXX,XX @@ static ssize_t net_dgram_receive(NetClientState *nc,
35
ssize_t ret;
36
37
do {
38
- if (s->dgram_dst.sin_family != AF_UNIX) {
39
- ret = sendto(s->fd, buf, size, 0,
40
- (struct sockaddr *)&s->dgram_dst,
41
- sizeof(s->dgram_dst));
42
+ if (s->dest_addr) {
43
+ ret = sendto(s->fd, buf, size, 0, s->dest_addr, s->dest_len);
44
} else {
45
ret = send(s->fd, buf, size, 0);
46
}
47
@@ -XXX,XX +XXX,XX @@ static void net_dgram_cleanup(NetClientState *nc)
48
close(s->fd);
49
s->fd = -1;
50
}
51
+ g_free(s->dest_addr);
52
+ s->dest_addr = NULL;
53
+ s->dest_len = 0;
54
}
55
56
static NetClientInfo net_dgram_socket_info = {
57
@@ -XXX,XX +XXX,XX @@ static NetDgramState *net_dgram_fd_init(NetClientState *peer,
58
SocketAddress *mcast,
59
Error **errp)
60
{
61
- struct sockaddr_in saddr;
62
+ struct sockaddr_in *saddr = NULL;
63
int newfd;
64
NetClientState *nc;
65
NetDgramState *s;
66
@@ -XXX,XX +XXX,XX @@ static NetDgramState *net_dgram_fd_init(NetClientState *peer,
67
qapi_free_SocketAddress(sa);
68
69
/*
70
- * fd passed: multicast: "learn" dgram_dst address from bound address and
71
+ * fd passed: multicast: "learn" dest_addr address from bound address and
72
* save it. Because this may be "shared" socket from a "master" process,
73
* datagrams would be recv() by ONLY ONE process: we must "clone" this
74
* dgram socket --jjo
75
*/
76
77
if (is_fd && mcast != NULL) {
78
- if (convert_host_port(&saddr, mcast->u.inet.host,
79
- mcast->u.inet.port, errp) < 0) {
80
+ saddr = g_new(struct sockaddr_in, 1);
81
+
82
+ if (convert_host_port(saddr, mcast->u.inet.host, mcast->u.inet.port,
83
+ errp) < 0) {
84
goto err;
85
}
86
/* must be bound */
87
- if (saddr.sin_addr.s_addr == 0) {
88
+ if (saddr->sin_addr.s_addr == 0) {
89
error_setg(errp, "can't setup multicast destination address");
90
goto err;
91
}
92
/* clone dgram socket */
93
- newfd = net_dgram_mcast_create(&saddr, NULL, errp);
94
+ newfd = net_dgram_mcast_create(saddr, NULL, errp);
95
if (newfd < 0) {
96
goto err;
97
}
98
/* clone newfd to fd, close newfd */
99
dup2(newfd, fd);
100
close(newfd);
101
-
102
}
103
104
nc = qemu_new_net_client(&net_dgram_socket_info, peer, model, name);
105
@@ -XXX,XX +XXX,XX @@ static NetDgramState *net_dgram_fd_init(NetClientState *peer,
106
net_dgram_read_poll(s, true);
107
108
/* mcast: save bound address as dst */
109
- if (is_fd && mcast != NULL) {
110
- s->dgram_dst = saddr;
111
+ if (saddr) {
112
+ g_assert(s->dest_addr == NULL);
113
+ s->dest_addr = (struct sockaddr *)saddr;
114
+ s->dest_len = sizeof(*saddr);
115
qemu_set_info_str(nc, "fd=%d (cloned mcast=%s:%d)", fd,
116
- inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
117
+ inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port));
118
} else {
119
- if (sa_type == SOCKET_ADDRESS_TYPE_UNIX) {
120
- s->dgram_dst.sin_family = AF_UNIX;
121
- }
122
-
123
qemu_set_info_str(nc, "fd=%d %s", fd, SocketAddressType_str(sa_type));
124
}
125
126
return s;
127
128
err:
129
+ g_free(saddr);
130
closesocket(fd);
131
return NULL;
132
}
133
@@ -XXX,XX +XXX,XX @@ static int net_dgram_mcast_init(NetClientState *peer,
134
{
135
NetDgramState *s;
136
int fd, ret;
137
- struct sockaddr_in saddr;
138
+ struct sockaddr_in *saddr;
139
140
if (remote->type != SOCKET_ADDRESS_TYPE_INET) {
141
error_setg(errp, "multicast only support inet type");
142
return -1;
143
}
144
145
- if (convert_host_port(&saddr, remote->u.inet.host, remote->u.inet.port,
146
+ saddr = g_new(struct sockaddr_in, 1);
147
+ if (convert_host_port(saddr, remote->u.inet.host, remote->u.inet.port,
148
errp) < 0) {
149
+ g_free(saddr);
150
return -1;
151
}
152
153
if (!local) {
154
- fd = net_dgram_mcast_create(&saddr, NULL, errp);
155
+ fd = net_dgram_mcast_create(saddr, NULL, errp);
156
if (fd < 0) {
157
+ g_free(saddr);
158
return -1;
159
}
160
} else {
161
@@ -XXX,XX +XXX,XX @@ static int net_dgram_mcast_init(NetClientState *peer,
162
struct in_addr localaddr;
163
164
if (inet_aton(local->u.inet.host, &localaddr) == 0) {
165
+ g_free(saddr);
166
error_setg(errp, "localaddr '%s' is not a valid IPv4 address",
167
local->u.inet.host);
168
return -1;
169
}
170
171
- fd = net_dgram_mcast_create(&saddr, &localaddr, errp);
172
+ fd = net_dgram_mcast_create(saddr, &localaddr, errp);
173
if (fd < 0) {
174
+ g_free(saddr);
175
return -1;
176
}
177
break;
178
@@ -XXX,XX +XXX,XX @@ static int net_dgram_mcast_init(NetClientState *peer,
179
case SOCKET_ADDRESS_TYPE_FD:
180
fd = monitor_fd_param(monitor_cur(), local->u.fd.str, errp);
181
if (fd == -1) {
182
+ g_free(saddr);
183
return -1;
184
}
185
ret = qemu_socket_try_set_nonblock(fd);
186
if (ret < 0) {
187
+ g_free(saddr);
188
error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
189
name, fd);
190
return -1;
191
}
192
break;
193
default:
194
+ g_free(saddr);
195
error_setg(errp, "only support inet or fd type for local");
196
return -1;
197
}
198
@@ -XXX,XX +XXX,XX @@ static int net_dgram_mcast_init(NetClientState *peer,
199
local->type == SOCKET_ADDRESS_TYPE_FD,
200
remote, errp);
201
if (!s) {
202
+ g_free(saddr);
203
return -1;
204
}
205
206
- s->dgram_dst = saddr;
207
+ g_assert(s->dest_addr == NULL);
208
+ s->dest_addr = (struct sockaddr *)saddr;
209
+ s->dest_len = sizeof(*saddr);
210
+
211
+ qemu_set_info_str(&s->nc, "mcast=%s:%d", inet_ntoa(saddr->sin_addr),
212
+ ntohs(saddr->sin_port));
213
214
- qemu_set_info_str(&s->nc, "mcast=%s:%d", inet_ntoa(saddr.sin_addr),
215
- ntohs(saddr.sin_port));
216
return 0;
217
218
}
219
@@ -XXX,XX +XXX,XX @@ int net_init_dgram(const Netdev *netdev, const char *name,
220
{
221
NetDgramState *s;
222
int fd, ret;
223
- struct sockaddr_in raddr_in;
224
- struct sockaddr_in laddr_in;
225
SocketAddress *remote, *local;
226
+ struct sockaddr *dest_addr;
227
+ struct sockaddr_in laddr_in, raddr_in;
228
+ socklen_t dest_len;
229
230
assert(netdev->type == NET_CLIENT_DRIVER_DGRAM);
231
232
@@ -XXX,XX +XXX,XX @@ int net_init_dgram(const Netdev *netdev, const char *name,
233
return -1;
234
}
235
qemu_socket_set_nonblock(fd);
236
+
237
+ dest_len = sizeof(raddr_in);
238
+ dest_addr = g_malloc(dest_len);
239
+ memcpy(dest_addr, &raddr_in, dest_len);
240
break;
241
case SOCKET_ADDRESS_TYPE_FD:
242
fd = monitor_fd_param(monitor_cur(), local->u.fd.str, errp);
243
@@ -XXX,XX +XXX,XX @@ int net_init_dgram(const Netdev *netdev, const char *name,
244
name, fd);
245
return -1;
246
}
247
+ dest_addr = NULL;
248
+ dest_len = 0;
249
break;
250
default:
251
error_setg(errp, "only support inet or fd type for local");
252
@@ -XXX,XX +XXX,XX @@ int net_init_dgram(const Netdev *netdev, const char *name,
253
}
254
255
if (remote) {
256
- s->dgram_dst = raddr_in;
257
+ g_assert(s->dest_addr == NULL);
258
+ s->dest_addr = dest_addr;
259
+ s->dest_len = dest_len;
260
}
261
262
switch (local->type) {
263
--
264
2.7.4
265
266
diff view generated by jsdifflib
New patch
1
From: Laurent Vivier <lvivier@redhat.com>
1
2
3
It is less complex to manage special cases directly in
4
net_dgram_mcast_init() and net_dgram_udp_init().
5
6
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
7
Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
8
Acked-by: Michael S. Tsirkin <mst@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
---
11
net/dgram.c | 143 ++++++++++++++++++++++++++++++++----------------------------
12
1 file changed, 76 insertions(+), 67 deletions(-)
13
14
diff --git a/net/dgram.c b/net/dgram.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/net/dgram.c
17
+++ b/net/dgram.c
18
@@ -XXX,XX +XXX,XX @@ static NetClientInfo net_dgram_socket_info = {
19
static NetDgramState *net_dgram_fd_init(NetClientState *peer,
20
const char *model,
21
const char *name,
22
- int fd, int is_fd,
23
- SocketAddress *mcast,
24
+ int fd,
25
Error **errp)
26
{
27
- struct sockaddr_in *saddr = NULL;
28
- int newfd;
29
NetClientState *nc;
30
NetDgramState *s;
31
- SocketAddress *sa;
32
- SocketAddressType sa_type;
33
-
34
- sa = socket_local_address(fd, errp);
35
- if (!sa) {
36
- return NULL;
37
- }
38
- sa_type = sa->type;
39
- qapi_free_SocketAddress(sa);
40
-
41
- /*
42
- * fd passed: multicast: "learn" dest_addr address from bound address and
43
- * save it. Because this may be "shared" socket from a "master" process,
44
- * datagrams would be recv() by ONLY ONE process: we must "clone" this
45
- * dgram socket --jjo
46
- */
47
-
48
- if (is_fd && mcast != NULL) {
49
- saddr = g_new(struct sockaddr_in, 1);
50
-
51
- if (convert_host_port(saddr, mcast->u.inet.host, mcast->u.inet.port,
52
- errp) < 0) {
53
- goto err;
54
- }
55
- /* must be bound */
56
- if (saddr->sin_addr.s_addr == 0) {
57
- error_setg(errp, "can't setup multicast destination address");
58
- goto err;
59
- }
60
- /* clone dgram socket */
61
- newfd = net_dgram_mcast_create(saddr, NULL, errp);
62
- if (newfd < 0) {
63
- goto err;
64
- }
65
- /* clone newfd to fd, close newfd */
66
- dup2(newfd, fd);
67
- close(newfd);
68
- }
69
70
nc = qemu_new_net_client(&net_dgram_socket_info, peer, model, name);
71
72
@@ -XXX,XX +XXX,XX @@ static NetDgramState *net_dgram_fd_init(NetClientState *peer,
73
net_socket_rs_init(&s->rs, net_dgram_rs_finalize, false);
74
net_dgram_read_poll(s, true);
75
76
- /* mcast: save bound address as dst */
77
- if (saddr) {
78
- g_assert(s->dest_addr == NULL);
79
- s->dest_addr = (struct sockaddr *)saddr;
80
- s->dest_len = sizeof(*saddr);
81
- qemu_set_info_str(nc, "fd=%d (cloned mcast=%s:%d)", fd,
82
- inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port));
83
- } else {
84
- qemu_set_info_str(nc, "fd=%d %s", fd, SocketAddressType_str(sa_type));
85
- }
86
-
87
return s;
88
-
89
-err:
90
- g_free(saddr);
91
- closesocket(fd);
92
- return NULL;
93
}
94
95
static int net_dgram_mcast_init(NetClientState *peer,
96
@@ -XXX,XX +XXX,XX @@ static int net_dgram_mcast_init(NetClientState *peer,
97
}
98
break;
99
}
100
- case SOCKET_ADDRESS_TYPE_FD:
101
+ case SOCKET_ADDRESS_TYPE_FD: {
102
+ int newfd;
103
+
104
fd = monitor_fd_param(monitor_cur(), local->u.fd.str, errp);
105
if (fd == -1) {
106
g_free(saddr);
107
@@ -XXX,XX +XXX,XX @@ static int net_dgram_mcast_init(NetClientState *peer,
108
name, fd);
109
return -1;
110
}
111
+
112
+ /*
113
+ * fd passed: multicast: "learn" dest_addr address from bound
114
+ * address and save it. Because this may be "shared" socket from a
115
+ * "master" process, datagrams would be recv() by ONLY ONE process:
116
+ * we must "clone" this dgram socket --jjo
117
+ */
118
+
119
+ saddr = g_new(struct sockaddr_in, 1);
120
+
121
+ if (convert_host_port(saddr, local->u.inet.host, local->u.inet.port,
122
+ errp) < 0) {
123
+ g_free(saddr);
124
+ closesocket(fd);
125
+ return -1;
126
+ }
127
+
128
+ /* must be bound */
129
+ if (saddr->sin_addr.s_addr == 0) {
130
+ error_setg(errp, "can't setup multicast destination address");
131
+ g_free(saddr);
132
+ closesocket(fd);
133
+ return -1;
134
+ }
135
+ /* clone dgram socket */
136
+ newfd = net_dgram_mcast_create(saddr, NULL, errp);
137
+ if (newfd < 0) {
138
+ g_free(saddr);
139
+ closesocket(fd);
140
+ return -1;
141
+ }
142
+ /* clone newfd to fd, close newfd */
143
+ dup2(newfd, fd);
144
+ close(newfd);
145
break;
146
+ }
147
default:
148
g_free(saddr);
149
error_setg(errp, "only support inet or fd type for local");
150
@@ -XXX,XX +XXX,XX @@ static int net_dgram_mcast_init(NetClientState *peer,
151
}
152
}
153
154
- s = net_dgram_fd_init(peer, model, name, fd,
155
- local->type == SOCKET_ADDRESS_TYPE_FD,
156
- remote, errp);
157
+ s = net_dgram_fd_init(peer, model, name, fd, errp);
158
if (!s) {
159
g_free(saddr);
160
return -1;
161
@@ -XXX,XX +XXX,XX @@ static int net_dgram_mcast_init(NetClientState *peer,
162
s->dest_addr = (struct sockaddr *)saddr;
163
s->dest_len = sizeof(*saddr);
164
165
- qemu_set_info_str(&s->nc, "mcast=%s:%d", inet_ntoa(saddr->sin_addr),
166
- ntohs(saddr->sin_port));
167
+ if (!local) {
168
+ qemu_set_info_str(&s->nc, "mcast=%s:%d",
169
+ inet_ntoa(saddr->sin_addr),
170
+ ntohs(saddr->sin_port));
171
+ } else {
172
+ switch (local->type) {
173
+ case SOCKET_ADDRESS_TYPE_INET:
174
+ qemu_set_info_str(&s->nc, "mcast=%s:%d",
175
+ inet_ntoa(saddr->sin_addr),
176
+ ntohs(saddr->sin_port));
177
+ break;
178
+ case SOCKET_ADDRESS_TYPE_FD:
179
+ qemu_set_info_str(&s->nc, "fd=%d (cloned mcast=%s:%d)",
180
+ fd, inet_ntoa(saddr->sin_addr),
181
+ ntohs(saddr->sin_port));
182
+ break;
183
+ default:
184
+ g_assert_not_reached();
185
+ }
186
+ }
187
188
return 0;
189
190
@@ -XXX,XX +XXX,XX @@ int net_init_dgram(const Netdev *netdev, const char *name,
191
return -1;
192
}
193
194
- s = net_dgram_fd_init(peer, "dgram", name, fd, 0, NULL, errp);
195
+ s = net_dgram_fd_init(peer, "dgram", name, fd, errp);
196
if (!s) {
197
return -1;
198
}
199
@@ -XXX,XX +XXX,XX @@ int net_init_dgram(const Netdev *netdev, const char *name,
200
inet_ntoa(raddr_in.sin_addr),
201
ntohs(raddr_in.sin_port));
202
break;
203
- case SOCKET_ADDRESS_TYPE_FD:
204
- qemu_set_info_str(&s->nc, "fd=%d", fd);
205
+ case SOCKET_ADDRESS_TYPE_FD: {
206
+ SocketAddress *sa;
207
+ SocketAddressType sa_type;
208
+
209
+ sa = socket_local_address(fd, errp);
210
+ if (sa) {
211
+ sa_type = sa->type;
212
+ qapi_free_SocketAddress(sa);
213
+
214
+ qemu_set_info_str(&s->nc, "fd=%d %s", fd,
215
+ SocketAddressType_str(sa_type));
216
+ } else {
217
+ qemu_set_info_str(&s->nc, "fd=%d", fd);
218
+ }
219
break;
220
+ }
221
default:
222
g_assert_not_reached();
223
}
224
--
225
2.7.4
diff view generated by jsdifflib
New patch
1
From: Laurent Vivier <lvivier@redhat.com>
1
2
3
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
4
Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
5
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
6
Acked-by: Michael S. Tsirkin <mst@redhat.com>
7
Acked-by: Markus Armbruster <armbru@redhat.com> (QAPI schema)
8
Signed-off-by: Jason Wang <jasowang@redhat.com>
9
---
10
net/dgram.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
11
qapi/net.json | 2 +-
12
qemu-options.hx | 1 +
13
3 files changed, 56 insertions(+), 2 deletions(-)
14
15
diff --git a/net/dgram.c b/net/dgram.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/net/dgram.c
18
+++ b/net/dgram.c
19
@@ -XXX,XX +XXX,XX @@ int net_init_dgram(const Netdev *netdev, const char *name,
20
SocketAddress *remote, *local;
21
struct sockaddr *dest_addr;
22
struct sockaddr_in laddr_in, raddr_in;
23
+ struct sockaddr_un laddr_un, raddr_un;
24
socklen_t dest_len;
25
26
assert(netdev->type == NET_CLIENT_DRIVER_DGRAM);
27
@@ -XXX,XX +XXX,XX @@ int net_init_dgram(const Netdev *netdev, const char *name,
28
}
29
} else {
30
if (local->type != SOCKET_ADDRESS_TYPE_FD) {
31
- error_setg(errp, "type=inet requires remote parameter");
32
+ error_setg(errp,
33
+ "type=inet or type=unix requires remote parameter");
34
return -1;
35
}
36
}
37
@@ -XXX,XX +XXX,XX @@ int net_init_dgram(const Netdev *netdev, const char *name,
38
dest_addr = g_malloc(dest_len);
39
memcpy(dest_addr, &raddr_in, dest_len);
40
break;
41
+ case SOCKET_ADDRESS_TYPE_UNIX:
42
+ ret = unlink(local->u.q_unix.path);
43
+ if (ret < 0 && errno != ENOENT) {
44
+ error_setg_errno(errp, errno, "failed to unlink socket %s",
45
+ local->u.q_unix.path);
46
+ return -1;
47
+ }
48
+
49
+ laddr_un.sun_family = PF_UNIX;
50
+ ret = snprintf(laddr_un.sun_path, sizeof(laddr_un.sun_path), "%s",
51
+ local->u.q_unix.path);
52
+ if (ret < 0 || ret >= sizeof(laddr_un.sun_path)) {
53
+ error_setg(errp, "UNIX socket path '%s' is too long",
54
+ local->u.q_unix.path);
55
+ error_append_hint(errp, "Path must be less than %zu bytes\n",
56
+ sizeof(laddr_un.sun_path));
57
+ }
58
+
59
+ raddr_un.sun_family = PF_UNIX;
60
+ ret = snprintf(raddr_un.sun_path, sizeof(raddr_un.sun_path), "%s",
61
+ remote->u.q_unix.path);
62
+ if (ret < 0 || ret >= sizeof(raddr_un.sun_path)) {
63
+ error_setg(errp, "UNIX socket path '%s' is too long",
64
+ remote->u.q_unix.path);
65
+ error_append_hint(errp, "Path must be less than %zu bytes\n",
66
+ sizeof(raddr_un.sun_path));
67
+ }
68
+
69
+ fd = qemu_socket(PF_UNIX, SOCK_DGRAM, 0);
70
+ if (fd < 0) {
71
+ error_setg_errno(errp, errno, "can't create datagram socket");
72
+ return -1;
73
+ }
74
+
75
+ ret = bind(fd, (struct sockaddr *)&laddr_un, sizeof(laddr_un));
76
+ if (ret < 0) {
77
+ error_setg_errno(errp, errno, "can't bind unix=%s to socket",
78
+ laddr_un.sun_path);
79
+ closesocket(fd);
80
+ return -1;
81
+ }
82
+ qemu_socket_set_nonblock(fd);
83
+
84
+ dest_len = sizeof(raddr_un);
85
+ dest_addr = g_malloc(dest_len);
86
+ memcpy(dest_addr, &raddr_un, dest_len);
87
+ break;
88
case SOCKET_ADDRESS_TYPE_FD:
89
fd = monitor_fd_param(monitor_cur(), local->u.fd.str, errp);
90
if (fd == -1) {
91
@@ -XXX,XX +XXX,XX @@ int net_init_dgram(const Netdev *netdev, const char *name,
92
inet_ntoa(raddr_in.sin_addr),
93
ntohs(raddr_in.sin_port));
94
break;
95
+ case SOCKET_ADDRESS_TYPE_UNIX:
96
+ qemu_set_info_str(&s->nc, "udp=%s:%s",
97
+ laddr_un.sun_path, raddr_un.sun_path);
98
+ break;
99
case SOCKET_ADDRESS_TYPE_FD: {
100
SocketAddress *sa;
101
SocketAddressType sa_type;
102
diff --git a/qapi/net.json b/qapi/net.json
103
index XXXXXXX..XXXXXXX 100644
104
--- a/qapi/net.json
105
+++ b/qapi/net.json
106
@@ -XXX,XX +XXX,XX @@
107
# @remote: remote address
108
# @local: local address
109
#
110
-# Only SocketAddress types 'inet' and 'fd' are supported.
111
+# Only SocketAddress types 'unix', 'inet' and 'fd' are supported.
112
#
113
# If remote address is present and it's a multicast address, local address
114
# is optional. Otherwise local address is required and remote address is
115
diff --git a/qemu-options.hx b/qemu-options.hx
116
index XXXXXXX..XXXXXXX 100644
117
--- a/qemu-options.hx
118
+++ b/qemu-options.hx
119
@@ -XXX,XX +XXX,XX @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
120
" configure a network backend to connect to a multicast maddr and port\n"
121
" use ``local.host=addr`` to specify the host address to send packets from\n"
122
"-netdev dgram,id=str,local.type=inet,local.host=addr,local.port=port[,remote.type=inet,remote.host=addr,remote.port=port]\n"
123
+ "-netdev dgram,id=str,local.type=unix,local.path=path[,remote.type=unix,remote.path=path]\n"
124
"-netdev dgram,id=str,local.type=fd,local.str=file-descriptor\n"
125
" configure a network backend to connect to another network\n"
126
" using an UDP tunnel\n"
127
--
128
2.7.4
diff view generated by jsdifflib
New patch
1
From: Laurent Vivier <lvivier@redhat.com>
1
2
3
Rename SocketAddress_to_str() to socket_uri() and move it to
4
util/qemu-sockets.c close to socket_parse().
5
6
socket_uri() generates a string from a SocketAddress while
7
socket_parse() generates a SocketAddress from a string.
8
9
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
10
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
11
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
12
Acked-by: Michael S. Tsirkin <mst@redhat.com>
13
Signed-off-by: Jason Wang <jasowang@redhat.com>
14
---
15
include/qemu/sockets.h | 2 +-
16
monitor/hmp-cmds.c | 23 +----------------------
17
util/qemu-sockets.c | 20 ++++++++++++++++++++
18
3 files changed, 22 insertions(+), 23 deletions(-)
19
20
diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
21
index XXXXXXX..XXXXXXX 100644
22
--- a/include/qemu/sockets.h
23
+++ b/include/qemu/sockets.h
24
@@ -XXX,XX +XXX,XX @@ NetworkAddressFamily inet_netfamily(int family);
25
int unix_listen(const char *path, Error **errp);
26
int unix_connect(const char *path, Error **errp);
27
28
+char *socket_uri(SocketAddress *addr);
29
SocketAddress *socket_parse(const char *str, Error **errp);
30
int socket_connect(SocketAddress *addr, Error **errp);
31
int socket_listen(SocketAddress *addr, int num, Error **errp);
32
@@ -XXX,XX +XXX,XX @@ SocketAddress *socket_address_flatten(SocketAddressLegacy *addr);
33
* Return 0 on success.
34
*/
35
int socket_address_parse_named_fd(SocketAddress *addr, Error **errp);
36
-
37
#endif /* QEMU_SOCKETS_H */
38
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
39
index XXXXXXX..XXXXXXX 100644
40
--- a/monitor/hmp-cmds.c
41
+++ b/monitor/hmp-cmds.c
42
@@ -XXX,XX +XXX,XX @@ void hmp_info_mice(Monitor *mon, const QDict *qdict)
43
qapi_free_MouseInfoList(mice_list);
44
}
45
46
-static char *SocketAddress_to_str(SocketAddress *addr)
47
-{
48
- switch (addr->type) {
49
- case SOCKET_ADDRESS_TYPE_INET:
50
- return g_strdup_printf("tcp:%s:%s",
51
- addr->u.inet.host,
52
- addr->u.inet.port);
53
- case SOCKET_ADDRESS_TYPE_UNIX:
54
- return g_strdup_printf("unix:%s",
55
- addr->u.q_unix.path);
56
- case SOCKET_ADDRESS_TYPE_FD:
57
- return g_strdup_printf("fd:%s", addr->u.fd.str);
58
- case SOCKET_ADDRESS_TYPE_VSOCK:
59
- return g_strdup_printf("tcp:%s:%s",
60
- addr->u.vsock.cid,
61
- addr->u.vsock.port);
62
- default:
63
- return g_strdup("unknown address type");
64
- }
65
-}
66
-
67
void hmp_info_migrate(Monitor *mon, const QDict *qdict)
68
{
69
MigrationInfo *info;
70
@@ -XXX,XX +XXX,XX @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
71
monitor_printf(mon, "socket address: [\n");
72
73
for (addr = info->socket_address; addr; addr = addr->next) {
74
- char *s = SocketAddress_to_str(addr->value);
75
+ char *s = socket_uri(addr->value);
76
monitor_printf(mon, "\t%s\n", s);
77
g_free(s);
78
}
79
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
80
index XXXXXXX..XXXXXXX 100644
81
--- a/util/qemu-sockets.c
82
+++ b/util/qemu-sockets.c
83
@@ -XXX,XX +XXX,XX @@ int unix_connect(const char *path, Error **errp)
84
return sock;
85
}
86
87
+char *socket_uri(SocketAddress *addr)
88
+{
89
+ switch (addr->type) {
90
+ case SOCKET_ADDRESS_TYPE_INET:
91
+ return g_strdup_printf("tcp:%s:%s",
92
+ addr->u.inet.host,
93
+ addr->u.inet.port);
94
+ case SOCKET_ADDRESS_TYPE_UNIX:
95
+ return g_strdup_printf("unix:%s",
96
+ addr->u.q_unix.path);
97
+ case SOCKET_ADDRESS_TYPE_FD:
98
+ return g_strdup_printf("fd:%s", addr->u.fd.str);
99
+ case SOCKET_ADDRESS_TYPE_VSOCK:
100
+ return g_strdup_printf("tcp:%s:%s",
101
+ addr->u.vsock.cid,
102
+ addr->u.vsock.port);
103
+ default:
104
+ return g_strdup("unknown address type");
105
+ }
106
+}
107
108
SocketAddress *socket_parse(const char *str, Error **errp)
109
{
110
--
111
2.7.4
diff view generated by jsdifflib
New patch
1
From: Laurent Vivier <lvivier@redhat.com>
1
2
3
To be consistent with socket_uri(), add 'tcp:' prefix for inet type in
4
socket_parse(), by default socket_parse() use tcp when no prefix is
5
provided (format is host:port).
6
7
In socket_uri(), use 'vsock:' prefix for vsock type rather than 'tcp:'
8
because it makes a vsock address look like an inet address with CID
9
misinterpreted as host.
10
Goes back to commit 9aca82ba31 "migration: Create socket-address parameter"
11
12
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
13
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
14
Reviewed-by: Markus Armbruster <armbru@redhat.com>
15
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
16
Acked-by: Michael S. Tsirkin <mst@redhat.com>
17
Signed-off-by: Jason Wang <jasowang@redhat.com>
18
---
19
util/qemu-sockets.c | 7 ++++++-
20
1 file changed, 6 insertions(+), 1 deletion(-)
21
22
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
23
index XXXXXXX..XXXXXXX 100644
24
--- a/util/qemu-sockets.c
25
+++ b/util/qemu-sockets.c
26
@@ -XXX,XX +XXX,XX @@ char *socket_uri(SocketAddress *addr)
27
case SOCKET_ADDRESS_TYPE_FD:
28
return g_strdup_printf("fd:%s", addr->u.fd.str);
29
case SOCKET_ADDRESS_TYPE_VSOCK:
30
- return g_strdup_printf("tcp:%s:%s",
31
+ return g_strdup_printf("vsock:%s:%s",
32
addr->u.vsock.cid,
33
addr->u.vsock.port);
34
default:
35
@@ -XXX,XX +XXX,XX @@ SocketAddress *socket_parse(const char *str, Error **errp)
36
if (vsock_parse(&addr->u.vsock, str + strlen("vsock:"), errp)) {
37
goto fail;
38
}
39
+ } else if (strstart(str, "tcp:", NULL)) {
40
+ addr->type = SOCKET_ADDRESS_TYPE_INET;
41
+ if (inet_parse(&addr->u.inet, str + strlen("tcp:"), errp)) {
42
+ goto fail;
43
+ }
44
} else {
45
addr->type = SOCKET_ADDRESS_TYPE_INET;
46
if (inet_parse(&addr->u.inet, str, errp)) {
47
--
48
2.7.4
diff view generated by jsdifflib
New patch
1
From: Laurent Vivier <lvivier@redhat.com>
1
2
3
Use QIOChannel, QIOChannelSocket and QIONetListener.
4
This allows net/stream to use all the available parameters provided by
5
SocketAddress.
6
7
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
8
Acked-by: Michael S. Tsirkin <mst@redhat.com>
9
Signed-off-by: Jason Wang <jasowang@redhat.com>
10
---
11
net/stream.c | 492 ++++++++++++++++++++------------------------------------
12
qemu-options.hx | 4 +-
13
2 files changed, 178 insertions(+), 318 deletions(-)
14
15
diff --git a/net/stream.c b/net/stream.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/net/stream.c
18
+++ b/net/stream.c
19
@@ -XXX,XX +XXX,XX @@
20
#include "qemu/iov.h"
21
#include "qemu/main-loop.h"
22
#include "qemu/cutils.h"
23
+#include "io/channel.h"
24
+#include "io/channel-socket.h"
25
+#include "io/net-listener.h"
26
27
typedef struct NetStreamState {
28
NetClientState nc;
29
- int listen_fd;
30
- int fd;
31
+ QIOChannel *listen_ioc;
32
+ QIONetListener *listener;
33
+ QIOChannel *ioc;
34
+ guint ioc_read_tag;
35
+ guint ioc_write_tag;
36
SocketReadState rs;
37
unsigned int send_index; /* number of bytes sent*/
38
- bool read_poll; /* waiting to receive data? */
39
- bool write_poll; /* waiting to transmit data? */
40
} NetStreamState;
41
42
-static void net_stream_send(void *opaque);
43
-static void net_stream_accept(void *opaque);
44
-static void net_stream_writable(void *opaque);
45
+static void net_stream_listen(QIONetListener *listener,
46
+ QIOChannelSocket *cioc,
47
+ void *opaque);
48
49
-static void net_stream_update_fd_handler(NetStreamState *s)
50
+static gboolean net_stream_writable(QIOChannel *ioc,
51
+ GIOCondition condition,
52
+ gpointer data)
53
{
54
- qemu_set_fd_handler(s->fd,
55
- s->read_poll ? net_stream_send : NULL,
56
- s->write_poll ? net_stream_writable : NULL,
57
- s);
58
-}
59
-
60
-static void net_stream_read_poll(NetStreamState *s, bool enable)
61
-{
62
- s->read_poll = enable;
63
- net_stream_update_fd_handler(s);
64
-}
65
-
66
-static void net_stream_write_poll(NetStreamState *s, bool enable)
67
-{
68
- s->write_poll = enable;
69
- net_stream_update_fd_handler(s);
70
-}
71
-
72
-static void net_stream_writable(void *opaque)
73
-{
74
- NetStreamState *s = opaque;
75
+ NetStreamState *s = data;
76
77
- net_stream_write_poll(s, false);
78
+ s->ioc_write_tag = 0;
79
80
qemu_flush_queued_packets(&s->nc);
81
+
82
+ return G_SOURCE_REMOVE;
83
}
84
85
static ssize_t net_stream_receive(NetClientState *nc, const uint8_t *buf,
86
@@ -XXX,XX +XXX,XX @@ static ssize_t net_stream_receive(NetClientState *nc, const uint8_t *buf,
87
.iov_len = size,
88
},
89
};
90
+ struct iovec local_iov[2];
91
+ unsigned int nlocal_iov;
92
size_t remaining;
93
ssize_t ret;
94
95
remaining = iov_size(iov, 2) - s->send_index;
96
- ret = iov_send(s->fd, iov, 2, s->send_index, remaining);
97
-
98
- if (ret == -1 && errno == EAGAIN) {
99
+ nlocal_iov = iov_copy(local_iov, 2, iov, 2, s->send_index, remaining);
100
+ ret = qio_channel_writev(s->ioc, local_iov, nlocal_iov, NULL);
101
+ if (ret == QIO_CHANNEL_ERR_BLOCK) {
102
ret = 0; /* handled further down */
103
}
104
if (ret == -1) {
105
@@ -XXX,XX +XXX,XX @@ static ssize_t net_stream_receive(NetClientState *nc, const uint8_t *buf,
106
}
107
if (ret < (ssize_t)remaining) {
108
s->send_index += ret;
109
- net_stream_write_poll(s, true);
110
+ s->ioc_write_tag = qio_channel_add_watch(s->ioc, G_IO_OUT,
111
+ net_stream_writable, s, NULL);
112
return 0;
113
}
114
s->send_index = 0;
115
return size;
116
}
117
118
+static gboolean net_stream_send(QIOChannel *ioc,
119
+ GIOCondition condition,
120
+ gpointer data);
121
+
122
static void net_stream_send_completed(NetClientState *nc, ssize_t len)
123
{
124
NetStreamState *s = DO_UPCAST(NetStreamState, nc, nc);
125
126
- if (!s->read_poll) {
127
- net_stream_read_poll(s, true);
128
+ if (!s->ioc_read_tag) {
129
+ s->ioc_read_tag = qio_channel_add_watch(s->ioc, G_IO_IN,
130
+ net_stream_send, s, NULL);
131
}
132
}
133
134
@@ -XXX,XX +XXX,XX @@ static void net_stream_rs_finalize(SocketReadState *rs)
135
if (qemu_send_packet_async(&s->nc, rs->buf,
136
rs->packet_len,
137
net_stream_send_completed) == 0) {
138
- net_stream_read_poll(s, false);
139
+ if (s->ioc_read_tag) {
140
+ g_source_remove(s->ioc_read_tag);
141
+ s->ioc_read_tag = 0;
142
+ }
143
}
144
}
145
146
-static void net_stream_send(void *opaque)
147
+static gboolean net_stream_send(QIOChannel *ioc,
148
+ GIOCondition condition,
149
+ gpointer data)
150
{
151
- NetStreamState *s = opaque;
152
+ NetStreamState *s = data;
153
int size;
154
int ret;
155
- uint8_t buf1[NET_BUFSIZE];
156
- const uint8_t *buf;
157
+ char buf1[NET_BUFSIZE];
158
+ const char *buf;
159
160
- size = recv(s->fd, buf1, sizeof(buf1), 0);
161
+ size = qio_channel_read(s->ioc, buf1, sizeof(buf1), NULL);
162
if (size < 0) {
163
if (errno != EWOULDBLOCK) {
164
goto eoc;
165
@@ -XXX,XX +XXX,XX @@ static void net_stream_send(void *opaque)
166
} else if (size == 0) {
167
/* end of connection */
168
eoc:
169
- net_stream_read_poll(s, false);
170
- net_stream_write_poll(s, false);
171
- if (s->listen_fd != -1) {
172
- qemu_set_fd_handler(s->listen_fd, net_stream_accept, NULL, s);
173
+ s->ioc_read_tag = 0;
174
+ if (s->ioc_write_tag) {
175
+ g_source_remove(s->ioc_write_tag);
176
+ s->ioc_write_tag = 0;
177
}
178
- closesocket(s->fd);
179
+ if (s->listener) {
180
+ qio_net_listener_set_client_func(s->listener, net_stream_listen,
181
+ s, NULL);
182
+ }
183
+ object_unref(OBJECT(s->ioc));
184
+ s->ioc = NULL;
185
186
- s->fd = -1;
187
net_socket_rs_init(&s->rs, net_stream_rs_finalize, false);
188
s->nc.link_down = true;
189
qemu_set_info_str(&s->nc, "");
190
191
- return;
192
+ return G_SOURCE_REMOVE;
193
}
194
buf = buf1;
195
196
- ret = net_fill_rstate(&s->rs, buf, size);
197
+ ret = net_fill_rstate(&s->rs, (const uint8_t *)buf, size);
198
199
if (ret == -1) {
200
goto eoc;
201
}
202
+
203
+ return G_SOURCE_CONTINUE;
204
}
205
206
static void net_stream_cleanup(NetClientState *nc)
207
{
208
NetStreamState *s = DO_UPCAST(NetStreamState, nc, nc);
209
- if (s->fd != -1) {
210
- net_stream_read_poll(s, false);
211
- net_stream_write_poll(s, false);
212
- close(s->fd);
213
- s->fd = -1;
214
+ if (s->ioc) {
215
+ if (QIO_CHANNEL_SOCKET(s->ioc)->fd != -1) {
216
+ if (s->ioc_read_tag) {
217
+ g_source_remove(s->ioc_read_tag);
218
+ s->ioc_read_tag = 0;
219
+ }
220
+ if (s->ioc_write_tag) {
221
+ g_source_remove(s->ioc_write_tag);
222
+ s->ioc_write_tag = 0;
223
+ }
224
+ }
225
+ object_unref(OBJECT(s->ioc));
226
+ s->ioc = NULL;
227
}
228
- if (s->listen_fd != -1) {
229
- qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
230
- closesocket(s->listen_fd);
231
- s->listen_fd = -1;
232
+ if (s->listen_ioc) {
233
+ if (s->listener) {
234
+ qio_net_listener_disconnect(s->listener);
235
+ object_unref(OBJECT(s->listener));
236
+ s->listener = NULL;
237
+ }
238
+ object_unref(OBJECT(s->listen_ioc));
239
+ s->listen_ioc = NULL;
240
}
241
}
242
243
-static void net_stream_connect(void *opaque)
244
-{
245
- NetStreamState *s = opaque;
246
- net_stream_read_poll(s, true);
247
-}
248
-
249
static NetClientInfo net_stream_info = {
250
.type = NET_CLIENT_DRIVER_STREAM,
251
.size = sizeof(NetStreamState),
252
@@ -XXX,XX +XXX,XX @@ static NetClientInfo net_stream_info = {
253
.cleanup = net_stream_cleanup,
254
};
255
256
-static NetStreamState *net_stream_fd_init(NetClientState *peer,
257
- const char *model,
258
- const char *name,
259
- int fd, int is_connected)
260
+static void net_stream_listen(QIONetListener *listener,
261
+ QIOChannelSocket *cioc,
262
+ void *opaque)
263
{
264
- NetClientState *nc;
265
- NetStreamState *s;
266
-
267
- nc = qemu_new_net_client(&net_stream_info, peer, model, name);
268
+ NetStreamState *s = opaque;
269
+ SocketAddress *addr;
270
+ char *uri;
271
272
- qemu_set_info_str(nc, "fd=%d", fd);
273
+ object_ref(OBJECT(cioc));
274
275
- s = DO_UPCAST(NetStreamState, nc, nc);
276
+ qio_net_listener_set_client_func(s->listener, NULL, s, NULL);
277
278
- s->fd = fd;
279
- s->listen_fd = -1;
280
- net_socket_rs_init(&s->rs, net_stream_rs_finalize, false);
281
+ s->ioc = QIO_CHANNEL(cioc);
282
+ qio_channel_set_name(s->ioc, "stream-server");
283
+ s->nc.link_down = false;
284
285
- /* Disable Nagle algorithm on TCP sockets to reduce latency */
286
- socket_set_nodelay(fd);
287
+ s->ioc_read_tag = qio_channel_add_watch(s->ioc, G_IO_IN, net_stream_send,
288
+ s, NULL);
289
290
- if (is_connected) {
291
- net_stream_connect(s);
292
+ if (cioc->localAddr.ss_family == AF_UNIX) {
293
+ addr = qio_channel_socket_get_local_address(cioc, NULL);
294
} else {
295
- qemu_set_fd_handler(s->fd, NULL, net_stream_connect, s);
296
+ addr = qio_channel_socket_get_remote_address(cioc, NULL);
297
}
298
- return s;
299
+ g_assert(addr != NULL);
300
+ uri = socket_uri(addr);
301
+ qemu_set_info_str(&s->nc, uri);
302
+ g_free(uri);
303
+ qapi_free_SocketAddress(addr);
304
}
305
306
-static void net_stream_accept(void *opaque)
307
+static void net_stream_server_listening(QIOTask *task, gpointer opaque)
308
{
309
NetStreamState *s = opaque;
310
- struct sockaddr_storage saddr;
311
- socklen_t len;
312
- int fd;
313
-
314
- for (;;) {
315
- len = sizeof(saddr);
316
- fd = qemu_accept(s->listen_fd, (struct sockaddr *)&saddr, &len);
317
- if (fd < 0 && errno != EINTR) {
318
- return;
319
- } else if (fd >= 0) {
320
- qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
321
- break;
322
- }
323
- }
324
+ QIOChannelSocket *listen_sioc = QIO_CHANNEL_SOCKET(s->listen_ioc);
325
+ SocketAddress *addr;
326
+ int ret;
327
328
- s->fd = fd;
329
- s->nc.link_down = false;
330
- net_stream_connect(s);
331
- switch (saddr.ss_family) {
332
- case AF_INET: {
333
- struct sockaddr_in *saddr_in = (struct sockaddr_in *)&saddr;
334
-
335
- qemu_set_info_str(&s->nc, "connection from %s:%d",
336
- inet_ntoa(saddr_in->sin_addr),
337
- ntohs(saddr_in->sin_port));
338
- break;
339
+ if (listen_sioc->fd < 0) {
340
+ qemu_set_info_str(&s->nc, "connection error");
341
+ return;
342
}
343
- case AF_UNIX: {
344
- struct sockaddr_un saddr_un;
345
346
- len = sizeof(saddr_un);
347
- getsockname(s->listen_fd, (struct sockaddr *)&saddr_un, &len);
348
- qemu_set_info_str(&s->nc, "connect from %s", saddr_un.sun_path);
349
- break;
350
- }
351
- default:
352
- g_assert_not_reached();
353
+ addr = qio_channel_socket_get_local_address(listen_sioc, NULL);
354
+ g_assert(addr != NULL);
355
+ ret = qemu_socket_try_set_nonblock(listen_sioc->fd);
356
+ if (addr->type == SOCKET_ADDRESS_TYPE_FD && ret < 0) {
357
+ qemu_set_info_str(&s->nc, "can't use file descriptor %s (errno %d)",
358
+ addr->u.fd.str, -ret);
359
+ return;
360
}
361
+ g_assert(ret == 0);
362
+ qapi_free_SocketAddress(addr);
363
+
364
+ s->nc.link_down = true;
365
+ s->listener = qio_net_listener_new();
366
+
367
+ net_socket_rs_init(&s->rs, net_stream_rs_finalize, false);
368
+ qio_net_listener_set_client_func(s->listener, net_stream_listen, s, NULL);
369
+ qio_net_listener_add(s->listener, listen_sioc);
370
}
371
372
static int net_stream_server_init(NetClientState *peer,
373
@@ -XXX,XX +XXX,XX @@ static int net_stream_server_init(NetClientState *peer,
374
{
375
NetClientState *nc;
376
NetStreamState *s;
377
- int fd, ret;
378
+ QIOChannelSocket *listen_sioc = qio_channel_socket_new();
379
380
- switch (addr->type) {
381
- case SOCKET_ADDRESS_TYPE_INET: {
382
- struct sockaddr_in saddr_in;
383
-
384
- if (convert_host_port(&saddr_in, addr->u.inet.host, addr->u.inet.port,
385
- errp) < 0) {
386
- return -1;
387
- }
388
-
389
- fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
390
- if (fd < 0) {
391
- error_setg_errno(errp, errno, "can't create stream socket");
392
- return -1;
393
- }
394
- qemu_socket_set_nonblock(fd);
395
+ nc = qemu_new_net_client(&net_stream_info, peer, model, name);
396
+ s = DO_UPCAST(NetStreamState, nc, nc);
397
398
- socket_set_fast_reuse(fd);
399
+ s->listen_ioc = QIO_CHANNEL(listen_sioc);
400
+ qio_channel_socket_listen_async(listen_sioc, addr, 0,
401
+ net_stream_server_listening, s,
402
+ NULL, NULL);
403
404
- ret = bind(fd, (struct sockaddr *)&saddr_in, sizeof(saddr_in));
405
- if (ret < 0) {
406
- error_setg_errno(errp, errno, "can't bind ip=%s to socket",
407
- inet_ntoa(saddr_in.sin_addr));
408
- closesocket(fd);
409
- return -1;
410
- }
411
- break;
412
- }
413
- case SOCKET_ADDRESS_TYPE_UNIX: {
414
- struct sockaddr_un saddr_un;
415
-
416
- ret = unlink(addr->u.q_unix.path);
417
- if (ret < 0 && errno != ENOENT) {
418
- error_setg_errno(errp, errno, "failed to unlink socket %s",
419
- addr->u.q_unix.path);
420
- return -1;
421
- }
422
+ return 0;
423
+}
424
425
- saddr_un.sun_family = PF_UNIX;
426
- ret = snprintf(saddr_un.sun_path, sizeof(saddr_un.sun_path), "%s",
427
- addr->u.q_unix.path);
428
- if (ret < 0 || ret >= sizeof(saddr_un.sun_path)) {
429
- error_setg(errp, "UNIX socket path '%s' is too long",
430
- addr->u.q_unix.path);
431
- error_append_hint(errp, "Path must be less than %zu bytes\n",
432
- sizeof(saddr_un.sun_path));
433
- return -1;
434
- }
435
+static void net_stream_client_connected(QIOTask *task, gpointer opaque)
436
+{
437
+ NetStreamState *s = opaque;
438
+ QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(s->ioc);
439
+ SocketAddress *addr;
440
+ gchar *uri;
441
+ int ret;
442
443
- fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
444
- if (fd < 0) {
445
- error_setg_errno(errp, errno, "can't create stream socket");
446
- return -1;
447
- }
448
- qemu_socket_set_nonblock(fd);
449
-
450
- ret = bind(fd, (struct sockaddr *)&saddr_un, sizeof(saddr_un));
451
- if (ret < 0) {
452
- error_setg_errno(errp, errno, "can't create socket with path: %s",
453
- saddr_un.sun_path);
454
- closesocket(fd);
455
- return -1;
456
- }
457
- break;
458
- }
459
- case SOCKET_ADDRESS_TYPE_FD:
460
- fd = monitor_fd_param(monitor_cur(), addr->u.fd.str, errp);
461
- if (fd == -1) {
462
- return -1;
463
- }
464
- ret = qemu_socket_try_set_nonblock(fd);
465
- if (ret < 0) {
466
- error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
467
- name, fd);
468
- return -1;
469
- }
470
- break;
471
- default:
472
- error_setg(errp, "only support inet or fd type");
473
- return -1;
474
+ if (sioc->fd < 0) {
475
+ qemu_set_info_str(&s->nc, "connection error");
476
+ goto error;
477
}
478
479
- ret = listen(fd, 0);
480
- if (ret < 0) {
481
- error_setg_errno(errp, errno, "can't listen on socket");
482
- closesocket(fd);
483
- return -1;
484
+ addr = qio_channel_socket_get_remote_address(sioc, NULL);
485
+ g_assert(addr != NULL);
486
+ uri = socket_uri(addr);
487
+ qemu_set_info_str(&s->nc, uri);
488
+ g_free(uri);
489
+
490
+ ret = qemu_socket_try_set_nonblock(sioc->fd);
491
+ if (addr->type == SOCKET_ADDRESS_TYPE_FD && ret < 0) {
492
+ qemu_set_info_str(&s->nc, "can't use file descriptor %s (errno %d)",
493
+ addr->u.fd.str, -ret);
494
+ qapi_free_SocketAddress(addr);
495
+ goto error;
496
}
497
+ g_assert(ret == 0);
498
499
- nc = qemu_new_net_client(&net_stream_info, peer, model, name);
500
- s = DO_UPCAST(NetStreamState, nc, nc);
501
- s->fd = -1;
502
- s->listen_fd = fd;
503
- s->nc.link_down = true;
504
net_socket_rs_init(&s->rs, net_stream_rs_finalize, false);
505
506
- qemu_set_fd_handler(s->listen_fd, net_stream_accept, NULL, s);
507
- return 0;
508
+ /* Disable Nagle algorithm on TCP sockets to reduce latency */
509
+ qio_channel_set_delay(s->ioc, false);
510
+
511
+ s->ioc_read_tag = qio_channel_add_watch(s->ioc, G_IO_IN, net_stream_send,
512
+ s, NULL);
513
+ s->nc.link_down = false;
514
+ qapi_free_SocketAddress(addr);
515
+
516
+ return;
517
+error:
518
+ object_unref(OBJECT(s->ioc));
519
+ s->ioc = NULL;
520
}
521
522
static int net_stream_client_init(NetClientState *peer,
523
@@ -XXX,XX +XXX,XX @@ static int net_stream_client_init(NetClientState *peer,
524
Error **errp)
525
{
526
NetStreamState *s;
527
- struct sockaddr_in saddr_in;
528
- struct sockaddr_un saddr_un;
529
- int fd, connected, ret;
530
-
531
- switch (addr->type) {
532
- case SOCKET_ADDRESS_TYPE_INET:
533
- if (convert_host_port(&saddr_in, addr->u.inet.host, addr->u.inet.port,
534
- errp) < 0) {
535
- return -1;
536
- }
537
+ NetClientState *nc;
538
+ QIOChannelSocket *sioc = qio_channel_socket_new();
539
540
- fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
541
- if (fd < 0) {
542
- error_setg_errno(errp, errno, "can't create stream socket");
543
- return -1;
544
- }
545
- qemu_socket_set_nonblock(fd);
546
-
547
- connected = 0;
548
- for (;;) {
549
- ret = connect(fd, (struct sockaddr *)&saddr_in, sizeof(saddr_in));
550
- if (ret < 0) {
551
- if (errno == EINTR || errno == EWOULDBLOCK) {
552
- /* continue */
553
- } else if (errno == EINPROGRESS ||
554
- errno == EALREADY) {
555
- break;
556
- } else {
557
- error_setg_errno(errp, errno, "can't connect socket");
558
- closesocket(fd);
559
- return -1;
560
- }
561
- } else {
562
- connected = 1;
563
- break;
564
- }
565
- }
566
- break;
567
- case SOCKET_ADDRESS_TYPE_UNIX:
568
- saddr_un.sun_family = PF_UNIX;
569
- ret = snprintf(saddr_un.sun_path, sizeof(saddr_un.sun_path), "%s",
570
- addr->u.q_unix.path);
571
- if (ret < 0 || ret >= sizeof(saddr_un.sun_path)) {
572
- error_setg(errp, "UNIX socket path '%s' is too long",
573
- addr->u.q_unix.path);
574
- error_append_hint(errp, "Path must be less than %zu bytes\n",
575
- sizeof(saddr_un.sun_path));
576
- return -1;
577
- }
578
+ nc = qemu_new_net_client(&net_stream_info, peer, model, name);
579
+ s = DO_UPCAST(NetStreamState, nc, nc);
580
581
- fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
582
- if (fd < 0) {
583
- error_setg_errno(errp, errno, "can't create stream socket");
584
- return -1;
585
- }
586
- qemu_socket_set_nonblock(fd);
587
-
588
- connected = 0;
589
- for (;;) {
590
- ret = connect(fd, (struct sockaddr *)&saddr_un, sizeof(saddr_un));
591
- if (ret < 0) {
592
- if (errno == EINTR || errno == EWOULDBLOCK) {
593
- /* continue */
594
- } else if (errno == EAGAIN ||
595
- errno == EALREADY) {
596
- break;
597
- } else {
598
- error_setg_errno(errp, errno, "can't connect socket");
599
- closesocket(fd);
600
- return -1;
601
- }
602
- } else {
603
- connected = 1;
604
- break;
605
- }
606
- }
607
- break;
608
- case SOCKET_ADDRESS_TYPE_FD:
609
- fd = monitor_fd_param(monitor_cur(), addr->u.fd.str, errp);
610
- if (fd == -1) {
611
- return -1;
612
- }
613
- ret = qemu_socket_try_set_nonblock(fd);
614
- if (ret < 0) {
615
- error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d",
616
- name, fd);
617
- return -1;
618
- }
619
- connected = 1;
620
- break;
621
- default:
622
- error_setg(errp, "only support inet, unix or fd type");
623
- return -1;
624
- }
625
+ s->ioc = QIO_CHANNEL(sioc);
626
+ s->nc.link_down = true;
627
+
628
+ qio_channel_socket_connect_async(sioc, addr,
629
+ net_stream_client_connected, s,
630
+ NULL, NULL);
631
632
- s = net_stream_fd_init(peer, model, name, fd, connected);
633
-
634
- switch (addr->type) {
635
- case SOCKET_ADDRESS_TYPE_INET:
636
- qemu_set_info_str(&s->nc, "connect to %s:%d",
637
- inet_ntoa(saddr_in.sin_addr),
638
- ntohs(saddr_in.sin_port));
639
- break;
640
- case SOCKET_ADDRESS_TYPE_UNIX:
641
- qemu_set_info_str(&s->nc, " connect to %s", saddr_un.sun_path);
642
- break;
643
- case SOCKET_ADDRESS_TYPE_FD:
644
- qemu_set_info_str(&s->nc, "connect to fd %d", fd);
645
- break;
646
- default:
647
- g_assert_not_reached();
648
- }
649
return 0;
650
}
651
652
diff --git a/qemu-options.hx b/qemu-options.hx
653
index XXXXXXX..XXXXXXX 100644
654
--- a/qemu-options.hx
655
+++ b/qemu-options.hx
656
@@ -XXX,XX +XXX,XX @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
657
"-netdev socket,id=str[,fd=h][,udp=host:port][,localaddr=host:port]\n"
658
" configure a network backend to connect to another network\n"
659
" using an UDP tunnel\n"
660
- "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port\n"
661
- "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path\n"
662
+ "-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"
663
+ "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off]\n"
664
"-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor\n"
665
" configure a network backend to connect to another network\n"
666
" using a socket connection in stream mode.\n"
667
--
668
2.7.4
diff view generated by jsdifflib
New patch
1
From: Laurent Vivier <lvivier@redhat.com>
1
2
3
The netdev reports NETDEV_STREAM_CONNECTED event when the backend
4
is connected, and NETDEV_STREAM_DISCONNECTED when it is disconnected.
5
6
The NETDEV_STREAM_CONNECTED event includes the destination address.
7
8
This allows a system manager like libvirt to detect when the server
9
fails.
10
11
For instance with passt:
12
13
{ 'execute': 'qmp_capabilities' }
14
{ "return": { } }
15
{ "timestamp": { "seconds": 1666341395, "microseconds": 505347 },
16
"event": "NETDEV_STREAM_CONNECTED",
17
"data": { "netdev-id": "netdev0",
18
"addr": { "path": "/tmp/passt_1.socket", "type": "unix" } } }
19
20
[killing passt here]
21
22
{ "timestamp": { "seconds": 1666341430, "microseconds": 968694 },
23
"event": "NETDEV_STREAM_DISCONNECTED",
24
"data": { "netdev-id": "netdev0" } }
25
26
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
27
Acked-by: Michael S. Tsirkin <mst@redhat.com>
28
Signed-off-by: Jason Wang <jasowang@redhat.com>
29
---
30
net/stream.c | 5 +++++
31
qapi/net.json | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
32
2 files changed, 54 insertions(+)
33
34
diff --git a/net/stream.c b/net/stream.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/net/stream.c
37
+++ b/net/stream.c
38
@@ -XXX,XX +XXX,XX @@
39
#include "io/channel.h"
40
#include "io/channel-socket.h"
41
#include "io/net-listener.h"
42
+#include "qapi/qapi-events-net.h"
43
44
typedef struct NetStreamState {
45
NetClientState nc;
46
@@ -XXX,XX +XXX,XX @@ static gboolean net_stream_send(QIOChannel *ioc,
47
s->nc.link_down = true;
48
qemu_set_info_str(&s->nc, "");
49
50
+ qapi_event_send_netdev_stream_disconnected(s->nc.name);
51
+
52
return G_SOURCE_REMOVE;
53
}
54
buf = buf1;
55
@@ -XXX,XX +XXX,XX @@ static void net_stream_listen(QIONetListener *listener,
56
uri = socket_uri(addr);
57
qemu_set_info_str(&s->nc, uri);
58
g_free(uri);
59
+ qapi_event_send_netdev_stream_connected(s->nc.name, addr);
60
qapi_free_SocketAddress(addr);
61
}
62
63
@@ -XXX,XX +XXX,XX @@ static void net_stream_client_connected(QIOTask *task, gpointer opaque)
64
s->ioc_read_tag = qio_channel_add_watch(s->ioc, G_IO_IN, net_stream_send,
65
s, NULL);
66
s->nc.link_down = false;
67
+ qapi_event_send_netdev_stream_connected(s->nc.name, addr);
68
qapi_free_SocketAddress(addr);
69
70
return;
71
diff --git a/qapi/net.json b/qapi/net.json
72
index XXXXXXX..XXXXXXX 100644
73
--- a/qapi/net.json
74
+++ b/qapi/net.json
75
@@ -XXX,XX +XXX,XX @@
76
##
77
{ 'event': 'FAILOVER_NEGOTIATED',
78
'data': {'device-id': 'str'} }
79
+
80
+##
81
+# @NETDEV_STREAM_CONNECTED:
82
+#
83
+# Emitted when the netdev stream backend is connected
84
+#
85
+# @netdev-id: QEMU netdev id that is connected
86
+# @addr: The destination address
87
+#
88
+# Since: 7.2
89
+#
90
+# Example:
91
+#
92
+# <- { "event": "NETDEV_STREAM_CONNECTED",
93
+# "data": { "netdev-id": "netdev0",
94
+# "addr": { "port": "47666", "ipv6": true,
95
+# "host": "::1", "type": "inet" } },
96
+# "timestamp": { "seconds": 1666269863, "microseconds": 311222 } }
97
+#
98
+# or
99
+#
100
+# <- { "event": "NETDEV_STREAM_CONNECTED",
101
+# "data": { "netdev-id": "netdev0",
102
+# "addr": { "path": "/tmp/qemu0", "type": "unix" } },
103
+# "timestamp": { "seconds": 1666269706, "microseconds": 413651 } }
104
+#
105
+##
106
+{ 'event': 'NETDEV_STREAM_CONNECTED',
107
+ 'data': { 'netdev-id': 'str',
108
+ 'addr': 'SocketAddress' } }
109
+
110
+##
111
+# @NETDEV_STREAM_DISCONNECTED:
112
+#
113
+# Emitted when the netdev stream backend is disconnected
114
+#
115
+# @netdev-id: QEMU netdev id that is disconnected
116
+#
117
+# Since: 7.2
118
+#
119
+# Example:
120
+#
121
+# <- { 'event': 'NETDEV_STREAM_DISCONNECTED',
122
+# 'data': {'netdev-id': 'netdev0'},
123
+# 'timestamp': {'seconds': 1663330937, 'microseconds': 526695} }
124
+#
125
+##
126
+{ 'event': 'NETDEV_STREAM_DISCONNECTED',
127
+ 'data': { 'netdev-id': 'str' } }
128
--
129
2.7.4
diff view generated by jsdifflib