1 | The following changes since commit f4abdf32714d1845b7c01ec136dd2b04c2f7db47: | 1 | The following changes since commit b6179aaff961627fcb59d7b234297966b81ac726: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-docs-xen-updates-100321-2' into staging (2021-03-11 16:20:58 +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 9bdb56367679e68e5e71a1c29a1087bda6414b25: | 9 | for you to fetch changes up to 4b9b70000218640a42c3ea908a12665e5840b6cd: |
10 | 10 | ||
11 | pvrdma: wean code off pvrdma_ring.h kernel header (2021-03-12 14:08:31 +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 | Alexander Bulekov (4): | 19 | Dr. David Alan Gilbert (9): |
17 | rtl8139: switch to use qemu_receive_packet() for loopback | 20 | net: Introduce announce timer |
18 | pcnet: switch to use qemu_receive_packet() for loopback | 21 | migration: Add announce parameters |
19 | cadence_gem: switch to use qemu_receive_packet() for loopback | 22 | virtio-net: Switch to using announce timer |
20 | lan9118: switch to use qemu_receive_packet() for loopback | 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 | ||
21 | 29 | ||
22 | Bin Meng (1): | 30 | Vincenzo Maffione (3): |
23 | net: Fix build error when DEBUG_NET is on | 31 | net: netmap: small improvements netmap_send() |
32 | net: netmap: simplify netmap_receive() | ||
33 | net: netmap: improve netmap_receive_iov() | ||
24 | 34 | ||
25 | Cornelia Huck (1): | 35 | Zhang Chen (1): |
26 | pvrdma: wean code off pvrdma_ring.h kernel header | 36 | net/colo-compare.c: Remove duplicated code |
27 | 37 | ||
28 | Jason Wang (9): | 38 | hmp-commands.hx | 16 +++++ |
29 | virtio-net: calculating proper msix vectors on init | 39 | hmp.c | 33 ++++++++++ |
30 | net: unbreak well-form id check for "-nic" | 40 | hmp.h | 1 + |
31 | e1000: fail early for evil descriptor | 41 | hw/net/trace-events | 6 ++ |
32 | net: introduce qemu_receive_packet() | 42 | hw/net/virtio-net.c | 69 +++++++++++++++----- |
33 | e1000: switch to use qemu_receive_packet() for loopback | 43 | include/hw/virtio/virtio-net.h | 4 +- |
34 | dp8393x: switch to use qemu_receive_packet() for loopback packet | 44 | include/migration/misc.h | 12 +--- |
35 | msf2-mac: switch to use qemu_receive_packet() for loopback | 45 | include/net/announce.h | 41 ++++++++++++ |
36 | sungem: switch to use qemu_receive_packet() for loopback | 46 | include/net/net.h | 2 + |
37 | tx_pkt: switch to use qemu_receive_packet_iov() for loopback | 47 | include/qemu/typedefs.h | 1 + |
38 | 48 | include/sysemu/sysemu.h | 2 - | |
39 | Paolo Bonzini (1): | 49 | migration/migration.c | 103 +++++++++++++++++++++++++++++- |
40 | net: validate that ids are well formed | 50 | migration/migration.h | 4 ++ |
41 | 51 | migration/savevm.c | 72 +-------------------- | |
42 | hw/core/machine.c | 1 + | 52 | migration/trace-events | 1 - |
43 | hw/net/cadence_gem.c | 4 +- | 53 | net/Makefile.objs | 1 + |
44 | hw/net/dp8393x.c | 2 +- | 54 | net/announce.c | 140 +++++++++++++++++++++++++++++++++++++++++ |
45 | hw/net/e1000.c | 6 +- | 55 | net/colo-compare.c | 8 --- |
46 | hw/net/lan9118.c | 2 +- | 56 | net/netmap.c | 110 ++++++++++++++------------------ |
47 | hw/net/msf2-emac.c | 2 +- | 57 | net/trace-events | 3 + |
48 | hw/net/net_tx_pkt.c | 2 +- | 58 | qapi/migration.json | 53 +++++++++++++++- |
49 | hw/net/pcnet.c | 2 +- | 59 | qapi/net.json | 43 +++++++++++++ |
50 | hw/net/rtl8139.c | 2 +- | 60 | tests/Makefile.include | 3 + |
51 | hw/net/sungem.c | 2 +- | 61 | tests/test-announce-self.c | 82 ++++++++++++++++++++++++ |
52 | hw/rdma/vmw/pvrdma.h | 5 +- | 62 | tests/test-hmp.c | 1 + |
53 | hw/rdma/vmw/pvrdma_cmd.c | 6 +- | 63 | 25 files changed, 637 insertions(+), 174 deletions(-) |
54 | hw/rdma/vmw/pvrdma_dev_ring.c | 41 ++++---- | 64 | create mode 100644 include/net/announce.h |
55 | hw/rdma/vmw/pvrdma_dev_ring.h | 9 +- | 65 | create mode 100644 net/announce.c |
56 | hw/rdma/vmw/pvrdma_main.c | 4 +- | 66 | create mode 100644 tests/test-announce-self.c |
57 | hw/virtio/virtio-net-pci.c | 10 +- | ||
58 | include/net/net.h | 5 + | ||
59 | include/net/queue.h | 8 ++ | ||
60 | .../drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h | 114 --------------------- | ||
61 | net/net.c | 53 ++++++++-- | ||
62 | net/queue.c | 22 ++++ | ||
63 | scripts/update-linux-headers.sh | 3 +- | ||
64 | 22 files changed, 142 insertions(+), 163 deletions(-) | ||
65 | delete mode 100644 include/standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h | ||
66 | 67 | ||
67 | 68 | ||
69 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | Currently, the default msix vectors for virtio-net-pci is 3 which is | ||
2 | obvious not suitable for multiqueue guest, so we depends on the user | ||
3 | or management tools to pass a correct vectors parameter. In fact, we | ||
4 | can simplifying this by calculating the number of vectors on realize. | ||
5 | 1 | ||
6 | Consider we have N queues, the number of vectors needed is 2*N + 2 | ||
7 | (#queue pairs + plus one config interrupt and control vq). We didn't | ||
8 | check whether or not host support control vq because it was added | ||
9 | unconditionally by qemu to avoid breaking legacy guests such as Minix. | ||
10 | |||
11 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com | ||
12 | Reviewed-by: Stefano Garzarella <sgarzare@redhat.com> | ||
13 | Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> | ||
14 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
15 | --- | ||
16 | hw/core/machine.c | 1 + | ||
17 | hw/virtio/virtio-net-pci.c | 10 +++++++++- | ||
18 | 2 files changed, 10 insertions(+), 1 deletion(-) | ||
19 | |||
20 | diff --git a/hw/core/machine.c b/hw/core/machine.c | ||
21 | index XXXXXXX..XXXXXXX 100644 | ||
22 | --- a/hw/core/machine.c | ||
23 | +++ b/hw/core/machine.c | ||
24 | @@ -XXX,XX +XXX,XX @@ | ||
25 | GlobalProperty hw_compat_5_2[] = { | ||
26 | { "ICH9-LPC", "smm-compat", "on"}, | ||
27 | { "PIIX4_PM", "smm-compat", "on"}, | ||
28 | + { "virtio-net-pci", "vectors", "3"}, | ||
29 | }; | ||
30 | const size_t hw_compat_5_2_len = G_N_ELEMENTS(hw_compat_5_2); | ||
31 | |||
32 | diff --git a/hw/virtio/virtio-net-pci.c b/hw/virtio/virtio-net-pci.c | ||
33 | index XXXXXXX..XXXXXXX 100644 | ||
34 | --- a/hw/virtio/virtio-net-pci.c | ||
35 | +++ b/hw/virtio/virtio-net-pci.c | ||
36 | @@ -XXX,XX +XXX,XX @@ struct VirtIONetPCI { | ||
37 | static Property virtio_net_properties[] = { | ||
38 | DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, | ||
39 | VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), | ||
40 | - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), | ||
41 | + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, | ||
42 | + DEV_NVECTORS_UNSPECIFIED), | ||
43 | DEFINE_PROP_END_OF_LIST(), | ||
44 | }; | ||
45 | |||
46 | @@ -XXX,XX +XXX,XX @@ static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) | ||
47 | DeviceState *qdev = DEVICE(vpci_dev); | ||
48 | VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev); | ||
49 | DeviceState *vdev = DEVICE(&dev->vdev); | ||
50 | + VirtIONet *net = VIRTIO_NET(vdev); | ||
51 | + | ||
52 | + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { | ||
53 | + vpci_dev->nvectors = 2 * MAX(net->nic_conf.peers.queues, 1) | ||
54 | + + 1 /* Config interrupt */ | ||
55 | + + 1 /* Control vq */; | ||
56 | + } | ||
57 | |||
58 | virtio_net_set_netclient_name(&dev->vdev, qdev->id, | ||
59 | object_get_typename(OBJECT(qdev))); | ||
60 | -- | ||
61 | 2.7.4 | ||
62 | |||
63 | diff view generated by jsdifflib |
1 | From: Alexander Bulekov <alxndr@bu.edu> | 1 | From: Zhang Chen <chen.zhang@intel.com> |
---|---|---|---|
2 | 2 | ||
3 | This patch switches to use qemu_receive_packet() which can detect | 3 | Fix duplicated code: |
4 | reentrancy and return early. | 4 | https://bugs.launchpad.net/qemu/+bug/1811499 |
5 | 5 | ||
6 | This is intended to address CVE-2021-3416. | 6 | Reviewed-by: Thomas Huth <thuth@redhat.com> |
7 | 7 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | |
8 | Cc: Prasad J Pandit <ppandit@redhat.com> | 8 | Signed-off-by: Zhang Chen <chen.zhang@intel.com> |
9 | Cc: qemu-stable@nongnu.org | ||
10 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com | ||
11 | Signed-off-by: Alexander Bulekov <alxndr@bu.edu> | ||
12 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 9 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
13 | --- | 10 | --- |
14 | hw/net/lan9118.c | 2 +- | 11 | net/colo-compare.c | 8 -------- |
15 | 1 file changed, 1 insertion(+), 1 deletion(-) | 12 | 1 file changed, 8 deletions(-) |
16 | 13 | ||
17 | diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c | 14 | diff --git a/net/colo-compare.c b/net/colo-compare.c |
18 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/hw/net/lan9118.c | 16 | --- a/net/colo-compare.c |
20 | +++ b/hw/net/lan9118.c | 17 | +++ b/net/colo-compare.c |
21 | @@ -XXX,XX +XXX,XX @@ static void do_tx_packet(lan9118_state *s) | 18 | @@ -XXX,XX +XXX,XX @@ static bool colo_mark_tcp_pkt(Packet *ppkt, Packet *spkt, |
22 | /* FIXME: Honor TX disable, and allow queueing of packets. */ | 19 | return true; |
23 | if (s->phy_control & 0x4000) { | 20 | } |
24 | /* This assumes the receive routine doesn't touch the VLANClient. */ | ||
25 | - lan9118_receive(qemu_get_queue(s->nic), s->txp->data, s->txp->len); | ||
26 | + qemu_receive_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len); | ||
27 | } else { | ||
28 | qemu_send_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len); | ||
29 | } | 21 | } |
22 | - if (ppkt->tcp_seq == spkt->tcp_seq && ppkt->seq_end == spkt->seq_end) { | ||
23 | - if (colo_compare_packet_payload(ppkt, spkt, | ||
24 | - ppkt->header_size, spkt->header_size, | ||
25 | - ppkt->payload_size)) { | ||
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)) { | ||
30 | -- | 33 | -- |
31 | 2.7.4 | 34 | 2.5.0 |
32 | 35 | ||
33 | 36 | diff view generated by jsdifflib |
1 | From: Alexander Bulekov <alxndr@bu.edu> | 1 | From: Vincenzo Maffione <v.maffione@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | This patch switches to use qemu_receive_packet() which can detect | 3 | This change improves the handling of incomplete multi-slot packets |
4 | reentrancy and return early. | 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. | ||
5 | 9 | ||
6 | This is intended to address CVE-2021-3416. | 10 | Signed-off-by: Vincenzo Maffione <v.maffione@gmail.com> |
7 | |||
8 | Cc: Prasad J Pandit <ppandit@redhat.com> | ||
9 | Cc: qemu-stable@nongnu.org | ||
10 | Buglink: https://bugs.launchpad.net/qemu/+bug/1910826 | ||
11 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com | ||
12 | Signed-off-by: Alexander Bulekov <alxndr@bu.edu> | ||
13 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 11 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
14 | --- | 12 | --- |
15 | hw/net/rtl8139.c | 2 +- | 13 | net/netmap.c | 31 +++++++++++++++++++------------ |
16 | 1 file changed, 1 insertion(+), 1 deletion(-) | 14 | 1 file changed, 19 insertions(+), 12 deletions(-) |
17 | 15 | ||
18 | diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c | 16 | diff --git a/net/netmap.c b/net/netmap.c |
19 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/hw/net/rtl8139.c | 18 | --- a/net/netmap.c |
21 | +++ b/hw/net/rtl8139.c | 19 | +++ b/net/netmap.c |
22 | @@ -XXX,XX +XXX,XX @@ static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size, | 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; | ||
23 | } | 63 | } |
24 | 64 | ||
25 | DPRINTF("+++ transmit loopback mode\n"); | 65 | iovsize = qemu_sendv_packet_async(&s->nc, s->iov, iovcnt, |
26 | - rtl8139_do_receive(qemu_get_queue(s->nic), buf, size, do_interrupt); | 66 | netmap_send_completed); |
27 | + qemu_receive_packet(qemu_get_queue(s->nic), buf, size); | 67 | |
28 | 68 | + /* Release the slots to the kernel. */ | |
29 | if (iov) { | 69 | + ring->head = i; |
30 | g_free(buf2); | 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 | } | ||
31 | -- | 79 | -- |
32 | 2.7.4 | 80 | 2.5.0 |
33 | 81 | ||
34 | 82 | diff view generated by jsdifflib |
1 | From: Cornelia Huck <cohuck@redhat.com> | 1 | From: Vincenzo Maffione <v.maffione@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | The pvrdma code relies on the pvrdma_ring.h kernel header for some | 3 | Improve code reuse by implementing netmap_receive() with a call |
4 | basic ring buffer handling. The content of that header isn't very | 4 | to netmap_receive_iov(). |
5 | exciting, but contains some (q)atomic_*() invocations that (a) | ||
6 | cause manual massaging when doing a headers update, and (b) are | ||
7 | an indication that we probably should not be importing that header | ||
8 | at all. | ||
9 | 5 | ||
10 | Let's reimplement the ring buffer handling directly in the pvrdma | 6 | Signed-off-by: Vincenzo Maffione <v.maffione@gmail.com> |
11 | code instead. This arguably also improves readability of the code. | ||
12 | |||
13 | Importing the header can now be dropped. | ||
14 | |||
15 | Signed-off-by: Cornelia Huck <cohuck@redhat.com> | ||
16 | Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> | ||
17 | Reviewed-by: Yuval Shaia <yuval.shaia.ml@gmail.com> | ||
18 | Tested-by: Yuval Shaia <yuval.shaia.ml@gmail.com> | ||
19 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 7 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
20 | --- | 8 | --- |
21 | hw/rdma/vmw/pvrdma.h | 5 +- | 9 | net/netmap.c | 50 +++++++++++--------------------------------------- |
22 | hw/rdma/vmw/pvrdma_cmd.c | 6 +- | 10 | 1 file changed, 11 insertions(+), 39 deletions(-) |
23 | hw/rdma/vmw/pvrdma_dev_ring.c | 41 ++++---- | ||
24 | hw/rdma/vmw/pvrdma_dev_ring.h | 9 +- | ||
25 | hw/rdma/vmw/pvrdma_main.c | 4 +- | ||
26 | .../drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h | 114 --------------------- | ||
27 | scripts/update-linux-headers.sh | 3 +- | ||
28 | 7 files changed, 38 insertions(+), 144 deletions(-) | ||
29 | delete mode 100644 include/standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h | ||
30 | 11 | ||
31 | diff --git a/hw/rdma/vmw/pvrdma.h b/hw/rdma/vmw/pvrdma.h | 12 | diff --git a/net/netmap.c b/net/netmap.c |
32 | index XXXXXXX..XXXXXXX 100644 | 13 | index XXXXXXX..XXXXXXX 100644 |
33 | --- a/hw/rdma/vmw/pvrdma.h | 14 | --- a/net/netmap.c |
34 | +++ b/hw/rdma/vmw/pvrdma.h | 15 | +++ b/net/netmap.c |
35 | @@ -XXX,XX +XXX,XX @@ | 16 | @@ -XXX,XX +XXX,XX @@ static void netmap_writable(void *opaque) |
36 | #include "../rdma_backend_defs.h" | 17 | qemu_flush_queued_packets(&s->nc); |
37 | #include "../rdma_rm_defs.h" | ||
38 | |||
39 | -#include "standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h" | ||
40 | #include "standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_dev_api.h" | ||
41 | #include "pvrdma_dev_ring.h" | ||
42 | #include "qom/object.h" | ||
43 | @@ -XXX,XX +XXX,XX @@ typedef struct DSRInfo { | ||
44 | union pvrdma_cmd_req *req; | ||
45 | union pvrdma_cmd_resp *rsp; | ||
46 | |||
47 | - struct pvrdma_ring *async_ring_state; | ||
48 | + PvrdmaRingState *async_ring_state; | ||
49 | PvrdmaRing async; | ||
50 | |||
51 | - struct pvrdma_ring *cq_ring_state; | ||
52 | + PvrdmaRingState *cq_ring_state; | ||
53 | PvrdmaRing cq; | ||
54 | } DSRInfo; | ||
55 | |||
56 | diff --git a/hw/rdma/vmw/pvrdma_cmd.c b/hw/rdma/vmw/pvrdma_cmd.c | ||
57 | index XXXXXXX..XXXXXXX 100644 | ||
58 | --- a/hw/rdma/vmw/pvrdma_cmd.c | ||
59 | +++ b/hw/rdma/vmw/pvrdma_cmd.c | ||
60 | @@ -XXX,XX +XXX,XX @@ static int create_cq_ring(PCIDevice *pci_dev , PvrdmaRing **ring, | ||
61 | r = g_malloc(sizeof(*r)); | ||
62 | *ring = r; | ||
63 | |||
64 | - r->ring_state = (struct pvrdma_ring *) | ||
65 | + r->ring_state = (PvrdmaRingState *) | ||
66 | rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE); | ||
67 | |||
68 | if (!r->ring_state) { | ||
69 | @@ -XXX,XX +XXX,XX @@ static int create_qp_rings(PCIDevice *pci_dev, uint64_t pdir_dma, | ||
70 | *rings = sr; | ||
71 | |||
72 | /* Create send ring */ | ||
73 | - sr->ring_state = (struct pvrdma_ring *) | ||
74 | + sr->ring_state = (PvrdmaRingState *) | ||
75 | rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE); | ||
76 | if (!sr->ring_state) { | ||
77 | rdma_error_report("Failed to map to QP ring state"); | ||
78 | @@ -XXX,XX +XXX,XX @@ static int create_srq_ring(PCIDevice *pci_dev, PvrdmaRing **ring, | ||
79 | r = g_malloc(sizeof(*r)); | ||
80 | *ring = r; | ||
81 | |||
82 | - r->ring_state = (struct pvrdma_ring *) | ||
83 | + r->ring_state = (PvrdmaRingState *) | ||
84 | rdma_pci_dma_map(pci_dev, tbl[0], TARGET_PAGE_SIZE); | ||
85 | if (!r->ring_state) { | ||
86 | rdma_error_report("Failed to map tp SRQ ring state"); | ||
87 | diff --git a/hw/rdma/vmw/pvrdma_dev_ring.c b/hw/rdma/vmw/pvrdma_dev_ring.c | ||
88 | index XXXXXXX..XXXXXXX 100644 | ||
89 | --- a/hw/rdma/vmw/pvrdma_dev_ring.c | ||
90 | +++ b/hw/rdma/vmw/pvrdma_dev_ring.c | ||
91 | @@ -XXX,XX +XXX,XX @@ | ||
92 | #include "trace.h" | ||
93 | |||
94 | #include "../rdma_utils.h" | ||
95 | -#include "standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h" | ||
96 | #include "pvrdma_dev_ring.h" | ||
97 | |||
98 | int pvrdma_ring_init(PvrdmaRing *ring, const char *name, PCIDevice *dev, | ||
99 | - struct pvrdma_ring *ring_state, uint32_t max_elems, | ||
100 | + PvrdmaRingState *ring_state, uint32_t max_elems, | ||
101 | size_t elem_sz, dma_addr_t *tbl, uint32_t npages) | ||
102 | { | ||
103 | int i; | ||
104 | @@ -XXX,XX +XXX,XX @@ out: | ||
105 | |||
106 | void *pvrdma_ring_next_elem_read(PvrdmaRing *ring) | ||
107 | { | ||
108 | - int e; | ||
109 | - unsigned int idx = 0, offset; | ||
110 | + unsigned int idx, offset; | ||
111 | + const uint32_t tail = qatomic_read(&ring->ring_state->prod_tail); | ||
112 | + const uint32_t head = qatomic_read(&ring->ring_state->cons_head); | ||
113 | |||
114 | - e = pvrdma_idx_ring_has_data(ring->ring_state, ring->max_elems, &idx); | ||
115 | - if (e <= 0) { | ||
116 | + if (tail & ~((ring->max_elems << 1) - 1) || | ||
117 | + head & ~((ring->max_elems << 1) - 1) || | ||
118 | + tail == head) { | ||
119 | trace_pvrdma_ring_next_elem_read_no_data(ring->name); | ||
120 | return NULL; | ||
121 | } | ||
122 | |||
123 | + idx = head & (ring->max_elems - 1); | ||
124 | offset = idx * ring->elem_sz; | ||
125 | return ring->pages[offset / TARGET_PAGE_SIZE] + (offset % TARGET_PAGE_SIZE); | ||
126 | } | 18 | } |
127 | 19 | ||
128 | void pvrdma_ring_read_inc(PvrdmaRing *ring) | 20 | -static ssize_t netmap_receive(NetClientState *nc, |
129 | { | 21 | - const uint8_t *buf, size_t size) |
130 | - pvrdma_idx_ring_inc(&ring->ring_state->cons_head, ring->max_elems); | 22 | -{ |
131 | + uint32_t idx = qatomic_read(&ring->ring_state->cons_head); | 23 | - NetmapState *s = DO_UPCAST(NetmapState, nc, nc); |
132 | + | 24 | - struct netmap_ring *ring = s->tx; |
133 | + idx = (idx + 1) & ((ring->max_elems << 1) - 1); | 25 | - uint32_t i; |
134 | + qatomic_set(&ring->ring_state->cons_head, idx); | 26 | - uint32_t idx; |
135 | } | 27 | - uint8_t *dst; |
136 | 28 | - | |
137 | void *pvrdma_ring_next_elem_write(PvrdmaRing *ring) | 29 | - if (unlikely(!ring)) { |
138 | { | 30 | - /* Drop. */ |
139 | - int idx; | 31 | - return size; |
140 | - unsigned int offset, tail; | ||
141 | + unsigned int idx, offset; | ||
142 | + const uint32_t tail = qatomic_read(&ring->ring_state->prod_tail); | ||
143 | + const uint32_t head = qatomic_read(&ring->ring_state->cons_head); | ||
144 | |||
145 | - idx = pvrdma_idx_ring_has_space(ring->ring_state, ring->max_elems, &tail); | ||
146 | - if (idx <= 0) { | ||
147 | + if (tail & ~((ring->max_elems << 1) - 1) || | ||
148 | + head & ~((ring->max_elems << 1) - 1) || | ||
149 | + tail == (head ^ ring->max_elems)) { | ||
150 | rdma_error_report("CQ is full"); | ||
151 | return NULL; | ||
152 | } | ||
153 | |||
154 | - idx = pvrdma_idx(&ring->ring_state->prod_tail, ring->max_elems); | ||
155 | - if (idx < 0 || tail != idx) { | ||
156 | - rdma_error_report("Invalid idx %d", idx); | ||
157 | - return NULL; | ||
158 | - } | 32 | - } |
159 | - | 33 | - |
160 | + idx = tail & (ring->max_elems - 1); | 34 | - if (unlikely(size > ring->nr_buf_size)) { |
161 | offset = idx * ring->elem_sz; | 35 | - RD(5, "[netmap_receive] drop packet of size %d > %d\n", |
162 | return ring->pages[offset / TARGET_PAGE_SIZE] + (offset % TARGET_PAGE_SIZE); | 36 | - (int)size, ring->nr_buf_size); |
163 | } | 37 | - return size; |
164 | 38 | - } | |
165 | void pvrdma_ring_write_inc(PvrdmaRing *ring) | ||
166 | { | ||
167 | - pvrdma_idx_ring_inc(&ring->ring_state->prod_tail, ring->max_elems); | ||
168 | + uint32_t idx = qatomic_read(&ring->ring_state->prod_tail); | ||
169 | + | ||
170 | + idx = (idx + 1) & ((ring->max_elems << 1) - 1); | ||
171 | + qatomic_set(&ring->ring_state->prod_tail, idx); | ||
172 | } | ||
173 | |||
174 | void pvrdma_ring_free(PvrdmaRing *ring) | ||
175 | diff --git a/hw/rdma/vmw/pvrdma_dev_ring.h b/hw/rdma/vmw/pvrdma_dev_ring.h | ||
176 | index XXXXXXX..XXXXXXX 100644 | ||
177 | --- a/hw/rdma/vmw/pvrdma_dev_ring.h | ||
178 | +++ b/hw/rdma/vmw/pvrdma_dev_ring.h | ||
179 | @@ -XXX,XX +XXX,XX @@ | ||
180 | |||
181 | #define MAX_RING_NAME_SZ 32 | ||
182 | |||
183 | +typedef struct PvrdmaRingState { | ||
184 | + int prod_tail; /* producer tail */ | ||
185 | + int cons_head; /* consumer head */ | ||
186 | +} PvrdmaRingState; | ||
187 | + | ||
188 | typedef struct PvrdmaRing { | ||
189 | char name[MAX_RING_NAME_SZ]; | ||
190 | PCIDevice *dev; | ||
191 | uint32_t max_elems; | ||
192 | size_t elem_sz; | ||
193 | - struct pvrdma_ring *ring_state; /* used only for unmap */ | ||
194 | + PvrdmaRingState *ring_state; /* used only for unmap */ | ||
195 | int npages; | ||
196 | void **pages; | ||
197 | } PvrdmaRing; | ||
198 | |||
199 | int pvrdma_ring_init(PvrdmaRing *ring, const char *name, PCIDevice *dev, | ||
200 | - struct pvrdma_ring *ring_state, uint32_t max_elems, | ||
201 | + PvrdmaRingState *ring_state, uint32_t max_elems, | ||
202 | size_t elem_sz, dma_addr_t *tbl, uint32_t npages); | ||
203 | void *pvrdma_ring_next_elem_read(PvrdmaRing *ring); | ||
204 | void pvrdma_ring_read_inc(PvrdmaRing *ring); | ||
205 | diff --git a/hw/rdma/vmw/pvrdma_main.c b/hw/rdma/vmw/pvrdma_main.c | ||
206 | index XXXXXXX..XXXXXXX 100644 | ||
207 | --- a/hw/rdma/vmw/pvrdma_main.c | ||
208 | +++ b/hw/rdma/vmw/pvrdma_main.c | ||
209 | @@ -XXX,XX +XXX,XX @@ static void free_dev_ring(PCIDevice *pci_dev, PvrdmaRing *ring, | ||
210 | rdma_pci_dma_unmap(pci_dev, ring_state, TARGET_PAGE_SIZE); | ||
211 | } | ||
212 | |||
213 | -static int init_dev_ring(PvrdmaRing *ring, struct pvrdma_ring **ring_state, | ||
214 | +static int init_dev_ring(PvrdmaRing *ring, PvrdmaRingState **ring_state, | ||
215 | const char *name, PCIDevice *pci_dev, | ||
216 | dma_addr_t dir_addr, uint32_t num_pages) | ||
217 | { | ||
218 | @@ -XXX,XX +XXX,XX @@ static int init_dev_ring(PvrdmaRing *ring, struct pvrdma_ring **ring_state, | ||
219 | /* RX ring is the second */ | ||
220 | (*ring_state)++; | ||
221 | rc = pvrdma_ring_init(ring, name, pci_dev, | ||
222 | - (struct pvrdma_ring *)*ring_state, | ||
223 | + (PvrdmaRingState *)*ring_state, | ||
224 | (num_pages - 1) * TARGET_PAGE_SIZE / | ||
225 | sizeof(struct pvrdma_cqne), | ||
226 | sizeof(struct pvrdma_cqne), | ||
227 | diff --git a/include/standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h b/include/standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h | ||
228 | deleted file mode 100644 | ||
229 | index XXXXXXX..XXXXXXX | ||
230 | --- a/include/standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h | ||
231 | +++ /dev/null | ||
232 | @@ -XXX,XX +XXX,XX @@ | ||
233 | -/* | ||
234 | - * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. | ||
235 | - * | ||
236 | - * This program is free software; you can redistribute it and/or | ||
237 | - * modify it under the terms of EITHER the GNU General Public License | ||
238 | - * version 2 as published by the Free Software Foundation or the BSD | ||
239 | - * 2-Clause License. This program is distributed in the hope that it | ||
240 | - * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED | ||
241 | - * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. | ||
242 | - * See the GNU General Public License version 2 for more details at | ||
243 | - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. | ||
244 | - * | ||
245 | - * You should have received a copy of the GNU General Public License | ||
246 | - * along with this program available in the file COPYING in the main | ||
247 | - * directory of this source tree. | ||
248 | - * | ||
249 | - * The BSD 2-Clause License | ||
250 | - * | ||
251 | - * Redistribution and use in source and binary forms, with or | ||
252 | - * without modification, are permitted provided that the following | ||
253 | - * conditions are met: | ||
254 | - * | ||
255 | - * - Redistributions of source code must retain the above | ||
256 | - * copyright notice, this list of conditions and the following | ||
257 | - * disclaimer. | ||
258 | - * | ||
259 | - * - Redistributions in binary form must reproduce the above | ||
260 | - * copyright notice, this list of conditions and the following | ||
261 | - * disclaimer in the documentation and/or other materials | ||
262 | - * provided with the distribution. | ||
263 | - * | ||
264 | - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
265 | - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
266 | - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
267 | - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
268 | - * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | ||
269 | - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
270 | - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
271 | - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
272 | - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
273 | - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
274 | - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
275 | - * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
276 | - */ | ||
277 | - | 39 | - |
278 | -#ifndef __PVRDMA_RING_H__ | 40 | - if (nm_ring_empty(ring)) { |
279 | -#define __PVRDMA_RING_H__ | 41 | - /* No available slots in the netmap TX ring. */ |
42 | - netmap_write_poll(s, true); | ||
43 | - return 0; | ||
44 | - } | ||
280 | - | 45 | - |
281 | -#include "standard-headers/linux/types.h" | 46 | - i = ring->cur; |
47 | - idx = ring->slot[i].buf_idx; | ||
48 | - dst = (uint8_t *)NETMAP_BUF(ring, idx); | ||
282 | - | 49 | - |
283 | -#define PVRDMA_INVALID_IDX -1 /* Invalid index. */ | 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); | ||
284 | - | 55 | - |
285 | -struct pvrdma_ring { | 56 | - return size; |
286 | - int prod_tail; /* Producer tail. */ | ||
287 | - int cons_head; /* Consumer head. */ | ||
288 | -}; | ||
289 | - | ||
290 | -struct pvrdma_ring_state { | ||
291 | - struct pvrdma_ring tx; /* Tx ring. */ | ||
292 | - struct pvrdma_ring rx; /* Rx ring. */ | ||
293 | -}; | ||
294 | - | ||
295 | -static inline int pvrdma_idx_valid(uint32_t idx, uint32_t max_elems) | ||
296 | -{ | ||
297 | - /* Generates fewer instructions than a less-than. */ | ||
298 | - return (idx & ~((max_elems << 1) - 1)) == 0; | ||
299 | -} | 57 | -} |
300 | - | 58 | - |
301 | -static inline int32_t pvrdma_idx(int *var, uint32_t max_elems) | 59 | static ssize_t netmap_receive_iov(NetClientState *nc, |
302 | -{ | 60 | const struct iovec *iov, int iovcnt) |
303 | - const unsigned int idx = qatomic_read(var); | 61 | { |
304 | - | 62 | @@ -XXX,XX +XXX,XX @@ static ssize_t netmap_receive_iov(NetClientState *nc, |
305 | - if (pvrdma_idx_valid(idx, max_elems)) | 63 | return iov_size(iov, iovcnt); |
306 | - return idx & (max_elems - 1); | 64 | } |
307 | - return PVRDMA_INVALID_IDX; | 65 | |
308 | -} | 66 | +static ssize_t netmap_receive(NetClientState *nc, |
309 | - | 67 | + const uint8_t *buf, size_t size) |
310 | -static inline void pvrdma_idx_ring_inc(int *var, uint32_t max_elems) | 68 | +{ |
311 | -{ | 69 | + struct iovec iov; |
312 | - uint32_t idx = qatomic_read(var) + 1; /* Increment. */ | 70 | + |
313 | - | 71 | + iov.iov_base = (void *)buf; |
314 | - idx &= (max_elems << 1) - 1; /* Modulo size, flip gen. */ | 72 | + iov.iov_len = size; |
315 | - qatomic_set(var, idx); | 73 | + |
316 | -} | 74 | + return netmap_receive_iov(nc, &iov, 1); |
317 | - | 75 | +} |
318 | -static inline int32_t pvrdma_idx_ring_has_space(const struct pvrdma_ring *r, | 76 | + |
319 | - uint32_t max_elems, uint32_t *out_tail) | 77 | /* Complete a previous send (backend --> guest) and enable the |
320 | -{ | 78 | fd_read callback. */ |
321 | - const uint32_t tail = qatomic_read(&r->prod_tail); | 79 | static void netmap_send_completed(NetClientState *nc, ssize_t len) |
322 | - const uint32_t head = qatomic_read(&r->cons_head); | ||
323 | - | ||
324 | - if (pvrdma_idx_valid(tail, max_elems) && | ||
325 | - pvrdma_idx_valid(head, max_elems)) { | ||
326 | - *out_tail = tail & (max_elems - 1); | ||
327 | - return tail != (head ^ max_elems); | ||
328 | - } | ||
329 | - return PVRDMA_INVALID_IDX; | ||
330 | -} | ||
331 | - | ||
332 | -static inline int32_t pvrdma_idx_ring_has_data(const struct pvrdma_ring *r, | ||
333 | - uint32_t max_elems, uint32_t *out_head) | ||
334 | -{ | ||
335 | - const uint32_t tail = qatomic_read(&r->prod_tail); | ||
336 | - const uint32_t head = qatomic_read(&r->cons_head); | ||
337 | - | ||
338 | - if (pvrdma_idx_valid(tail, max_elems) && | ||
339 | - pvrdma_idx_valid(head, max_elems)) { | ||
340 | - *out_head = head & (max_elems - 1); | ||
341 | - return tail != head; | ||
342 | - } | ||
343 | - return PVRDMA_INVALID_IDX; | ||
344 | -} | ||
345 | - | ||
346 | -#endif /* __PVRDMA_RING_H__ */ | ||
347 | diff --git a/scripts/update-linux-headers.sh b/scripts/update-linux-headers.sh | ||
348 | index XXXXXXX..XXXXXXX 100755 | ||
349 | --- a/scripts/update-linux-headers.sh | ||
350 | +++ b/scripts/update-linux-headers.sh | ||
351 | @@ -XXX,XX +XXX,XX @@ sed -e '1h;2,$H;$!d;g' -e 's/[^};]*pvrdma[^(| ]*([^)]*);//g' \ | ||
352 | "$linux/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.h" > \ | ||
353 | "$tmp_pvrdma_verbs"; | ||
354 | |||
355 | -for i in "$linux/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h" \ | ||
356 | - "$linux/drivers/infiniband/hw/vmw_pvrdma/pvrdma_dev_api.h" \ | ||
357 | +for i in "$linux/drivers/infiniband/hw/vmw_pvrdma/pvrdma_dev_api.h" \ | ||
358 | "$tmp_pvrdma_verbs"; do \ | ||
359 | cp_portable "$i" \ | ||
360 | "$output/include/standard-headers/drivers/infiniband/hw/vmw_pvrdma/" | ||
361 | -- | 80 | -- |
362 | 2.7.4 | 81 | 2.5.0 |
363 | 82 | ||
364 | 83 | diff view generated by jsdifflib |
1 | From: Alexander Bulekov <alxndr@bu.edu> | 1 | From: Vincenzo Maffione <v.maffione@gmail.com> |
---|---|---|---|
2 | 2 | ||
3 | This patch switches to use qemu_receive_packet() which can detect | 3 | Changes: |
4 | reentrancy and return early. | 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). | ||
5 | 13 | ||
6 | This is intended to address CVE-2021-3416. | 14 | Signed-off-by: Vincenzo Maffione <v.maffione@gmail.com> |
7 | |||
8 | Cc: Prasad J Pandit <ppandit@redhat.com> | ||
9 | Cc: qemu-stable@nongnu.org | ||
10 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
11 | Signed-off-by: Alexander Bulekov <alxndr@bu.edu> | ||
12 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 15 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
13 | --- | 16 | --- |
14 | hw/net/cadence_gem.c | 4 ++-- | 17 | net/netmap.c | 29 +++++++++++++++++------------ |
15 | 1 file changed, 2 insertions(+), 2 deletions(-) | 18 | 1 file changed, 17 insertions(+), 12 deletions(-) |
16 | 19 | ||
17 | diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c | 20 | diff --git a/net/netmap.c b/net/netmap.c |
18 | index XXXXXXX..XXXXXXX 100644 | 21 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/hw/net/cadence_gem.c | 22 | --- a/net/netmap.c |
20 | +++ b/hw/net/cadence_gem.c | 23 | +++ b/net/netmap.c |
21 | @@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s) | 24 | @@ -XXX,XX +XXX,XX @@ static ssize_t netmap_receive_iov(NetClientState *nc, |
22 | /* Send the packet somewhere */ | 25 | { |
23 | if (s->phy_loop || (s->regs[GEM_NWCTRL] & | 26 | NetmapState *s = DO_UPCAST(NetmapState, nc, nc); |
24 | GEM_NWCTRL_LOCALLOOP)) { | 27 | struct netmap_ring *ring = s->tx; |
25 | - gem_receive(qemu_get_queue(s->nic), s->tx_packet, | 28 | + unsigned int tail = ring->tail; |
26 | - total_bytes); | 29 | + ssize_t totlen = 0; |
27 | + qemu_receive_packet(qemu_get_queue(s->nic), s->tx_packet, | 30 | uint32_t last; |
28 | + total_bytes); | 31 | uint32_t idx; |
29 | } else { | 32 | uint8_t *dst; |
30 | qemu_send_packet(qemu_get_queue(s->nic), s->tx_packet, | 33 | int j; |
31 | total_bytes); | 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, | ||
32 | -- | 91 | -- |
33 | 2.7.4 | 92 | 2.5.0 |
34 | 93 | ||
35 | 94 | diff view generated by jsdifflib |
1 | From: Alexander Bulekov <alxndr@bu.edu> | 1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | This patch switches to use qemu_receive_packet() which can detect | 3 | The 'announce timer' will be used by migration, and explicit |
4 | reentrancy and return early. | 4 | requests for qemu to perform network announces. |
5 | 5 | ||
6 | This is intended to address CVE-2021-3416. | 6 | Based on the work by Germano Veit Michel <germano@redhat.com> |
7 | 7 | and Vlad Yasevich <vyasevic@redhat.com> | |
8 | Cc: Prasad J Pandit <ppandit@redhat.com> | 8 | |
9 | Cc: qemu-stable@nongnu.org | 9 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> |
10 | Buglink: https://bugs.launchpad.net/qemu/+bug/1917085 | 10 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> |
11 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com | ||
12 | Signed-off-by: Alexander Bulekov <alxndr@bu.edu> | ||
13 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 11 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
14 | --- | 12 | --- |
15 | hw/net/pcnet.c | 2 +- | 13 | include/net/announce.h | 39 ++++++++++++++++++++++++++++++++ |
16 | 1 file changed, 1 insertion(+), 1 deletion(-) | 14 | include/qemu/typedefs.h | 1 + |
17 | 15 | migration/migration.c | 1 + | |
18 | diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c | 16 | net/Makefile.objs | 1 + |
19 | index XXXXXXX..XXXXXXX 100644 | 17 | net/announce.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ |
20 | --- a/hw/net/pcnet.c | 18 | qapi/net.json | 23 +++++++++++++++++++ |
21 | +++ b/hw/net/pcnet.c | 19 | 6 files changed, 125 insertions(+) |
22 | @@ -XXX,XX +XXX,XX @@ txagain: | 20 | create mode 100644 include/net/announce.h |
23 | if (BCR_SWSTYLE(s) == 1) | 21 | create mode 100644 net/announce.c |
24 | add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS); | 22 | |
25 | s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC; | 23 | diff --git a/include/net/announce.h b/include/net/announce.h |
26 | - pcnet_receive(qemu_get_queue(s->nic), s->buffer, s->xmit_pos); | 24 | new file mode 100644 |
27 | + qemu_receive_packet(qemu_get_queue(s->nic), s->buffer, s->xmit_pos); | 25 | index XXXXXXX..XXXXXXX |
28 | s->looptest = 0; | 26 | --- /dev/null |
29 | } else { | 27 | +++ b/include/net/announce.h |
30 | if (s->nic) { | 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' } } | ||
31 | -- | 201 | -- |
32 | 2.7.4 | 202 | 2.5.0 |
33 | 203 | ||
34 | 204 | diff view generated by jsdifflib |
1 | From: Bin Meng <bin.meng@windriver.com> | 1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | "qemu-common.h" should be included to provide the forward declaration | 3 | Add migration parameters that control RARP/GARP announcement timeouts. |
4 | of qemu_hexdump() when DEBUG_NET is on. | 4 | |
5 | 5 | Based on earlier patches by myself and | |
6 | Signed-off-by: Bin Meng <bin.meng@windriver.com> | 6 | Vladislav Yasevich <vyasevic@redhat.com> |
7 | Reviewed-by: Philippe Mathieu-Daudé <philmd@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> | ||
8 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 11 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
9 | --- | 12 | --- |
10 | net/net.c | 1 + | 13 | hmp.c | 28 +++++++++++++ |
11 | 1 file changed, 1 insertion(+) | 14 | include/migration/misc.h | 2 + |
12 | 15 | migration/migration.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++ | |
13 | diff --git a/net/net.c b/net/net.c | 16 | qapi/migration.json | 53 +++++++++++++++++++++++-- |
17 | 4 files changed, 180 insertions(+), 3 deletions(-) | ||
18 | |||
19 | diff --git a/hmp.c b/hmp.c | ||
14 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
15 | --- a/net/net.c | 21 | --- a/hmp.c |
16 | +++ b/net/net.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 | ||
17 | @@ -XXX,XX +XXX,XX @@ | 89 | @@ -XXX,XX +XXX,XX @@ |
18 | */ | 90 | */ |
19 | 91 | #define DEFAULT_MIGRATE_MAX_POSTCOPY_BANDWIDTH 0 | |
20 | #include "qemu/osdep.h" | 92 | |
21 | +#include "qemu-common.h" | 93 | +/* |
22 | 94 | + * Parameters for self_announce_delay giving a stream of RARP/ARP | |
23 | #include "net/net.h" | 95 | + * packets after migration. |
24 | #include "clients.h" | 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', | ||
25 | -- | 344 | -- |
26 | 2.7.4 | 345 | 2.5.0 |
27 | 346 | ||
28 | 347 | diff view generated by jsdifflib |
1 | During procss_tx_desc(), driver can try to chain data descriptor with | 1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> |
---|---|---|---|
2 | legacy descriptor, when will lead underflow for the following | ||
3 | calculation in process_tx_desc() for bytes: | ||
4 | 2 | ||
5 | if (tp->size + bytes > msh) | 3 | Switch virtio's self announcement to use the AnnounceTimer. |
6 | bytes = msh - tp->size; | 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. | ||
7 | 9 | ||
8 | This will lead a infinite loop. So check and fail early if tp->size if | 10 | Based on earlier patches by myself and |
9 | greater or equal to msh. | 11 | Vladislav Yasevich <vyasevic@redhat.com> |
10 | 12 | ||
11 | Reported-by: Alexander Bulekov <alxndr@bu.edu> | 13 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> |
12 | Reported-by: Cheolwoo Myung <cwmyung@snu.ac.kr> | 14 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> |
13 | Reported-by: Ruhr-University Bochum <bugs-syssec@rub.de> | ||
14 | Cc: Prasad J Pandit <ppandit@redhat.com> | ||
15 | Cc: qemu-stable@nongnu.org | ||
16 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 15 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
17 | --- | 16 | --- |
18 | hw/net/e1000.c | 4 ++++ | 17 | hw/net/trace-events | 5 +++++ |
19 | 1 file changed, 4 insertions(+) | 18 | hw/net/virtio-net.c | 36 +++++++++++++++++++++++------------- |
19 | include/hw/virtio/virtio-net.h | 4 ++-- | ||
20 | 3 files changed, 30 insertions(+), 15 deletions(-) | ||
20 | 21 | ||
21 | diff --git a/hw/net/e1000.c b/hw/net/e1000.c | 22 | diff --git a/hw/net/trace-events b/hw/net/trace-events |
22 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
23 | --- a/hw/net/e1000.c | 24 | --- a/hw/net/trace-events |
24 | +++ b/hw/net/e1000.c | 25 | +++ b/hw/net/trace-events |
25 | @@ -XXX,XX +XXX,XX @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) | 26 | @@ -XXX,XX +XXX,XX @@ sunhme_rx_filter_reject(void) "rejecting incoming frame" |
26 | msh = tp->tso_props.hdr_len + tp->tso_props.mss; | 27 | sunhme_rx_filter_accept(void) "accepting incoming frame" |
27 | do { | 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)" |
28 | bytes = split_size; | 29 | sunhme_rx_xsum_calc(uint16_t xsum) "calculated incoming xsum as 0x%x" |
29 | + if (tp->size >= msh) { | 30 | + |
30 | + goto eop; | 31 | +# hw/net/virtio-net.c |
31 | + } | 32 | +virtio_net_announce_timer(int round) "%d" |
32 | if (tp->size + bytes > msh) | 33 | +virtio_net_handle_announce(int round) "%d" |
33 | bytes = msh - tp->size; | 34 | +virtio_net_post_load_device(void) |
34 | 35 | diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c | |
35 | @@ -XXX,XX +XXX,XX @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) | 36 | index XXXXXXX..XXXXXXX 100644 |
36 | tp->size += split_size; | 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 | + } | ||
37 | } | 116 | } |
38 | 117 | ||
39 | +eop: | 118 | return 0; |
40 | if (!(txd_lower & E1000_TXD_CMD_EOP)) | 119 | @@ -XXX,XX +XXX,XX @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) |
41 | return; | 120 | qemu_macaddr_default_if_unset(&n->nic_conf.macaddr); |
42 | if (!(tp->cptse && tp->size < tp->tso_props.hdr_len)) { | 121 | memcpy(&n->mac[0], &n->nic_conf.macaddr, sizeof(n->mac)); |
122 | n->status = VIRTIO_NET_S_LINK_UP; | ||
123 | - n->announce_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, | ||
124 | - virtio_net_announce_timer, n); | ||
125 | + qemu_announce_timer_reset(&n->announce_timer, migrate_announce_params(), | ||
126 | + QEMU_CLOCK_VIRTUAL, | ||
127 | + virtio_net_announce_timer, n); | ||
128 | |||
129 | if (n->netclient_type) { | ||
130 | /* | ||
131 | @@ -XXX,XX +XXX,XX @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) | ||
132 | virtio_net_del_queue(n, i); | ||
133 | } | ||
134 | |||
135 | - timer_del(n->announce_timer); | ||
136 | - timer_free(n->announce_timer); | ||
137 | + qemu_announce_timer_del(&n->announce_timer); | ||
138 | g_free(n->vqs); | ||
139 | qemu_del_nic(n->nic); | ||
140 | virtio_net_rsc_cleanup(n); | ||
141 | diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h | ||
142 | index XXXXXXX..XXXXXXX 100644 | ||
143 | --- a/include/hw/virtio/virtio-net.h | ||
144 | +++ b/include/hw/virtio/virtio-net.h | ||
145 | @@ -XXX,XX +XXX,XX @@ | ||
146 | #include "qemu/units.h" | ||
147 | #include "standard-headers/linux/virtio_net.h" | ||
148 | #include "hw/virtio/virtio.h" | ||
149 | +#include "net/announce.h" | ||
150 | |||
151 | #define TYPE_VIRTIO_NET "virtio-net-device" | ||
152 | #define VIRTIO_NET(obj) \ | ||
153 | @@ -XXX,XX +XXX,XX @@ struct VirtIONet { | ||
154 | char *netclient_name; | ||
155 | char *netclient_type; | ||
156 | uint64_t curr_guest_offloads; | ||
157 | - QEMUTimer *announce_timer; | ||
158 | - int announce_counter; | ||
159 | + AnnounceTimer announce_timer; | ||
160 | bool needs_vnet_hdr_swap; | ||
161 | bool mtu_bypass_backend; | ||
162 | }; | ||
43 | -- | 163 | -- |
44 | 2.7.4 | 164 | 2.5.0 |
45 | 165 | ||
46 | 166 | diff view generated by jsdifflib |
1 | The auto genreated id for "-nic" has "_" prefix which can't satisfy | 1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> |
---|---|---|---|
2 | the well-formed id check that is introduced by | 2 | |
3 | 871579b9834aca517dc2d4941691a1d2082db6f2 ("net: validate that ids are | 3 | Switch the announcements to using the new announce timer. |
4 | well formed"). Fix this by simply removing the "__" prefix. | 4 | Move the code that does it to announce.c rather than savevm |
5 | 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> | ||
6 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 13 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
7 | --- | 14 | --- |
8 | net/net.c | 2 +- | 15 | include/migration/misc.h | 10 ------- |
9 | 1 file changed, 1 insertion(+), 1 deletion(-) | 16 | include/net/announce.h | 2 ++ |
10 | 17 | include/sysemu/sysemu.h | 2 -- | |
11 | diff --git a/net/net.c b/net/net.c | 18 | migration/migration.c | 2 +- |
12 | index XXXXXXX..XXXXXXX 100644 | 19 | migration/migration.h | 4 +++ |
13 | --- a/net/net.c | 20 | migration/savevm.c | 72 ++---------------------------------------------- |
14 | +++ b/net/net.c | 21 | migration/trace-events | 1 - |
15 | @@ -XXX,XX +XXX,XX @@ static int net_param_nic(void *dummy, QemuOpts *opts, Error **errp) | 22 | net/announce.c | 68 +++++++++++++++++++++++++++++++++++++++++++++ |
16 | /* Create an ID if the user did not specify one */ | 23 | net/trace-events | 3 ++ |
17 | nd_id = g_strdup(qemu_opts_id(opts)); | 24 | 9 files changed, 81 insertions(+), 83 deletions(-) |
18 | if (!nd_id) { | 25 | |
19 | - nd_id = g_strdup_printf("__org.qemu.nic%i", idx); | 26 | diff --git a/include/migration/misc.h b/include/migration/misc.h |
20 | + nd_id = g_strdup_printf("org.qemu.nic%i", idx); | 27 | index XXXXXXX..XXXXXXX 100644 |
21 | qemu_opts_set_id(opts, nd_id); | 28 | --- a/include/migration/misc.h |
22 | } | 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" | ||
23 | 318 | ||
24 | -- | 319 | -- |
25 | 2.7.4 | 320 | 2.5.0 |
26 | 321 | ||
27 | 322 | diff view generated by jsdifflib |
1 | Some NIC supports loopback mode and this is done by calling | 1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> |
---|---|---|---|
2 | nc->info->receive() directly which in fact suppresses the effort of | ||
3 | reentrancy check that is done in qemu_net_queue_send(). | ||
4 | 2 | ||
5 | Unfortunately we can't use qemu_net_queue_send() here since for | 3 | Some network devices have a capability to do self announcements |
6 | loopback there's no sender as peer, so this patch introduce a | 4 | (ex: virtio-net). Add infrastructure that would allow devices |
7 | qemu_receive_packet() which is used for implementing loopback mode | 5 | to expose this ability. |
8 | for a NIC with this check. | ||
9 | 6 | ||
10 | NIC that supports loopback mode will be converted to this helper. | 7 | Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com> |
11 | 8 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | |
12 | This is intended to address CVE-2021-3416. | 9 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> |
13 | |||
14 | Cc: Prasad J Pandit <ppandit@redhat.com> | ||
15 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
16 | Cc: qemu-stable@nongnu.org | ||
17 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 10 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
18 | --- | 11 | --- |
19 | include/net/net.h | 5 +++++ | 12 | include/net/net.h | 2 ++ |
20 | include/net/queue.h | 8 ++++++++ | 13 | net/announce.c | 5 +++++ |
21 | net/net.c | 38 +++++++++++++++++++++++++++++++------- | 14 | 2 files changed, 7 insertions(+) |
22 | net/queue.c | 22 ++++++++++++++++++++++ | ||
23 | 4 files changed, 66 insertions(+), 7 deletions(-) | ||
24 | 15 | ||
25 | diff --git a/include/net/net.h b/include/net/net.h | 16 | diff --git a/include/net/net.h b/include/net/net.h |
26 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
27 | --- a/include/net/net.h | 18 | --- a/include/net/net.h |
28 | +++ b/include/net/net.h | 19 | +++ b/include/net/net.h |
29 | @@ -XXX,XX +XXX,XX @@ void *qemu_get_nic_opaque(NetClientState *nc); | 20 | @@ -XXX,XX +XXX,XX @@ typedef int (SetVnetLE)(NetClientState *, bool); |
30 | void qemu_del_net_client(NetClientState *nc); | 21 | typedef int (SetVnetBE)(NetClientState *, bool); |
31 | typedef void (*qemu_nic_foreach)(NICState *nic, void *opaque); | 22 | typedef struct SocketReadState SocketReadState; |
32 | void qemu_foreach_nic(qemu_nic_foreach func, void *opaque); | 23 | typedef void (SocketReadStateFinalize)(SocketReadState *rs); |
33 | +int qemu_can_receive_packet(NetClientState *nc); | 24 | +typedef void (NetAnnounce)(NetClientState *); |
34 | int qemu_can_send_packet(NetClientState *nc); | 25 | |
35 | ssize_t qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, | 26 | typedef struct NetClientInfo { |
36 | int iovcnt); | 27 | NetClientDriver type; |
37 | ssize_t qemu_sendv_packet_async(NetClientState *nc, const struct iovec *iov, | 28 | @@ -XXX,XX +XXX,XX @@ typedef struct NetClientInfo { |
38 | int iovcnt, NetPacketSent *sent_cb); | 29 | SetVnetHdrLen *set_vnet_hdr_len; |
39 | ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size); | 30 | SetVnetLE *set_vnet_le; |
40 | +ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size); | 31 | SetVnetBE *set_vnet_be; |
41 | +ssize_t qemu_receive_packet_iov(NetClientState *nc, | 32 | + NetAnnounce *announce; |
42 | + const struct iovec *iov, | 33 | } NetClientInfo; |
43 | + int iovcnt); | 34 | |
44 | ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size); | 35 | struct NetClientState { |
45 | ssize_t qemu_send_packet_async(NetClientState *nc, const uint8_t *buf, | 36 | diff --git a/net/announce.c b/net/announce.c |
46 | int size, NetPacketSent *sent_cb); | ||
47 | diff --git a/include/net/queue.h b/include/net/queue.h | ||
48 | index XXXXXXX..XXXXXXX 100644 | 37 | index XXXXXXX..XXXXXXX 100644 |
49 | --- a/include/net/queue.h | 38 | --- a/net/announce.c |
50 | +++ b/include/net/queue.h | 39 | +++ b/net/announce.c |
51 | @@ -XXX,XX +XXX,XX @@ void qemu_net_queue_append_iov(NetQueue *queue, | 40 | @@ -XXX,XX +XXX,XX @@ static void qemu_announce_self_iter(NICState *nic, void *opaque) |
52 | 41 | len = announce_self_create(buf, nic->conf->macaddr.a); | |
53 | void qemu_del_net_queue(NetQueue *queue); | 42 | |
54 | 43 | qemu_send_packet_raw(qemu_get_queue(nic), buf, len); | |
55 | +ssize_t qemu_net_queue_receive(NetQueue *queue, | ||
56 | + const uint8_t *data, | ||
57 | + size_t size); | ||
58 | + | 44 | + |
59 | +ssize_t qemu_net_queue_receive_iov(NetQueue *queue, | 45 | + /* if the NIC provides it's own announcement support, use it as well */ |
60 | + const struct iovec *iov, | 46 | + if (nic->ncs->info->announce) { |
61 | + int iovcnt); | 47 | + nic->ncs->info->announce(nic->ncs); |
62 | + | 48 | + } |
63 | ssize_t qemu_net_queue_send(NetQueue *queue, | ||
64 | NetClientState *sender, | ||
65 | unsigned flags, | ||
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 @@ int qemu_set_vnet_be(NetClientState *nc, bool is_be) | ||
71 | #endif | ||
72 | } | 49 | } |
73 | 50 | static void qemu_announce_self_once(void *opaque) | |
74 | +int qemu_can_receive_packet(NetClientState *nc) | ||
75 | +{ | ||
76 | + if (nc->receive_disabled) { | ||
77 | + return 0; | ||
78 | + } else if (nc->info->can_receive && | ||
79 | + !nc->info->can_receive(nc)) { | ||
80 | + return 0; | ||
81 | + } | ||
82 | + return 1; | ||
83 | +} | ||
84 | + | ||
85 | int qemu_can_send_packet(NetClientState *sender) | ||
86 | { | 51 | { |
87 | int vm_running = runstate_is_running(); | ||
88 | @@ -XXX,XX +XXX,XX @@ int qemu_can_send_packet(NetClientState *sender) | ||
89 | return 1; | ||
90 | } | ||
91 | |||
92 | - if (sender->peer->receive_disabled) { | ||
93 | - return 0; | ||
94 | - } else if (sender->peer->info->can_receive && | ||
95 | - !sender->peer->info->can_receive(sender->peer)) { | ||
96 | - return 0; | ||
97 | - } | ||
98 | - return 1; | ||
99 | + return qemu_can_receive_packet(sender->peer); | ||
100 | } | ||
101 | |||
102 | static ssize_t filter_receive_iov(NetClientState *nc, | ||
103 | @@ -XXX,XX +XXX,XX @@ ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size) | ||
104 | return qemu_send_packet_async(nc, buf, size, NULL); | ||
105 | } | ||
106 | |||
107 | +ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size) | ||
108 | +{ | ||
109 | + if (!qemu_can_receive_packet(nc)) { | ||
110 | + return 0; | ||
111 | + } | ||
112 | + | ||
113 | + return qemu_net_queue_receive(nc->incoming_queue, buf, size); | ||
114 | +} | ||
115 | + | ||
116 | +ssize_t qemu_receive_packet_iov(NetClientState *nc, const struct iovec *iov, | ||
117 | + int iovcnt) | ||
118 | +{ | ||
119 | + if (!qemu_can_receive_packet(nc)) { | ||
120 | + return 0; | ||
121 | + } | ||
122 | + | ||
123 | + return qemu_net_queue_receive_iov(nc->incoming_queue, iov, iovcnt); | ||
124 | +} | ||
125 | + | ||
126 | ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size) | ||
127 | { | ||
128 | return qemu_send_packet_async_with_flags(nc, QEMU_NET_PACKET_FLAG_RAW, | ||
129 | diff --git a/net/queue.c b/net/queue.c | ||
130 | index XXXXXXX..XXXXXXX 100644 | ||
131 | --- a/net/queue.c | ||
132 | +++ b/net/queue.c | ||
133 | @@ -XXX,XX +XXX,XX @@ static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue, | ||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | +ssize_t qemu_net_queue_receive(NetQueue *queue, | ||
138 | + const uint8_t *data, | ||
139 | + size_t size) | ||
140 | +{ | ||
141 | + if (queue->delivering) { | ||
142 | + return 0; | ||
143 | + } | ||
144 | + | ||
145 | + return qemu_net_queue_deliver(queue, NULL, 0, data, size); | ||
146 | +} | ||
147 | + | ||
148 | +ssize_t qemu_net_queue_receive_iov(NetQueue *queue, | ||
149 | + const struct iovec *iov, | ||
150 | + int iovcnt) | ||
151 | +{ | ||
152 | + if (queue->delivering) { | ||
153 | + return 0; | ||
154 | + } | ||
155 | + | ||
156 | + return qemu_net_queue_deliver_iov(queue, NULL, 0, iov, iovcnt); | ||
157 | +} | ||
158 | + | ||
159 | ssize_t qemu_net_queue_send(NetQueue *queue, | ||
160 | NetClientState *sender, | ||
161 | unsigned flags, | ||
162 | -- | 52 | -- |
163 | 2.7.4 | 53 | 2.5.0 |
164 | 54 | ||
165 | 55 | diff view generated by jsdifflib |
1 | From: Paolo Bonzini <pbonzini@redhat.com> | 1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | When a network or network device is created from the command line or HMP, | 3 | Expose the virtio-net self announcement capability and allow |
4 | QemuOpts ensures that the id passes the id_wellformed check. However, | 4 | qemu_announce_self() to call it. |
5 | QMP skips this: | ||
6 | 5 | ||
7 | $ qemu-system-x86_64 -qmp stdio -S -nic user,id=123/456 | 6 | These announces are caused by something external (i.e. the |
8 | qemu-system-x86_64: -nic user,id=123/456: Parameter id expects an identifier | 7 | announce-self command); they won't trigger if the migration |
9 | Identifiers consist of letters, digits, -, ., _, starting with a letter. | 8 | counter is triggering announces at the same time. |
10 | 9 | ||
11 | $ qemu-system-x86_64 -qmp stdio -S | 10 | Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com> |
12 | {"execute":"qmp_capabilities"} | 11 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> |
13 | {"return": {}} | 12 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> |
14 | {"execute":"netdev_add", "arguments": {"type": "user", "id": "123/456"}} | ||
15 | {"return": {}} | ||
16 | |||
17 | After: | ||
18 | |||
19 | $ qemu-system-x86_64 -qmp stdio -S | ||
20 | {"execute":"qmp_capabilities"} | ||
21 | {"return": {}} | ||
22 | {"execute":"netdev_add", "arguments": {"type": "user", "id": "123/456"}} | ||
23 | {"error": {"class": "GenericError", "desc": "Parameter "id" expects an identifier"}} | ||
24 | |||
25 | Validity checks should be performed always at the bottom of the call chain, | ||
26 | because QMP skips all the steps above. Do this for the network subsystem. | ||
27 | |||
28 | Cc: Jason Wang <jasowang@redhat.com> | ||
29 | Reviewed-by: Eric Blake <eblake@redhat.com> | ||
30 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
31 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 13 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
32 | --- | 14 | --- |
33 | net/net.c | 12 ++++++++++++ | 15 | hw/net/trace-events | 1 + |
34 | 1 file changed, 12 insertions(+) | 16 | hw/net/virtio-net.c | 35 ++++++++++++++++++++++++++++++++--- |
17 | 2 files changed, 33 insertions(+), 3 deletions(-) | ||
35 | 18 | ||
36 | diff --git a/net/net.c b/net/net.c | 19 | diff --git a/hw/net/trace-events b/hw/net/trace-events |
37 | index XXXXXXX..XXXXXXX 100644 | 20 | index XXXXXXX..XXXXXXX 100644 |
38 | --- a/net/net.c | 21 | --- a/hw/net/trace-events |
39 | +++ b/net/net.c | 22 | +++ b/hw/net/trace-events |
40 | @@ -XXX,XX +XXX,XX @@ | 23 | @@ -XXX,XX +XXX,XX @@ sunhme_rx_desc(uint32_t addr, int offset, uint32_t status, int len, int cr, int |
41 | #include "qemu/cutils.h" | 24 | sunhme_rx_xsum_calc(uint16_t xsum) "calculated incoming xsum as 0x%x" |
42 | #include "qemu/config-file.h" | 25 | |
43 | #include "qemu/ctype.h" | 26 | # hw/net/virtio-net.c |
44 | +#include "qemu/id.h" | 27 | +virtio_net_announce_notify(void) "" |
45 | #include "qemu/iov.h" | 28 | virtio_net_announce_timer(int round) "%d" |
46 | #include "qemu/qemu-print.h" | 29 | virtio_net_handle_announce(int round) "%d" |
47 | #include "qemu/main-loop.h" | 30 | virtio_net_post_load_device(void) |
48 | @@ -XXX,XX +XXX,XX @@ static int net_client_init1(const Netdev *netdev, bool is_netdev, Error **errp) | 31 | diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c |
49 | } | 32 | index XXXXXXX..XXXXXXX 100644 |
50 | } | 33 | --- a/hw/net/virtio-net.c |
51 | 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(); | ||
43 | + | ||
44 | + net->status |= VIRTIO_NET_S_ANNOUNCE; | ||
45 | + virtio_notify_config(vdev); | ||
46 | +} | ||
47 | + | ||
48 | static void virtio_net_announce_timer(void *opaque) | ||
49 | { | ||
50 | VirtIONet *n = opaque; | ||
51 | - VirtIODevice *vdev = VIRTIO_DEVICE(n); | ||
52 | trace_virtio_net_announce_timer(n->announce_timer.round); | ||
53 | |||
54 | n->announce_timer.round--; | ||
55 | - n->status |= VIRTIO_NET_S_ANNOUNCE; | ||
56 | - virtio_notify_config(vdev); | ||
57 | + virtio_net_announce_notify(n); | ||
58 | +} | ||
59 | + | ||
60 | +static void virtio_net_announce(NetClientState *nc) | ||
61 | +{ | ||
62 | + VirtIONet *n = qemu_get_nic_opaque(nc); | ||
63 | + VirtIODevice *vdev = VIRTIO_DEVICE(n); | ||
64 | + | ||
52 | + /* | 65 | + /* |
53 | + * The id for -net has already been checked by QemuOpts and | 66 | + * Make sure the virtio migration announcement timer isn't running |
54 | + * could be automatically generated, in which case it is not | 67 | + * If it is, let it trigger announcement so that we do not cause |
55 | + * well-formed by design. HMP and QMP only call us with | 68 | + * confusion. |
56 | + * is_netdev == true. | ||
57 | + */ | 69 | + */ |
58 | + if (is_netdev && !id_wellformed(netdev->id)) { | 70 | + if (n->announce_timer.round) { |
59 | + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "id", "an identifier"); | 71 | + return; |
60 | + return -1; | ||
61 | + } | 72 | + } |
62 | + | 73 | + |
63 | nc = qemu_find_netdev(netdev->id); | 74 | + if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) && |
64 | if (nc) { | 75 | + virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) { |
65 | error_setg(errp, "Duplicate ID '%s'", netdev->id); | 76 | + virtio_net_announce_notify(n); |
77 | + } | ||
78 | } | ||
79 | |||
80 | static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) | ||
81 | @@ -XXX,XX +XXX,XX @@ static NetClientInfo net_virtio_info = { | ||
82 | .receive = virtio_net_receive, | ||
83 | .link_status_changed = virtio_net_set_link_status, | ||
84 | .query_rx_filter = virtio_net_query_rxfilter, | ||
85 | + .announce = virtio_net_announce, | ||
86 | }; | ||
87 | |||
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 | /* | ||
66 | -- | 97 | -- |
67 | 2.7.4 | 98 | 2.5.0 |
68 | 99 | ||
69 | 100 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | This patch switches to use qemu_receive_packet() which can detect | ||
2 | reentrancy and return early. | ||
3 | 1 | ||
4 | This is intended to address CVE-2021-3416. | ||
5 | |||
6 | Cc: Prasad J Pandit <ppandit@redhat.com> | ||
7 | Cc: qemu-stable@nongnu.org | ||
8 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
9 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
10 | --- | ||
11 | hw/net/e1000.c | 2 +- | ||
12 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
13 | |||
14 | diff --git a/hw/net/e1000.c b/hw/net/e1000.c | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/hw/net/e1000.c | ||
17 | +++ b/hw/net/e1000.c | ||
18 | @@ -XXX,XX +XXX,XX @@ e1000_send_packet(E1000State *s, const uint8_t *buf, int size) | ||
19 | |||
20 | NetClientState *nc = qemu_get_queue(s->nic); | ||
21 | if (s->phy_reg[PHY_CTRL] & MII_CR_LOOPBACK) { | ||
22 | - nc->info->receive(nc, buf, size); | ||
23 | + qemu_receive_packet(nc, buf, size); | ||
24 | } else { | ||
25 | qemu_send_packet(nc, buf, size); | ||
26 | } | ||
27 | -- | ||
28 | 2.7.4 | ||
29 | |||
30 | diff view generated by jsdifflib |
Deleted patch | |||
---|---|---|---|
1 | This patch switches to use qemu_receive_packet() which can detect | ||
2 | reentrancy and return early. | ||
3 | 1 | ||
4 | This is intended to address CVE-2021-3416. | ||
5 | |||
6 | Cc: Prasad J Pandit <ppandit@redhat.com> | ||
7 | Cc: qemu-stable@nongnu.org | ||
8 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com | ||
9 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
10 | --- | ||
11 | hw/net/dp8393x.c | 2 +- | ||
12 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
13 | |||
14 | diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c | ||
15 | index XXXXXXX..XXXXXXX 100644 | ||
16 | --- a/hw/net/dp8393x.c | ||
17 | +++ b/hw/net/dp8393x.c | ||
18 | @@ -XXX,XX +XXX,XX @@ static void dp8393x_do_transmit_packets(dp8393xState *s) | ||
19 | s->regs[SONIC_TCR] |= SONIC_TCR_CRSL; | ||
20 | if (nc->info->can_receive(nc)) { | ||
21 | s->loopback_packet = 1; | ||
22 | - nc->info->receive(nc, s->tx_buffer, tx_len); | ||
23 | + qemu_receive_packet(nc, s->tx_buffer, tx_len); | ||
24 | } | ||
25 | } else { | ||
26 | /* Transmit packet */ | ||
27 | -- | ||
28 | 2.7.4 | ||
29 | |||
30 | diff view generated by jsdifflib |
1 | This patch switches to use qemu_receive_receive_iov() which can detect | 1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> |
---|---|---|---|
2 | reentrancy and return early. | ||
3 | 2 | ||
4 | This is intended to address CVE-2021-3416. | 3 | Add a qmp command that can trigger guest announcements. |
5 | 4 | ||
6 | Cc: Prasad J Pandit <ppandit@redhat.com> | 5 | It uses its own announce-timer instance, and parameters |
7 | Cc: qemu-stable@nongnu.org | 6 | passed to it explicitly in the command. |
8 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | 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> | ||
9 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 16 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
10 | --- | 17 | --- |
11 | hw/net/net_tx_pkt.c | 2 +- | 18 | net/announce.c | 7 +++++++ |
12 | 1 file changed, 1 insertion(+), 1 deletion(-) | 19 | qapi/net.json | 20 ++++++++++++++++++++ |
20 | 2 files changed, 27 insertions(+) | ||
13 | 21 | ||
14 | diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c | 22 | diff --git a/net/announce.c b/net/announce.c |
15 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/hw/net/net_tx_pkt.c | 24 | --- a/net/announce.c |
17 | +++ b/hw/net/net_tx_pkt.c | 25 | +++ b/net/announce.c |
18 | @@ -XXX,XX +XXX,XX @@ static inline void net_tx_pkt_sendv(struct NetTxPkt *pkt, | 26 | @@ -XXX,XX +XXX,XX @@ |
19 | NetClientState *nc, const struct iovec *iov, int iov_cnt) | 27 | #include "net/net.h" |
20 | { | 28 | #include "qapi/clone-visitor.h" |
21 | if (pkt->is_loopback) { | 29 | #include "qapi/qapi-visit-net.h" |
22 | - nc->info->receive_iov(nc, iov, iov_cnt); | 30 | +#include "qapi/qapi-commands-net.h" |
23 | + qemu_receive_packet_iov(nc, iov, iov_cnt); | 31 | #include "trace.h" |
24 | } else { | 32 | |
25 | qemu_sendv_packet(nc, iov, iov_cnt); | 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); | ||
26 | } | 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'} | ||
27 | -- | 72 | -- |
28 | 2.7.4 | 73 | 2.5.0 |
29 | 74 | ||
30 | 75 | diff view generated by jsdifflib |
1 | This patch switches to use qemu_receive_packet() which can detect | 1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> |
---|---|---|---|
2 | reentrancy and return early. | ||
3 | 2 | ||
4 | This is intended to address CVE-2021-3416. | 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. | ||
5 | 6 | ||
6 | Cc: Prasad J Pandit <ppandit@redhat.com> | 7 | Signend-off-by: Vladislav Yasevich <vyasevic@redhat.com> |
7 | Cc: qemu-stable@nongnu.org | 8 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> |
8 | Reviewed-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> | 9 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> |
9 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
10 | Reviewed-by: Alistair Francis <alistair.francis@wdc.com> | ||
11 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 10 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
12 | --- | 11 | --- |
13 | hw/net/sungem.c | 2 +- | 12 | hmp-commands.hx | 16 ++++++++++++++++ |
14 | 1 file changed, 1 insertion(+), 1 deletion(-) | 13 | hmp.c | 5 +++++ |
14 | hmp.h | 1 + | ||
15 | tests/test-hmp.c | 1 + | ||
16 | 4 files changed, 23 insertions(+) | ||
15 | 17 | ||
16 | diff --git a/hw/net/sungem.c b/hw/net/sungem.c | 18 | diff --git a/hmp-commands.hx b/hmp-commands.hx |
17 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/hw/net/sungem.c | 20 | --- a/hmp-commands.hx |
19 | +++ b/hw/net/sungem.c | 21 | +++ b/hmp-commands.hx |
20 | @@ -XXX,XX +XXX,XX @@ static void sungem_send_packet(SunGEMState *s, const uint8_t *buf, | 22 | @@ -XXX,XX +XXX,XX @@ stops because the size limit is reached. |
21 | NetClientState *nc = qemu_get_queue(s->nic); | 23 | ETEXI |
22 | 24 | ||
23 | if (s->macregs[MAC_XIFCFG >> 2] & MAC_XIFCFG_LBCK) { | 25 | { |
24 | - nc->info->receive(nc, buf, size); | 26 | + .name = "announce_self", |
25 | + qemu_receive_packet(nc, buf, size); | 27 | + .args_type = "", |
26 | } else { | 28 | + .params = "", |
27 | qemu_send_packet(nc, buf, size); | 29 | + .help = "Trigger GARP/RARP announcements", |
28 | } | 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", | ||
29 | -- | 85 | -- |
30 | 2.7.4 | 86 | 2.5.0 |
31 | 87 | ||
32 | 88 | diff view generated by jsdifflib |
1 | This patch switches to use qemu_receive_packet() which can detect | 1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> |
---|---|---|---|
2 | reentrancy and return early. | ||
3 | 2 | ||
4 | This is intended to address CVE-2021-3416. | 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). | ||
5 | 5 | ||
6 | Cc: Prasad J Pandit <ppandit@redhat.com> | 6 | Signed-off-by: Vlad Yasevich <vyasevic@redhat.com> |
7 | Cc: qemu-stable@nongnu.org | 7 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> |
8 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | 8 | Reviewed-by: Michael S. Tsirkin <mst@redhat.com> |
9 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 9 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
10 | --- | 10 | --- |
11 | hw/net/msf2-emac.c | 2 +- | 11 | tests/Makefile.include | 3 ++ |
12 | 1 file changed, 1 insertion(+), 1 deletion(-) | 12 | tests/test-announce-self.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++ |
13 | 2 files changed, 85 insertions(+) | ||
14 | create mode 100644 tests/test-announce-self.c | ||
13 | 15 | ||
14 | diff --git a/hw/net/msf2-emac.c b/hw/net/msf2-emac.c | 16 | diff --git a/tests/Makefile.include b/tests/Makefile.include |
15 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/hw/net/msf2-emac.c | 18 | --- a/tests/Makefile.include |
17 | +++ b/hw/net/msf2-emac.c | 19 | +++ b/tests/Makefile.include |
18 | @@ -XXX,XX +XXX,XX @@ static void msf2_dma_tx(MSF2EmacState *s) | 20 | @@ -XXX,XX +XXX,XX @@ check-qtest-i386-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF) |
19 | * R_CFG1 bit 0 is set. | 21 | check-qtest-i386-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF) |
20 | */ | 22 | check-qtest-i386-$(CONFIG_RTL8139_PCI) += tests/test-filter-redirector$(EXESUF) |
21 | if (s->regs[R_CFG1] & R_CFG1_LB_EN_MASK) { | 23 | check-qtest-i386-y += tests/migration-test$(EXESUF) |
22 | - nc->info->receive(nc, buf, size); | 24 | +check-qtest-i386-y += tests/test-announce-self$(EXESUF) |
23 | + qemu_receive_packet(nc, buf, size); | 25 | check-qtest-i386-y += tests/test-x86-cpuid-compat$(EXESUF) |
24 | } else { | 26 | check-qtest-i386-y += tests/numa-test$(EXESUF) |
25 | qemu_send_packet(nc, buf, size); | 27 | check-qtest-x86_64-y += $(check-qtest-i386-y) |
26 | } | 28 | @@ -XXX,XX +XXX,XX @@ check-qtest-ppc64-$(CONFIG_PSERIES) += tests/spapr-phb-test$(EXESUF) |
29 | check-qtest-ppc64-$(CONFIG_PSERIES) += tests/device-plug-test$(EXESUF) | ||
30 | check-qtest-ppc64-$(CONFIG_POWERNV) += tests/pnv-xscom-test$(EXESUF) | ||
31 | check-qtest-ppc64-y += tests/migration-test$(EXESUF) | ||
32 | +check-qtest-ppc64-y += tests/test-announce-self$(EXESUF) | ||
33 | check-qtest-ppc64-$(CONFIG_PSERIES) += tests/rtas-test$(EXESUF) | ||
34 | check-qtest-ppc64-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF) | ||
35 | check-qtest-ppc64-$(CONFIG_USB_OHCI) += tests/usb-hcd-ohci-test$(EXESUF) | ||
36 | @@ -XXX,XX +XXX,XX @@ tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-usb-obj-y) | ||
37 | tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y) | ||
38 | tests/cpu-plug-test$(EXESUF): tests/cpu-plug-test.o | ||
39 | tests/migration-test$(EXESUF): tests/migration-test.o | ||
40 | +tests/test-announce-self$(EXESUF): tests/test-announce-self.o | ||
41 | tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o $(test-util-obj-y) \ | ||
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 | + */ | ||
59 | + | ||
60 | +#include "qemu/osdep.h" | ||
61 | +#include "libqtest.h" | ||
62 | +#include "qapi/qmp/qdict.h" | ||
63 | +#include "qemu-common.h" | ||
64 | +#include "qemu/sockets.h" | ||
65 | +#include "qemu/iov.h" | ||
66 | +#include "libqos/libqos-pc.h" | ||
67 | +#include "libqos/libqos-spapr.h" | ||
68 | + | ||
69 | +#ifndef ETH_P_RARP | ||
70 | +#define ETH_P_RARP 0x8035 | ||
71 | +#endif | ||
72 | + | ||
73 | +static QTestState *test_init(int socket) | ||
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 | +} | ||
27 | -- | 132 | -- |
28 | 2.7.4 | 133 | 2.5.0 |
29 | 134 | ||
30 | 135 | diff view generated by jsdifflib |