perl-540: update to 5.40.1
[oi-userland.git] / components / sysutils / qemu / patches / 0009-Add-support-for-VNICs.patch
blobc49a1f3116194e7ca98582b14b752f83f12f7fa6
1 From 99d2ece8b1f49686077959eec1fd0d66acbfc99d Mon Sep 17 00:00:00 2001
2 From: Andy Fiddaman <illumos@fiddaman.net>
3 Date: Mon, 28 Nov 2022 14:51:42 +0000
4 Subject: Add support for VNICs
6 This work originated in SmartOS as part of
7 https://github.com/TritonDataCenter/illumos-kvm-cmd
8 ---
9 meson.build | 3 +-
10 net/clients.h | 2 +
11 net/hub.c | 1 +
12 net/meson.build | 1 +
13 net/net.c | 1 +
14 net/vnic.c | 274 ++++++++++++++++++++++++++++++++++++++++++++++++
15 qapi/net.json | 14 ++-
16 7 files changed, 294 insertions(+), 2 deletions(-)
17 create mode 100644 net/vnic.c
19 diff --git a/meson.build b/meson.build
20 index 5c6b5a1c75..9343d7fc2f 100644
21 --- a/meson.build
22 +++ b/meson.build
23 @@ -407,7 +407,8 @@ elif targetos == 'darwin'
24 elif targetos == 'sunos'
25 socket = [cc.find_library('socket'),
26 cc.find_library('nsl'),
27 - cc.find_library('resolv')]
28 + cc.find_library('resolv'),
29 + cc.find_library('dlpi')]
30 elif targetos == 'haiku'
31 socket = [cc.find_library('posix_error_mapper'),
32 cc.find_library('network'),
33 diff --git a/net/clients.h b/net/clients.h
34 index ed8bdfff1e..b4b376819b 100644
35 --- a/net/clients.h
36 +++ b/net/clients.h
37 @@ -58,6 +58,8 @@ int net_init_l2tpv3(const Netdev *netdev, const char *name,
38 int net_init_vde(const Netdev *netdev, const char *name,
39 NetClientState *peer, Error **errp);
40 #endif
41 +int net_init_vnic(const Netdev *netdev, const char *name,
42 + NetClientState *peer, Error **errp);
44 #ifdef CONFIG_NETMAP
45 int net_init_netmap(const Netdev *netdev, const char *name,
46 diff --git a/net/hub.c b/net/hub.c
47 index 67ca534856..a5f73ef0a5 100644
48 --- a/net/hub.c
49 +++ b/net/hub.c
50 @@ -316,6 +316,7 @@ void net_hub_check_clients(void)
51 case NET_CLIENT_DRIVER_STREAM:
52 case NET_CLIENT_DRIVER_DGRAM:
53 case NET_CLIENT_DRIVER_VDE:
54 + case NET_CLIENT_DRIVER_VNIC:
55 case NET_CLIENT_DRIVER_VHOST_USER:
56 has_host_dev = 1;
57 break;
58 diff --git a/net/meson.build b/net/meson.build
59 index 6cd1e3dab3..48001067b3 100644
60 --- a/net/meson.build
61 +++ b/net/meson.build
62 @@ -36,6 +36,7 @@ endif
63 softmmu_ss.add(when: 'CONFIG_LINUX', if_true: files('tap-linux.c'))
64 softmmu_ss.add(when: 'CONFIG_BSD', if_true: files('tap-bsd.c'))
65 softmmu_ss.add(when: 'CONFIG_SOLARIS', if_true: files('tap-solaris.c'))
66 +softmmu_ss.add(when: 'CONFIG_SOLARIS', if_true: files('vnic.c'))
67 tap_posix = ['tap.c']
68 if not config_host.has_key('CONFIG_LINUX') and not config_host.has_key('CONFIG_BSD') and not config_host.has_key('CONFIG_SOLARIS')
69 tap_posix += 'tap-stub.c'
70 diff --git a/net/net.c b/net/net.c
71 index 840ad9dca5..3cf376d432 100644
72 --- a/net/net.c
73 +++ b/net/net.c
74 @@ -1027,6 +1027,7 @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
75 #ifdef CONFIG_VDE
76 [NET_CLIENT_DRIVER_VDE] = net_init_vde,
77 #endif
78 + [NET_CLIENT_DRIVER_VNIC] = net_init_vnic,
79 #ifdef CONFIG_NETMAP
80 [NET_CLIENT_DRIVER_NETMAP] = net_init_netmap,
81 #endif
82 diff --git a/net/vnic.c b/net/vnic.c
83 new file mode 100644
84 index 0000000000..481661b583
85 --- /dev/null
86 +++ b/net/vnic.c
87 @@ -0,0 +1,274 @@
88 +/*
89 + * QEMU System Emulator Solaris VNIC support
90 + *
91 + * Copyright 2016 Joyent, Inc.
92 + *
93 + * Permission is hereby granted, free of charge, to any person obtaining a
94 + * copy of this software and associated documentation files (the
95 + * "Software"), to deal in the Software without restriction, including
96 + * without limitation the rights to use, copy, modify, merge, publish,
97 + * distribute, sublicense, and/or sell copies of the Software, and to
98 + * permit persons to whom the Software is furnished to do so, subject to
99 + * the following conditions:
101 + * The above copyright notice and this permission notice shall be included
102 + * in all copies or substantial portions of the Software.
104 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
105 + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
106 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
107 + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
108 + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
109 + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
110 + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
111 + */
113 +#include "qemu/osdep.h"
114 +#include "tap_int.h"
115 +#include "qemu/ctype.h"
116 +#include "qemu/cutils.h"
118 +#include <fcntl.h>
119 +#include <libdlpi.h>
120 +#include <stdbool.h>
121 +#include <sys/dlpi.h>
122 +#include <sys/ethernet.h>
123 +#include <sys/stat.h>
124 +#include <sys/types.h>
125 +#include <stropts.h>
127 +#include "net/net.h"
128 +#include "clients.h"
129 +#include "qemu/option.h"
130 +#include "qemu/main-loop.h"
131 +#include "qemu/error-report.h"
133 +#define VNIC_BUFSIZE 65536
135 +typedef struct VNICState {
136 + NetClientState vns_nc;
137 + int vns_fd;
138 + bool vns_rpoll;
139 + bool vns_wpoll;
140 + uint8_t vns_buf[VNIC_BUFSIZE];
141 + uint_t vns_sap;
142 + dlpi_handle_t vns_hdl;
143 +} VNICState;
145 +static void vnic_update_fd_handler(VNICState *);
147 +static void
148 +vnic_read_poll(VNICState *vsp, bool enable)
150 + vsp->vns_rpoll = enable;
151 + vnic_update_fd_handler(vsp);
154 +static void
155 +vnic_write_poll(VNICState *vsp, bool enable)
157 + vsp->vns_wpoll = enable;
158 + vnic_update_fd_handler(vsp);
161 +static void
162 +vnic_poll(NetClientState *ncp, bool enable)
164 + VNICState *vsp = DO_UPCAST(VNICState, vns_nc, ncp);
165 + vnic_read_poll(vsp, true);
166 + vnic_write_poll(vsp, true);
169 +static int
170 +vnic_read_packet(VNICState *vsp, uint8_t *buf, int len)
172 + struct strbuf sbuf;
173 + int flags, ret;
175 + flags = 0;
176 + sbuf.maxlen = len;
177 + sbuf.buf = (char *)buf;
179 + do {
180 + ret = getmsg(vsp->vns_fd, NULL, &sbuf, &flags);
181 + } while (ret == -1 && errno == EINTR);
183 + if (ret == -1 && errno == EAGAIN) {
184 + vnic_write_poll(vsp, true);
185 + return (0);
188 + if (ret == -1)
189 + return (-1);
191 + return (sbuf.len);
194 +static int
195 +vnic_write_packet(VNICState *vsp, const uint8_t *buf, int len)
197 + struct strbuf sbuf;
198 + int flags, ret;
200 + flags = 0;
201 + sbuf.len = len;
202 + sbuf.buf = (char *)buf;
204 + do {
205 + ret = putmsg(vsp->vns_fd, NULL, &sbuf, flags);
206 + } while (ret == -1 && errno == EINTR);
208 + if (ret == -1 && errno == EAGAIN) {
209 + vnic_write_poll(vsp, true);
210 + return (0);
213 + if (ret == -1)
214 + return (-1);
216 + return (len);
219 +static void
220 +vnic_send_completed(NetClientState *nc, ssize_t len)
222 + VNICState *vsp = DO_UPCAST(VNICState, vns_nc, nc);
224 + vnic_read_poll(vsp, true);
227 +/* outside world -> VM */
228 +static void
229 +vnic_send(void *opaque)
231 + VNICState *vsp = opaque;
232 + int ret;
234 + do {
235 + ret = vnic_read_packet(vsp, vsp->vns_buf,
236 + sizeof (vsp->vns_buf));
237 + if (ret <= 0)
238 + break;
240 + ret = qemu_send_packet_async(&vsp->vns_nc, vsp->vns_buf, ret,
241 + vnic_send_completed);
243 + if (ret == 0)
244 + vnic_read_poll(vsp, false);
246 + } while (ret > 0 && qemu_can_send_packet(&vsp->vns_nc));
249 +static void
250 +vnic_writable(void *opaque)
252 + VNICState *vsp = opaque;
253 + vnic_write_poll(vsp, false);
254 + qemu_flush_queued_packets(&vsp->vns_nc);
257 +/* VM -> outside world */
258 +static ssize_t
259 +vnic_receive(NetClientState *ncp, const uint8_t *buf, size_t size)
261 + VNICState *vsp = DO_UPCAST(VNICState, vns_nc, ncp);
263 + return (vnic_write_packet(vsp, buf, size));
267 +static void
268 +vnic_cleanup(NetClientState *ncp)
270 + VNICState *vsp = DO_UPCAST(VNICState, vns_nc, ncp);
272 + qemu_purge_queued_packets(ncp);
274 + dlpi_close(vsp->vns_hdl);
277 +static void
278 +vnic_update_fd_handler(VNICState *vsp)
280 + qemu_set_fd_handler(vsp->vns_fd,
281 + vsp->vns_rpoll ? vnic_send : NULL,
282 + vsp->vns_wpoll ? vnic_writable : NULL,
283 + vsp);
286 +static NetClientInfo net_vnic_info = {
287 + .type = NET_CLIENT_DRIVER_VNIC,
288 + .size = sizeof(VNICState),
289 + .receive = vnic_receive,
290 + .poll = vnic_poll,
291 + .cleanup = vnic_cleanup,
294 +int net_init_vnic(const Netdev *netdev, const char *name,
295 + NetClientState *peer, Error **errp)
297 + const NetdevVNICOptions *vnic;
298 + NetClientState *ncp;
299 + VNICState *vsp;
300 + int fd, ret;
302 + assert(netdev->type == NET_CLIENT_DRIVER_VNIC);
303 + vnic = &netdev->u.vnic;
305 + ncp = qemu_new_net_client(&net_vnic_info, peer, "vnic", name);
306 + vsp = DO_UPCAST(VNICState, vns_nc, ncp);
308 + ret = dlpi_open(vnic->ifname, &vsp->vns_hdl, DLPI_RAW);
309 + if (ret != DLPI_SUCCESS) {
310 + error_report("vnic: failed to open interface %s, err %d",
311 + vnic->ifname, ret);
312 + return (-1);
315 + ret = dlpi_bind(vsp->vns_hdl, DLPI_ANY_SAP, &vsp->vns_sap);
316 + if (ret != DLPI_SUCCESS) {
317 + error_report("vnic: failed to bind interface %s, err %d",
318 + vnic->ifname, ret);
319 + return (-1);
322 + /*
323 + * We are enabling support for two different kinds of promiscuous modes.
324 + * The first is getting us the basics of the unicast traffic that we
325 + * care about. The latter is going to ensure that we also get other
326 + * types of physical traffic such as multicast and broadcast.
327 + */
328 + ret = dlpi_promiscon(vsp->vns_hdl, DL_PROMISC_SAP);
329 + if (ret != DLPI_SUCCESS) {
330 + error_report(
331 + "vnic: failed to be promiscous with interface %s, err %d",
332 + vnic->ifname, ret);
333 + return (-1);
336 + ret = dlpi_promiscon(vsp->vns_hdl, DL_PROMISC_PHYS);
337 + if (ret != DLPI_SUCCESS) {
338 + error_report(
339 + "vnic: failed to be promiscous with interface %s, err %d",
340 + vnic-> ifname, ret);
341 + return (-1);
344 + fd = dlpi_fd(vsp->vns_hdl);
346 + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
347 + error_report("vnic: failed to set fd on interface %s to "
348 + "non-blocking: %s", vnic->ifname, strerror(errno));
349 + return (-1);
352 + vsp->vns_fd = fd;
354 + snprintf(vsp->vns_nc.info_str, sizeof (vsp->vns_nc.info_str),
355 + "ifname=%s", vnic->ifname);
357 + /* We have to manually intialize the polling for read */
358 + vnic_read_poll(vsp, true);
360 + return (0);
362 diff --git a/qapi/net.json b/qapi/net.json
363 index 522ac582ed..30ce9233b4 100644
364 --- a/qapi/net.json
365 +++ b/qapi/net.json
366 @@ -360,6 +360,17 @@
367 '*group': 'str',
368 '*mode': 'uint16' } }
371 +# @NetdevVNICOptions:
373 +# Connect to a VNIC on the host.
375 +# @ifname: VNIC interface name
377 +{ 'struct': 'NetdevVNICOptions',
378 + 'data': {
379 + 'ifname': 'str' } }
382 # @NetdevBridgeOptions:
384 @@ -648,7 +659,7 @@
385 { 'enum': 'NetClientDriver',
386 'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'stream',
387 'dgram', 'vde', 'bridge', 'hubport', 'netmap', 'vhost-user',
388 - 'vhost-vdpa',
389 + 'vhost-vdpa', 'vnic',
390 { 'name': 'vmnet-host', 'if': 'CONFIG_VMNET' },
391 { 'name': 'vmnet-shared', 'if': 'CONFIG_VMNET' },
392 { 'name': 'vmnet-bridged', 'if': 'CONFIG_VMNET' }] }
393 @@ -683,6 +694,7 @@
394 'stream': 'NetdevStreamOptions',
395 'dgram': 'NetdevDgramOptions',
396 'vde': 'NetdevVdeOptions',
397 + 'vnic': 'NetdevVNICOptions',
398 'bridge': 'NetdevBridgeOptions',
399 'hubport': 'NetdevHubPortOptions',
400 'netmap': 'NetdevNetmapOptions',