1 | The following changes since commit a04d91c701251a9b32b7364ddb48029ba024cb75: | 1 | The following changes since commit b6179aaff961627fcb59d7b234297966b81ac726: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/alistair/tags/pull-device-tree-20190327' into staging (2019-03-28 12:39:43 +0000) | 3 | Merge remote-tracking branch 'remotes/pmaydell/tags/pull-cocoa-20190304' into staging (2019-03-04 16:50:41 +0000) |
4 | 4 | ||
5 | are available in the git repository at: | 5 | are available in the git repository at: |
6 | 6 | ||
7 | https://github.com/jasowang/qemu.git tags/net-pull-request | 7 | https://github.com/jasowang/qemu.git tags/net-pull-request |
8 | 8 | ||
9 | for you to fetch changes up to ab79237a15e8f8c23310291b672d83374cf17935: | 9 | for you to fetch changes up to 4b9b70000218640a42c3ea908a12665e5840b6cd: |
10 | 10 | ||
11 | net: tap: use qemu_set_nonblock (2019-03-29 15:22:18 +0800) | 11 | tests: Add a test for qemu self announcements (2019-03-05 11:27:41 +0800) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | 14 | ||
15 | Changes from V1: | ||
16 | - build fixes for qmp controlled announcing | ||
17 | |||
15 | ---------------------------------------------------------------- | 18 | ---------------------------------------------------------------- |
16 | Li Qiang (1): | 19 | Dr. David Alan Gilbert (9): |
17 | net: tap: use qemu_set_nonblock | 20 | net: Introduce announce timer |
21 | migration: Add announce parameters | ||
22 | virtio-net: Switch to using announce timer | ||
23 | migration: Switch to using announce timer | ||
24 | net: Add a network device specific self-announcement ability | ||
25 | virtio-net: Allow qemu_announce_self to trigger virtio announcements | ||
26 | qmp: Add announce-self command | ||
27 | hmp: Add hmp_announce_self | ||
28 | tests: Add a test for qemu self announcements | ||
18 | 29 | ||
19 | Marc-André Lureau (1): | 30 | Vincenzo Maffione (3): |
20 | net/socket: learn to talk with a unix dgram socket | 31 | net: netmap: small improvements netmap_send() |
32 | net: netmap: simplify netmap_receive() | ||
33 | net: netmap: improve netmap_receive_iov() | ||
21 | 34 | ||
22 | Zhang Chen (1): | 35 | Zhang Chen (1): |
23 | MAINTAINERS: Update the latest email address | 36 | net/colo-compare.c: Remove duplicated code |
24 | 37 | ||
25 | yuchenlin (1): | 38 | hmp-commands.hx | 16 +++++ |
26 | e1000: Delay flush queue when receive RCTL | 39 | hmp.c | 33 ++++++++++ |
27 | 40 | hmp.h | 1 + | |
28 | MAINTAINERS | 2 +- | 41 | hw/net/trace-events | 6 ++ |
29 | hw/net/e1000.c | 24 ++++++++++++++++++++++-- | 42 | hw/net/virtio-net.c | 69 +++++++++++++++----- |
30 | net/socket.c | 25 +++++++++++++++++++++---- | 43 | include/hw/virtio/virtio-net.h | 4 +- |
31 | net/tap.c | 10 +++++----- | 44 | include/migration/misc.h | 12 +--- |
32 | 4 files changed, 49 insertions(+), 12 deletions(-) | 45 | include/net/announce.h | 41 ++++++++++++ |
46 | include/net/net.h | 2 + | ||
47 | include/qemu/typedefs.h | 1 + | ||
48 | include/sysemu/sysemu.h | 2 - | ||
49 | migration/migration.c | 103 +++++++++++++++++++++++++++++- | ||
50 | migration/migration.h | 4 ++ | ||
51 | migration/savevm.c | 72 +-------------------- | ||
52 | migration/trace-events | 1 - | ||
53 | net/Makefile.objs | 1 + | ||
54 | net/announce.c | 140 +++++++++++++++++++++++++++++++++++++++++ | ||
55 | net/colo-compare.c | 8 --- | ||
56 | net/netmap.c | 110 ++++++++++++++------------------ | ||
57 | net/trace-events | 3 + | ||
58 | qapi/migration.json | 53 +++++++++++++++- | ||
59 | qapi/net.json | 43 +++++++++++++ | ||
60 | tests/Makefile.include | 3 + | ||
61 | tests/test-announce-self.c | 82 ++++++++++++++++++++++++ | ||
62 | tests/test-hmp.c | 1 + | ||
63 | 25 files changed, 637 insertions(+), 174 deletions(-) | ||
64 | create mode 100644 include/net/announce.h | ||
65 | create mode 100644 net/announce.c | ||
66 | create mode 100644 tests/test-announce-self.c | ||
33 | 67 | ||
34 | 68 | ||
69 | diff view generated by jsdifflib |
1 | From: Zhang Chen <chen.zhang@intel.com> | 1 | From: Zhang Chen <chen.zhang@intel.com> |
---|---|---|---|
2 | 2 | ||
3 | Fix duplicated code: | ||
4 | https://bugs.launchpad.net/qemu/+bug/1811499 | ||
5 | |||
6 | Reviewed-by: Thomas Huth <thuth@redhat.com> | ||
7 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
3 | Signed-off-by: Zhang Chen <chen.zhang@intel.com> | 8 | Signed-off-by: Zhang Chen <chen.zhang@intel.com> |
4 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 9 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
5 | --- | 10 | --- |
6 | MAINTAINERS | 2 +- | 11 | net/colo-compare.c | 8 -------- |
7 | 1 file changed, 1 insertion(+), 1 deletion(-) | 12 | 1 file changed, 8 deletions(-) |
8 | 13 | ||
9 | diff --git a/MAINTAINERS b/MAINTAINERS | 14 | diff --git a/net/colo-compare.c b/net/colo-compare.c |
10 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
11 | --- a/MAINTAINERS | 16 | --- a/net/colo-compare.c |
12 | +++ b/MAINTAINERS | 17 | +++ b/net/colo-compare.c |
13 | @@ -XXX,XX +XXX,XX @@ F: include/migration/failover.h | 18 | @@ -XXX,XX +XXX,XX @@ static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt, |
14 | F: docs/COLO-FT.txt | 19 | return true; |
15 | 20 | } | |
16 | COLO Proxy | 21 | } |
17 | -M: Zhang Chen <zhangckid@gmail.com> | 22 | - if (ppkt->tcp_seq == spkt->tcp_seq && ppkt->seq_end == spkt->seq_end) { |
18 | +M: Zhang Chen <chen.zhang@intel.com> | 23 | - if (colo_compare_packet_payload(ppkt, spkt, |
19 | M: Li Zhijian <lizhijian@cn.fujitsu.com> | 24 | - ppkt->header_size, spkt->header_size, |
20 | S: Supported | 25 | - ppkt->payload_size)) { |
21 | F: docs/colo-proxy.txt | 26 | - *mark = COLO_COMPARE_FREE_SECONDARY | COLO_COMPARE_FREE_PRIMARY; |
27 | - return true; | ||
28 | - } | ||
29 | - } | ||
30 | |||
31 | /* one part of secondary packet payload still need to be compared */ | ||
32 | if (!after(ppkt->seq_end, spkt->seq_end)) { | ||
22 | -- | 33 | -- |
23 | 2.5.0 | 34 | 2.5.0 |
24 | 35 | ||
25 | 36 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Vincenzo Maffione <v.maffione@gmail.com> | ||
1 | 2 | ||
3 | This change improves the handling of incomplete multi-slot packets | ||
4 | (e.g. with the NS_MOREFRAG set), by advancing ring->head only on | ||
5 | complete packets. The ring->cur pointer is advanced in any case in | ||
6 | order to acknowledge the kernel and move the wake-up point (thus | ||
7 | avoiding repeated wake-ups). | ||
8 | Also don't be verbose when incomplete packets are found. | ||
9 | |||
10 | Signed-off-by: Vincenzo Maffione <v.maffione@gmail.com> | ||
11 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
12 | --- | ||
13 | net/netmap.c | 31 +++++++++++++++++++------------ | ||
14 | 1 file changed, 19 insertions(+), 12 deletions(-) | ||
15 | |||
16 | diff --git a/net/netmap.c b/net/netmap.c | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/net/netmap.c | ||
19 | +++ b/net/netmap.c | ||
20 | @@ -XXX,XX +XXX,XX @@ static void netmap_send(void *opaque) | ||
21 | { | ||
22 | NetmapState *s = opaque; | ||
23 | struct netmap_ring *ring = s->rx; | ||
24 | + unsigned int tail = ring->tail; | ||
25 | |||
26 | - /* Keep sending while there are available packets into the netmap | ||
27 | + /* Keep sending while there are available slots in the netmap | ||
28 | RX ring and the forwarding path towards the peer is open. */ | ||
29 | - while (!nm_ring_empty(ring)) { | ||
30 | - uint32_t i; | ||
31 | + while (ring->head != tail) { | ||
32 | + uint32_t i = ring->head; | ||
33 | uint32_t idx; | ||
34 | bool morefrag; | ||
35 | int iovcnt = 0; | ||
36 | int iovsize; | ||
37 | |||
38 | + /* Get a (possibly multi-slot) packet. */ | ||
39 | do { | ||
40 | - i = ring->cur; | ||
41 | idx = ring->slot[i].buf_idx; | ||
42 | morefrag = (ring->slot[i].flags & NS_MOREFRAG); | ||
43 | - s->iov[iovcnt].iov_base = (u_char *)NETMAP_BUF(ring, idx); | ||
44 | + s->iov[iovcnt].iov_base = (void *)NETMAP_BUF(ring, idx); | ||
45 | s->iov[iovcnt].iov_len = ring->slot[i].len; | ||
46 | iovcnt++; | ||
47 | + i = nm_ring_next(ring, i); | ||
48 | + } while (i != tail && morefrag); | ||
49 | |||
50 | - ring->cur = ring->head = nm_ring_next(ring, i); | ||
51 | - } while (!nm_ring_empty(ring) && morefrag); | ||
52 | + /* Advance ring->cur to tell the kernel that we have seen the slots. */ | ||
53 | + ring->cur = i; | ||
54 | |||
55 | - if (unlikely(nm_ring_empty(ring) && morefrag)) { | ||
56 | - RD(5, "[netmap_send] ran out of slots, with a pending" | ||
57 | - "incomplete packet\n"); | ||
58 | + if (unlikely(morefrag)) { | ||
59 | + /* This is a truncated packet, so we can stop without releasing the | ||
60 | + * incomplete slots by updating ring->head. We will hopefully | ||
61 | + * re-read the complete packet the next time we are called. */ | ||
62 | + break; | ||
63 | } | ||
64 | |||
65 | iovsize = qemu_sendv_packet_async(&s->nc, s->iov, iovcnt, | ||
66 | netmap_send_completed); | ||
67 | |||
68 | + /* Release the slots to the kernel. */ | ||
69 | + ring->head = i; | ||
70 | + | ||
71 | if (iovsize == 0) { | ||
72 | /* The peer does not receive anymore. Packet is queued, stop | ||
73 | - * reading from the backend until netmap_send_completed() | ||
74 | - */ | ||
75 | + * reading from the backend until netmap_send_completed(). */ | ||
76 | netmap_read_poll(s, false); | ||
77 | break; | ||
78 | } | ||
79 | -- | ||
80 | 2.5.0 | ||
81 | |||
82 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Vincenzo Maffione <v.maffione@gmail.com> | ||
1 | 2 | ||
3 | Improve code reuse by implementing netmap_receive() with a call | ||
4 | to netmap_receive_iov(). | ||
5 | |||
6 | Signed-off-by: Vincenzo Maffione <v.maffione@gmail.com> | ||
7 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
8 | --- | ||
9 | net/netmap.c | 50 +++++++++++--------------------------------------- | ||
10 | 1 file changed, 11 insertions(+), 39 deletions(-) | ||
11 | |||
12 | diff --git a/net/netmap.c b/net/netmap.c | ||
13 | index XXXXXXX..XXXXXXX 100644 | ||
14 | --- a/net/netmap.c | ||
15 | +++ b/net/netmap.c | ||
16 | @@ -XXX,XX +XXX,XX @@ static void netmap_writable(void *opaque) | ||
17 | qemu_flush_queued_packets(&s->nc); | ||
18 | } | ||
19 | |||
20 | -static ssize_t netmap_receive(NetClientState *nc, | ||
21 | - const uint8_t *buf, size_t size) | ||
22 | -{ | ||
23 | - NetmapState *s = DO_UPCAST(NetmapState, nc, nc); | ||
24 | - struct netmap_ring *ring = s->tx; | ||
25 | - uint32_t i; | ||
26 | - uint32_t idx; | ||
27 | - uint8_t *dst; | ||
28 | - | ||
29 | - if (unlikely(!ring)) { | ||
30 | - /* Drop. */ | ||
31 | - return size; | ||
32 | - } | ||
33 | - | ||
34 | - if (unlikely(size > ring->nr_buf_size)) { | ||
35 | - RD(5, "[netmap_receive] drop packet of size %d > %d\n", | ||
36 | - (int)size, ring->nr_buf_size); | ||
37 | - return size; | ||
38 | - } | ||
39 | - | ||
40 | - if (nm_ring_empty(ring)) { | ||
41 | - /* No available slots in the netmap TX ring. */ | ||
42 | - netmap_write_poll(s, true); | ||
43 | - return 0; | ||
44 | - } | ||
45 | - | ||
46 | - i = ring->cur; | ||
47 | - idx = ring->slot[i].buf_idx; | ||
48 | - dst = (uint8_t *)NETMAP_BUF(ring, idx); | ||
49 | - | ||
50 | - ring->slot[i].len = size; | ||
51 | - ring->slot[i].flags = 0; | ||
52 | - pkt_copy(buf, dst, size); | ||
53 | - ring->cur = ring->head = nm_ring_next(ring, i); | ||
54 | - ioctl(s->nmd->fd, NIOCTXSYNC, NULL); | ||
55 | - | ||
56 | - return size; | ||
57 | -} | ||
58 | - | ||
59 | static ssize_t netmap_receive_iov(NetClientState *nc, | ||
60 | const struct iovec *iov, int iovcnt) | ||
61 | { | ||
62 | @@ -XXX,XX +XXX,XX @@ static ssize_t netmap_receive_iov(NetClientState *nc, | ||
63 | return iov_size(iov, iovcnt); | ||
64 | } | ||
65 | |||
66 | +static ssize_t netmap_receive(NetClientState *nc, | ||
67 | + const uint8_t *buf, size_t size) | ||
68 | +{ | ||
69 | + struct iovec iov; | ||
70 | + | ||
71 | + iov.iov_base = (void *)buf; | ||
72 | + iov.iov_len = size; | ||
73 | + | ||
74 | + return netmap_receive_iov(nc, &iov, 1); | ||
75 | +} | ||
76 | + | ||
77 | /* Complete a previous send (backend --> guest) and enable the | ||
78 | fd_read callback. */ | ||
79 | static void netmap_send_completed(NetClientState *nc, ssize_t len) | ||
80 | -- | ||
81 | 2.5.0 | ||
82 | |||
83 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Vincenzo Maffione <v.maffione@gmail.com> | ||
1 | 2 | ||
3 | Changes: | ||
4 | - Save CPU cycles by computing the return value while scanning the | ||
5 | input iovec, rather than calling iov_size() at the end. | ||
6 | - Remove check for s->tx != NULL, because it cannot happen. | ||
7 | - Cache ring->tail in a local variable and use it to check for | ||
8 | space in the TX ring. The use of nm_ring_empty() was invalid, | ||
9 | because nobody is updating ring->cur and ring->head at that point. | ||
10 | - In case we run out of netmap slots in the middle of a packet, | ||
11 | move the wake-up point by advancing ring->cur, but do not | ||
12 | expose the incomplete packet (i.e., by updating also ring->head). | ||
13 | |||
14 | Signed-off-by: Vincenzo Maffione <v.maffione@gmail.com> | ||
15 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
16 | --- | ||
17 | net/netmap.c | 29 +++++++++++++++++------------ | ||
18 | 1 file changed, 17 insertions(+), 12 deletions(-) | ||
19 | |||
20 | diff --git a/net/netmap.c b/net/netmap.c | ||
21 | index XXXXXXX..XXXXXXX 100644 | ||
22 | --- a/net/netmap.c | ||
23 | +++ b/net/netmap.c | ||
24 | @@ -XXX,XX +XXX,XX @@ static ssize_t netmap_receive_iov(NetClientState *nc, | ||
25 | { | ||
26 | NetmapState *s = DO_UPCAST(NetmapState, nc, nc); | ||
27 | struct netmap_ring *ring = s->tx; | ||
28 | + unsigned int tail = ring->tail; | ||
29 | + ssize_t totlen = 0; | ||
30 | uint32_t last; | ||
31 | uint32_t idx; | ||
32 | uint8_t *dst; | ||
33 | int j; | ||
34 | uint32_t i; | ||
35 | |||
36 | - if (unlikely(!ring)) { | ||
37 | - /* Drop the packet. */ | ||
38 | - return iov_size(iov, iovcnt); | ||
39 | - } | ||
40 | - | ||
41 | - last = i = ring->cur; | ||
42 | + last = i = ring->head; | ||
43 | |||
44 | if (nm_ring_space(ring) < iovcnt) { | ||
45 | - /* Not enough netmap slots. */ | ||
46 | + /* Not enough netmap slots. Tell the kernel that we have seen the new | ||
47 | + * available slots (so that it notifies us again when it has more | ||
48 | + * ones), but without publishing any new slots to be processed | ||
49 | + * (e.g., we don't advance ring->head). */ | ||
50 | + ring->cur = tail; | ||
51 | netmap_write_poll(s, true); | ||
52 | return 0; | ||
53 | } | ||
54 | @@ -XXX,XX +XXX,XX @@ static ssize_t netmap_receive_iov(NetClientState *nc, | ||
55 | int offset = 0; | ||
56 | int nm_frag_size; | ||
57 | |||
58 | + totlen += iov_frag_size; | ||
59 | + | ||
60 | /* Split each iovec fragment over more netmap slots, if | ||
61 | necessary. */ | ||
62 | while (iov_frag_size) { | ||
63 | nm_frag_size = MIN(iov_frag_size, ring->nr_buf_size); | ||
64 | |||
65 | - if (unlikely(nm_ring_empty(ring))) { | ||
66 | - /* We run out of netmap slots while splitting the | ||
67 | + if (unlikely(i == tail)) { | ||
68 | + /* We ran out of netmap slots while splitting the | ||
69 | iovec fragments. */ | ||
70 | + ring->cur = tail; | ||
71 | netmap_write_poll(s, true); | ||
72 | return 0; | ||
73 | } | ||
74 | @@ -XXX,XX +XXX,XX @@ static ssize_t netmap_receive_iov(NetClientState *nc, | ||
75 | /* The last slot must not have NS_MOREFRAG set. */ | ||
76 | ring->slot[last].flags &= ~NS_MOREFRAG; | ||
77 | |||
78 | - /* Now update ring->cur and ring->head. */ | ||
79 | - ring->cur = ring->head = i; | ||
80 | + /* Now update ring->head and ring->cur to publish the new slots and | ||
81 | + * the new wakeup point. */ | ||
82 | + ring->head = ring->cur = i; | ||
83 | |||
84 | ioctl(s->nmd->fd, NIOCTXSYNC, NULL); | ||
85 | |||
86 | - return iov_size(iov, iovcnt); | ||
87 | + return totlen; | ||
88 | } | ||
89 | |||
90 | static ssize_t netmap_receive(NetClientState *nc, | ||
91 | -- | ||
92 | 2.5.0 | ||
93 | |||
94 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | 1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> | |
2 | |||
3 | The 'announce timer' will be used by migration, and explicit | ||
4 | requests for qemu to perform network announces. | ||
5 | |||
6 | Based on the work by Germano Veit Michel <germano@redhat.com> | ||
7 | and Vlad Yasevich <vyasevic@redhat.com> | ||
8 | |||
9 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | ||
10 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||
11 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
12 | --- | ||
13 | include/net/announce.h | 39 ++++++++++++++++++++++++++++++++ | ||
14 | include/qemu/typedefs.h | 1 + | ||
15 | migration/migration.c | 1 + | ||
16 | net/Makefile.objs | 1 + | ||
17 | net/announce.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ | ||
18 | qapi/net.json | 23 +++++++++++++++++++ | ||
19 | 6 files changed, 125 insertions(+) | ||
20 | create mode 100644 include/net/announce.h | ||
21 | create mode 100644 net/announce.c | ||
22 | |||
23 | diff --git a/include/net/announce.h b/include/net/announce.h | ||
24 | new file mode 100644 | ||
25 | index XXXXXXX..XXXXXXX | ||
26 | --- /dev/null | ||
27 | +++ b/include/net/announce.h | ||
28 | @@ -XXX,XX +XXX,XX @@ | ||
29 | +/* | ||
30 | + * Self-announce facility | ||
31 | + * (c) 2017-2019 Red Hat, Inc. | ||
32 | + * | ||
33 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||
34 | + * See the COPYING file in the top-level directory. | ||
35 | + */ | ||
36 | + | ||
37 | +#ifndef QEMU_NET_ANNOUNCE_H | ||
38 | +#define QEMU_NET_ANNOUNCE_H | ||
39 | + | ||
40 | +#include "qemu-common.h" | ||
41 | +#include "qapi/qapi-types-net.h" | ||
42 | +#include "qemu/timer.h" | ||
43 | + | ||
44 | +struct AnnounceTimer { | ||
45 | + QEMUTimer *tm; | ||
46 | + AnnounceParameters params; | ||
47 | + QEMUClockType type; | ||
48 | + int round; | ||
49 | +}; | ||
50 | + | ||
51 | +/* Returns: update the timer to the next time point */ | ||
52 | +int64_t qemu_announce_timer_step(AnnounceTimer *timer); | ||
53 | + | ||
54 | +/* Delete the underlying timer */ | ||
55 | +void qemu_announce_timer_del(AnnounceTimer *timer); | ||
56 | + | ||
57 | +/* | ||
58 | + * Under BQL/main thread | ||
59 | + * Reset the timer to the given parameters/type/notifier. | ||
60 | + */ | ||
61 | +void qemu_announce_timer_reset(AnnounceTimer *timer, | ||
62 | + AnnounceParameters *params, | ||
63 | + QEMUClockType type, | ||
64 | + QEMUTimerCB *cb, | ||
65 | + void *opaque); | ||
66 | + | ||
67 | +#endif | ||
68 | diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h | ||
69 | index XXXXXXX..XXXXXXX 100644 | ||
70 | --- a/include/qemu/typedefs.h | ||
71 | +++ b/include/qemu/typedefs.h | ||
72 | @@ -XXX,XX +XXX,XX @@ | ||
73 | typedef struct AdapterInfo AdapterInfo; | ||
74 | typedef struct AddressSpace AddressSpace; | ||
75 | typedef struct AioContext AioContext; | ||
76 | +typedef struct AnnounceTimer AnnounceTimer; | ||
77 | typedef struct BdrvDirtyBitmap BdrvDirtyBitmap; | ||
78 | typedef struct BdrvDirtyBitmapIter BdrvDirtyBitmapIter; | ||
79 | typedef struct BlockBackend BlockBackend; | ||
80 | diff --git a/migration/migration.c b/migration/migration.c | ||
81 | index XXXXXXX..XXXXXXX 100644 | ||
82 | --- a/migration/migration.c | ||
83 | +++ b/migration/migration.c | ||
84 | @@ -XXX,XX +XXX,XX @@ | ||
85 | #include "migration/colo.h" | ||
86 | #include "hw/boards.h" | ||
87 | #include "monitor/monitor.h" | ||
88 | +#include "net/announce.h" | ||
89 | |||
90 | #define MAX_THROTTLE (32 << 20) /* Migration transfer speed throttling */ | ||
91 | |||
92 | diff --git a/net/Makefile.objs b/net/Makefile.objs | ||
93 | index XXXXXXX..XXXXXXX 100644 | ||
94 | --- a/net/Makefile.objs | ||
95 | +++ b/net/Makefile.objs | ||
96 | @@ -XXX,XX +XXX,XX @@ common-obj-y = net.o queue.o checksum.o util.o hub.o | ||
97 | common-obj-y += socket.o | ||
98 | common-obj-y += dump.o | ||
99 | common-obj-y += eth.o | ||
100 | +common-obj-y += announce.o | ||
101 | common-obj-$(CONFIG_L2TPV3) += l2tpv3.o | ||
102 | common-obj-$(call land,$(CONFIG_VIRTIO_NET),$(CONFIG_VHOST_NET_USER)) += vhost-user.o | ||
103 | common-obj-$(call land,$(call lnot,$(CONFIG_VIRTIO_NET)),$(CONFIG_VHOST_NET_USER)) += vhost-user-stub.o | ||
104 | diff --git a/net/announce.c b/net/announce.c | ||
105 | new file mode 100644 | ||
106 | index XXXXXXX..XXXXXXX | ||
107 | --- /dev/null | ||
108 | +++ b/net/announce.c | ||
109 | @@ -XXX,XX +XXX,XX @@ | ||
110 | +/* | ||
111 | + * Self-announce | ||
112 | + * (c) 2017-2019 Red Hat, Inc. | ||
113 | + * | ||
114 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||
115 | + * See the COPYING file in the top-level directory. | ||
116 | + */ | ||
117 | + | ||
118 | +#include "qemu/osdep.h" | ||
119 | +#include "qemu-common.h" | ||
120 | +#include "net/announce.h" | ||
121 | +#include "qapi/clone-visitor.h" | ||
122 | +#include "qapi/qapi-visit-net.h" | ||
123 | + | ||
124 | +int64_t qemu_announce_timer_step(AnnounceTimer *timer) | ||
125 | +{ | ||
126 | + int64_t step; | ||
127 | + | ||
128 | + step = timer->params.initial + | ||
129 | + (timer->params.rounds - timer->round - 1) * | ||
130 | + timer->params.step; | ||
131 | + | ||
132 | + if (step < 0 || step > timer->params.max) { | ||
133 | + step = timer->params.max; | ||
134 | + } | ||
135 | + timer_mod(timer->tm, qemu_clock_get_ms(timer->type) + step); | ||
136 | + | ||
137 | + return step; | ||
138 | +} | ||
139 | + | ||
140 | +void qemu_announce_timer_del(AnnounceTimer *timer) | ||
141 | +{ | ||
142 | + if (timer->tm) { | ||
143 | + timer_del(timer->tm); | ||
144 | + timer_free(timer->tm); | ||
145 | + timer->tm = NULL; | ||
146 | + } | ||
147 | +} | ||
148 | + | ||
149 | +/* | ||
150 | + * Under BQL/main thread | ||
151 | + * Reset the timer to the given parameters/type/notifier. | ||
152 | + */ | ||
153 | +void qemu_announce_timer_reset(AnnounceTimer *timer, | ||
154 | + AnnounceParameters *params, | ||
155 | + QEMUClockType type, | ||
156 | + QEMUTimerCB *cb, | ||
157 | + void *opaque) | ||
158 | +{ | ||
159 | + /* | ||
160 | + * We're under the BQL, so the current timer can't | ||
161 | + * be firing, so we should be able to delete it. | ||
162 | + */ | ||
163 | + qemu_announce_timer_del(timer); | ||
164 | + | ||
165 | + QAPI_CLONE_MEMBERS(AnnounceParameters, &timer->params, params); | ||
166 | + timer->round = params->rounds; | ||
167 | + timer->type = type; | ||
168 | + timer->tm = timer_new_ms(type, cb, opaque); | ||
169 | +} | ||
170 | diff --git a/qapi/net.json b/qapi/net.json | ||
171 | index XXXXXXX..XXXXXXX 100644 | ||
172 | --- a/qapi/net.json | ||
173 | +++ b/qapi/net.json | ||
174 | @@ -XXX,XX +XXX,XX @@ | ||
175 | ## | ||
176 | { 'event': 'NIC_RX_FILTER_CHANGED', | ||
177 | 'data': { '*name': 'str', 'path': 'str' } } | ||
178 | + | ||
179 | +## | ||
180 | +# @AnnounceParameters: | ||
181 | +# | ||
182 | +# Parameters for self-announce timers | ||
183 | +# | ||
184 | +# @initial: Initial delay (in ms) before sending the first GARP/RARP | ||
185 | +# announcement | ||
186 | +# | ||
187 | +# @max: Maximum delay (in ms) between GARP/RARP announcement packets | ||
188 | +# | ||
189 | +# @rounds: Number of self-announcement attempts | ||
190 | +# | ||
191 | +# @step: Delay increase (in ms) after each self-announcement attempt | ||
192 | +# | ||
193 | +# Since: 4.0 | ||
194 | +## | ||
195 | + | ||
196 | +{ 'struct': 'AnnounceParameters', | ||
197 | + 'data': { 'initial': 'int', | ||
198 | + 'max': 'int', | ||
199 | + 'rounds': 'int', | ||
200 | + 'step': 'int' } } | ||
201 | -- | ||
202 | 2.5.0 | ||
203 | |||
204 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | 1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> | |
2 | |||
3 | Add migration parameters that control RARP/GARP announcement timeouts. | ||
4 | |||
5 | Based on earlier patches by myself and | ||
6 | Vladislav Yasevich <vyasevic@redhat.com> | ||
7 | |||
8 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | ||
9 | Acked-by: Markus Armbruster <armbru@redhat.com> | ||
10 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||
11 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
12 | --- | ||
13 | hmp.c | 28 +++++++++++++ | ||
14 | include/migration/misc.h | 2 + | ||
15 | migration/migration.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++ | ||
16 | qapi/migration.json | 53 +++++++++++++++++++++++-- | ||
17 | 4 files changed, 180 insertions(+), 3 deletions(-) | ||
18 | |||
19 | diff --git a/hmp.c b/hmp.c | ||
20 | index XXXXXXX..XXXXXXX 100644 | ||
21 | --- a/hmp.c | ||
22 | +++ b/hmp.c | ||
23 | @@ -XXX,XX +XXX,XX @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) | ||
24 | params = qmp_query_migrate_parameters(NULL); | ||
25 | |||
26 | if (params) { | ||
27 | + monitor_printf(mon, "%s: %" PRIu64 " ms\n", | ||
28 | + MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_INITIAL), | ||
29 | + params->announce_initial); | ||
30 | + monitor_printf(mon, "%s: %" PRIu64 " ms\n", | ||
31 | + MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_MAX), | ||
32 | + params->announce_max); | ||
33 | + monitor_printf(mon, "%s: %" PRIu64 "\n", | ||
34 | + MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_ROUNDS), | ||
35 | + params->announce_rounds); | ||
36 | + monitor_printf(mon, "%s: %" PRIu64 " ms\n", | ||
37 | + MigrationParameter_str(MIGRATION_PARAMETER_ANNOUNCE_STEP), | ||
38 | + params->announce_step); | ||
39 | assert(params->has_compress_level); | ||
40 | monitor_printf(mon, "%s: %u\n", | ||
41 | MigrationParameter_str(MIGRATION_PARAMETER_COMPRESS_LEVEL), | ||
42 | @@ -XXX,XX +XXX,XX @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) | ||
43 | p->has_max_postcopy_bandwidth = true; | ||
44 | visit_type_size(v, param, &p->max_postcopy_bandwidth, &err); | ||
45 | break; | ||
46 | + case MIGRATION_PARAMETER_ANNOUNCE_INITIAL: | ||
47 | + p->has_announce_initial = true; | ||
48 | + visit_type_size(v, param, &p->announce_initial, &err); | ||
49 | + break; | ||
50 | + case MIGRATION_PARAMETER_ANNOUNCE_MAX: | ||
51 | + p->has_announce_max = true; | ||
52 | + visit_type_size(v, param, &p->announce_max, &err); | ||
53 | + break; | ||
54 | + case MIGRATION_PARAMETER_ANNOUNCE_ROUNDS: | ||
55 | + p->has_announce_rounds = true; | ||
56 | + visit_type_size(v, param, &p->announce_rounds, &err); | ||
57 | + break; | ||
58 | + case MIGRATION_PARAMETER_ANNOUNCE_STEP: | ||
59 | + p->has_announce_step = true; | ||
60 | + visit_type_size(v, param, &p->announce_step, &err); | ||
61 | + break; | ||
62 | default: | ||
63 | assert(0); | ||
64 | } | ||
65 | diff --git a/include/migration/misc.h b/include/migration/misc.h | ||
66 | index XXXXXXX..XXXXXXX 100644 | ||
67 | --- a/include/migration/misc.h | ||
68 | +++ b/include/migration/misc.h | ||
69 | @@ -XXX,XX +XXX,XX @@ | ||
70 | #define MIGRATION_MISC_H | ||
71 | |||
72 | #include "qemu/notify.h" | ||
73 | +#include "qapi/qapi-types-net.h" | ||
74 | |||
75 | /* migration/ram.c */ | ||
76 | |||
77 | @@ -XXX,XX +XXX,XX @@ int64_t self_announce_delay(int round) | ||
78 | return 50 + (SELF_ANNOUNCE_ROUNDS - round - 1) * 100; | ||
79 | } | ||
80 | |||
81 | +AnnounceParameters *migrate_announce_params(void); | ||
82 | /* migration/savevm.c */ | ||
83 | |||
84 | void dump_vmstate_json_to_file(FILE *out_fp); | ||
85 | diff --git a/migration/migration.c b/migration/migration.c | ||
86 | index XXXXXXX..XXXXXXX 100644 | ||
87 | --- a/migration/migration.c | ||
88 | +++ b/migration/migration.c | ||
89 | @@ -XXX,XX +XXX,XX @@ | ||
90 | */ | ||
91 | #define DEFAULT_MIGRATE_MAX_POSTCOPY_BANDWIDTH 0 | ||
92 | |||
93 | +/* | ||
94 | + * Parameters for self_announce_delay giving a stream of RARP/ARP | ||
95 | + * packets after migration. | ||
96 | + */ | ||
97 | +#define DEFAULT_MIGRATE_ANNOUNCE_INITIAL 50 | ||
98 | +#define DEFAULT_MIGRATE_ANNOUNCE_MAX 550 | ||
99 | +#define DEFAULT_MIGRATE_ANNOUNCE_ROUNDS 5 | ||
100 | +#define DEFAULT_MIGRATE_ANNOUNCE_STEP 100 | ||
101 | + | ||
102 | static NotifierList migration_state_notifiers = | ||
103 | NOTIFIER_LIST_INITIALIZER(migration_state_notifiers); | ||
104 | |||
105 | @@ -XXX,XX +XXX,XX @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) | ||
106 | params->max_postcopy_bandwidth = s->parameters.max_postcopy_bandwidth; | ||
107 | params->has_max_cpu_throttle = true; | ||
108 | params->max_cpu_throttle = s->parameters.max_cpu_throttle; | ||
109 | + params->has_announce_initial = true; | ||
110 | + params->announce_initial = s->parameters.announce_initial; | ||
111 | + params->has_announce_max = true; | ||
112 | + params->announce_max = s->parameters.announce_max; | ||
113 | + params->has_announce_rounds = true; | ||
114 | + params->announce_rounds = s->parameters.announce_rounds; | ||
115 | + params->has_announce_step = true; | ||
116 | + params->announce_step = s->parameters.announce_step; | ||
117 | |||
118 | return params; | ||
119 | } | ||
120 | |||
121 | +AnnounceParameters *migrate_announce_params(void) | ||
122 | +{ | ||
123 | + static AnnounceParameters ap; | ||
124 | + | ||
125 | + MigrationState *s = migrate_get_current(); | ||
126 | + | ||
127 | + ap.initial = s->parameters.announce_initial; | ||
128 | + ap.max = s->parameters.announce_max; | ||
129 | + ap.rounds = s->parameters.announce_rounds; | ||
130 | + ap.step = s->parameters.announce_step; | ||
131 | + | ||
132 | + return ≈ | ||
133 | +} | ||
134 | + | ||
135 | /* | ||
136 | * Return true if we're already in the middle of a migration | ||
137 | * (i.e. any of the active or setup states) | ||
138 | @@ -XXX,XX +XXX,XX @@ static bool migrate_params_check(MigrationParameters *params, Error **errp) | ||
139 | return false; | ||
140 | } | ||
141 | |||
142 | + if (params->has_announce_initial && | ||
143 | + params->announce_initial > 100000) { | ||
144 | + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, | ||
145 | + "announce_initial", | ||
146 | + "is invalid, it must be less than 100000 ms"); | ||
147 | + return false; | ||
148 | + } | ||
149 | + if (params->has_announce_max && | ||
150 | + params->announce_max > 100000) { | ||
151 | + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, | ||
152 | + "announce_max", | ||
153 | + "is invalid, it must be less than 100000 ms"); | ||
154 | + return false; | ||
155 | + } | ||
156 | + if (params->has_announce_rounds && | ||
157 | + params->announce_rounds > 1000) { | ||
158 | + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, | ||
159 | + "announce_rounds", | ||
160 | + "is invalid, it must be in the range of 0 to 1000"); | ||
161 | + return false; | ||
162 | + } | ||
163 | + if (params->has_announce_step && | ||
164 | + (params->announce_step < 1 || | ||
165 | + params->announce_step > 10000)) { | ||
166 | + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, | ||
167 | + "announce_step", | ||
168 | + "is invalid, it must be in the range of 1 to 10000 ms"); | ||
169 | + return false; | ||
170 | + } | ||
171 | return true; | ||
172 | } | ||
173 | |||
174 | @@ -XXX,XX +XXX,XX @@ static void migrate_params_test_apply(MigrateSetParameters *params, | ||
175 | if (params->has_max_cpu_throttle) { | ||
176 | dest->max_cpu_throttle = params->max_cpu_throttle; | ||
177 | } | ||
178 | + if (params->has_announce_initial) { | ||
179 | + dest->announce_initial = params->announce_initial; | ||
180 | + } | ||
181 | + if (params->has_announce_max) { | ||
182 | + dest->announce_max = params->announce_max; | ||
183 | + } | ||
184 | + if (params->has_announce_rounds) { | ||
185 | + dest->announce_rounds = params->announce_rounds; | ||
186 | + } | ||
187 | + if (params->has_announce_step) { | ||
188 | + dest->announce_step = params->announce_step; | ||
189 | + } | ||
190 | } | ||
191 | |||
192 | static void migrate_params_apply(MigrateSetParameters *params, Error **errp) | ||
193 | @@ -XXX,XX +XXX,XX @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) | ||
194 | if (params->has_max_cpu_throttle) { | ||
195 | s->parameters.max_cpu_throttle = params->max_cpu_throttle; | ||
196 | } | ||
197 | + if (params->has_announce_initial) { | ||
198 | + s->parameters.announce_initial = params->announce_initial; | ||
199 | + } | ||
200 | + if (params->has_announce_max) { | ||
201 | + s->parameters.announce_max = params->announce_max; | ||
202 | + } | ||
203 | + if (params->has_announce_rounds) { | ||
204 | + s->parameters.announce_rounds = params->announce_rounds; | ||
205 | + } | ||
206 | + if (params->has_announce_step) { | ||
207 | + s->parameters.announce_step = params->announce_step; | ||
208 | + } | ||
209 | } | ||
210 | |||
211 | void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp) | ||
212 | @@ -XXX,XX +XXX,XX @@ static Property migration_properties[] = { | ||
213 | DEFINE_PROP_UINT8("max-cpu-throttle", MigrationState, | ||
214 | parameters.max_cpu_throttle, | ||
215 | DEFAULT_MIGRATE_MAX_CPU_THROTTLE), | ||
216 | + DEFINE_PROP_SIZE("announce-initial", MigrationState, | ||
217 | + parameters.announce_initial, | ||
218 | + DEFAULT_MIGRATE_ANNOUNCE_INITIAL), | ||
219 | + DEFINE_PROP_SIZE("announce-max", MigrationState, | ||
220 | + parameters.announce_max, | ||
221 | + DEFAULT_MIGRATE_ANNOUNCE_MAX), | ||
222 | + DEFINE_PROP_SIZE("announce-rounds", MigrationState, | ||
223 | + parameters.announce_rounds, | ||
224 | + DEFAULT_MIGRATE_ANNOUNCE_ROUNDS), | ||
225 | + DEFINE_PROP_SIZE("announce-step", MigrationState, | ||
226 | + parameters.announce_step, | ||
227 | + DEFAULT_MIGRATE_ANNOUNCE_STEP), | ||
228 | |||
229 | /* Migration capabilities */ | ||
230 | DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE), | ||
231 | @@ -XXX,XX +XXX,XX @@ static void migration_instance_init(Object *obj) | ||
232 | params->has_xbzrle_cache_size = true; | ||
233 | params->has_max_postcopy_bandwidth = true; | ||
234 | params->has_max_cpu_throttle = true; | ||
235 | + params->has_announce_initial = true; | ||
236 | + params->has_announce_max = true; | ||
237 | + params->has_announce_rounds = true; | ||
238 | + params->has_announce_step = true; | ||
239 | |||
240 | qemu_sem_init(&ms->postcopy_pause_sem, 0); | ||
241 | qemu_sem_init(&ms->postcopy_pause_rp_sem, 0); | ||
242 | diff --git a/qapi/migration.json b/qapi/migration.json | ||
243 | index XXXXXXX..XXXXXXX 100644 | ||
244 | --- a/qapi/migration.json | ||
245 | +++ b/qapi/migration.json | ||
246 | @@ -XXX,XX +XXX,XX @@ | ||
247 | # | ||
248 | # Migration parameters enumeration | ||
249 | # | ||
250 | +# @announce-initial: Initial delay (in milliseconds) before sending the first | ||
251 | +# announce (Since 4.0) | ||
252 | +# | ||
253 | +# @announce-max: Maximum delay (in milliseconds) between packets in the | ||
254 | +# announcement (Since 4.0) | ||
255 | +# | ||
256 | +# @announce-rounds: Number of self-announce packets sent after migration | ||
257 | +# (Since 4.0) | ||
258 | +# | ||
259 | +# @announce-step: Increase in delay (in milliseconds) between subsequent | ||
260 | +# packets in the announcement (Since 4.0) | ||
261 | +# | ||
262 | # @compress-level: Set the compression level to be used in live migration, | ||
263 | # the compression level is an integer between 0 and 9, where 0 means | ||
264 | # no compression, 1 means the best compression speed, and 9 means best | ||
265 | @@ -XXX,XX +XXX,XX @@ | ||
266 | # | ||
267 | # @max-cpu-throttle: maximum cpu throttle percentage. | ||
268 | # Defaults to 99. (Since 3.1) | ||
269 | +# | ||
270 | # Since: 2.4 | ||
271 | ## | ||
272 | { 'enum': 'MigrationParameter', | ||
273 | - 'data': ['compress-level', 'compress-threads', 'decompress-threads', | ||
274 | + 'data': ['announce-initial', 'announce-max', | ||
275 | + 'announce-rounds', 'announce-step', | ||
276 | + 'compress-level', 'compress-threads', 'decompress-threads', | ||
277 | 'compress-wait-thread', | ||
278 | 'cpu-throttle-initial', 'cpu-throttle-increment', | ||
279 | 'tls-creds', 'tls-hostname', 'max-bandwidth', | ||
280 | @@ -XXX,XX +XXX,XX @@ | ||
281 | ## | ||
282 | # @MigrateSetParameters: | ||
283 | # | ||
284 | +# @announce-initial: Initial delay (in milliseconds) before sending the first | ||
285 | +# announce (Since 4.0) | ||
286 | +# | ||
287 | +# @announce-max: Maximum delay (in milliseconds) between packets in the | ||
288 | +# announcement (Since 4.0) | ||
289 | +# | ||
290 | +# @announce-rounds: Number of self-announce packets sent after migration | ||
291 | +# (Since 4.0) | ||
292 | +# | ||
293 | +# @announce-step: Increase in delay (in milliseconds) between subsequent | ||
294 | +# packets in the announcement (Since 4.0) | ||
295 | +# | ||
296 | # @compress-level: compression level | ||
297 | # | ||
298 | # @compress-threads: compression thread count | ||
299 | @@ -XXX,XX +XXX,XX @@ | ||
300 | # TODO either fuse back into MigrationParameters, or make | ||
301 | # MigrationParameters members mandatory | ||
302 | { 'struct': 'MigrateSetParameters', | ||
303 | - 'data': { '*compress-level': 'int', | ||
304 | + 'data': { '*announce-initial': 'size', | ||
305 | + '*announce-max': 'size', | ||
306 | + '*announce-rounds': 'size', | ||
307 | + '*announce-step': 'size', | ||
308 | + '*compress-level': 'int', | ||
309 | '*compress-threads': 'int', | ||
310 | '*compress-wait-thread': 'bool', | ||
311 | '*decompress-threads': 'int', | ||
312 | @@ -XXX,XX +XXX,XX @@ | ||
313 | # | ||
314 | # The optional members aren't actually optional. | ||
315 | # | ||
316 | +# @announce-initial: Initial delay (in milliseconds) before sending the | ||
317 | +# first announce (Since 4.0) | ||
318 | +# | ||
319 | +# @announce-max: Maximum delay (in milliseconds) between packets in the | ||
320 | +# announcement (Since 4.0) | ||
321 | +# | ||
322 | +# @announce-rounds: Number of self-announce packets sent after migration | ||
323 | +# (Since 4.0) | ||
324 | +# | ||
325 | +# @announce-step: Increase in delay (in milliseconds) between subsequent | ||
326 | +# packets in the announcement (Since 4.0) | ||
327 | +# | ||
328 | # @compress-level: compression level | ||
329 | # | ||
330 | # @compress-threads: compression thread count | ||
331 | @@ -XXX,XX +XXX,XX @@ | ||
332 | # Since: 2.4 | ||
333 | ## | ||
334 | { 'struct': 'MigrationParameters', | ||
335 | - 'data': { '*compress-level': 'uint8', | ||
336 | + 'data': { '*announce-initial': 'size', | ||
337 | + '*announce-max': 'size', | ||
338 | + '*announce-rounds': 'size', | ||
339 | + '*announce-step': 'size', | ||
340 | + '*compress-level': 'uint8', | ||
341 | '*compress-threads': 'uint8', | ||
342 | '*compress-wait-thread': 'bool', | ||
343 | '*decompress-threads': 'uint8', | ||
344 | -- | ||
345 | 2.5.0 | ||
346 | |||
347 | diff view generated by jsdifflib |
1 | From: Li Qiang <liq3ea@gmail.com> | 1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | The fcntl will change the flags directly, use qemu_set_nonblock() | 3 | Switch virtio's self announcement to use the AnnounceTimer. |
4 | instead. | 4 | It keeps it's own AnnounceTimer (per device), and starts running it |
5 | using a migration post-load and a virtual clock; that way the | ||
6 | announce happens once the guest is actually running. | ||
7 | The timer uses the migration parameters to set the timing of | ||
8 | the repeats. | ||
5 | 9 | ||
6 | Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> | 10 | Based on earlier patches by myself and |
7 | Acked-by: Michael S. Tsirkin <mst@redhat.com> | 11 | Vladislav Yasevich <vyasevic@redhat.com> |
8 | Signed-off-by: Li Qiang <liq3ea@gmail.com> | 12 | |
13 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | ||
14 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||
9 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 15 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
10 | --- | 16 | --- |
11 | net/tap.c | 10 +++++----- | 17 | hw/net/trace-events | 5 +++++ |
12 | 1 file changed, 5 insertions(+), 5 deletions(-) | 18 | hw/net/virtio-net.c | 36 +++++++++++++++++++++++------------- |
19 | include/hw/virtio/virtio-net.h | 4 ++-- | ||
20 | 3 files changed, 30 insertions(+), 15 deletions(-) | ||
13 | 21 | ||
14 | diff --git a/net/tap.c b/net/tap.c | 22 | diff --git a/hw/net/trace-events b/hw/net/trace-events |
15 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/net/tap.c | 24 | --- a/hw/net/trace-events |
17 | +++ b/net/tap.c | 25 | +++ b/hw/net/trace-events |
18 | @@ -XXX,XX +XXX,XX @@ int net_init_bridge(const Netdev *netdev, const char *name, | 26 | @@ -XXX,XX +XXX,XX @@ sunhme_rx_filter_reject(void) "rejecting incoming frame" |
19 | return -1; | 27 | sunhme_rx_filter_accept(void) "accepting incoming frame" |
28 | sunhme_rx_desc(uint32_t addr, int offset, uint32_t status, int len, int cr, int nr) "addr 0x%"PRIx32"(+0x%x) status 0x%"PRIx32 " len %d (ring %d/%d)" | ||
29 | sunhme_rx_xsum_calc(uint16_t xsum) "calculated incoming xsum as 0x%x" | ||
30 | + | ||
31 | +# hw/net/virtio-net.c | ||
32 | +virtio_net_announce_timer(int round) "%d" | ||
33 | +virtio_net_handle_announce(int round) "%d" | ||
34 | +virtio_net_post_load_device(void) | ||
35 | diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c | ||
36 | index XXXXXXX..XXXXXXX 100644 | ||
37 | --- a/hw/net/virtio-net.c | ||
38 | +++ b/hw/net/virtio-net.c | ||
39 | @@ -XXX,XX +XXX,XX @@ | ||
40 | #include "qemu/timer.h" | ||
41 | #include "hw/virtio/virtio-net.h" | ||
42 | #include "net/vhost_net.h" | ||
43 | +#include "net/announce.h" | ||
44 | #include "hw/virtio/virtio-bus.h" | ||
45 | #include "qapi/error.h" | ||
46 | #include "qapi/qapi-events-net.h" | ||
47 | #include "hw/virtio/virtio-access.h" | ||
48 | #include "migration/misc.h" | ||
49 | #include "standard-headers/linux/ethtool.h" | ||
50 | +#include "trace.h" | ||
51 | |||
52 | #define VIRTIO_NET_VM_VERSION 11 | ||
53 | |||
54 | @@ -XXX,XX +XXX,XX @@ static void virtio_net_announce_timer(void *opaque) | ||
55 | { | ||
56 | VirtIONet *n = opaque; | ||
57 | VirtIODevice *vdev = VIRTIO_DEVICE(n); | ||
58 | + trace_virtio_net_announce_timer(n->announce_timer.round); | ||
59 | |||
60 | - n->announce_counter--; | ||
61 | + n->announce_timer.round--; | ||
62 | n->status |= VIRTIO_NET_S_ANNOUNCE; | ||
63 | virtio_notify_config(vdev); | ||
64 | } | ||
65 | @@ -XXX,XX +XXX,XX @@ static void virtio_net_reset(VirtIODevice *vdev) | ||
66 | n->nobcast = 0; | ||
67 | /* multiqueue is disabled by default */ | ||
68 | n->curr_queues = 1; | ||
69 | - timer_del(n->announce_timer); | ||
70 | - n->announce_counter = 0; | ||
71 | + timer_del(n->announce_timer.tm); | ||
72 | + n->announce_timer.round = 0; | ||
73 | n->status &= ~VIRTIO_NET_S_ANNOUNCE; | ||
74 | |||
75 | /* Flush any MAC and VLAN filter table state */ | ||
76 | @@ -XXX,XX +XXX,XX @@ static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd, | ||
77 | static int virtio_net_handle_announce(VirtIONet *n, uint8_t cmd, | ||
78 | struct iovec *iov, unsigned int iov_cnt) | ||
79 | { | ||
80 | + trace_virtio_net_handle_announce(n->announce_timer.round); | ||
81 | if (cmd == VIRTIO_NET_CTRL_ANNOUNCE_ACK && | ||
82 | n->status & VIRTIO_NET_S_ANNOUNCE) { | ||
83 | n->status &= ~VIRTIO_NET_S_ANNOUNCE; | ||
84 | - if (n->announce_counter) { | ||
85 | - timer_mod(n->announce_timer, | ||
86 | - qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + | ||
87 | - self_announce_delay(n->announce_counter)); | ||
88 | + if (n->announce_timer.round) { | ||
89 | + qemu_announce_timer_step(&n->announce_timer); | ||
90 | } | ||
91 | return VIRTIO_NET_OK; | ||
92 | } else { | ||
93 | @@ -XXX,XX +XXX,XX @@ static int virtio_net_post_load_device(void *opaque, int version_id) | ||
94 | VirtIODevice *vdev = VIRTIO_DEVICE(n); | ||
95 | int i, link_down; | ||
96 | |||
97 | + trace_virtio_net_post_load_device(); | ||
98 | virtio_net_set_mrg_rx_bufs(n, n->mergeable_rx_bufs, | ||
99 | virtio_vdev_has_feature(vdev, | ||
100 | VIRTIO_F_VERSION_1)); | ||
101 | @@ -XXX,XX +XXX,XX @@ static int virtio_net_post_load_device(void *opaque, int version_id) | ||
102 | |||
103 | if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) && | ||
104 | virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { | ||
105 | - n->announce_counter = SELF_ANNOUNCE_ROUNDS; | ||
106 | - timer_mod(n->announce_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)); | ||
107 | + qemu_announce_timer_reset(&n->announce_timer, migrate_announce_params(), | ||
108 | + QEMU_CLOCK_VIRTUAL, | ||
109 | + virtio_net_announce_timer, n); | ||
110 | + if (n->announce_timer.round) { | ||
111 | + timer_mod(n->announce_timer.tm, | ||
112 | + qemu_clock_get_ms(n->announce_timer.type)); | ||
113 | + } else { | ||
114 | + qemu_announce_timer_del(&n->announce_timer); | ||
115 | + } | ||
20 | } | 116 | } |
21 | 117 | ||
22 | - fcntl(fd, F_SETFL, O_NONBLOCK); | 118 | return 0; |
23 | + qemu_set_nonblock(fd); | 119 | @@ -XXX,XX +XXX,XX @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) |
24 | vnet_hdr = tap_probe_vnet_hdr(fd); | 120 | qemu_macaddr_default_if_unset(&n->nic_conf.macaddr); |
25 | s = net_tap_fd_init(peer, "bridge", name, fd, vnet_hdr); | 121 | memcpy(&n->mac[0], &n->nic_conf.macaddr, sizeof(n->mac)); |
26 | 122 | n->status = VIRTIO_NET_S_LINK_UP; | |
27 | @@ -XXX,XX +XXX,XX @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, | 123 | - n->announce_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, |
28 | } | 124 | - virtio_net_announce_timer, n); |
29 | return; | 125 | + qemu_announce_timer_reset(&n->announce_timer, migrate_announce_params(), |
30 | } | 126 | + QEMU_CLOCK_VIRTUAL, |
31 | - fcntl(vhostfd, F_SETFL, O_NONBLOCK); | 127 | + virtio_net_announce_timer, n); |
32 | + qemu_set_nonblock(vhostfd); | 128 | |
33 | } | 129 | if (n->netclient_type) { |
34 | options.opaque = (void *)(uintptr_t)vhostfd; | 130 | /* |
35 | 131 | @@ -XXX,XX +XXX,XX @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) | |
36 | @@ -XXX,XX +XXX,XX @@ int net_init_tap(const Netdev *netdev, const char *name, | 132 | virtio_net_del_queue(n, i); |
37 | return -1; | 133 | } |
38 | } | 134 | |
39 | 135 | - timer_del(n->announce_timer); | |
40 | - fcntl(fd, F_SETFL, O_NONBLOCK); | 136 | - timer_free(n->announce_timer); |
41 | + qemu_set_nonblock(fd); | 137 | + qemu_announce_timer_del(&n->announce_timer); |
42 | 138 | g_free(n->vqs); | |
43 | vnet_hdr = tap_probe_vnet_hdr(fd); | 139 | qemu_del_nic(n->nic); |
44 | 140 | virtio_net_rsc_cleanup(n); | |
45 | @@ -XXX,XX +XXX,XX @@ int net_init_tap(const Netdev *netdev, const char *name, | 141 | diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h |
46 | goto free_fail; | 142 | index XXXXXXX..XXXXXXX 100644 |
47 | } | 143 | --- a/include/hw/virtio/virtio-net.h |
48 | 144 | +++ b/include/hw/virtio/virtio-net.h | |
49 | - fcntl(fd, F_SETFL, O_NONBLOCK); | 145 | @@ -XXX,XX +XXX,XX @@ |
50 | + qemu_set_nonblock(fd); | 146 | #include "qemu/units.h" |
51 | 147 | #include "standard-headers/linux/virtio_net.h" | |
52 | if (i == 0) { | 148 | #include "hw/virtio/virtio.h" |
53 | vnet_hdr = tap_probe_vnet_hdr(fd); | 149 | +#include "net/announce.h" |
54 | @@ -XXX,XX +XXX,XX @@ free_fail: | 150 | |
55 | return -1; | 151 | #define TYPE_VIRTIO_NET "virtio-net-device" |
56 | } | 152 | #define VIRTIO_NET(obj) \ |
57 | 153 | @@ -XXX,XX +XXX,XX @@ struct VirtIONet { | |
58 | - fcntl(fd, F_SETFL, O_NONBLOCK); | 154 | char *netclient_name; |
59 | + qemu_set_nonblock(fd); | 155 | char *netclient_type; |
60 | vnet_hdr = tap_probe_vnet_hdr(fd); | 156 | uint64_t curr_guest_offloads; |
61 | 157 | - QEMUTimer *announce_timer; | |
62 | net_init_tap_one(tap, peer, "bridge", name, ifname, | 158 | - int announce_counter; |
159 | + AnnounceTimer announce_timer; | ||
160 | bool needs_vnet_hdr_swap; | ||
161 | bool mtu_bypass_backend; | ||
162 | }; | ||
63 | -- | 163 | -- |
64 | 2.5.0 | 164 | 2.5.0 |
65 | 165 | ||
66 | 166 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | 1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> | |
2 | |||
3 | Switch the announcements to using the new announce timer. | ||
4 | Move the code that does it to announce.c rather than savevm | ||
5 | because it really has nothing to do with the actual migration. | ||
6 | |||
7 | Migration starts the announce from bh's and so they're all | ||
8 | in the main thread/bql, and so there's never any racing with | ||
9 | the timers themselves. | ||
10 | |||
11 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | ||
12 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||
13 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
14 | --- | ||
15 | include/migration/misc.h | 10 ------- | ||
16 | include/net/announce.h | 2 ++ | ||
17 | include/sysemu/sysemu.h | 2 -- | ||
18 | migration/migration.c | 2 +- | ||
19 | migration/migration.h | 4 +++ | ||
20 | migration/savevm.c | 72 ++---------------------------------------------- | ||
21 | migration/trace-events | 1 - | ||
22 | net/announce.c | 68 +++++++++++++++++++++++++++++++++++++++++++++ | ||
23 | net/trace-events | 3 ++ | ||
24 | 9 files changed, 81 insertions(+), 83 deletions(-) | ||
25 | |||
26 | diff --git a/include/migration/misc.h b/include/migration/misc.h | ||
27 | index XXXXXXX..XXXXXXX 100644 | ||
28 | --- a/include/migration/misc.h | ||
29 | +++ b/include/migration/misc.h | ||
30 | @@ -XXX,XX +XXX,XX @@ void blk_mig_init(void); | ||
31 | static inline void blk_mig_init(void) {} | ||
32 | #endif | ||
33 | |||
34 | -#define SELF_ANNOUNCE_ROUNDS 5 | ||
35 | - | ||
36 | -static inline | ||
37 | -int64_t self_announce_delay(int round) | ||
38 | -{ | ||
39 | - assert(round < SELF_ANNOUNCE_ROUNDS && round > 0); | ||
40 | - /* delay 50ms, 150ms, 250ms, ... */ | ||
41 | - return 50 + (SELF_ANNOUNCE_ROUNDS - round - 1) * 100; | ||
42 | -} | ||
43 | - | ||
44 | AnnounceParameters *migrate_announce_params(void); | ||
45 | /* migration/savevm.c */ | ||
46 | |||
47 | diff --git a/include/net/announce.h b/include/net/announce.h | ||
48 | index XXXXXXX..XXXXXXX 100644 | ||
49 | --- a/include/net/announce.h | ||
50 | +++ b/include/net/announce.h | ||
51 | @@ -XXX,XX +XXX,XX @@ void qemu_announce_timer_reset(AnnounceTimer *timer, | ||
52 | QEMUTimerCB *cb, | ||
53 | void *opaque); | ||
54 | |||
55 | +void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params); | ||
56 | + | ||
57 | #endif | ||
58 | diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h | ||
59 | index XXXXXXX..XXXXXXX 100644 | ||
60 | --- a/include/sysemu/sysemu.h | ||
61 | +++ b/include/sysemu/sysemu.h | ||
62 | @@ -XXX,XX +XXX,XX @@ extern bool machine_init_done; | ||
63 | void qemu_add_machine_init_done_notifier(Notifier *notify); | ||
64 | void qemu_remove_machine_init_done_notifier(Notifier *notify); | ||
65 | |||
66 | -void qemu_announce_self(void); | ||
67 | - | ||
68 | extern int autostart; | ||
69 | |||
70 | typedef enum { | ||
71 | diff --git a/migration/migration.c b/migration/migration.c | ||
72 | index XXXXXXX..XXXXXXX 100644 | ||
73 | --- a/migration/migration.c | ||
74 | +++ b/migration/migration.c | ||
75 | @@ -XXX,XX +XXX,XX @@ static void process_incoming_migration_bh(void *opaque) | ||
76 | * This must happen after all error conditions are dealt with and | ||
77 | * we're sure the VM is going to be running on this host. | ||
78 | */ | ||
79 | - qemu_announce_self(); | ||
80 | + qemu_announce_self(&mis->announce_timer, migrate_announce_params()); | ||
81 | |||
82 | if (multifd_load_cleanup(&local_err) != 0) { | ||
83 | error_report_err(local_err); | ||
84 | diff --git a/migration/migration.h b/migration/migration.h | ||
85 | index XXXXXXX..XXXXXXX 100644 | ||
86 | --- a/migration/migration.h | ||
87 | +++ b/migration/migration.h | ||
88 | @@ -XXX,XX +XXX,XX @@ | ||
89 | #include "qemu/coroutine_int.h" | ||
90 | #include "hw/qdev.h" | ||
91 | #include "io/channel.h" | ||
92 | +#include "net/announce.h" | ||
93 | |||
94 | struct PostcopyBlocktimeContext; | ||
95 | |||
96 | @@ -XXX,XX +XXX,XX @@ struct MigrationIncomingState { | ||
97 | */ | ||
98 | QemuEvent main_thread_load_event; | ||
99 | |||
100 | + /* For network announces */ | ||
101 | + AnnounceTimer announce_timer; | ||
102 | + | ||
103 | size_t largest_page_size; | ||
104 | bool have_fault_thread; | ||
105 | QemuThread fault_thread; | ||
106 | diff --git a/migration/savevm.c b/migration/savevm.c | ||
107 | index XXXXXXX..XXXXXXX 100644 | ||
108 | --- a/migration/savevm.c | ||
109 | +++ b/migration/savevm.c | ||
110 | @@ -XXX,XX +XXX,XX @@ | ||
111 | #include "sysemu/replay.h" | ||
112 | #include "qjson.h" | ||
113 | #include "migration/colo.h" | ||
114 | - | ||
115 | -#ifndef ETH_P_RARP | ||
116 | -#define ETH_P_RARP 0x8035 | ||
117 | -#endif | ||
118 | -#define ARP_HTYPE_ETH 0x0001 | ||
119 | -#define ARP_PTYPE_IP 0x0800 | ||
120 | -#define ARP_OP_REQUEST_REV 0x3 | ||
121 | +#include "net/announce.h" | ||
122 | |||
123 | const unsigned int postcopy_ram_discard_version = 0; | ||
124 | |||
125 | @@ -XXX,XX +XXX,XX @@ static struct mig_cmd_args { | ||
126 | * generic extendable format with an exception for two old entities. | ||
127 | */ | ||
128 | |||
129 | -static int announce_self_create(uint8_t *buf, | ||
130 | - uint8_t *mac_addr) | ||
131 | -{ | ||
132 | - /* Ethernet header. */ | ||
133 | - memset(buf, 0xff, 6); /* destination MAC addr */ | ||
134 | - memcpy(buf + 6, mac_addr, 6); /* source MAC addr */ | ||
135 | - *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */ | ||
136 | - | ||
137 | - /* RARP header. */ | ||
138 | - *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */ | ||
139 | - *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */ | ||
140 | - *(buf + 18) = 6; /* hardware addr length (ethernet) */ | ||
141 | - *(buf + 19) = 4; /* protocol addr length (IPv4) */ | ||
142 | - *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */ | ||
143 | - memcpy(buf + 22, mac_addr, 6); /* source hw addr */ | ||
144 | - memset(buf + 28, 0x00, 4); /* source protocol addr */ | ||
145 | - memcpy(buf + 32, mac_addr, 6); /* target hw addr */ | ||
146 | - memset(buf + 38, 0x00, 4); /* target protocol addr */ | ||
147 | - | ||
148 | - /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */ | ||
149 | - memset(buf + 42, 0x00, 18); | ||
150 | - | ||
151 | - return 60; /* len (FCS will be added by hardware) */ | ||
152 | -} | ||
153 | - | ||
154 | -static void qemu_announce_self_iter(NICState *nic, void *opaque) | ||
155 | -{ | ||
156 | - uint8_t buf[60]; | ||
157 | - int len; | ||
158 | - | ||
159 | - trace_qemu_announce_self_iter(qemu_ether_ntoa(&nic->conf->macaddr)); | ||
160 | - len = announce_self_create(buf, nic->conf->macaddr.a); | ||
161 | - | ||
162 | - qemu_send_packet_raw(qemu_get_queue(nic), buf, len); | ||
163 | -} | ||
164 | - | ||
165 | - | ||
166 | -static void qemu_announce_self_once(void *opaque) | ||
167 | -{ | ||
168 | - static int count = SELF_ANNOUNCE_ROUNDS; | ||
169 | - QEMUTimer *timer = *(QEMUTimer **)opaque; | ||
170 | - | ||
171 | - qemu_foreach_nic(qemu_announce_self_iter, NULL); | ||
172 | - | ||
173 | - if (--count) { | ||
174 | - /* delay 50ms, 150ms, 250ms, ... */ | ||
175 | - timer_mod(timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + | ||
176 | - self_announce_delay(count)); | ||
177 | - } else { | ||
178 | - timer_del(timer); | ||
179 | - timer_free(timer); | ||
180 | - } | ||
181 | -} | ||
182 | - | ||
183 | -void qemu_announce_self(void) | ||
184 | -{ | ||
185 | - static QEMUTimer *timer; | ||
186 | - timer = timer_new_ms(QEMU_CLOCK_REALTIME, qemu_announce_self_once, &timer); | ||
187 | - qemu_announce_self_once(&timer); | ||
188 | -} | ||
189 | - | ||
190 | /***********************************************************/ | ||
191 | /* savevm/loadvm support */ | ||
192 | |||
193 | @@ -XXX,XX +XXX,XX @@ static void loadvm_postcopy_handle_run_bh(void *opaque) | ||
194 | { | ||
195 | Error *local_err = NULL; | ||
196 | HandleRunBhData *data = opaque; | ||
197 | + MigrationIncomingState *mis = migration_incoming_get_current(); | ||
198 | |||
199 | /* TODO we should move all of this lot into postcopy_ram.c or a shared code | ||
200 | * in migration.c | ||
201 | */ | ||
202 | cpu_synchronize_all_post_init(); | ||
203 | |||
204 | - qemu_announce_self(); | ||
205 | + qemu_announce_self(&mis->announce_timer, migrate_announce_params()); | ||
206 | |||
207 | /* Make sure all file formats flush their mutable metadata. | ||
208 | * If we get an error here, just don't restart the VM yet. */ | ||
209 | diff --git a/migration/trace-events b/migration/trace-events | ||
210 | index XXXXXXX..XXXXXXX 100644 | ||
211 | --- a/migration/trace-events | ||
212 | +++ b/migration/trace-events | ||
213 | @@ -XXX,XX +XXX,XX @@ vmstate_save_state_top(const char *idstr) "%s" | ||
214 | vmstate_subsection_save_loop(const char *name, const char *sub) "%s/%s" | ||
215 | vmstate_subsection_save_top(const char *idstr) "%s" | ||
216 | vmstate_load(const char *idstr, const char *vmsd_name) "%s, %s" | ||
217 | -qemu_announce_self_iter(const char *mac) "%s" | ||
218 | |||
219 | # migration/vmstate.c | ||
220 | vmstate_load_field_error(const char *field, int ret) "field \"%s\" load failed, ret = %d" | ||
221 | diff --git a/net/announce.c b/net/announce.c | ||
222 | index XXXXXXX..XXXXXXX 100644 | ||
223 | --- a/net/announce.c | ||
224 | +++ b/net/announce.c | ||
225 | @@ -XXX,XX +XXX,XX @@ | ||
226 | #include "qemu/osdep.h" | ||
227 | #include "qemu-common.h" | ||
228 | #include "net/announce.h" | ||
229 | +#include "net/net.h" | ||
230 | #include "qapi/clone-visitor.h" | ||
231 | #include "qapi/qapi-visit-net.h" | ||
232 | +#include "trace.h" | ||
233 | |||
234 | int64_t qemu_announce_timer_step(AnnounceTimer *timer) | ||
235 | { | ||
236 | @@ -XXX,XX +XXX,XX @@ void qemu_announce_timer_reset(AnnounceTimer *timer, | ||
237 | timer->type = type; | ||
238 | timer->tm = timer_new_ms(type, cb, opaque); | ||
239 | } | ||
240 | + | ||
241 | +#ifndef ETH_P_RARP | ||
242 | +#define ETH_P_RARP 0x8035 | ||
243 | +#endif | ||
244 | +#define ARP_HTYPE_ETH 0x0001 | ||
245 | +#define ARP_PTYPE_IP 0x0800 | ||
246 | +#define ARP_OP_REQUEST_REV 0x3 | ||
247 | + | ||
248 | +static int announce_self_create(uint8_t *buf, | ||
249 | + uint8_t *mac_addr) | ||
250 | +{ | ||
251 | + /* Ethernet header. */ | ||
252 | + memset(buf, 0xff, 6); /* destination MAC addr */ | ||
253 | + memcpy(buf + 6, mac_addr, 6); /* source MAC addr */ | ||
254 | + *(uint16_t *)(buf + 12) = htons(ETH_P_RARP); /* ethertype */ | ||
255 | + | ||
256 | + /* RARP header. */ | ||
257 | + *(uint16_t *)(buf + 14) = htons(ARP_HTYPE_ETH); /* hardware addr space */ | ||
258 | + *(uint16_t *)(buf + 16) = htons(ARP_PTYPE_IP); /* protocol addr space */ | ||
259 | + *(buf + 18) = 6; /* hardware addr length (ethernet) */ | ||
260 | + *(buf + 19) = 4; /* protocol addr length (IPv4) */ | ||
261 | + *(uint16_t *)(buf + 20) = htons(ARP_OP_REQUEST_REV); /* opcode */ | ||
262 | + memcpy(buf + 22, mac_addr, 6); /* source hw addr */ | ||
263 | + memset(buf + 28, 0x00, 4); /* source protocol addr */ | ||
264 | + memcpy(buf + 32, mac_addr, 6); /* target hw addr */ | ||
265 | + memset(buf + 38, 0x00, 4); /* target protocol addr */ | ||
266 | + | ||
267 | + /* Padding to get up to 60 bytes (ethernet min packet size, minus FCS). */ | ||
268 | + memset(buf + 42, 0x00, 18); | ||
269 | + | ||
270 | + return 60; /* len (FCS will be added by hardware) */ | ||
271 | +} | ||
272 | + | ||
273 | +static void qemu_announce_self_iter(NICState *nic, void *opaque) | ||
274 | +{ | ||
275 | + uint8_t buf[60]; | ||
276 | + int len; | ||
277 | + | ||
278 | + trace_qemu_announce_self_iter(qemu_ether_ntoa(&nic->conf->macaddr)); | ||
279 | + len = announce_self_create(buf, nic->conf->macaddr.a); | ||
280 | + | ||
281 | + qemu_send_packet_raw(qemu_get_queue(nic), buf, len); | ||
282 | +} | ||
283 | +static void qemu_announce_self_once(void *opaque) | ||
284 | +{ | ||
285 | + AnnounceTimer *timer = (AnnounceTimer *)opaque; | ||
286 | + | ||
287 | + qemu_foreach_nic(qemu_announce_self_iter, NULL); | ||
288 | + | ||
289 | + if (--timer->round) { | ||
290 | + qemu_announce_timer_step(timer); | ||
291 | + } else { | ||
292 | + qemu_announce_timer_del(timer); | ||
293 | + } | ||
294 | +} | ||
295 | + | ||
296 | +void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params) | ||
297 | +{ | ||
298 | + qemu_announce_timer_reset(timer, params, QEMU_CLOCK_REALTIME, | ||
299 | + qemu_announce_self_once, timer); | ||
300 | + if (params->rounds) { | ||
301 | + qemu_announce_self_once(timer); | ||
302 | + } else { | ||
303 | + qemu_announce_timer_del(timer); | ||
304 | + } | ||
305 | +} | ||
306 | diff --git a/net/trace-events b/net/trace-events | ||
307 | index XXXXXXX..XXXXXXX 100644 | ||
308 | --- a/net/trace-events | ||
309 | +++ b/net/trace-events | ||
310 | @@ -XXX,XX +XXX,XX @@ | ||
311 | # See docs/devel/tracing.txt for syntax documentation. | ||
312 | |||
313 | +# net/announce.c | ||
314 | +qemu_announce_self_iter(const char *mac) "%s" | ||
315 | + | ||
316 | # net/vhost-user.c | ||
317 | vhost_user_event(const char *chr, int event) "chr: %s got event: %d" | ||
318 | |||
319 | -- | ||
320 | 2.5.0 | ||
321 | |||
322 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> | ||
1 | 2 | ||
3 | Some network devices have a capability to do self announcements | ||
4 | (ex: virtio-net). Add infrastructure that would allow devices | ||
5 | to expose this ability. | ||
6 | |||
7 | Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com> | ||
8 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | ||
9 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||
10 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
11 | --- | ||
12 | include/net/net.h | 2 ++ | ||
13 | net/announce.c | 5 +++++ | ||
14 | 2 files changed, 7 insertions(+) | ||
15 | |||
16 | diff --git a/include/net/net.h b/include/net/net.h | ||
17 | index XXXXXXX..XXXXXXX 100644 | ||
18 | --- a/include/net/net.h | ||
19 | +++ b/include/net/net.h | ||
20 | @@ -XXX,XX +XXX,XX @@ typedef int (SetVnetLE)(NetClientState *, bool); | ||
21 | typedef int (SetVnetBE)(NetClientState *, bool); | ||
22 | typedef struct SocketReadState SocketReadState; | ||
23 | typedef void (SocketReadStateFinalize)(SocketReadState *rs); | ||
24 | +typedef void (NetAnnounce)(NetClientState *); | ||
25 | |||
26 | typedef struct NetClientInfo { | ||
27 | NetClientDriver type; | ||
28 | @@ -XXX,XX +XXX,XX @@ typedef struct NetClientInfo { | ||
29 | SetVnetHdrLen *set_vnet_hdr_len; | ||
30 | SetVnetLE *set_vnet_le; | ||
31 | SetVnetBE *set_vnet_be; | ||
32 | + NetAnnounce *announce; | ||
33 | } NetClientInfo; | ||
34 | |||
35 | struct NetClientState { | ||
36 | diff --git a/net/announce.c b/net/announce.c | ||
37 | index XXXXXXX..XXXXXXX 100644 | ||
38 | --- a/net/announce.c | ||
39 | +++ b/net/announce.c | ||
40 | @@ -XXX,XX +XXX,XX @@ static void qemu_announce_self_iter(NICState *nic, void *opaque) | ||
41 | len = announce_self_create(buf, nic->conf->macaddr.a); | ||
42 | |||
43 | qemu_send_packet_raw(qemu_get_queue(nic), buf, len); | ||
44 | + | ||
45 | + /* if the NIC provides it's own announcement support, use it as well */ | ||
46 | + if (nic->ncs->info->announce) { | ||
47 | + nic->ncs->info->announce(nic->ncs); | ||
48 | + } | ||
49 | } | ||
50 | static void qemu_announce_self_once(void *opaque) | ||
51 | { | ||
52 | -- | ||
53 | 2.5.0 | ||
54 | |||
55 | diff view generated by jsdifflib |
1 | From: yuchenlin <yuchenlin@synology.com> | 1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Due to too early RCT0 interrput, win10x32 may hang on booting. | 3 | Expose the virtio-net self announcement capability and allow |
4 | This problem can be reproduced by doing power cycle on win10x32 guest. | 4 | qemu_announce_self() to call it. |
5 | In our environment, we have 10 win10x32 and stress power cycle. | ||
6 | The problem will happen about 20 rounds. | ||
7 | 5 | ||
8 | Below shows some log with comment: | 6 | These announces are caused by something external (i.e. the |
7 | announce-self command); they won't trigger if the migration | ||
8 | counter is triggering announces at the same time. | ||
9 | 9 | ||
10 | The normal case: | 10 | Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com> |
11 | 11 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | |
12 | 22831@1551928392.984687:e1000x_rx_disabled Received packet dropped | 12 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> |
13 | because receive is disabled RCTL = 0 | ||
14 | 22831@1551928392.985655:e1000x_rx_disabled Received packet dropped | ||
15 | because receive is disabled RCTL = 0 | ||
16 | 22831@1551928392.985801:e1000x_rx_disabled Received packet dropped | ||
17 | because receive is disabled RCTL = 0 | ||
18 | e1000: set_ics 0, ICR 0, IMR 0 | ||
19 | e1000: set_ics 0, ICR 0, IMR 0 | ||
20 | e1000: set_ics 0, ICR 0, IMR 0 | ||
21 | e1000: RCTL: 0, mac_reg[RCTL] = 0x0 | ||
22 | 22831@1551928393.056710:e1000x_rx_disabled Received packet dropped | ||
23 | because receive is disabled RCTL = 0 | ||
24 | e1000: set_ics 0, ICR 0, IMR 0 | ||
25 | e1000: ICR read: 0 | ||
26 | e1000: set_ics 0, ICR 0, IMR 0 | ||
27 | e1000: set_ics 0, ICR 0, IMR 0 | ||
28 | e1000: RCTL: 0, mac_reg[RCTL] = 0x0 | ||
29 | 22831@1551928393.077548:e1000x_rx_disabled Received packet dropped | ||
30 | because receive is disabled RCTL = 0 | ||
31 | e1000: set_ics 0, ICR 0, IMR 0 | ||
32 | e1000: ICR read: 0 | ||
33 | e1000: set_ics 2, ICR 0, IMR 0 | ||
34 | e1000: set_ics 2, ICR 2, IMR 0 | ||
35 | e1000: RCTL: 0, mac_reg[RCTL] = 0x0 | ||
36 | 22831@1551928393.102974:e1000x_rx_disabled Received packet dropped | ||
37 | because receive is disabled RCTL = 0 | ||
38 | 22831@1551928393.103267:e1000x_rx_disabled Received packet dropped | ||
39 | because receive is disabled RCTL = 0 | ||
40 | e1000: RCTL: 255, mac_reg[RCTL] = 0x40002 <- win10x32 says it can handle | ||
41 | RX now | ||
42 | e1000: set_ics 0, ICR 2, IMR 9d <- unmask interrupt | ||
43 | e1000: RCTL: 255, mac_reg[RCTL] = 0x48002 | ||
44 | e1000: set_ics 80, ICR 2, IMR 9d <- interrupt and work! | ||
45 | ... | ||
46 | |||
47 | The bad case: | ||
48 | |||
49 | 27744@1551930483.117766:e1000x_rx_disabled Received packet dropped | ||
50 | because receive is disabled RCTL = 0 | ||
51 | 27744@1551930483.118398:e1000x_rx_disabled Received packet dropped | ||
52 | because receive is disabled RCTL = 0 | ||
53 | e1000: set_ics 0, ICR 0, IMR 0 | ||
54 | e1000: set_ics 0, ICR 0, IMR 0 | ||
55 | e1000: set_ics 0, ICR 0, IMR 0 | ||
56 | e1000: RCTL: 0, mac_reg[RCTL] = 0x0 | ||
57 | 27744@1551930483.198063:e1000x_rx_disabled Received packet dropped | ||
58 | because receive is disabled RCTL = 0 | ||
59 | e1000: set_ics 0, ICR 0, IMR 0 | ||
60 | e1000: ICR read: 0 | ||
61 | e1000: set_ics 0, ICR 0, IMR 0 | ||
62 | e1000: set_ics 0, ICR 0, IMR 0 | ||
63 | e1000: RCTL: 0, mac_reg[RCTL] = 0x0 | ||
64 | 27744@1551930483.218675:e1000x_rx_disabled Received packet dropped | ||
65 | because receive is disabled RCTL = 0 | ||
66 | e1000: set_ics 0, ICR 0, IMR 0 | ||
67 | e1000: ICR read: 0 | ||
68 | e1000: set_ics 2, ICR 0, IMR 0 | ||
69 | e1000: set_ics 2, ICR 2, IMR 0 | ||
70 | e1000: RCTL: 0, mac_reg[RCTL] = 0x0 | ||
71 | 27744@1551930483.241768:e1000x_rx_disabled Received packet dropped | ||
72 | because receive is disabled RCTL = 0 | ||
73 | 27744@1551930483.241979:e1000x_rx_disabled Received packet dropped | ||
74 | because receive is disabled RCTL = 0 | ||
75 | e1000: RCTL: 255, mac_reg[RCTL] = 0x40002 <- win10x32 says it can handle | ||
76 | RX now | ||
77 | e1000: set_ics 80, ICR 2, IMR 0 <- flush queue (caused by setting RCTL) | ||
78 | e1000: set_ics 0, ICR 82, IMR 9d <- unmask interrupt and because 0x82&0x9d | ||
79 | != 0 generate interrupt, hang on here... | ||
80 | |||
81 | To workaround this problem, simply delay flush queue. Also stop receiving | ||
82 | when timer is going to run. | ||
83 | |||
84 | Tested on CentOS, Win7SP1x64 and Win10x32. | ||
85 | |||
86 | Signed-off-by: yuchenlin <yuchenlin@synology.com> | ||
87 | Reviewed-by: Dmitry Fleytman <dmitry.fleytman@gmail.com> | ||
88 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 13 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
89 | --- | 14 | --- |
90 | hw/net/e1000.c | 24 ++++++++++++++++++++++-- | 15 | hw/net/trace-events | 1 + |
91 | 1 file changed, 22 insertions(+), 2 deletions(-) | 16 | hw/net/virtio-net.c | 35 ++++++++++++++++++++++++++++++++--- |
17 | 2 files changed, 33 insertions(+), 3 deletions(-) | ||
92 | 18 | ||
93 | diff --git a/hw/net/e1000.c b/hw/net/e1000.c | 19 | diff --git a/hw/net/trace-events b/hw/net/trace-events |
94 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
95 | --- a/hw/net/e1000.c | 21 | --- a/hw/net/trace-events |
96 | +++ b/hw/net/e1000.c | 22 | +++ b/hw/net/trace-events |
97 | @@ -XXX,XX +XXX,XX @@ typedef struct E1000State_st { | 23 | @@ -XXX,XX +XXX,XX @@ sunhme_rx_desc(uint32_t addr, int offset, uint32_t status, int len, int cr, int |
98 | bool mit_irq_level; /* Tracks interrupt pin level. */ | 24 | sunhme_rx_xsum_calc(uint16_t xsum) "calculated incoming xsum as 0x%x" |
99 | uint32_t mit_ide; /* Tracks E1000_TXD_CMD_IDE bit. */ | 25 | |
100 | 26 | # hw/net/virtio-net.c | |
101 | + QEMUTimer *flush_queue_timer; | 27 | +virtio_net_announce_notify(void) "" |
28 | virtio_net_announce_timer(int round) "%d" | ||
29 | virtio_net_handle_announce(int round) "%d" | ||
30 | virtio_net_post_load_device(void) | ||
31 | diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c | ||
32 | index XXXXXXX..XXXXXXX 100644 | ||
33 | --- a/hw/net/virtio-net.c | ||
34 | +++ b/hw/net/virtio-net.c | ||
35 | @@ -XXX,XX +XXX,XX @@ static bool virtio_net_started(VirtIONet *n, uint8_t status) | ||
36 | (n->status & VIRTIO_NET_S_LINK_UP) && vdev->vm_running; | ||
37 | } | ||
38 | |||
39 | +static void virtio_net_announce_notify(VirtIONet *net) | ||
40 | +{ | ||
41 | + VirtIODevice *vdev = VIRTIO_DEVICE(net); | ||
42 | + trace_virtio_net_announce_notify(); | ||
102 | + | 43 | + |
103 | /* Compatibility flags for migration to/from qemu 1.3.0 and older */ | 44 | + net->status |= VIRTIO_NET_S_ANNOUNCE; |
104 | #define E1000_FLAG_AUTONEG_BIT 0 | 45 | + virtio_notify_config(vdev); |
105 | #define E1000_FLAG_MIT_BIT 1 | ||
106 | @@ -XXX,XX +XXX,XX @@ static void e1000_reset(void *opaque) | ||
107 | |||
108 | timer_del(d->autoneg_timer); | ||
109 | timer_del(d->mit_timer); | ||
110 | + timer_del(d->flush_queue_timer); | ||
111 | d->mit_timer_on = 0; | ||
112 | d->mit_irq_level = 0; | ||
113 | d->mit_ide = 0; | ||
114 | @@ -XXX,XX +XXX,XX @@ set_ctrl(E1000State *s, int index, uint32_t val) | ||
115 | } | ||
116 | |||
117 | static void | ||
118 | +e1000_flush_queue_timer(void *opaque) | ||
119 | +{ | ||
120 | + E1000State *s = opaque; | ||
121 | + | ||
122 | + qemu_flush_queued_packets(qemu_get_queue(s->nic)); | ||
123 | +} | 46 | +} |
124 | + | 47 | + |
125 | +static void | 48 | static void virtio_net_announce_timer(void *opaque) |
126 | set_rx_control(E1000State *s, int index, uint32_t val) | ||
127 | { | 49 | { |
128 | s->mac_reg[RCTL] = val; | 50 | VirtIONet *n = opaque; |
129 | @@ -XXX,XX +XXX,XX @@ set_rx_control(E1000State *s, int index, uint32_t val) | 51 | - VirtIODevice *vdev = VIRTIO_DEVICE(n); |
130 | s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1; | 52 | trace_virtio_net_announce_timer(n->announce_timer.round); |
131 | DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT], | 53 | |
132 | s->mac_reg[RCTL]); | 54 | n->announce_timer.round--; |
133 | - qemu_flush_queued_packets(qemu_get_queue(s->nic)); | 55 | - n->status |= VIRTIO_NET_S_ANNOUNCE; |
134 | + timer_mod(s->flush_queue_timer, | 56 | - virtio_notify_config(vdev); |
135 | + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000); | 57 | + virtio_net_announce_notify(n); |
136 | } | 58 | +} |
137 | 59 | + | |
138 | static void | 60 | +static void virtio_net_announce(NetClientState *nc) |
139 | @@ -XXX,XX +XXX,XX @@ e1000_can_receive(NetClientState *nc) | 61 | +{ |
140 | E1000State *s = qemu_get_nic_opaque(nc); | 62 | + VirtIONet *n = qemu_get_nic_opaque(nc); |
141 | 63 | + VirtIODevice *vdev = VIRTIO_DEVICE(n); | |
142 | return e1000x_rx_ready(&s->parent_obj, s->mac_reg) && | 64 | + |
143 | - e1000_has_rxbufs(s, 1); | 65 | + /* |
144 | + e1000_has_rxbufs(s, 1) && !timer_pending(s->flush_queue_timer); | 66 | + * Make sure the virtio migration announcement timer isn't running |
145 | } | 67 | + * If it is, let it trigger announcement so that we do not cause |
146 | 68 | + * confusion. | |
147 | static uint64_t rx_desc_base(E1000State *s) | 69 | + */ |
148 | @@ -XXX,XX +XXX,XX @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) | 70 | + if (n->announce_timer.round) { |
149 | return -1; | 71 | + return; |
150 | } | ||
151 | |||
152 | + if (timer_pending(s->flush_queue_timer)) { | ||
153 | + return 0; | ||
154 | + } | 72 | + } |
155 | + | 73 | + |
156 | /* Pad to minimum Ethernet frame length */ | 74 | + if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) && |
157 | if (size < sizeof(min_buf)) { | 75 | + virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { |
158 | iov_to_buf(iov, iovcnt, 0, min_buf, size); | 76 | + virtio_net_announce_notify(n); |
159 | @@ -XXX,XX +XXX,XX @@ pci_e1000_uninit(PCIDevice *dev) | 77 | + } |
160 | timer_free(d->autoneg_timer); | ||
161 | timer_del(d->mit_timer); | ||
162 | timer_free(d->mit_timer); | ||
163 | + timer_del(d->flush_queue_timer); | ||
164 | + timer_free(d->flush_queue_timer); | ||
165 | qemu_del_nic(d->nic); | ||
166 | } | 78 | } |
167 | 79 | ||
168 | @@ -XXX,XX +XXX,XX @@ static void pci_e1000_realize(PCIDevice *pci_dev, Error **errp) | 80 | static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) |
169 | 81 | @@ -XXX,XX +XXX,XX @@ static NetClientInfo net_virtio_info = { | |
170 | d->autoneg_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, e1000_autoneg_timer, d); | 82 | .receive = virtio_net_receive, |
171 | d->mit_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, e1000_mit_timer, d); | 83 | .link_status_changed = virtio_net_set_link_status, |
172 | + d->flush_queue_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, | 84 | .query_rx_filter = virtio_net_query_rxfilter, |
173 | + e1000_flush_queue_timer, d); | 85 | + .announce = virtio_net_announce, |
174 | } | 86 | }; |
175 | 87 | ||
176 | static void qdev_e1000_reset(DeviceState *dev) | 88 | static bool virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx) |
89 | @@ -XXX,XX +XXX,XX @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) | ||
90 | qemu_announce_timer_reset(&n->announce_timer, migrate_announce_params(), | ||
91 | QEMU_CLOCK_VIRTUAL, | ||
92 | virtio_net_announce_timer, n); | ||
93 | + n->announce_timer.round = 0; | ||
94 | |||
95 | if (n->netclient_type) { | ||
96 | /* | ||
177 | -- | 97 | -- |
178 | 2.5.0 | 98 | 2.5.0 |
179 | 99 | ||
180 | 100 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> | ||
1 | 2 | ||
3 | Add a qmp command that can trigger guest announcements. | ||
4 | |||
5 | It uses its own announce-timer instance, and parameters | ||
6 | passed to it explicitly in the command. | ||
7 | |||
8 | Like most qmp commands, it's in the main thread/bql, so | ||
9 | there's no racing with any outstanding timer. | ||
10 | |||
11 | Based on work of Germano Veit Michel <germano@redhat.com> and | ||
12 | Vladislav Yasevich <vyasevic@redhat.com> | ||
13 | |||
14 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | ||
15 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||
16 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
17 | --- | ||
18 | net/announce.c | 7 +++++++ | ||
19 | qapi/net.json | 20 ++++++++++++++++++++ | ||
20 | 2 files changed, 27 insertions(+) | ||
21 | |||
22 | diff --git a/net/announce.c b/net/announce.c | ||
23 | index XXXXXXX..XXXXXXX 100644 | ||
24 | --- a/net/announce.c | ||
25 | +++ b/net/announce.c | ||
26 | @@ -XXX,XX +XXX,XX @@ | ||
27 | #include "net/net.h" | ||
28 | #include "qapi/clone-visitor.h" | ||
29 | #include "qapi/qapi-visit-net.h" | ||
30 | +#include "qapi/qapi-commands-net.h" | ||
31 | #include "trace.h" | ||
32 | |||
33 | int64_t qemu_announce_timer_step(AnnounceTimer *timer) | ||
34 | @@ -XXX,XX +XXX,XX @@ void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params) | ||
35 | qemu_announce_timer_del(timer); | ||
36 | } | ||
37 | } | ||
38 | + | ||
39 | +void qmp_announce_self(AnnounceParameters *params, Error **errp) | ||
40 | +{ | ||
41 | + static AnnounceTimer announce_timer; | ||
42 | + qemu_announce_self(&announce_timer, params); | ||
43 | +} | ||
44 | diff --git a/qapi/net.json b/qapi/net.json | ||
45 | index XXXXXXX..XXXXXXX 100644 | ||
46 | --- a/qapi/net.json | ||
47 | +++ b/qapi/net.json | ||
48 | @@ -XXX,XX +XXX,XX @@ | ||
49 | 'max': 'int', | ||
50 | 'rounds': 'int', | ||
51 | 'step': 'int' } } | ||
52 | + | ||
53 | +## | ||
54 | +# @announce-self: | ||
55 | +# | ||
56 | +# Trigger generation of broadcast RARP frames to update network switches. | ||
57 | +# This can be useful when network bonds fail-over the active slave. | ||
58 | +# | ||
59 | +# @params: AnnounceParameters giving timing and repetition count of announce | ||
60 | +# | ||
61 | +# Example: | ||
62 | +# | ||
63 | +# -> { "execute": "announce-self" | ||
64 | +# "arguments": { | ||
65 | +# "initial": 50, "max": 550, "rounds": 10, "step": 50 } } | ||
66 | +# <- { "return": {} } | ||
67 | +# | ||
68 | +# Since: 4.0 | ||
69 | +## | ||
70 | +{ 'command': 'announce-self', 'boxed': true, | ||
71 | + 'data' : 'AnnounceParameters'} | ||
72 | -- | ||
73 | 2.5.0 | ||
74 | |||
75 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> | ||
1 | 2 | ||
3 | Add an HMP command to trigger self annocements. | ||
4 | Unlike the QMP command (which takes a set of parameters), the HMP | ||
5 | command reuses the set of parameters used for migration. | ||
6 | |||
7 | Signend-off-by: Vladislav Yasevich <vyasevic@redhat.com> | ||
8 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | ||
9 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | ||
10 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
11 | --- | ||
12 | hmp-commands.hx | 16 ++++++++++++++++ | ||
13 | hmp.c | 5 +++++ | ||
14 | hmp.h | 1 + | ||
15 | tests/test-hmp.c | 1 + | ||
16 | 4 files changed, 23 insertions(+) | ||
17 | |||
18 | diff --git a/hmp-commands.hx b/hmp-commands.hx | ||
19 | index XXXXXXX..XXXXXXX 100644 | ||
20 | --- a/hmp-commands.hx | ||
21 | +++ b/hmp-commands.hx | ||
22 | @@ -XXX,XX +XXX,XX @@ stops because the size limit is reached. | ||
23 | ETEXI | ||
24 | |||
25 | { | ||
26 | + .name = "announce_self", | ||
27 | + .args_type = "", | ||
28 | + .params = "", | ||
29 | + .help = "Trigger GARP/RARP announcements", | ||
30 | + .cmd = hmp_announce_self, | ||
31 | + }, | ||
32 | + | ||
33 | +STEXI | ||
34 | +@item announce_self | ||
35 | +@findex announce_self | ||
36 | +Trigger a round of GARP/RARP broadcasts; this is useful for explicitly updating the | ||
37 | +network infrastructure after a reconfiguration or some forms of migration. | ||
38 | +The timings of the round are set by the migration announce parameters. | ||
39 | +ETEXI | ||
40 | + | ||
41 | + { | ||
42 | .name = "migrate", | ||
43 | .args_type = "detach:-d,blk:-b,inc:-i,resume:-r,uri:s", | ||
44 | .params = "[-d] [-b] [-i] [-r] uri", | ||
45 | diff --git a/hmp.c b/hmp.c | ||
46 | index XXXXXXX..XXXXXXX 100644 | ||
47 | --- a/hmp.c | ||
48 | +++ b/hmp.c | ||
49 | @@ -XXX,XX +XXX,XX @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict) | ||
50 | |||
51 | } | ||
52 | |||
53 | +void hmp_announce_self(Monitor *mon, const QDict *qdict) | ||
54 | +{ | ||
55 | + qmp_announce_self(migrate_announce_params(), NULL); | ||
56 | +} | ||
57 | + | ||
58 | void hmp_migrate_cancel(Monitor *mon, const QDict *qdict) | ||
59 | { | ||
60 | qmp_migrate_cancel(NULL); | ||
61 | diff --git a/hmp.h b/hmp.h | ||
62 | index XXXXXXX..XXXXXXX 100644 | ||
63 | --- a/hmp.h | ||
64 | +++ b/hmp.h | ||
65 | @@ -XXX,XX +XXX,XX @@ void hmp_sync_profile(Monitor *mon, const QDict *qdict); | ||
66 | void hmp_system_reset(Monitor *mon, const QDict *qdict); | ||
67 | void hmp_system_powerdown(Monitor *mon, const QDict *qdict); | ||
68 | void hmp_exit_preconfig(Monitor *mon, const QDict *qdict); | ||
69 | +void hmp_announce_self(Monitor *mon, const QDict *qdict); | ||
70 | void hmp_cpu(Monitor *mon, const QDict *qdict); | ||
71 | void hmp_memsave(Monitor *mon, const QDict *qdict); | ||
72 | void hmp_pmemsave(Monitor *mon, const QDict *qdict); | ||
73 | diff --git a/tests/test-hmp.c b/tests/test-hmp.c | ||
74 | index XXXXXXX..XXXXXXX 100644 | ||
75 | --- a/tests/test-hmp.c | ||
76 | +++ b/tests/test-hmp.c | ||
77 | @@ -XXX,XX +XXX,XX @@ | ||
78 | static int verbose; | ||
79 | |||
80 | static const char *hmp_cmds[] = { | ||
81 | + "announce_self", | ||
82 | "boot_set ndc", | ||
83 | "chardev-add null,id=testchardev1", | ||
84 | "chardev-send-break testchardev1", | ||
85 | -- | ||
86 | 2.5.0 | ||
87 | |||
88 | diff view generated by jsdifflib |
1 | From: Marc-André Lureau <marcandre.lureau@redhat.com> | 1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | -net socket has a fd argument, and may be passed pre-opened sockets. | 3 | We now expose qemu_announce_self through QMP and HMP. Add a test |
4 | with some very basic packet validation (make sure we get a RARP). | ||
4 | 5 | ||
5 | TCP sockets use framing. | 6 | Signed-off-by: Vlad Yasevich <vyasevic@redhat.com> |
6 | UDP sockets have datagram boundaries. | 7 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> |
7 | 8 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> | |
8 | When given a unix dgram socket, it will be able to read from it, but | ||
9 | will attempt to send on the dgram_dst, which is unset. The other end | ||
10 | will not receive the data. | ||
11 | |||
12 | Let's teach -net socket to recognize a UNIX DGRAM socket, and use the | ||
13 | regular send() command (without dgram_dst). | ||
14 | |||
15 | This makes running slirp out-of-process possible that | ||
16 | way (python pseudo-code): | ||
17 | |||
18 | a, b = socket.socketpair(socket.AF_UNIX, socket.SOCK_DGRAM) | ||
19 | |||
20 | subprocess.Popen('qemu -net socket,fd=%d -net user' % a.fileno(), shell=True) | ||
21 | subprocess.Popen('qemu ... -net nic -net socket,fd=%d' % b.fileno(), shell=True) | ||
22 | |||
23 | Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> | ||
24 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 9 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
25 | --- | 10 | --- |
26 | net/socket.c | 25 +++++++++++++++++++++---- | 11 | tests/Makefile.include | 3 ++ |
27 | 1 file changed, 21 insertions(+), 4 deletions(-) | 12 | tests/test-announce-self.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++ |
13 | 2 files changed, 85 insertions(+) | ||
14 | create mode 100644 tests/test-announce-self.c | ||
28 | 15 | ||
29 | diff --git a/net/socket.c b/net/socket.c | 16 | diff --git a/tests/Makefile.include b/tests/Makefile.include |
30 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
31 | --- a/net/socket.c | 18 | --- a/tests/Makefile.include |
32 | +++ b/net/socket.c | 19 | +++ b/tests/Makefile.include |
33 | @@ -XXX,XX +XXX,XX @@ static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, | 20 | @@ -XXX,XX +XXX,XX @@ check-qtest-i386-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF) |
34 | ssize_t ret; | 21 | check-qtest-i386-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF) |
35 | 22 | check-qtest-i386-$(CONFIG_RTL8139_PCI) += tests/test-filter-redirector$(EXESUF) | |
36 | do { | 23 | check-qtest-i386-y += tests/migration-test$(EXESUF) |
37 | - ret = qemu_sendto(s->fd, buf, size, 0, | 24 | +check-qtest-i386-y += tests/test-announce-self$(EXESUF) |
38 | - (struct sockaddr *)&s->dgram_dst, | 25 | check-qtest-i386-y += tests/test-x86-cpuid-compat$(EXESUF) |
39 | - sizeof(s->dgram_dst)); | 26 | check-qtest-i386-y += tests/numa-test$(EXESUF) |
40 | + if (s->dgram_dst.sin_family != AF_UNIX) { | 27 | check-qtest-x86_64-y += $(check-qtest-i386-y) |
41 | + ret = qemu_sendto(s->fd, buf, size, 0, | 28 | @@ -XXX,XX +XXX,XX @@ check-qtest-ppc64-$(CONFIG_PSERIES) += tests/spapr-phb-test$(EXESUF) |
42 | + (struct sockaddr *)&s->dgram_dst, | 29 | check-qtest-ppc64-$(CONFIG_PSERIES) += tests/device-plug-test$(EXESUF) |
43 | + sizeof(s->dgram_dst)); | 30 | check-qtest-ppc64-$(CONFIG_POWERNV) += tests/pnv-xscom-test$(EXESUF) |
44 | + } else { | 31 | check-qtest-ppc64-y += tests/migration-test$(EXESUF) |
45 | + ret = send(s->fd, buf, size, 0); | 32 | +check-qtest-ppc64-y += tests/test-announce-self$(EXESUF) |
46 | + } | 33 | check-qtest-ppc64-$(CONFIG_PSERIES) += tests/rtas-test$(EXESUF) |
47 | } while (ret == -1 && errno == EINTR); | 34 | check-qtest-ppc64-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF) |
48 | 35 | check-qtest-ppc64-$(CONFIG_USB_OHCI) += tests/usb-hcd-ohci-test$(EXESUF) | |
49 | if (ret == -1 && errno == EAGAIN) { | 36 | @@ -XXX,XX +XXX,XX @@ tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-usb-obj-y) |
50 | @@ -XXX,XX +XXX,XX @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer, | 37 | tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y) |
51 | int newfd; | 38 | tests/cpu-plug-test$(EXESUF): tests/cpu-plug-test.o |
52 | NetClientState *nc; | 39 | tests/migration-test$(EXESUF): tests/migration-test.o |
53 | NetSocketState *s; | 40 | +tests/test-announce-self$(EXESUF): tests/test-announce-self.o |
54 | + SocketAddress *sa; | 41 | tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o $(test-util-obj-y) \ |
55 | + SocketAddressType sa_type; | 42 | $(qtest-obj-y) $(test-io-obj-y) $(libqos-virtio-obj-y) $(libqos-pc-obj-y) \ |
43 | $(chardev-obj-y) | ||
44 | diff --git a/tests/test-announce-self.c b/tests/test-announce-self.c | ||
45 | new file mode 100644 | ||
46 | index XXXXXXX..XXXXXXX | ||
47 | --- /dev/null | ||
48 | +++ b/tests/test-announce-self.c | ||
49 | @@ -XXX,XX +XXX,XX @@ | ||
50 | +/* | ||
51 | + * QTest testcase for qemu_announce_self | ||
52 | + * | ||
53 | + * Copyright (c) 2017 Red hat, Inc. | ||
54 | + * Copyright (c) 2014 SUSE LINUX Products GmbH | ||
55 | + * | ||
56 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||
57 | + * See the COPYING file in the top-level directory. | ||
58 | + */ | ||
56 | + | 59 | + |
57 | + sa = socket_local_address(fd, errp); | 60 | +#include "qemu/osdep.h" |
58 | + if (!sa) { | 61 | +#include "libqtest.h" |
59 | + return NULL; | 62 | +#include "qapi/qmp/qdict.h" |
60 | + } | 63 | +#include "qemu-common.h" |
61 | + sa_type = sa->type; | 64 | +#include "qemu/sockets.h" |
62 | + qapi_free_SocketAddress(sa); | 65 | +#include "qemu/iov.h" |
63 | 66 | +#include "libqos/libqos-pc.h" | |
64 | /* fd passed: multicast: "learn" dgram_dst address from bound address and save it | 67 | +#include "libqos/libqos-spapr.h" |
65 | * Because this may be "shared" socket from a "master" process, datagrams would be recv() | ||
66 | @@ -XXX,XX +XXX,XX @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer, | ||
67 | "socket: fd=%d (cloned mcast=%s:%d)", | ||
68 | fd, inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); | ||
69 | } else { | ||
70 | + if (sa_type == SOCKET_ADDRESS_TYPE_UNIX) { | ||
71 | + s->dgram_dst.sin_family = AF_UNIX; | ||
72 | + } | ||
73 | + | 68 | + |
74 | snprintf(nc->info_str, sizeof(nc->info_str), | 69 | +#ifndef ETH_P_RARP |
75 | - "socket: fd=%d", fd); | 70 | +#define ETH_P_RARP 0x8035 |
76 | + "socket: fd=%d %s", fd, SocketAddressType_str(sa_type)); | 71 | +#endif |
77 | } | 72 | + |
78 | 73 | +static QTestState *test_init(int socket) | |
79 | return s; | 74 | +{ |
75 | + char *args; | ||
76 | + | ||
77 | + args = g_strdup_printf("-netdev socket,fd=%d,id=hs0 -device " | ||
78 | + "virtio-net-pci,netdev=hs0", socket); | ||
79 | + | ||
80 | + return qtest_start(args); | ||
81 | +} | ||
82 | + | ||
83 | + | ||
84 | +static void test_announce(int socket) | ||
85 | +{ | ||
86 | + char buffer[60]; | ||
87 | + int len; | ||
88 | + QDict *rsp; | ||
89 | + int ret; | ||
90 | + uint16_t *proto = (uint16_t *)&buffer[12]; | ||
91 | + | ||
92 | + rsp = qmp("{ 'execute' : 'announce-self', " | ||
93 | + " 'arguments': {" | ||
94 | + " 'initial': 50, 'max': 550," | ||
95 | + " 'rounds': 10, 'step': 50 } }"); | ||
96 | + assert(!qdict_haskey(rsp, "error")); | ||
97 | + qobject_unref(rsp); | ||
98 | + | ||
99 | + /* Catch the packet and make sure it's a RARP */ | ||
100 | + ret = qemu_recv(socket, &len, sizeof(len), 0); | ||
101 | + g_assert_cmpint(ret, ==, sizeof(len)); | ||
102 | + len = ntohl(len); | ||
103 | + | ||
104 | + ret = qemu_recv(socket, buffer, len, 0); | ||
105 | + g_assert_cmpint(*proto, ==, htons(ETH_P_RARP)); | ||
106 | +} | ||
107 | + | ||
108 | +static void setup(gconstpointer data) | ||
109 | +{ | ||
110 | + QTestState *qs; | ||
111 | + void (*func) (int socket) = data; | ||
112 | + int sv[2], ret; | ||
113 | + | ||
114 | + ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sv); | ||
115 | + g_assert_cmpint(ret, !=, -1); | ||
116 | + | ||
117 | + qs = test_init(sv[1]); | ||
118 | + func(sv[0]); | ||
119 | + | ||
120 | + /* End test */ | ||
121 | + close(sv[0]); | ||
122 | + qtest_quit(qs); | ||
123 | +} | ||
124 | + | ||
125 | +int main(int argc, char **argv) | ||
126 | +{ | ||
127 | + g_test_init(&argc, &argv, NULL); | ||
128 | + qtest_add_data_func("/virtio/net/test_announce_self", test_announce, setup); | ||
129 | + | ||
130 | + return g_test_run(); | ||
131 | +} | ||
80 | -- | 132 | -- |
81 | 2.5.0 | 133 | 2.5.0 |
82 | 134 | ||
83 | 135 | diff view generated by jsdifflib |