1 | The following changes since commit 5dae13cd71f0755a1395b5a4cde635b8a6ee3f58: | 1 | The following changes since commit eec398119fc6911d99412c37af06a6bc27871f85: |
---|---|---|---|
2 | 2 | ||
3 | Merge remote-tracking branch 'remotes/rth/tags/pull-or-20170214' into staging (2017-02-14 09:55:48 +0000) | 3 | Merge tag 'for_upstream' of git://git.kernel.org/pub/scm/virt/kvm/mst/qemu into staging (2022-05-16 16:31:01 -0700) |
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 4154c7e03fa55b4cf52509a83d50d6c09d743b77: | 9 | for you to fetch changes up to 052c2579b89b0d87debe8b05594b5180f0fde87d: |
10 | 10 | ||
11 | net: e1000e: fix an infinite loop issue (2017-02-15 11:18:57 +0800) | 11 | tulip: Assign default MAC address if not specified (2022-05-17 16:48:23 +0800) |
12 | 12 | ||
13 | ---------------------------------------------------------------- | 13 | ---------------------------------------------------------------- |
14 | 14 | ||
15 | ---------------------------------------------------------------- | 15 | ---------------------------------------------------------------- |
16 | Li Qiang (1): | 16 | Helge Deller (1): |
17 | net: e1000e: fix an infinite loop issue | 17 | tulip: Assign default MAC address if not specified |
18 | 18 | ||
19 | Paolo Bonzini (1): | 19 | Vladislav Yaroshchuk (7): |
20 | net: e1000e: fix dead code in e1000e_write_packet_to_guest | 20 | net/vmnet: add vmnet dependency and customizable option |
21 | net/vmnet: add vmnet backends to qapi/net | ||
22 | net/vmnet: implement shared mode (vmnet-shared) | ||
23 | net/vmnet: implement host mode (vmnet-host) | ||
24 | net/vmnet: implement bridged mode (vmnet-bridged) | ||
25 | net/vmnet: update qemu-options.hx | ||
26 | net/vmnet: update hmp-commands.hx | ||
21 | 27 | ||
22 | Prasad J Pandit (1): | 28 | hmp-commands.hx | 6 +- |
23 | net: imx: limit buffer descriptor count | 29 | hw/net/tulip.c | 4 +- |
24 | 30 | meson.build | 16 +- | |
25 | Thomas Huth (1): | 31 | meson_options.txt | 2 + |
26 | net: Mark 'vlan' parameter as deprecated | 32 | net/clients.h | 11 ++ |
27 | 33 | net/meson.build | 7 + | |
28 | Zhang Chen (1): | 34 | net/net.c | 10 ++ |
29 | colo-compare: sort TCP packet queue by sequence number | 35 | net/vmnet-bridged.m | 152 +++++++++++++++++ |
30 | 36 | net/vmnet-common.m | 378 ++++++++++++++++++++++++++++++++++++++++++ | |
31 | hw/net/e1000e_core.c | 9 +++++++-- | 37 | net/vmnet-host.c | 128 ++++++++++++++ |
32 | hw/net/imx_fec.c | 10 ++++++---- | 38 | net/vmnet-shared.c | 114 +++++++++++++ |
33 | net/colo-compare.c | 19 +++++++++++++++++++ | 39 | net/vmnet_int.h | 63 +++++++ |
34 | net/net.c | 6 ++++++ | 40 | qapi/net.json | 133 ++++++++++++++- |
35 | 4 files changed, 38 insertions(+), 6 deletions(-) | 41 | qemu-options.hx | 25 +++ |
36 | 42 | scripts/meson-buildoptions.sh | 1 + | |
37 | 43 | 15 files changed, 1044 insertions(+), 6 deletions(-) | |
44 | create mode 100644 net/vmnet-bridged.m | ||
45 | create mode 100644 net/vmnet-common.m | ||
46 | create mode 100644 net/vmnet-host.c | ||
47 | create mode 100644 net/vmnet-shared.c | ||
48 | create mode 100644 net/vmnet_int.h | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com> | ||
1 | 2 | ||
3 | vmnet.framework dependency is added with 'vmnet' option | ||
4 | to enable or disable it. Default value is 'auto'. | ||
5 | |||
6 | used vmnet features are available since macOS 11.0, | ||
7 | but new backend can be built and work properly with | ||
8 | subset of them on 10.15 too. | ||
9 | |||
10 | Reviewed-by: Akihiko Odaki <akihiko.odaki@gmail.com> | ||
11 | Tested-by: Akihiko Odaki <akihiko.odaki@gmail.com> | ||
12 | Signed-off-by: Vladislav Yaroshchuk <Vladislav.Yaroshchuk@jetbrains.com> | ||
13 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
14 | --- | ||
15 | meson.build | 16 +++++++++++++++- | ||
16 | meson_options.txt | 2 ++ | ||
17 | scripts/meson-buildoptions.sh | 1 + | ||
18 | 3 files changed, 18 insertions(+), 1 deletion(-) | ||
19 | |||
20 | diff --git a/meson.build b/meson.build | ||
21 | index XXXXXXX..XXXXXXX 100644 | ||
22 | --- a/meson.build | ||
23 | +++ b/meson.build | ||
24 | @@ -XXX,XX +XXX,XX @@ if cocoa.found() and get_option('gtk').enabled() | ||
25 | error('Cocoa and GTK+ cannot be enabled at the same time') | ||
26 | endif | ||
27 | |||
28 | +vmnet = dependency('appleframeworks', modules: 'vmnet', required: get_option('vmnet')) | ||
29 | +if vmnet.found() and not cc.has_header_symbol('vmnet/vmnet.h', | ||
30 | + 'VMNET_BRIDGED_MODE', | ||
31 | + dependencies: vmnet) | ||
32 | + vmnet = not_found | ||
33 | + if get_option('vmnet').enabled() | ||
34 | + error('vmnet.framework API is outdated') | ||
35 | + else | ||
36 | + warning('vmnet.framework API is outdated, disabling') | ||
37 | + endif | ||
38 | +endif | ||
39 | + | ||
40 | seccomp = not_found | ||
41 | if not get_option('seccomp').auto() or have_system or have_tools | ||
42 | seccomp = dependency('libseccomp', version: '>=2.3.0', | ||
43 | @@ -XXX,XX +XXX,XX @@ config_host_data.set('CONFIG_VHOST_KERNEL', have_vhost_kernel) | ||
44 | config_host_data.set('CONFIG_VHOST_USER', have_vhost_user) | ||
45 | config_host_data.set('CONFIG_VHOST_CRYPTO', have_vhost_user_crypto) | ||
46 | config_host_data.set('CONFIG_VHOST_VDPA', have_vhost_vdpa) | ||
47 | +config_host_data.set('CONFIG_VMNET', vmnet.found()) | ||
48 | config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', have_vhost_user_blk_server) | ||
49 | config_host_data.set('CONFIG_PNG', png.found()) | ||
50 | config_host_data.set('CONFIG_VNC', vnc.found()) | ||
51 | @@ -XXX,XX +XXX,XX @@ summary(summary_info, bool_yn: true, section: 'Crypto') | ||
52 | # Libraries | ||
53 | summary_info = {} | ||
54 | if targetos == 'darwin' | ||
55 | - summary_info += {'Cocoa support': cocoa} | ||
56 | + summary_info += {'Cocoa support': cocoa} | ||
57 | + summary_info += {'vmnet.framework support': vmnet} | ||
58 | endif | ||
59 | summary_info += {'SDL support': sdl} | ||
60 | summary_info += {'SDL image support': sdl_image} | ||
61 | diff --git a/meson_options.txt b/meson_options.txt | ||
62 | index XXXXXXX..XXXXXXX 100644 | ||
63 | --- a/meson_options.txt | ||
64 | +++ b/meson_options.txt | ||
65 | @@ -XXX,XX +XXX,XX @@ option('netmap', type : 'feature', value : 'auto', | ||
66 | description: 'netmap network backend support') | ||
67 | option('vde', type : 'feature', value : 'auto', | ||
68 | description: 'vde network backend support') | ||
69 | +option('vmnet', type : 'feature', value : 'auto', | ||
70 | + description: 'vmnet.framework network backend support') | ||
71 | option('virglrenderer', type : 'feature', value : 'auto', | ||
72 | description: 'virgl rendering support') | ||
73 | option('png', type : 'feature', value : 'auto', | ||
74 | diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh | ||
75 | index XXXXXXX..XXXXXXX 100644 | ||
76 | --- a/scripts/meson-buildoptions.sh | ||
77 | +++ b/scripts/meson-buildoptions.sh | ||
78 | @@ -XXX,XX +XXX,XX @@ meson_options_help() { | ||
79 | printf "%s\n" ' vhost-kernel vhost kernel backend support' | ||
80 | printf "%s\n" ' vhost-net vhost-net kernel acceleration support' | ||
81 | printf "%s\n" ' vhost-user vhost-user backend support' | ||
82 | + printf "%s\n" ' vmnet vmnet.framework network backend support' | ||
83 | printf "%s\n" ' vhost-user-blk-server' | ||
84 | printf "%s\n" ' build vhost-user-blk server' | ||
85 | printf "%s\n" ' vhost-vdpa vhost-vdpa kernel backend support' | ||
86 | -- | ||
87 | 2.25.1 | diff view generated by jsdifflib |
1 | From: Thomas Huth <thuth@redhat.com> | 1 | From: Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com> |
---|---|---|---|
2 | 2 | ||
3 | The 'vlan' parameter is a continuous source of confusion for the users, | 3 | Create separate netdevs for each vmnet operating mode: |
4 | many people mix it up with the more common term VLAN (the link layer | 4 | - vmnet-host |
5 | packet encapsulation), and even if they realize that the QEMU 'vlan' is | 5 | - vmnet-shared |
6 | rather some kind of network hub emulation, there is still a high risk | 6 | - vmnet-bridged |
7 | that they configure their QEMU networking in a wrong way with this | ||
8 | parameter (e.g. by hooking NICs together, so they get a 'loopback' | ||
9 | between one and the other NIC). | ||
10 | Thus at one point in time, we should finally get rid of the 'vlan' | ||
11 | feature in QEMU. Let's do a first step in this direction by declaring | ||
12 | the 'vlan' parameter as deprecated and informing the users to use the | ||
13 | 'netdev' parameter instead. | ||
14 | 7 | ||
15 | Signed-off-by: Thomas Huth <thuth@redhat.com> | 8 | Reviewed-by: Akihiko Odaki <akihiko.odaki@gmail.com> |
9 | Tested-by: Akihiko Odaki <akihiko.odaki@gmail.com> | ||
10 | Acked-by: Markus Armbruster <armbru@redhat.com> | ||
11 | Signed-off-by: Vladislav Yaroshchuk <Vladislav.Yaroshchuk@jetbrains.com> | ||
16 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 12 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
17 | --- | 13 | --- |
18 | net/net.c | 6 ++++++ | 14 | net/clients.h | 11 ++++ |
19 | 1 file changed, 6 insertions(+) | 15 | net/meson.build | 7 +++ |
16 | net/net.c | 10 ++++ | ||
17 | net/vmnet-bridged.m | 25 +++++++++ | ||
18 | net/vmnet-common.m | 19 +++++++ | ||
19 | net/vmnet-host.c | 24 ++++++++ | ||
20 | net/vmnet-shared.c | 25 +++++++++ | ||
21 | net/vmnet_int.h | 25 +++++++++ | ||
22 | qapi/net.json | 133 +++++++++++++++++++++++++++++++++++++++++++- | ||
23 | 9 files changed, 277 insertions(+), 2 deletions(-) | ||
24 | create mode 100644 net/vmnet-bridged.m | ||
25 | create mode 100644 net/vmnet-common.m | ||
26 | create mode 100644 net/vmnet-host.c | ||
27 | create mode 100644 net/vmnet-shared.c | ||
28 | create mode 100644 net/vmnet_int.h | ||
20 | 29 | ||
30 | diff --git a/net/clients.h b/net/clients.h | ||
31 | index XXXXXXX..XXXXXXX 100644 | ||
32 | --- a/net/clients.h | ||
33 | +++ b/net/clients.h | ||
34 | @@ -XXX,XX +XXX,XX @@ int net_init_vhost_user(const Netdev *netdev, const char *name, | ||
35 | |||
36 | int net_init_vhost_vdpa(const Netdev *netdev, const char *name, | ||
37 | NetClientState *peer, Error **errp); | ||
38 | +#ifdef CONFIG_VMNET | ||
39 | +int net_init_vmnet_host(const Netdev *netdev, const char *name, | ||
40 | + NetClientState *peer, Error **errp); | ||
41 | + | ||
42 | +int net_init_vmnet_shared(const Netdev *netdev, const char *name, | ||
43 | + NetClientState *peer, Error **errp); | ||
44 | + | ||
45 | +int net_init_vmnet_bridged(const Netdev *netdev, const char *name, | ||
46 | + NetClientState *peer, Error **errp); | ||
47 | +#endif /* CONFIG_VMNET */ | ||
48 | + | ||
49 | #endif /* QEMU_NET_CLIENTS_H */ | ||
50 | diff --git a/net/meson.build b/net/meson.build | ||
51 | index XXXXXXX..XXXXXXX 100644 | ||
52 | --- a/net/meson.build | ||
53 | +++ b/net/meson.build | ||
54 | @@ -XXX,XX +XXX,XX @@ if have_vhost_net_vdpa | ||
55 | softmmu_ss.add(files('vhost-vdpa.c')) | ||
56 | endif | ||
57 | |||
58 | +vmnet_files = files( | ||
59 | + 'vmnet-common.m', | ||
60 | + 'vmnet-bridged.m', | ||
61 | + 'vmnet-host.c', | ||
62 | + 'vmnet-shared.c' | ||
63 | +) | ||
64 | +softmmu_ss.add(when: vmnet, if_true: vmnet_files) | ||
65 | subdir('can') | ||
21 | diff --git a/net/net.c b/net/net.c | 66 | diff --git a/net/net.c b/net/net.c |
22 | index XXXXXXX..XXXXXXX 100644 | 67 | index XXXXXXX..XXXXXXX 100644 |
23 | --- a/net/net.c | 68 | --- a/net/net.c |
24 | +++ b/net/net.c | 69 | +++ b/net/net.c |
25 | @@ -XXX,XX +XXX,XX @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp) | 70 | @@ -XXX,XX +XXX,XX @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])( |
26 | const Netdev *netdev; | 71 | #ifdef CONFIG_L2TPV3 |
27 | const char *name; | 72 | [NET_CLIENT_DRIVER_L2TPV3] = net_init_l2tpv3, |
28 | NetClientState *peer = NULL; | 73 | #endif |
29 | + static bool vlan_warned; | 74 | +#ifdef CONFIG_VMNET |
30 | 75 | + [NET_CLIENT_DRIVER_VMNET_HOST] = net_init_vmnet_host, | |
31 | if (is_netdev) { | 76 | + [NET_CLIENT_DRIVER_VMNET_SHARED] = net_init_vmnet_shared, |
32 | netdev = object; | 77 | + [NET_CLIENT_DRIVER_VMNET_BRIDGED] = net_init_vmnet_bridged, |
33 | @@ -XXX,XX +XXX,XX @@ static int net_client_init1(const void *object, bool is_netdev, Error **errp) | 78 | +#endif /* CONFIG_VMNET */ |
34 | !opts->u.nic.data->has_netdev) { | 79 | }; |
35 | peer = net_hub_add_port(net->has_vlan ? net->vlan : 0, NULL); | 80 | |
36 | } | 81 | |
37 | + | 82 | @@ -XXX,XX +XXX,XX @@ void show_netdevs(void) |
38 | + if (net->has_vlan && !vlan_warned) { | 83 | #endif |
39 | + error_report("'vlan' is deprecated. Please use 'netdev' instead."); | 84 | #ifdef CONFIG_VHOST_VDPA |
40 | + vlan_warned = true; | 85 | "vhost-vdpa", |
41 | + } | 86 | +#endif |
42 | } | 87 | +#ifdef CONFIG_VMNET |
43 | 88 | + "vmnet-host", | |
44 | if (net_client_init_fun[netdev->type](netdev, name, peer, errp) < 0) { | 89 | + "vmnet-shared", |
90 | + "vmnet-bridged", | ||
91 | #endif | ||
92 | }; | ||
93 | |||
94 | diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m | ||
95 | new file mode 100644 | ||
96 | index XXXXXXX..XXXXXXX | ||
97 | --- /dev/null | ||
98 | +++ b/net/vmnet-bridged.m | ||
99 | @@ -XXX,XX +XXX,XX @@ | ||
100 | +/* | ||
101 | + * vmnet-bridged.m | ||
102 | + * | ||
103 | + * Copyright(c) 2022 Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com> | ||
104 | + * | ||
105 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||
106 | + * See the COPYING file in the top-level directory. | ||
107 | + * | ||
108 | + */ | ||
109 | + | ||
110 | +#include "qemu/osdep.h" | ||
111 | +#include "qapi/qapi-types-net.h" | ||
112 | +#include "vmnet_int.h" | ||
113 | +#include "clients.h" | ||
114 | +#include "qemu/error-report.h" | ||
115 | +#include "qapi/error.h" | ||
116 | + | ||
117 | +#include <vmnet/vmnet.h> | ||
118 | + | ||
119 | +int net_init_vmnet_bridged(const Netdev *netdev, const char *name, | ||
120 | + NetClientState *peer, Error **errp) | ||
121 | +{ | ||
122 | + error_setg(errp, "vmnet-bridged is not implemented yet"); | ||
123 | + return -1; | ||
124 | +} | ||
125 | diff --git a/net/vmnet-common.m b/net/vmnet-common.m | ||
126 | new file mode 100644 | ||
127 | index XXXXXXX..XXXXXXX | ||
128 | --- /dev/null | ||
129 | +++ b/net/vmnet-common.m | ||
130 | @@ -XXX,XX +XXX,XX @@ | ||
131 | +/* | ||
132 | + * vmnet-common.m - network client wrapper for Apple vmnet.framework | ||
133 | + * | ||
134 | + * Copyright(c) 2022 Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com> | ||
135 | + * Copyright(c) 2021 Phillip Tennen <phillip@axleos.com> | ||
136 | + * | ||
137 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||
138 | + * See the COPYING file in the top-level directory. | ||
139 | + * | ||
140 | + */ | ||
141 | + | ||
142 | +#include "qemu/osdep.h" | ||
143 | +#include "qapi/qapi-types-net.h" | ||
144 | +#include "vmnet_int.h" | ||
145 | +#include "clients.h" | ||
146 | +#include "qemu/error-report.h" | ||
147 | +#include "qapi/error.h" | ||
148 | + | ||
149 | +#include <vmnet/vmnet.h> | ||
150 | diff --git a/net/vmnet-host.c b/net/vmnet-host.c | ||
151 | new file mode 100644 | ||
152 | index XXXXXXX..XXXXXXX | ||
153 | --- /dev/null | ||
154 | +++ b/net/vmnet-host.c | ||
155 | @@ -XXX,XX +XXX,XX @@ | ||
156 | +/* | ||
157 | + * vmnet-host.c | ||
158 | + * | ||
159 | + * Copyright(c) 2022 Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com> | ||
160 | + * | ||
161 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||
162 | + * See the COPYING file in the top-level directory. | ||
163 | + * | ||
164 | + */ | ||
165 | + | ||
166 | +#include "qemu/osdep.h" | ||
167 | +#include "qapi/qapi-types-net.h" | ||
168 | +#include "vmnet_int.h" | ||
169 | +#include "clients.h" | ||
170 | +#include "qemu/error-report.h" | ||
171 | +#include "qapi/error.h" | ||
172 | + | ||
173 | +#include <vmnet/vmnet.h> | ||
174 | + | ||
175 | +int net_init_vmnet_host(const Netdev *netdev, const char *name, | ||
176 | + NetClientState *peer, Error **errp) { | ||
177 | + error_setg(errp, "vmnet-host is not implemented yet"); | ||
178 | + return -1; | ||
179 | +} | ||
180 | diff --git a/net/vmnet-shared.c b/net/vmnet-shared.c | ||
181 | new file mode 100644 | ||
182 | index XXXXXXX..XXXXXXX | ||
183 | --- /dev/null | ||
184 | +++ b/net/vmnet-shared.c | ||
185 | @@ -XXX,XX +XXX,XX @@ | ||
186 | +/* | ||
187 | + * vmnet-shared.c | ||
188 | + * | ||
189 | + * Copyright(c) 2022 Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com> | ||
190 | + * | ||
191 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||
192 | + * See the COPYING file in the top-level directory. | ||
193 | + * | ||
194 | + */ | ||
195 | + | ||
196 | +#include "qemu/osdep.h" | ||
197 | +#include "qapi/qapi-types-net.h" | ||
198 | +#include "vmnet_int.h" | ||
199 | +#include "clients.h" | ||
200 | +#include "qemu/error-report.h" | ||
201 | +#include "qapi/error.h" | ||
202 | + | ||
203 | +#include <vmnet/vmnet.h> | ||
204 | + | ||
205 | +int net_init_vmnet_shared(const Netdev *netdev, const char *name, | ||
206 | + NetClientState *peer, Error **errp) | ||
207 | +{ | ||
208 | + error_setg(errp, "vmnet-shared is not implemented yet"); | ||
209 | + return -1; | ||
210 | +} | ||
211 | diff --git a/net/vmnet_int.h b/net/vmnet_int.h | ||
212 | new file mode 100644 | ||
213 | index XXXXXXX..XXXXXXX | ||
214 | --- /dev/null | ||
215 | +++ b/net/vmnet_int.h | ||
216 | @@ -XXX,XX +XXX,XX @@ | ||
217 | +/* | ||
218 | + * vmnet_int.h | ||
219 | + * | ||
220 | + * Copyright(c) 2022 Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com> | ||
221 | + * | ||
222 | + * This work is licensed under the terms of the GNU GPL, version 2 or later. | ||
223 | + * See the COPYING file in the top-level directory. | ||
224 | + * | ||
225 | + */ | ||
226 | +#ifndef VMNET_INT_H | ||
227 | +#define VMNET_INT_H | ||
228 | + | ||
229 | +#include "qemu/osdep.h" | ||
230 | +#include "vmnet_int.h" | ||
231 | +#include "clients.h" | ||
232 | + | ||
233 | +#include <vmnet/vmnet.h> | ||
234 | + | ||
235 | +typedef struct VmnetState { | ||
236 | + NetClientState nc; | ||
237 | + | ||
238 | +} VmnetState; | ||
239 | + | ||
240 | + | ||
241 | +#endif /* VMNET_INT_H */ | ||
242 | diff --git a/qapi/net.json b/qapi/net.json | ||
243 | index XXXXXXX..XXXXXXX 100644 | ||
244 | --- a/qapi/net.json | ||
245 | +++ b/qapi/net.json | ||
246 | @@ -XXX,XX +XXX,XX @@ | ||
247 | '*vhostdev': 'str', | ||
248 | '*queues': 'int' } } | ||
249 | |||
250 | +## | ||
251 | +# @NetdevVmnetHostOptions: | ||
252 | +# | ||
253 | +# vmnet (host mode) network backend. | ||
254 | +# | ||
255 | +# Allows the vmnet interface to communicate with other vmnet | ||
256 | +# interfaces that are in host mode and also with the host. | ||
257 | +# | ||
258 | +# @start-address: The starting IPv4 address to use for the interface. | ||
259 | +# Must be in the private IP range (RFC 1918). Must be | ||
260 | +# specified along with @end-address and @subnet-mask. | ||
261 | +# This address is used as the gateway address. The | ||
262 | +# subsequent address up to and including end-address are | ||
263 | +# placed in the DHCP pool. | ||
264 | +# | ||
265 | +# @end-address: The DHCP IPv4 range end address to use for the | ||
266 | +# interface. Must be in the private IP range (RFC 1918). | ||
267 | +# Must be specified along with @start-address and | ||
268 | +# @subnet-mask. | ||
269 | +# | ||
270 | +# @subnet-mask: The IPv4 subnet mask to use on the interface. Must | ||
271 | +# be specified along with @start-address and @subnet-mask. | ||
272 | +# | ||
273 | +# @isolated: Enable isolation for this interface. Interface isolation | ||
274 | +# ensures that vmnet interface is not able to communicate | ||
275 | +# with any other vmnet interfaces. Only communication with | ||
276 | +# host is allowed. Requires at least macOS Big Sur 11.0. | ||
277 | +# | ||
278 | +# @net-uuid: The identifier (UUID) to uniquely identify the isolated | ||
279 | +# network vmnet interface should be added to. If | ||
280 | +# set, no DHCP service is provided for this interface and | ||
281 | +# network communication is allowed only with other interfaces | ||
282 | +# added to this network identified by the UUID. Requires | ||
283 | +# at least macOS Big Sur 11.0. | ||
284 | +# | ||
285 | +# Since: 7.1 | ||
286 | +## | ||
287 | +{ 'struct': 'NetdevVmnetHostOptions', | ||
288 | + 'data': { | ||
289 | + '*start-address': 'str', | ||
290 | + '*end-address': 'str', | ||
291 | + '*subnet-mask': 'str', | ||
292 | + '*isolated': 'bool', | ||
293 | + '*net-uuid': 'str' }, | ||
294 | + 'if': 'CONFIG_VMNET' } | ||
295 | + | ||
296 | +## | ||
297 | +# @NetdevVmnetSharedOptions: | ||
298 | +# | ||
299 | +# vmnet (shared mode) network backend. | ||
300 | +# | ||
301 | +# Allows traffic originating from the vmnet interface to reach the | ||
302 | +# Internet through a network address translator (NAT). | ||
303 | +# The vmnet interface can communicate with the host and with | ||
304 | +# other shared mode interfaces on the same subnet. If no DHCP | ||
305 | +# settings, subnet mask and IPv6 prefix specified, the interface can | ||
306 | +# communicate with any of other interfaces in shared mode. | ||
307 | +# | ||
308 | +# @start-address: The starting IPv4 address to use for the interface. | ||
309 | +# Must be in the private IP range (RFC 1918). Must be | ||
310 | +# specified along with @end-address and @subnet-mask. | ||
311 | +# This address is used as the gateway address. The | ||
312 | +# subsequent address up to and including end-address are | ||
313 | +# placed in the DHCP pool. | ||
314 | +# | ||
315 | +# @end-address: The DHCP IPv4 range end address to use for the | ||
316 | +# interface. Must be in the private IP range (RFC 1918). | ||
317 | +# Must be specified along with @start-address and @subnet-mask. | ||
318 | +# | ||
319 | +# @subnet-mask: The IPv4 subnet mask to use on the interface. Must | ||
320 | +# be specified along with @start-address and @subnet-mask. | ||
321 | +# | ||
322 | +# @isolated: Enable isolation for this interface. Interface isolation | ||
323 | +# ensures that vmnet interface is not able to communicate | ||
324 | +# with any other vmnet interfaces. Only communication with | ||
325 | +# host is allowed. Requires at least macOS Big Sur 11.0. | ||
326 | +# | ||
327 | +# @nat66-prefix: The IPv6 prefix to use into guest network. Must be a | ||
328 | +# unique local address i.e. start with fd00::/8 and have | ||
329 | +# length of 64. | ||
330 | +# | ||
331 | +# Since: 7.1 | ||
332 | +## | ||
333 | +{ 'struct': 'NetdevVmnetSharedOptions', | ||
334 | + 'data': { | ||
335 | + '*start-address': 'str', | ||
336 | + '*end-address': 'str', | ||
337 | + '*subnet-mask': 'str', | ||
338 | + '*isolated': 'bool', | ||
339 | + '*nat66-prefix': 'str' }, | ||
340 | + 'if': 'CONFIG_VMNET' } | ||
341 | + | ||
342 | +## | ||
343 | +# @NetdevVmnetBridgedOptions: | ||
344 | +# | ||
345 | +# vmnet (bridged mode) network backend. | ||
346 | +# | ||
347 | +# Bridges the vmnet interface with a physical network interface. | ||
348 | +# | ||
349 | +# @ifname: The name of the physical interface to be bridged. | ||
350 | +# | ||
351 | +# @isolated: Enable isolation for this interface. Interface isolation | ||
352 | +# ensures that vmnet interface is not able to communicate | ||
353 | +# with any other vmnet interfaces. Only communication with | ||
354 | +# host is allowed. Requires at least macOS Big Sur 11.0. | ||
355 | +# | ||
356 | +# Since: 7.1 | ||
357 | +## | ||
358 | +{ 'struct': 'NetdevVmnetBridgedOptions', | ||
359 | + 'data': { | ||
360 | + 'ifname': 'str', | ||
361 | + '*isolated': 'bool' }, | ||
362 | + 'if': 'CONFIG_VMNET' } | ||
363 | + | ||
364 | ## | ||
365 | # @NetClientDriver: | ||
366 | # | ||
367 | @@ -XXX,XX +XXX,XX @@ | ||
368 | # Since: 2.7 | ||
369 | # | ||
370 | # @vhost-vdpa since 5.1 | ||
371 | +# @vmnet-host since 7.1 | ||
372 | +# @vmnet-shared since 7.1 | ||
373 | +# @vmnet-bridged since 7.1 | ||
374 | ## | ||
375 | { 'enum': 'NetClientDriver', | ||
376 | 'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'vde', | ||
377 | - 'bridge', 'hubport', 'netmap', 'vhost-user', 'vhost-vdpa' ] } | ||
378 | + 'bridge', 'hubport', 'netmap', 'vhost-user', 'vhost-vdpa', | ||
379 | + { 'name': 'vmnet-host', 'if': 'CONFIG_VMNET' }, | ||
380 | + { 'name': 'vmnet-shared', 'if': 'CONFIG_VMNET' }, | ||
381 | + { 'name': 'vmnet-bridged', 'if': 'CONFIG_VMNET' }] } | ||
382 | |||
383 | ## | ||
384 | # @Netdev: | ||
385 | @@ -XXX,XX +XXX,XX @@ | ||
386 | # Since: 1.2 | ||
387 | # | ||
388 | # 'l2tpv3' - since 2.1 | ||
389 | +# 'vmnet-host' - since 7.1 | ||
390 | +# 'vmnet-shared' - since 7.1 | ||
391 | +# 'vmnet-bridged' - since 7.1 | ||
392 | ## | ||
393 | { 'union': 'Netdev', | ||
394 | 'base': { 'id': 'str', 'type': 'NetClientDriver' }, | ||
395 | @@ -XXX,XX +XXX,XX @@ | ||
396 | 'hubport': 'NetdevHubPortOptions', | ||
397 | 'netmap': 'NetdevNetmapOptions', | ||
398 | 'vhost-user': 'NetdevVhostUserOptions', | ||
399 | - 'vhost-vdpa': 'NetdevVhostVDPAOptions' } } | ||
400 | + 'vhost-vdpa': 'NetdevVhostVDPAOptions', | ||
401 | + 'vmnet-host': { 'type': 'NetdevVmnetHostOptions', | ||
402 | + 'if': 'CONFIG_VMNET' }, | ||
403 | + 'vmnet-shared': { 'type': 'NetdevVmnetSharedOptions', | ||
404 | + 'if': 'CONFIG_VMNET' }, | ||
405 | + 'vmnet-bridged': { 'type': 'NetdevVmnetBridgedOptions', | ||
406 | + 'if': 'CONFIG_VMNET' } } } | ||
407 | |||
408 | ## | ||
409 | # @RxState: | ||
45 | -- | 410 | -- |
46 | 2.7.4 | 411 | 2.25.1 |
47 | |||
48 | diff view generated by jsdifflib |
1 | From: Li Qiang <liq3ea@gmail.com> | 1 | From: Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com> |
---|---|---|---|
2 | 2 | ||
3 | This issue is like the issue in e1000 network card addressed in | 3 | Interaction with vmnet.framework in different modes |
4 | this commit: | 4 | differs only on configuration stage, so we can create |
5 | e1000: eliminate infinite loops on out-of-bounds transfer start. | 5 | common `send`, `receive`, etc. procedures and reuse them. |
6 | 6 | ||
7 | Signed-off-by: Li Qiang <liqiang6-s@360.cn> | 7 | Reviewed-by: Akihiko Odaki <akihiko.odaki@gmail.com> |
8 | Reviewed-by: Dmitry Fleytman <dmitry@daynix.com> | 8 | Tested-by: Akihiko Odaki <akihiko.odaki@gmail.com> |
9 | Signed-off-by: Phillip Tennen <phillip@axleos.com> | ||
10 | Signed-off-by: Vladislav Yaroshchuk <Vladislav.Yaroshchuk@jetbrains.com> | ||
9 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 11 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
10 | --- | 12 | --- |
11 | hw/net/e1000e_core.c | 7 ++++++- | 13 | net/vmnet-common.m | 359 +++++++++++++++++++++++++++++++++++++++++++++ |
12 | 1 file changed, 6 insertions(+), 1 deletion(-) | 14 | net/vmnet-shared.c | 97 +++++++++++- |
15 | net/vmnet_int.h | 40 ++++- | ||
16 | 3 files changed, 491 insertions(+), 5 deletions(-) | ||
13 | 17 | ||
14 | diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c | 18 | diff --git a/net/vmnet-common.m b/net/vmnet-common.m |
15 | index XXXXXXX..XXXXXXX 100644 | 19 | index XXXXXXX..XXXXXXX 100644 |
16 | --- a/hw/net/e1000e_core.c | 20 | --- a/net/vmnet-common.m |
17 | +++ b/hw/net/e1000e_core.c | 21 | +++ b/net/vmnet-common.m |
18 | @@ -XXX,XX +XXX,XX @@ typedef struct E1000E_RingInfo_st { | 22 | @@ -XXX,XX +XXX,XX @@ |
19 | static inline bool | 23 | */ |
20 | e1000e_ring_empty(E1000ECore *core, const E1000E_RingInfo *r) | 24 | |
21 | { | 25 | #include "qemu/osdep.h" |
22 | - return core->mac[r->dh] == core->mac[r->dt]; | 26 | +#include "qemu/main-loop.h" |
23 | + return core->mac[r->dh] == core->mac[r->dt] || | 27 | +#include "qemu/log.h" |
24 | + core->mac[r->dt] >= core->mac[r->dlen] / E1000_RING_DESC_LEN; | 28 | #include "qapi/qapi-types-net.h" |
25 | } | 29 | #include "vmnet_int.h" |
26 | 30 | #include "clients.h" | |
27 | static inline uint64_t | 31 | @@ -XXX,XX +XXX,XX @@ |
28 | @@ -XXX,XX +XXX,XX @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt, | 32 | #include "qapi/error.h" |
29 | desc_size = core->rx_desc_buf_size; | 33 | |
30 | } | 34 | #include <vmnet/vmnet.h> |
31 | 35 | +#include <dispatch/dispatch.h> | |
32 | + if (e1000e_ring_empty(core, rxi)) { | 36 | + |
37 | + | ||
38 | +static void vmnet_send_completed(NetClientState *nc, ssize_t len); | ||
39 | + | ||
40 | + | ||
41 | +const char *vmnet_status_map_str(vmnet_return_t status) | ||
42 | +{ | ||
43 | + switch (status) { | ||
44 | + case VMNET_SUCCESS: | ||
45 | + return "success"; | ||
46 | + case VMNET_FAILURE: | ||
47 | + return "general failure (possibly not enough privileges)"; | ||
48 | + case VMNET_MEM_FAILURE: | ||
49 | + return "memory allocation failure"; | ||
50 | + case VMNET_INVALID_ARGUMENT: | ||
51 | + return "invalid argument specified"; | ||
52 | + case VMNET_SETUP_INCOMPLETE: | ||
53 | + return "interface setup is not complete"; | ||
54 | + case VMNET_INVALID_ACCESS: | ||
55 | + return "invalid access, permission denied"; | ||
56 | + case VMNET_PACKET_TOO_BIG: | ||
57 | + return "packet size is larger than MTU"; | ||
58 | + case VMNET_BUFFER_EXHAUSTED: | ||
59 | + return "buffers exhausted in kernel"; | ||
60 | + case VMNET_TOO_MANY_PACKETS: | ||
61 | + return "packet count exceeds limit"; | ||
62 | +#if defined(MAC_OS_VERSION_11_0) && \ | ||
63 | + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 | ||
64 | + case VMNET_SHARING_SERVICE_BUSY: | ||
65 | + return "conflict, sharing service is in use"; | ||
66 | +#endif | ||
67 | + default: | ||
68 | + return "unknown vmnet error"; | ||
69 | + } | ||
70 | +} | ||
71 | + | ||
72 | + | ||
73 | +/** | ||
74 | + * Write packets from QEMU to vmnet interface. | ||
75 | + * | ||
76 | + * vmnet.framework supports iov, but writing more than | ||
77 | + * one iov into vmnet interface fails with | ||
78 | + * 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into | ||
79 | + * one and passing it to vmnet works fine. That's the | ||
80 | + * reason why receive_iov() left unimplemented. But it still | ||
81 | + * works with good performance having .receive() only. | ||
82 | + */ | ||
83 | +ssize_t vmnet_receive_common(NetClientState *nc, | ||
84 | + const uint8_t *buf, | ||
85 | + size_t size) | ||
86 | +{ | ||
87 | + VmnetState *s = DO_UPCAST(VmnetState, nc, nc); | ||
88 | + struct vmpktdesc packet; | ||
89 | + struct iovec iov; | ||
90 | + int pkt_cnt; | ||
91 | + vmnet_return_t if_status; | ||
92 | + | ||
93 | + if (size > s->max_packet_size) { | ||
94 | + warn_report("vmnet: packet is too big, %zu > %" PRIu64, | ||
95 | + packet.vm_pkt_size, | ||
96 | + s->max_packet_size); | ||
97 | + return -1; | ||
98 | + } | ||
99 | + | ||
100 | + iov.iov_base = (char *) buf; | ||
101 | + iov.iov_len = size; | ||
102 | + | ||
103 | + packet.vm_pkt_iovcnt = 1; | ||
104 | + packet.vm_flags = 0; | ||
105 | + packet.vm_pkt_size = size; | ||
106 | + packet.vm_pkt_iov = &iov; | ||
107 | + pkt_cnt = 1; | ||
108 | + | ||
109 | + if_status = vmnet_write(s->vmnet_if, &packet, &pkt_cnt); | ||
110 | + if (if_status != VMNET_SUCCESS) { | ||
111 | + error_report("vmnet: write error: %s\n", | ||
112 | + vmnet_status_map_str(if_status)); | ||
113 | + return -1; | ||
114 | + } | ||
115 | + | ||
116 | + if (pkt_cnt) { | ||
117 | + return size; | ||
118 | + } | ||
119 | + return 0; | ||
120 | +} | ||
121 | + | ||
122 | + | ||
123 | +/** | ||
124 | + * Read packets from vmnet interface and write them | ||
125 | + * to temporary buffers in VmnetState. | ||
126 | + * | ||
127 | + * Returns read packets number (may be 0) on success, | ||
128 | + * -1 on error | ||
129 | + */ | ||
130 | +static int vmnet_read_packets(VmnetState *s) | ||
131 | +{ | ||
132 | + assert(s->packets_send_current_pos == s->packets_send_end_pos); | ||
133 | + | ||
134 | + struct vmpktdesc *packets = s->packets_buf; | ||
135 | + vmnet_return_t status; | ||
136 | + int i; | ||
137 | + | ||
138 | + /* Read as many packets as present */ | ||
139 | + s->packets_send_current_pos = 0; | ||
140 | + s->packets_send_end_pos = VMNET_PACKETS_LIMIT; | ||
141 | + for (i = 0; i < s->packets_send_end_pos; ++i) { | ||
142 | + packets[i].vm_pkt_size = s->max_packet_size; | ||
143 | + packets[i].vm_pkt_iovcnt = 1; | ||
144 | + packets[i].vm_flags = 0; | ||
145 | + } | ||
146 | + | ||
147 | + status = vmnet_read(s->vmnet_if, packets, &s->packets_send_end_pos); | ||
148 | + if (status != VMNET_SUCCESS) { | ||
149 | + error_printf("vmnet: read failed: %s\n", | ||
150 | + vmnet_status_map_str(status)); | ||
151 | + s->packets_send_current_pos = 0; | ||
152 | + s->packets_send_end_pos = 0; | ||
153 | + return -1; | ||
154 | + } | ||
155 | + return s->packets_send_end_pos; | ||
156 | +} | ||
157 | + | ||
158 | + | ||
159 | +/** | ||
160 | + * Write packets from temporary buffers in VmnetState | ||
161 | + * to QEMU. | ||
162 | + */ | ||
163 | +static void vmnet_write_packets_to_qemu(VmnetState *s) | ||
164 | +{ | ||
165 | + while (s->packets_send_current_pos < s->packets_send_end_pos) { | ||
166 | + ssize_t size = qemu_send_packet_async(&s->nc, | ||
167 | + s->iov_buf[s->packets_send_current_pos].iov_base, | ||
168 | + s->packets_buf[s->packets_send_current_pos].vm_pkt_size, | ||
169 | + vmnet_send_completed); | ||
170 | + | ||
171 | + if (size == 0) { | ||
172 | + /* QEMU is not ready to consume more packets - | ||
173 | + * stop and wait for completion callback call */ | ||
33 | + return; | 174 | + return; |
34 | + } | 175 | + } |
35 | + | 176 | + ++s->packets_send_current_pos; |
36 | base = e1000e_ring_head_descr(core, rxi); | 177 | + } |
37 | 178 | +} | |
38 | pci_dma_read(d, base, &desc, core->rx_desc_len); | 179 | + |
180 | + | ||
181 | +/** | ||
182 | + * Bottom half callback that transfers packets from vmnet interface | ||
183 | + * to QEMU. | ||
184 | + * | ||
185 | + * The process of transferring packets is three-staged: | ||
186 | + * 1. Handle vmnet event; | ||
187 | + * 2. Read packets from vmnet interface into temporary buffer; | ||
188 | + * 3. Write packets from temporary buffer to QEMU. | ||
189 | + * | ||
190 | + * QEMU may suspend this process on the last stage, returning 0 from | ||
191 | + * qemu_send_packet_async function. If this happens, we should | ||
192 | + * respectfully wait until it is ready to consume more packets, | ||
193 | + * write left ones in temporary buffer and only after this | ||
194 | + * continue reading more packets from vmnet interface. | ||
195 | + * | ||
196 | + * Packets to be transferred are stored into packets_buf, | ||
197 | + * in the window [packets_send_current_pos..packets_send_end_pos) | ||
198 | + * including current_pos, excluding end_pos. | ||
199 | + * | ||
200 | + * Thus, if QEMU is not ready, buffer is not read and | ||
201 | + * packets_send_current_pos < packets_send_end_pos. | ||
202 | + */ | ||
203 | +static void vmnet_send_bh(void *opaque) | ||
204 | +{ | ||
205 | + NetClientState *nc = (NetClientState *) opaque; | ||
206 | + VmnetState *s = DO_UPCAST(VmnetState, nc, nc); | ||
207 | + | ||
208 | + /* | ||
209 | + * Do nothing if QEMU is not ready - wait | ||
210 | + * for completion callback invocation | ||
211 | + */ | ||
212 | + if (s->packets_send_current_pos < s->packets_send_end_pos) { | ||
213 | + return; | ||
214 | + } | ||
215 | + | ||
216 | + /* Read packets from vmnet interface */ | ||
217 | + if (vmnet_read_packets(s) > 0) { | ||
218 | + /* Send them to QEMU */ | ||
219 | + vmnet_write_packets_to_qemu(s); | ||
220 | + } | ||
221 | +} | ||
222 | + | ||
223 | + | ||
224 | +/** | ||
225 | + * Completion callback to be invoked by QEMU when it becomes | ||
226 | + * ready to consume more packets. | ||
227 | + */ | ||
228 | +static void vmnet_send_completed(NetClientState *nc, ssize_t len) | ||
229 | +{ | ||
230 | + VmnetState *s = DO_UPCAST(VmnetState, nc, nc); | ||
231 | + | ||
232 | + /* Callback is invoked eq queued packet is sent */ | ||
233 | + ++s->packets_send_current_pos; | ||
234 | + | ||
235 | + /* Complete sending packets left in VmnetState buffers */ | ||
236 | + vmnet_write_packets_to_qemu(s); | ||
237 | + | ||
238 | + /* And read new ones from vmnet if VmnetState buffer is ready */ | ||
239 | + if (s->packets_send_current_pos < s->packets_send_end_pos) { | ||
240 | + qemu_bh_schedule(s->send_bh); | ||
241 | + } | ||
242 | +} | ||
243 | + | ||
244 | + | ||
245 | +static void vmnet_bufs_init(VmnetState *s) | ||
246 | +{ | ||
247 | + struct vmpktdesc *packets = s->packets_buf; | ||
248 | + struct iovec *iov = s->iov_buf; | ||
249 | + int i; | ||
250 | + | ||
251 | + for (i = 0; i < VMNET_PACKETS_LIMIT; ++i) { | ||
252 | + iov[i].iov_len = s->max_packet_size; | ||
253 | + iov[i].iov_base = g_malloc0(iov[i].iov_len); | ||
254 | + packets[i].vm_pkt_iov = iov + i; | ||
255 | + } | ||
256 | +} | ||
257 | + | ||
258 | + | ||
259 | +int vmnet_if_create(NetClientState *nc, | ||
260 | + xpc_object_t if_desc, | ||
261 | + Error **errp) | ||
262 | +{ | ||
263 | + VmnetState *s = DO_UPCAST(VmnetState, nc, nc); | ||
264 | + dispatch_semaphore_t if_created_sem = dispatch_semaphore_create(0); | ||
265 | + __block vmnet_return_t if_status; | ||
266 | + | ||
267 | + s->if_queue = dispatch_queue_create( | ||
268 | + "org.qemu.vmnet.if_queue", | ||
269 | + DISPATCH_QUEUE_SERIAL | ||
270 | + ); | ||
271 | + | ||
272 | + xpc_dictionary_set_bool( | ||
273 | + if_desc, | ||
274 | + vmnet_allocate_mac_address_key, | ||
275 | + false | ||
276 | + ); | ||
277 | + | ||
278 | +#ifdef DEBUG | ||
279 | + qemu_log("vmnet.start.interface_desc:\n"); | ||
280 | + xpc_dictionary_apply(if_desc, | ||
281 | + ^bool(const char *k, xpc_object_t v) { | ||
282 | + char *desc = xpc_copy_description(v); | ||
283 | + qemu_log(" %s=%s\n", k, desc); | ||
284 | + free(desc); | ||
285 | + return true; | ||
286 | + }); | ||
287 | +#endif /* DEBUG */ | ||
288 | + | ||
289 | + s->vmnet_if = vmnet_start_interface( | ||
290 | + if_desc, | ||
291 | + s->if_queue, | ||
292 | + ^(vmnet_return_t status, xpc_object_t interface_param) { | ||
293 | + if_status = status; | ||
294 | + if (status != VMNET_SUCCESS || !interface_param) { | ||
295 | + dispatch_semaphore_signal(if_created_sem); | ||
296 | + return; | ||
297 | + } | ||
298 | + | ||
299 | +#ifdef DEBUG | ||
300 | + qemu_log("vmnet.start.interface_param:\n"); | ||
301 | + xpc_dictionary_apply(interface_param, | ||
302 | + ^bool(const char *k, xpc_object_t v) { | ||
303 | + char *desc = xpc_copy_description(v); | ||
304 | + qemu_log(" %s=%s\n", k, desc); | ||
305 | + free(desc); | ||
306 | + return true; | ||
307 | + }); | ||
308 | +#endif /* DEBUG */ | ||
309 | + | ||
310 | + s->mtu = xpc_dictionary_get_uint64( | ||
311 | + interface_param, | ||
312 | + vmnet_mtu_key); | ||
313 | + s->max_packet_size = xpc_dictionary_get_uint64( | ||
314 | + interface_param, | ||
315 | + vmnet_max_packet_size_key); | ||
316 | + | ||
317 | + dispatch_semaphore_signal(if_created_sem); | ||
318 | + }); | ||
319 | + | ||
320 | + if (s->vmnet_if == NULL) { | ||
321 | + dispatch_release(s->if_queue); | ||
322 | + dispatch_release(if_created_sem); | ||
323 | + error_setg(errp, | ||
324 | + "unable to create interface with requested params"); | ||
325 | + return -1; | ||
326 | + } | ||
327 | + | ||
328 | + dispatch_semaphore_wait(if_created_sem, DISPATCH_TIME_FOREVER); | ||
329 | + dispatch_release(if_created_sem); | ||
330 | + | ||
331 | + if (if_status != VMNET_SUCCESS) { | ||
332 | + dispatch_release(s->if_queue); | ||
333 | + error_setg(errp, | ||
334 | + "cannot create vmnet interface: %s", | ||
335 | + vmnet_status_map_str(if_status)); | ||
336 | + return -1; | ||
337 | + } | ||
338 | + | ||
339 | + s->send_bh = aio_bh_new(qemu_get_aio_context(), vmnet_send_bh, nc); | ||
340 | + vmnet_bufs_init(s); | ||
341 | + | ||
342 | + s->packets_send_current_pos = 0; | ||
343 | + s->packets_send_end_pos = 0; | ||
344 | + | ||
345 | + vmnet_interface_set_event_callback( | ||
346 | + s->vmnet_if, | ||
347 | + VMNET_INTERFACE_PACKETS_AVAILABLE, | ||
348 | + s->if_queue, | ||
349 | + ^(interface_event_t event_id, xpc_object_t event) { | ||
350 | + assert(event_id == VMNET_INTERFACE_PACKETS_AVAILABLE); | ||
351 | + /* | ||
352 | + * This function is being called from a non qemu thread, so | ||
353 | + * we only schedule a BH, and do the rest of the io completion | ||
354 | + * handling from vmnet_send_bh() which runs in a qemu context. | ||
355 | + */ | ||
356 | + qemu_bh_schedule(s->send_bh); | ||
357 | + }); | ||
358 | + | ||
359 | + return 0; | ||
360 | +} | ||
361 | + | ||
362 | + | ||
363 | +void vmnet_cleanup_common(NetClientState *nc) | ||
364 | +{ | ||
365 | + VmnetState *s = DO_UPCAST(VmnetState, nc, nc); | ||
366 | + dispatch_semaphore_t if_stopped_sem; | ||
367 | + | ||
368 | + if (s->vmnet_if == NULL) { | ||
369 | + return; | ||
370 | + } | ||
371 | + | ||
372 | + if_stopped_sem = dispatch_semaphore_create(0); | ||
373 | + vmnet_stop_interface( | ||
374 | + s->vmnet_if, | ||
375 | + s->if_queue, | ||
376 | + ^(vmnet_return_t status) { | ||
377 | + assert(status == VMNET_SUCCESS); | ||
378 | + dispatch_semaphore_signal(if_stopped_sem); | ||
379 | + }); | ||
380 | + dispatch_semaphore_wait(if_stopped_sem, DISPATCH_TIME_FOREVER); | ||
381 | + | ||
382 | + qemu_purge_queued_packets(nc); | ||
383 | + | ||
384 | + qemu_bh_delete(s->send_bh); | ||
385 | + dispatch_release(if_stopped_sem); | ||
386 | + dispatch_release(s->if_queue); | ||
387 | + | ||
388 | + for (int i = 0; i < VMNET_PACKETS_LIMIT; ++i) { | ||
389 | + g_free(s->iov_buf[i].iov_base); | ||
390 | + } | ||
391 | +} | ||
392 | diff --git a/net/vmnet-shared.c b/net/vmnet-shared.c | ||
393 | index XXXXXXX..XXXXXXX 100644 | ||
394 | --- a/net/vmnet-shared.c | ||
395 | +++ b/net/vmnet-shared.c | ||
396 | @@ -XXX,XX +XXX,XX @@ | ||
397 | |||
398 | #include "qemu/osdep.h" | ||
399 | #include "qapi/qapi-types-net.h" | ||
400 | +#include "qapi/error.h" | ||
401 | #include "vmnet_int.h" | ||
402 | #include "clients.h" | ||
403 | -#include "qemu/error-report.h" | ||
404 | -#include "qapi/error.h" | ||
405 | |||
406 | #include <vmnet/vmnet.h> | ||
407 | |||
408 | + | ||
409 | +static bool validate_options(const Netdev *netdev, Error **errp) | ||
410 | +{ | ||
411 | + const NetdevVmnetSharedOptions *options = &(netdev->u.vmnet_shared); | ||
412 | + | ||
413 | +#if !defined(MAC_OS_VERSION_11_0) || \ | ||
414 | + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_11_0 | ||
415 | + if (options->has_isolated) { | ||
416 | + error_setg(errp, | ||
417 | + "vmnet-shared.isolated feature is " | ||
418 | + "unavailable: outdated vmnet.framework API"); | ||
419 | + return false; | ||
420 | + } | ||
421 | +#endif | ||
422 | + | ||
423 | + if ((options->has_start_address || | ||
424 | + options->has_end_address || | ||
425 | + options->has_subnet_mask) && | ||
426 | + !(options->has_start_address && | ||
427 | + options->has_end_address && | ||
428 | + options->has_subnet_mask)) { | ||
429 | + error_setg(errp, | ||
430 | + "'start-address', 'end-address', 'subnet-mask' " | ||
431 | + "should be provided together" | ||
432 | + ); | ||
433 | + return false; | ||
434 | + } | ||
435 | + | ||
436 | + return true; | ||
437 | +} | ||
438 | + | ||
439 | +static xpc_object_t build_if_desc(const Netdev *netdev) | ||
440 | +{ | ||
441 | + const NetdevVmnetSharedOptions *options = &(netdev->u.vmnet_shared); | ||
442 | + xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0); | ||
443 | + | ||
444 | + xpc_dictionary_set_uint64( | ||
445 | + if_desc, | ||
446 | + vmnet_operation_mode_key, | ||
447 | + VMNET_SHARED_MODE | ||
448 | + ); | ||
449 | + | ||
450 | + if (options->has_nat66_prefix) { | ||
451 | + xpc_dictionary_set_string(if_desc, | ||
452 | + vmnet_nat66_prefix_key, | ||
453 | + options->nat66_prefix); | ||
454 | + } | ||
455 | + | ||
456 | + if (options->has_start_address) { | ||
457 | + xpc_dictionary_set_string(if_desc, | ||
458 | + vmnet_start_address_key, | ||
459 | + options->start_address); | ||
460 | + xpc_dictionary_set_string(if_desc, | ||
461 | + vmnet_end_address_key, | ||
462 | + options->end_address); | ||
463 | + xpc_dictionary_set_string(if_desc, | ||
464 | + vmnet_subnet_mask_key, | ||
465 | + options->subnet_mask); | ||
466 | + } | ||
467 | + | ||
468 | +#if defined(MAC_OS_VERSION_11_0) && \ | ||
469 | + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 | ||
470 | + xpc_dictionary_set_bool( | ||
471 | + if_desc, | ||
472 | + vmnet_enable_isolation_key, | ||
473 | + options->isolated | ||
474 | + ); | ||
475 | +#endif | ||
476 | + | ||
477 | + return if_desc; | ||
478 | +} | ||
479 | + | ||
480 | +static NetClientInfo net_vmnet_shared_info = { | ||
481 | + .type = NET_CLIENT_DRIVER_VMNET_SHARED, | ||
482 | + .size = sizeof(VmnetState), | ||
483 | + .receive = vmnet_receive_common, | ||
484 | + .cleanup = vmnet_cleanup_common, | ||
485 | +}; | ||
486 | + | ||
487 | int net_init_vmnet_shared(const Netdev *netdev, const char *name, | ||
488 | NetClientState *peer, Error **errp) | ||
489 | { | ||
490 | - error_setg(errp, "vmnet-shared is not implemented yet"); | ||
491 | - return -1; | ||
492 | + NetClientState *nc = qemu_new_net_client(&net_vmnet_shared_info, | ||
493 | + peer, "vmnet-shared", name); | ||
494 | + xpc_object_t if_desc; | ||
495 | + int result = -1; | ||
496 | + | ||
497 | + if (!validate_options(netdev, errp)) { | ||
498 | + return result; | ||
499 | + } | ||
500 | + | ||
501 | + if_desc = build_if_desc(netdev); | ||
502 | + result = vmnet_if_create(nc, if_desc, errp); | ||
503 | + xpc_release(if_desc); | ||
504 | + return result; | ||
505 | } | ||
506 | diff --git a/net/vmnet_int.h b/net/vmnet_int.h | ||
507 | index XXXXXXX..XXXXXXX 100644 | ||
508 | --- a/net/vmnet_int.h | ||
509 | +++ b/net/vmnet_int.h | ||
510 | @@ -XXX,XX +XXX,XX @@ | ||
511 | #include "clients.h" | ||
512 | |||
513 | #include <vmnet/vmnet.h> | ||
514 | +#include <dispatch/dispatch.h> | ||
515 | + | ||
516 | +/** | ||
517 | + * From vmnet.framework documentation | ||
518 | + * | ||
519 | + * Each read/write call allows up to 200 packets to be | ||
520 | + * read or written for a maximum of 256KB. | ||
521 | + * | ||
522 | + * Each packet written should be a complete | ||
523 | + * ethernet frame. | ||
524 | + * | ||
525 | + * https://developer.apple.com/documentation/vmnet | ||
526 | + */ | ||
527 | +#define VMNET_PACKETS_LIMIT 200 | ||
528 | |||
529 | typedef struct VmnetState { | ||
530 | - NetClientState nc; | ||
531 | + NetClientState nc; | ||
532 | + interface_ref vmnet_if; | ||
533 | + | ||
534 | + uint64_t mtu; | ||
535 | + uint64_t max_packet_size; | ||
536 | |||
537 | + dispatch_queue_t if_queue; | ||
538 | + | ||
539 | + QEMUBH *send_bh; | ||
540 | + | ||
541 | + struct vmpktdesc packets_buf[VMNET_PACKETS_LIMIT]; | ||
542 | + int packets_send_current_pos; | ||
543 | + int packets_send_end_pos; | ||
544 | + | ||
545 | + struct iovec iov_buf[VMNET_PACKETS_LIMIT]; | ||
546 | } VmnetState; | ||
547 | |||
548 | +const char *vmnet_status_map_str(vmnet_return_t status); | ||
549 | + | ||
550 | +int vmnet_if_create(NetClientState *nc, | ||
551 | + xpc_object_t if_desc, | ||
552 | + Error **errp); | ||
553 | + | ||
554 | +ssize_t vmnet_receive_common(NetClientState *nc, | ||
555 | + const uint8_t *buf, | ||
556 | + size_t size); | ||
557 | + | ||
558 | +void vmnet_cleanup_common(NetClientState *nc); | ||
559 | |||
560 | #endif /* VMNET_INT_H */ | ||
39 | -- | 561 | -- |
40 | 2.7.4 | 562 | 2.25.1 |
41 | |||
42 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com> | ||
1 | 2 | ||
3 | Reviewed-by: Akihiko Odaki <akihiko.odaki@gmail.com> | ||
4 | Tested-by: Akihiko Odaki <akihiko.odaki@gmail.com> | ||
5 | Signed-off-by: Vladislav Yaroshchuk <Vladislav.Yaroshchuk@jetbrains.com> | ||
6 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
7 | --- | ||
8 | net/vmnet-host.c | 116 ++++++++++++++++++++++++++++++++++++++++++++--- | ||
9 | 1 file changed, 110 insertions(+), 6 deletions(-) | ||
10 | |||
11 | diff --git a/net/vmnet-host.c b/net/vmnet-host.c | ||
12 | index XXXXXXX..XXXXXXX 100644 | ||
13 | --- a/net/vmnet-host.c | ||
14 | +++ b/net/vmnet-host.c | ||
15 | @@ -XXX,XX +XXX,XX @@ | ||
16 | */ | ||
17 | |||
18 | #include "qemu/osdep.h" | ||
19 | +#include "qemu/uuid.h" | ||
20 | #include "qapi/qapi-types-net.h" | ||
21 | -#include "vmnet_int.h" | ||
22 | -#include "clients.h" | ||
23 | -#include "qemu/error-report.h" | ||
24 | #include "qapi/error.h" | ||
25 | +#include "clients.h" | ||
26 | +#include "vmnet_int.h" | ||
27 | |||
28 | #include <vmnet/vmnet.h> | ||
29 | |||
30 | + | ||
31 | +static bool validate_options(const Netdev *netdev, Error **errp) | ||
32 | +{ | ||
33 | + const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host); | ||
34 | + | ||
35 | +#if defined(MAC_OS_VERSION_11_0) && \ | ||
36 | + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 | ||
37 | + | ||
38 | + QemuUUID net_uuid; | ||
39 | + if (options->has_net_uuid && | ||
40 | + qemu_uuid_parse(options->net_uuid, &net_uuid) < 0) { | ||
41 | + error_setg(errp, "Invalid UUID provided in 'net-uuid'"); | ||
42 | + return false; | ||
43 | + } | ||
44 | +#else | ||
45 | + if (options->has_isolated) { | ||
46 | + error_setg(errp, | ||
47 | + "vmnet-host.isolated feature is " | ||
48 | + "unavailable: outdated vmnet.framework API"); | ||
49 | + return false; | ||
50 | + } | ||
51 | + | ||
52 | + if (options->has_net_uuid) { | ||
53 | + error_setg(errp, | ||
54 | + "vmnet-host.net-uuid feature is " | ||
55 | + "unavailable: outdated vmnet.framework API"); | ||
56 | + return false; | ||
57 | + } | ||
58 | +#endif | ||
59 | + | ||
60 | + if ((options->has_start_address || | ||
61 | + options->has_end_address || | ||
62 | + options->has_subnet_mask) && | ||
63 | + !(options->has_start_address && | ||
64 | + options->has_end_address && | ||
65 | + options->has_subnet_mask)) { | ||
66 | + error_setg(errp, | ||
67 | + "'start-address', 'end-address', 'subnet-mask' " | ||
68 | + "should be provided together"); | ||
69 | + return false; | ||
70 | + } | ||
71 | + | ||
72 | + return true; | ||
73 | +} | ||
74 | + | ||
75 | +static xpc_object_t build_if_desc(const Netdev *netdev) | ||
76 | +{ | ||
77 | + const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host); | ||
78 | + xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0); | ||
79 | + | ||
80 | + xpc_dictionary_set_uint64(if_desc, | ||
81 | + vmnet_operation_mode_key, | ||
82 | + VMNET_HOST_MODE); | ||
83 | + | ||
84 | +#if defined(MAC_OS_VERSION_11_0) && \ | ||
85 | + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 | ||
86 | + | ||
87 | + xpc_dictionary_set_bool(if_desc, | ||
88 | + vmnet_enable_isolation_key, | ||
89 | + options->isolated); | ||
90 | + | ||
91 | + QemuUUID net_uuid; | ||
92 | + if (options->has_net_uuid) { | ||
93 | + qemu_uuid_parse(options->net_uuid, &net_uuid); | ||
94 | + xpc_dictionary_set_uuid(if_desc, | ||
95 | + vmnet_network_identifier_key, | ||
96 | + net_uuid.data); | ||
97 | + } | ||
98 | +#endif | ||
99 | + | ||
100 | + if (options->has_start_address) { | ||
101 | + xpc_dictionary_set_string(if_desc, | ||
102 | + vmnet_start_address_key, | ||
103 | + options->start_address); | ||
104 | + xpc_dictionary_set_string(if_desc, | ||
105 | + vmnet_end_address_key, | ||
106 | + options->end_address); | ||
107 | + xpc_dictionary_set_string(if_desc, | ||
108 | + vmnet_subnet_mask_key, | ||
109 | + options->subnet_mask); | ||
110 | + } | ||
111 | + | ||
112 | + return if_desc; | ||
113 | +} | ||
114 | + | ||
115 | +static NetClientInfo net_vmnet_host_info = { | ||
116 | + .type = NET_CLIENT_DRIVER_VMNET_HOST, | ||
117 | + .size = sizeof(VmnetState), | ||
118 | + .receive = vmnet_receive_common, | ||
119 | + .cleanup = vmnet_cleanup_common, | ||
120 | +}; | ||
121 | + | ||
122 | int net_init_vmnet_host(const Netdev *netdev, const char *name, | ||
123 | - NetClientState *peer, Error **errp) { | ||
124 | - error_setg(errp, "vmnet-host is not implemented yet"); | ||
125 | - return -1; | ||
126 | + NetClientState *peer, Error **errp) | ||
127 | +{ | ||
128 | + NetClientState *nc = qemu_new_net_client(&net_vmnet_host_info, | ||
129 | + peer, "vmnet-host", name); | ||
130 | + xpc_object_t if_desc; | ||
131 | + int result = -1; | ||
132 | + | ||
133 | + if (!validate_options(netdev, errp)) { | ||
134 | + return result; | ||
135 | + } | ||
136 | + | ||
137 | + if_desc = build_if_desc(netdev); | ||
138 | + result = vmnet_if_create(nc, if_desc, errp); | ||
139 | + xpc_release(if_desc); | ||
140 | + return result; | ||
141 | } | ||
142 | -- | ||
143 | 2.25.1 | diff view generated by jsdifflib |
1 | From: Zhang Chen <zhangchen.fnst@cn.fujitsu.com> | 1 | From: Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com> |
---|---|---|---|
2 | 2 | ||
3 | Improve efficiency of TCP packet comparison. | 3 | Reviewed-by: Akihiko Odaki <akihiko.odaki@gmail.com> |
4 | 4 | Tested-by: Akihiko Odaki <akihiko.odaki@gmail.com> | |
5 | Signed-off-by: Zhang Chen <zhangchen.fnst@cn.fujitsu.com> | 5 | Signed-off-by: Vladislav Yaroshchuk <Vladislav.Yaroshchuk@jetbrains.com> |
6 | Signed-off-by: Li Zhijian <lizhijian@cn.fujitsu.com> | ||
7 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 6 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
8 | --- | 7 | --- |
9 | net/colo-compare.c | 19 +++++++++++++++++++ | 8 | net/vmnet-bridged.m | 137 ++++++++++++++++++++++++++++++++++++++++++-- |
10 | 1 file changed, 19 insertions(+) | 9 | 1 file changed, 132 insertions(+), 5 deletions(-) |
11 | 10 | ||
12 | diff --git a/net/colo-compare.c b/net/colo-compare.c | 11 | diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m |
13 | index XXXXXXX..XXXXXXX 100644 | 12 | index XXXXXXX..XXXXXXX 100644 |
14 | --- a/net/colo-compare.c | 13 | --- a/net/vmnet-bridged.m |
15 | +++ b/net/colo-compare.c | 14 | +++ b/net/vmnet-bridged.m |
16 | @@ -XXX,XX +XXX,XX @@ static int compare_chr_send(CharBackend *out, | 15 | @@ -XXX,XX +XXX,XX @@ |
17 | const uint8_t *buf, | 16 | |
18 | uint32_t size); | 17 | #include "qemu/osdep.h" |
19 | 18 | #include "qapi/qapi-types-net.h" | |
20 | +static gint seq_sorter(Packet *a, Packet *b, gpointer data) | 19 | -#include "vmnet_int.h" |
20 | -#include "clients.h" | ||
21 | -#include "qemu/error-report.h" | ||
22 | #include "qapi/error.h" | ||
23 | +#include "clients.h" | ||
24 | +#include "vmnet_int.h" | ||
25 | |||
26 | #include <vmnet/vmnet.h> | ||
27 | |||
28 | + | ||
29 | +static bool validate_ifname(const char *ifname) | ||
21 | +{ | 30 | +{ |
22 | + struct tcphdr *atcp, *btcp; | 31 | + xpc_object_t shared_if_list = vmnet_copy_shared_interface_list(); |
32 | + bool match = false; | ||
33 | + if (!xpc_array_get_count(shared_if_list)) { | ||
34 | + goto done; | ||
35 | + } | ||
23 | + | 36 | + |
24 | + atcp = (struct tcphdr *)(a->transport_header); | 37 | + match = !xpc_array_apply( |
25 | + btcp = (struct tcphdr *)(b->transport_header); | 38 | + shared_if_list, |
26 | + return ntohl(atcp->th_seq) - ntohl(btcp->th_seq); | 39 | + ^bool(size_t index, xpc_object_t value) { |
40 | + return strcmp(xpc_string_get_string_ptr(value), ifname) != 0; | ||
41 | + }); | ||
42 | + | ||
43 | +done: | ||
44 | + xpc_release(shared_if_list); | ||
45 | + return match; | ||
27 | +} | 46 | +} |
28 | + | 47 | + |
29 | /* | 48 | + |
30 | * Return 0 on success, if return -1 means the pkt | 49 | +static char* get_valid_ifnames() |
31 | * is unsupported(arp and ipv6) and will be sent later | 50 | +{ |
32 | @@ -XXX,XX +XXX,XX @@ static int packet_enqueue(CompareState *s, int mode) | 51 | + xpc_object_t shared_if_list = vmnet_copy_shared_interface_list(); |
33 | if (g_queue_get_length(&conn->primary_list) <= | 52 | + __block char *if_list = NULL; |
34 | MAX_QUEUE_SIZE) { | 53 | + __block char *if_list_prev = NULL; |
35 | g_queue_push_tail(&conn->primary_list, pkt); | 54 | + |
36 | + if (conn->ip_proto == IPPROTO_TCP) { | 55 | + if (!xpc_array_get_count(shared_if_list)) { |
37 | + g_queue_sort(&conn->primary_list, | 56 | + goto done; |
38 | + (GCompareDataFunc)seq_sorter, | 57 | + } |
39 | + NULL); | 58 | + |
40 | + } | 59 | + xpc_array_apply( |
41 | } else { | 60 | + shared_if_list, |
42 | error_report("colo compare primary queue size too big," | 61 | + ^bool(size_t index, xpc_object_t value) { |
43 | "drop packet"); | 62 | + /* build list of strings like "en0 en1 en2 " */ |
44 | @@ -XXX,XX +XXX,XX @@ static int packet_enqueue(CompareState *s, int mode) | 63 | + if_list = g_strconcat(xpc_string_get_string_ptr(value), |
45 | if (g_queue_get_length(&conn->secondary_list) <= | 64 | + " ", |
46 | MAX_QUEUE_SIZE) { | 65 | + if_list_prev, |
47 | g_queue_push_tail(&conn->secondary_list, pkt); | 66 | + NULL); |
48 | + if (conn->ip_proto == IPPROTO_TCP) { | 67 | + g_free(if_list_prev); |
49 | + g_queue_sort(&conn->secondary_list, | 68 | + if_list_prev = if_list; |
50 | + (GCompareDataFunc)seq_sorter, | 69 | + return true; |
51 | + NULL); | 70 | + }); |
52 | + } | 71 | + |
53 | } else { | 72 | +done: |
54 | error_report("colo compare secondary queue size too big," | 73 | + xpc_release(shared_if_list); |
55 | "drop packet"); | 74 | + return if_list; |
75 | +} | ||
76 | + | ||
77 | + | ||
78 | +static bool validate_options(const Netdev *netdev, Error **errp) | ||
79 | +{ | ||
80 | + const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged); | ||
81 | + char* if_list; | ||
82 | + | ||
83 | + if (!validate_ifname(options->ifname)) { | ||
84 | + if_list = get_valid_ifnames(); | ||
85 | + if (if_list) { | ||
86 | + error_setg(errp, | ||
87 | + "unsupported ifname '%s', expected one of [ %s]", | ||
88 | + options->ifname, | ||
89 | + if_list); | ||
90 | + g_free(if_list); | ||
91 | + } else { | ||
92 | + error_setg(errp, | ||
93 | + "unsupported ifname '%s', no supported " | ||
94 | + "interfaces available", | ||
95 | + options->ifname); | ||
96 | + } | ||
97 | + return false; | ||
98 | + } | ||
99 | + | ||
100 | +#if !defined(MAC_OS_VERSION_11_0) || \ | ||
101 | + MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_11_0 | ||
102 | + if (options->has_isolated) { | ||
103 | + error_setg(errp, | ||
104 | + "vmnet-bridged.isolated feature is " | ||
105 | + "unavailable: outdated vmnet.framework API"); | ||
106 | + return false; | ||
107 | + } | ||
108 | +#endif | ||
109 | + return true; | ||
110 | +} | ||
111 | + | ||
112 | + | ||
113 | +static xpc_object_t build_if_desc(const Netdev *netdev) | ||
114 | +{ | ||
115 | + const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged); | ||
116 | + xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0); | ||
117 | + | ||
118 | + xpc_dictionary_set_uint64(if_desc, | ||
119 | + vmnet_operation_mode_key, | ||
120 | + VMNET_BRIDGED_MODE | ||
121 | + ); | ||
122 | + | ||
123 | + xpc_dictionary_set_string(if_desc, | ||
124 | + vmnet_shared_interface_name_key, | ||
125 | + options->ifname); | ||
126 | + | ||
127 | +#if defined(MAC_OS_VERSION_11_0) && \ | ||
128 | + MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 | ||
129 | + xpc_dictionary_set_bool(if_desc, | ||
130 | + vmnet_enable_isolation_key, | ||
131 | + options->isolated); | ||
132 | +#endif | ||
133 | + return if_desc; | ||
134 | +} | ||
135 | + | ||
136 | + | ||
137 | +static NetClientInfo net_vmnet_bridged_info = { | ||
138 | + .type = NET_CLIENT_DRIVER_VMNET_BRIDGED, | ||
139 | + .size = sizeof(VmnetState), | ||
140 | + .receive = vmnet_receive_common, | ||
141 | + .cleanup = vmnet_cleanup_common, | ||
142 | +}; | ||
143 | + | ||
144 | + | ||
145 | int net_init_vmnet_bridged(const Netdev *netdev, const char *name, | ||
146 | NetClientState *peer, Error **errp) | ||
147 | { | ||
148 | - error_setg(errp, "vmnet-bridged is not implemented yet"); | ||
149 | - return -1; | ||
150 | + NetClientState *nc = qemu_new_net_client(&net_vmnet_bridged_info, | ||
151 | + peer, "vmnet-bridged", name); | ||
152 | + xpc_object_t if_desc; | ||
153 | + int result = -1; | ||
154 | + | ||
155 | + if (!validate_options(netdev, errp)) { | ||
156 | + return result; | ||
157 | + } | ||
158 | + | ||
159 | + if_desc = build_if_desc(netdev); | ||
160 | + result = vmnet_if_create(nc, if_desc, errp); | ||
161 | + xpc_release(if_desc); | ||
162 | + return result; | ||
163 | } | ||
56 | -- | 164 | -- |
57 | 2.7.4 | 165 | 2.25.1 |
58 | |||
59 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | From: Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com> | ||
1 | 2 | ||
3 | Update qemu-options.hx to support vmnet networking backend. | ||
4 | |||
5 | Reviewed-by: Akihiko Odaki <akihiko.odaki@gmail.com> | ||
6 | Tested-by: Akihiko Odaki <akihiko.odaki@gmail.com> | ||
7 | Signed-off-by: Vladislav Yaroshchuk <Vladislav.Yaroshchuk@jetbrains.com> | ||
8 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
9 | --- | ||
10 | qemu-options.hx | 25 +++++++++++++++++++++++++ | ||
11 | 1 file changed, 25 insertions(+) | ||
12 | |||
13 | diff --git a/qemu-options.hx b/qemu-options.hx | ||
14 | index XXXXXXX..XXXXXXX 100644 | ||
15 | --- a/qemu-options.hx | ||
16 | +++ b/qemu-options.hx | ||
17 | @@ -XXX,XX +XXX,XX @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, | ||
18 | #ifdef __linux__ | ||
19 | "-netdev vhost-vdpa,id=str,vhostdev=/path/to/dev\n" | ||
20 | " configure a vhost-vdpa network,Establish a vhost-vdpa netdev\n" | ||
21 | +#endif | ||
22 | +#ifdef CONFIG_VMNET | ||
23 | + "-netdev vmnet-host,id=str[,isolated=on|off][,net-uuid=uuid]\n" | ||
24 | + " [,start-address=addr,end-address=addr,subnet-mask=mask]\n" | ||
25 | + " configure a vmnet network backend in host mode with ID 'str',\n" | ||
26 | + " isolate this interface from others with 'isolated',\n" | ||
27 | + " configure the address range and choose a subnet mask,\n" | ||
28 | + " specify network UUID 'uuid' to disable DHCP and interact with\n" | ||
29 | + " vmnet-host interfaces within this isolated network\n" | ||
30 | + "-netdev vmnet-shared,id=str[,isolated=on|off][,nat66-prefix=addr]\n" | ||
31 | + " [,start-address=addr,end-address=addr,subnet-mask=mask]\n" | ||
32 | + " configure a vmnet network backend in shared mode with ID 'str',\n" | ||
33 | + " configure the address range and choose a subnet mask,\n" | ||
34 | + " set IPv6 ULA prefix (of length 64) to use for internal network,\n" | ||
35 | + " isolate this interface from others with 'isolated'\n" | ||
36 | + "-netdev vmnet-bridged,id=str,ifname=name[,isolated=on|off]\n" | ||
37 | + " configure a vmnet network backend in bridged mode with ID 'str',\n" | ||
38 | + " use 'ifname=name' to select a physical network interface to be bridged,\n" | ||
39 | + " isolate this interface from others with 'isolated'\n" | ||
40 | #endif | ||
41 | "-netdev hubport,id=str,hubid=n[,netdev=nd]\n" | ||
42 | " configure a hub port on the hub with ID 'n'\n", QEMU_ARCH_ALL) | ||
43 | @@ -XXX,XX +XXX,XX @@ DEF("nic", HAS_ARG, QEMU_OPTION_nic, | ||
44 | #endif | ||
45 | #ifdef CONFIG_POSIX | ||
46 | "vhost-user|" | ||
47 | +#endif | ||
48 | +#ifdef CONFIG_VMNET | ||
49 | + "vmnet-host|vmnet-shared|vmnet-bridged|" | ||
50 | #endif | ||
51 | "socket][,option][,...][mac=macaddr]\n" | ||
52 | " initialize an on-board / default host NIC (using MAC address\n" | ||
53 | @@ -XXX,XX +XXX,XX @@ DEF("net", HAS_ARG, QEMU_OPTION_net, | ||
54 | #endif | ||
55 | #ifdef CONFIG_NETMAP | ||
56 | "netmap|" | ||
57 | +#endif | ||
58 | +#ifdef CONFIG_VMNET | ||
59 | + "vmnet-host|vmnet-shared|vmnet-bridged|" | ||
60 | #endif | ||
61 | "socket][,option][,option][,...]\n" | ||
62 | " old way to initialize a host network interface\n" | ||
63 | -- | ||
64 | 2.25.1 | diff view generated by jsdifflib |
1 | From: Prasad J Pandit <pjp@fedoraproject.org> | 1 | From: Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com> |
---|---|---|---|
2 | 2 | ||
3 | i.MX Fast Ethernet Controller uses buffer descriptors to manage | 3 | Update HMP for supporting vmnet. |
4 | data flow to/fro receive & transmit queues. While transmitting | ||
5 | packets, it could continue to read buffer descriptors if a buffer | ||
6 | descriptor has length of zero and has crafted values in bd.flags. | ||
7 | Set an upper limit to number of buffer descriptors. | ||
8 | 4 | ||
9 | Reported-by: Li Qiang <liqiang6-s@360.cn> | 5 | Reviewed-by: Akihiko Odaki <akihiko.odaki@gmail.com> |
10 | Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> | 6 | Tested-by: Akihiko Odaki <akihiko.odaki@gmail.com> |
7 | Signed-off-by: Vladislav Yaroshchuk <Vladislav.Yaroshchuk@jetbrains.com> | ||
11 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 8 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
12 | --- | 9 | --- |
13 | hw/net/imx_fec.c | 10 ++++++---- | 10 | hmp-commands.hx | 6 +++++- |
14 | 1 file changed, 6 insertions(+), 4 deletions(-) | 11 | 1 file changed, 5 insertions(+), 1 deletion(-) |
15 | 12 | ||
16 | diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c | 13 | diff --git a/hmp-commands.hx b/hmp-commands.hx |
17 | index XXXXXXX..XXXXXXX 100644 | 14 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/hw/net/imx_fec.c | 15 | --- a/hmp-commands.hx |
19 | +++ b/hw/net/imx_fec.c | 16 | +++ b/hmp-commands.hx |
20 | @@ -XXX,XX +XXX,XX @@ | 17 | @@ -XXX,XX +XXX,XX @@ ERST |
21 | } \ | 18 | { |
22 | } while (0) | 19 | .name = "netdev_add", |
23 | 20 | .args_type = "netdev:O", | |
24 | +#define IMX_MAX_DESC 1024 | 21 | - .params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user],id=str[,prop=value][,...]", |
25 | + | 22 | + .params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user" |
26 | static const char *imx_default_reg_name(IMXFECState *s, uint32_t index) | 23 | +#ifdef CONFIG_VMNET |
27 | { | 24 | + "|vmnet-host|vmnet-shared|vmnet-bridged" |
28 | static char tmp[20]; | 25 | +#endif |
29 | @@ -XXX,XX +XXX,XX @@ static void imx_eth_update(IMXFECState *s) | 26 | + "],id=str[,prop=value][,...]", |
30 | 27 | .help = "add host network device", | |
31 | static void imx_fec_do_tx(IMXFECState *s) | 28 | .cmd = hmp_netdev_add, |
32 | { | 29 | .command_completion = netdev_add_completion, |
33 | - int frame_size = 0; | ||
34 | + int frame_size = 0, descnt = 0; | ||
35 | uint8_t frame[ENET_MAX_FRAME_SIZE]; | ||
36 | uint8_t *ptr = frame; | ||
37 | uint32_t addr = s->tx_descriptor; | ||
38 | |||
39 | - while (1) { | ||
40 | + while (descnt++ < IMX_MAX_DESC) { | ||
41 | IMXFECBufDesc bd; | ||
42 | int len; | ||
43 | |||
44 | @@ -XXX,XX +XXX,XX @@ static void imx_fec_do_tx(IMXFECState *s) | ||
45 | |||
46 | static void imx_enet_do_tx(IMXFECState *s) | ||
47 | { | ||
48 | - int frame_size = 0; | ||
49 | + int frame_size = 0, descnt = 0; | ||
50 | uint8_t frame[ENET_MAX_FRAME_SIZE]; | ||
51 | uint8_t *ptr = frame; | ||
52 | uint32_t addr = s->tx_descriptor; | ||
53 | |||
54 | - while (1) { | ||
55 | + while (descnt++ < IMX_MAX_DESC) { | ||
56 | IMXENETBufDesc bd; | ||
57 | int len; | ||
58 | |||
59 | -- | 30 | -- |
60 | 2.7.4 | 31 | 2.25.1 |
61 | |||
62 | diff view generated by jsdifflib |
1 | From: Paolo Bonzini <pbonzini@redhat.com> | 1 | From: Helge Deller <deller@gmx.de> |
---|---|---|---|
2 | 2 | ||
3 | Because is_first is declared inside a loop, it is always true. The store | 3 | The MAC of the tulip card is stored in the EEPROM and at startup |
4 | is dead, and so is the "else" branch of "if (is_first)". is_last is | 4 | tulip_fill_eeprom() is called to initialize the EEPROM with the MAC |
5 | okay though. | 5 | address given on the command line, e.g.: |
6 | -device tulip,mac=00:11:22:33:44:55 | ||
6 | 7 | ||
7 | Reported by Coverity. | 8 | In case the mac address was not given on the command line, |
9 | tulip_fill_eeprom() initializes the MAC in EEPROM with 00:00:00:00:00:00 | ||
10 | which breaks e.g. a HP-UX guest. | ||
8 | 11 | ||
9 | Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> | 12 | Fix this problem by moving qemu_macaddr_default_if_unset() a few lines |
10 | Reviewed-by: Dmitry Fleytman <dmitry@daynix.com> | 13 | up, so that a default mac address is assigned before tulip_fill_eeprom() |
14 | initializes the EEPROM. | ||
15 | |||
16 | Signed-off-by: Helge Deller <deller@gmx.de> | ||
17 | Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> | ||
11 | Signed-off-by: Jason Wang <jasowang@redhat.com> | 18 | Signed-off-by: Jason Wang <jasowang@redhat.com> |
12 | --- | 19 | --- |
13 | hw/net/e1000e_core.c | 2 +- | 20 | hw/net/tulip.c | 4 ++-- |
14 | 1 file changed, 1 insertion(+), 1 deletion(-) | 21 | 1 file changed, 2 insertions(+), 2 deletions(-) |
15 | 22 | ||
16 | diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c | 23 | diff --git a/hw/net/tulip.c b/hw/net/tulip.c |
17 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
18 | --- a/hw/net/e1000e_core.c | 25 | --- a/hw/net/tulip.c |
19 | +++ b/hw/net/e1000e_core.c | 26 | +++ b/hw/net/tulip.c |
20 | @@ -XXX,XX +XXX,XX @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt, | 27 | @@ -XXX,XX +XXX,XX @@ static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp) |
21 | const E1000E_RingInfo *rxi; | 28 | pci_conf = s->dev.config; |
22 | size_t ps_hdr_len = 0; | 29 | pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */ |
23 | bool do_ps = e1000e_do_ps(core, pkt, &ps_hdr_len); | 30 | |
24 | + bool is_first = true; | 31 | + qemu_macaddr_default_if_unset(&s->c.macaddr); |
25 | 32 | + | |
26 | rxi = rxr->i; | 33 | s->eeprom = eeprom93xx_new(&pci_dev->qdev, 64); |
27 | 34 | tulip_fill_eeprom(s); | |
28 | @@ -XXX,XX +XXX,XX @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt, | 35 | |
29 | hwaddr ba[MAX_PS_BUFFERS]; | 36 | @@ -XXX,XX +XXX,XX @@ static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp) |
30 | e1000e_ba_state bastate = { { 0 } }; | 37 | |
31 | bool is_last = false; | 38 | s->irq = pci_allocate_irq(&s->dev); |
32 | - bool is_first = true; | 39 | |
33 | 40 | - qemu_macaddr_default_if_unset(&s->c.macaddr); | |
34 | desc_size = total_size - desc_offset; | 41 | - |
35 | 42 | s->nic = qemu_new_nic(&net_tulip_info, &s->c, | |
43 | object_get_typename(OBJECT(pci_dev)), | ||
44 | pci_dev->qdev.id, s); | ||
36 | -- | 45 | -- |
37 | 2.7.4 | 46 | 2.25.1 |
38 | 47 | ||
39 | 48 | diff view generated by jsdifflib |