1 | The following changes since commit 7d0e02405fc02a181319b1ab8681d2f72246b7c6: | 1 | The following changes since commit 6157b0e19721aadb4c7fdcfe57b2924af6144b14: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/vivier2/tags/trivial-patches-pull-request' into staging (2019-07-01 17:40:32 +0100) | 3 | Merge remote-tracking branch 'remotes/vivier2/tags/linux-user-for-6.0-pull-request' into staging (2021-03-14 17:47:49 +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 0e8818f023616677416840d6ddc880db8de3c967: | 9 | for you to fetch changes up to f2e8319d456724c3d8514d943dc4607e2f08e88a: |
10 | 10 | ||
11 | migration/colo.c: Add missed filter notify for Xen COLO. (2019-07-02 10:21:07 +0800) | 11 | net: Do not fill legacy info_str for backends (2021-03-15 16:41:22 +0800) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | 14 | ||
15 | Changes since V1: | ||
16 | - drop the workaound of "-nic" id and fix the merge | ||
17 | - add the series of query-netdev | ||
18 | |||
15 | ---------------------------------------------------------------- | 19 | ---------------------------------------------------------------- |
16 | Cédric Le Goater (1): | 20 | Alexander Bulekov (4): |
17 | ftgmac100: do not link to netdev | 21 | rtl8139: switch to use qemu_receive_packet() for loopback |
22 | pcnet: switch to use qemu_receive_packet() for loopback | ||
23 | cadence_gem: switch to use qemu_receive_packet() for loopback | ||
24 | lan9118: switch to use qemu_receive_packet() for loopback | ||
18 | 25 | ||
19 | Dr. David Alan Gilbert (5): | 26 | Alexey Kirillov (5): |
20 | net/announce: Allow optional list of interfaces | 27 | qapi: net: Add query-netdev command |
21 | net/announce: Add HMP optional interface list | 28 | tests: Add tests for query-netdev command |
22 | net/announce: Add optional ID | 29 | net: Move NetClientState.info_str to dynamic allocations |
23 | net/announce: Add HMP optional ID | 30 | hmp: Use QAPI NetdevInfo in hmp_info_network |
24 | net/announce: Expand test for stopping self announce | 31 | net: Do not fill legacy info_str for backends |
25 | 32 | ||
26 | Markus Armbruster (2): | 33 | Bin Meng (1): |
27 | MAINTAINERS: Add qemu-bridge-helper.c to "Network device backends" | 34 | net: Fix build error when DEBUG_NET is on |
28 | qemu-bridge-helper: Document known shortcomings | ||
29 | 35 | ||
30 | Stefano Garzarella (4): | 36 | Cornelia Huck (1): |
31 | net: fix assertion failure when ipv6-prefixlen is not a number | 37 | pvrdma: wean code off pvrdma_ring.h kernel header |
32 | net: avoid using variable length array in net_client_init() | ||
33 | net: use g_strsplit() for parsing host address and port | ||
34 | net: remove unused get_str_sep() function | ||
35 | 38 | ||
36 | Zhang Chen (5): | 39 | Jason Wang (8): |
37 | COLO-compare: Add new parameter to communicate with remote colo-frame | 40 | virtio-net: calculating proper msix vectors on init |
38 | COLO-compare: Add remote notification chardev handler frame | 41 | e1000: fail early for evil descriptor |
39 | COLO-compare: Make the compare_chr_send() can send notification message. | 42 | net: introduce qemu_receive_packet() |
40 | COLO-compare: Add colo-compare remote notify support | 43 | e1000: switch to use qemu_receive_packet() for loopback |
41 | migration/colo.c: Add missed filter notify for Xen COLO. | 44 | dp8393x: switch to use qemu_receive_packet() for loopback packet |
45 | msf2-mac: switch to use qemu_receive_packet() for loopback | ||
46 | sungem: switch to use qemu_receive_packet() for loopback | ||
47 | tx_pkt: switch to use qemu_receive_packet_iov() for loopback | ||
42 | 48 | ||
43 | MAINTAINERS | 1 + | 49 | Paolo Bonzini (1): |
44 | hmp-commands.hx | 7 ++- | 50 | net: validate that ids are well formed |
45 | hw/net/ftgmac100.c | 2 - | 51 | |
46 | hw/net/virtio-net.c | 4 +- | 52 | hw/core/machine.c | 1 + |
47 | include/net/announce.h | 8 ++- | 53 | hw/net/cadence_gem.c | 4 +- |
48 | migration/colo.c | 2 + | 54 | hw/net/dp8393x.c | 2 +- |
49 | monitor/hmp-cmds.c | 41 ++++++++++++- | 55 | hw/net/e1000.c | 6 +- |
50 | net/announce.c | 89 +++++++++++++++++++++++---- | 56 | hw/net/lan9118.c | 2 +- |
51 | net/colo-compare.c | 155 ++++++++++++++++++++++++++++++++++++++++++------ | 57 | hw/net/msf2-emac.c | 2 +- |
52 | net/net.c | 99 +++++++++++++++---------------- | 58 | hw/net/net_tx_pkt.c | 2 +- |
53 | net/trace-events | 3 +- | 59 | hw/net/pcnet.c | 2 +- |
54 | qapi/net.json | 16 ++++- | 60 | hw/net/rtl8139.c | 2 +- |
55 | qemu-bridge-helper.c | 12 +++- | 61 | hw/net/sungem.c | 2 +- |
56 | qemu-options.hx | 33 ++++++++++- | 62 | hw/net/xen_nic.c | 5 +- |
57 | tests/virtio-net-test.c | 57 +++++++++++++++++- | 63 | hw/rdma/vmw/pvrdma.h | 5 +- |
58 | 15 files changed, 430 insertions(+), 99 deletions(-) | 64 | hw/rdma/vmw/pvrdma_cmd.c | 6 +- |
65 | hw/rdma/vmw/pvrdma_dev_ring.c | 41 +++-- | ||
66 | hw/rdma/vmw/pvrdma_dev_ring.h | 9 +- | ||
67 | hw/rdma/vmw/pvrdma_main.c | 4 +- | ||
68 | hw/virtio/virtio-net-pci.c | 10 +- | ||
69 | include/net/net.h | 10 +- | ||
70 | include/net/queue.h | 8 + | ||
71 | include/qapi/hmp-output-visitor.h | 30 ++++ | ||
72 | .../drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h | 114 ------------ | ||
73 | net/l2tpv3.c | 8 +- | ||
74 | net/net.c | 117 +++++++++++-- | ||
75 | net/netmap.c | 7 + | ||
76 | net/queue.c | 22 +++ | ||
77 | net/slirp.c | 124 ++++++++++++- | ||
78 | net/socket.c | 92 +++++++--- | ||
79 | net/tap-win32.c | 10 +- | ||
80 | net/tap.c | 107 ++++++++++-- | ||
81 | net/vde.c | 25 ++- | ||
82 | net/vhost-user.c | 20 ++- | ||
83 | net/vhost-vdpa.c | 15 +- | ||
84 | qapi/hmp-output-visitor.c | 193 +++++++++++++++++++++ | ||
85 | qapi/meson.build | 1 + | ||
86 | qapi/net.json | 80 +++++++++ | ||
87 | scripts/update-linux-headers.sh | 3 +- | ||
88 | tests/qtest/meson.build | 3 + | ||
89 | tests/qtest/test-query-netdev.c | 120 +++++++++++++ | ||
90 | 38 files changed, 990 insertions(+), 224 deletions(-) | ||
91 | create mode 100644 include/qapi/hmp-output-visitor.h | ||
92 | delete mode 100644 include/standard-headers/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h | ||
93 | create mode 100644 qapi/hmp-output-visitor.c | ||
94 | create mode 100644 tests/qtest/test-query-netdev.c | ||
59 | 95 | ||
60 | 96 | ||
97 | diff view generated by jsdifflib |
1 | From: Zhang Chen <chen.zhang@intel.com> | 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. | ||
2 | 5 | ||
3 | This patch make colo-compare can send message to remote COLO frame(Xen) when occur checkpoint. | 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. | ||
4 | 10 | ||
5 | Signed-off-by: Zhang Chen <chen.zhang@intel.com> | 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> | ||
6 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 14 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
7 | --- | 15 | --- |
8 | net/colo-compare.c | 54 ++++++++++++++++++++++++++++++++++++++++++++---------- | 16 | hw/core/machine.c | 1 + |
9 | 1 file changed, 44 insertions(+), 10 deletions(-) | 17 | hw/virtio/virtio-net-pci.c | 10 +++++++++- |
18 | 2 files changed, 10 insertions(+), 1 deletion(-) | ||
10 | 19 | ||
11 | diff --git a/net/colo-compare.c b/net/colo-compare.c | 20 | diff --git a/hw/core/machine.c b/hw/core/machine.c |
12 | index XXXXXXX..XXXXXXX 100644 | 21 | index XXXXXXX..XXXXXXX 100644 |
13 | --- a/net/colo-compare.c | 22 | --- a/hw/core/machine.c |
14 | +++ b/net/colo-compare.c | 23 | +++ b/hw/core/machine.c |
15 | @@ -XXX,XX +XXX,XX @@ enum { | 24 | @@ -XXX,XX +XXX,XX @@ |
16 | SECONDARY_IN, | 25 | GlobalProperty hw_compat_5_2[] = { |
26 | { "ICH9-LPC", "smm-compat", "on"}, | ||
27 | { "PIIX4_PM", "smm-compat", "on"}, | ||
28 | + { "virtio-net-pci", "vectors", "3"}, | ||
17 | }; | 29 | }; |
18 | 30 | const size_t hw_compat_5_2_len = G_N_ELEMENTS(hw_compat_5_2); | |
19 | -static void colo_compare_inconsistency_notify(void) | 31 | |
20 | -{ | 32 | diff --git a/hw/virtio/virtio-net-pci.c b/hw/virtio/virtio-net-pci.c |
21 | - notifier_list_notify(&colo_compare_notifiers, | 33 | index XXXXXXX..XXXXXXX 100644 |
22 | - migrate_get_current()); | 34 | --- a/hw/virtio/virtio-net-pci.c |
23 | -} | 35 | +++ b/hw/virtio/virtio-net-pci.c |
24 | 36 | @@ -XXX,XX +XXX,XX @@ struct VirtIONetPCI { | |
25 | static int compare_chr_send(CompareState *s, | 37 | static Property virtio_net_properties[] = { |
26 | const uint8_t *buf, | 38 | DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, |
27 | @@ -XXX,XX +XXX,XX @@ static int compare_chr_send(CompareState *s, | 39 | VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), |
28 | uint32_t vnet_hdr_len, | 40 | - DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3), |
29 | bool notify_remote_frame); | 41 | + DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, |
30 | 42 | + DEV_NVECTORS_UNSPECIFIED), | |
31 | +static void notify_remote_frame(CompareState *s) | 43 | DEFINE_PROP_END_OF_LIST(), |
32 | +{ | 44 | }; |
33 | + char msg[] = "DO_CHECKPOINT"; | 45 | |
34 | + int ret = 0; | 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); | ||
35 | + | 51 | + |
36 | + ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true); | 52 | + if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) { |
37 | + if (ret < 0) { | 53 | + vpci_dev->nvectors = 2 * MAX(net->nic_conf.peers.queues, 1) |
38 | + error_report("Notify Xen COLO-frame failed"); | 54 | + + 1 /* Config interrupt */ |
55 | + + 1 /* Control vq */; | ||
39 | + } | 56 | + } |
40 | +} | 57 | |
41 | + | 58 | virtio_net_set_netclient_name(&dev->vdev, qdev->id, |
42 | +static void colo_compare_inconsistency_notify(CompareState *s) | 59 | object_get_typename(OBJECT(qdev))); |
43 | +{ | ||
44 | + if (s->notify_dev) { | ||
45 | + notify_remote_frame(s); | ||
46 | + } else { | ||
47 | + notifier_list_notify(&colo_compare_notifiers, | ||
48 | + migrate_get_current()); | ||
49 | + } | ||
50 | +} | ||
51 | + | ||
52 | static gint seq_sorter(Packet *a, Packet *b, gpointer data) | ||
53 | { | ||
54 | struct tcp_hdr *atcp, *btcp; | ||
55 | @@ -XXX,XX +XXX,XX @@ sec: | ||
56 | qemu_hexdump((char *)spkt->data, stderr, | ||
57 | "colo-compare spkt", spkt->size); | ||
58 | |||
59 | - colo_compare_inconsistency_notify(); | ||
60 | + colo_compare_inconsistency_notify(s); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | @@ -XXX,XX +XXX,XX @@ void colo_compare_unregister_notifier(Notifier *notify) | ||
65 | } | ||
66 | |||
67 | static int colo_old_packet_check_one_conn(Connection *conn, | ||
68 | - void *user_data) | ||
69 | + CompareState *s) | ||
70 | { | ||
71 | GList *result = NULL; | ||
72 | int64_t check_time = REGULAR_PACKET_CHECK_MS; | ||
73 | @@ -XXX,XX +XXX,XX @@ static int colo_old_packet_check_one_conn(Connection *conn, | ||
74 | |||
75 | if (result) { | ||
76 | /* Do checkpoint will flush old packet */ | ||
77 | - colo_compare_inconsistency_notify(); | ||
78 | + colo_compare_inconsistency_notify(s); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | @@ -XXX,XX +XXX,XX @@ static void colo_old_packet_check(void *opaque) | ||
83 | * If we find one old packet, stop finding job and notify | ||
84 | * COLO frame do checkpoint. | ||
85 | */ | ||
86 | - g_queue_find_custom(&s->conn_list, NULL, | ||
87 | + g_queue_find_custom(&s->conn_list, s, | ||
88 | (GCompareFunc)colo_old_packet_check_one_conn); | ||
89 | } | ||
90 | |||
91 | @@ -XXX,XX +XXX,XX @@ static void colo_compare_packet(CompareState *s, Connection *conn, | ||
92 | */ | ||
93 | trace_colo_compare_main("packet different"); | ||
94 | g_queue_push_head(&conn->primary_list, pkt); | ||
95 | - colo_compare_inconsistency_notify(); | ||
96 | + | ||
97 | + colo_compare_inconsistency_notify(s); | ||
98 | break; | ||
99 | } | ||
100 | } | ||
101 | @@ -XXX,XX +XXX,XX @@ static void compare_sec_rs_finalize(SocketReadState *sec_rs) | ||
102 | |||
103 | static void compare_notify_rs_finalize(SocketReadState *notify_rs) | ||
104 | { | ||
105 | + CompareState *s = container_of(notify_rs, CompareState, notify_rs); | ||
106 | + | ||
107 | /* Get Xen colo-frame's notify and handle the message */ | ||
108 | + char *data = g_memdup(notify_rs->buf, notify_rs->packet_len); | ||
109 | + char msg[] = "COLO_COMPARE_GET_XEN_INIT"; | ||
110 | + int ret; | ||
111 | + | ||
112 | + if (!strcmp(data, "COLO_USERSPACE_PROXY_INIT")) { | ||
113 | + ret = compare_chr_send(s, (uint8_t *)msg, strlen(msg), 0, true); | ||
114 | + if (ret < 0) { | ||
115 | + error_report("Notify Xen COLO-frame INIT failed"); | ||
116 | + } | ||
117 | + } | ||
118 | + | ||
119 | + if (!strcmp(data, "COLO_CHECKPOINT")) { | ||
120 | + /* colo-compare do checkpoint, flush pri packet and remove sec packet */ | ||
121 | + g_queue_foreach(&s->conn_list, colo_flush_packets, s); | ||
122 | + } | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | -- | 60 | -- |
127 | 2.5.0 | 61 | 2.7.4 |
128 | 62 | ||
129 | 63 | diff view generated by jsdifflib |
1 | From: Stefano Garzarella <sgarzare@redhat.com> | 1 | From: Bin Meng <bin.meng@windriver.com> |
---|---|---|---|
2 | 2 | ||
3 | Since the get_str_sep() function is no longer used in | 3 | "qemu-common.h" should be included to provide the forward declaration |
4 | net/net.c, we can remove it. | 4 | of qemu_hexdump() when DEBUG_NET is on. |
5 | 5 | ||
6 | Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> | 6 | Signed-off-by: Bin Meng <bin.meng@windriver.com> |
7 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | 7 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> |
8 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 8 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
9 | --- | 9 | --- |
10 | net/net.c | 20 -------------------- | 10 | net/net.c | 1 + |
11 | 1 file changed, 20 deletions(-) | 11 | 1 file changed, 1 insertion(+) |
12 | 12 | ||
13 | diff --git a/net/net.c b/net/net.c | 13 | diff --git a/net/net.c b/net/net.c |
14 | index XXXXXXX..XXXXXXX 100644 | 14 | index XXXXXXX..XXXXXXX 100644 |
15 | --- a/net/net.c | 15 | --- a/net/net.c |
16 | +++ b/net/net.c | 16 | +++ b/net/net.c |
17 | @@ -XXX,XX +XXX,XX @@ static QTAILQ_HEAD(, NetClientState) net_clients; | 17 | @@ -XXX,XX +XXX,XX @@ |
18 | /***********************************************************/ | 18 | */ |
19 | /* network device redirectors */ | 19 | |
20 | 20 | #include "qemu/osdep.h" | |
21 | -static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) | 21 | +#include "qemu-common.h" |
22 | -{ | 22 | |
23 | - const char *p, *p1; | 23 | #include "net/net.h" |
24 | - int len; | 24 | #include "clients.h" |
25 | - p = *pp; | ||
26 | - p1 = strchr(p, sep); | ||
27 | - if (!p1) | ||
28 | - return -1; | ||
29 | - len = p1 - p; | ||
30 | - p1++; | ||
31 | - if (buf_size > 0) { | ||
32 | - if (len > buf_size - 1) | ||
33 | - len = buf_size - 1; | ||
34 | - memcpy(buf, p, len); | ||
35 | - buf[len] = '\0'; | ||
36 | - } | ||
37 | - *pp = p1; | ||
38 | - return 0; | ||
39 | -} | ||
40 | - | ||
41 | int parse_host_port(struct sockaddr_in *saddr, const char *str, | ||
42 | Error **errp) | ||
43 | { | ||
44 | -- | 25 | -- |
45 | 2.5.0 | 26 | 2.7.4 |
46 | 27 | ||
47 | 28 | diff view generated by jsdifflib |
1 | From: Stefano Garzarella <sgarzare@redhat.com> | 1 | From: Paolo Bonzini <pbonzini@redhat.com> |
---|---|---|---|
2 | 2 | ||
3 | Use the glib function to split host address and port in | 3 | When a network or network device is created from the command line or HMP, |
4 | the parse_host_port() function. | 4 | QemuOpts ensures that the id passes the id_wellformed check. However, |
5 | QMP skips this: | ||
5 | 6 | ||
6 | Suggested-by: Markus Armbruster <armbru@redhat.com> | 7 | $ qemu-system-x86_64 -qmp stdio -S -nic user,id=123/456 |
7 | Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> | 8 | qemu-system-x86_64: -nic user,id=123/456: Parameter id expects an identifier |
8 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | 9 | Identifiers consist of letters, digits, -, ., _, starting with a letter. |
10 | |||
11 | $ qemu-system-x86_64 -qmp stdio -S | ||
12 | {"execute":"qmp_capabilities"} | ||
13 | {"return": {}} | ||
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. At the same time we know that every | ||
27 | call chain should go through either QMP or (for legacy) through QemuOpts. | ||
28 | Because the id for -net and -nic is automatically generated and not | ||
29 | well-formed by design, just add the check to QMP. | ||
30 | |||
31 | Cc: Jason Wang <jasowang@redhat.com> | ||
32 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | ||
9 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 33 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
10 | --- | 34 | --- |
11 | net/net.c | 43 +++++++++++++++++++++++++++---------------- | 35 | net/net.c | 5 +++++ |
12 | 1 file changed, 27 insertions(+), 16 deletions(-) | 36 | 1 file changed, 5 insertions(+) |
13 | 37 | ||
14 | diff --git a/net/net.c b/net/net.c | 38 | diff --git a/net/net.c b/net/net.c |
15 | index XXXXXXX..XXXXXXX 100644 | 39 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/net/net.c | 40 | --- a/net/net.c |
17 | +++ b/net/net.c | 41 | +++ b/net/net.c |
18 | @@ -XXX,XX +XXX,XX @@ static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) | 42 | @@ -XXX,XX +XXX,XX @@ void netdev_add(QemuOpts *opts, Error **errp) |
19 | int parse_host_port(struct sockaddr_in *saddr, const char *str, | 43 | |
20 | Error **errp) | 44 | void qmp_netdev_add(Netdev *netdev, Error **errp) |
21 | { | 45 | { |
22 | - char buf[512]; | 46 | + if (!id_wellformed(netdev->id)) { |
23 | + gchar **substrings; | 47 | + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "id", "an identifier"); |
24 | struct hostent *he; | 48 | + return; |
25 | - const char *p, *r; | 49 | + } |
26 | - int port; | ||
27 | + const char *addr, *p, *r; | ||
28 | + int port, ret = 0; | ||
29 | |||
30 | - p = str; | ||
31 | - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { | ||
32 | + substrings = g_strsplit(str, ":", 2); | ||
33 | + if (!substrings || !substrings[0] || !substrings[1]) { | ||
34 | error_setg(errp, "host address '%s' doesn't contain ':' " | ||
35 | "separating host from port", str); | ||
36 | - return -1; | ||
37 | + ret = -1; | ||
38 | + goto out; | ||
39 | } | ||
40 | + | 50 | + |
41 | + addr = substrings[0]; | 51 | net_client_init1(netdev, true, errp); |
42 | + p = substrings[1]; | ||
43 | + | ||
44 | saddr->sin_family = AF_INET; | ||
45 | - if (buf[0] == '\0') { | ||
46 | + if (addr[0] == '\0') { | ||
47 | saddr->sin_addr.s_addr = 0; | ||
48 | } else { | ||
49 | - if (qemu_isdigit(buf[0])) { | ||
50 | - if (!inet_aton(buf, &saddr->sin_addr)) { | ||
51 | + if (qemu_isdigit(addr[0])) { | ||
52 | + if (!inet_aton(addr, &saddr->sin_addr)) { | ||
53 | error_setg(errp, "host address '%s' is not a valid " | ||
54 | - "IPv4 address", buf); | ||
55 | - return -1; | ||
56 | + "IPv4 address", addr); | ||
57 | + ret = -1; | ||
58 | + goto out; | ||
59 | } | ||
60 | } else { | ||
61 | - he = gethostbyname(buf); | ||
62 | + he = gethostbyname(addr); | ||
63 | if (he == NULL) { | ||
64 | - error_setg(errp, "can't resolve host address '%s'", buf); | ||
65 | - return - 1; | ||
66 | + error_setg(errp, "can't resolve host address '%s'", addr); | ||
67 | + ret = -1; | ||
68 | + goto out; | ||
69 | } | ||
70 | saddr->sin_addr = *(struct in_addr *)he->h_addr; | ||
71 | } | ||
72 | @@ -XXX,XX +XXX,XX @@ int parse_host_port(struct sockaddr_in *saddr, const char *str, | ||
73 | port = strtol(p, (char **)&r, 0); | ||
74 | if (r == p) { | ||
75 | error_setg(errp, "port number '%s' is invalid", p); | ||
76 | - return -1; | ||
77 | + ret = -1; | ||
78 | + goto out; | ||
79 | } | ||
80 | saddr->sin_port = htons(port); | ||
81 | - return 0; | ||
82 | + | ||
83 | +out: | ||
84 | + g_strfreev(substrings); | ||
85 | + return ret; | ||
86 | } | 52 | } |
87 | 53 | ||
88 | char *qemu_mac_strdup_printf(const uint8_t *macaddr) | ||
89 | -- | 54 | -- |
90 | 2.5.0 | 55 | 2.7.4 |
91 | 56 | ||
92 | 57 | diff view generated by jsdifflib |
1 | From: Stefano Garzarella <sgarzare@redhat.com> | 1 | During procss_tx_desc(), driver can try to chain data descriptor with |
---|---|---|---|
2 | legacy descriptor, when will lead underflow for the following | ||
3 | calculation in process_tx_desc() for bytes: | ||
2 | 4 | ||
3 | If 'ipv6-prefixlen' is not a number, the current behaviour | 5 | if (tp->size + bytes > msh) |
4 | produces an assertion failure: | 6 | bytes = msh - tp->size; |
5 | $ qemu-system-x86_64 -net user,ipv6-net=feca::0/a | ||
6 | qemu-system-x86_64: qemu/util/qemu-option.c:1175: qemu_opts_foreach: | ||
7 | Assertion `!errp || !*errp' failed. | ||
8 | Aborted (core dumped) | ||
9 | 7 | ||
10 | This patch fixes it, jumping to the end of the function when | 8 | This will lead a infinite loop. So check and fail early if tp->size if |
11 | 'ipv6-prefixlen' is not a number, and printing the more friendly | 9 | greater or equal to msh. |
12 | message: | ||
13 | $ qemu-system-x86_64 -net user,ipv6-net=feca::0/a | ||
14 | qemu-system-x86_64: Parameter 'ipv6-prefixlen' expects a number | ||
15 | 10 | ||
16 | Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> | 11 | Reported-by: Alexander Bulekov <alxndr@bu.edu> |
17 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | 12 | Reported-by: Cheolwoo Myung <cwmyung@snu.ac.kr> |
13 | Reported-by: Ruhr-University Bochum <bugs-syssec@rub.de> | ||
14 | Cc: Prasad J Pandit <ppandit@redhat.com> | ||
15 | Cc: qemu-stable@nongnu.org | ||
18 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 16 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
19 | --- | 17 | --- |
20 | net/net.c | 9 +++++---- | 18 | hw/net/e1000.c | 4 ++++ |
21 | 1 file changed, 5 insertions(+), 4 deletions(-) | 19 | 1 file changed, 4 insertions(+) |
22 | 20 | ||
23 | diff --git a/net/net.c b/net/net.c | 21 | diff --git a/hw/net/e1000.c b/hw/net/e1000.c |
24 | index XXXXXXX..XXXXXXX 100644 | 22 | index XXXXXXX..XXXXXXX 100644 |
25 | --- a/net/net.c | 23 | --- a/hw/net/e1000.c |
26 | +++ b/net/net.c | 24 | +++ b/hw/net/e1000.c |
27 | @@ -XXX,XX +XXX,XX @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) | 25 | @@ -XXX,XX +XXX,XX @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) |
28 | 26 | msh = tp->tso_props.hdr_len + tp->tso_props.mss; | |
29 | if (err) { | 27 | do { |
30 | error_setg(errp, QERR_INVALID_PARAMETER_VALUE, | 28 | bytes = split_size; |
31 | - "ipv6-prefix", "a number"); | 29 | + if (tp->size >= msh) { |
32 | - } else { | 30 | + goto eop; |
33 | - qemu_opt_set_number(opts, "ipv6-prefixlen", len, | 31 | + } |
34 | - &error_abort); | 32 | if (tp->size + bytes > msh) |
35 | + "ipv6-prefixlen", "a number"); | 33 | bytes = msh - tp->size; |
36 | + goto out; | 34 | |
37 | } | 35 | @@ -XXX,XX +XXX,XX @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) |
38 | + | 36 | tp->size += split_size; |
39 | + qemu_opt_set_number(opts, "ipv6-prefixlen", len, &error_abort); | ||
40 | } | ||
41 | qemu_opt_unset(opts, "ipv6-net"); | ||
42 | } | ||
43 | @@ -XXX,XX +XXX,XX @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) | ||
44 | qapi_free_NetLegacy(object); | ||
45 | } | 37 | } |
46 | 38 | ||
47 | +out: | 39 | +eop: |
48 | error_propagate(errp, err); | 40 | if (!(txd_lower & E1000_TXD_CMD_EOP)) |
49 | visit_free(v); | 41 | return; |
50 | return ret; | 42 | if (!(tp->cptse && tp->size < tp->tso_props.hdr_len)) { |
51 | -- | 43 | -- |
52 | 2.5.0 | 44 | 2.7.4 |
53 | 45 | ||
54 | 46 | diff view generated by jsdifflib |
1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> | 1 | Some NIC supports loopback mode and this is done by calling |
---|---|---|---|
2 | nc->info->receive() directly which in fact suppresses the effort of | ||
3 | reentrancy check that is done in qemu_net_queue_send(). | ||
2 | 4 | ||
3 | Previously there was a single instance of the timer used by | 5 | Unfortunately we can't use qemu_net_queue_send() here since for |
4 | monitor triggered announces, that's OK, but when combined with the | 6 | loopback there's no sender as peer, so this patch introduce a |
5 | previous change that lets you have announces for subsets of interfaces | 7 | qemu_receive_packet() which is used for implementing loopback mode |
6 | it's a bit restrictive if you want to do different things to different | 8 | for a NIC with this check. |
7 | interfaces. | ||
8 | 9 | ||
9 | Add an 'id' field to the announce, and maintain a list of the | 10 | NIC that supports loopback mode will be converted to this helper. |
10 | timers based on id. | ||
11 | 11 | ||
12 | This allows you to for example: | 12 | This is intended to address CVE-2021-3416. |
13 | a) Start an announce going on interface eth0 for a long time | ||
14 | b) Start an announce going on interface eth1 for a long time | ||
15 | c) Kill the announce on eth0 while leaving eth1 going. | ||
16 | 13 | ||
17 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | 14 | Cc: Prasad J Pandit <ppandit@redhat.com> |
15 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
16 | Cc: qemu-stable@nongnu.org | ||
18 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 17 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
19 | --- | 18 | --- |
20 | hw/net/virtio-net.c | 4 ++-- | 19 | include/net/net.h | 5 +++++ |
21 | include/net/announce.h | 8 ++++++-- | 20 | include/net/queue.h | 8 ++++++++ |
22 | net/announce.c | 52 +++++++++++++++++++++++++++++++++++++++++++------- | 21 | net/net.c | 38 +++++++++++++++++++++++++++++++------- |
23 | net/trace-events | 3 ++- | 22 | net/queue.c | 22 ++++++++++++++++++++++ |
24 | qapi/net.json | 9 +++++++-- | 23 | 4 files changed, 66 insertions(+), 7 deletions(-) |
25 | 5 files changed, 62 insertions(+), 14 deletions(-) | ||
26 | 24 | ||
27 | diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c | 25 | diff --git a/include/net/net.h b/include/net/net.h |
28 | index XXXXXXX..XXXXXXX 100644 | 26 | index XXXXXXX..XXXXXXX 100644 |
29 | --- a/hw/net/virtio-net.c | 27 | --- a/include/net/net.h |
30 | +++ b/hw/net/virtio-net.c | 28 | +++ b/include/net/net.h |
31 | @@ -XXX,XX +XXX,XX @@ static int virtio_net_post_load_device(void *opaque, int version_id) | 29 | @@ -XXX,XX +XXX,XX @@ void *qemu_get_nic_opaque(NetClientState *nc); |
32 | timer_mod(n->announce_timer.tm, | 30 | void qemu_del_net_client(NetClientState *nc); |
33 | qemu_clock_get_ms(n->announce_timer.type)); | 31 | typedef void (*qemu_nic_foreach)(NICState *nic, void *opaque); |
34 | } else { | 32 | void qemu_foreach_nic(qemu_nic_foreach func, void *opaque); |
35 | - qemu_announce_timer_del(&n->announce_timer); | 33 | +int qemu_can_receive_packet(NetClientState *nc); |
36 | + qemu_announce_timer_del(&n->announce_timer, false); | 34 | int qemu_can_send_packet(NetClientState *nc); |
37 | } | 35 | ssize_t qemu_sendv_packet(NetClientState *nc, const struct iovec *iov, |
36 | int iovcnt); | ||
37 | ssize_t qemu_sendv_packet_async(NetClientState *nc, const struct iovec *iov, | ||
38 | int iovcnt, NetPacketSent *sent_cb); | ||
39 | ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size); | ||
40 | +ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size); | ||
41 | +ssize_t qemu_receive_packet_iov(NetClientState *nc, | ||
42 | + const struct iovec *iov, | ||
43 | + int iovcnt); | ||
44 | ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size); | ||
45 | ssize_t qemu_send_packet_async(NetClientState *nc, const uint8_t *buf, | ||
46 | int size, NetPacketSent *sent_cb); | ||
47 | diff --git a/include/net/queue.h b/include/net/queue.h | ||
48 | index XXXXXXX..XXXXXXX 100644 | ||
49 | --- a/include/net/queue.h | ||
50 | +++ b/include/net/queue.h | ||
51 | @@ -XXX,XX +XXX,XX @@ void qemu_net_queue_append_iov(NetQueue *queue, | ||
52 | |||
53 | void qemu_del_net_queue(NetQueue *queue); | ||
54 | |||
55 | +ssize_t qemu_net_queue_receive(NetQueue *queue, | ||
56 | + const uint8_t *data, | ||
57 | + size_t size); | ||
58 | + | ||
59 | +ssize_t qemu_net_queue_receive_iov(NetQueue *queue, | ||
60 | + const struct iovec *iov, | ||
61 | + int iovcnt); | ||
62 | + | ||
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 | } | ||
73 | |||
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 | { | ||
87 | int vm_running = runstate_is_running(); | ||
88 | @@ -XXX,XX +XXX,XX @@ int qemu_can_send_packet(NetClientState *sender) | ||
89 | return 1; | ||
38 | } | 90 | } |
39 | 91 | ||
40 | @@ -XXX,XX +XXX,XX @@ static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) | 92 | - if (sender->peer->receive_disabled) { |
41 | virtio_net_del_queue(n, i); | 93 | - return 0; |
42 | } | 94 | - } else if (sender->peer->info->can_receive && |
43 | 95 | - !sender->peer->info->can_receive(sender->peer)) { | |
44 | - qemu_announce_timer_del(&n->announce_timer); | 96 | - return 0; |
45 | + qemu_announce_timer_del(&n->announce_timer, false); | 97 | - } |
46 | g_free(n->vqs); | 98 | - return 1; |
47 | qemu_del_nic(n->nic); | 99 | + return qemu_can_receive_packet(sender->peer); |
48 | virtio_net_rsc_cleanup(n); | ||
49 | diff --git a/include/net/announce.h b/include/net/announce.h | ||
50 | index XXXXXXX..XXXXXXX 100644 | ||
51 | --- a/include/net/announce.h | ||
52 | +++ b/include/net/announce.h | ||
53 | @@ -XXX,XX +XXX,XX @@ struct AnnounceTimer { | ||
54 | /* Returns: update the timer to the next time point */ | ||
55 | int64_t qemu_announce_timer_step(AnnounceTimer *timer); | ||
56 | |||
57 | -/* Delete the underlying timer and other data */ | ||
58 | -void qemu_announce_timer_del(AnnounceTimer *timer); | ||
59 | +/* | ||
60 | + * Delete the underlying timer and other data | ||
61 | + * If 'free_named' true and the timer is a named timer, then remove | ||
62 | + * it from the list of named timers and free the AnnounceTimer itself. | ||
63 | + */ | ||
64 | +void qemu_announce_timer_del(AnnounceTimer *timer, bool free_named); | ||
65 | |||
66 | /* | ||
67 | * Under BQL/main thread | ||
68 | diff --git a/net/announce.c b/net/announce.c | ||
69 | index XXXXXXX..XXXXXXX 100644 | ||
70 | --- a/net/announce.c | ||
71 | +++ b/net/announce.c | ||
72 | @@ -XXX,XX +XXX,XX @@ | ||
73 | #include "qapi/qapi-commands-net.h" | ||
74 | #include "trace.h" | ||
75 | |||
76 | +static GData *named_timers; | ||
77 | + | ||
78 | int64_t qemu_announce_timer_step(AnnounceTimer *timer) | ||
79 | { | ||
80 | int64_t step; | ||
81 | @@ -XXX,XX +XXX,XX @@ int64_t qemu_announce_timer_step(AnnounceTimer *timer) | ||
82 | return step; | ||
83 | } | 100 | } |
84 | 101 | ||
85 | -void qemu_announce_timer_del(AnnounceTimer *timer) | 102 | static ssize_t filter_receive_iov(NetClientState *nc, |
86 | +/* | 103 | @@ -XXX,XX +XXX,XX @@ ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size) |
87 | + * If 'free_named' is true, then remove the timer from the list | 104 | return qemu_send_packet_async(nc, buf, size, NULL); |
88 | + * and free the timer itself. | ||
89 | + */ | ||
90 | +void qemu_announce_timer_del(AnnounceTimer *timer, bool free_named) | ||
91 | { | ||
92 | + bool free_timer = false; | ||
93 | if (timer->tm) { | ||
94 | timer_del(timer->tm); | ||
95 | timer_free(timer->tm); | ||
96 | @@ -XXX,XX +XXX,XX @@ void qemu_announce_timer_del(AnnounceTimer *timer) | ||
97 | } | ||
98 | qapi_free_strList(timer->params.interfaces); | ||
99 | timer->params.interfaces = NULL; | ||
100 | + if (free_named && timer->params.has_id) { | ||
101 | + AnnounceTimer *list_timer; | ||
102 | + /* | ||
103 | + * Sanity check: There should only be one timer on the list with | ||
104 | + * the id. | ||
105 | + */ | ||
106 | + list_timer = g_datalist_get_data(&named_timers, timer->params.id); | ||
107 | + assert(timer == list_timer); | ||
108 | + free_timer = true; | ||
109 | + g_datalist_remove_data(&named_timers, timer->params.id); | ||
110 | + } | ||
111 | + trace_qemu_announce_timer_del(free_named, free_timer, timer->params.id); | ||
112 | + g_free(timer->params.id); | ||
113 | + timer->params.id = NULL; | ||
114 | + | ||
115 | + if (free_timer) { | ||
116 | + g_free(timer); | ||
117 | + } | ||
118 | } | 105 | } |
119 | 106 | ||
120 | /* | 107 | +ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size) |
121 | @@ -XXX,XX +XXX,XX @@ void qemu_announce_timer_reset(AnnounceTimer *timer, | 108 | +{ |
122 | * We're under the BQL, so the current timer can't | 109 | + if (!qemu_can_receive_packet(nc)) { |
123 | * be firing, so we should be able to delete it. | 110 | + return 0; |
124 | */ | ||
125 | - qemu_announce_timer_del(timer); | ||
126 | + qemu_announce_timer_del(timer, false); | ||
127 | |||
128 | QAPI_CLONE_MEMBERS(AnnounceParameters, &timer->params, params); | ||
129 | timer->round = params->rounds; | ||
130 | @@ -XXX,XX +XXX,XX @@ static void qemu_announce_self_iter(NICState *nic, void *opaque) | ||
131 | skip = false; | ||
132 | } | ||
133 | |||
134 | - trace_qemu_announce_self_iter(nic->ncs->name, | ||
135 | + trace_qemu_announce_self_iter(timer->params.has_id ? timer->params.id : "_", | ||
136 | + nic->ncs->name, | ||
137 | qemu_ether_ntoa(&nic->conf->macaddr), skip); | ||
138 | |||
139 | if (!skip) { | ||
140 | @@ -XXX,XX +XXX,XX @@ static void qemu_announce_self_once(void *opaque) | ||
141 | if (--timer->round) { | ||
142 | qemu_announce_timer_step(timer); | ||
143 | } else { | ||
144 | - qemu_announce_timer_del(timer); | ||
145 | + qemu_announce_timer_del(timer, true); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | @@ -XXX,XX +XXX,XX @@ void qemu_announce_self(AnnounceTimer *timer, AnnounceParameters *params) | ||
150 | if (params->rounds) { | ||
151 | qemu_announce_self_once(timer); | ||
152 | } else { | ||
153 | - qemu_announce_timer_del(timer); | ||
154 | + qemu_announce_timer_del(timer, true); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | void qmp_announce_self(AnnounceParameters *params, Error **errp) | ||
159 | { | ||
160 | - static AnnounceTimer announce_timer; | ||
161 | - qemu_announce_self(&announce_timer, params); | ||
162 | + AnnounceTimer *named_timer; | ||
163 | + if (!params->has_id) { | ||
164 | + params->id = g_strdup(""); | ||
165 | + params->has_id = true; | ||
166 | + } | 111 | + } |
167 | + | 112 | + |
168 | + named_timer = g_datalist_get_data(&named_timers, params->id); | 113 | + return qemu_net_queue_receive(nc->incoming_queue, buf, size); |
114 | +} | ||
169 | + | 115 | + |
170 | + if (!named_timer) { | 116 | +ssize_t qemu_receive_packet_iov(NetClientState *nc, const struct iovec *iov, |
171 | + named_timer = g_new0(AnnounceTimer, 1); | 117 | + int iovcnt) |
172 | + g_datalist_set_data(&named_timers, params->id, named_timer); | 118 | +{ |
119 | + if (!qemu_can_receive_packet(nc)) { | ||
120 | + return 0; | ||
173 | + } | 121 | + } |
174 | + | 122 | + |
175 | + qemu_announce_self(named_timer, params); | 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; | ||
176 | } | 135 | } |
177 | diff --git a/net/trace-events b/net/trace-events | 136 | |
178 | index XXXXXXX..XXXXXXX 100644 | 137 | +ssize_t qemu_net_queue_receive(NetQueue *queue, |
179 | --- a/net/trace-events | 138 | + const uint8_t *data, |
180 | +++ b/net/trace-events | 139 | + size_t size) |
181 | @@ -XXX,XX +XXX,XX @@ | 140 | +{ |
182 | # See docs/devel/tracing.txt for syntax documentation. | 141 | + if (queue->delivering) { |
183 | 142 | + return 0; | |
184 | # announce.c | 143 | + } |
185 | -qemu_announce_self_iter(const char *name, const char *mac, int skip) "%s:%s skip: %d" | 144 | + |
186 | +qemu_announce_self_iter(const char *id, const char *name, const char *mac, int skip) "%s:%s:%s skip: %d" | 145 | + return qemu_net_queue_deliver(queue, NULL, 0, data, size); |
187 | +qemu_announce_timer_del(bool free_named, bool free_timer, char *id) "free named: %d free timer: %d id: %s" | 146 | +} |
188 | 147 | + | |
189 | # vhost-user.c | 148 | +ssize_t qemu_net_queue_receive_iov(NetQueue *queue, |
190 | vhost_user_event(const char *chr, int event) "chr: %s got event: %d" | 149 | + const struct iovec *iov, |
191 | diff --git a/qapi/net.json b/qapi/net.json | 150 | + int iovcnt) |
192 | index XXXXXXX..XXXXXXX 100644 | 151 | +{ |
193 | --- a/qapi/net.json | 152 | + if (queue->delivering) { |
194 | +++ b/qapi/net.json | 153 | + return 0; |
195 | @@ -XXX,XX +XXX,XX @@ | 154 | + } |
196 | # @interfaces: An optional list of interface names, which restricts the | 155 | + |
197 | # announcement to the listed interfaces. (Since 4.1) | 156 | + return qemu_net_queue_deliver_iov(queue, NULL, 0, iov, iovcnt); |
198 | # | 157 | +} |
199 | +# @id: A name to be used to identify an instance of announce-timers | 158 | + |
200 | +# and to allow it to modified later. Not for use as | 159 | ssize_t qemu_net_queue_send(NetQueue *queue, |
201 | +# part of the migration parameters. (Since 4.1) | 160 | NetClientState *sender, |
202 | +# | 161 | unsigned flags, |
203 | # Since: 4.0 | ||
204 | ## | ||
205 | |||
206 | @@ -XXX,XX +XXX,XX @@ | ||
207 | 'max': 'int', | ||
208 | 'rounds': 'int', | ||
209 | 'step': 'int', | ||
210 | - '*interfaces': ['str'] } } | ||
211 | + '*interfaces': ['str'], | ||
212 | + '*id' : 'str' } } | ||
213 | |||
214 | ## | ||
215 | # @announce-self: | ||
216 | @@ -XXX,XX +XXX,XX @@ | ||
217 | # -> { "execute": "announce-self", | ||
218 | # "arguments": { | ||
219 | # "initial": 50, "max": 550, "rounds": 10, "step": 50, | ||
220 | -# "interfaces": ["vn2", "vn3"] } } | ||
221 | +# "interfaces": ["vn2", "vn3"], "id": "bob" } } | ||
222 | # <- { "return": {} } | ||
223 | # | ||
224 | # Since: 4.0 | ||
225 | -- | 162 | -- |
226 | 2.5.0 | 163 | 2.7.4 |
227 | 164 | ||
228 | 165 | diff view generated by jsdifflib |
1 | From: Markus Armbruster <armbru@redhat.com> | 1 | This patch switches to use qemu_receive_packet() which can detect |
---|---|---|---|
2 | reentrancy and return early. | ||
2 | 3 | ||
3 | Signed-off-by: Markus Armbruster <armbru@redhat.com> | 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> | ||
4 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 9 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
5 | --- | 10 | --- |
6 | qemu-bridge-helper.c | 12 +++++++++++- | 11 | hw/net/e1000.c | 2 +- |
7 | 1 file changed, 11 insertions(+), 1 deletion(-) | 12 | 1 file changed, 1 insertion(+), 1 deletion(-) |
8 | 13 | ||
9 | diff --git a/qemu-bridge-helper.c b/qemu-bridge-helper.c | 14 | diff --git a/hw/net/e1000.c b/hw/net/e1000.c |
10 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
11 | --- a/qemu-bridge-helper.c | 16 | --- a/hw/net/e1000.c |
12 | +++ b/qemu-bridge-helper.c | 17 | +++ b/hw/net/e1000.c |
13 | @@ -XXX,XX +XXX,XX @@ | 18 | @@ -XXX,XX +XXX,XX @@ e1000_send_packet(E1000State *s, const uint8_t *buf, int size) |
14 | * | 19 | |
15 | * This work is licensed under the terms of the GNU GPL, version 2. See | 20 | NetClientState *nc = qemu_get_queue(s->nic); |
16 | * the COPYING file in the top-level directory. | 21 | if (s->phy_reg[PHY_CTRL] & MII_CR_LOOPBACK) { |
17 | - * | 22 | - nc->info->receive(nc, buf, size); |
18 | + */ | 23 | + qemu_receive_packet(nc, buf, size); |
19 | + | 24 | } else { |
20 | +/* | 25 | qemu_send_packet(nc, buf, size); |
21 | + * Known shortcomings: | 26 | } |
22 | + * - There is no manual page | ||
23 | + * - The syntax of the ACL file is not documented anywhere | ||
24 | + * - parse_acl_file() doesn't report fopen() failure properly, fails | ||
25 | + * to check ferror() after fgets() failure, arbitrarily truncates | ||
26 | + * long lines, handles whitespace inconsistently, error messages | ||
27 | + * don't point to the offending file and line, errors in included | ||
28 | + * files are reported, but otherwise ignored, ... | ||
29 | */ | ||
30 | |||
31 | #include "qemu/osdep.h" | ||
32 | -- | 27 | -- |
33 | 2.5.0 | 28 | 2.7.4 |
34 | 29 | ||
35 | 30 | diff view generated by jsdifflib |
1 | From: Zhang Chen <chen.zhang@intel.com> | 1 | This patch switches to use qemu_receive_packet() which can detect |
---|---|---|---|
2 | reentrancy and return early. | ||
2 | 3 | ||
3 | We need to notify net filter to do checkpoint for Xen COLO, like KVM side. | 4 | This is intended to address CVE-2021-3416. |
4 | 5 | ||
5 | Signed-off-by: Zhang Chen <chen.zhang@intel.com> | 6 | Cc: Prasad J Pandit <ppandit@redhat.com> |
7 | Cc: qemu-stable@nongnu.org | ||
8 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com | ||
6 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 9 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
7 | --- | 10 | --- |
8 | migration/colo.c | 2 ++ | 11 | hw/net/dp8393x.c | 2 +- |
9 | 1 file changed, 2 insertions(+) | 12 | 1 file changed, 1 insertion(+), 1 deletion(-) |
10 | 13 | ||
11 | diff --git a/migration/colo.c b/migration/colo.c | 14 | diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c |
12 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
13 | --- a/migration/colo.c | 16 | --- a/hw/net/dp8393x.c |
14 | +++ b/migration/colo.c | 17 | +++ b/hw/net/dp8393x.c |
15 | @@ -XXX,XX +XXX,XX @@ ReplicationStatus *qmp_query_xen_replication_status(Error **errp) | 18 | @@ -XXX,XX +XXX,XX @@ static void dp8393x_do_transmit_packets(dp8393xState *s) |
16 | void qmp_xen_colo_do_checkpoint(Error **errp) | 19 | s->regs[SONIC_TCR] |= SONIC_TCR_CRSL; |
17 | { | 20 | if (nc->info->can_receive(nc)) { |
18 | replication_do_checkpoint_all(errp); | 21 | s->loopback_packet = 1; |
19 | + /* Notify all filters of all NIC to do checkpoint */ | 22 | - nc->info->receive(nc, s->tx_buffer, tx_len); |
20 | + colo_notify_filters_event(COLO_EVENT_CHECKPOINT, errp); | 23 | + qemu_receive_packet(nc, s->tx_buffer, tx_len); |
21 | } | 24 | } |
22 | #endif | 25 | } else { |
23 | 26 | /* Transmit packet */ | |
24 | -- | 27 | -- |
25 | 2.5.0 | 28 | 2.7.4 |
26 | 29 | ||
27 | 30 | diff view generated by jsdifflib |
1 | From: Zhang Chen <chen.zhang@intel.com> | 1 | This patch switches to use qemu_receive_packet() which can detect |
---|---|---|---|
2 | reentrancy and return early. | ||
2 | 3 | ||
3 | We need use this function to send notification message for remote colo-frame(Xen). | 4 | This is intended to address CVE-2021-3416. |
4 | So we add new parameter for this job. | ||
5 | 5 | ||
6 | Signed-off-by: Zhang Chen <chen.zhang@intel.com> | 6 | Cc: Prasad J Pandit <ppandit@redhat.com> |
7 | Cc: qemu-stable@nongnu.org | ||
8 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
7 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 9 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
8 | --- | 10 | --- |
9 | net/colo-compare.c | 41 +++++++++++++++++++++++++++++++++-------- | 11 | hw/net/msf2-emac.c | 2 +- |
10 | 1 file changed, 33 insertions(+), 8 deletions(-) | 12 | 1 file changed, 1 insertion(+), 1 deletion(-) |
11 | 13 | ||
12 | diff --git a/net/colo-compare.c b/net/colo-compare.c | 14 | diff --git a/hw/net/msf2-emac.c b/hw/net/msf2-emac.c |
13 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/net/colo-compare.c | 16 | --- a/hw/net/msf2-emac.c |
15 | +++ b/net/colo-compare.c | 17 | +++ b/hw/net/msf2-emac.c |
16 | @@ -XXX,XX +XXX,XX @@ static void colo_compare_inconsistency_notify(void) | 18 | @@ -XXX,XX +XXX,XX @@ static void msf2_dma_tx(MSF2EmacState *s) |
17 | static int compare_chr_send(CompareState *s, | 19 | * R_CFG1 bit 0 is set. |
18 | const uint8_t *buf, | ||
19 | uint32_t size, | ||
20 | - uint32_t vnet_hdr_len); | ||
21 | + uint32_t vnet_hdr_len, | ||
22 | + bool notify_remote_frame); | ||
23 | |||
24 | static gint seq_sorter(Packet *a, Packet *b, gpointer data) | ||
25 | { | ||
26 | @@ -XXX,XX +XXX,XX @@ static void colo_release_primary_pkt(CompareState *s, Packet *pkt) | ||
27 | ret = compare_chr_send(s, | ||
28 | pkt->data, | ||
29 | pkt->size, | ||
30 | - pkt->vnet_hdr_len); | ||
31 | + pkt->vnet_hdr_len, | ||
32 | + false); | ||
33 | if (ret < 0) { | ||
34 | error_report("colo send primary packet failed"); | ||
35 | } | ||
36 | @@ -XXX,XX +XXX,XX @@ static void colo_compare_connection(void *opaque, void *user_data) | ||
37 | static int compare_chr_send(CompareState *s, | ||
38 | const uint8_t *buf, | ||
39 | uint32_t size, | ||
40 | - uint32_t vnet_hdr_len) | ||
41 | + uint32_t vnet_hdr_len, | ||
42 | + bool notify_remote_frame) | ||
43 | { | ||
44 | int ret = 0; | ||
45 | uint32_t len = htonl(size); | ||
46 | @@ -XXX,XX +XXX,XX @@ static int compare_chr_send(CompareState *s, | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | - ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len)); | ||
51 | + if (notify_remote_frame) { | ||
52 | + ret = qemu_chr_fe_write_all(&s->chr_notify_dev, | ||
53 | + (uint8_t *)&len, | ||
54 | + sizeof(len)); | ||
55 | + } else { | ||
56 | + ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len)); | ||
57 | + } | ||
58 | + | ||
59 | if (ret != sizeof(len)) { | ||
60 | goto err; | ||
61 | } | ||
62 | @@ -XXX,XX +XXX,XX @@ static int compare_chr_send(CompareState *s, | ||
63 | * know how to parse net packet correctly. | ||
64 | */ | 20 | */ |
65 | len = htonl(vnet_hdr_len); | 21 | if (s->regs[R_CFG1] & R_CFG1_LB_EN_MASK) { |
66 | - ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len)); | 22 | - nc->info->receive(nc, buf, size); |
67 | + | 23 | + qemu_receive_packet(nc, buf, size); |
68 | + if (!notify_remote_frame) { | 24 | } else { |
69 | + ret = qemu_chr_fe_write_all(&s->chr_out, | 25 | qemu_send_packet(nc, buf, size); |
70 | + (uint8_t *)&len, | ||
71 | + sizeof(len)); | ||
72 | + } | ||
73 | + | ||
74 | if (ret != sizeof(len)) { | ||
75 | goto err; | ||
76 | } | 26 | } |
77 | } | ||
78 | |||
79 | - ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size); | ||
80 | + if (notify_remote_frame) { | ||
81 | + ret = qemu_chr_fe_write_all(&s->chr_notify_dev, | ||
82 | + (uint8_t *)buf, | ||
83 | + size); | ||
84 | + } else { | ||
85 | + ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size); | ||
86 | + } | ||
87 | + | ||
88 | if (ret != size) { | ||
89 | goto err; | ||
90 | } | ||
91 | @@ -XXX,XX +XXX,XX @@ static void compare_pri_rs_finalize(SocketReadState *pri_rs) | ||
92 | compare_chr_send(s, | ||
93 | pri_rs->buf, | ||
94 | pri_rs->packet_len, | ||
95 | - pri_rs->vnet_hdr_len); | ||
96 | + pri_rs->vnet_hdr_len, | ||
97 | + false); | ||
98 | } else { | ||
99 | /* compare packet in the specified connection */ | ||
100 | colo_compare_connection(conn, s); | ||
101 | @@ -XXX,XX +XXX,XX @@ static void colo_flush_packets(void *opaque, void *user_data) | ||
102 | compare_chr_send(s, | ||
103 | pkt->data, | ||
104 | pkt->size, | ||
105 | - pkt->vnet_hdr_len); | ||
106 | + pkt->vnet_hdr_len, | ||
107 | + false); | ||
108 | packet_destroy(pkt, NULL); | ||
109 | } | ||
110 | while (!g_queue_is_empty(&conn->secondary_list)) { | ||
111 | -- | 27 | -- |
112 | 2.5.0 | 28 | 2.7.4 |
113 | 29 | ||
114 | 30 | diff view generated by jsdifflib |
1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> | 1 | This patch switches to use qemu_receive_packet() which can detect |
---|---|---|---|
2 | reentrancy and return early. | ||
2 | 3 | ||
3 | Expand self-announce test to check we can stop an announce timer. | 4 | This is intended to address CVE-2021-3416. |
4 | We set it up to send 300 packets, but after we receive | ||
5 | the first one we tell it to stop. | ||
6 | 5 | ||
7 | We error if: | 6 | Cc: Prasad J Pandit <ppandit@redhat.com> |
8 | a) We receive more than 30 of the packets | 7 | Cc: qemu-stable@nongnu.org |
9 | b) We're still receiving packets after a lot longer than the | 8 | Reviewed-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> |
10 | 30 seconds should have arrived | 9 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> |
11 | 10 | Reviewed-by: Alistair Francis <alistair.francis@wdc.com> | |
12 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | ||
13 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 11 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
14 | --- | 12 | --- |
15 | tests/virtio-net-test.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++--- | 13 | hw/net/sungem.c | 2 +- |
16 | 1 file changed, 54 insertions(+), 3 deletions(-) | 14 | 1 file changed, 1 insertion(+), 1 deletion(-) |
17 | 15 | ||
18 | diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c | 16 | diff --git a/hw/net/sungem.c b/hw/net/sungem.c |
19 | index XXXXXXX..XXXXXXX 100644 | 17 | index XXXXXXX..XXXXXXX 100644 |
20 | --- a/tests/virtio-net-test.c | 18 | --- a/hw/net/sungem.c |
21 | +++ b/tests/virtio-net-test.c | 19 | +++ b/hw/net/sungem.c |
22 | @@ -XXX,XX +XXX,XX @@ static void announce_self(void *obj, void *data, QGuestAllocator *t_alloc) | 20 | @@ -XXX,XX +XXX,XX @@ static void sungem_send_packet(SunGEMState *s, const uint8_t *buf, |
23 | QDict *rsp; | 21 | NetClientState *nc = qemu_get_queue(s->nic); |
24 | int ret; | 22 | |
25 | uint16_t *proto = (uint16_t *)&buffer[12]; | 23 | if (s->macregs[MAC_XIFCFG >> 2] & MAC_XIFCFG_LBCK) { |
26 | + size_t total_received = 0; | 24 | - nc->info->receive(nc, buf, size); |
27 | + uint64_t start, now, last_rxt, deadline; | 25 | + qemu_receive_packet(nc, buf, size); |
28 | 26 | } else { | |
29 | + /* Send a set of packets over a few second period */ | 27 | qemu_send_packet(nc, buf, size); |
30 | rsp = qmp("{ 'execute' : 'announce-self', " | 28 | } |
31 | " 'arguments': {" | ||
32 | - " 'initial': 50, 'max': 550," | ||
33 | - " 'rounds': 10, 'step': 50 } }"); | ||
34 | + " 'initial': 20, 'max': 100," | ||
35 | + " 'rounds': 300, 'step': 10, 'id': 'bob' } }"); | ||
36 | assert(!qdict_haskey(rsp, "error")); | ||
37 | qobject_unref(rsp); | ||
38 | |||
39 | - /* Catch the packet and make sure it's a RARP */ | ||
40 | + /* Catch the first packet and make sure it's a RARP */ | ||
41 | ret = qemu_recv(sv[0], &len, sizeof(len), 0); | ||
42 | g_assert_cmpint(ret, ==, sizeof(len)); | ||
43 | len = ntohl(len); | ||
44 | |||
45 | ret = qemu_recv(sv[0], buffer, len, 0); | ||
46 | g_assert_cmpint(*proto, ==, htons(ETH_P_RARP)); | ||
47 | + | ||
48 | + /* | ||
49 | + * Stop the announcment by settings rounds to 0 on the | ||
50 | + * existing timer. | ||
51 | + */ | ||
52 | + rsp = qmp("{ 'execute' : 'announce-self', " | ||
53 | + " 'arguments': {" | ||
54 | + " 'initial': 20, 'max': 100," | ||
55 | + " 'rounds': 0, 'step': 10, 'id': 'bob' } }"); | ||
56 | + assert(!qdict_haskey(rsp, "error")); | ||
57 | + qobject_unref(rsp); | ||
58 | + | ||
59 | + /* Now make sure the packets stop */ | ||
60 | + | ||
61 | + /* Times are in us */ | ||
62 | + start = g_get_monotonic_time(); | ||
63 | + /* 30 packets, max gap 100ms, * 4 for wiggle */ | ||
64 | + deadline = start + 1000 * (100 * 30 * 4); | ||
65 | + last_rxt = start; | ||
66 | + | ||
67 | + while (true) { | ||
68 | + int saved_err; | ||
69 | + ret = qemu_recv(sv[0], buffer, 60, MSG_DONTWAIT); | ||
70 | + saved_err = errno; | ||
71 | + now = g_get_monotonic_time(); | ||
72 | + g_assert_cmpint(now, <, deadline); | ||
73 | + | ||
74 | + if (ret >= 0) { | ||
75 | + if (ret) { | ||
76 | + last_rxt = now; | ||
77 | + } | ||
78 | + total_received += ret; | ||
79 | + | ||
80 | + /* Check it's not spewing loads */ | ||
81 | + g_assert_cmpint(total_received, <, 60 * 30 * 2); | ||
82 | + } else { | ||
83 | + g_assert_cmpint(saved_err, ==, EAGAIN); | ||
84 | + | ||
85 | + /* 400ms, i.e. 4 worst case gaps */ | ||
86 | + if ((now - last_rxt) > (1000 * 100 * 4)) { | ||
87 | + /* Nothings arrived for a while - must have stopped */ | ||
88 | + break; | ||
89 | + }; | ||
90 | + | ||
91 | + /* 100ms */ | ||
92 | + g_usleep(1000 * 100); | ||
93 | + } | ||
94 | + }; | ||
95 | } | ||
96 | |||
97 | static void virtio_net_test_cleanup(void *sockets) | ||
98 | -- | 29 | -- |
99 | 2.5.0 | 30 | 2.7.4 |
100 | 31 | ||
101 | 32 | diff view generated by jsdifflib |
1 | From: Zhang Chen <chen.zhang@intel.com> | 1 | This patch switches to use qemu_receive_receive_iov() which can detect |
---|---|---|---|
2 | reentrancy and return early. | ||
2 | 3 | ||
3 | Add chardev handler to send notification to remote(current from Xen) colo-frame. | 4 | This is intended to address CVE-2021-3416. |
4 | 5 | ||
5 | Signed-off-by: Zhang Chen <chen.zhang@intel.com> | 6 | Cc: Prasad J Pandit <ppandit@redhat.com> |
7 | Cc: qemu-stable@nongnu.org | ||
8 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> | ||
6 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 9 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
7 | --- | 10 | --- |
8 | net/colo-compare.c | 39 +++++++++++++++++++++++++++++++++++++++ | 11 | hw/net/net_tx_pkt.c | 2 +- |
9 | 1 file changed, 39 insertions(+) | 12 | 1 file changed, 1 insertion(+), 1 deletion(-) |
10 | 13 | ||
11 | diff --git a/net/colo-compare.c b/net/colo-compare.c | 14 | diff --git a/hw/net/net_tx_pkt.c b/hw/net/net_tx_pkt.c |
12 | index XXXXXXX..XXXXXXX 100644 | 15 | index XXXXXXX..XXXXXXX 100644 |
13 | --- a/net/colo-compare.c | 16 | --- a/hw/net/net_tx_pkt.c |
14 | +++ b/net/colo-compare.c | 17 | +++ b/hw/net/net_tx_pkt.c |
15 | @@ -XXX,XX +XXX,XX @@ typedef struct CompareState { | 18 | @@ -XXX,XX +XXX,XX @@ static inline void net_tx_pkt_sendv(struct NetTxPkt *pkt, |
16 | CharBackend chr_pri_in; | 19 | NetClientState *nc, const struct iovec *iov, int iov_cnt) |
17 | CharBackend chr_sec_in; | 20 | { |
18 | CharBackend chr_out; | 21 | if (pkt->is_loopback) { |
19 | + CharBackend chr_notify_dev; | 22 | - nc->info->receive_iov(nc, iov, iov_cnt); |
20 | SocketReadState pri_rs; | 23 | + qemu_receive_packet_iov(nc, iov, iov_cnt); |
21 | SocketReadState sec_rs; | 24 | } else { |
22 | + SocketReadState notify_rs; | 25 | qemu_sendv_packet(nc, iov, iov_cnt); |
23 | bool vnet_hdr; | ||
24 | |||
25 | /* | ||
26 | @@ -XXX,XX +XXX,XX @@ static void compare_sec_chr_in(void *opaque, const uint8_t *buf, int size) | ||
27 | } | ||
28 | } | ||
29 | |||
30 | +static void compare_notify_chr(void *opaque, const uint8_t *buf, int size) | ||
31 | +{ | ||
32 | + CompareState *s = COLO_COMPARE(opaque); | ||
33 | + int ret; | ||
34 | + | ||
35 | + ret = net_fill_rstate(&s->notify_rs, buf, size); | ||
36 | + if (ret == -1) { | ||
37 | + qemu_chr_fe_set_handlers(&s->chr_notify_dev, NULL, NULL, NULL, NULL, | ||
38 | + NULL, NULL, true); | ||
39 | + error_report("colo-compare notify_dev error"); | ||
40 | + } | ||
41 | +} | ||
42 | + | ||
43 | /* | ||
44 | * Check old packet regularly so it can watch for any packets | ||
45 | * that the secondary hasn't produced equivalents of. | ||
46 | @@ -XXX,XX +XXX,XX @@ static void colo_compare_iothread(CompareState *s) | ||
47 | qemu_chr_fe_set_handlers(&s->chr_sec_in, compare_chr_can_read, | ||
48 | compare_sec_chr_in, NULL, NULL, | ||
49 | s, s->worker_context, true); | ||
50 | + if (s->notify_dev) { | ||
51 | + qemu_chr_fe_set_handlers(&s->chr_notify_dev, compare_chr_can_read, | ||
52 | + compare_notify_chr, NULL, NULL, | ||
53 | + s, s->worker_context, true); | ||
54 | + } | ||
55 | |||
56 | colo_compare_timer_init(s); | ||
57 | s->event_bh = qemu_bh_new(colo_compare_handle_event, s); | ||
58 | @@ -XXX,XX +XXX,XX @@ static void compare_sec_rs_finalize(SocketReadState *sec_rs) | ||
59 | } | ||
60 | } | ||
61 | |||
62 | +static void compare_notify_rs_finalize(SocketReadState *notify_rs) | ||
63 | +{ | ||
64 | + /* Get Xen colo-frame's notify and handle the message */ | ||
65 | +} | ||
66 | |||
67 | /* | ||
68 | * Return 0 is success. | ||
69 | @@ -XXX,XX +XXX,XX @@ static void colo_compare_complete(UserCreatable *uc, Error **errp) | ||
70 | net_socket_rs_init(&s->pri_rs, compare_pri_rs_finalize, s->vnet_hdr); | ||
71 | net_socket_rs_init(&s->sec_rs, compare_sec_rs_finalize, s->vnet_hdr); | ||
72 | |||
73 | + /* Try to enable remote notify chardev, currently just for Xen COLO */ | ||
74 | + if (s->notify_dev) { | ||
75 | + if (find_and_check_chardev(&chr, s->notify_dev, errp) || | ||
76 | + !qemu_chr_fe_init(&s->chr_notify_dev, chr, errp)) { | ||
77 | + return; | ||
78 | + } | ||
79 | + | ||
80 | + net_socket_rs_init(&s->notify_rs, compare_notify_rs_finalize, | ||
81 | + s->vnet_hdr); | ||
82 | + } | ||
83 | + | ||
84 | QTAILQ_INSERT_TAIL(&net_compares, s, next); | ||
85 | |||
86 | g_queue_init(&s->conn_list); | ||
87 | @@ -XXX,XX +XXX,XX @@ static void colo_compare_finalize(Object *obj) | ||
88 | qemu_chr_fe_deinit(&s->chr_pri_in, false); | ||
89 | qemu_chr_fe_deinit(&s->chr_sec_in, false); | ||
90 | qemu_chr_fe_deinit(&s->chr_out, false); | ||
91 | + if (s->notify_dev) { | ||
92 | + qemu_chr_fe_deinit(&s->chr_notify_dev, false); | ||
93 | + } | ||
94 | + | ||
95 | if (s->iothread) { | ||
96 | colo_compare_timer_del(s); | ||
97 | } | 26 | } |
98 | -- | 27 | -- |
99 | 2.5.0 | 28 | 2.7.4 |
100 | 29 | ||
101 | 30 | diff view generated by jsdifflib |
1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> | 1 | From: Alexander Bulekov <alxndr@bu.edu> |
---|---|---|---|
2 | 2 | ||
3 | Add the optional ID to the HMP command. | 3 | This patch switches to use qemu_receive_packet() which can detect |
4 | reentrancy and return early. | ||
4 | 5 | ||
5 | e.g. | 6 | This is intended to address CVE-2021-3416. |
6 | # start an announce for a long time on eth1 | ||
7 | migrate_set_parameter announce-rounds 1000 | ||
8 | announce_self "eth1" e1 | ||
9 | 7 | ||
10 | # start an announce on eth2 | 8 | Cc: Prasad J Pandit <ppandit@redhat.com> |
11 | announce_self "eth2" e2 | 9 | Cc: qemu-stable@nongnu.org |
12 | 10 | Buglink: https://bugs.launchpad.net/qemu/+bug/1910826 | |
13 | # Change e1 to be announcing on eth1 and eth3 | 11 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com |
14 | announce_self "eth1,eth3" e1 | 12 | Signed-off-by: Alexander Bulekov <alxndr@bu.edu> |
15 | |||
16 | # Cancel e1 | ||
17 | migrate_set_parameter announce-rounds 0 | ||
18 | announce_self "" e1 | ||
19 | |||
20 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | ||
21 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 13 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
22 | --- | 14 | --- |
23 | hmp-commands.hx | 7 ++++--- | 15 | hw/net/rtl8139.c | 2 +- |
24 | monitor/hmp-cmds.c | 3 +++ | 16 | 1 file changed, 1 insertion(+), 1 deletion(-) |
25 | 2 files changed, 7 insertions(+), 3 deletions(-) | ||
26 | 17 | ||
27 | diff --git a/hmp-commands.hx b/hmp-commands.hx | 18 | diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c |
28 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
29 | --- a/hmp-commands.hx | 20 | --- a/hw/net/rtl8139.c |
30 | +++ b/hmp-commands.hx | 21 | +++ b/hw/net/rtl8139.c |
31 | @@ -XXX,XX +XXX,XX @@ ETEXI | 22 | @@ -XXX,XX +XXX,XX @@ static void rtl8139_transfer_frame(RTL8139State *s, uint8_t *buf, int size, |
32 | 23 | } | |
33 | { | 24 | |
34 | .name = "announce_self", | 25 | DPRINTF("+++ transmit loopback mode\n"); |
35 | - .args_type = "interfaces:s?", | 26 | - rtl8139_do_receive(qemu_get_queue(s->nic), buf, size, do_interrupt); |
36 | - .params = "[interfaces]", | 27 | + qemu_receive_packet(qemu_get_queue(s->nic), buf, size); |
37 | + .args_type = "interfaces:s?,id:s?", | 28 | |
38 | + .params = "[interfaces] [id]", | 29 | if (iov) { |
39 | .help = "Trigger GARP/RARP announcements", | 30 | g_free(buf2); |
40 | .cmd = hmp_announce_self, | ||
41 | }, | ||
42 | @@ -XXX,XX +XXX,XX @@ Trigger a round of GARP/RARP broadcasts; this is useful for explicitly updating | ||
43 | network infrastructure after a reconfiguration or some forms of migration. | ||
44 | The timings of the round are set by the migration announce parameters. | ||
45 | An optional comma separated @var{interfaces} list restricts the announce to the | ||
46 | -named set of interfaces. | ||
47 | +named set of interfaces. An optional @var{id} can be used to start a separate announce | ||
48 | +timer and to change the parameters of it later. | ||
49 | ETEXI | ||
50 | |||
51 | { | ||
52 | diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c | ||
53 | index XXXXXXX..XXXXXXX 100644 | ||
54 | --- a/monitor/hmp-cmds.c | ||
55 | +++ b/monitor/hmp-cmds.c | ||
56 | @@ -XXX,XX +XXX,XX @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict) | ||
57 | void hmp_announce_self(Monitor *mon, const QDict *qdict) | ||
58 | { | ||
59 | const char *interfaces_str = qdict_get_try_str(qdict, "interfaces"); | ||
60 | + const char *id = qdict_get_try_str(qdict, "id"); | ||
61 | AnnounceParameters *params = QAPI_CLONE(AnnounceParameters, | ||
62 | migrate_announce_params()); | ||
63 | |||
64 | qapi_free_strList(params->interfaces); | ||
65 | params->interfaces = strList_from_comma_list(interfaces_str); | ||
66 | params->has_interfaces = params->interfaces != NULL; | ||
67 | + params->id = g_strdup(id); | ||
68 | + params->has_id = !!params->id; | ||
69 | qmp_announce_self(params, NULL); | ||
70 | qapi_free_AnnounceParameters(params); | ||
71 | } | ||
72 | -- | 31 | -- |
73 | 2.5.0 | 32 | 2.7.4 |
74 | 33 | ||
75 | 34 | diff view generated by jsdifflib |
1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> | 1 | From: Alexander Bulekov <alxndr@bu.edu> |
---|---|---|---|
2 | 2 | ||
3 | Add the optional interface list to the HMP command. | 3 | This patch switches to use qemu_receive_packet() which can detect |
4 | reentrancy and return early. | ||
4 | 5 | ||
5 | i.e. | 6 | This is intended to address CVE-2021-3416. |
6 | 7 | ||
7 | All interfaces | 8 | Cc: Prasad J Pandit <ppandit@redhat.com> |
8 | announce_self | 9 | Cc: qemu-stable@nongnu.org |
9 | 10 | Buglink: https://bugs.launchpad.net/qemu/+bug/1917085 | |
10 | Just the named interfaces: | 11 | Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com |
11 | announce_self vn1,vn2 | 12 | Signed-off-by: Alexander Bulekov <alxndr@bu.edu> |
12 | |||
13 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | ||
14 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 13 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
15 | --- | 14 | --- |
16 | hmp-commands.hx | 6 ++++-- | 15 | hw/net/pcnet.c | 2 +- |
17 | monitor/hmp-cmds.c | 38 +++++++++++++++++++++++++++++++++++++- | 16 | 1 file changed, 1 insertion(+), 1 deletion(-) |
18 | 2 files changed, 41 insertions(+), 3 deletions(-) | ||
19 | 17 | ||
20 | diff --git a/hmp-commands.hx b/hmp-commands.hx | 18 | diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c |
21 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
22 | --- a/hmp-commands.hx | 20 | --- a/hw/net/pcnet.c |
23 | +++ b/hmp-commands.hx | 21 | +++ b/hw/net/pcnet.c |
24 | @@ -XXX,XX +XXX,XX @@ ETEXI | 22 | @@ -XXX,XX +XXX,XX @@ txagain: |
25 | 23 | if (BCR_SWSTYLE(s) == 1) | |
26 | { | 24 | add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS); |
27 | .name = "announce_self", | 25 | s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC; |
28 | - .args_type = "", | 26 | - pcnet_receive(qemu_get_queue(s->nic), s->buffer, s->xmit_pos); |
29 | - .params = "", | 27 | + qemu_receive_packet(qemu_get_queue(s->nic), s->buffer, s->xmit_pos); |
30 | + .args_type = "interfaces:s?", | 28 | s->looptest = 0; |
31 | + .params = "[interfaces]", | 29 | } else { |
32 | .help = "Trigger GARP/RARP announcements", | 30 | if (s->nic) { |
33 | .cmd = hmp_announce_self, | ||
34 | }, | ||
35 | @@ -XXX,XX +XXX,XX @@ STEXI | ||
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 | +An optional comma separated @var{interfaces} list restricts the announce to the | ||
40 | +named set of interfaces. | ||
41 | ETEXI | ||
42 | |||
43 | { | ||
44 | diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c | ||
45 | index XXXXXXX..XXXXXXX 100644 | ||
46 | --- a/monitor/hmp-cmds.c | ||
47 | +++ b/monitor/hmp-cmds.c | ||
48 | @@ -XXX,XX +XXX,XX @@ | ||
49 | #include "monitor/monitor-internal.h" | ||
50 | #include "monitor/qdev.h" | ||
51 | #include "qapi/error.h" | ||
52 | +#include "qapi/clone-visitor.h" | ||
53 | #include "qapi/opts-visitor.h" | ||
54 | #include "qapi/qapi-builtin-visit.h" | ||
55 | #include "qapi/qapi-commands-block.h" | ||
56 | @@ -XXX,XX +XXX,XX @@ | ||
57 | #include "qapi/qapi-commands-run-state.h" | ||
58 | #include "qapi/qapi-commands-tpm.h" | ||
59 | #include "qapi/qapi-commands-ui.h" | ||
60 | +#include "qapi/qapi-visit-net.h" | ||
61 | #include "qapi/qmp/qdict.h" | ||
62 | #include "qapi/qmp/qerror.h" | ||
63 | #include "qapi/string-input-visitor.h" | ||
64 | @@ -XXX,XX +XXX,XX @@ static void hmp_handle_error(Monitor *mon, Error **errp) | ||
65 | } | ||
66 | } | ||
67 | |||
68 | +/* | ||
69 | + * Produce a strList from a comma separated list. | ||
70 | + * A NULL or empty input string return NULL. | ||
71 | + */ | ||
72 | +static strList *strList_from_comma_list(const char *in) | ||
73 | +{ | ||
74 | + strList *res = NULL; | ||
75 | + strList **hook = &res; | ||
76 | + | ||
77 | + while (in && in[0]) { | ||
78 | + char *comma = strchr(in, ','); | ||
79 | + *hook = g_new0(strList, 1); | ||
80 | + | ||
81 | + if (comma) { | ||
82 | + (*hook)->value = g_strndup(in, comma - in); | ||
83 | + in = comma + 1; /* skip the , */ | ||
84 | + } else { | ||
85 | + (*hook)->value = g_strdup(in); | ||
86 | + in = NULL; | ||
87 | + } | ||
88 | + hook = &(*hook)->next; | ||
89 | + } | ||
90 | + | ||
91 | + return res; | ||
92 | +} | ||
93 | + | ||
94 | void hmp_info_name(Monitor *mon, const QDict *qdict) | ||
95 | { | ||
96 | NameInfo *info; | ||
97 | @@ -XXX,XX +XXX,XX @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict) | ||
98 | |||
99 | void hmp_announce_self(Monitor *mon, const QDict *qdict) | ||
100 | { | ||
101 | - qmp_announce_self(migrate_announce_params(), NULL); | ||
102 | + const char *interfaces_str = qdict_get_try_str(qdict, "interfaces"); | ||
103 | + AnnounceParameters *params = QAPI_CLONE(AnnounceParameters, | ||
104 | + migrate_announce_params()); | ||
105 | + | ||
106 | + qapi_free_strList(params->interfaces); | ||
107 | + params->interfaces = strList_from_comma_list(interfaces_str); | ||
108 | + params->has_interfaces = params->interfaces != NULL; | ||
109 | + qmp_announce_self(params, NULL); | ||
110 | + qapi_free_AnnounceParameters(params); | ||
111 | } | ||
112 | |||
113 | void hmp_migrate_cancel(Monitor *mon, const QDict *qdict) | ||
114 | -- | 31 | -- |
115 | 2.5.0 | 32 | 2.7.4 |
116 | 33 | ||
117 | 34 | diff view generated by jsdifflib |
1 | From: Markus Armbruster <armbru@redhat.com> | 1 | From: Alexander Bulekov <alxndr@bu.edu> |
---|---|---|---|
2 | 2 | ||
3 | Signed-off-by: Markus Armbruster <armbru@redhat.com> | 3 | This patch switches to use qemu_receive_packet() which can detect |
4 | reentrancy and return early. | ||
5 | |||
6 | This is intended to address CVE-2021-3416. | ||
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> | ||
4 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 12 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
5 | --- | 13 | --- |
6 | MAINTAINERS | 1 + | 14 | hw/net/cadence_gem.c | 4 ++-- |
7 | 1 file changed, 1 insertion(+) | 15 | 1 file changed, 2 insertions(+), 2 deletions(-) |
8 | 16 | ||
9 | diff --git a/MAINTAINERS b/MAINTAINERS | 17 | diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c |
10 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
11 | --- a/MAINTAINERS | 19 | --- a/hw/net/cadence_gem.c |
12 | +++ b/MAINTAINERS | 20 | +++ b/hw/net/cadence_gem.c |
13 | @@ -XXX,XX +XXX,XX @@ M: Jason Wang <jasowang@redhat.com> | 21 | @@ -XXX,XX +XXX,XX @@ static void gem_transmit(CadenceGEMState *s) |
14 | S: Maintained | 22 | /* Send the packet somewhere */ |
15 | F: net/ | 23 | if (s->phy_loop || (s->regs[GEM_NWCTRL] & |
16 | F: include/net/ | 24 | GEM_NWCTRL_LOCALLOOP)) { |
17 | +F: qemu-bridge-helper.c | 25 | - gem_receive(qemu_get_queue(s->nic), s->tx_packet, |
18 | T: git https://github.com/jasowang/qemu.git net | 26 | - total_bytes); |
19 | F: qapi/net.json | 27 | + qemu_receive_packet(qemu_get_queue(s->nic), s->tx_packet, |
20 | 28 | + total_bytes); | |
29 | } else { | ||
30 | qemu_send_packet(qemu_get_queue(s->nic), s->tx_packet, | ||
31 | total_bytes); | ||
21 | -- | 32 | -- |
22 | 2.5.0 | 33 | 2.7.4 |
23 | 34 | ||
24 | 35 | diff view generated by jsdifflib |
1 | From: Cédric Le Goater <clg@kaod.org> | 1 | From: Alexander Bulekov <alxndr@bu.edu> |
---|---|---|---|
2 | 2 | ||
3 | qdev_set_nic_properties() is already used in the Aspeed SoC level to | 3 | This patch switches to use qemu_receive_packet() which can detect |
4 | bind the ftgmac100 device to the netdev. | 4 | reentrancy and return early. |
5 | 5 | ||
6 | This is fixing support for multiple net devices. | 6 | This is intended to address CVE-2021-3416. |
7 | 7 | ||
8 | Signed-off-by: Cédric Le Goater <clg@kaod.org> | 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> | ||
9 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 12 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
10 | --- | 13 | --- |
11 | hw/net/ftgmac100.c | 2 -- | 14 | hw/net/lan9118.c | 2 +- |
12 | 1 file changed, 2 deletions(-) | 15 | 1 file changed, 1 insertion(+), 1 deletion(-) |
13 | 16 | ||
14 | diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c | 17 | diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c |
15 | index XXXXXXX..XXXXXXX 100644 | 18 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/hw/net/ftgmac100.c | 19 | --- a/hw/net/lan9118.c |
17 | +++ b/hw/net/ftgmac100.c | 20 | +++ b/hw/net/lan9118.c |
18 | @@ -XXX,XX +XXX,XX @@ static void ftgmac100_realize(DeviceState *dev, Error **errp) | 21 | @@ -XXX,XX +XXX,XX @@ static void do_tx_packet(lan9118_state *s) |
19 | sysbus_init_irq(sbd, &s->irq); | 22 | /* FIXME: Honor TX disable, and allow queueing of packets. */ |
20 | qemu_macaddr_default_if_unset(&s->conf.macaddr); | 23 | if (s->phy_control & 0x4000) { |
21 | 24 | /* This assumes the receive routine doesn't touch the VLANClient. */ | |
22 | - s->conf.peers.ncs[0] = nd_table[0].netdev; | 25 | - lan9118_receive(qemu_get_queue(s->nic), s->txp->data, s->txp->len); |
23 | - | 26 | + qemu_receive_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len); |
24 | s->nic = qemu_new_nic(&net_ftgmac100_info, &s->conf, | 27 | } else { |
25 | object_get_typename(OBJECT(dev)), DEVICE(dev)->id, | 28 | qemu_send_packet(qemu_get_queue(s->nic), s->txp->data, s->txp->len); |
26 | s); | 29 | } |
27 | -- | 30 | -- |
28 | 2.5.0 | 31 | 2.7.4 |
29 | 32 | ||
30 | 33 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | 1 | From: Cornelia Huck <cohuck@redhat.com> | |
2 | |||
3 | The pvrdma code relies on the pvrdma_ring.h kernel header for some | ||
4 | basic ring buffer handling. The content of that header isn't very | ||
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 | |||
10 | Let's reimplement the ring buffer handling directly in the pvrdma | ||
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> | ||
20 | --- | ||
21 | hw/rdma/vmw/pvrdma.h | 5 +- | ||
22 | hw/rdma/vmw/pvrdma_cmd.c | 6 +- | ||
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 | |||
31 | diff --git a/hw/rdma/vmw/pvrdma.h b/hw/rdma/vmw/pvrdma.h | ||
32 | index XXXXXXX..XXXXXXX 100644 | ||
33 | --- a/hw/rdma/vmw/pvrdma.h | ||
34 | +++ b/hw/rdma/vmw/pvrdma.h | ||
35 | @@ -XXX,XX +XXX,XX @@ | ||
36 | #include "../rdma_backend_defs.h" | ||
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 | } | ||
127 | |||
128 | void pvrdma_ring_read_inc(PvrdmaRing *ring) | ||
129 | { | ||
130 | - pvrdma_idx_ring_inc(&ring->ring_state->cons_head, ring->max_elems); | ||
131 | + uint32_t idx = qatomic_read(&ring->ring_state->cons_head); | ||
132 | + | ||
133 | + idx = (idx + 1) & ((ring->max_elems << 1) - 1); | ||
134 | + qatomic_set(&ring->ring_state->cons_head, idx); | ||
135 | } | ||
136 | |||
137 | void *pvrdma_ring_next_elem_write(PvrdmaRing *ring) | ||
138 | { | ||
139 | - int idx; | ||
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 | - } | ||
159 | - | ||
160 | + idx = tail & (ring->max_elems - 1); | ||
161 | offset = idx * ring->elem_sz; | ||
162 | return ring->pages[offset / TARGET_PAGE_SIZE] + (offset % TARGET_PAGE_SIZE); | ||
163 | } | ||
164 | |||
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 | - | ||
278 | -#ifndef __PVRDMA_RING_H__ | ||
279 | -#define __PVRDMA_RING_H__ | ||
280 | - | ||
281 | -#include "standard-headers/linux/types.h" | ||
282 | - | ||
283 | -#define PVRDMA_INVALID_IDX -1 /* Invalid index. */ | ||
284 | - | ||
285 | -struct pvrdma_ring { | ||
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 | -} | ||
300 | - | ||
301 | -static inline int32_t pvrdma_idx(int *var, uint32_t max_elems) | ||
302 | -{ | ||
303 | - const unsigned int idx = qatomic_read(var); | ||
304 | - | ||
305 | - if (pvrdma_idx_valid(idx, max_elems)) | ||
306 | - return idx & (max_elems - 1); | ||
307 | - return PVRDMA_INVALID_IDX; | ||
308 | -} | ||
309 | - | ||
310 | -static inline void pvrdma_idx_ring_inc(int *var, uint32_t max_elems) | ||
311 | -{ | ||
312 | - uint32_t idx = qatomic_read(var) + 1; /* Increment. */ | ||
313 | - | ||
314 | - idx &= (max_elems << 1) - 1; /* Modulo size, flip gen. */ | ||
315 | - qatomic_set(var, idx); | ||
316 | -} | ||
317 | - | ||
318 | -static inline int32_t pvrdma_idx_ring_has_space(const struct pvrdma_ring *r, | ||
319 | - uint32_t max_elems, uint32_t *out_tail) | ||
320 | -{ | ||
321 | - const uint32_t tail = qatomic_read(&r->prod_tail); | ||
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 | -- | ||
362 | 2.7.4 | ||
363 | |||
364 | diff view generated by jsdifflib |
1 | From: "Dr. David Alan Gilbert" <dgilbert@redhat.com> | 1 | From: Alexey Kirillov <lekiravi@yandex-team.ru> |
---|---|---|---|
2 | 2 | ||
3 | Allow the caller to restrict the set of interfaces that announces are | 3 | The query-netdev command is used to get the configuration of the current |
4 | sent on. The default is still to send on all interfaces. | 4 | network device backends (netdevs). |
5 | This is the QMP analog of the HMP command "info network" but only for | ||
6 | netdevs (i.e. excluding NIC and hubports). | ||
5 | 7 | ||
6 | e.g. | 8 | The query-netdev command returns an array of objects of the NetdevInfo |
9 | type, which are an extension of Netdev type. It means that response can | ||
10 | be used for netdev-add after small modification. This can be useful for | ||
11 | recreate the same netdev configuration. | ||
7 | 12 | ||
8 | { "execute": "announce-self", "arguments": { "initial": 50, "max": 550, "rounds": 5, "step": 50, "interfaces": ["vn2", "vn1"] } } | 13 | Information about the network device is filled in when it is created or |
14 | modified and is available through the NetClientState->stored_config. | ||
9 | 15 | ||
10 | This doesn't affect the behaviour of migraiton announcments. | 16 | Signed-off-by: Alexey Kirillov <lekiravi@yandex-team.ru> |
11 | 17 | Acked-by: Markus Armbruster <armbru@redhat.com> | |
12 | Note: There's still only one timer for the qmp command, so that | ||
13 | performing an 'announce-self' on one list of interfaces followed | ||
14 | by another 'announce-self' on another list will stop the announces | ||
15 | on the existing set. | ||
16 | |||
17 | Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com> | ||
18 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 18 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
19 | --- | 19 | --- |
20 | include/net/announce.h | 2 +- | 20 | include/net/net.h | 3 ++ |
21 | net/announce.c | 39 ++++++++++++++++++++++++++++++++------- | 21 | net/l2tpv3.c | 7 ++++ |
22 | net/trace-events | 2 +- | 22 | net/net.c | 30 +++++++++++++- |
23 | qapi/net.json | 11 ++++++++--- | 23 | net/netmap.c | 7 ++++ |
24 | 4 files changed, 42 insertions(+), 12 deletions(-) | 24 | net/slirp.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
25 | net/socket.c | 71 +++++++++++++++++++++++++++++++ | ||
26 | net/tap-win32.c | 9 ++++ | ||
27 | net/tap.c | 103 ++++++++++++++++++++++++++++++++++++++++++--- | ||
28 | net/vde.c | 22 ++++++++++ | ||
29 | net/vhost-user.c | 18 ++++++-- | ||
30 | net/vhost-vdpa.c | 14 +++++++ | ||
31 | qapi/net.json | 80 +++++++++++++++++++++++++++++++++++ | ||
32 | 12 files changed, 477 insertions(+), 9 deletions(-) | ||
25 | 33 | ||
26 | diff --git a/include/net/announce.h b/include/net/announce.h | 34 | diff --git a/include/net/net.h b/include/net/net.h |
27 | index XXXXXXX..XXXXXXX 100644 | 35 | index XXXXXXX..XXXXXXX 100644 |
28 | --- a/include/net/announce.h | 36 | --- a/include/net/net.h |
29 | +++ b/include/net/announce.h | 37 | +++ b/include/net/net.h |
30 | @@ -XXX,XX +XXX,XX @@ struct AnnounceTimer { | 38 | @@ -XXX,XX +XXX,XX @@ |
31 | /* Returns: update the timer to the next time point */ | 39 | #include "qapi/qapi-types-net.h" |
32 | int64_t qemu_announce_timer_step(AnnounceTimer *timer); | 40 | #include "net/queue.h" |
33 | 41 | #include "hw/qdev-properties-system.h" | |
34 | -/* Delete the underlying timer */ | 42 | +#include "qapi/clone-visitor.h" |
35 | +/* Delete the underlying timer and other data */ | 43 | +#include "qapi/qapi-visit-net.h" |
36 | void qemu_announce_timer_del(AnnounceTimer *timer); | 44 | |
37 | 45 | #define MAC_FMT "%02X:%02X:%02X:%02X:%02X:%02X" | |
38 | /* | 46 | #define MAC_ARG(x) ((uint8_t *)(x))[0], ((uint8_t *)(x))[1], \ |
39 | diff --git a/net/announce.c b/net/announce.c | 47 | @@ -XXX,XX +XXX,XX @@ struct NetClientState { |
40 | index XXXXXXX..XXXXXXX 100644 | 48 | char *model; |
41 | --- a/net/announce.c | 49 | char *name; |
42 | +++ b/net/announce.c | 50 | char info_str[256]; |
43 | @@ -XXX,XX +XXX,XX @@ void qemu_announce_timer_del(AnnounceTimer *timer) | 51 | + NetdevInfo *stored_config; |
44 | timer_free(timer->tm); | 52 | unsigned receive_disabled : 1; |
45 | timer->tm = NULL; | 53 | NetClientDestructor *destructor; |
54 | unsigned int queue_index; | ||
55 | diff --git a/net/l2tpv3.c b/net/l2tpv3.c | ||
56 | index XXXXXXX..XXXXXXX 100644 | ||
57 | --- a/net/l2tpv3.c | ||
58 | +++ b/net/l2tpv3.c | ||
59 | @@ -XXX,XX +XXX,XX @@ int net_init_l2tpv3(const Netdev *netdev, | ||
60 | |||
61 | l2tpv3_read_poll(s, true); | ||
62 | |||
63 | + /* Store startup parameters */ | ||
64 | + nc->stored_config = g_new0(NetdevInfo, 1); | ||
65 | + nc->stored_config->type = NET_BACKEND_L2TPV3; | ||
66 | + | ||
67 | + QAPI_CLONE_MEMBERS(NetdevL2TPv3Options, | ||
68 | + &nc->stored_config->u.l2tpv3, l2tpv3); | ||
69 | + | ||
70 | snprintf(s->nc.info_str, sizeof(s->nc.info_str), | ||
71 | "l2tpv3: connected"); | ||
72 | return 0; | ||
73 | diff --git a/net/net.c b/net/net.c | ||
74 | index XXXXXXX..XXXXXXX 100644 | ||
75 | --- a/net/net.c | ||
76 | +++ b/net/net.c | ||
77 | @@ -XXX,XX +XXX,XX @@ | ||
78 | #include "monitor/monitor.h" | ||
79 | #include "qemu/help_option.h" | ||
80 | #include "qapi/qapi-commands-net.h" | ||
81 | -#include "qapi/qapi-visit-net.h" | ||
82 | #include "qapi/qmp/qdict.h" | ||
83 | #include "qapi/qmp/qerror.h" | ||
84 | #include "qemu/error-report.h" | ||
85 | @@ -XXX,XX +XXX,XX @@ static void qemu_free_net_client(NetClientState *nc) | ||
46 | } | 86 | } |
47 | + qapi_free_strList(timer->params.interfaces); | 87 | g_free(nc->name); |
48 | + timer->params.interfaces = NULL; | 88 | g_free(nc->model); |
89 | + qapi_free_NetdevInfo(nc->stored_config); | ||
90 | if (nc->destructor) { | ||
91 | nc->destructor(nc); | ||
92 | } | ||
93 | @@ -XXX,XX +XXX,XX @@ RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name, | ||
94 | return filter_list; | ||
49 | } | 95 | } |
50 | 96 | ||
51 | /* | 97 | +NetdevInfoList *qmp_query_netdev(Error **errp) |
52 | @@ -XXX,XX +XXX,XX @@ static int announce_self_create(uint8_t *buf, | 98 | +{ |
53 | 99 | + NetdevInfoList *list = NULL; | |
54 | static void qemu_announce_self_iter(NICState *nic, void *opaque) | 100 | + NetClientState *nc; |
101 | + | ||
102 | + QTAILQ_FOREACH(nc, &net_clients, next) { | ||
103 | + /* | ||
104 | + * Only look at netdevs (backend network devices), not for each queue | ||
105 | + * or NIC / hubport | ||
106 | + */ | ||
107 | + if (nc->stored_config) { | ||
108 | + NetdevInfo *element = QAPI_CLONE(NetdevInfo, nc->stored_config); | ||
109 | + | ||
110 | + g_free(element->id); /* Need to dealloc empty id after clone */ | ||
111 | + element->id = g_strdup(nc->name); | ||
112 | + | ||
113 | + element->has_peer_id = nc->peer != NULL; | ||
114 | + if (element->has_peer_id) { | ||
115 | + element->peer_id = g_strdup(nc->peer->name); | ||
116 | + } | ||
117 | + | ||
118 | + QAPI_LIST_PREPEND(list, element); | ||
119 | + } | ||
120 | + } | ||
121 | + | ||
122 | + return list; | ||
123 | +} | ||
124 | + | ||
125 | void hmp_info_network(Monitor *mon, const QDict *qdict) | ||
55 | { | 126 | { |
56 | + AnnounceTimer *timer = opaque; | 127 | NetClientState *nc, *peer; |
57 | uint8_t buf[60]; | 128 | diff --git a/net/netmap.c b/net/netmap.c |
58 | int len; | 129 | index XXXXXXX..XXXXXXX 100644 |
59 | + bool skip; | 130 | --- a/net/netmap.c |
60 | + | 131 | +++ b/net/netmap.c |
61 | + if (timer->params.has_interfaces) { | 132 | @@ -XXX,XX +XXX,XX @@ int net_init_netmap(const Netdev *netdev, |
62 | + strList *entry = timer->params.interfaces; | 133 | pstrcpy(s->ifname, sizeof(s->ifname), netmap_opts->ifname); |
63 | + /* Skip unless we find our name in the requested list */ | 134 | netmap_read_poll(s, true); /* Initially only poll for reads. */ |
64 | + skip = true; | 135 | |
65 | + | 136 | + /* Store startup parameters */ |
66 | + while (entry) { | 137 | + nc->stored_config = g_new0(NetdevInfo, 1); |
67 | + if (!strcmp(entry->value, nic->ncs->name)) { | 138 | + nc->stored_config->type = NET_BACKEND_NETMAP; |
68 | + /* Found us */ | 139 | + |
69 | + skip = false; | 140 | + QAPI_CLONE_MEMBERS(NetdevNetmapOptions, |
70 | + break; | 141 | + &nc->stored_config->u.netmap, netmap_opts); |
71 | + } | 142 | + |
72 | + entry = entry->next; | 143 | return 0; |
144 | } | ||
145 | |||
146 | diff --git a/net/slirp.c b/net/slirp.c | ||
147 | index XXXXXXX..XXXXXXX 100644 | ||
148 | --- a/net/slirp.c | ||
149 | +++ b/net/slirp.c | ||
150 | @@ -XXX,XX +XXX,XX @@ static int net_slirp_init(NetClientState *peer, const char *model, | ||
151 | int shift; | ||
152 | char *end; | ||
153 | struct slirp_config_str *config; | ||
154 | + NetdevUserOptions *stored; | ||
155 | + StringList **stored_hostfwd; | ||
156 | + StringList **stored_guestfwd; | ||
157 | |||
158 | if (!ipv4 && (vnetwork || vhost || vnameserver)) { | ||
159 | error_setg(errp, "IPv4 disabled but netmask/host/dns provided"); | ||
160 | @@ -XXX,XX +XXX,XX @@ static int net_slirp_init(NetClientState *peer, const char *model, | ||
161 | |||
162 | nc = qemu_new_net_client(&net_slirp_info, peer, model, name); | ||
163 | |||
164 | + /* Store startup parameters */ | ||
165 | + nc->stored_config = g_new0(NetdevInfo, 1); | ||
166 | + nc->stored_config->type = NET_BACKEND_USER; | ||
167 | + stored = &nc->stored_config->u.user; | ||
168 | + | ||
169 | + if (vhostname) { | ||
170 | + stored->has_hostname = true; | ||
171 | + stored->hostname = g_strdup(vhostname); | ||
172 | + } | ||
173 | + | ||
174 | + stored->has_q_restrict = true; | ||
175 | + stored->q_restrict = restricted; | ||
176 | + | ||
177 | + stored->has_ipv4 = true; | ||
178 | + stored->ipv4 = ipv4; | ||
179 | + | ||
180 | + stored->has_ipv6 = true; | ||
181 | + stored->ipv6 = ipv6; | ||
182 | + | ||
183 | + if (ipv4) { | ||
184 | + uint8_t *net_bytes = (uint8_t *)&net; | ||
185 | + uint8_t *mask_bytes = (uint8_t *)&mask; | ||
186 | + | ||
187 | + stored->has_net = true; | ||
188 | + stored->net = g_strdup_printf("%d.%d.%d.%d/%d.%d.%d.%d", | ||
189 | + net_bytes[0], net_bytes[1], | ||
190 | + net_bytes[2], net_bytes[3], | ||
191 | + mask_bytes[0], mask_bytes[1], | ||
192 | + mask_bytes[2], mask_bytes[3]); | ||
193 | + | ||
194 | + stored->has_host = true; | ||
195 | + stored->host = g_strdup(inet_ntoa(host)); | ||
196 | + } | ||
197 | + | ||
198 | + if (tftp_export) { | ||
199 | + stored->has_tftp = true; | ||
200 | + stored->tftp = g_strdup(tftp_export); | ||
201 | + } | ||
202 | + | ||
203 | + if (bootfile) { | ||
204 | + stored->has_bootfile = true; | ||
205 | + stored->bootfile = g_strdup(bootfile); | ||
206 | + } | ||
207 | + | ||
208 | + if (vdhcp_start) { | ||
209 | + stored->has_dhcpstart = true; | ||
210 | + stored->dhcpstart = g_strdup(vdhcp_start); | ||
211 | + } | ||
212 | + | ||
213 | + if (ipv4) { | ||
214 | + stored->has_dns = true; | ||
215 | + stored->dns = g_strdup(inet_ntoa(dns)); | ||
216 | + } | ||
217 | + | ||
218 | + if (dnssearch) { | ||
219 | + stored->has_dnssearch = true; | ||
220 | + StringList **stored_list = &stored->dnssearch; | ||
221 | + | ||
222 | + for (int i = 0; dnssearch[i]; i++) { | ||
223 | + String *element = g_new0(String, 1); | ||
224 | + | ||
225 | + element->str = g_strdup(dnssearch[i]); | ||
226 | + QAPI_LIST_APPEND(stored_list, element); | ||
73 | + } | 227 | + } |
74 | + } else { | 228 | + } |
75 | + skip = false; | 229 | + |
76 | + } | 230 | + if (vdomainname) { |
77 | + | 231 | + stored->has_domainname = true; |
78 | + trace_qemu_announce_self_iter(nic->ncs->name, | 232 | + stored->domainname = g_strdup(vdomainname); |
79 | + qemu_ether_ntoa(&nic->conf->macaddr), skip); | 233 | + } |
80 | 234 | + | |
81 | - trace_qemu_announce_self_iter(qemu_ether_ntoa(&nic->conf->macaddr)); | 235 | + if (ipv6) { |
82 | - len = announce_self_create(buf, nic->conf->macaddr.a); | 236 | + char addrstr[INET6_ADDRSTRLEN]; |
83 | + if (!skip) { | 237 | + const char *res; |
84 | + len = announce_self_create(buf, nic->conf->macaddr.a); | 238 | + |
85 | 239 | + stored->has_ipv6_prefix = true; | |
86 | - qemu_send_packet_raw(qemu_get_queue(nic), buf, len); | 240 | + stored->ipv6_prefix = g_strdup(vprefix6); |
87 | + qemu_send_packet_raw(qemu_get_queue(nic), buf, len); | 241 | + |
88 | 242 | + stored->has_ipv6_prefixlen = true; | |
89 | - /* if the NIC provides it's own announcement support, use it as well */ | 243 | + stored->ipv6_prefixlen = vprefix6_len; |
90 | - if (nic->ncs->info->announce) { | 244 | + |
91 | - nic->ncs->info->announce(nic->ncs); | 245 | + res = inet_ntop(AF_INET6, &ip6_host, |
92 | + /* if the NIC provides it's own announcement support, use it as well */ | 246 | + addrstr, sizeof(addrstr)); |
93 | + if (nic->ncs->info->announce) { | 247 | + |
94 | + nic->ncs->info->announce(nic->ncs); | 248 | + stored->has_ipv6_host = true; |
249 | + stored->ipv6_host = g_strdup(res); | ||
250 | + | ||
251 | + res = inet_ntop(AF_INET6, &ip6_dns, | ||
252 | + addrstr, sizeof(addrstr)); | ||
253 | + | ||
254 | + stored->has_ipv6_dns = true; | ||
255 | + stored->ipv6_dns = g_strdup(res); | ||
256 | + } | ||
257 | + | ||
258 | + if (smb_export) { | ||
259 | + stored->has_smb = true; | ||
260 | + stored->smb = g_strdup(smb_export); | ||
261 | + } | ||
262 | + | ||
263 | + if (vsmbserver) { | ||
264 | + stored->has_smbserver = true; | ||
265 | + stored->smbserver = g_strdup(vsmbserver); | ||
266 | + } | ||
267 | + | ||
268 | + if (tftp_server_name) { | ||
269 | + stored->has_tftp_server_name = true; | ||
270 | + stored->tftp_server_name = g_strdup(tftp_server_name); | ||
271 | + } | ||
272 | + | ||
273 | snprintf(nc->info_str, sizeof(nc->info_str), | ||
274 | "net=%s,restrict=%s", inet_ntoa(net), | ||
275 | restricted ? "on" : "off"); | ||
276 | @@ -XXX,XX +XXX,XX @@ static int net_slirp_init(NetClientState *peer, const char *model, | ||
277 | s->poll_notifier.notify = net_slirp_poll_notify; | ||
278 | main_loop_poll_add_notifier(&s->poll_notifier); | ||
279 | |||
280 | + stored_hostfwd = &stored->hostfwd; | ||
281 | + stored_guestfwd = &stored->guestfwd; | ||
282 | + | ||
283 | for (config = slirp_configs; config; config = config->next) { | ||
284 | + String *element = g_new0(String, 1); | ||
285 | + | ||
286 | + element->str = g_strdup(config->str); | ||
287 | if (config->flags & SLIRP_CFG_HOSTFWD) { | ||
288 | if (slirp_hostfwd(s, config->str, errp) < 0) { | ||
289 | goto error; | ||
290 | } | ||
291 | + stored->has_hostfwd = true; | ||
292 | + QAPI_LIST_APPEND(stored_hostfwd, element); | ||
293 | } else { | ||
294 | if (slirp_guestfwd(s, config->str, errp) < 0) { | ||
295 | goto error; | ||
296 | } | ||
297 | + stored->has_guestfwd = true; | ||
298 | + QAPI_LIST_APPEND(stored_guestfwd, element); | ||
299 | } | ||
300 | } | ||
301 | #ifndef _WIN32 | ||
302 | diff --git a/net/socket.c b/net/socket.c | ||
303 | index XXXXXXX..XXXXXXX 100644 | ||
304 | --- a/net/socket.c | ||
305 | +++ b/net/socket.c | ||
306 | @@ -XXX,XX +XXX,XX @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer, | ||
307 | NetSocketState *s; | ||
308 | SocketAddress *sa; | ||
309 | SocketAddressType sa_type; | ||
310 | + NetdevSocketOptions *stored; | ||
311 | |||
312 | sa = socket_local_address(fd, errp); | ||
313 | if (!sa) { | ||
314 | @@ -XXX,XX +XXX,XX @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer, | ||
315 | net_socket_rs_init(&s->rs, net_socket_rs_finalize, false); | ||
316 | net_socket_read_poll(s, true); | ||
317 | |||
318 | + /* Store startup parameters */ | ||
319 | + nc->stored_config = g_new0(NetdevInfo, 1); | ||
320 | + nc->stored_config->type = NET_BACKEND_SOCKET; | ||
321 | + stored = &nc->stored_config->u.socket; | ||
322 | + | ||
323 | + stored->has_fd = true; | ||
324 | + stored->fd = g_strdup_printf("%d", fd); | ||
325 | + | ||
326 | /* mcast: save bound address as dst */ | ||
327 | if (is_connected && mcast != NULL) { | ||
328 | + stored->has_mcast = true; | ||
329 | + stored->mcast = g_strdup(mcast); | ||
330 | + | ||
331 | s->dgram_dst = saddr; | ||
332 | snprintf(nc->info_str, sizeof(nc->info_str), | ||
333 | "socket: fd=%d (cloned mcast=%s:%d)", | ||
334 | @@ -XXX,XX +XXX,XX @@ static NetSocketState *net_socket_fd_init_stream(NetClientState *peer, | ||
335 | { | ||
336 | NetClientState *nc; | ||
337 | NetSocketState *s; | ||
338 | + NetdevSocketOptions *stored; | ||
339 | |||
340 | nc = qemu_new_net_client(&net_socket_info, peer, model, name); | ||
341 | |||
342 | @@ -XXX,XX +XXX,XX @@ static NetSocketState *net_socket_fd_init_stream(NetClientState *peer, | ||
343 | } else { | ||
344 | qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s); | ||
345 | } | ||
346 | + | ||
347 | + /* Store startup parameters */ | ||
348 | + nc->stored_config = g_new0(NetdevInfo, 1); | ||
349 | + nc->stored_config->type = NET_BACKEND_SOCKET; | ||
350 | + stored = &nc->stored_config->u.socket; | ||
351 | + | ||
352 | + stored->has_fd = true; | ||
353 | + stored->fd = g_strdup_printf("%d", fd); | ||
354 | + | ||
355 | return s; | ||
356 | } | ||
357 | |||
358 | @@ -XXX,XX +XXX,XX @@ static void net_socket_accept(void *opaque) | ||
359 | struct sockaddr_in saddr; | ||
360 | socklen_t len; | ||
361 | int fd; | ||
362 | + NetdevSocketOptions *stored; | ||
363 | |||
364 | for(;;) { | ||
365 | len = sizeof(saddr); | ||
366 | @@ -XXX,XX +XXX,XX @@ static void net_socket_accept(void *opaque) | ||
367 | s->fd = fd; | ||
368 | s->nc.link_down = false; | ||
369 | net_socket_connect(s); | ||
370 | + | ||
371 | + /* Store additional startup parameters (extend net_socket_listen_init) */ | ||
372 | + stored = &s->nc.stored_config->u.socket; | ||
373 | + | ||
374 | + stored->has_fd = true; | ||
375 | + stored->fd = g_strdup_printf("%d", fd); | ||
376 | + | ||
377 | snprintf(s->nc.info_str, sizeof(s->nc.info_str), | ||
378 | "socket: connection from %s:%d", | ||
379 | inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); | ||
380 | @@ -XXX,XX +XXX,XX @@ static int net_socket_listen_init(NetClientState *peer, | ||
381 | NetSocketState *s; | ||
382 | struct sockaddr_in saddr; | ||
383 | int fd, ret; | ||
384 | + NetdevSocketOptions *stored; | ||
385 | |||
386 | if (parse_host_port(&saddr, host_str, errp) < 0) { | ||
387 | return -1; | ||
388 | @@ -XXX,XX +XXX,XX @@ static int net_socket_listen_init(NetClientState *peer, | ||
389 | net_socket_rs_init(&s->rs, net_socket_rs_finalize, false); | ||
390 | |||
391 | qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s); | ||
392 | + | ||
393 | + /* Store startup parameters */ | ||
394 | + nc->stored_config = g_new0(NetdevInfo, 1); | ||
395 | + nc->stored_config->type = NET_BACKEND_SOCKET; | ||
396 | + stored = &nc->stored_config->u.socket; | ||
397 | + | ||
398 | + stored->has_listen = true; | ||
399 | + stored->listen = g_strdup(host_str); | ||
400 | + | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | @@ -XXX,XX +XXX,XX @@ static int net_socket_connect_init(NetClientState *peer, | ||
405 | NetSocketState *s; | ||
406 | int fd, connected, ret; | ||
407 | struct sockaddr_in saddr; | ||
408 | + NetdevSocketOptions *stored; | ||
409 | |||
410 | if (parse_host_port(&saddr, host_str, errp) < 0) { | ||
411 | return -1; | ||
412 | @@ -XXX,XX +XXX,XX @@ static int net_socket_connect_init(NetClientState *peer, | ||
413 | return -1; | ||
414 | } | ||
415 | |||
416 | + /* Store additional startup parameters (extend net_socket_fd_init) */ | ||
417 | + stored = &s->nc.stored_config->u.socket; | ||
418 | + | ||
419 | + stored->has_connect = true; | ||
420 | + stored->connect = g_strdup(host_str); | ||
421 | + | ||
422 | snprintf(s->nc.info_str, sizeof(s->nc.info_str), | ||
423 | "socket: connect to %s:%d", | ||
424 | inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); | ||
425 | @@ -XXX,XX +XXX,XX @@ static int net_socket_mcast_init(NetClientState *peer, | ||
426 | int fd; | ||
427 | struct sockaddr_in saddr; | ||
428 | struct in_addr localaddr, *param_localaddr; | ||
429 | + NetdevSocketOptions *stored; | ||
430 | |||
431 | if (parse_host_port(&saddr, host_str, errp) < 0) { | ||
432 | return -1; | ||
433 | @@ -XXX,XX +XXX,XX @@ static int net_socket_mcast_init(NetClientState *peer, | ||
434 | |||
435 | s->dgram_dst = saddr; | ||
436 | |||
437 | + /* Store additional startup parameters (extend net_socket_fd_init) */ | ||
438 | + stored = &s->nc.stored_config->u.socket; | ||
439 | + | ||
440 | + if (!stored->has_mcast) { | ||
441 | + stored->has_mcast = true; | ||
442 | + stored->mcast = g_strdup(host_str); | ||
443 | + } | ||
444 | + | ||
445 | + if (localaddr_str) { | ||
446 | + stored->has_localaddr = true; | ||
447 | + stored->localaddr = g_strdup(localaddr_str); | ||
448 | + } | ||
449 | + | ||
450 | snprintf(s->nc.info_str, sizeof(s->nc.info_str), | ||
451 | "socket: mcast=%s:%d", | ||
452 | inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); | ||
453 | @@ -XXX,XX +XXX,XX @@ static int net_socket_udp_init(NetClientState *peer, | ||
454 | NetSocketState *s; | ||
455 | int fd, ret; | ||
456 | struct sockaddr_in laddr, raddr; | ||
457 | + NetdevSocketOptions *stored; | ||
458 | |||
459 | if (parse_host_port(&laddr, lhost, errp) < 0) { | ||
460 | return -1; | ||
461 | @@ -XXX,XX +XXX,XX @@ static int net_socket_udp_init(NetClientState *peer, | ||
462 | |||
463 | s->dgram_dst = raddr; | ||
464 | |||
465 | + /* Store additional startup parameters (extend net_socket_fd_init) */ | ||
466 | + stored = &s->nc.stored_config->u.socket; | ||
467 | + | ||
468 | + stored->has_localaddr = true; | ||
469 | + stored->localaddr = g_strdup(lhost); | ||
470 | + | ||
471 | + stored->has_udp = true; | ||
472 | + stored->udp = g_strdup(rhost); | ||
473 | + | ||
474 | snprintf(s->nc.info_str, sizeof(s->nc.info_str), | ||
475 | "socket: udp=%s:%d", | ||
476 | inet_ntoa(raddr.sin_addr), ntohs(raddr.sin_port)); | ||
477 | diff --git a/net/tap-win32.c b/net/tap-win32.c | ||
478 | index XXXXXXX..XXXXXXX 100644 | ||
479 | --- a/net/tap-win32.c | ||
480 | +++ b/net/tap-win32.c | ||
481 | @@ -XXX,XX +XXX,XX @@ static int tap_win32_init(NetClientState *peer, const char *model, | ||
482 | NetClientState *nc; | ||
483 | TAPState *s; | ||
484 | tap_win32_overlapped_t *handle; | ||
485 | + NetdevTapOptions *stored; | ||
486 | |||
487 | if (tap_win32_open(&handle, ifname) < 0) { | ||
488 | printf("tap: Could not open '%s'\n", ifname); | ||
489 | @@ -XXX,XX +XXX,XX @@ static int tap_win32_init(NetClientState *peer, const char *model, | ||
490 | |||
491 | s = DO_UPCAST(TAPState, nc, nc); | ||
492 | |||
493 | + /* Store startup parameters */ | ||
494 | + nc->stored_config = g_new0(NetdevInfo, 1); | ||
495 | + nc->stored_config->type = NET_BACKEND_TAP; | ||
496 | + stored = &nc->stored_config->u.tap; | ||
497 | + | ||
498 | + stored->has_ifname = true; | ||
499 | + stored->ifname = g_strdup(ifname); | ||
500 | + | ||
501 | snprintf(s->nc.info_str, sizeof(s->nc.info_str), | ||
502 | "tap: ifname=%s", ifname); | ||
503 | |||
504 | diff --git a/net/tap.c b/net/tap.c | ||
505 | index XXXXXXX..XXXXXXX 100644 | ||
506 | --- a/net/tap.c | ||
507 | +++ b/net/tap.c | ||
508 | @@ -XXX,XX +XXX,XX @@ int net_init_bridge(const Netdev *netdev, const char *name, | ||
509 | const char *helper, *br; | ||
510 | TAPState *s; | ||
511 | int fd, vnet_hdr; | ||
512 | + NetdevBridgeOptions *stored; | ||
513 | |||
514 | assert(netdev->type == NET_CLIENT_DRIVER_BRIDGE); | ||
515 | bridge = &netdev->u.bridge; | ||
516 | @@ -XXX,XX +XXX,XX @@ int net_init_bridge(const Netdev *netdev, const char *name, | ||
517 | } | ||
518 | s = net_tap_fd_init(peer, "bridge", name, fd, vnet_hdr); | ||
519 | |||
520 | + /* Store startup parameters */ | ||
521 | + s->nc.stored_config = g_new0(NetdevInfo, 1); | ||
522 | + s->nc.stored_config->type = NET_BACKEND_BRIDGE; | ||
523 | + stored = &s->nc.stored_config->u.bridge; | ||
524 | + | ||
525 | + if (br) { | ||
526 | + stored->has_br = true; | ||
527 | + stored->br = g_strdup(br); | ||
528 | + } | ||
529 | + | ||
530 | + if (helper) { | ||
531 | + stored->has_helper = true; | ||
532 | + stored->helper = g_strdup(helper); | ||
533 | + } | ||
534 | + | ||
535 | snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s,br=%s", helper, | ||
536 | br); | ||
537 | |||
538 | @@ -XXX,XX +XXX,XX @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, | ||
539 | const char *model, const char *name, | ||
540 | const char *ifname, const char *script, | ||
541 | const char *downscript, const char *vhostfdname, | ||
542 | - int vnet_hdr, int fd, Error **errp) | ||
543 | + int vnet_hdr, int fd, NetdevInfo **common_stored, | ||
544 | + Error **errp) | ||
545 | { | ||
546 | Error *err = NULL; | ||
547 | TAPState *s = net_tap_fd_init(peer, model, name, fd, vnet_hdr); | ||
548 | int vhostfd; | ||
549 | + NetdevTapOptions *stored; | ||
550 | |||
551 | tap_set_sndbuf(s->fd, tap, &err); | ||
552 | if (err) { | ||
553 | @@ -XXX,XX +XXX,XX @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, | ||
554 | return; | ||
555 | } | ||
556 | |||
557 | + /* Store startup parameters */ | ||
558 | + if (!*common_stored) { | ||
559 | + *common_stored = g_new0(NetdevInfo, 1); | ||
560 | + (*common_stored)->type = NET_BACKEND_TAP; | ||
561 | + s->nc.stored_config = *common_stored; | ||
562 | + } | ||
563 | + stored = &(*common_stored)->u.tap; | ||
564 | + | ||
565 | + if (tap->has_sndbuf && !stored->has_sndbuf) { | ||
566 | + stored->has_sndbuf = true; | ||
567 | + stored->sndbuf = tap->sndbuf; | ||
568 | + } | ||
569 | + | ||
570 | + if (vnet_hdr && !stored->has_vnet_hdr) { | ||
571 | + stored->has_vnet_hdr = true; | ||
572 | + stored->vnet_hdr = true; | ||
573 | + } | ||
574 | + | ||
575 | if (tap->has_fd || tap->has_fds) { | ||
576 | + if (!stored->has_fds) { | ||
577 | + stored->has_fds = true; | ||
578 | + stored->fds = g_strdup_printf("%d", fd); | ||
579 | + } else { | ||
580 | + char *tmp_s = stored->fds; | ||
581 | + stored->fds = g_strdup_printf("%s:%d", stored->fds, fd); | ||
582 | + g_free(tmp_s); | ||
95 | + } | 583 | + } |
584 | + | ||
585 | snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd); | ||
586 | } else if (tap->has_helper) { | ||
587 | + if (!stored->has_helper) { | ||
588 | + stored->has_helper = true; | ||
589 | + stored->helper = g_strdup(tap->helper); | ||
590 | + } | ||
591 | + | ||
592 | + if (!stored->has_br) { | ||
593 | + stored->has_br = true; | ||
594 | + stored->br = tap->has_br ? g_strdup(tap->br) : | ||
595 | + g_strdup(DEFAULT_BRIDGE_INTERFACE); | ||
596 | + } | ||
597 | + | ||
598 | snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s", | ||
599 | tap->helper); | ||
600 | } else { | ||
601 | + if (ifname && !stored->has_ifname) { | ||
602 | + stored->has_ifname = true; | ||
603 | + stored->ifname = g_strdup(ifname); | ||
604 | + } | ||
605 | + | ||
606 | + if (script && !stored->has_script) { | ||
607 | + stored->has_script = true; | ||
608 | + stored->script = g_strdup(script); | ||
609 | + } | ||
610 | + | ||
611 | + if (downscript && !stored->has_downscript) { | ||
612 | + stored->has_downscript = true; | ||
613 | + stored->downscript = g_strdup(downscript); | ||
614 | + } | ||
615 | + | ||
616 | snprintf(s->nc.info_str, sizeof(s->nc.info_str), | ||
617 | "ifname=%s,script=%s,downscript=%s", ifname, script, | ||
618 | downscript); | ||
619 | @@ -XXX,XX +XXX,XX @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, | ||
620 | vhostfdname || (tap->has_vhostforce && tap->vhostforce)) { | ||
621 | VhostNetOptions options; | ||
622 | |||
623 | + stored->has_vhost = true; | ||
624 | + stored->vhost = true; | ||
625 | + | ||
626 | + if (tap->has_vhostforce && tap->vhostforce) { | ||
627 | + stored->has_vhostforce = true; | ||
628 | + stored->vhostforce = true; | ||
629 | + } | ||
630 | + | ||
631 | options.backend_type = VHOST_BACKEND_TYPE_KERNEL; | ||
632 | options.net_backend = &s->nc; | ||
633 | if (tap->has_poll_us) { | ||
634 | + stored->has_poll_us = true; | ||
635 | + stored->poll_us = tap->poll_us; | ||
636 | + | ||
637 | options.busyloop_timeout = tap->poll_us; | ||
638 | } else { | ||
639 | options.busyloop_timeout = 0; | ||
640 | @@ -XXX,XX +XXX,XX @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, | ||
641 | } | ||
642 | options.opaque = (void *)(uintptr_t)vhostfd; | ||
643 | |||
644 | + if (!stored->has_vhostfds) { | ||
645 | + stored->has_vhostfds = true; | ||
646 | + stored->vhostfds = g_strdup_printf("%d", vhostfd); | ||
647 | + } else { | ||
648 | + char *tmp_s = stored->vhostfds; | ||
649 | + stored->vhostfds = g_strdup_printf("%s:%d", stored->fds, vhostfd); | ||
650 | + g_free(tmp_s); | ||
651 | + } | ||
652 | + | ||
653 | s->vhost_net = vhost_net_init(&options); | ||
654 | if (!s->vhost_net) { | ||
655 | if (tap->has_vhostforce && tap->vhostforce) { | ||
656 | @@ -XXX,XX +XXX,XX @@ int net_init_tap(const Netdev *netdev, const char *name, | ||
657 | const char *vhostfdname; | ||
658 | char ifname[128]; | ||
659 | int ret = 0; | ||
660 | + NetdevInfo *common_stored = NULL; /* will store configuration */ | ||
661 | |||
662 | assert(netdev->type == NET_CLIENT_DRIVER_TAP); | ||
663 | tap = &netdev->u.tap; | ||
664 | @@ -XXX,XX +XXX,XX @@ int net_init_tap(const Netdev *netdev, const char *name, | ||
665 | |||
666 | net_init_tap_one(tap, peer, "tap", name, NULL, | ||
667 | script, downscript, | ||
668 | - vhostfdname, vnet_hdr, fd, &err); | ||
669 | + vhostfdname, vnet_hdr, fd, &common_stored, &err); | ||
670 | if (err) { | ||
671 | error_propagate(errp, err); | ||
672 | close(fd); | ||
673 | @@ -XXX,XX +XXX,XX @@ int net_init_tap(const Netdev *netdev, const char *name, | ||
674 | net_init_tap_one(tap, peer, "tap", name, ifname, | ||
675 | script, downscript, | ||
676 | tap->has_vhostfds ? vhost_fds[i] : NULL, | ||
677 | - vnet_hdr, fd, &err); | ||
678 | + vnet_hdr, fd, &common_stored, &err); | ||
679 | if (err) { | ||
680 | error_propagate(errp, err); | ||
681 | ret = -1; | ||
682 | @@ -XXX,XX +XXX,XX @@ free_fail: | ||
683 | |||
684 | net_init_tap_one(tap, peer, "bridge", name, ifname, | ||
685 | script, downscript, vhostfdname, | ||
686 | - vnet_hdr, fd, &err); | ||
687 | + vnet_hdr, fd, &common_stored, &err); | ||
688 | if (err) { | ||
689 | error_propagate(errp, err); | ||
690 | close(fd); | ||
691 | @@ -XXX,XX +XXX,XX @@ free_fail: | ||
692 | net_init_tap_one(tap, peer, "tap", name, ifname, | ||
693 | i >= 1 ? "no" : script, | ||
694 | i >= 1 ? "no" : downscript, | ||
695 | - vhostfdname, vnet_hdr, fd, &err); | ||
696 | + vhostfdname, vnet_hdr, fd, | ||
697 | + &common_stored, &err); | ||
698 | if (err) { | ||
699 | error_propagate(errp, err); | ||
700 | close(fd); | ||
701 | diff --git a/net/vde.c b/net/vde.c | ||
702 | index XXXXXXX..XXXXXXX 100644 | ||
703 | --- a/net/vde.c | ||
704 | +++ b/net/vde.c | ||
705 | @@ -XXX,XX +XXX,XX @@ static int net_vde_init(NetClientState *peer, const char *model, | ||
706 | VDECONN *vde; | ||
707 | char *init_group = (char *)group; | ||
708 | char *init_sock = (char *)sock; | ||
709 | + NetdevVdeOptions *stored; | ||
710 | |||
711 | struct vde_open_args args = { | ||
712 | .port = port, | ||
713 | @@ -XXX,XX +XXX,XX @@ static int net_vde_init(NetClientState *peer, const char *model, | ||
714 | |||
715 | qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s); | ||
716 | |||
717 | + /* Store startup parameters */ | ||
718 | + nc->stored_config = g_new0(NetdevInfo, 1); | ||
719 | + nc->stored_config->type = NET_BACKEND_VDE; | ||
720 | + stored = &nc->stored_config->u.vde; | ||
721 | + | ||
722 | + if (sock) { | ||
723 | + stored->has_sock = true; | ||
724 | + stored->sock = g_strdup(sock); | ||
725 | + } | ||
726 | + | ||
727 | + stored->has_port = true; | ||
728 | + stored->port = port; | ||
729 | + | ||
730 | + if (group) { | ||
731 | + stored->has_group = true; | ||
732 | + stored->group = g_strdup(group); | ||
733 | + } | ||
734 | + | ||
735 | + stored->has_mode = true; | ||
736 | + stored->mode = mode; | ||
737 | + | ||
738 | return 0; | ||
739 | } | ||
740 | |||
741 | diff --git a/net/vhost-user.c b/net/vhost-user.c | ||
742 | index XXXXXXX..XXXXXXX 100644 | ||
743 | --- a/net/vhost-user.c | ||
744 | +++ b/net/vhost-user.c | ||
745 | @@ -XXX,XX +XXX,XX @@ static void net_vhost_user_event(void *opaque, QEMUChrEvent event) | ||
746 | } | ||
747 | |||
748 | static int net_vhost_user_init(NetClientState *peer, const char *device, | ||
749 | - const char *name, Chardev *chr, | ||
750 | - int queues) | ||
751 | + const char *name, const char *chardev, | ||
752 | + Chardev *chr, int queues) | ||
753 | { | ||
754 | Error *err = NULL; | ||
755 | NetClientState *nc, *nc0 = NULL; | ||
756 | NetVhostUserState *s = NULL; | ||
757 | VhostUserState *user; | ||
758 | int i; | ||
759 | + NetdevVhostUserOptions *stored; | ||
760 | |||
761 | assert(name); | ||
762 | assert(queues > 0); | ||
763 | @@ -XXX,XX +XXX,XX @@ static int net_vhost_user_init(NetClientState *peer, const char *device, | ||
764 | |||
765 | assert(s->vhost_net); | ||
766 | |||
767 | + /* Store startup parameters */ | ||
768 | + nc0->stored_config = g_new0(NetdevInfo, 1); | ||
769 | + nc0->stored_config->type = NET_BACKEND_VHOST_USER; | ||
770 | + stored = &nc0->stored_config->u.vhost_user; | ||
771 | + | ||
772 | + stored->chardev = g_strdup(chardev); | ||
773 | + | ||
774 | + stored->has_queues = true; | ||
775 | + stored->queues = queues; | ||
776 | + | ||
777 | return 0; | ||
778 | |||
779 | err: | ||
780 | @@ -XXX,XX +XXX,XX @@ int net_init_vhost_user(const Netdev *netdev, const char *name, | ||
781 | return -1; | ||
96 | } | 782 | } |
783 | |||
784 | - return net_vhost_user_init(peer, "vhost_user", name, chr, queues); | ||
785 | + return net_vhost_user_init(peer, "vhost_user", name, | ||
786 | + vhost_user_opts->chardev, chr, queues); | ||
97 | } | 787 | } |
98 | static void qemu_announce_self_once(void *opaque) | 788 | diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c |
99 | { | 789 | index XXXXXXX..XXXXXXX 100644 |
100 | AnnounceTimer *timer = (AnnounceTimer *)opaque; | 790 | --- a/net/vhost-vdpa.c |
101 | 791 | +++ b/net/vhost-vdpa.c | |
102 | - qemu_foreach_nic(qemu_announce_self_iter, NULL); | 792 | @@ -XXX,XX +XXX,XX @@ static int net_vhost_vdpa_init(NetClientState *peer, const char *device, |
103 | + qemu_foreach_nic(qemu_announce_self_iter, timer); | 793 | VhostVDPAState *s; |
104 | 794 | int vdpa_device_fd = -1; | |
105 | if (--timer->round) { | 795 | int ret = 0; |
106 | qemu_announce_timer_step(timer); | 796 | + NetdevVhostVDPAOptions *stored; |
107 | diff --git a/net/trace-events b/net/trace-events | 797 | + |
108 | index XXXXXXX..XXXXXXX 100644 | 798 | assert(name); |
109 | --- a/net/trace-events | 799 | nc = qemu_new_net_client(&net_vhost_vdpa_info, peer, device, name); |
110 | +++ b/net/trace-events | 800 | + |
111 | @@ -XXX,XX +XXX,XX @@ | 801 | + /* Store startup parameters */ |
112 | # See docs/devel/tracing.txt for syntax documentation. | 802 | + nc->stored_config = g_new0(NetdevInfo, 1); |
113 | 803 | + nc->stored_config->type = NET_BACKEND_VHOST_VDPA; | |
114 | # announce.c | 804 | + stored = &nc->stored_config->u.vhost_vdpa; |
115 | -qemu_announce_self_iter(const char *mac) "%s" | 805 | + |
116 | +qemu_announce_self_iter(const char *name, const char *mac, int skip) "%s:%s skip: %d" | 806 | + stored->has_vhostdev = true; |
117 | 807 | + stored->vhostdev = g_strdup(vhostdev); | |
118 | # vhost-user.c | 808 | + |
119 | vhost_user_event(const char *chr, int event) "chr: %s got event: %d" | 809 | + stored->has_queues = true; |
810 | + stored->queues = 1; /* TODO: change when support multiqueue */ | ||
811 | + | ||
812 | snprintf(nc->info_str, sizeof(nc->info_str), TYPE_VHOST_VDPA); | ||
813 | nc->queue_index = 0; | ||
814 | s = DO_UPCAST(VhostVDPAState, nc, nc); | ||
120 | diff --git a/qapi/net.json b/qapi/net.json | 815 | diff --git a/qapi/net.json b/qapi/net.json |
121 | index XXXXXXX..XXXXXXX 100644 | 816 | index XXXXXXX..XXXXXXX 100644 |
122 | --- a/qapi/net.json | 817 | --- a/qapi/net.json |
123 | +++ b/qapi/net.json | 818 | +++ b/qapi/net.json |
124 | @@ -XXX,XX +XXX,XX @@ | 819 | @@ -XXX,XX +XXX,XX @@ |
125 | # | ||
126 | # @step: Delay increase (in ms) after each self-announcement attempt | ||
127 | # | ||
128 | +# @interfaces: An optional list of interface names, which restricts the | ||
129 | +# announcement to the listed interfaces. (Since 4.1) | ||
130 | +# | ||
131 | # Since: 4.0 | ||
132 | ## | 820 | ## |
133 | 821 | { 'event': 'FAILOVER_NEGOTIATED', | |
134 | @@ -XXX,XX +XXX,XX @@ | 822 | 'data': {'device-id': 'str'} } |
135 | 'data': { 'initial': 'int', | 823 | + |
136 | 'max': 'int', | 824 | +## |
137 | 'rounds': 'int', | 825 | +# @NetBackend: |
138 | - 'step': 'int' } } | 826 | +# |
139 | + 'step': 'int', | 827 | +# Available netdev backend drivers. |
140 | + '*interfaces': ['str'] } } | 828 | +# |
141 | 829 | +# Since: 6.0 | |
142 | ## | 830 | +## |
143 | # @announce-self: | 831 | +{ 'enum': 'NetBackend', |
144 | @@ -XXX,XX +XXX,XX @@ | 832 | + 'data': [ 'bridge', 'l2tpv3', 'netmap', 'socket', 'tap', 'user', 'vde', |
145 | # | 833 | + 'vhost-user', 'vhost-vdpa' ] } |
146 | # Example: | 834 | + |
147 | # | 835 | +## |
148 | -# -> { "execute": "announce-self" | 836 | +# @NetdevInfo: |
149 | +# -> { "execute": "announce-self", | 837 | +# |
150 | # "arguments": { | 838 | +# Configuration of a network backend device (netdev). |
151 | -# "initial": 50, "max": 550, "rounds": 10, "step": 50 } } | 839 | +# |
152 | +# "initial": 50, "max": 550, "rounds": 10, "step": 50, | 840 | +# @id: Device identifier. |
153 | +# "interfaces": ["vn2", "vn3"] } } | 841 | +# |
154 | # <- { "return": {} } | 842 | +# @type: Specify the driver used for interpreting remaining arguments. |
155 | # | 843 | +# |
156 | # Since: 4.0 | 844 | +# @peer-id: The connected frontend network device name (absent if no frontend |
845 | +# is connected). | ||
846 | +# | ||
847 | +# Since: 6.0 | ||
848 | +## | ||
849 | +{ 'union': 'NetdevInfo', | ||
850 | + 'base': { 'id': 'str', | ||
851 | + 'type': 'NetBackend', | ||
852 | + '*peer-id': 'str' }, | ||
853 | + 'discriminator': 'type', | ||
854 | + 'data': { | ||
855 | + 'bridge': 'NetdevBridgeOptions', | ||
856 | + 'l2tpv3': 'NetdevL2TPv3Options', | ||
857 | + 'netmap': 'NetdevNetmapOptions', | ||
858 | + 'socket': 'NetdevSocketOptions', | ||
859 | + 'tap': 'NetdevTapOptions', | ||
860 | + 'user': 'NetdevUserOptions', | ||
861 | + 'vde': 'NetdevVdeOptions', | ||
862 | + 'vhost-user': 'NetdevVhostUserOptions', | ||
863 | + 'vhost-vdpa': 'NetdevVhostVDPAOptions' } } | ||
864 | + | ||
865 | +## | ||
866 | +# @query-netdev: | ||
867 | +# | ||
868 | +# Get a list of @NetdevInfo for all virtual network backend devices (netdevs). | ||
869 | +# | ||
870 | +# Returns: a list of @NetdevInfo describing each netdev. | ||
871 | +# | ||
872 | +# Since: 6.0 | ||
873 | +# | ||
874 | +# Example: | ||
875 | +# | ||
876 | +# -> { "execute": "query-netdev" } | ||
877 | +# <- { "return": [ | ||
878 | +# { | ||
879 | +# "ipv6": true, | ||
880 | +# "ipv4": true, | ||
881 | +# "host": "10.0.2.2", | ||
882 | +# "ipv6-dns": "fec0::3", | ||
883 | +# "ipv6-prefix": "fec0::", | ||
884 | +# "net": "10.0.2.0/255.255.255.0", | ||
885 | +# "ipv6-host": "fec0::2", | ||
886 | +# "type": "user", | ||
887 | +# "peer-id": "net0", | ||
888 | +# "dns": "10.0.2.3", | ||
889 | +# "hostfwd": [ | ||
890 | +# { | ||
891 | +# "str": "tcp::20004-:22" | ||
892 | +# } | ||
893 | +# ], | ||
894 | +# "ipv6-prefixlen": 64, | ||
895 | +# "id": "netdev0", | ||
896 | +# "restrict": false | ||
897 | +# } | ||
898 | +# ] | ||
899 | +# } | ||
900 | +# | ||
901 | +## | ||
902 | +{ 'command': 'query-netdev', 'returns': ['NetdevInfo'] } | ||
157 | -- | 903 | -- |
158 | 2.5.0 | 904 | 2.7.4 |
159 | 905 | ||
160 | 906 | diff view generated by jsdifflib |
1 | From: Zhang Chen <chen.zhang@intel.com> | 1 | From: Alexey Kirillov <lekiravi@yandex-team.ru> |
---|---|---|---|
2 | 2 | ||
3 | We add the "notify_dev=chardevID" parameter. After that colo-compare can connect with | 3 | A simply qtest that checks for correct number of netdevs in the response |
4 | remote(currently just for Xen, KVM-COLO didn't need it.) colo-frame through chardev socket, | 4 | of the query-netdev. |
5 | it can notify remote(Xen) colo-frame to handle checkpoint event. | ||
6 | 5 | ||
7 | Signed-off-by: Zhang Chen <chen.zhang@intel.com> | 6 | Signed-off-by: Alexey Kirillov <lekiravi@yandex-team.ru> |
7 | Acked-by: Thomas Huth <thuth@redhat.com> | ||
8 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 8 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
9 | --- | 9 | --- |
10 | net/colo-compare.c | 21 +++++++++++++++++++++ | 10 | tests/qtest/meson.build | 3 + |
11 | qemu-options.hx | 33 ++++++++++++++++++++++++++++++++- | 11 | tests/qtest/test-query-netdev.c | 120 ++++++++++++++++++++++++++++++++++++++++ |
12 | 2 files changed, 53 insertions(+), 1 deletion(-) | 12 | 2 files changed, 123 insertions(+) |
13 | create mode 100644 tests/qtest/test-query-netdev.c | ||
13 | 14 | ||
14 | diff --git a/net/colo-compare.c b/net/colo-compare.c | 15 | diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build |
15 | index XXXXXXX..XXXXXXX 100644 | 16 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/net/colo-compare.c | 17 | --- a/tests/qtest/meson.build |
17 | +++ b/net/colo-compare.c | 18 | +++ b/tests/qtest/meson.build |
18 | @@ -XXX,XX +XXX,XX @@ typedef struct CompareState { | 19 | @@ -XXX,XX +XXX,XX @@ qtests_generic = [ |
19 | char *pri_indev; | 20 | if config_host.has_key('CONFIG_MODULES') |
20 | char *sec_indev; | 21 | qtests_generic += [ 'modules-test' ] |
21 | char *outdev; | 22 | endif |
22 | + char *notify_dev; | 23 | +if slirp.found() |
23 | CharBackend chr_pri_in; | 24 | + qtests_generic += [ 'test-query-netdev' ] |
24 | CharBackend chr_sec_in; | 25 | +endif |
25 | CharBackend chr_out; | 26 | |
26 | @@ -XXX,XX +XXX,XX @@ static void compare_set_vnet_hdr(Object *obj, | 27 | qtests_pci = \ |
27 | s->vnet_hdr = value; | 28 | (config_all_devices.has_key('CONFIG_VGA') ? ['display-vga-test'] : []) + \ |
28 | } | 29 | diff --git a/tests/qtest/test-query-netdev.c b/tests/qtest/test-query-netdev.c |
29 | 30 | new file mode 100644 | |
30 | +static char *compare_get_notify_dev(Object *obj, Error **errp) | 31 | index XXXXXXX..XXXXXXX |
32 | --- /dev/null | ||
33 | +++ b/tests/qtest/test-query-netdev.c | ||
34 | @@ -XXX,XX +XXX,XX @@ | ||
35 | +/* | ||
36 | + * QTest testcase for the query-netdev | ||
37 | + * | ||
38 | + * Copyright Yandex N.V., 2019 | ||
39 | + * | ||
40 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||
41 | + * See the COPYING file in the top-level directory. | ||
42 | + * | ||
43 | + */ | ||
44 | + | ||
45 | +#include "qemu/osdep.h" | ||
46 | + | ||
47 | +#include "libqos/libqtest.h" | ||
48 | +#include "qapi/qmp/qdict.h" | ||
49 | +#include "qapi/qmp/qlist.h" | ||
50 | + | ||
51 | +/* | ||
52 | + * Events can get in the way of responses we are actually waiting for. | ||
53 | + */ | ||
54 | +GCC_FMT_ATTR(2, 3) | ||
55 | +static QObject *wait_command(QTestState *who, const char *command, ...) | ||
31 | +{ | 56 | +{ |
32 | + CompareState *s = COLO_COMPARE(obj); | 57 | + va_list ap; |
58 | + QDict *response; | ||
59 | + QObject *result; | ||
33 | + | 60 | + |
34 | + return g_strdup(s->notify_dev); | 61 | + va_start(ap, command); |
62 | + qtest_qmp_vsend(who, command, ap); | ||
63 | + va_end(ap); | ||
64 | + | ||
65 | + response = qtest_qmp_receive(who); | ||
66 | + | ||
67 | + result = qdict_get(response, "return"); | ||
68 | + g_assert(result); | ||
69 | + qobject_ref(result); | ||
70 | + qobject_unref(response); | ||
71 | + | ||
72 | + return result; | ||
35 | +} | 73 | +} |
36 | + | 74 | + |
37 | +static void compare_set_notify_dev(Object *obj, const char *value, Error **errp) | 75 | +static void qmp_query_netdev_no_error(QTestState *qts, size_t netdevs_count) |
38 | +{ | 76 | +{ |
39 | + CompareState *s = COLO_COMPARE(obj); | 77 | + QObject *resp; |
78 | + QList *netdevs; | ||
40 | + | 79 | + |
41 | + g_free(s->notify_dev); | 80 | + resp = wait_command(qts, "{'execute': 'query-netdev'}"); |
42 | + s->notify_dev = g_strdup(value); | 81 | + |
82 | + netdevs = qobject_to(QList, resp); | ||
83 | + g_assert(netdevs); | ||
84 | + g_assert(qlist_size(netdevs) == netdevs_count); | ||
85 | + | ||
86 | + qobject_unref(resp); | ||
43 | +} | 87 | +} |
44 | + | 88 | + |
45 | static void compare_pri_rs_finalize(SocketReadState *pri_rs) | 89 | +static void test_query_netdev(void) |
46 | { | 90 | +{ |
47 | CompareState *s = container_of(pri_rs, CompareState, pri_rs); | 91 | + const char *arch = qtest_get_arch(); |
48 | @@ -XXX,XX +XXX,XX @@ static void colo_compare_init(Object *obj) | 92 | + QObject *resp; |
49 | (Object **)&s->iothread, | 93 | + QTestState *state; |
50 | object_property_allow_set_link, | ||
51 | OBJ_PROP_LINK_STRONG, NULL); | ||
52 | + /* This parameter just for Xen COLO */ | ||
53 | + object_property_add_str(obj, "notify_dev", | ||
54 | + compare_get_notify_dev, compare_set_notify_dev, | ||
55 | + NULL); | ||
56 | |||
57 | s->vnet_hdr = false; | ||
58 | object_property_add_bool(obj, "vnet_hdr_support", compare_get_vnet_hdr, | ||
59 | @@ -XXX,XX +XXX,XX @@ static void colo_compare_finalize(Object *obj) | ||
60 | g_free(s->pri_indev); | ||
61 | g_free(s->sec_indev); | ||
62 | g_free(s->outdev); | ||
63 | + g_free(s->notify_dev); | ||
64 | } | ||
65 | |||
66 | static const TypeInfo colo_compare_info = { | ||
67 | diff --git a/qemu-options.hx b/qemu-options.hx | ||
68 | index XXXXXXX..XXXXXXX 100644 | ||
69 | --- a/qemu-options.hx | ||
70 | +++ b/qemu-options.hx | ||
71 | @@ -XXX,XX +XXX,XX @@ Dump the network traffic on netdev @var{dev} to the file specified by | ||
72 | The file format is libpcap, so it can be analyzed with tools such as tcpdump | ||
73 | or Wireshark. | ||
74 | |||
75 | -@item -object colo-compare,id=@var{id},primary_in=@var{chardevid},secondary_in=@var{chardevid},outdev=@var{chardevid},iothread=@var{id}[,vnet_hdr_support] | ||
76 | +@item -object colo-compare,id=@var{id},primary_in=@var{chardevid},secondary_in=@var{chardevid},outdev=@var{chardevid},iothread=@var{id}[,vnet_hdr_support][,notify_dev=@var{id}] | ||
77 | |||
78 | Colo-compare gets packet from primary_in@var{chardevid} and secondary_in@var{chardevid}, than compare primary packet with | ||
79 | secondary packet. If the packets are same, we will output primary | ||
80 | @@ -XXX,XX +XXX,XX @@ do checkpoint and send primary packet to outdev@var{chardevid}. | ||
81 | In order to improve efficiency, we need to put the task of comparison | ||
82 | in another thread. If it has the vnet_hdr_support flag, colo compare | ||
83 | will send/recv packet with vnet_hdr_len. | ||
84 | +If you want to use Xen COLO, will need the notify_dev to notify Xen | ||
85 | +colo-frame to do checkpoint. | ||
86 | |||
87 | we must use it with the help of filter-mirror and filter-redirector. | ||
88 | |||
89 | @example | ||
90 | |||
91 | +KVM COLO | ||
92 | + | 94 | + |
93 | primary: | 95 | + /* Choosing machine for platforms without default one */ |
94 | -netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown | 96 | + if (g_str_equal(arch, "arm") || |
95 | -device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66 | 97 | + g_str_equal(arch, "aarch64")) { |
96 | @@ -XXX,XX +XXX,XX @@ secondary: | 98 | + state = qtest_init( |
97 | -object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 | 99 | + "-nodefaults " |
98 | -object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 | 100 | + "-M virt " |
99 | 101 | + "-netdev user,id=slirp0"); | |
102 | + } else if (g_str_equal(arch, "tricore")) { | ||
103 | + state = qtest_init( | ||
104 | + "-nodefaults " | ||
105 | + "-M tricore_testboard " | ||
106 | + "-netdev user,id=slirp0"); | ||
107 | + } else if (g_str_equal(arch, "avr")) { | ||
108 | + state = qtest_init( | ||
109 | + "-nodefaults " | ||
110 | + "-M mega2560 " | ||
111 | + "-netdev user,id=slirp0"); | ||
112 | + } else if (g_str_equal(arch, "rx")) { | ||
113 | + state = qtest_init( | ||
114 | + "-nodefaults " | ||
115 | + "-M gdbsim-r5f562n8 " | ||
116 | + "-netdev user,id=slirp0"); | ||
117 | + } else { | ||
118 | + state = qtest_init( | ||
119 | + "-nodefaults " | ||
120 | + "-netdev user,id=slirp0"); | ||
121 | + } | ||
122 | + g_assert(state); | ||
100 | + | 123 | + |
101 | +Xen COLO | 124 | + qmp_query_netdev_no_error(state, 1); |
102 | + | 125 | + |
103 | +primary: | 126 | + resp = wait_command(state, |
104 | +-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown | 127 | + "{'execute': 'netdev_add', 'arguments': {" |
105 | +-device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66 | 128 | + " 'id': 'slirp1'," |
106 | +-chardev socket,id=mirror0,host=3.3.3.3,port=9003,server,nowait | 129 | + " 'type': 'user'}}"); |
107 | +-chardev socket,id=compare1,host=3.3.3.3,port=9004,server,nowait | 130 | + qobject_unref(resp); |
108 | +-chardev socket,id=compare0,host=3.3.3.3,port=9001,server,nowait | ||
109 | +-chardev socket,id=compare0-0,host=3.3.3.3,port=9001 | ||
110 | +-chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait | ||
111 | +-chardev socket,id=compare_out0,host=3.3.3.3,port=9005 | ||
112 | +-chardev socket,id=notify_way,host=3.3.3.3,port=9009,server,nowait | ||
113 | +-object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0 | ||
114 | +-object filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out | ||
115 | +-object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0 | ||
116 | +-object iothread,id=iothread1 | ||
117 | +-object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0,notify_dev=nofity_way,iothread=iothread1 | ||
118 | + | 131 | + |
119 | +secondary: | 132 | + qmp_query_netdev_no_error(state, 2); |
120 | +-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down script=/etc/qemu-ifdown | ||
121 | +-device e1000,netdev=hn0,mac=52:a4:00:12:78:66 | ||
122 | +-chardev socket,id=red0,host=3.3.3.3,port=9003 | ||
123 | +-chardev socket,id=red1,host=3.3.3.3,port=9004 | ||
124 | +-object filter-redirector,id=f1,netdev=hn0,queue=tx,indev=red0 | ||
125 | +-object filter-redirector,id=f2,netdev=hn0,queue=rx,outdev=red1 | ||
126 | + | 133 | + |
127 | @end example | 134 | + resp = wait_command(state, |
128 | 135 | + "{'execute': 'netdev_del', 'arguments': {" | |
129 | If you want to know the detail of above command line, you can read | 136 | + " 'id': 'slirp1'}}"); |
137 | + qobject_unref(resp); | ||
138 | + | ||
139 | + qmp_query_netdev_no_error(state, 1); | ||
140 | + | ||
141 | + qtest_quit(state); | ||
142 | +} | ||
143 | + | ||
144 | +int main(int argc, char **argv) | ||
145 | +{ | ||
146 | + int ret = 0; | ||
147 | + g_test_init(&argc, &argv, NULL); | ||
148 | + | ||
149 | + qtest_add_func("/net/qapi/query_netdev", test_query_netdev); | ||
150 | + | ||
151 | + ret = g_test_run(); | ||
152 | + | ||
153 | + return ret; | ||
154 | +} | ||
130 | -- | 155 | -- |
131 | 2.5.0 | 156 | 2.7.4 |
132 | 157 | ||
133 | 158 | diff view generated by jsdifflib |
1 | From: Stefano Garzarella <sgarzare@redhat.com> | 1 | From: Alexey Kirillov <lekiravi@yandex-team.ru> |
---|---|---|---|
2 | 2 | ||
3 | net_client_init() uses a variable length array to store the prefix | 3 | The info_str field of the NetClientState structure is static and has a size |
4 | of 'ipv6-net' parameter (e.g. if ipv6-net=fec0::0/64, the prefix | 4 | of 256 bytes. This amount is often unclaimed, and the field itself is used |
5 | is 'fec0::0'). | 5 | exclusively for HMP "info network". |
6 | This patch introduces g_strsplit() to split the 'ipv6-net' parameter, | 6 | |
7 | so we can remove the variable length array. | 7 | The patch translates info_str to dynamic memory allocation. |
8 | 8 | ||
9 | Suggested-by: Markus Armbruster <armbru@redhat.com> | 9 | This action is also allows us to painlessly discard usage of this field |
10 | Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> | 10 | for backend devices. |
11 | Reviewed-by: Markus Armbruster <armbru@redhat.com> | 11 | |
12 | Signed-off-by: Alexey Kirillov <lekiravi@yandex-team.ru> | ||
12 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 13 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
13 | --- | 14 | --- |
14 | net/net.c | 31 +++++++++++++++++++------------ | 15 | hw/net/xen_nic.c | 5 ++--- |
15 | 1 file changed, 19 insertions(+), 12 deletions(-) | 16 | include/net/net.h | 2 +- |
16 | 17 | net/l2tpv3.c | 3 +-- | |
18 | net/net.c | 14 ++++++++------ | ||
19 | net/slirp.c | 5 ++--- | ||
20 | net/socket.c | 43 ++++++++++++++++++++++++------------------- | ||
21 | net/tap-win32.c | 3 +-- | ||
22 | net/tap.c | 13 +++++-------- | ||
23 | net/vde.c | 3 +-- | ||
24 | net/vhost-user.c | 3 +-- | ||
25 | net/vhost-vdpa.c | 2 +- | ||
26 | 11 files changed, 47 insertions(+), 49 deletions(-) | ||
27 | |||
28 | diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c | ||
29 | index XXXXXXX..XXXXXXX 100644 | ||
30 | --- a/hw/net/xen_nic.c | ||
31 | +++ b/hw/net/xen_nic.c | ||
32 | @@ -XXX,XX +XXX,XX @@ static int net_init(struct XenLegacyDevice *xendev) | ||
33 | netdev->nic = qemu_new_nic(&net_xen_info, &netdev->conf, | ||
34 | "xen", NULL, netdev); | ||
35 | |||
36 | - snprintf(qemu_get_queue(netdev->nic)->info_str, | ||
37 | - sizeof(qemu_get_queue(netdev->nic)->info_str), | ||
38 | - "nic: xenbus vif macaddr=%s", netdev->mac); | ||
39 | + qemu_get_queue(netdev->nic)->info_str = g_strdup_printf( | ||
40 | + "nic: xenbus vif macaddr=%s", netdev->mac); | ||
41 | |||
42 | /* fill info */ | ||
43 | xenstore_write_be_int(&netdev->xendev, "feature-rx-copy", 1); | ||
44 | diff --git a/include/net/net.h b/include/net/net.h | ||
45 | index XXXXXXX..XXXXXXX 100644 | ||
46 | --- a/include/net/net.h | ||
47 | +++ b/include/net/net.h | ||
48 | @@ -XXX,XX +XXX,XX @@ struct NetClientState { | ||
49 | NetQueue *incoming_queue; | ||
50 | char *model; | ||
51 | char *name; | ||
52 | - char info_str[256]; | ||
53 | + char *info_str; | ||
54 | NetdevInfo *stored_config; | ||
55 | unsigned receive_disabled : 1; | ||
56 | NetClientDestructor *destructor; | ||
57 | diff --git a/net/l2tpv3.c b/net/l2tpv3.c | ||
58 | index XXXXXXX..XXXXXXX 100644 | ||
59 | --- a/net/l2tpv3.c | ||
60 | +++ b/net/l2tpv3.c | ||
61 | @@ -XXX,XX +XXX,XX @@ int net_init_l2tpv3(const Netdev *netdev, | ||
62 | QAPI_CLONE_MEMBERS(NetdevL2TPv3Options, | ||
63 | &nc->stored_config->u.l2tpv3, l2tpv3); | ||
64 | |||
65 | - snprintf(s->nc.info_str, sizeof(s->nc.info_str), | ||
66 | - "l2tpv3: connected"); | ||
67 | + s->nc.info_str = g_strdup_printf("l2tpv3: connected"); | ||
68 | return 0; | ||
69 | outerr: | ||
70 | qemu_del_net_client(nc); | ||
17 | diff --git a/net/net.c b/net/net.c | 71 | diff --git a/net/net.c b/net/net.c |
18 | index XXXXXXX..XXXXXXX 100644 | 72 | index XXXXXXX..XXXXXXX 100644 |
19 | --- a/net/net.c | 73 | --- a/net/net.c |
20 | +++ b/net/net.c | 74 | +++ b/net/net.c |
21 | @@ -XXX,XX +XXX,XX @@ static void show_netdevs(void) | 75 | @@ -XXX,XX +XXX,XX @@ char *qemu_mac_strdup_printf(const uint8_t *macaddr) |
22 | 76 | ||
23 | static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) | 77 | void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]) |
24 | { | 78 | { |
25 | + gchar **substrings = NULL; | 79 | - snprintf(nc->info_str, sizeof(nc->info_str), |
26 | void *object = NULL; | 80 | - "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x", |
27 | Error *err = NULL; | 81 | - nc->model, |
28 | int ret = -1; | 82 | - macaddr[0], macaddr[1], macaddr[2], |
29 | @@ -XXX,XX +XXX,XX @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) | 83 | - macaddr[3], macaddr[4], macaddr[5]); |
30 | const char *ip6_net = qemu_opt_get(opts, "ipv6-net"); | 84 | + g_free(nc->info_str); |
31 | 85 | + nc->info_str = g_strdup_printf( | |
32 | if (ip6_net) { | 86 | + "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x", |
33 | - char buf[strlen(ip6_net) + 1]; | 87 | + nc->model, |
34 | + char *prefix_addr; | 88 | + macaddr[0], macaddr[1], macaddr[2], |
35 | + unsigned long prefix_len = 64; /* Default 64bit prefix length. */ | 89 | + macaddr[3], macaddr[4], macaddr[5]); |
36 | + | 90 | } |
37 | + substrings = g_strsplit(ip6_net, "/", 2); | 91 | |
38 | + if (!substrings || !substrings[0]) { | 92 | static int mac_table[256] = {0}; |
39 | + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "ipv6-net", | 93 | @@ -XXX,XX +XXX,XX @@ static void qemu_free_net_client(NetClientState *nc) |
40 | + "a valid IPv6 prefix"); | 94 | } |
41 | + goto out; | 95 | g_free(nc->name); |
42 | + } | 96 | g_free(nc->model); |
43 | 97 | + g_free(nc->info_str); | |
44 | - if (get_str_sep(buf, sizeof(buf), &ip6_net, '/') < 0) { | 98 | qapi_free_NetdevInfo(nc->stored_config); |
45 | - /* Default 64bit prefix length. */ | 99 | if (nc->destructor) { |
46 | - qemu_opt_set(opts, "ipv6-prefix", ip6_net, &error_abort); | 100 | nc->destructor(nc); |
47 | - qemu_opt_set_number(opts, "ipv6-prefixlen", 64, &error_abort); | 101 | @@ -XXX,XX +XXX,XX @@ void print_net_client(Monitor *mon, NetClientState *nc) |
48 | - } else { | 102 | monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name, |
49 | + prefix_addr = substrings[0]; | 103 | nc->queue_index, |
50 | + | 104 | NetClientDriver_str(nc->info->type), |
51 | + if (substrings[1]) { | 105 | - nc->info_str); |
52 | /* User-specified prefix length. */ | 106 | + nc->info_str ? nc->info_str : ""); |
53 | - unsigned long len; | 107 | if (!QTAILQ_EMPTY(&nc->filters)) { |
54 | int err; | 108 | monitor_printf(mon, "filters:\n"); |
55 | 109 | } | |
56 | - qemu_opt_set(opts, "ipv6-prefix", buf, &error_abort); | 110 | diff --git a/net/slirp.c b/net/slirp.c |
57 | - err = qemu_strtoul(ip6_net, NULL, 10, &len); | 111 | index XXXXXXX..XXXXXXX 100644 |
58 | - | 112 | --- a/net/slirp.c |
59 | + err = qemu_strtoul(substrings[1], NULL, 10, &prefix_len); | 113 | +++ b/net/slirp.c |
60 | if (err) { | 114 | @@ -XXX,XX +XXX,XX @@ static int net_slirp_init(NetClientState *peer, const char *model, |
61 | error_setg(errp, QERR_INVALID_PARAMETER_VALUE, | 115 | stored->tftp_server_name = g_strdup(tftp_server_name); |
62 | "ipv6-prefixlen", "a number"); | 116 | } |
63 | goto out; | 117 | |
64 | } | 118 | - snprintf(nc->info_str, sizeof(nc->info_str), |
65 | - | 119 | - "net=%s,restrict=%s", inet_ntoa(net), |
66 | - qemu_opt_set_number(opts, "ipv6-prefixlen", len, &error_abort); | 120 | - restricted ? "on" : "off"); |
67 | } | 121 | + nc->info_str = g_strdup_printf("net=%s,restrict=%s", inet_ntoa(net), |
68 | + | 122 | + restricted ? "on" : "off"); |
69 | + qemu_opt_set(opts, "ipv6-prefix", prefix_addr, &error_abort); | 123 | |
70 | + qemu_opt_set_number(opts, "ipv6-prefixlen", prefix_len, | 124 | s = DO_UPCAST(SlirpState, nc, nc); |
71 | + &error_abort); | 125 | |
72 | qemu_opt_unset(opts, "ipv6-net"); | 126 | diff --git a/net/socket.c b/net/socket.c |
127 | index XXXXXXX..XXXXXXX 100644 | ||
128 | --- a/net/socket.c | ||
129 | +++ b/net/socket.c | ||
130 | @@ -XXX,XX +XXX,XX @@ static void net_socket_send(void *opaque) | ||
131 | s->fd = -1; | ||
132 | net_socket_rs_init(&s->rs, net_socket_rs_finalize, false); | ||
133 | s->nc.link_down = true; | ||
134 | - memset(s->nc.info_str, 0, sizeof(s->nc.info_str)); | ||
135 | + g_free(s->nc.info_str); | ||
136 | + s->nc.info_str = g_new0(char, 1); | ||
137 | |||
138 | return; | ||
139 | } | ||
140 | @@ -XXX,XX +XXX,XX @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer, | ||
141 | stored->mcast = g_strdup(mcast); | ||
142 | |||
143 | s->dgram_dst = saddr; | ||
144 | - snprintf(nc->info_str, sizeof(nc->info_str), | ||
145 | - "socket: fd=%d (cloned mcast=%s:%d)", | ||
146 | - fd, inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); | ||
147 | + nc->info_str = g_strdup_printf("socket: fd=%d (cloned mcast=%s:%d)", | ||
148 | + fd, inet_ntoa(saddr.sin_addr), | ||
149 | + ntohs(saddr.sin_port)); | ||
150 | } else { | ||
151 | if (sa_type == SOCKET_ADDRESS_TYPE_UNIX) { | ||
152 | s->dgram_dst.sin_family = AF_UNIX; | ||
73 | } | 153 | } |
74 | } | 154 | |
75 | @@ -XXX,XX +XXX,XX @@ static int net_client_init(QemuOpts *opts, bool is_netdev, Error **errp) | 155 | - snprintf(nc->info_str, sizeof(nc->info_str), |
76 | 156 | - "socket: fd=%d %s", fd, SocketAddressType_str(sa_type)); | |
77 | out: | 157 | + nc->info_str = g_strdup_printf("socket: fd=%d %s", |
78 | error_propagate(errp, err); | 158 | + fd, SocketAddressType_str(sa_type)); |
79 | + g_strfreev(substrings); | 159 | } |
80 | visit_free(v); | 160 | |
81 | return ret; | 161 | return s; |
82 | } | 162 | @@ -XXX,XX +XXX,XX @@ static NetSocketState *net_socket_fd_init_stream(NetClientState *peer, |
163 | |||
164 | nc = qemu_new_net_client(&net_socket_info, peer, model, name); | ||
165 | |||
166 | - snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd); | ||
167 | + nc->info_str = g_strdup_printf("socket: fd=%d", fd); | ||
168 | |||
169 | s = DO_UPCAST(NetSocketState, nc, nc); | ||
170 | |||
171 | @@ -XXX,XX +XXX,XX @@ static void net_socket_accept(void *opaque) | ||
172 | stored->has_fd = true; | ||
173 | stored->fd = g_strdup_printf("%d", fd); | ||
174 | |||
175 | - snprintf(s->nc.info_str, sizeof(s->nc.info_str), | ||
176 | - "socket: connection from %s:%d", | ||
177 | - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); | ||
178 | + g_free(s->nc.info_str); | ||
179 | + s->nc.info_str = g_strdup_printf("socket: connection from %s:%d", | ||
180 | + inet_ntoa(saddr.sin_addr), | ||
181 | + ntohs(saddr.sin_port)); | ||
182 | } | ||
183 | |||
184 | static int net_socket_listen_init(NetClientState *peer, | ||
185 | @@ -XXX,XX +XXX,XX @@ static int net_socket_connect_init(NetClientState *peer, | ||
186 | stored->has_connect = true; | ||
187 | stored->connect = g_strdup(host_str); | ||
188 | |||
189 | - snprintf(s->nc.info_str, sizeof(s->nc.info_str), | ||
190 | - "socket: connect to %s:%d", | ||
191 | - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); | ||
192 | + g_free(s->nc.info_str); | ||
193 | + s->nc.info_str = g_strdup_printf("socket: connect to %s:%d", | ||
194 | + inet_ntoa(saddr.sin_addr), | ||
195 | + ntohs(saddr.sin_port)); | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | @@ -XXX,XX +XXX,XX @@ static int net_socket_mcast_init(NetClientState *peer, | ||
200 | stored->localaddr = g_strdup(localaddr_str); | ||
201 | } | ||
202 | |||
203 | - snprintf(s->nc.info_str, sizeof(s->nc.info_str), | ||
204 | - "socket: mcast=%s:%d", | ||
205 | - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); | ||
206 | + g_free(s->nc.info_str); | ||
207 | + s->nc.info_str = g_strdup_printf("socket: mcast=%s:%d", | ||
208 | + inet_ntoa(saddr.sin_addr), | ||
209 | + ntohs(saddr.sin_port)); | ||
210 | return 0; | ||
211 | |||
212 | } | ||
213 | @@ -XXX,XX +XXX,XX @@ static int net_socket_udp_init(NetClientState *peer, | ||
214 | stored->has_udp = true; | ||
215 | stored->udp = g_strdup(rhost); | ||
216 | |||
217 | - snprintf(s->nc.info_str, sizeof(s->nc.info_str), | ||
218 | - "socket: udp=%s:%d", | ||
219 | - inet_ntoa(raddr.sin_addr), ntohs(raddr.sin_port)); | ||
220 | + g_free(s->nc.info_str); | ||
221 | + s->nc.info_str = g_strdup_printf("socket: udp=%s:%d", | ||
222 | + inet_ntoa(raddr.sin_addr), | ||
223 | + ntohs(raddr.sin_port)); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | diff --git a/net/tap-win32.c b/net/tap-win32.c | ||
228 | index XXXXXXX..XXXXXXX 100644 | ||
229 | --- a/net/tap-win32.c | ||
230 | +++ b/net/tap-win32.c | ||
231 | @@ -XXX,XX +XXX,XX @@ static int tap_win32_init(NetClientState *peer, const char *model, | ||
232 | stored->has_ifname = true; | ||
233 | stored->ifname = g_strdup(ifname); | ||
234 | |||
235 | - snprintf(s->nc.info_str, sizeof(s->nc.info_str), | ||
236 | - "tap: ifname=%s", ifname); | ||
237 | + s->nc.info_str = g_strdup_printf("tap: ifname=%s", ifname); | ||
238 | |||
239 | s->handle = handle; | ||
240 | |||
241 | diff --git a/net/tap.c b/net/tap.c | ||
242 | index XXXXXXX..XXXXXXX 100644 | ||
243 | --- a/net/tap.c | ||
244 | +++ b/net/tap.c | ||
245 | @@ -XXX,XX +XXX,XX @@ int net_init_bridge(const Netdev *netdev, const char *name, | ||
246 | stored->helper = g_strdup(helper); | ||
247 | } | ||
248 | |||
249 | - snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s,br=%s", helper, | ||
250 | - br); | ||
251 | + s->nc.info_str = g_strdup_printf("helper=%s,br=%s", helper, br); | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | @@ -XXX,XX +XXX,XX @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, | ||
256 | g_free(tmp_s); | ||
257 | } | ||
258 | |||
259 | - snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd); | ||
260 | + s->nc.info_str = g_strdup_printf("fd=%d", fd); | ||
261 | } else if (tap->has_helper) { | ||
262 | if (!stored->has_helper) { | ||
263 | stored->has_helper = true; | ||
264 | @@ -XXX,XX +XXX,XX @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, | ||
265 | g_strdup(DEFAULT_BRIDGE_INTERFACE); | ||
266 | } | ||
267 | |||
268 | - snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s", | ||
269 | - tap->helper); | ||
270 | + s->nc.info_str = g_strdup_printf("helper=%s", tap->helper); | ||
271 | } else { | ||
272 | if (ifname && !stored->has_ifname) { | ||
273 | stored->has_ifname = true; | ||
274 | @@ -XXX,XX +XXX,XX @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, | ||
275 | stored->downscript = g_strdup(downscript); | ||
276 | } | ||
277 | |||
278 | - snprintf(s->nc.info_str, sizeof(s->nc.info_str), | ||
279 | - "ifname=%s,script=%s,downscript=%s", ifname, script, | ||
280 | - downscript); | ||
281 | + s->nc.info_str = g_strdup_printf("ifname=%s,script=%s,downscript=%s", | ||
282 | + ifname, script, downscript); | ||
283 | |||
284 | if (strcmp(downscript, "no") != 0) { | ||
285 | snprintf(s->down_script, sizeof(s->down_script), "%s", downscript); | ||
286 | diff --git a/net/vde.c b/net/vde.c | ||
287 | index XXXXXXX..XXXXXXX 100644 | ||
288 | --- a/net/vde.c | ||
289 | +++ b/net/vde.c | ||
290 | @@ -XXX,XX +XXX,XX @@ static int net_vde_init(NetClientState *peer, const char *model, | ||
291 | |||
292 | nc = qemu_new_net_client(&net_vde_info, peer, model, name); | ||
293 | |||
294 | - snprintf(nc->info_str, sizeof(nc->info_str), "sock=%s,fd=%d", | ||
295 | - sock, vde_datafd(vde)); | ||
296 | + nc->info_str = g_strdup_printf("sock=%s,fd=%d", sock, vde_datafd(vde)); | ||
297 | |||
298 | s = DO_UPCAST(VDEState, nc, nc); | ||
299 | |||
300 | diff --git a/net/vhost-user.c b/net/vhost-user.c | ||
301 | index XXXXXXX..XXXXXXX 100644 | ||
302 | --- a/net/vhost-user.c | ||
303 | +++ b/net/vhost-user.c | ||
304 | @@ -XXX,XX +XXX,XX @@ static int net_vhost_user_init(NetClientState *peer, const char *device, | ||
305 | user = g_new0(struct VhostUserState, 1); | ||
306 | for (i = 0; i < queues; i++) { | ||
307 | nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name); | ||
308 | - snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s", | ||
309 | - i, chr->label); | ||
310 | + nc->info_str = g_strdup_printf("vhost-user%d to %s", i, chr->label); | ||
311 | nc->queue_index = i; | ||
312 | if (!nc0) { | ||
313 | nc0 = nc; | ||
314 | diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c | ||
315 | index XXXXXXX..XXXXXXX 100644 | ||
316 | --- a/net/vhost-vdpa.c | ||
317 | +++ b/net/vhost-vdpa.c | ||
318 | @@ -XXX,XX +XXX,XX @@ static int net_vhost_vdpa_init(NetClientState *peer, const char *device, | ||
319 | stored->has_queues = true; | ||
320 | stored->queues = 1; /* TODO: change when support multiqueue */ | ||
321 | |||
322 | - snprintf(nc->info_str, sizeof(nc->info_str), TYPE_VHOST_VDPA); | ||
323 | + nc->info_str = g_strdup_printf(TYPE_VHOST_VDPA); | ||
324 | nc->queue_index = 0; | ||
325 | s = DO_UPCAST(VhostVDPAState, nc, nc); | ||
326 | vdpa_device_fd = qemu_open_old(vhostdev, O_RDWR); | ||
83 | -- | 327 | -- |
84 | 2.5.0 | 328 | 2.7.4 |
85 | 329 | ||
86 | 330 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | 1 | From: Alexey Kirillov <lekiravi@yandex-team.ru> | |
2 | |||
3 | Replace usage of legacy field info_str of NetClientState for backend | ||
4 | network devices with QAPI NetdevInfo stored_config that already used | ||
5 | in QMP query-netdev. | ||
6 | |||
7 | This change increases the detail of the "info network" output and takes | ||
8 | a more general approach to composing the output. | ||
9 | |||
10 | NIC and hubports still use legacy info_str field. | ||
11 | |||
12 | Signed-off-by: Alexey Kirillov <lekiravi@yandex-team.ru> | ||
13 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
14 | --- | ||
15 | include/qapi/hmp-output-visitor.h | 30 ++++++ | ||
16 | net/net.c | 31 +++++- | ||
17 | qapi/hmp-output-visitor.c | 193 ++++++++++++++++++++++++++++++++++++++ | ||
18 | qapi/meson.build | 1 + | ||
19 | 4 files changed, 254 insertions(+), 1 deletion(-) | ||
20 | create mode 100644 include/qapi/hmp-output-visitor.h | ||
21 | create mode 100644 qapi/hmp-output-visitor.c | ||
22 | |||
23 | diff --git a/include/qapi/hmp-output-visitor.h b/include/qapi/hmp-output-visitor.h | ||
24 | new file mode 100644 | ||
25 | index XXXXXXX..XXXXXXX | ||
26 | --- /dev/null | ||
27 | +++ b/include/qapi/hmp-output-visitor.h | ||
28 | @@ -XXX,XX +XXX,XX @@ | ||
29 | +/* | ||
30 | + * HMP string output Visitor | ||
31 | + * | ||
32 | + * Copyright Yandex N.V., 2021 | ||
33 | + * | ||
34 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||
35 | + * See the COPYING file in the top-level directory. | ||
36 | + * | ||
37 | + */ | ||
38 | + | ||
39 | +#ifndef HMP_OUTPUT_VISITOR_H | ||
40 | +#define HMP_OUTPUT_VISITOR_H | ||
41 | + | ||
42 | +#include "qapi/visitor.h" | ||
43 | + | ||
44 | +typedef struct HMPOutputVisitor HMPOutputVisitor; | ||
45 | + | ||
46 | +/** | ||
47 | + * Create a HMP string output visitor for @obj | ||
48 | + * | ||
49 | + * Flattens dicts/structures, only shows arrays borders. | ||
50 | + * | ||
51 | + * Errors are not expected to happen. | ||
52 | + * | ||
53 | + * The caller is responsible for freeing the visitor with | ||
54 | + * visit_free(). | ||
55 | + */ | ||
56 | +Visitor *hmp_output_visitor_new(char **result); | ||
57 | + | ||
58 | +#endif | ||
59 | diff --git a/net/net.c b/net/net.c | ||
60 | index XXXXXXX..XXXXXXX 100644 | ||
61 | --- a/net/net.c | ||
62 | +++ b/net/net.c | ||
63 | @@ -XXX,XX +XXX,XX @@ | ||
64 | #include "sysemu/sysemu.h" | ||
65 | #include "net/filter.h" | ||
66 | #include "qapi/string-output-visitor.h" | ||
67 | +#include "qapi/hmp-output-visitor.h" | ||
68 | |||
69 | /* Net bridge is currently not supported for W32. */ | ||
70 | #if !defined(_WIN32) | ||
71 | @@ -XXX,XX +XXX,XX @@ static void netfilter_print_info(Monitor *mon, NetFilterState *nf) | ||
72 | monitor_printf(mon, "\n"); | ||
73 | } | ||
74 | |||
75 | +static char *generate_info_str(NetClientState *nc) | ||
76 | +{ | ||
77 | + NetdevInfo *ni = nc->stored_config; | ||
78 | + char *ret_out = NULL; | ||
79 | + Visitor *v; | ||
80 | + | ||
81 | + /* Use legacy field info_str for NIC and hubports */ | ||
82 | + if ((nc->info->type == NET_CLIENT_DRIVER_NIC) || | ||
83 | + (nc->info->type == NET_CLIENT_DRIVER_HUBPORT)) { | ||
84 | + return g_strdup(nc->info_str ? nc->info_str : ""); | ||
85 | + } | ||
86 | + | ||
87 | + if (!ni) { | ||
88 | + return g_malloc0(1); | ||
89 | + } | ||
90 | + | ||
91 | + v = hmp_output_visitor_new(&ret_out); | ||
92 | + if (visit_type_NetdevInfo(v, "", &ni, NULL)) { | ||
93 | + visit_complete(v, &ret_out); | ||
94 | + } | ||
95 | + visit_free(v); | ||
96 | + | ||
97 | + return ret_out; | ||
98 | +} | ||
99 | + | ||
100 | void print_net_client(Monitor *mon, NetClientState *nc) | ||
101 | { | ||
102 | NetFilterState *nf; | ||
103 | + char *info_str = generate_info_str(nc); | ||
104 | |||
105 | monitor_printf(mon, "%s: index=%d,type=%s,%s\n", nc->name, | ||
106 | nc->queue_index, | ||
107 | NetClientDriver_str(nc->info->type), | ||
108 | - nc->info_str ? nc->info_str : ""); | ||
109 | + info_str); | ||
110 | + g_free(info_str); | ||
111 | + | ||
112 | if (!QTAILQ_EMPTY(&nc->filters)) { | ||
113 | monitor_printf(mon, "filters:\n"); | ||
114 | } | ||
115 | diff --git a/qapi/hmp-output-visitor.c b/qapi/hmp-output-visitor.c | ||
116 | new file mode 100644 | ||
117 | index XXXXXXX..XXXXXXX | ||
118 | --- /dev/null | ||
119 | +++ b/qapi/hmp-output-visitor.c | ||
120 | @@ -XXX,XX +XXX,XX @@ | ||
121 | +/* | ||
122 | + * HMP string output Visitor | ||
123 | + * | ||
124 | + * Copyright Yandex N.V., 2021 | ||
125 | + * | ||
126 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||
127 | + * See the COPYING file in the top-level directory. | ||
128 | + * | ||
129 | + */ | ||
130 | + | ||
131 | +#include "qemu/osdep.h" | ||
132 | +#include "qemu/cutils.h" | ||
133 | +#include "qapi/hmp-output-visitor.h" | ||
134 | +#include "qapi/visitor-impl.h" | ||
135 | + | ||
136 | +struct HMPOutputVisitor { | ||
137 | + Visitor visitor; | ||
138 | + char **result; | ||
139 | + GString *buffer; | ||
140 | + bool is_continue; | ||
141 | +}; | ||
142 | + | ||
143 | +static HMPOutputVisitor *to_hov(Visitor *v) | ||
144 | +{ | ||
145 | + return container_of(v, HMPOutputVisitor, visitor); | ||
146 | +} | ||
147 | + | ||
148 | +static void hmp_output_append_formatted(Visitor *v, const char *fmt, ...) | ||
149 | +{ | ||
150 | + HMPOutputVisitor *ov = to_hov(v); | ||
151 | + va_list args; | ||
152 | + | ||
153 | + if (ov->is_continue) { | ||
154 | + g_string_append(ov->buffer, ","); | ||
155 | + } else { | ||
156 | + ov->is_continue = true; | ||
157 | + } | ||
158 | + | ||
159 | + va_start(args, fmt); | ||
160 | + g_string_append_vprintf(ov->buffer, fmt, args); | ||
161 | + va_end(args); | ||
162 | +} | ||
163 | + | ||
164 | +static void hmp_output_skip_comma(Visitor *v) | ||
165 | +{ | ||
166 | + HMPOutputVisitor *ov = to_hov(v); | ||
167 | + | ||
168 | + ov->is_continue = false; | ||
169 | +} | ||
170 | + | ||
171 | +static bool hmp_output_start_struct(Visitor *v, const char *name, | ||
172 | + void **obj, size_t unused, Error **errp) | ||
173 | +{ | ||
174 | + return true; | ||
175 | +} | ||
176 | + | ||
177 | +static void hmp_output_end_struct(Visitor *v, void **obj) {} | ||
178 | + | ||
179 | +static bool hmp_output_start_list(Visitor *v, const char *name, | ||
180 | + GenericList **listp, size_t size, | ||
181 | + Error **errp) | ||
182 | +{ | ||
183 | + hmp_output_append_formatted(v, "%s=[", name); | ||
184 | + /* First element in array without comma before it */ | ||
185 | + hmp_output_skip_comma(v); | ||
186 | + | ||
187 | + return true; | ||
188 | +} | ||
189 | + | ||
190 | +static GenericList *hmp_output_next_list(Visitor *v, GenericList *tail, | ||
191 | + size_t size) | ||
192 | +{ | ||
193 | + return tail->next; | ||
194 | +} | ||
195 | + | ||
196 | +static void hmp_output_end_list(Visitor *v, void **obj) | ||
197 | +{ | ||
198 | + /* Don't need comma after last array element */ | ||
199 | + hmp_output_skip_comma(v); | ||
200 | + hmp_output_append_formatted(v, "]"); | ||
201 | +} | ||
202 | + | ||
203 | +static bool hmp_output_type_int64(Visitor *v, const char *name, | ||
204 | + int64_t *obj, Error **errp) | ||
205 | +{ | ||
206 | + hmp_output_append_formatted(v, "%s=%" PRId64, name, *obj); | ||
207 | + | ||
208 | + return true; | ||
209 | +} | ||
210 | + | ||
211 | +static bool hmp_output_type_uint64(Visitor *v, const char *name, | ||
212 | + uint64_t *obj, Error **errp) | ||
213 | +{ | ||
214 | + hmp_output_append_formatted(v, "%s=%" PRIu64, name, *obj); | ||
215 | + | ||
216 | + return true; | ||
217 | +} | ||
218 | + | ||
219 | +static bool hmp_output_type_bool(Visitor *v, const char *name, bool *obj, | ||
220 | + Error **errp) | ||
221 | +{ | ||
222 | + hmp_output_append_formatted(v, "%s=%s", name, *obj ? "true" : "false"); | ||
223 | + | ||
224 | + return true; | ||
225 | +} | ||
226 | + | ||
227 | +static bool hmp_output_type_str(Visitor *v, const char *name, char **obj, | ||
228 | + Error **errp) | ||
229 | +{ | ||
230 | + /* Skip already printed or unused fields */ | ||
231 | + if (!*obj || g_str_equal(name, "id") || g_str_equal(name, "type")) { | ||
232 | + return true; | ||
233 | + } | ||
234 | + | ||
235 | + /* Do not print stub name for StringList elements */ | ||
236 | + if (g_str_equal(name, "str")) { | ||
237 | + hmp_output_append_formatted(v, "%s", *obj); | ||
238 | + } else { | ||
239 | + hmp_output_append_formatted(v, "%s=%s", name, *obj); | ||
240 | + } | ||
241 | + | ||
242 | + return true; | ||
243 | +} | ||
244 | + | ||
245 | +static bool hmp_output_type_number(Visitor *v, const char *name, | ||
246 | + double *obj, Error **errp) | ||
247 | +{ | ||
248 | + hmp_output_append_formatted(v, "%s=%.17g", name, *obj); | ||
249 | + | ||
250 | + return true; | ||
251 | +} | ||
252 | + | ||
253 | +/* TODO: remove this function? */ | ||
254 | +static bool hmp_output_type_any(Visitor *v, const char *name, | ||
255 | + QObject **obj, Error **errp) | ||
256 | +{ | ||
257 | + return true; | ||
258 | +} | ||
259 | + | ||
260 | +static bool hmp_output_type_null(Visitor *v, const char *name, | ||
261 | + QNull **obj, Error **errp) | ||
262 | +{ | ||
263 | + hmp_output_append_formatted(v, "%s=NULL", name); | ||
264 | + | ||
265 | + return true; | ||
266 | +} | ||
267 | + | ||
268 | +static void hmp_output_complete(Visitor *v, void *opaque) | ||
269 | +{ | ||
270 | + HMPOutputVisitor *ov = to_hov(v); | ||
271 | + | ||
272 | + *ov->result = g_string_free(ov->buffer, false); | ||
273 | + ov->buffer = NULL; | ||
274 | +} | ||
275 | + | ||
276 | +static void hmp_output_free(Visitor *v) | ||
277 | +{ | ||
278 | + HMPOutputVisitor *ov = to_hov(v); | ||
279 | + | ||
280 | + if (ov->buffer) { | ||
281 | + g_string_free(ov->buffer, true); | ||
282 | + } | ||
283 | + g_free(v); | ||
284 | +} | ||
285 | + | ||
286 | +Visitor *hmp_output_visitor_new(char **result) | ||
287 | +{ | ||
288 | + HMPOutputVisitor *v; | ||
289 | + | ||
290 | + v = g_malloc0(sizeof(*v)); | ||
291 | + | ||
292 | + v->visitor.type = VISITOR_OUTPUT; | ||
293 | + v->visitor.start_struct = hmp_output_start_struct; | ||
294 | + v->visitor.end_struct = hmp_output_end_struct; | ||
295 | + v->visitor.start_list = hmp_output_start_list; | ||
296 | + v->visitor.next_list = hmp_output_next_list; | ||
297 | + v->visitor.end_list = hmp_output_end_list; | ||
298 | + v->visitor.type_int64 = hmp_output_type_int64; | ||
299 | + v->visitor.type_uint64 = hmp_output_type_uint64; | ||
300 | + v->visitor.type_bool = hmp_output_type_bool; | ||
301 | + v->visitor.type_str = hmp_output_type_str; | ||
302 | + v->visitor.type_number = hmp_output_type_number; | ||
303 | + v->visitor.type_any = hmp_output_type_any; | ||
304 | + v->visitor.type_null = hmp_output_type_null; | ||
305 | + v->visitor.complete = hmp_output_complete; | ||
306 | + v->visitor.free = hmp_output_free; | ||
307 | + | ||
308 | + v->result = result; | ||
309 | + v->buffer = g_string_new(""); | ||
310 | + v->is_continue = false; | ||
311 | + | ||
312 | + return &v->visitor; | ||
313 | +} | ||
314 | diff --git a/qapi/meson.build b/qapi/meson.build | ||
315 | index XXXXXXX..XXXXXXX 100644 | ||
316 | --- a/qapi/meson.build | ||
317 | +++ b/qapi/meson.build | ||
318 | @@ -XXX,XX +XXX,XX @@ util_ss.add(files( | ||
319 | 'qobject-output-visitor.c', | ||
320 | 'string-input-visitor.c', | ||
321 | 'string-output-visitor.c', | ||
322 | + 'hmp-output-visitor.c', | ||
323 | )) | ||
324 | if have_system or have_tools | ||
325 | util_ss.add(files( | ||
326 | -- | ||
327 | 2.7.4 | ||
328 | |||
329 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | 1 | From: Alexey Kirillov <lekiravi@yandex-team.ru> | |
2 | |||
3 | As we use QAPI NetClientState->stored_config to store and get information | ||
4 | about backend network devices, we can drop fill of legacy field info_str | ||
5 | for them. | ||
6 | |||
7 | We still use info_str field for NIC and hubports, so we can not completely | ||
8 | remove it. | ||
9 | |||
10 | Signed-off-by: Alexey Kirillov <lekiravi@yandex-team.ru> | ||
11 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
12 | --- | ||
13 | net/l2tpv3.c | 2 -- | ||
14 | net/slirp.c | 3 --- | ||
15 | net/socket.c | 28 ---------------------------- | ||
16 | net/tap-win32.c | 2 -- | ||
17 | net/tap.c | 9 --------- | ||
18 | net/vde.c | 2 -- | ||
19 | net/vhost-user.c | 1 - | ||
20 | net/vhost-vdpa.c | 1 - | ||
21 | 8 files changed, 48 deletions(-) | ||
22 | |||
23 | diff --git a/net/l2tpv3.c b/net/l2tpv3.c | ||
24 | index XXXXXXX..XXXXXXX 100644 | ||
25 | --- a/net/l2tpv3.c | ||
26 | +++ b/net/l2tpv3.c | ||
27 | @@ -XXX,XX +XXX,XX @@ int net_init_l2tpv3(const Netdev *netdev, | ||
28 | |||
29 | QAPI_CLONE_MEMBERS(NetdevL2TPv3Options, | ||
30 | &nc->stored_config->u.l2tpv3, l2tpv3); | ||
31 | - | ||
32 | - s->nc.info_str = g_strdup_printf("l2tpv3: connected"); | ||
33 | return 0; | ||
34 | outerr: | ||
35 | qemu_del_net_client(nc); | ||
36 | diff --git a/net/slirp.c b/net/slirp.c | ||
37 | index XXXXXXX..XXXXXXX 100644 | ||
38 | --- a/net/slirp.c | ||
39 | +++ b/net/slirp.c | ||
40 | @@ -XXX,XX +XXX,XX @@ static int net_slirp_init(NetClientState *peer, const char *model, | ||
41 | stored->tftp_server_name = g_strdup(tftp_server_name); | ||
42 | } | ||
43 | |||
44 | - nc->info_str = g_strdup_printf("net=%s,restrict=%s", inet_ntoa(net), | ||
45 | - restricted ? "on" : "off"); | ||
46 | - | ||
47 | s = DO_UPCAST(SlirpState, nc, nc); | ||
48 | |||
49 | s->slirp = slirp_init(restricted, ipv4, net, mask, host, | ||
50 | diff --git a/net/socket.c b/net/socket.c | ||
51 | index XXXXXXX..XXXXXXX 100644 | ||
52 | --- a/net/socket.c | ||
53 | +++ b/net/socket.c | ||
54 | @@ -XXX,XX +XXX,XX @@ static void net_socket_send(void *opaque) | ||
55 | s->fd = -1; | ||
56 | net_socket_rs_init(&s->rs, net_socket_rs_finalize, false); | ||
57 | s->nc.link_down = true; | ||
58 | - g_free(s->nc.info_str); | ||
59 | - s->nc.info_str = g_new0(char, 1); | ||
60 | |||
61 | return; | ||
62 | } | ||
63 | @@ -XXX,XX +XXX,XX @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer, | ||
64 | stored->mcast = g_strdup(mcast); | ||
65 | |||
66 | s->dgram_dst = saddr; | ||
67 | - nc->info_str = g_strdup_printf("socket: fd=%d (cloned mcast=%s:%d)", | ||
68 | - fd, inet_ntoa(saddr.sin_addr), | ||
69 | - ntohs(saddr.sin_port)); | ||
70 | } else { | ||
71 | if (sa_type == SOCKET_ADDRESS_TYPE_UNIX) { | ||
72 | s->dgram_dst.sin_family = AF_UNIX; | ||
73 | } | ||
74 | - | ||
75 | - nc->info_str = g_strdup_printf("socket: fd=%d %s", | ||
76 | - fd, SocketAddressType_str(sa_type)); | ||
77 | } | ||
78 | |||
79 | return s; | ||
80 | @@ -XXX,XX +XXX,XX @@ static NetSocketState *net_socket_fd_init_stream(NetClientState *peer, | ||
81 | |||
82 | nc = qemu_new_net_client(&net_socket_info, peer, model, name); | ||
83 | |||
84 | - nc->info_str = g_strdup_printf("socket: fd=%d", fd); | ||
85 | - | ||
86 | s = DO_UPCAST(NetSocketState, nc, nc); | ||
87 | |||
88 | s->fd = fd; | ||
89 | @@ -XXX,XX +XXX,XX @@ static void net_socket_accept(void *opaque) | ||
90 | |||
91 | stored->has_fd = true; | ||
92 | stored->fd = g_strdup_printf("%d", fd); | ||
93 | - | ||
94 | - g_free(s->nc.info_str); | ||
95 | - s->nc.info_str = g_strdup_printf("socket: connection from %s:%d", | ||
96 | - inet_ntoa(saddr.sin_addr), | ||
97 | - ntohs(saddr.sin_port)); | ||
98 | } | ||
99 | |||
100 | static int net_socket_listen_init(NetClientState *peer, | ||
101 | @@ -XXX,XX +XXX,XX @@ static int net_socket_connect_init(NetClientState *peer, | ||
102 | stored->has_connect = true; | ||
103 | stored->connect = g_strdup(host_str); | ||
104 | |||
105 | - g_free(s->nc.info_str); | ||
106 | - s->nc.info_str = g_strdup_printf("socket: connect to %s:%d", | ||
107 | - inet_ntoa(saddr.sin_addr), | ||
108 | - ntohs(saddr.sin_port)); | ||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | @@ -XXX,XX +XXX,XX @@ static int net_socket_mcast_init(NetClientState *peer, | ||
113 | stored->localaddr = g_strdup(localaddr_str); | ||
114 | } | ||
115 | |||
116 | - g_free(s->nc.info_str); | ||
117 | - s->nc.info_str = g_strdup_printf("socket: mcast=%s:%d", | ||
118 | - inet_ntoa(saddr.sin_addr), | ||
119 | - ntohs(saddr.sin_port)); | ||
120 | return 0; | ||
121 | - | ||
122 | } | ||
123 | |||
124 | static int net_socket_udp_init(NetClientState *peer, | ||
125 | @@ -XXX,XX +XXX,XX @@ static int net_socket_udp_init(NetClientState *peer, | ||
126 | stored->has_udp = true; | ||
127 | stored->udp = g_strdup(rhost); | ||
128 | |||
129 | - g_free(s->nc.info_str); | ||
130 | - s->nc.info_str = g_strdup_printf("socket: udp=%s:%d", | ||
131 | - inet_ntoa(raddr.sin_addr), | ||
132 | - ntohs(raddr.sin_port)); | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | diff --git a/net/tap-win32.c b/net/tap-win32.c | ||
137 | index XXXXXXX..XXXXXXX 100644 | ||
138 | --- a/net/tap-win32.c | ||
139 | +++ b/net/tap-win32.c | ||
140 | @@ -XXX,XX +XXX,XX @@ static int tap_win32_init(NetClientState *peer, const char *model, | ||
141 | stored->has_ifname = true; | ||
142 | stored->ifname = g_strdup(ifname); | ||
143 | |||
144 | - s->nc.info_str = g_strdup_printf("tap: ifname=%s", ifname); | ||
145 | - | ||
146 | s->handle = handle; | ||
147 | |||
148 | qemu_add_wait_object(s->handle->tap_semaphore, tap_win32_send, s); | ||
149 | diff --git a/net/tap.c b/net/tap.c | ||
150 | index XXXXXXX..XXXXXXX 100644 | ||
151 | --- a/net/tap.c | ||
152 | +++ b/net/tap.c | ||
153 | @@ -XXX,XX +XXX,XX @@ int net_init_bridge(const Netdev *netdev, const char *name, | ||
154 | stored->helper = g_strdup(helper); | ||
155 | } | ||
156 | |||
157 | - s->nc.info_str = g_strdup_printf("helper=%s,br=%s", helper, br); | ||
158 | - | ||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | @@ -XXX,XX +XXX,XX @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, | ||
163 | stored->fds = g_strdup_printf("%s:%d", stored->fds, fd); | ||
164 | g_free(tmp_s); | ||
165 | } | ||
166 | - | ||
167 | - s->nc.info_str = g_strdup_printf("fd=%d", fd); | ||
168 | } else if (tap->has_helper) { | ||
169 | if (!stored->has_helper) { | ||
170 | stored->has_helper = true; | ||
171 | @@ -XXX,XX +XXX,XX @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, | ||
172 | stored->br = tap->has_br ? g_strdup(tap->br) : | ||
173 | g_strdup(DEFAULT_BRIDGE_INTERFACE); | ||
174 | } | ||
175 | - | ||
176 | - s->nc.info_str = g_strdup_printf("helper=%s", tap->helper); | ||
177 | } else { | ||
178 | if (ifname && !stored->has_ifname) { | ||
179 | stored->has_ifname = true; | ||
180 | @@ -XXX,XX +XXX,XX @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, | ||
181 | stored->downscript = g_strdup(downscript); | ||
182 | } | ||
183 | |||
184 | - s->nc.info_str = g_strdup_printf("ifname=%s,script=%s,downscript=%s", | ||
185 | - ifname, script, downscript); | ||
186 | - | ||
187 | if (strcmp(downscript, "no") != 0) { | ||
188 | snprintf(s->down_script, sizeof(s->down_script), "%s", downscript); | ||
189 | snprintf(s->down_script_arg, sizeof(s->down_script_arg), | ||
190 | diff --git a/net/vde.c b/net/vde.c | ||
191 | index XXXXXXX..XXXXXXX 100644 | ||
192 | --- a/net/vde.c | ||
193 | +++ b/net/vde.c | ||
194 | @@ -XXX,XX +XXX,XX @@ static int net_vde_init(NetClientState *peer, const char *model, | ||
195 | |||
196 | nc = qemu_new_net_client(&net_vde_info, peer, model, name); | ||
197 | |||
198 | - nc->info_str = g_strdup_printf("sock=%s,fd=%d", sock, vde_datafd(vde)); | ||
199 | - | ||
200 | s = DO_UPCAST(VDEState, nc, nc); | ||
201 | |||
202 | s->vde = vde; | ||
203 | diff --git a/net/vhost-user.c b/net/vhost-user.c | ||
204 | index XXXXXXX..XXXXXXX 100644 | ||
205 | --- a/net/vhost-user.c | ||
206 | +++ b/net/vhost-user.c | ||
207 | @@ -XXX,XX +XXX,XX @@ static int net_vhost_user_init(NetClientState *peer, const char *device, | ||
208 | user = g_new0(struct VhostUserState, 1); | ||
209 | for (i = 0; i < queues; i++) { | ||
210 | nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name); | ||
211 | - nc->info_str = g_strdup_printf("vhost-user%d to %s", i, chr->label); | ||
212 | nc->queue_index = i; | ||
213 | if (!nc0) { | ||
214 | nc0 = nc; | ||
215 | diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c | ||
216 | index XXXXXXX..XXXXXXX 100644 | ||
217 | --- a/net/vhost-vdpa.c | ||
218 | +++ b/net/vhost-vdpa.c | ||
219 | @@ -XXX,XX +XXX,XX @@ static int net_vhost_vdpa_init(NetClientState *peer, const char *device, | ||
220 | stored->has_queues = true; | ||
221 | stored->queues = 1; /* TODO: change when support multiqueue */ | ||
222 | |||
223 | - nc->info_str = g_strdup_printf(TYPE_VHOST_VDPA); | ||
224 | nc->queue_index = 0; | ||
225 | s = DO_UPCAST(VhostVDPAState, nc, nc); | ||
226 | vdpa_device_fd = qemu_open_old(vhostdev, O_RDWR); | ||
227 | -- | ||
228 | 2.7.4 | ||
229 | |||
230 | diff view generated by jsdifflib |