[PATCH v10] isa-applesmc: provide OSK forwarding on Apple hosts

2022-04-29 Thread Vladislav Yaroshchuk
On Apple hosts we can read AppleSMC OSK key directly from host's
SMC and forward this value to QEMU Guest.

New 'hostosk' property is added:
* `-device isa-applesmc,hostosk=on`
The property is set to 'on' by default for machine version > 7.0

Apple licence allows use and run up to two additional copies
or instances of macOS operating system within virtual operating system
environments on each Apple-branded computer that is already running
the Apple Software, for purposes of:
 * software development
 * testing during software development
 * using macOS Server
 * personal, non-commercial use

Guest macOS requires AppleSMC with correct OSK. The most legal
way to pass it to the Guest is to forward the key from host SMC
without any value exposion.

Based on 
https://web.archive.org/web/20200103161737/osxbook.com/book/bonus/chapter7/tpmdrmmyth/

Signed-off-by: Vladislav Yaroshchuk 
---
 hw/core/machine.c  |   4 +-
 hw/misc/applesmc.c | 125 +++--
 2 files changed, 125 insertions(+), 4 deletions(-)

diff --git a/hw/core/machine.c b/hw/core/machine.c
index cb9bbc844d..7f4a27406a 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -37,7 +37,9 @@
 #include "hw/virtio/virtio.h"
 #include "hw/virtio/virtio-pci.h"
 
-GlobalProperty hw_compat_7_0[] = {};
+GlobalProperty hw_compat_7_0[] = {
+{ "isa-applesmc", "hostosk", "off" }
+};
 const size_t hw_compat_7_0_len = G_N_ELEMENTS(hw_compat_7_0);
 
 GlobalProperty hw_compat_6_2[] = {
diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c
index 81cd6b6423..8672c9d56e 100644
--- a/hw/misc/applesmc.c
+++ b/hw/misc/applesmc.c
@@ -37,6 +37,11 @@
 #include "qemu/module.h"
 #include "qemu/timer.h"
 #include "qom/object.h"
+#include "qapi/error.h"
+
+#if defined(__APPLE__) && defined(__MACH__)
+#include 
+#endif
 
 /* #define DEBUG_SMC */
 
@@ -80,7 +85,7 @@ enum {
 #define smc_debug(...) do { } while (0)
 #endif
 
-static char default_osk[64] = "This is a dummy key. Enter the real key "
+static char default_osk[65] = "This is a dummy key. Enter the real key "
   "using the -osk parameter";
 
 struct AppleSMCData {
@@ -109,6 +114,7 @@ struct AppleSMCState {
 uint8_t data_pos;
 uint8_t data[255];
 char *osk;
+bool hostosk;
 QLIST_HEAD(, AppleSMCData) data_def;
 };
 
@@ -312,6 +318,101 @@ static const MemoryRegionOps applesmc_err_io_ops = {
 },
 };
 
+#if defined(__APPLE__) && defined(__MACH__)
+/*
+ * Based on
+ * 
https://web.archive.org/web/20200103161737/osxbook.com/book/bonus/chapter7/tpmdrmmyth/
+ */
+enum {
+SMC_HANDLE_EVENT = 2,
+SMC_READ_KEY = 5
+};
+
+struct AppleSMCParam {
+uint32_t key;
+uint8_t pad0[22];
+IOByteCount data_size;
+uint8_t pad1[10];
+uint8_t command;
+uint32_t pad2;
+uint8_t bytes[32];
+};
+
+static bool applesmc_read_host_osk(char *host_osk, Error **errp)
+{
+assert(host_osk != NULL);
+
+io_service_t hostsmc_service = IO_OBJECT_NULL;
+io_connect_t hostsmc_connect = IO_OBJECT_NULL;
+size_t smc_param_size = sizeof(struct AppleSMCParam);
+IOReturn status = kIOReturnError;
+int i;
+
+struct AppleSMCParam smc_param[2] = {
+ {
+ .key = ('OSK0'),
+ .data_size = sizeof(smc_param[0].bytes),
+ .command = SMC_READ_KEY,
+ }, {
+ .key = ('OSK1'),
+ .data_size = sizeof(smc_param[0].bytes),
+ .command = SMC_READ_KEY,
+ },
+};
+
+hostsmc_service = IOServiceGetMatchingService(
+kIOMasterPortDefault,
+IOServiceMatching("AppleSMC"));
+if (hostsmc_service == IO_OBJECT_NULL) {
+error_setg(errp, "Unable to get host-AppleSMC service");
+goto error;
+}
+
+status = IOServiceOpen(hostsmc_service,
+   mach_task_self(),
+   0,
+   _connect);
+if (status != kIOReturnSuccess || hostsmc_connect == IO_OBJECT_NULL) {
+error_setg(errp, "Unable to open host-AppleSMC service");
+goto error;
+}
+
+for (i = 0; i < ARRAY_SIZE(smc_param); ++i) {
+status = IOConnectCallStructMethod(
+hostsmc_connect,
+SMC_HANDLE_EVENT,
+_param[i],
+sizeof(struct AppleSMCParam),
+_param[i],
+_param_size
+);
+
+if (status != kIOReturnSuccess) {
+error_setg(errp, "Unable to read OSK from host-AppleSMC");
+goto error;
+}
+}
+
+memcpy(host_osk, smc_param[0].bytes, 32);
+memcpy(host_osk + 32, smc_param[1].bytes, 32);
+
+IOServiceClose(hostsmc_connect);
+IOObjectRelease(hostsmc_service);
+return true;
+
+error:
+IOServiceClose(host

[PATCH v9] isa-applesmc: provide OSK forwarding on Apple hosts

2022-04-29 Thread Vladislav Yaroshchuk
On Apple hosts we can read AppleSMC OSK key directly from host's
SMC and forward this value to QEMU Guest.

New 'hostosk' property is added:
* `-device isa-applesmc,hostosk=on`
The property is set to 'on' by default for machine version > 6.2

Apple licence allows use and run up to two additional copies
or instances of macOS operating system within virtual operating system
environments on each Apple-branded computer that is already running
the Apple Software, for purposes of:
 * software development
 * testing during software development
 * using macOS Server
 * personal, non-commercial use

Guest macOS requires AppleSMC with correct OSK. The most legal
way to pass it to the Guest is to forward the key from host SMC
without any value exposion.

Based on 
https://web.archive.org/web/20200103161737/osxbook.com/book/bonus/chapter7/tpmdrmmyth/

Signed-off-by: Vladislav Yaroshchuk 
---
 hw/core/machine.c  |   4 +-
 hw/misc/applesmc.c | 127 +++--
 2 files changed, 126 insertions(+), 5 deletions(-)

diff --git a/hw/core/machine.c b/hw/core/machine.c
index cb9bbc844d..7f4a27406a 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -37,7 +37,9 @@
 #include "hw/virtio/virtio.h"
 #include "hw/virtio/virtio-pci.h"
 
-GlobalProperty hw_compat_7_0[] = {};
+GlobalProperty hw_compat_7_0[] = {
+{ "isa-applesmc", "hostosk", "off" }
+};
 const size_t hw_compat_7_0_len = G_N_ELEMENTS(hw_compat_7_0);
 
 GlobalProperty hw_compat_6_2[] = {
diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c
index 81cd6b6423..99bcc937f9 100644
--- a/hw/misc/applesmc.c
+++ b/hw/misc/applesmc.c
@@ -37,6 +37,11 @@
 #include "qemu/module.h"
 #include "qemu/timer.h"
 #include "qom/object.h"
+#include "qapi/error.h"
+
+#if defined(__APPLE__) && defined(__MACH__)
+#include 
+#endif
 
 /* #define DEBUG_SMC */
 
@@ -80,7 +85,7 @@ enum {
 #define smc_debug(...) do { } while (0)
 #endif
 
-static char default_osk[64] = "This is a dummy key. Enter the real key "
+static char default_osk[65] = "This is a dummy key. Enter the real key "
   "using the -osk parameter";
 
 struct AppleSMCData {
@@ -109,6 +114,7 @@ struct AppleSMCState {
 uint8_t data_pos;
 uint8_t data[255];
 char *osk;
+bool hostosk;
 QLIST_HEAD(, AppleSMCData) data_def;
 };
 
@@ -253,7 +259,7 @@ static void applesmc_add_key(AppleSMCState *s, const char 
*key,
 {
 struct AppleSMCData *def;
 
-def = g_new0(struct AppleSMCData, 1);
+def = g_malloc0(sizeof(struct AppleSMCData));
 def->key = key;
 def->len = len;
 def->data = data;
@@ -312,6 +318,101 @@ static const MemoryRegionOps applesmc_err_io_ops = {
 },
 };
 
+#if defined(__APPLE__) && defined(__MACH__)
+/*
+ * Based on
+ * 
https://web.archive.org/web/20200103161737/osxbook.com/book/bonus/chapter7/tpmdrmmyth/
+ */
+enum {
+SMC_HANDLE_EVENT = 2,
+SMC_READ_KEY = 5
+};
+
+struct AppleSMCParam {
+uint32_t key;
+uint8_t pad0[22];
+IOByteCount data_size;
+uint8_t pad1[10];
+uint8_t command;
+uint32_t pad2;
+uint8_t bytes[32];
+};
+
+static bool applesmc_read_host_osk(char *host_osk, Error **errp)
+{
+assert(host_osk != NULL);
+
+io_service_t hostsmc_service = IO_OBJECT_NULL;
+io_connect_t hostsmc_connect = IO_OBJECT_NULL;
+size_t smc_param_size = sizeof(struct AppleSMCParam);
+IOReturn status = kIOReturnError;
+int i;
+
+struct AppleSMCParam smc_param[2] = {
+ {
+ .key = ('OSK0'),
+ .data_size = sizeof(smc_param[0].bytes),
+ .command = SMC_READ_KEY,
+ }, {
+ .key = ('OSK1'),
+ .data_size = sizeof(smc_param[0].bytes),
+ .command = SMC_READ_KEY,
+ },
+};
+
+hostsmc_service = IOServiceGetMatchingService(
+kIOMasterPortDefault,
+IOServiceMatching("AppleSMC"));
+if (hostsmc_service == IO_OBJECT_NULL) {
+error_setg(errp, "Unable to get host-AppleSMC service");
+goto error;
+}
+
+status = IOServiceOpen(hostsmc_service,
+   mach_task_self(),
+   0,
+   _connect);
+if (status != kIOReturnSuccess || hostsmc_connect == IO_OBJECT_NULL) {
+error_setg(errp, "Unable to open host-AppleSMC service");
+goto error;
+}
+
+for (i = 0; i < ARRAY_SIZE(smc_param); ++i) {
+status = IOConnectCallStructMethod(
+hostsmc_connect,
+SMC_HANDLE_EVENT,
+_param[i],
+sizeof(struct AppleSMCParam),
+_param[i],
+_param_size
+);
+
+if (status != kIOReturnSuccess) {
+error_setg(errp, "Unable to read OSK from host-AppleSM

Re: [PATCH v3] hw/misc: applesmc: use host osk as default on macs

2022-04-21 Thread Vladislav Yaroshchuk
Hi, Daniel!

Ok, thank you - then I'll wait until compat machines
for 7.1 are added (after release) and send a new
patch.

Regards,
Vladislav

вт, 19 апр. 2022 г. в 19:03, Daniel P. Berrangé :

> On Sun, Apr 17, 2022 at 04:43:14PM +0300, Vladislav Yaroshchuk wrote:
> > I've CCed all the people from previous threads.
> >
> >
> > > [...]
> > > +static bool applesmc_read_osk(uint8_t *osk)
> > > +{
> > > +#if defined(__APPLE__) && defined(__MACH__)
> > > +struct AppleSMCParams {
> > > +uint32_t key;
> > > +uint8_t __pad0[16];
> > > +uint8_t result;
> > > +uint8_t __pad1[7];
> > > +uint32_t size;
> > > +uint8_t __pad2[10];
> > > +uint8_t data8;
> > > +uint8_t __pad3[5];
> > > +uint8_t output[32];
> > > +};
> > > +
> > > +io_service_t svc;
> > > +io_connect_t conn;
> > > +kern_return_t ret;
> > > +size_t size = sizeof(struct AppleSMCParams);
> > > +struct AppleSMCParams params_in = { .size = 32, .data8 = 5 };
> >
> > Maybe it's better to name this magic number '5'
> >
> > > +struct AppleSMCParams params_out = {};
> > > +
> >
> > params_in and params_out can be the same variable, see
> >
> https://patchew.org/QEMU/20211022161448.81579-1-yaroshchuk2...@gmail.com/
> >
> > > +svc = IOServiceGetMatchingService(0,
> IOServiceMatching("AppleSMC"));
> > > +if (svc == 0) {
> > > +return false;
> > > +}
> > > +
> > > +ret = IOServiceOpen(svc, mach_task_self(), 0, );
> > > +if (ret != 0) {
> > > +return false;
> > > +}
> > > +
> > > +for (params_in.key = 'OSK0'; params_in.key <= 'OSK1';
> > ++params_in.key) {
> > > +ret = IOConnectCallStructMethod(conn, 2, _in, size,
> > _out, );
> >
> > Same about this magic number '2'.
> >
> > > +if (ret != 0) {
> > > +return false;
> > > +}
> > > +
> > > +if (params_out.result != 0) {
> > > +return false;
> > > +}
> > > +memcpy(osk, params_out.output, params_in.size);
> > > +
> > > +osk += params_in.size;
> > > + }
> > > +
> >
> > Cleanup IOServiceClose and IOObjectReturn are not called at the
> > end of the procedure.
> >
> > This is also mentioned in Phil Dennis-Jordan's instruction you noted
> (stage
> > 5):
> > https://lists.nongnu.org/archive/html/qemu-devel/2021-10/msg02843.html
> >
> > > +return true;
> > > +#else
> > > +return false;
> > > +#endif
> > > +}
> > > +
> > > [...]
> > >
> > > static void applesmc_isa_realize(DeviceState *dev, Error **errp)
> > >  {
> > >  AppleSMCState *s = APPLE_SMC(dev);
> > > +bool valid_osk = false;
> > >
> > >  memory_region_init_io(>io_data, OBJECT(s),
> _data_io_ops,
> > s,
> > >"applesmc-data", 1);
> > > @@ -331,8 +393,17 @@ static void applesmc_isa_realize(DeviceState *dev,
> > Error **errp)
> > >  isa_register_ioport(>parent_obj, >io_err,
> > >  s->iobase + APPLESMC_ERR_PORT);
> > >
> > > -if (!s->osk || (strlen(s->osk) != 64)) {
> > > -warn_report("Using AppleSMC with invalid key");
> > > +if (s->osk) {
> > > +valid_osk = strlen(s->osk) == 64;
> > > +} else {
> > > +valid_osk = applesmc_read_osk((uint8_t *) default_osk);
> > > +if (valid_osk) {
> > > +warn_report("Using AppleSMC with host OSK");
> > > +s->osk = default_osk;
> > > +}
> > > +}
> > > +if (!valid_osk) {
> > > +warn_report("Using AppleSMC with invalid OSK");
> > >  s->osk = default_osk;
> > >  }
> > > [...]
> >
> > After the previous discussion we've decided (if i don't confuse anything)
> > to have a way to enable/disable host OSK reading with new property:
> > 1. properties osk=$key and hostosk=on cannot be used together (fail hard)
> > 2. for QEMU machine > 7.0 - hostosk=on by default.
> > If unable to read - fail hard with error_setg.
> > 3. for QEMU machine <= 7.0 - hostosk=off by default,
> >the dummy OSK is used (as previously).
> >
> > BTW since my patches lost 7.0, I planned to wait until compat machines
> > for 7.1 are added (after 7.0 release) and then rebase the patches,
> > adding required changes into `hw/core/machine.c`
> >
> > Now we have two versions of host OSK forwarding implementations,
> > Pedro's (this one) and mine (
> >
> https://patchew.org/QEMU/20220113152836.60398-1-yaroshchuk2...@gmail.com/#
> )
> >
> > Do we still want to add this feature? If yes - whose version is
> preferred?
> > (I'm still ready to work on this)
>
> I prefer yours, since the feature is introspectable by mgmt apps,
> given the existance of the 'hostosk' property
>
> With regards,
> Daniel
> --
> |: https://berrange.com  -o-
> https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org -o-
> https://fstop138.berrange.com :|
> |: https://entangle-photo.org-o-
> https://www.instagram.com/dberrange :|
>
>


Re: [PATCH v3] hw/misc: applesmc: use host osk as default on macs

2022-04-17 Thread Vladislav Yaroshchuk
I've CCed all the people from previous threads.


> [...]
> +static bool applesmc_read_osk(uint8_t *osk)
> +{
> +#if defined(__APPLE__) && defined(__MACH__)
> +struct AppleSMCParams {
> +uint32_t key;
> +uint8_t __pad0[16];
> +uint8_t result;
> +uint8_t __pad1[7];
> +uint32_t size;
> +uint8_t __pad2[10];
> +uint8_t data8;
> +uint8_t __pad3[5];
> +uint8_t output[32];
> +};
> +
> +io_service_t svc;
> +io_connect_t conn;
> +kern_return_t ret;
> +size_t size = sizeof(struct AppleSMCParams);
> +struct AppleSMCParams params_in = { .size = 32, .data8 = 5 };

Maybe it's better to name this magic number '5'

> +struct AppleSMCParams params_out = {};
> +

params_in and params_out can be the same variable, see
https://patchew.org/QEMU/20211022161448.81579-1-yaroshchuk2...@gmail.com/

> +svc = IOServiceGetMatchingService(0, IOServiceMatching("AppleSMC"));
> +if (svc == 0) {
> +return false;
> +}
> +
> +ret = IOServiceOpen(svc, mach_task_self(), 0, );
> +if (ret != 0) {
> +return false;
> +}
> +
> +for (params_in.key = 'OSK0'; params_in.key <= 'OSK1';
++params_in.key) {
> +ret = IOConnectCallStructMethod(conn, 2, _in, size,
_out, );

Same about this magic number '2'.

> +if (ret != 0) {
> +return false;
> +}
> +
> +if (params_out.result != 0) {
> +return false;
> +}
> +memcpy(osk, params_out.output, params_in.size);
> +
> +osk += params_in.size;
> + }
> +

Cleanup IOServiceClose and IOObjectReturn are not called at the
end of the procedure.

This is also mentioned in Phil Dennis-Jordan's instruction you noted (stage
5):
https://lists.nongnu.org/archive/html/qemu-devel/2021-10/msg02843.html

> +return true;
> +#else
> +return false;
> +#endif
> +}
> +
> [...]
>
> static void applesmc_isa_realize(DeviceState *dev, Error **errp)
>  {
>  AppleSMCState *s = APPLE_SMC(dev);
> +bool valid_osk = false;
>
>  memory_region_init_io(>io_data, OBJECT(s), _data_io_ops,
s,
>"applesmc-data", 1);
> @@ -331,8 +393,17 @@ static void applesmc_isa_realize(DeviceState *dev,
Error **errp)
>  isa_register_ioport(>parent_obj, >io_err,
>  s->iobase + APPLESMC_ERR_PORT);
>
> -if (!s->osk || (strlen(s->osk) != 64)) {
> -warn_report("Using AppleSMC with invalid key");
> +if (s->osk) {
> +valid_osk = strlen(s->osk) == 64;
> +} else {
> +valid_osk = applesmc_read_osk((uint8_t *) default_osk);
> +if (valid_osk) {
> +warn_report("Using AppleSMC with host OSK");
> +s->osk = default_osk;
> +}
> +}
> +if (!valid_osk) {
> +warn_report("Using AppleSMC with invalid OSK");
>  s->osk = default_osk;
>  }
> [...]

After the previous discussion we've decided (if i don't confuse anything)
to have a way to enable/disable host OSK reading with new property:
1. properties osk=$key and hostosk=on cannot be used together (fail hard)
2. for QEMU machine > 7.0 - hostosk=on by default.
If unable to read - fail hard with error_setg.
3. for QEMU machine <= 7.0 - hostosk=off by default,
   the dummy OSK is used (as previously).

BTW since my patches lost 7.0, I planned to wait until compat machines
for 7.1 are added (after 7.0 release) and then rebase the patches,
adding required changes into `hw/core/machine.c`

Now we have two versions of host OSK forwarding implementations,
Pedro's (this one) and mine (
https://patchew.org/QEMU/20220113152836.60398-1-yaroshchuk2...@gmail.com/#)

Do we still want to add this feature? If yes - whose version is preferred?
(I'm still ready to work on this)

Regards,
Vlad

вс, 17 апр. 2022 г. в 04:36, Vladislav Yaroshchuk :

> Hi Pedro Torres,
>
> Please note this threads
> https://patchew.org/QEMU/20211022161448.81579-1-yaroshchuk2...@gmail.com/
> https://patchew.org/QEMU/20220113152836.60398-1-yaroshchuk2...@gmail.com/
>
> There was a discussion about how to preserve
> backward compatibility of emulated AppleSMC
> behaviour. The discussion has stopped, but
> if you're intended to see this feature working
> within QEMU - it'd be good to cc all the
> participans of previous threads :)
>
>
> Thanks,
>
> Vladislav Yaroshchuk
>
>


Re: [PATCH v3] hw/misc: applesmc: use host osk as default on macs

2022-04-16 Thread Vladislav Yaroshchuk
Hi Pedro Torres,

Please note this threads
https://patchew.org/QEMU/20211022161448.81579-1-yaroshchuk2...@gmail.com/
https://patchew.org/QEMU/20220113152836.60398-1-yaroshchuk2...@gmail.com/

There was a discussion about how to preserve
backward compatibility of emulated AppleSMC
behaviour. The discussion has stopped, but
if you're intended to see this feature working
within QEMU - it'd be good to cc all the
participans of previous threads :)


Thanks,

Vladislav Yaroshchuk 




Re: [PATCH v21 3/7] net/vmnet: implement shared mode (vmnet-shared)

2022-03-17 Thread Vladislav Yaroshchuk
On Thu, Mar 17, 2022 at 6:40 PM Akihiko Odaki 
wrote:

> On 2022/03/17 19:28, Vladislav Yaroshchuk wrote:
> > Interaction with vmnet.framework in different modes
> > differs only on configuration stage, so we can create
> > common `send`, `receive`, etc. procedures and reuse them.
> >
> > Signed-off-by: Phillip Tennen 
> > Signed-off-by: Vladislav Yaroshchuk 
> > ---
> >   net/vmnet-common.m | 358 +
> >   net/vmnet-shared.c |  90 +++-
> >   net/vmnet_int.h|  40 -
> >   3 files changed, 483 insertions(+), 5 deletions(-)
> >
> > diff --git a/net/vmnet-common.m b/net/vmnet-common.m
> > index 06326efb1c..2cb60b9ddd 100644
> > --- a/net/vmnet-common.m
> > +++ b/net/vmnet-common.m
> > @@ -10,6 +10,8 @@
> >*/
> >
> >   #include "qemu/osdep.h"
> > +#include "qemu/main-loop.h"
> > +#include "qemu/log.h"
> >   #include "qapi/qapi-types-net.h"
> >   #include "vmnet_int.h"
> >   #include "clients.h"
> > @@ -17,4 +19,360 @@
> >   #include "qapi/error.h"
> >
> >   #include 
> > +#include 
> >
> > +
> > +static void vmnet_send_completed(NetClientState *nc, ssize_t len);
> > +
> > +
> > +const char *vmnet_status_map_str(vmnet_return_t status)
> > +{
> > +switch (status) {
> > +case VMNET_SUCCESS:
> > +return "success";
> > +case VMNET_FAILURE:
> > +return "general failure (possibly not enough privileges)";
> > +case VMNET_MEM_FAILURE:
> > +return "memory allocation failure";
> > +case VMNET_INVALID_ARGUMENT:
> > +return "invalid argument specified";
> > +case VMNET_SETUP_INCOMPLETE:
> > +return "interface setup is not complete";
> > +case VMNET_INVALID_ACCESS:
> > +return "invalid access, permission denied";
> > +case VMNET_PACKET_TOO_BIG:
> > +return "packet size is larger than MTU";
> > +case VMNET_BUFFER_EXHAUSTED:
> > +return "buffers exhausted in kernel";
> > +case VMNET_TOO_MANY_PACKETS:
> > +return "packet count exceeds limit";
> > +#if defined(MAC_OS_VERSION_11_0) && \
> > +MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
> > +case VMNET_SHARING_SERVICE_BUSY:
> > +return "conflict, sharing service is in use";
> > +#endif
> > +default:
> > +return "unknown vmnet error";
> > +}
> > +}
> > +
> > +
> > +/**
> > + * Write packets from QEMU to vmnet interface.
> > + *
> > + * vmnet.framework supports iov, but writing more than
> > + * one iov into vmnet interface fails with
> > + * 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
> > + * one and passing it to vmnet works fine. That's the
> > + * reason why receive_iov() left unimplemented. But it still
> > + * works with good performance having .receive() only.
> > + */
> > +ssize_t vmnet_receive_common(NetClientState *nc,
> > + const uint8_t *buf,
> > + size_t size)
> > +{
> > +VmnetState *s = DO_UPCAST(VmnetState, nc, nc);
> > +struct vmpktdesc packet;
> > +struct iovec iov;
> > +int pkt_cnt;
> > +vmnet_return_t if_status;
> > +
> > +if (size > s->max_packet_size) {
> > +warn_report("vmnet: packet is too big, %zu > %" PRIu64,
> > +packet.vm_pkt_size,
> > +s->max_packet_size);
> > +return -1;
> > +}
> > +
> > +iov.iov_base = (char *) buf;
> > +iov.iov_len = size;
> > +
> > +packet.vm_pkt_iovcnt = 1;
> > +packet.vm_flags = 0;
> > +packet.vm_pkt_size = size;
> > +packet.vm_pkt_iov = 
> > +pkt_cnt = 1;
> > +
> > +if_status = vmnet_write(s->vmnet_if, , _cnt);
> > +if (if_status != VMNET_SUCCESS) {
> > +error_report("vmnet: write error: %s\n",
> > + vmnet_status_map_str(if_status));
> > +return -1;
> > +}
> > +
> > +if (pkt_cnt) {
> > +return size;
> > +}
> > +return 0;
> > +}
> > +
> > +
> > +/**
> > + * Read packets from vmnet interface and write them
> > + * to temporary buffers in VmnetState.
> > + *

[PATCH v22 6/7] net/vmnet: update qemu-options.hx

2022-03-17 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 qemu-options.hx | 25 +
 1 file changed, 25 insertions(+)

diff --git a/qemu-options.hx b/qemu-options.hx
index 5ce0ada75e..ea00d0eeb6 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2743,6 +2743,25 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
 #ifdef __linux__
 "-netdev vhost-vdpa,id=str,vhostdev=/path/to/dev\n"
 "configure a vhost-vdpa network,Establish a vhost-vdpa 
netdev\n"
+#endif
+#ifdef CONFIG_VMNET
+"-netdev vmnet-host,id=str[,isolated=on|off][,net-uuid=uuid]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in host mode with ID 
'str',\n"
+"isolate this interface from others with 'isolated',\n"
+"configure the address range and choose a subnet mask,\n"
+"specify network UUID 'uuid' to disable DHCP and interact 
with\n"
+"vmnet-host interfaces within this isolated network\n"
+"-netdev vmnet-shared,id=str[,isolated=on|off][,nat66-prefix=addr]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in shared mode with ID 
'str',\n"
+"configure the address range and choose a subnet mask,\n"
+"set IPv6 ULA prefix (of length 64) to use for internal 
network,\n"
+"isolate this interface from others with 'isolated'\n"
+"-netdev vmnet-bridged,id=str,ifname=name[,isolated=on|off]\n"
+"configure a vmnet network backend in bridged mode with ID 
'str',\n"
+"use 'ifname=name' to select a physical network interface 
to be bridged,\n"
+"isolate this interface from others with 'isolated'\n"
 #endif
 "-netdev hubport,id=str,hubid=n[,netdev=nd]\n"
 "configure a hub port on the hub with ID 'n'\n", 
QEMU_ARCH_ALL)
@@ -2762,6 +2781,9 @@ DEF("nic", HAS_ARG, QEMU_OPTION_nic,
 #endif
 #ifdef CONFIG_POSIX
 "vhost-user|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,...][mac=macaddr]\n"
 "initialize an on-board / default host NIC (using MAC 
address\n"
@@ -2784,6 +2806,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
 #endif
 #ifdef CONFIG_NETMAP
 "netmap|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,option][,...]\n"
 "old way to initialize a host network interface\n"
-- 
2.34.1.vfs.0.0




[PATCH v22 7/7] net/vmnet: update hmp-commands.hx

2022-03-17 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 hmp-commands.hx | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 8476277aa9..8f3d78f177 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1265,7 +1265,11 @@ ERST
 {
 .name   = "netdev_add",
 .args_type  = "netdev:O",
-.params = 
"[user|tap|socket|vde|bridge|hubport|netmap|vhost-user],id=str[,prop=value][,...]",
+.params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user"
+#ifdef CONFIG_VMNET
+  "|vmnet-host|vmnet-shared|vmnet-bridged"
+#endif
+  "],id=str[,prop=value][,...]",
 .help   = "add host network device",
 .cmd= hmp_netdev_add,
 .command_completion = netdev_add_completion,
-- 
2.34.1.vfs.0.0




[PATCH v22 3/7] net/vmnet: implement shared mode (vmnet-shared)

2022-03-17 Thread Vladislav Yaroshchuk
Interaction with vmnet.framework in different modes
differs only on configuration stage, so we can create
common `send`, `receive`, etc. procedures and reuse them.

Signed-off-by: Phillip Tennen 
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-common.m | 358 +
 net/vmnet-shared.c |  97 +++-
 net/vmnet_int.h|  40 -
 3 files changed, 490 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-common.m b/net/vmnet-common.m
index 06326efb1c..2cb60b9ddd 100644
--- a/net/vmnet-common.m
+++ b/net/vmnet-common.m
@@ -10,6 +10,8 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "qemu/log.h"
 #include "qapi/qapi-types-net.h"
 #include "vmnet_int.h"
 #include "clients.h"
@@ -17,4 +19,360 @@
 #include "qapi/error.h"
 
 #include 
+#include 
 
+
+static void vmnet_send_completed(NetClientState *nc, ssize_t len);
+
+
+const char *vmnet_status_map_str(vmnet_return_t status)
+{
+switch (status) {
+case VMNET_SUCCESS:
+return "success";
+case VMNET_FAILURE:
+return "general failure (possibly not enough privileges)";
+case VMNET_MEM_FAILURE:
+return "memory allocation failure";
+case VMNET_INVALID_ARGUMENT:
+return "invalid argument specified";
+case VMNET_SETUP_INCOMPLETE:
+return "interface setup is not complete";
+case VMNET_INVALID_ACCESS:
+return "invalid access, permission denied";
+case VMNET_PACKET_TOO_BIG:
+return "packet size is larger than MTU";
+case VMNET_BUFFER_EXHAUSTED:
+return "buffers exhausted in kernel";
+case VMNET_TOO_MANY_PACKETS:
+return "packet count exceeds limit";
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+case VMNET_SHARING_SERVICE_BUSY:
+return "conflict, sharing service is in use";
+#endif
+default:
+return "unknown vmnet error";
+}
+}
+
+
+/**
+ * Write packets from QEMU to vmnet interface.
+ *
+ * vmnet.framework supports iov, but writing more than
+ * one iov into vmnet interface fails with
+ * 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
+ * one and passing it to vmnet works fine. That's the
+ * reason why receive_iov() left unimplemented. But it still
+ * works with good performance having .receive() only.
+ */
+ssize_t vmnet_receive_common(NetClientState *nc,
+ const uint8_t *buf,
+ size_t size)
+{
+VmnetState *s = DO_UPCAST(VmnetState, nc, nc);
+struct vmpktdesc packet;
+struct iovec iov;
+int pkt_cnt;
+vmnet_return_t if_status;
+
+if (size > s->max_packet_size) {
+warn_report("vmnet: packet is too big, %zu > %" PRIu64,
+packet.vm_pkt_size,
+s->max_packet_size);
+return -1;
+}
+
+iov.iov_base = (char *) buf;
+iov.iov_len = size;
+
+packet.vm_pkt_iovcnt = 1;
+packet.vm_flags = 0;
+packet.vm_pkt_size = size;
+packet.vm_pkt_iov = 
+pkt_cnt = 1;
+
+if_status = vmnet_write(s->vmnet_if, , _cnt);
+if (if_status != VMNET_SUCCESS) {
+error_report("vmnet: write error: %s\n",
+ vmnet_status_map_str(if_status));
+return -1;
+}
+
+if (pkt_cnt) {
+return size;
+}
+return 0;
+}
+
+
+/**
+ * Read packets from vmnet interface and write them
+ * to temporary buffers in VmnetState.
+ *
+ * Returns read packets number (may be 0) on success,
+ * -1 on error
+ */
+static int vmnet_read_packets(VmnetState *s)
+{
+assert(s->packets_send_current_pos == s->packets_send_end_pos);
+
+struct vmpktdesc *packets = s->packets_buf;
+vmnet_return_t status;
+int i;
+
+/* Read as many packets as present */
+s->packets_send_current_pos = 0;
+s->packets_send_end_pos = VMNET_PACKETS_LIMIT;
+for (i = 0; i < s->packets_send_end_pos; ++i) {
+packets[i].vm_pkt_size = s->max_packet_size;
+packets[i].vm_pkt_iovcnt = 1;
+packets[i].vm_flags = 0;
+}
+
+status = vmnet_read(s->vmnet_if, packets, >packets_send_end_pos);
+if (status != VMNET_SUCCESS) {
+error_printf("vmnet: read failed: %s\n",
+ vmnet_status_map_str(status));
+s->packets_send_current_pos = 0;
+s->packets_send_end_pos = 0;
+return -1;
+}
+return s->packets_send_end_pos;
+}
+
+
+/**
+ * Write packets from temporary buffers in VmnetState
+ * to QEMU.
+ */
+static void vmnet_write_packets_to_qemu(VmnetState *s)
+{
+while (s->packets_send_current_pos < s->packets_send_end_pos) {
+ssize_t size = qemu_send_packet_async(>nc,
+ 

[PATCH v22 5/7] net/vmnet: implement bridged mode (vmnet-bridged)

2022-03-17 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-bridged.m | 137 ++--
 1 file changed, 132 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
index 91c1a2f2c7..46d2282863 100644
--- a/net/vmnet-bridged.m
+++ b/net/vmnet-bridged.m
@@ -10,16 +10,143 @@
 
 #include "qemu/osdep.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+
+static bool validate_ifname(const char *ifname)
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+bool match = false;
+if (!xpc_array_get_count(shared_if_list)) {
+goto done;
+}
+
+match = !xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+return strcmp(xpc_string_get_string_ptr(value), ifname) != 0;
+});
+
+done:
+xpc_release(shared_if_list);
+return match;
+}
+
+
+static char* get_valid_ifnames()
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+__block char *if_list = NULL;
+__block char *if_list_prev = NULL;
+
+if (!xpc_array_get_count(shared_if_list)) {
+goto done;
+}
+
+xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+/* build list of strings like "en0 en1 en2 " */
+if_list = g_strconcat(xpc_string_get_string_ptr(value),
+  " ",
+  if_list_prev,
+  NULL);
+g_free(if_list_prev);
+if_list_prev = if_list;
+return true;
+});
+
+done:
+xpc_release(shared_if_list);
+return if_list;
+}
+
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+char* if_list;
+
+if (!validate_ifname(options->ifname)) {
+if_list = get_valid_ifnames();
+if (if_list) {
+error_setg(errp,
+   "unsupported ifname '%s', expected one of [ %s]",
+   options->ifname,
+   if_list);
+g_free(if_list);
+} else {
+error_setg(errp,
+   "unsupported ifname '%s', no supported "
+   "interfaces available",
+   options->ifname);
+}
+return false;
+}
+
+#if !defined(MAC_OS_VERSION_11_0) || \
+MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_11_0
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-bridged.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+return true;
+}
+
+
+static xpc_object_t build_if_desc(const Netdev *netdev)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_BRIDGED_MODE
+);
+
+xpc_dictionary_set_string(if_desc,
+  vmnet_shared_interface_name_key,
+  options->ifname);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+#endif
+return if_desc;
+}
+
+
+static NetClientInfo net_vmnet_bridged_info = {
+.type = NET_CLIENT_DRIVER_VMNET_BRIDGED,
+.size = sizeof(VmnetState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
+
 int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
NetClientState *peer, Error **errp)
 {
-  error_setg(errp, "vmnet-bridged is not implemented yet");
-  return -1;
+NetClientState *nc = qemu_new_net_client(_vmnet_bridged_info,
+ peer, "vmnet-bridged", name);
+xpc_object_t if_desc;
+int result = -1;
+
+if (!validate_options(netdev, errp)) {
+return result;
+}
+
+if_desc = build_if_desc(netdev);
+result = vmnet_if_create(nc, if_desc, errp);
+xpc_release(if_desc);
+return result;
 }
-- 
2.34.1.vfs.0.0




[PATCH v22 4/7] net/vmnet: implement host mode (vmnet-host)

2022-03-17 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-host.c | 116 ---
 1 file changed, 110 insertions(+), 6 deletions(-)

diff --git a/net/vmnet-host.c b/net/vmnet-host.c
index a461d507c5..05f8d78864 100644
--- a/net/vmnet-host.c
+++ b/net/vmnet-host.c
@@ -9,16 +9,120 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/uuid.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+QemuUUID net_uuid;
+if (options->has_net_uuid &&
+qemu_uuid_parse(options->net_uuid, _uuid) < 0) {
+error_setg(errp, "Invalid UUID provided in 'net-uuid'");
+return false;
+}
+#else
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-host.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+
+if (options->has_net_uuid) {
+error_setg(errp,
+   "vmnet-host.net-uuid feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+
+if ((options->has_start_address ||
+ options->has_end_address ||
+ options->has_subnet_mask) &&
+!(options->has_start_address &&
+  options->has_end_address &&
+  options->has_subnet_mask)) {
+error_setg(errp,
+   "'start-address', 'end-address', 'subnet-mask' "
+   "should be provided together");
+return false;
+}
+
+return true;
+}
+
+static xpc_object_t build_if_desc(const Netdev *netdev)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_HOST_MODE);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+
+QemuUUID net_uuid;
+if (options->has_net_uuid) {
+qemu_uuid_parse(options->net_uuid, _uuid);
+xpc_dictionary_set_uuid(if_desc,
+vmnet_network_identifier_key,
+net_uuid.data);
+}
+#endif
+
+if (options->has_start_address) {
+xpc_dictionary_set_string(if_desc,
+  vmnet_start_address_key,
+  options->start_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_end_address_key,
+  options->end_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_subnet_mask_key,
+  options->subnet_mask);
+}
+
+return if_desc;
+}
+
+static NetClientInfo net_vmnet_host_info = {
+.type = NET_CLIENT_DRIVER_VMNET_HOST,
+.size = sizeof(VmnetState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
 int net_init_vmnet_host(const Netdev *netdev, const char *name,
-NetClientState *peer, Error **errp) {
-  error_setg(errp, "vmnet-host is not implemented yet");
-  return -1;
+NetClientState *peer, Error **errp)
+{
+NetClientState *nc = qemu_new_net_client(_vmnet_host_info,
+ peer, "vmnet-host", name);
+xpc_object_t if_desc;
+int result = -1;
+
+if (!validate_options(netdev, errp)) {
+return result;
+}
+
+if_desc = build_if_desc(netdev);
+result = vmnet_if_create(nc, if_desc, errp);
+xpc_release(if_desc);
+return result;
 }
-- 
2.34.1.vfs.0.0




[PATCH v22 2/7] net/vmnet: add vmnet backends to qapi/net

2022-03-17 Thread Vladislav Yaroshchuk
Create separate netdevs for each vmnet operating mode:
- vmnet-host
- vmnet-shared
- vmnet-bridged

Acked-by: Markus Armbruster 
Signed-off-by: Vladislav Yaroshchuk 
---
 net/clients.h   |  11 
 net/meson.build |   7 +++
 net/net.c   |  10 
 net/vmnet-bridged.m |  25 +
 net/vmnet-common.m  |  20 +++
 net/vmnet-host.c|  24 
 net/vmnet-shared.c  |  25 +
 net/vmnet_int.h |  25 +
 qapi/net.json   | 133 +++-
 9 files changed, 278 insertions(+), 2 deletions(-)
 create mode 100644 net/vmnet-bridged.m
 create mode 100644 net/vmnet-common.m
 create mode 100644 net/vmnet-host.c
 create mode 100644 net/vmnet-shared.c
 create mode 100644 net/vmnet_int.h

diff --git a/net/clients.h b/net/clients.h
index 92f9b59aed..c9157789f2 100644
--- a/net/clients.h
+++ b/net/clients.h
@@ -63,4 +63,15 @@ int net_init_vhost_user(const Netdev *netdev, const char 
*name,
 
 int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
 NetClientState *peer, Error **errp);
+#ifdef CONFIG_VMNET
+int net_init_vmnet_host(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_shared(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+#endif /* CONFIG_VMNET */
+
 #endif /* QEMU_NET_CLIENTS_H */
diff --git a/net/meson.build b/net/meson.build
index 847bc2ac85..00a88c4951 100644
--- a/net/meson.build
+++ b/net/meson.build
@@ -42,4 +42,11 @@ softmmu_ss.add(when: 'CONFIG_POSIX', if_true: 
files(tap_posix))
 softmmu_ss.add(when: 'CONFIG_WIN32', if_true: files('tap-win32.c'))
 softmmu_ss.add(when: 'CONFIG_VHOST_NET_VDPA', if_true: files('vhost-vdpa.c'))
 
+vmnet_files = files(
+  'vmnet-common.m',
+  'vmnet-bridged.m',
+  'vmnet-host.c',
+  'vmnet-shared.c'
+)
+softmmu_ss.add(when: vmnet, if_true: vmnet_files)
 subdir('can')
diff --git a/net/net.c b/net/net.c
index f0d14dbfc1..1dbb64b935 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1021,6 +1021,11 @@ static int (* const 
net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
 #ifdef CONFIG_L2TPV3
 [NET_CLIENT_DRIVER_L2TPV3]= net_init_l2tpv3,
 #endif
+#ifdef CONFIG_VMNET
+[NET_CLIENT_DRIVER_VMNET_HOST] = net_init_vmnet_host,
+[NET_CLIENT_DRIVER_VMNET_SHARED] = net_init_vmnet_shared,
+[NET_CLIENT_DRIVER_VMNET_BRIDGED] = net_init_vmnet_bridged,
+#endif /* CONFIG_VMNET */
 };
 
 
@@ -1106,6 +,11 @@ void show_netdevs(void)
 #endif
 #ifdef CONFIG_VHOST_VDPA
 "vhost-vdpa",
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host",
+"vmnet-shared",
+"vmnet-bridged",
 #endif
 };
 
diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
new file mode 100644
index 00..91c1a2f2c7
--- /dev/null
+++ b/net/vmnet-bridged.m
@@ -0,0 +1,25 @@
+/*
+ * vmnet-bridged.m
+ *
+ * Copyright(c) 2022 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+   NetClientState *peer, Error **errp)
+{
+  error_setg(errp, "vmnet-bridged is not implemented yet");
+  return -1;
+}
diff --git a/net/vmnet-common.m b/net/vmnet-common.m
new file mode 100644
index 00..06326efb1c
--- /dev/null
+++ b/net/vmnet-common.m
@@ -0,0 +1,20 @@
+/*
+ * vmnet-common.m - network client wrapper for Apple vmnet.framework
+ *
+ * Copyright(c) 2022 Vladislav Yaroshchuk 
+ * Copyright(c) 2021 Phillip Tennen 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
diff --git a/net/vmnet-host.c b/net/vmnet-host.c
new file mode 100644
index 00..a461d507c5
--- /dev/null
+++ b/net/vmnet-host.c
@@ -0,0 +1,24 @@
+/*
+ * vmnet-host.c
+ *
+ * Copyright(c) 2022 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/

[PATCH v22 1/7] net/vmnet: add vmnet dependency and customizable option

2022-03-17 Thread Vladislav Yaroshchuk
vmnet.framework dependency is added with 'vmnet' option
to enable or disable it. Default value is 'auto'.

used vmnet features are available since macOS 11.0,
but new backend can be built and work properly with
subset of them on 10.15 too.

Signed-off-by: Vladislav Yaroshchuk 
---
 meson.build   | 16 +++-
 meson_options.txt |  2 ++
 scripts/meson-buildoptions.sh |  1 +
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index 2d6601467f..806f3869f9 100644
--- a/meson.build
+++ b/meson.build
@@ -522,6 +522,18 @@ if cocoa.found() and get_option('gtk').enabled()
   error('Cocoa and GTK+ cannot be enabled at the same time')
 endif
 
+vmnet = dependency('appleframeworks', modules: 'vmnet', required: 
get_option('vmnet'))
+if vmnet.found() and not cc.has_header_symbol('vmnet/vmnet.h',
+  'VMNET_BRIDGED_MODE',
+  dependencies: vmnet)
+  vmnet = not_found
+  if get_option('vmnet').enabled()
+error('vmnet.framework API is outdated')
+  else
+warning('vmnet.framework API is outdated, disabling')
+  endif
+endif
+
 seccomp = not_found
 if not get_option('seccomp').auto() or have_system or have_tools
   seccomp = dependency('libseccomp', version: '>=2.3.0',
@@ -1550,6 +1562,7 @@ config_host_data.set('CONFIG_SNAPPY', snappy.found())
 config_host_data.set('CONFIG_TPM', have_tpm)
 config_host_data.set('CONFIG_USB_LIBUSB', libusb.found())
 config_host_data.set('CONFIG_VDE', vde.found())
+config_host_data.set('CONFIG_VMNET', vmnet.found())
 config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', 
have_vhost_user_blk_server)
 config_host_data.set('CONFIG_VNC', vnc.found())
 config_host_data.set('CONFIG_VNC_JPEG', jpeg.found())
@@ -3588,7 +3601,8 @@ summary(summary_info, bool_yn: true, section: 'Crypto')
 # Libraries
 summary_info = {}
 if targetos == 'darwin'
-  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'vmnet.framework support': vmnet}
 endif
 summary_info += {'SDL support':   sdl}
 summary_info += {'SDL image support': sdl_image}
diff --git a/meson_options.txt b/meson_options.txt
index 52b11cead4..d2c0b6b412 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -175,6 +175,8 @@ option('netmap', type : 'feature', value : 'auto',
description: 'netmap network backend support')
 option('vde', type : 'feature', value : 'auto',
description: 'vde network backend support')
+option('vmnet', type : 'feature', value : 'auto',
+   description: 'vmnet.framework network backend support')
 option('virglrenderer', type : 'feature', value : 'auto',
description: 'virgl rendering support')
 option('vnc', type : 'feature', value : 'auto',
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 9ee684ef03..30946f3798 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -116,6 +116,7 @@ meson_options_help() {
   printf "%s\n" '  usb-redir   libusbredir support'
   printf "%s\n" '  vde vde network backend support'
   printf "%s\n" '  vdi vdi image format support'
+  printf "%s\n" '  vmnet   vmnet.framework network backend support'
   printf "%s\n" '  vhost-user-blk-server'
   printf "%s\n" '  build vhost-user-blk server'
   printf "%s\n" '  virglrenderer   virgl rendering support'
-- 
2.34.1.vfs.0.0




[PATCH v22 0/7] Add vmnet.framework based network backend

2022-03-17 Thread Vladislav Yaroshchuk
r proper printing
 - NOTE: This version of patch series may be one the last
   I submit - JetBrains has suspended operations in
   Russia indefinitely due to all the awful things happened
   the last weeks. I may leave this company and loose the
   ability to work on vmnet support :(
   It will be perfect if someone can handle my unfinished work,
   if something required to fix/improve is found.
   Because of this, MAINTAINERS list update is dropped
v16 -> v17
 - host: move network_uuid to local variable
 - common: refactor, add documentation
 - common/send (vmnet->qemu): read new packets after QEMU
   send_cb invoked
 - common/receive (qemu->vmnet): drop redundant vmnet
   status checks
 - restore dropped commit messaged from the previous series
v17 -> v18
 - use VmnetState struct for all three operation modes
 - drop send_enabled flag
 - do not unregister vmnet event callback on cleanup,
   let vmnet.framework do everything itself while interface
   destruction
v18 -> v19
 - use positive pointers values to describe unsent packets
   window of VmnetState buffer
v19 -> v20
 - vmnet-host: minor but required refactor
v20 -> v21
 - vmnet-bridged: dynamically allocate valid ifnames list
 - QAPI schema: add `Markus Armbruster `'s acked-by
v21 -> v22
 - common: fix if_desc memory leak

Vladislav Yaroshchuk (7):
  net/vmnet: add vmnet dependency and customizable option
  net/vmnet: add vmnet backends to qapi/net
  net/vmnet: implement shared mode (vmnet-shared)
  net/vmnet: implement host mode (vmnet-host)
  net/vmnet: implement bridged mode (vmnet-bridged)
  net/vmnet: update qemu-options.hx
  net/vmnet: update hmp-commands.hx

 hmp-commands.hx   |   6 +-
 meson.build   |  16 +-
 meson_options.txt |   2 +
 net/clients.h |  11 +
 net/meson.build   |   7 +
 net/net.c |  10 +
 net/vmnet-bridged.m   | 152 ++
 net/vmnet-common.m| 378 ++
 net/vmnet-host.c  | 128 
 net/vmnet-shared.c| 114 ++
 net/vmnet_int.h   |  63 ++
 qapi/net.json | 133 +++-
 qemu-options.hx   |  25 +++
 scripts/meson-buildoptions.sh |   1 +
 14 files changed, 1042 insertions(+), 4 deletions(-)
 create mode 100644 net/vmnet-bridged.m
 create mode 100644 net/vmnet-common.m
 create mode 100644 net/vmnet-host.c
 create mode 100644 net/vmnet-shared.c
 create mode 100644 net/vmnet_int.h

-- 
2.34.1.vfs.0.0




[PATCH v21 5/7] net/vmnet: implement bridged mode (vmnet-bridged)

2022-03-17 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-bridged.m | 130 ++--
 1 file changed, 125 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
index 91c1a2f2c7..6970c7d17b 100644
--- a/net/vmnet-bridged.m
+++ b/net/vmnet-bridged.m
@@ -10,16 +10,136 @@
 
 #include "qemu/osdep.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+
+static bool validate_ifname(const char *ifname)
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+bool match = false;
+if (!xpc_array_get_count(shared_if_list)) {
+goto done;
+}
+
+match = !xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+return strcmp(xpc_string_get_string_ptr(value), ifname) != 0;
+});
+
+done:
+xpc_release(shared_if_list);
+return match;
+}
+
+
+static char* get_valid_ifnames()
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+__block char *if_list = NULL;
+__block char *if_list_prev = NULL;
+
+if (!xpc_array_get_count(shared_if_list)) {
+goto done;
+}
+
+xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+/* build list of strings like "en0 en1 en2 " */
+if_list = g_strconcat(xpc_string_get_string_ptr(value),
+  " ",
+  if_list_prev,
+  NULL);
+g_free(if_list_prev);
+if_list_prev = if_list;
+return true;
+});
+
+done:
+xpc_release(shared_if_list);
+return if_list;
+}
+
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+char* if_list;
+
+if (!validate_ifname(options->ifname)) {
+if_list = get_valid_ifnames();
+if (if_list) {
+error_setg(errp,
+   "unsupported ifname '%s', expected one of [ %s]",
+   options->ifname,
+   if_list);
+g_free(if_list);
+} else {
+error_setg(errp,
+   "unsupported ifname '%s', no supported "
+   "interfaces available",
+   options->ifname);
+}
+return false;
+}
+
+#if !defined(MAC_OS_VERSION_11_0) || \
+MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_11_0
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-bridged.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+return true;
+}
+
+
+static xpc_object_t build_if_desc(const Netdev *netdev)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_BRIDGED_MODE
+);
+
+xpc_dictionary_set_string(if_desc,
+  vmnet_shared_interface_name_key,
+  options->ifname);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+#endif
+return if_desc;
+}
+
+
+static NetClientInfo net_vmnet_bridged_info = {
+.type = NET_CLIENT_DRIVER_VMNET_BRIDGED,
+.size = sizeof(VmnetState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
+
 int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
NetClientState *peer, Error **errp)
 {
-  error_setg(errp, "vmnet-bridged is not implemented yet");
-  return -1;
+NetClientState *nc = qemu_new_net_client(_vmnet_bridged_info,
+ peer, "vmnet-bridged", name);
+if (!validate_options(netdev, errp)) {
+return -1;
+}
+return vmnet_if_create(nc, build_if_desc(netdev), errp);
 }
-- 
2.34.1.vfs.0.0




[PATCH v21 4/7] net/vmnet: implement host mode (vmnet-host)

2022-03-17 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-host.c | 109 ---
 1 file changed, 103 insertions(+), 6 deletions(-)

diff --git a/net/vmnet-host.c b/net/vmnet-host.c
index a461d507c5..e6d01fd65e 100644
--- a/net/vmnet-host.c
+++ b/net/vmnet-host.c
@@ -9,16 +9,113 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/uuid.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+QemuUUID net_uuid;
+if (options->has_net_uuid &&
+qemu_uuid_parse(options->net_uuid, _uuid) < 0) {
+error_setg(errp, "Invalid UUID provided in 'net-uuid'");
+return false;
+}
+#else
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-host.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+
+if (options->has_net_uuid) {
+error_setg(errp,
+   "vmnet-host.net-uuid feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+
+if ((options->has_start_address ||
+ options->has_end_address ||
+ options->has_subnet_mask) &&
+!(options->has_start_address &&
+  options->has_end_address &&
+  options->has_subnet_mask)) {
+error_setg(errp,
+   "'start-address', 'end-address', 'subnet-mask' "
+   "should be provided together");
+return false;
+}
+
+return true;
+}
+
+static xpc_object_t build_if_desc(const Netdev *netdev)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_HOST_MODE);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+
+QemuUUID net_uuid;
+if (options->has_net_uuid) {
+qemu_uuid_parse(options->net_uuid, _uuid);
+xpc_dictionary_set_uuid(if_desc,
+vmnet_network_identifier_key,
+net_uuid.data);
+}
+#endif
+
+if (options->has_start_address) {
+xpc_dictionary_set_string(if_desc,
+  vmnet_start_address_key,
+  options->start_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_end_address_key,
+  options->end_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_subnet_mask_key,
+  options->subnet_mask);
+}
+
+return if_desc;
+}
+
+static NetClientInfo net_vmnet_host_info = {
+.type = NET_CLIENT_DRIVER_VMNET_HOST,
+.size = sizeof(VmnetState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
 int net_init_vmnet_host(const Netdev *netdev, const char *name,
-NetClientState *peer, Error **errp) {
-  error_setg(errp, "vmnet-host is not implemented yet");
-  return -1;
+NetClientState *peer, Error **errp)
+{
+NetClientState *nc = qemu_new_net_client(_vmnet_host_info,
+ peer, "vmnet-host", name);
+if (!validate_options(netdev, errp)) {
+return -1;
+}
+return vmnet_if_create(nc, build_if_desc(netdev), errp);
 }
-- 
2.34.1.vfs.0.0




[PATCH v21 3/7] net/vmnet: implement shared mode (vmnet-shared)

2022-03-17 Thread Vladislav Yaroshchuk
Interaction with vmnet.framework in different modes
differs only on configuration stage, so we can create
common `send`, `receive`, etc. procedures and reuse them.

Signed-off-by: Phillip Tennen 
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-common.m | 358 +
 net/vmnet-shared.c |  90 +++-
 net/vmnet_int.h|  40 -
 3 files changed, 483 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-common.m b/net/vmnet-common.m
index 06326efb1c..2cb60b9ddd 100644
--- a/net/vmnet-common.m
+++ b/net/vmnet-common.m
@@ -10,6 +10,8 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "qemu/log.h"
 #include "qapi/qapi-types-net.h"
 #include "vmnet_int.h"
 #include "clients.h"
@@ -17,4 +19,360 @@
 #include "qapi/error.h"
 
 #include 
+#include 
 
+
+static void vmnet_send_completed(NetClientState *nc, ssize_t len);
+
+
+const char *vmnet_status_map_str(vmnet_return_t status)
+{
+switch (status) {
+case VMNET_SUCCESS:
+return "success";
+case VMNET_FAILURE:
+return "general failure (possibly not enough privileges)";
+case VMNET_MEM_FAILURE:
+return "memory allocation failure";
+case VMNET_INVALID_ARGUMENT:
+return "invalid argument specified";
+case VMNET_SETUP_INCOMPLETE:
+return "interface setup is not complete";
+case VMNET_INVALID_ACCESS:
+return "invalid access, permission denied";
+case VMNET_PACKET_TOO_BIG:
+return "packet size is larger than MTU";
+case VMNET_BUFFER_EXHAUSTED:
+return "buffers exhausted in kernel";
+case VMNET_TOO_MANY_PACKETS:
+return "packet count exceeds limit";
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+case VMNET_SHARING_SERVICE_BUSY:
+return "conflict, sharing service is in use";
+#endif
+default:
+return "unknown vmnet error";
+}
+}
+
+
+/**
+ * Write packets from QEMU to vmnet interface.
+ *
+ * vmnet.framework supports iov, but writing more than
+ * one iov into vmnet interface fails with
+ * 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
+ * one and passing it to vmnet works fine. That's the
+ * reason why receive_iov() left unimplemented. But it still
+ * works with good performance having .receive() only.
+ */
+ssize_t vmnet_receive_common(NetClientState *nc,
+ const uint8_t *buf,
+ size_t size)
+{
+VmnetState *s = DO_UPCAST(VmnetState, nc, nc);
+struct vmpktdesc packet;
+struct iovec iov;
+int pkt_cnt;
+vmnet_return_t if_status;
+
+if (size > s->max_packet_size) {
+warn_report("vmnet: packet is too big, %zu > %" PRIu64,
+packet.vm_pkt_size,
+s->max_packet_size);
+return -1;
+}
+
+iov.iov_base = (char *) buf;
+iov.iov_len = size;
+
+packet.vm_pkt_iovcnt = 1;
+packet.vm_flags = 0;
+packet.vm_pkt_size = size;
+packet.vm_pkt_iov = 
+pkt_cnt = 1;
+
+if_status = vmnet_write(s->vmnet_if, , _cnt);
+if (if_status != VMNET_SUCCESS) {
+error_report("vmnet: write error: %s\n",
+ vmnet_status_map_str(if_status));
+return -1;
+}
+
+if (pkt_cnt) {
+return size;
+}
+return 0;
+}
+
+
+/**
+ * Read packets from vmnet interface and write them
+ * to temporary buffers in VmnetState.
+ *
+ * Returns read packets number (may be 0) on success,
+ * -1 on error
+ */
+static int vmnet_read_packets(VmnetState *s)
+{
+assert(s->packets_send_current_pos == s->packets_send_end_pos);
+
+struct vmpktdesc *packets = s->packets_buf;
+vmnet_return_t status;
+int i;
+
+/* Read as many packets as present */
+s->packets_send_current_pos = 0;
+s->packets_send_end_pos = VMNET_PACKETS_LIMIT;
+for (i = 0; i < s->packets_send_end_pos; ++i) {
+packets[i].vm_pkt_size = s->max_packet_size;
+packets[i].vm_pkt_iovcnt = 1;
+packets[i].vm_flags = 0;
+}
+
+status = vmnet_read(s->vmnet_if, packets, >packets_send_end_pos);
+if (status != VMNET_SUCCESS) {
+error_printf("vmnet: read failed: %s\n",
+ vmnet_status_map_str(status));
+s->packets_send_current_pos = 0;
+s->packets_send_end_pos = 0;
+return -1;
+}
+return s->packets_send_end_pos;
+}
+
+
+/**
+ * Write packets from temporary buffers in VmnetState
+ * to QEMU.
+ */
+static void vmnet_write_packets_to_qemu(VmnetState *s)
+{
+while (s->packets_send_current_pos < s->packets_send_end_pos) {
+ssize_t size = qemu_send_packet_async(>nc,
+ 

[PATCH v21 2/7] net/vmnet: add vmnet backends to qapi/net

2022-03-17 Thread Vladislav Yaroshchuk
Create separate netdevs for each vmnet operating mode:
- vmnet-host
- vmnet-shared
- vmnet-bridged

Acked-by: Markus Armbruster 
Signed-off-by: Vladislav Yaroshchuk 
---
 net/clients.h   |  11 
 net/meson.build |   7 +++
 net/net.c   |  10 
 net/vmnet-bridged.m |  25 +
 net/vmnet-common.m  |  20 +++
 net/vmnet-host.c|  24 
 net/vmnet-shared.c  |  25 +
 net/vmnet_int.h |  25 +
 qapi/net.json   | 133 +++-
 9 files changed, 278 insertions(+), 2 deletions(-)
 create mode 100644 net/vmnet-bridged.m
 create mode 100644 net/vmnet-common.m
 create mode 100644 net/vmnet-host.c
 create mode 100644 net/vmnet-shared.c
 create mode 100644 net/vmnet_int.h

diff --git a/net/clients.h b/net/clients.h
index 92f9b59aed..c9157789f2 100644
--- a/net/clients.h
+++ b/net/clients.h
@@ -63,4 +63,15 @@ int net_init_vhost_user(const Netdev *netdev, const char 
*name,
 
 int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
 NetClientState *peer, Error **errp);
+#ifdef CONFIG_VMNET
+int net_init_vmnet_host(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_shared(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+#endif /* CONFIG_VMNET */
+
 #endif /* QEMU_NET_CLIENTS_H */
diff --git a/net/meson.build b/net/meson.build
index 847bc2ac85..00a88c4951 100644
--- a/net/meson.build
+++ b/net/meson.build
@@ -42,4 +42,11 @@ softmmu_ss.add(when: 'CONFIG_POSIX', if_true: 
files(tap_posix))
 softmmu_ss.add(when: 'CONFIG_WIN32', if_true: files('tap-win32.c'))
 softmmu_ss.add(when: 'CONFIG_VHOST_NET_VDPA', if_true: files('vhost-vdpa.c'))
 
+vmnet_files = files(
+  'vmnet-common.m',
+  'vmnet-bridged.m',
+  'vmnet-host.c',
+  'vmnet-shared.c'
+)
+softmmu_ss.add(when: vmnet, if_true: vmnet_files)
 subdir('can')
diff --git a/net/net.c b/net/net.c
index f0d14dbfc1..1dbb64b935 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1021,6 +1021,11 @@ static int (* const 
net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
 #ifdef CONFIG_L2TPV3
 [NET_CLIENT_DRIVER_L2TPV3]= net_init_l2tpv3,
 #endif
+#ifdef CONFIG_VMNET
+[NET_CLIENT_DRIVER_VMNET_HOST] = net_init_vmnet_host,
+[NET_CLIENT_DRIVER_VMNET_SHARED] = net_init_vmnet_shared,
+[NET_CLIENT_DRIVER_VMNET_BRIDGED] = net_init_vmnet_bridged,
+#endif /* CONFIG_VMNET */
 };
 
 
@@ -1106,6 +,11 @@ void show_netdevs(void)
 #endif
 #ifdef CONFIG_VHOST_VDPA
 "vhost-vdpa",
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host",
+"vmnet-shared",
+"vmnet-bridged",
 #endif
 };
 
diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
new file mode 100644
index 00..91c1a2f2c7
--- /dev/null
+++ b/net/vmnet-bridged.m
@@ -0,0 +1,25 @@
+/*
+ * vmnet-bridged.m
+ *
+ * Copyright(c) 2022 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+   NetClientState *peer, Error **errp)
+{
+  error_setg(errp, "vmnet-bridged is not implemented yet");
+  return -1;
+}
diff --git a/net/vmnet-common.m b/net/vmnet-common.m
new file mode 100644
index 00..06326efb1c
--- /dev/null
+++ b/net/vmnet-common.m
@@ -0,0 +1,20 @@
+/*
+ * vmnet-common.m - network client wrapper for Apple vmnet.framework
+ *
+ * Copyright(c) 2022 Vladislav Yaroshchuk 
+ * Copyright(c) 2021 Phillip Tennen 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
diff --git a/net/vmnet-host.c b/net/vmnet-host.c
new file mode 100644
index 00..a461d507c5
--- /dev/null
+++ b/net/vmnet-host.c
@@ -0,0 +1,24 @@
+/*
+ * vmnet-host.c
+ *
+ * Copyright(c) 2022 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/

[PATCH v21 6/7] net/vmnet: update qemu-options.hx

2022-03-17 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 qemu-options.hx | 25 +
 1 file changed, 25 insertions(+)

diff --git a/qemu-options.hx b/qemu-options.hx
index 5ce0ada75e..ea00d0eeb6 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2743,6 +2743,25 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
 #ifdef __linux__
 "-netdev vhost-vdpa,id=str,vhostdev=/path/to/dev\n"
 "configure a vhost-vdpa network,Establish a vhost-vdpa 
netdev\n"
+#endif
+#ifdef CONFIG_VMNET
+"-netdev vmnet-host,id=str[,isolated=on|off][,net-uuid=uuid]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in host mode with ID 
'str',\n"
+"isolate this interface from others with 'isolated',\n"
+"configure the address range and choose a subnet mask,\n"
+"specify network UUID 'uuid' to disable DHCP and interact 
with\n"
+"vmnet-host interfaces within this isolated network\n"
+"-netdev vmnet-shared,id=str[,isolated=on|off][,nat66-prefix=addr]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in shared mode with ID 
'str',\n"
+"configure the address range and choose a subnet mask,\n"
+"set IPv6 ULA prefix (of length 64) to use for internal 
network,\n"
+"isolate this interface from others with 'isolated'\n"
+"-netdev vmnet-bridged,id=str,ifname=name[,isolated=on|off]\n"
+"configure a vmnet network backend in bridged mode with ID 
'str',\n"
+"use 'ifname=name' to select a physical network interface 
to be bridged,\n"
+"isolate this interface from others with 'isolated'\n"
 #endif
 "-netdev hubport,id=str,hubid=n[,netdev=nd]\n"
 "configure a hub port on the hub with ID 'n'\n", 
QEMU_ARCH_ALL)
@@ -2762,6 +2781,9 @@ DEF("nic", HAS_ARG, QEMU_OPTION_nic,
 #endif
 #ifdef CONFIG_POSIX
 "vhost-user|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,...][mac=macaddr]\n"
 "initialize an on-board / default host NIC (using MAC 
address\n"
@@ -2784,6 +2806,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
 #endif
 #ifdef CONFIG_NETMAP
 "netmap|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,option][,...]\n"
 "old way to initialize a host network interface\n"
-- 
2.34.1.vfs.0.0




[PATCH v21 0/7] Add vmnet.framework based network backend

2022-03-17 Thread Vladislav Yaroshchuk
r proper printing
 - NOTE: This version of patch series may be one the last
   I submit - JetBrains has suspended operations in
   Russia indefinitely due to all the awful things happened
   the last weeks. I may leave this company and loose the
   ability to work on vmnet support :(
   It will be perfect if someone can handle my unfinished work,
   if something required to fix/improve is found.
   Because of this, MAINTAINERS list update is dropped
v16 -> v17
 - host: move network_uuid to local variable
 - common: refactor, add documentation
 - common/send (vmnet->qemu): read new packets after QEMU
   send_cb invoked
 - common/receive (qemu->vmnet): drop redundant vmnet
   status checks
 - restore dropped commit messaged from the previous series
v17 -> v18
 - use VmnetState struct for all three operation modes
 - drop send_enabled flag
 - do not unregister vmnet event callback on cleanup,
   let vmnet.framework do everything itself while interface
   destruction
v18 -> v19
 - use positive pointers values to describe unsent packets
   window of VmnetState buffer
v19 -> v20
 - vmnet-host: minor but required refactor
v20 -> v21
 - vmnet-bridged: dynamically allocate valid ifnames list
 - QAPI schema: add `Markus Armbruster `'s acked-by

Vladislav Yaroshchuk (7):
  net/vmnet: add vmnet dependency and customizable option
  net/vmnet: add vmnet backends to qapi/net
  net/vmnet: implement shared mode (vmnet-shared)
  net/vmnet: implement host mode (vmnet-host)
  net/vmnet: implement bridged mode (vmnet-bridged)
  net/vmnet: update qemu-options.hx
  net/vmnet: update hmp-commands.hx

 hmp-commands.hx   |   6 +-
 meson.build   |  16 +-
 meson_options.txt |   2 +
 net/clients.h |  11 +
 net/meson.build   |   7 +
 net/net.c |  10 +
 net/vmnet-bridged.m   | 145 +
 net/vmnet-common.m| 378 ++
 net/vmnet-host.c  | 121 +++
 net/vmnet-shared.c| 107 ++
 net/vmnet_int.h   |  63 ++
 qapi/net.json | 133 +++-
 qemu-options.hx   |  25 +++
 scripts/meson-buildoptions.sh |   1 +
 14 files changed, 1021 insertions(+), 4 deletions(-)
 create mode 100644 net/vmnet-bridged.m
 create mode 100644 net/vmnet-common.m
 create mode 100644 net/vmnet-host.c
 create mode 100644 net/vmnet-shared.c
 create mode 100644 net/vmnet_int.h

-- 
2.34.1.vfs.0.0




[PATCH v21 7/7] net/vmnet: update hmp-commands.hx

2022-03-17 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 hmp-commands.hx | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 8476277aa9..8f3d78f177 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1265,7 +1265,11 @@ ERST
 {
 .name   = "netdev_add",
 .args_type  = "netdev:O",
-.params = 
"[user|tap|socket|vde|bridge|hubport|netmap|vhost-user],id=str[,prop=value][,...]",
+.params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user"
+#ifdef CONFIG_VMNET
+  "|vmnet-host|vmnet-shared|vmnet-bridged"
+#endif
+  "],id=str[,prop=value][,...]",
 .help   = "add host network device",
 .cmd= hmp_netdev_add,
 .command_completion = netdev_add_completion,
-- 
2.34.1.vfs.0.0




[PATCH v21 1/7] net/vmnet: add vmnet dependency and customizable option

2022-03-17 Thread Vladislav Yaroshchuk
vmnet.framework dependency is added with 'vmnet' option
to enable or disable it. Default value is 'auto'.

used vmnet features are available since macOS 11.0,
but new backend can be built and work properly with
subset of them on 10.15 too.

Signed-off-by: Vladislav Yaroshchuk 
---
 meson.build   | 16 +++-
 meson_options.txt |  2 ++
 scripts/meson-buildoptions.sh |  1 +
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index 2d6601467f..806f3869f9 100644
--- a/meson.build
+++ b/meson.build
@@ -522,6 +522,18 @@ if cocoa.found() and get_option('gtk').enabled()
   error('Cocoa and GTK+ cannot be enabled at the same time')
 endif
 
+vmnet = dependency('appleframeworks', modules: 'vmnet', required: 
get_option('vmnet'))
+if vmnet.found() and not cc.has_header_symbol('vmnet/vmnet.h',
+  'VMNET_BRIDGED_MODE',
+  dependencies: vmnet)
+  vmnet = not_found
+  if get_option('vmnet').enabled()
+error('vmnet.framework API is outdated')
+  else
+warning('vmnet.framework API is outdated, disabling')
+  endif
+endif
+
 seccomp = not_found
 if not get_option('seccomp').auto() or have_system or have_tools
   seccomp = dependency('libseccomp', version: '>=2.3.0',
@@ -1550,6 +1562,7 @@ config_host_data.set('CONFIG_SNAPPY', snappy.found())
 config_host_data.set('CONFIG_TPM', have_tpm)
 config_host_data.set('CONFIG_USB_LIBUSB', libusb.found())
 config_host_data.set('CONFIG_VDE', vde.found())
+config_host_data.set('CONFIG_VMNET', vmnet.found())
 config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', 
have_vhost_user_blk_server)
 config_host_data.set('CONFIG_VNC', vnc.found())
 config_host_data.set('CONFIG_VNC_JPEG', jpeg.found())
@@ -3588,7 +3601,8 @@ summary(summary_info, bool_yn: true, section: 'Crypto')
 # Libraries
 summary_info = {}
 if targetos == 'darwin'
-  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'vmnet.framework support': vmnet}
 endif
 summary_info += {'SDL support':   sdl}
 summary_info += {'SDL image support': sdl_image}
diff --git a/meson_options.txt b/meson_options.txt
index 52b11cead4..d2c0b6b412 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -175,6 +175,8 @@ option('netmap', type : 'feature', value : 'auto',
description: 'netmap network backend support')
 option('vde', type : 'feature', value : 'auto',
description: 'vde network backend support')
+option('vmnet', type : 'feature', value : 'auto',
+   description: 'vmnet.framework network backend support')
 option('virglrenderer', type : 'feature', value : 'auto',
description: 'virgl rendering support')
 option('vnc', type : 'feature', value : 'auto',
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 9ee684ef03..30946f3798 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -116,6 +116,7 @@ meson_options_help() {
   printf "%s\n" '  usb-redir   libusbredir support'
   printf "%s\n" '  vde vde network backend support'
   printf "%s\n" '  vdi vdi image format support'
+  printf "%s\n" '  vmnet   vmnet.framework network backend support'
   printf "%s\n" '  vhost-user-blk-server'
   printf "%s\n" '  build vhost-user-blk server'
   printf "%s\n" '  virglrenderer   virgl rendering support'
-- 
2.34.1.vfs.0.0




Re: [PATCH v20 2/7] net/vmnet: add vmnet backends to qapi/net

2022-03-16 Thread Vladislav Yaroshchuk
On Wed, Mar 16, 2022 at 4:58 PM Markus Armbruster  wrote:

> Vladislav Yaroshchuk  writes:
>
> > Create separate netdevs for each vmnet operating mode:
> > - vmnet-host
> > - vmnet-shared
> > - vmnet-bridged
> >
> > Signed-off-by: Vladislav Yaroshchuk 
>
> Any QAPI schema changes since v15?  I'm asking because I acked v8, v13,
> and v15, but each time you neglected to carry my Acked-by lines in later
> revisions.
>
>
QAPI is not changed, but the "Since" statement was updated
for new netdevs (7.0 -> 7.1). That's the reason why I dropped
your Acked-by. I've also mentioned this in cover letter:

v15 -> v16
[...]
 - QAPI: change version to 7.1 (cause 7.0 feature freeze
   happened). This is the only change in QAPI, Markus Armbruster,
   please confirm if you can (decided to drop your Acked-by due
   to this change)
[...]

Best Regards,
Vladislav Yaroshchuk


Re: [PATCH v19 4/7] net/vmnet: implement host mode (vmnet-host)

2022-03-15 Thread Vladislav Yaroshchuk
On Tue, Mar 15, 2022 at 11:37 PM Akihiko Odaki 
wrote:

> On 2022/03/16 5:27, Vladislav Yaroshchuk wrote:
> > Signed-off-by: Vladislav Yaroshchuk 
> > ---
> >   net/vmnet-host.c | 110 ---
> >   1 file changed, 104 insertions(+), 6 deletions(-)
> >
> > diff --git a/net/vmnet-host.c b/net/vmnet-host.c
> > index a461d507c5..8f7a638967 100644
> > --- a/net/vmnet-host.c
> > +++ b/net/vmnet-host.c
> > @@ -9,16 +9,114 @@
> >*/
> >
> >   #include "qemu/osdep.h"
> > +#include "qemu/uuid.h"
> >   #include "qapi/qapi-types-net.h"
> > -#include "vmnet_int.h"
> > -#include "clients.h"
> > -#include "qemu/error-report.h"
> >   #include "qapi/error.h"
> > +#include "clients.h"
> > +#include "vmnet_int.h"
> >
> >   #include 
> >
> > +
> > +static bool validate_options(const Netdev *netdev, Error **errp)
> > +{
> > +const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
> > +QemuUUID uuid;
>
> The variable uuid is used only when defined(MAC_OS_VERSION_11_0) && \
> MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 and may result in a
> compilation warning otherwise. It should be in the #if block as
> network_uuid variable in build_if_desc is in the counterpart.
>
> Also I suggest to unify the names of identifiers. There are
> options->net_uuid, uuid, and network_uuid, but the differences tells
> nothing.
>
> This should be the last thing to be addressed (unless I missed something
> again.) Thank you for persistence (It's v19!). I really appreciate your
> contribution.
>
>
Thank you for your help and persistence in the review
process :)

Fixed bad naming and moved 'QemuUUID net_uuid'
definition into #if block in validate_options in v20.

Best Regards,
Vladislav Yaroshchuk

Regards,
> Akihiko Odaki
>
> > +
> > +#if defined(MAC_OS_VERSION_11_0) && \
> > +MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
> > +
> > +if (options->has_net_uuid &&
> > +qemu_uuid_parse(options->net_uuid, ) < 0) {
> > +error_setg(errp, "Invalid UUID provided in 'net-uuid'");
> > +return false;
> > +}
> > +#else
> > +if (options->has_isolated) {
> > +error_setg(errp,
> > +   "vmnet-host.isolated feature is "
> > +   "unavailable: outdated vmnet.framework API");
> > +return false;
> > +}
> > +
> > +if (options->has_net_uuid) {
> > +error_setg(errp,
> > +   "vmnet-host.net-uuid feature is "
> > +   "unavailable: outdated vmnet.framework API");
> > +return false;
> > +}
> > +#endif
> > +
> > +if ((options->has_start_address ||
> > + options->has_end_address ||
> > + options->has_subnet_mask) &&
> > +!(options->has_start_address &&
> > +  options->has_end_address &&
> > +  options->has_subnet_mask)) {
> > +error_setg(errp,
> > +   "'start-address', 'end-address', 'subnet-mask' "
> > +   "should be provided together");
> > +return false;
> > +}
> > +
> > +return true;
> > +}
> > +
> > +static xpc_object_t build_if_desc(const Netdev *netdev,
> > +  NetClientState *nc)
> > +{
> > +const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
> > +xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
> > +
> > +xpc_dictionary_set_uint64(if_desc,
> > +  vmnet_operation_mode_key,
> > +  VMNET_HOST_MODE);
> > +
> > +#if defined(MAC_OS_VERSION_11_0) && \
> > +MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
> > +
> > +xpc_dictionary_set_bool(if_desc,
> > +vmnet_enable_isolation_key,
> > +options->isolated);
> > +
> > +QemuUUID network_uuid;
> > +if (options->has_net_uuid) {
> > +qemu_uuid_parse(options->net_uuid, _uuid);
> > +xpc_dictionary_set_uuid(if_desc,
> > +vmnet_network_identifier_key,
> > + 

[PATCH v20 5/7] net/vmnet: implement bridged mode (vmnet-bridged)

2022-03-15 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-bridged.m | 128 ++--
 1 file changed, 123 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
index 91c1a2f2c7..5936c87718 100644
--- a/net/vmnet-bridged.m
+++ b/net/vmnet-bridged.m
@@ -10,16 +10,134 @@
 
 #include "qemu/osdep.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+
+static bool validate_ifname(const char *ifname)
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+bool match = false;
+if (!xpc_array_get_count(shared_if_list)) {
+goto done;
+}
+
+match = !xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+return strcmp(xpc_string_get_string_ptr(value), ifname) != 0;
+});
+
+done:
+xpc_release(shared_if_list);
+return match;
+}
+
+
+static bool get_valid_ifnames(char *output_buf)
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+__block const char *ifname = NULL;
+__block int str_offset = 0;
+bool interfaces_available = true;
+
+if (!xpc_array_get_count(shared_if_list)) {
+interfaces_available = false;
+goto done;
+}
+
+xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+/* build list of strings like "en0 en1 en2 " */
+ifname = xpc_string_get_string_ptr(value);
+strcpy(output_buf + str_offset, ifname);
+strcpy(output_buf + str_offset + strlen(ifname), " ");
+str_offset += strlen(ifname) + 1;
+return true;
+});
+
+done:
+xpc_release(shared_if_list);
+return interfaces_available;
+}
+
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+char ifnames[1024];
+
+if (!validate_ifname(options->ifname)) {
+if (get_valid_ifnames(ifnames)) {
+error_setg(errp,
+   "unsupported ifname '%s', expected one of [ %s]",
+   options->ifname,
+   ifnames);
+return false;
+}
+error_setg(errp,
+   "unsupported ifname '%s', no supported "
+   "interfaces available",
+   options->ifname);
+return false;
+}
+
+#if !defined(MAC_OS_VERSION_11_0) || \
+MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_11_0
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-bridged.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+return true;
+}
+
+
+static xpc_object_t build_if_desc(const Netdev *netdev)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_BRIDGED_MODE
+);
+
+xpc_dictionary_set_string(if_desc,
+  vmnet_shared_interface_name_key,
+  options->ifname);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+#endif
+return if_desc;
+}
+
+
+static NetClientInfo net_vmnet_bridged_info = {
+.type = NET_CLIENT_DRIVER_VMNET_BRIDGED,
+.size = sizeof(VmnetState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
+
 int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
NetClientState *peer, Error **errp)
 {
-  error_setg(errp, "vmnet-bridged is not implemented yet");
-  return -1;
+NetClientState *nc = qemu_new_net_client(_vmnet_bridged_info,
+ peer, "vmnet-bridged", name);
+if (!validate_options(netdev, errp)) {
+return -1;
+}
+return vmnet_if_create(nc, build_if_desc(netdev), errp);
 }
-- 
2.34.1.vfs.0.0




[PATCH v20 3/7] net/vmnet: implement shared mode (vmnet-shared)

2022-03-15 Thread Vladislav Yaroshchuk
Interaction with vmnet.framework in different modes
differs only on configuration stage, so we can create
common `send`, `receive`, etc. procedures and reuse them.

Signed-off-by: Phillip Tennen 
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-common.m | 358 +
 net/vmnet-shared.c |  90 +++-
 net/vmnet_int.h|  40 -
 3 files changed, 483 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-common.m b/net/vmnet-common.m
index 06326efb1c..2cb60b9ddd 100644
--- a/net/vmnet-common.m
+++ b/net/vmnet-common.m
@@ -10,6 +10,8 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "qemu/log.h"
 #include "qapi/qapi-types-net.h"
 #include "vmnet_int.h"
 #include "clients.h"
@@ -17,4 +19,360 @@
 #include "qapi/error.h"
 
 #include 
+#include 
 
+
+static void vmnet_send_completed(NetClientState *nc, ssize_t len);
+
+
+const char *vmnet_status_map_str(vmnet_return_t status)
+{
+switch (status) {
+case VMNET_SUCCESS:
+return "success";
+case VMNET_FAILURE:
+return "general failure (possibly not enough privileges)";
+case VMNET_MEM_FAILURE:
+return "memory allocation failure";
+case VMNET_INVALID_ARGUMENT:
+return "invalid argument specified";
+case VMNET_SETUP_INCOMPLETE:
+return "interface setup is not complete";
+case VMNET_INVALID_ACCESS:
+return "invalid access, permission denied";
+case VMNET_PACKET_TOO_BIG:
+return "packet size is larger than MTU";
+case VMNET_BUFFER_EXHAUSTED:
+return "buffers exhausted in kernel";
+case VMNET_TOO_MANY_PACKETS:
+return "packet count exceeds limit";
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+case VMNET_SHARING_SERVICE_BUSY:
+return "conflict, sharing service is in use";
+#endif
+default:
+return "unknown vmnet error";
+}
+}
+
+
+/**
+ * Write packets from QEMU to vmnet interface.
+ *
+ * vmnet.framework supports iov, but writing more than
+ * one iov into vmnet interface fails with
+ * 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
+ * one and passing it to vmnet works fine. That's the
+ * reason why receive_iov() left unimplemented. But it still
+ * works with good performance having .receive() only.
+ */
+ssize_t vmnet_receive_common(NetClientState *nc,
+ const uint8_t *buf,
+ size_t size)
+{
+VmnetState *s = DO_UPCAST(VmnetState, nc, nc);
+struct vmpktdesc packet;
+struct iovec iov;
+int pkt_cnt;
+vmnet_return_t if_status;
+
+if (size > s->max_packet_size) {
+warn_report("vmnet: packet is too big, %zu > %" PRIu64,
+packet.vm_pkt_size,
+s->max_packet_size);
+return -1;
+}
+
+iov.iov_base = (char *) buf;
+iov.iov_len = size;
+
+packet.vm_pkt_iovcnt = 1;
+packet.vm_flags = 0;
+packet.vm_pkt_size = size;
+packet.vm_pkt_iov = 
+pkt_cnt = 1;
+
+if_status = vmnet_write(s->vmnet_if, , _cnt);
+if (if_status != VMNET_SUCCESS) {
+error_report("vmnet: write error: %s\n",
+ vmnet_status_map_str(if_status));
+return -1;
+}
+
+if (pkt_cnt) {
+return size;
+}
+return 0;
+}
+
+
+/**
+ * Read packets from vmnet interface and write them
+ * to temporary buffers in VmnetState.
+ *
+ * Returns read packets number (may be 0) on success,
+ * -1 on error
+ */
+static int vmnet_read_packets(VmnetState *s)
+{
+assert(s->packets_send_current_pos == s->packets_send_end_pos);
+
+struct vmpktdesc *packets = s->packets_buf;
+vmnet_return_t status;
+int i;
+
+/* Read as many packets as present */
+s->packets_send_current_pos = 0;
+s->packets_send_end_pos = VMNET_PACKETS_LIMIT;
+for (i = 0; i < s->packets_send_end_pos; ++i) {
+packets[i].vm_pkt_size = s->max_packet_size;
+packets[i].vm_pkt_iovcnt = 1;
+packets[i].vm_flags = 0;
+}
+
+status = vmnet_read(s->vmnet_if, packets, >packets_send_end_pos);
+if (status != VMNET_SUCCESS) {
+error_printf("vmnet: read failed: %s\n",
+ vmnet_status_map_str(status));
+s->packets_send_current_pos = 0;
+s->packets_send_end_pos = 0;
+return -1;
+}
+return s->packets_send_end_pos;
+}
+
+
+/**
+ * Write packets from temporary buffers in VmnetState
+ * to QEMU.
+ */
+static void vmnet_write_packets_to_qemu(VmnetState *s)
+{
+while (s->packets_send_current_pos < s->packets_send_end_pos) {
+ssize_t size = qemu_send_packet_async(>nc,
+ 

[PATCH v20 2/7] net/vmnet: add vmnet backends to qapi/net

2022-03-15 Thread Vladislav Yaroshchuk
Create separate netdevs for each vmnet operating mode:
- vmnet-host
- vmnet-shared
- vmnet-bridged

Signed-off-by: Vladislav Yaroshchuk 
---
 net/clients.h   |  11 
 net/meson.build |   7 +++
 net/net.c   |  10 
 net/vmnet-bridged.m |  25 +
 net/vmnet-common.m  |  20 +++
 net/vmnet-host.c|  24 
 net/vmnet-shared.c  |  25 +
 net/vmnet_int.h |  25 +
 qapi/net.json   | 133 +++-
 9 files changed, 278 insertions(+), 2 deletions(-)
 create mode 100644 net/vmnet-bridged.m
 create mode 100644 net/vmnet-common.m
 create mode 100644 net/vmnet-host.c
 create mode 100644 net/vmnet-shared.c
 create mode 100644 net/vmnet_int.h

diff --git a/net/clients.h b/net/clients.h
index 92f9b59aed..c9157789f2 100644
--- a/net/clients.h
+++ b/net/clients.h
@@ -63,4 +63,15 @@ int net_init_vhost_user(const Netdev *netdev, const char 
*name,
 
 int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
 NetClientState *peer, Error **errp);
+#ifdef CONFIG_VMNET
+int net_init_vmnet_host(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_shared(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+#endif /* CONFIG_VMNET */
+
 #endif /* QEMU_NET_CLIENTS_H */
diff --git a/net/meson.build b/net/meson.build
index 847bc2ac85..00a88c4951 100644
--- a/net/meson.build
+++ b/net/meson.build
@@ -42,4 +42,11 @@ softmmu_ss.add(when: 'CONFIG_POSIX', if_true: 
files(tap_posix))
 softmmu_ss.add(when: 'CONFIG_WIN32', if_true: files('tap-win32.c'))
 softmmu_ss.add(when: 'CONFIG_VHOST_NET_VDPA', if_true: files('vhost-vdpa.c'))
 
+vmnet_files = files(
+  'vmnet-common.m',
+  'vmnet-bridged.m',
+  'vmnet-host.c',
+  'vmnet-shared.c'
+)
+softmmu_ss.add(when: vmnet, if_true: vmnet_files)
 subdir('can')
diff --git a/net/net.c b/net/net.c
index f0d14dbfc1..1dbb64b935 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1021,6 +1021,11 @@ static int (* const 
net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
 #ifdef CONFIG_L2TPV3
 [NET_CLIENT_DRIVER_L2TPV3]= net_init_l2tpv3,
 #endif
+#ifdef CONFIG_VMNET
+[NET_CLIENT_DRIVER_VMNET_HOST] = net_init_vmnet_host,
+[NET_CLIENT_DRIVER_VMNET_SHARED] = net_init_vmnet_shared,
+[NET_CLIENT_DRIVER_VMNET_BRIDGED] = net_init_vmnet_bridged,
+#endif /* CONFIG_VMNET */
 };
 
 
@@ -1106,6 +,11 @@ void show_netdevs(void)
 #endif
 #ifdef CONFIG_VHOST_VDPA
 "vhost-vdpa",
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host",
+"vmnet-shared",
+"vmnet-bridged",
 #endif
 };
 
diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
new file mode 100644
index 00..91c1a2f2c7
--- /dev/null
+++ b/net/vmnet-bridged.m
@@ -0,0 +1,25 @@
+/*
+ * vmnet-bridged.m
+ *
+ * Copyright(c) 2022 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+   NetClientState *peer, Error **errp)
+{
+  error_setg(errp, "vmnet-bridged is not implemented yet");
+  return -1;
+}
diff --git a/net/vmnet-common.m b/net/vmnet-common.m
new file mode 100644
index 00..06326efb1c
--- /dev/null
+++ b/net/vmnet-common.m
@@ -0,0 +1,20 @@
+/*
+ * vmnet-common.m - network client wrapper for Apple vmnet.framework
+ *
+ * Copyright(c) 2022 Vladislav Yaroshchuk 
+ * Copyright(c) 2021 Phillip Tennen 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
diff --git a/net/vmnet-host.c b/net/vmnet-host.c
new file mode 100644
index 00..a461d507c5
--- /dev/null
+++ b/net/vmnet-host.c
@@ -0,0 +1,24 @@
+/*
+ * vmnet-host.c
+ *
+ * Copyright(c) 2022 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qa

[PATCH v20 7/7] net/vmnet: update hmp-commands.hx

2022-03-15 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 hmp-commands.hx | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 8476277aa9..8f3d78f177 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1265,7 +1265,11 @@ ERST
 {
 .name   = "netdev_add",
 .args_type  = "netdev:O",
-.params = 
"[user|tap|socket|vde|bridge|hubport|netmap|vhost-user],id=str[,prop=value][,...]",
+.params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user"
+#ifdef CONFIG_VMNET
+  "|vmnet-host|vmnet-shared|vmnet-bridged"
+#endif
+  "],id=str[,prop=value][,...]",
 .help   = "add host network device",
 .cmd= hmp_netdev_add,
 .command_completion = netdev_add_completion,
-- 
2.34.1.vfs.0.0




[PATCH v20 6/7] net/vmnet: update qemu-options.hx

2022-03-15 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 qemu-options.hx | 25 +
 1 file changed, 25 insertions(+)

diff --git a/qemu-options.hx b/qemu-options.hx
index 5ce0ada75e..ea00d0eeb6 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2743,6 +2743,25 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
 #ifdef __linux__
 "-netdev vhost-vdpa,id=str,vhostdev=/path/to/dev\n"
 "configure a vhost-vdpa network,Establish a vhost-vdpa 
netdev\n"
+#endif
+#ifdef CONFIG_VMNET
+"-netdev vmnet-host,id=str[,isolated=on|off][,net-uuid=uuid]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in host mode with ID 
'str',\n"
+"isolate this interface from others with 'isolated',\n"
+"configure the address range and choose a subnet mask,\n"
+"specify network UUID 'uuid' to disable DHCP and interact 
with\n"
+"vmnet-host interfaces within this isolated network\n"
+"-netdev vmnet-shared,id=str[,isolated=on|off][,nat66-prefix=addr]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in shared mode with ID 
'str',\n"
+"configure the address range and choose a subnet mask,\n"
+"set IPv6 ULA prefix (of length 64) to use for internal 
network,\n"
+"isolate this interface from others with 'isolated'\n"
+"-netdev vmnet-bridged,id=str,ifname=name[,isolated=on|off]\n"
+"configure a vmnet network backend in bridged mode with ID 
'str',\n"
+"use 'ifname=name' to select a physical network interface 
to be bridged,\n"
+"isolate this interface from others with 'isolated'\n"
 #endif
 "-netdev hubport,id=str,hubid=n[,netdev=nd]\n"
 "configure a hub port on the hub with ID 'n'\n", 
QEMU_ARCH_ALL)
@@ -2762,6 +2781,9 @@ DEF("nic", HAS_ARG, QEMU_OPTION_nic,
 #endif
 #ifdef CONFIG_POSIX
 "vhost-user|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,...][mac=macaddr]\n"
 "initialize an on-board / default host NIC (using MAC 
address\n"
@@ -2784,6 +2806,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
 #endif
 #ifdef CONFIG_NETMAP
 "netmap|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,option][,...]\n"
 "old way to initialize a host network interface\n"
-- 
2.34.1.vfs.0.0




[PATCH v20 0/7] Add vmnet.framework based network backend

2022-03-15 Thread Vladislav Yaroshchuk
r proper printing
 - NOTE: This version of patch series may be one the last
   I submit - JetBrains has suspended operations in
   Russia indefinitely due to all the awful things happened
   the last weeks. I may leave this company and loose the
   ability to work on vmnet support :(
   It will be perfect if someone can handle my unfinished work,
   if something required to fix/improve is found.
   Because of this, MAINTAINERS list update is dropped
v16 -> v17
 - host: move network_uuid to local variable
 - common: refactor, add documentation
 - common/send (vmnet->qemu): read new packets after QEMU
   send_cb invoked
 - common/receive (qemu->vmnet): drop redundant vmnet
   status checks
 - restore dropped commit messaged from the previous series
v17 -> v18
 - use VmnetState struct for all three operation modes
 - drop send_enabled flag
 - do not unregister vmnet event callback on cleanup,
   let vmnet.framework do everything itself while interface
   destruction
v18 -> v19
 - use positive pointers values to describe unsent packets
   window of VmnetState buffer
v19 -> v20
 - vmnet-host: minor but required refactor

Vladislav Yaroshchuk (7):
  net/vmnet: add vmnet dependency and customizable option
  net/vmnet: add vmnet backends to qapi/net
  net/vmnet: implement shared mode (vmnet-shared)
  net/vmnet: implement host mode (vmnet-host)
  net/vmnet: implement bridged mode (vmnet-bridged)
  net/vmnet: update qemu-options.hx
  net/vmnet: update hmp-commands.hx

 hmp-commands.hx   |   6 +-
 meson.build   |  16 +-
 meson_options.txt |   2 +
 net/clients.h |  11 +
 net/meson.build   |   7 +
 net/net.c |  10 +
 net/vmnet-bridged.m   | 143 +
 net/vmnet-common.m| 378 ++
 net/vmnet-host.c  | 121 +++
 net/vmnet-shared.c| 107 ++
 net/vmnet_int.h   |  63 ++
 qapi/net.json | 133 +++-
 qemu-options.hx   |  25 +++
 scripts/meson-buildoptions.sh |   1 +
 14 files changed, 1019 insertions(+), 4 deletions(-)
 create mode 100644 net/vmnet-bridged.m
 create mode 100644 net/vmnet-common.m
 create mode 100644 net/vmnet-host.c
 create mode 100644 net/vmnet-shared.c
 create mode 100644 net/vmnet_int.h

-- 
2.34.1.vfs.0.0




[PATCH v20 4/7] net/vmnet: implement host mode (vmnet-host)

2022-03-15 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-host.c | 109 ---
 1 file changed, 103 insertions(+), 6 deletions(-)

diff --git a/net/vmnet-host.c b/net/vmnet-host.c
index a461d507c5..e6d01fd65e 100644
--- a/net/vmnet-host.c
+++ b/net/vmnet-host.c
@@ -9,16 +9,113 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/uuid.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+QemuUUID net_uuid;
+if (options->has_net_uuid &&
+qemu_uuid_parse(options->net_uuid, _uuid) < 0) {
+error_setg(errp, "Invalid UUID provided in 'net-uuid'");
+return false;
+}
+#else
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-host.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+
+if (options->has_net_uuid) {
+error_setg(errp,
+   "vmnet-host.net-uuid feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+
+if ((options->has_start_address ||
+ options->has_end_address ||
+ options->has_subnet_mask) &&
+!(options->has_start_address &&
+  options->has_end_address &&
+  options->has_subnet_mask)) {
+error_setg(errp,
+   "'start-address', 'end-address', 'subnet-mask' "
+   "should be provided together");
+return false;
+}
+
+return true;
+}
+
+static xpc_object_t build_if_desc(const Netdev *netdev)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_HOST_MODE);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+
+QemuUUID net_uuid;
+if (options->has_net_uuid) {
+qemu_uuid_parse(options->net_uuid, _uuid);
+xpc_dictionary_set_uuid(if_desc,
+vmnet_network_identifier_key,
+net_uuid.data);
+}
+#endif
+
+if (options->has_start_address) {
+xpc_dictionary_set_string(if_desc,
+  vmnet_start_address_key,
+  options->start_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_end_address_key,
+  options->end_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_subnet_mask_key,
+  options->subnet_mask);
+}
+
+return if_desc;
+}
+
+static NetClientInfo net_vmnet_host_info = {
+.type = NET_CLIENT_DRIVER_VMNET_HOST,
+.size = sizeof(VmnetState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
 int net_init_vmnet_host(const Netdev *netdev, const char *name,
-NetClientState *peer, Error **errp) {
-  error_setg(errp, "vmnet-host is not implemented yet");
-  return -1;
+NetClientState *peer, Error **errp)
+{
+NetClientState *nc = qemu_new_net_client(_vmnet_host_info,
+ peer, "vmnet-host", name);
+if (!validate_options(netdev, errp)) {
+return -1;
+}
+return vmnet_if_create(nc, build_if_desc(netdev), errp);
 }
-- 
2.34.1.vfs.0.0




[PATCH v20 1/7] net/vmnet: add vmnet dependency and customizable option

2022-03-15 Thread Vladislav Yaroshchuk
vmnet.framework dependency is added with 'vmnet' option
to enable or disable it. Default value is 'auto'.

used vmnet features are available since macOS 11.0,
but new backend can be built and work properly with
subset of them on 10.15 too.

Signed-off-by: Vladislav Yaroshchuk 
---
 meson.build   | 16 +++-
 meson_options.txt |  2 ++
 scripts/meson-buildoptions.sh |  1 +
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index 2d6601467f..806f3869f9 100644
--- a/meson.build
+++ b/meson.build
@@ -522,6 +522,18 @@ if cocoa.found() and get_option('gtk').enabled()
   error('Cocoa and GTK+ cannot be enabled at the same time')
 endif
 
+vmnet = dependency('appleframeworks', modules: 'vmnet', required: 
get_option('vmnet'))
+if vmnet.found() and not cc.has_header_symbol('vmnet/vmnet.h',
+  'VMNET_BRIDGED_MODE',
+  dependencies: vmnet)
+  vmnet = not_found
+  if get_option('vmnet').enabled()
+error('vmnet.framework API is outdated')
+  else
+warning('vmnet.framework API is outdated, disabling')
+  endif
+endif
+
 seccomp = not_found
 if not get_option('seccomp').auto() or have_system or have_tools
   seccomp = dependency('libseccomp', version: '>=2.3.0',
@@ -1550,6 +1562,7 @@ config_host_data.set('CONFIG_SNAPPY', snappy.found())
 config_host_data.set('CONFIG_TPM', have_tpm)
 config_host_data.set('CONFIG_USB_LIBUSB', libusb.found())
 config_host_data.set('CONFIG_VDE', vde.found())
+config_host_data.set('CONFIG_VMNET', vmnet.found())
 config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', 
have_vhost_user_blk_server)
 config_host_data.set('CONFIG_VNC', vnc.found())
 config_host_data.set('CONFIG_VNC_JPEG', jpeg.found())
@@ -3588,7 +3601,8 @@ summary(summary_info, bool_yn: true, section: 'Crypto')
 # Libraries
 summary_info = {}
 if targetos == 'darwin'
-  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'vmnet.framework support': vmnet}
 endif
 summary_info += {'SDL support':   sdl}
 summary_info += {'SDL image support': sdl_image}
diff --git a/meson_options.txt b/meson_options.txt
index 52b11cead4..d2c0b6b412 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -175,6 +175,8 @@ option('netmap', type : 'feature', value : 'auto',
description: 'netmap network backend support')
 option('vde', type : 'feature', value : 'auto',
description: 'vde network backend support')
+option('vmnet', type : 'feature', value : 'auto',
+   description: 'vmnet.framework network backend support')
 option('virglrenderer', type : 'feature', value : 'auto',
description: 'virgl rendering support')
 option('vnc', type : 'feature', value : 'auto',
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 9ee684ef03..30946f3798 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -116,6 +116,7 @@ meson_options_help() {
   printf "%s\n" '  usb-redir   libusbredir support'
   printf "%s\n" '  vde vde network backend support'
   printf "%s\n" '  vdi vdi image format support'
+  printf "%s\n" '  vmnet   vmnet.framework network backend support'
   printf "%s\n" '  vhost-user-blk-server'
   printf "%s\n" '  build vhost-user-blk server'
   printf "%s\n" '  virglrenderer   virgl rendering support'
-- 
2.34.1.vfs.0.0




[PATCH v19 7/7] net/vmnet: update hmp-commands.hx

2022-03-15 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 hmp-commands.hx | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 8476277aa9..8f3d78f177 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1265,7 +1265,11 @@ ERST
 {
 .name   = "netdev_add",
 .args_type  = "netdev:O",
-.params = 
"[user|tap|socket|vde|bridge|hubport|netmap|vhost-user],id=str[,prop=value][,...]",
+.params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user"
+#ifdef CONFIG_VMNET
+  "|vmnet-host|vmnet-shared|vmnet-bridged"
+#endif
+  "],id=str[,prop=value][,...]",
 .help   = "add host network device",
 .cmd= hmp_netdev_add,
 .command_completion = netdev_add_completion,
-- 
2.34.1.vfs.0.0




[PATCH v19 5/7] net/vmnet: implement bridged mode (vmnet-bridged)

2022-03-15 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-bridged.m | 128 ++--
 1 file changed, 123 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
index 91c1a2f2c7..5936c87718 100644
--- a/net/vmnet-bridged.m
+++ b/net/vmnet-bridged.m
@@ -10,16 +10,134 @@
 
 #include "qemu/osdep.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+
+static bool validate_ifname(const char *ifname)
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+bool match = false;
+if (!xpc_array_get_count(shared_if_list)) {
+goto done;
+}
+
+match = !xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+return strcmp(xpc_string_get_string_ptr(value), ifname) != 0;
+});
+
+done:
+xpc_release(shared_if_list);
+return match;
+}
+
+
+static bool get_valid_ifnames(char *output_buf)
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+__block const char *ifname = NULL;
+__block int str_offset = 0;
+bool interfaces_available = true;
+
+if (!xpc_array_get_count(shared_if_list)) {
+interfaces_available = false;
+goto done;
+}
+
+xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+/* build list of strings like "en0 en1 en2 " */
+ifname = xpc_string_get_string_ptr(value);
+strcpy(output_buf + str_offset, ifname);
+strcpy(output_buf + str_offset + strlen(ifname), " ");
+str_offset += strlen(ifname) + 1;
+return true;
+});
+
+done:
+xpc_release(shared_if_list);
+return interfaces_available;
+}
+
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+char ifnames[1024];
+
+if (!validate_ifname(options->ifname)) {
+if (get_valid_ifnames(ifnames)) {
+error_setg(errp,
+   "unsupported ifname '%s', expected one of [ %s]",
+   options->ifname,
+   ifnames);
+return false;
+}
+error_setg(errp,
+   "unsupported ifname '%s', no supported "
+   "interfaces available",
+   options->ifname);
+return false;
+}
+
+#if !defined(MAC_OS_VERSION_11_0) || \
+MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_11_0
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-bridged.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+return true;
+}
+
+
+static xpc_object_t build_if_desc(const Netdev *netdev)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_BRIDGED_MODE
+);
+
+xpc_dictionary_set_string(if_desc,
+  vmnet_shared_interface_name_key,
+  options->ifname);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+#endif
+return if_desc;
+}
+
+
+static NetClientInfo net_vmnet_bridged_info = {
+.type = NET_CLIENT_DRIVER_VMNET_BRIDGED,
+.size = sizeof(VmnetState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
+
 int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
NetClientState *peer, Error **errp)
 {
-  error_setg(errp, "vmnet-bridged is not implemented yet");
-  return -1;
+NetClientState *nc = qemu_new_net_client(_vmnet_bridged_info,
+ peer, "vmnet-bridged", name);
+if (!validate_options(netdev, errp)) {
+return -1;
+}
+return vmnet_if_create(nc, build_if_desc(netdev), errp);
 }
-- 
2.34.1.vfs.0.0




[PATCH v19 2/7] net/vmnet: add vmnet backends to qapi/net

2022-03-15 Thread Vladislav Yaroshchuk
Create separate netdevs for each vmnet operating mode:
- vmnet-host
- vmnet-shared
- vmnet-bridged

Signed-off-by: Vladislav Yaroshchuk 
---
 net/clients.h   |  11 
 net/meson.build |   7 +++
 net/net.c   |  10 
 net/vmnet-bridged.m |  25 +
 net/vmnet-common.m  |  20 +++
 net/vmnet-host.c|  24 
 net/vmnet-shared.c  |  25 +
 net/vmnet_int.h |  25 +
 qapi/net.json   | 133 +++-
 9 files changed, 278 insertions(+), 2 deletions(-)
 create mode 100644 net/vmnet-bridged.m
 create mode 100644 net/vmnet-common.m
 create mode 100644 net/vmnet-host.c
 create mode 100644 net/vmnet-shared.c
 create mode 100644 net/vmnet_int.h

diff --git a/net/clients.h b/net/clients.h
index 92f9b59aed..c9157789f2 100644
--- a/net/clients.h
+++ b/net/clients.h
@@ -63,4 +63,15 @@ int net_init_vhost_user(const Netdev *netdev, const char 
*name,
 
 int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
 NetClientState *peer, Error **errp);
+#ifdef CONFIG_VMNET
+int net_init_vmnet_host(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_shared(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+#endif /* CONFIG_VMNET */
+
 #endif /* QEMU_NET_CLIENTS_H */
diff --git a/net/meson.build b/net/meson.build
index 847bc2ac85..00a88c4951 100644
--- a/net/meson.build
+++ b/net/meson.build
@@ -42,4 +42,11 @@ softmmu_ss.add(when: 'CONFIG_POSIX', if_true: 
files(tap_posix))
 softmmu_ss.add(when: 'CONFIG_WIN32', if_true: files('tap-win32.c'))
 softmmu_ss.add(when: 'CONFIG_VHOST_NET_VDPA', if_true: files('vhost-vdpa.c'))
 
+vmnet_files = files(
+  'vmnet-common.m',
+  'vmnet-bridged.m',
+  'vmnet-host.c',
+  'vmnet-shared.c'
+)
+softmmu_ss.add(when: vmnet, if_true: vmnet_files)
 subdir('can')
diff --git a/net/net.c b/net/net.c
index f0d14dbfc1..1dbb64b935 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1021,6 +1021,11 @@ static int (* const 
net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
 #ifdef CONFIG_L2TPV3
 [NET_CLIENT_DRIVER_L2TPV3]= net_init_l2tpv3,
 #endif
+#ifdef CONFIG_VMNET
+[NET_CLIENT_DRIVER_VMNET_HOST] = net_init_vmnet_host,
+[NET_CLIENT_DRIVER_VMNET_SHARED] = net_init_vmnet_shared,
+[NET_CLIENT_DRIVER_VMNET_BRIDGED] = net_init_vmnet_bridged,
+#endif /* CONFIG_VMNET */
 };
 
 
@@ -1106,6 +,11 @@ void show_netdevs(void)
 #endif
 #ifdef CONFIG_VHOST_VDPA
 "vhost-vdpa",
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host",
+"vmnet-shared",
+"vmnet-bridged",
 #endif
 };
 
diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
new file mode 100644
index 00..91c1a2f2c7
--- /dev/null
+++ b/net/vmnet-bridged.m
@@ -0,0 +1,25 @@
+/*
+ * vmnet-bridged.m
+ *
+ * Copyright(c) 2022 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+   NetClientState *peer, Error **errp)
+{
+  error_setg(errp, "vmnet-bridged is not implemented yet");
+  return -1;
+}
diff --git a/net/vmnet-common.m b/net/vmnet-common.m
new file mode 100644
index 00..06326efb1c
--- /dev/null
+++ b/net/vmnet-common.m
@@ -0,0 +1,20 @@
+/*
+ * vmnet-common.m - network client wrapper for Apple vmnet.framework
+ *
+ * Copyright(c) 2022 Vladislav Yaroshchuk 
+ * Copyright(c) 2021 Phillip Tennen 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
diff --git a/net/vmnet-host.c b/net/vmnet-host.c
new file mode 100644
index 00..a461d507c5
--- /dev/null
+++ b/net/vmnet-host.c
@@ -0,0 +1,24 @@
+/*
+ * vmnet-host.c
+ *
+ * Copyright(c) 2022 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qa

[PATCH v19 6/7] net/vmnet: update qemu-options.hx

2022-03-15 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 qemu-options.hx | 25 +
 1 file changed, 25 insertions(+)

diff --git a/qemu-options.hx b/qemu-options.hx
index 5ce0ada75e..ea00d0eeb6 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2743,6 +2743,25 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
 #ifdef __linux__
 "-netdev vhost-vdpa,id=str,vhostdev=/path/to/dev\n"
 "configure a vhost-vdpa network,Establish a vhost-vdpa 
netdev\n"
+#endif
+#ifdef CONFIG_VMNET
+"-netdev vmnet-host,id=str[,isolated=on|off][,net-uuid=uuid]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in host mode with ID 
'str',\n"
+"isolate this interface from others with 'isolated',\n"
+"configure the address range and choose a subnet mask,\n"
+"specify network UUID 'uuid' to disable DHCP and interact 
with\n"
+"vmnet-host interfaces within this isolated network\n"
+"-netdev vmnet-shared,id=str[,isolated=on|off][,nat66-prefix=addr]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in shared mode with ID 
'str',\n"
+"configure the address range and choose a subnet mask,\n"
+"set IPv6 ULA prefix (of length 64) to use for internal 
network,\n"
+"isolate this interface from others with 'isolated'\n"
+"-netdev vmnet-bridged,id=str,ifname=name[,isolated=on|off]\n"
+"configure a vmnet network backend in bridged mode with ID 
'str',\n"
+"use 'ifname=name' to select a physical network interface 
to be bridged,\n"
+"isolate this interface from others with 'isolated'\n"
 #endif
 "-netdev hubport,id=str,hubid=n[,netdev=nd]\n"
 "configure a hub port on the hub with ID 'n'\n", 
QEMU_ARCH_ALL)
@@ -2762,6 +2781,9 @@ DEF("nic", HAS_ARG, QEMU_OPTION_nic,
 #endif
 #ifdef CONFIG_POSIX
 "vhost-user|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,...][mac=macaddr]\n"
 "initialize an on-board / default host NIC (using MAC 
address\n"
@@ -2784,6 +2806,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
 #endif
 #ifdef CONFIG_NETMAP
 "netmap|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,option][,...]\n"
 "old way to initialize a host network interface\n"
-- 
2.34.1.vfs.0.0




[PATCH v19 4/7] net/vmnet: implement host mode (vmnet-host)

2022-03-15 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-host.c | 110 ---
 1 file changed, 104 insertions(+), 6 deletions(-)

diff --git a/net/vmnet-host.c b/net/vmnet-host.c
index a461d507c5..8f7a638967 100644
--- a/net/vmnet-host.c
+++ b/net/vmnet-host.c
@@ -9,16 +9,114 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/uuid.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+QemuUUID uuid;
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+if (options->has_net_uuid &&
+qemu_uuid_parse(options->net_uuid, ) < 0) {
+error_setg(errp, "Invalid UUID provided in 'net-uuid'");
+return false;
+}
+#else
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-host.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+
+if (options->has_net_uuid) {
+error_setg(errp,
+   "vmnet-host.net-uuid feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+
+if ((options->has_start_address ||
+ options->has_end_address ||
+ options->has_subnet_mask) &&
+!(options->has_start_address &&
+  options->has_end_address &&
+  options->has_subnet_mask)) {
+error_setg(errp,
+   "'start-address', 'end-address', 'subnet-mask' "
+   "should be provided together");
+return false;
+}
+
+return true;
+}
+
+static xpc_object_t build_if_desc(const Netdev *netdev,
+  NetClientState *nc)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_HOST_MODE);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+
+QemuUUID network_uuid;
+if (options->has_net_uuid) {
+qemu_uuid_parse(options->net_uuid, _uuid);
+xpc_dictionary_set_uuid(if_desc,
+vmnet_network_identifier_key,
+network_uuid.data);
+}
+#endif
+
+if (options->has_start_address) {
+xpc_dictionary_set_string(if_desc,
+  vmnet_start_address_key,
+  options->start_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_end_address_key,
+  options->end_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_subnet_mask_key,
+  options->subnet_mask);
+}
+
+return if_desc;
+}
+
+static NetClientInfo net_vmnet_host_info = {
+.type = NET_CLIENT_DRIVER_VMNET_HOST,
+.size = sizeof(VmnetState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
 int net_init_vmnet_host(const Netdev *netdev, const char *name,
-NetClientState *peer, Error **errp) {
-  error_setg(errp, "vmnet-host is not implemented yet");
-  return -1;
+NetClientState *peer, Error **errp)
+{
+NetClientState *nc = qemu_new_net_client(_vmnet_host_info,
+ peer, "vmnet-host", name);
+if (!validate_options(netdev, errp)) {
+return -1;
+}
+return vmnet_if_create(nc, build_if_desc(netdev, nc), errp);
 }
-- 
2.34.1.vfs.0.0




[PATCH v19 3/7] net/vmnet: implement shared mode (vmnet-shared)

2022-03-15 Thread Vladislav Yaroshchuk
Interaction with vmnet.framework in different modes
differs only on configuration stage, so we can create
common `send`, `receive`, etc. procedures and reuse them.

Signed-off-by: Phillip Tennen 
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-common.m | 358 +
 net/vmnet-shared.c |  90 +++-
 net/vmnet_int.h|  40 -
 3 files changed, 483 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-common.m b/net/vmnet-common.m
index 06326efb1c..2cb60b9ddd 100644
--- a/net/vmnet-common.m
+++ b/net/vmnet-common.m
@@ -10,6 +10,8 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "qemu/log.h"
 #include "qapi/qapi-types-net.h"
 #include "vmnet_int.h"
 #include "clients.h"
@@ -17,4 +19,360 @@
 #include "qapi/error.h"
 
 #include 
+#include 
 
+
+static void vmnet_send_completed(NetClientState *nc, ssize_t len);
+
+
+const char *vmnet_status_map_str(vmnet_return_t status)
+{
+switch (status) {
+case VMNET_SUCCESS:
+return "success";
+case VMNET_FAILURE:
+return "general failure (possibly not enough privileges)";
+case VMNET_MEM_FAILURE:
+return "memory allocation failure";
+case VMNET_INVALID_ARGUMENT:
+return "invalid argument specified";
+case VMNET_SETUP_INCOMPLETE:
+return "interface setup is not complete";
+case VMNET_INVALID_ACCESS:
+return "invalid access, permission denied";
+case VMNET_PACKET_TOO_BIG:
+return "packet size is larger than MTU";
+case VMNET_BUFFER_EXHAUSTED:
+return "buffers exhausted in kernel";
+case VMNET_TOO_MANY_PACKETS:
+return "packet count exceeds limit";
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+case VMNET_SHARING_SERVICE_BUSY:
+return "conflict, sharing service is in use";
+#endif
+default:
+return "unknown vmnet error";
+}
+}
+
+
+/**
+ * Write packets from QEMU to vmnet interface.
+ *
+ * vmnet.framework supports iov, but writing more than
+ * one iov into vmnet interface fails with
+ * 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
+ * one and passing it to vmnet works fine. That's the
+ * reason why receive_iov() left unimplemented. But it still
+ * works with good performance having .receive() only.
+ */
+ssize_t vmnet_receive_common(NetClientState *nc,
+ const uint8_t *buf,
+ size_t size)
+{
+VmnetState *s = DO_UPCAST(VmnetState, nc, nc);
+struct vmpktdesc packet;
+struct iovec iov;
+int pkt_cnt;
+vmnet_return_t if_status;
+
+if (size > s->max_packet_size) {
+warn_report("vmnet: packet is too big, %zu > %" PRIu64,
+packet.vm_pkt_size,
+s->max_packet_size);
+return -1;
+}
+
+iov.iov_base = (char *) buf;
+iov.iov_len = size;
+
+packet.vm_pkt_iovcnt = 1;
+packet.vm_flags = 0;
+packet.vm_pkt_size = size;
+packet.vm_pkt_iov = 
+pkt_cnt = 1;
+
+if_status = vmnet_write(s->vmnet_if, , _cnt);
+if (if_status != VMNET_SUCCESS) {
+error_report("vmnet: write error: %s\n",
+ vmnet_status_map_str(if_status));
+return -1;
+}
+
+if (pkt_cnt) {
+return size;
+}
+return 0;
+}
+
+
+/**
+ * Read packets from vmnet interface and write them
+ * to temporary buffers in VmnetState.
+ *
+ * Returns read packets number (may be 0) on success,
+ * -1 on error
+ */
+static int vmnet_read_packets(VmnetState *s)
+{
+assert(s->packets_send_current_pos == s->packets_send_end_pos);
+
+struct vmpktdesc *packets = s->packets_buf;
+vmnet_return_t status;
+int i;
+
+/* Read as many packets as present */
+s->packets_send_current_pos = 0;
+s->packets_send_end_pos = VMNET_PACKETS_LIMIT;
+for (i = 0; i < s->packets_send_end_pos; ++i) {
+packets[i].vm_pkt_size = s->max_packet_size;
+packets[i].vm_pkt_iovcnt = 1;
+packets[i].vm_flags = 0;
+}
+
+status = vmnet_read(s->vmnet_if, packets, >packets_send_end_pos);
+if (status != VMNET_SUCCESS) {
+error_printf("vmnet: read failed: %s\n",
+ vmnet_status_map_str(status));
+s->packets_send_current_pos = 0;
+s->packets_send_end_pos = 0;
+return -1;
+}
+return s->packets_send_end_pos;
+}
+
+
+/**
+ * Write packets from temporary buffers in VmnetState
+ * to QEMU.
+ */
+static void vmnet_write_packets_to_qemu(VmnetState *s)
+{
+while (s->packets_send_current_pos < s->packets_send_end_pos) {
+ssize_t size = qemu_send_packet_async(>nc,
+ 

[PATCH v19 1/7] net/vmnet: add vmnet dependency and customizable option

2022-03-15 Thread Vladislav Yaroshchuk
vmnet.framework dependency is added with 'vmnet' option
to enable or disable it. Default value is 'auto'.

used vmnet features are available since macOS 11.0,
but new backend can be built and work properly with
subset of them on 10.15 too.

Signed-off-by: Vladislav Yaroshchuk 
---
 meson.build   | 16 +++-
 meson_options.txt |  2 ++
 scripts/meson-buildoptions.sh |  1 +
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index 2d6601467f..806f3869f9 100644
--- a/meson.build
+++ b/meson.build
@@ -522,6 +522,18 @@ if cocoa.found() and get_option('gtk').enabled()
   error('Cocoa and GTK+ cannot be enabled at the same time')
 endif
 
+vmnet = dependency('appleframeworks', modules: 'vmnet', required: 
get_option('vmnet'))
+if vmnet.found() and not cc.has_header_symbol('vmnet/vmnet.h',
+  'VMNET_BRIDGED_MODE',
+  dependencies: vmnet)
+  vmnet = not_found
+  if get_option('vmnet').enabled()
+error('vmnet.framework API is outdated')
+  else
+warning('vmnet.framework API is outdated, disabling')
+  endif
+endif
+
 seccomp = not_found
 if not get_option('seccomp').auto() or have_system or have_tools
   seccomp = dependency('libseccomp', version: '>=2.3.0',
@@ -1550,6 +1562,7 @@ config_host_data.set('CONFIG_SNAPPY', snappy.found())
 config_host_data.set('CONFIG_TPM', have_tpm)
 config_host_data.set('CONFIG_USB_LIBUSB', libusb.found())
 config_host_data.set('CONFIG_VDE', vde.found())
+config_host_data.set('CONFIG_VMNET', vmnet.found())
 config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', 
have_vhost_user_blk_server)
 config_host_data.set('CONFIG_VNC', vnc.found())
 config_host_data.set('CONFIG_VNC_JPEG', jpeg.found())
@@ -3588,7 +3601,8 @@ summary(summary_info, bool_yn: true, section: 'Crypto')
 # Libraries
 summary_info = {}
 if targetos == 'darwin'
-  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'vmnet.framework support': vmnet}
 endif
 summary_info += {'SDL support':   sdl}
 summary_info += {'SDL image support': sdl_image}
diff --git a/meson_options.txt b/meson_options.txt
index 52b11cead4..d2c0b6b412 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -175,6 +175,8 @@ option('netmap', type : 'feature', value : 'auto',
description: 'netmap network backend support')
 option('vde', type : 'feature', value : 'auto',
description: 'vde network backend support')
+option('vmnet', type : 'feature', value : 'auto',
+   description: 'vmnet.framework network backend support')
 option('virglrenderer', type : 'feature', value : 'auto',
description: 'virgl rendering support')
 option('vnc', type : 'feature', value : 'auto',
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 9ee684ef03..30946f3798 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -116,6 +116,7 @@ meson_options_help() {
   printf "%s\n" '  usb-redir   libusbredir support'
   printf "%s\n" '  vde vde network backend support'
   printf "%s\n" '  vdi vdi image format support'
+  printf "%s\n" '  vmnet   vmnet.framework network backend support'
   printf "%s\n" '  vhost-user-blk-server'
   printf "%s\n" '  build vhost-user-blk server'
   printf "%s\n" '  virglrenderer   virgl rendering support'
-- 
2.34.1.vfs.0.0




[PATCH v19 0/7] Add vmnet.framework based network backend

2022-03-15 Thread Vladislav Yaroshchuk
r proper printing
 - NOTE: This version of patch series may be one the last
   I submit - JetBrains has suspended operations in
   Russia indefinitely due to all the awful things happened
   the last weeks. I may leave this company and loose the
   ability to work on vmnet support :(
   It will be perfect if someone can handle my unfinished work,
   if something required to fix/improve is found.
   Because of this, MAINTAINERS list update is dropped
v16 -> v17
 - host: move network_uuid to local variable
 - common: refactor, add documentation
 - common/send (vmnet->qemu): read new packets after QEMU
   send_cb invoked
 - common/receive (qemu->vmnet): drop redundant vmnet
   status checks
 - restore dropped commit messaged from the previous series
v17 -> v18
 - use VmnetState struct for all three operation modes
 - drop send_enabled flag
 - do not unregister vmnet event callback on cleanup,
   let vmnet.framework do everything itself while interface
   destruction
v18 -> v19
 - use positive pointers values to describe unsent packets
   window of VmnetState buffer

Vladislav Yaroshchuk (7):
  net/vmnet: add vmnet dependency and customizable option
  net/vmnet: add vmnet backends to qapi/net
  net/vmnet: implement shared mode (vmnet-shared)
  net/vmnet: implement host mode (vmnet-host)
  net/vmnet: implement bridged mode (vmnet-bridged)
  net/vmnet: update qemu-options.hx
  net/vmnet: update hmp-commands.hx

 hmp-commands.hx   |   6 +-
 meson.build   |  16 +-
 meson_options.txt |   2 +
 net/clients.h |  11 +
 net/meson.build   |   7 +
 net/net.c |  10 +
 net/vmnet-bridged.m   | 143 +
 net/vmnet-common.m| 378 ++
 net/vmnet-host.c  | 122 +++
 net/vmnet-shared.c| 107 ++
 net/vmnet_int.h   |  63 ++
 qapi/net.json | 133 +++-
 qemu-options.hx   |  25 +++
 scripts/meson-buildoptions.sh |   1 +
 14 files changed, 1020 insertions(+), 4 deletions(-)
 create mode 100644 net/vmnet-bridged.m
 create mode 100644 net/vmnet-common.m
 create mode 100644 net/vmnet-host.c
 create mode 100644 net/vmnet-shared.c
 create mode 100644 net/vmnet_int.h

-- 
2.34.1.vfs.0.0




Re: [PATCH v18 3/7] net/vmnet: implement shared mode (vmnet-shared)

2022-03-15 Thread Vladislav Yaroshchuk
On Tue, Mar 15, 2022 at 11:07 PM Akihiko Odaki 
wrote:

> On 2022/03/16 4:59, Vladislav Yaroshchuk wrote:
> > Interaction with vmnet.framework in different modes
> > differs only on configuration stage, so we can create
> > common `send`, `receive`, etc. procedures and reuse them.
> >
> > Signed-off-by: Phillip Tennen 
> > Signed-off-by: Vladislav Yaroshchuk 
> > ---
> >   net/vmnet-common.m | 368 +
> >   net/vmnet-shared.c |  90 ++-
> >   net/vmnet_int.h|  40 -
> >   3 files changed, 493 insertions(+), 5 deletions(-)
> >
> > diff --git a/net/vmnet-common.m b/net/vmnet-common.m
> > index 06326efb1c..b9dac7b241 100644
> > --- a/net/vmnet-common.m
> > +++ b/net/vmnet-common.m
> > @@ -10,6 +10,8 @@
> >*/
> >
> >   #include "qemu/osdep.h"
> > +#include "qemu/main-loop.h"
> > +#include "qemu/log.h"
> >   #include "qapi/qapi-types-net.h"
> >   #include "vmnet_int.h"
> >   #include "clients.h"
> > @@ -17,4 +19,370 @@
> >   #include "qapi/error.h"
> >
> >   #include 
> > +#include 
> >
> > +
>

[...]


> > +/**
> > + * Bottom half callback that transfers packets from vmnet interface
> > + * to QEMU.
> > + *
> > + * The process of transferring packets is three-staged:
> > + * 1. Handle vmnet event;
> > + * 2. Read packets from vmnet interface into temporary buffer;
> > + * 3. Write packets from temporary buffer to QEMU.
> > + *
> > + * QEMU may suspend this process on the last stage, returning 0 from
> > + * qemu_send_packet_async function. If this happens, we should
> > + * respectfully wait until it is ready to consume more packets,
> > + * write left ones in temporary buffer and only after this
> > + * continue reading more packets from vmnet interface.
> > + *
> > + * Packets to be transferred are stored into packets_buf,
> > + * in the window (packets_send_current_pos..packets_send_end_pos]
> > + * excluding current_pos, including end_pos.
>
> I wonder why you changed the window from [packets_send_current_pos,
> packets_send_end_pos). It is an unconventional way to represent such
> kind of window, requires signed integers and calculating
> packets_send_current_pos + 1 before operating with the first item of the
> window.
>
>
Did this mistakenly while removing send_enabled :facepalm:
Sorry for this.

Submitting v19 with this fixed.

Best Regards,
Vladislav Yaroshchuk



> Regards,
> Akihiko Odaki
>
> + *
> > + * Thus, if QEMU is not ready, buffer is not read and
> > + * packets_send_current_pos < packets_send_end_pos.
> > + */
> > +static void vmnet_send_bh(void *opaque)
> > +{
> > +NetClientState *nc = (NetClientState *) opaque;
> > +VmnetState *s = DO_UPCAST(VmnetState, nc, nc);
> > +
> > +/*
> > + * Do nothing if QEMU is not ready - wait
> > + * for completion callback invocation
> > + */
> > +if (s->packets_send_current_pos < s->packets_send_end_pos) {
> > +return;
> > +}
> > +
> > +/* Read packets from vmnet interface */
> > +if (vmnet_read_packets(s) > 0) {
> > +/* Send them to QEMU */
> > +vmnet_write_packets_to_qemu(s);
> > +}
> > +}
> > +
> > +
> > +/**
> > + * Completion callback to be invoked by QEMU when it becomes
> > + * ready to consume more packets.
> > + */
> > +static void vmnet_send_completed(NetClientState *nc, ssize_t len)
> > +{
> > +VmnetState *s = DO_UPCAST(VmnetState, nc, nc);
> > +
> > +/* Callback is invoked eq queued packet is sent */
> > +++s->packets_send_current_pos;
> > +
> > +/* Complete sending packets left in VmnetState buffers */
> > +vmnet_write_packets_to_qemu(s);
> > +
> > +/* And read new ones from vmnet if VmnetState buffer is ready */
> > +if (s->packets_send_current_pos < s->packets_send_end_pos) {
> > +qemu_bh_schedule(s->send_bh);
> > +}
> > +}
> > +
> > +
> > +static void vmnet_bufs_init(VmnetState *s)
> > +{
> > +struct vmpktdesc *packets = s->packets_buf;
> > +struct iovec *iov = s->iov_buf;
> > +int i;
> > +
> > +for (i = 0; i < VMNET_PACKETS_LIMIT; ++i) {
> > +iov[i].iov_len = s->max_packet_size;
> > +iov[i].iov_base = g_malloc0(iov[i].iov_len);
> > +packets[i].vm_pkt_iov = iov + i;
&

[PATCH v18 5/7] net/vmnet: implement bridged mode (vmnet-bridged)

2022-03-15 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-bridged.m | 128 ++--
 1 file changed, 123 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
index 91c1a2f2c7..5936c87718 100644
--- a/net/vmnet-bridged.m
+++ b/net/vmnet-bridged.m
@@ -10,16 +10,134 @@
 
 #include "qemu/osdep.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+
+static bool validate_ifname(const char *ifname)
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+bool match = false;
+if (!xpc_array_get_count(shared_if_list)) {
+goto done;
+}
+
+match = !xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+return strcmp(xpc_string_get_string_ptr(value), ifname) != 0;
+});
+
+done:
+xpc_release(shared_if_list);
+return match;
+}
+
+
+static bool get_valid_ifnames(char *output_buf)
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+__block const char *ifname = NULL;
+__block int str_offset = 0;
+bool interfaces_available = true;
+
+if (!xpc_array_get_count(shared_if_list)) {
+interfaces_available = false;
+goto done;
+}
+
+xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+/* build list of strings like "en0 en1 en2 " */
+ifname = xpc_string_get_string_ptr(value);
+strcpy(output_buf + str_offset, ifname);
+strcpy(output_buf + str_offset + strlen(ifname), " ");
+str_offset += strlen(ifname) + 1;
+return true;
+});
+
+done:
+xpc_release(shared_if_list);
+return interfaces_available;
+}
+
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+char ifnames[1024];
+
+if (!validate_ifname(options->ifname)) {
+if (get_valid_ifnames(ifnames)) {
+error_setg(errp,
+   "unsupported ifname '%s', expected one of [ %s]",
+   options->ifname,
+   ifnames);
+return false;
+}
+error_setg(errp,
+   "unsupported ifname '%s', no supported "
+   "interfaces available",
+   options->ifname);
+return false;
+}
+
+#if !defined(MAC_OS_VERSION_11_0) || \
+MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_11_0
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-bridged.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+return true;
+}
+
+
+static xpc_object_t build_if_desc(const Netdev *netdev)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_BRIDGED_MODE
+);
+
+xpc_dictionary_set_string(if_desc,
+  vmnet_shared_interface_name_key,
+  options->ifname);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+#endif
+return if_desc;
+}
+
+
+static NetClientInfo net_vmnet_bridged_info = {
+.type = NET_CLIENT_DRIVER_VMNET_BRIDGED,
+.size = sizeof(VmnetState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
+
 int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
NetClientState *peer, Error **errp)
 {
-  error_setg(errp, "vmnet-bridged is not implemented yet");
-  return -1;
+NetClientState *nc = qemu_new_net_client(_vmnet_bridged_info,
+ peer, "vmnet-bridged", name);
+if (!validate_options(netdev, errp)) {
+return -1;
+}
+return vmnet_if_create(nc, build_if_desc(netdev), errp);
 }
-- 
2.34.1.vfs.0.0




[PATCH v18 4/7] net/vmnet: implement host mode (vmnet-host)

2022-03-15 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-host.c | 110 ---
 1 file changed, 104 insertions(+), 6 deletions(-)

diff --git a/net/vmnet-host.c b/net/vmnet-host.c
index a461d507c5..8f7a638967 100644
--- a/net/vmnet-host.c
+++ b/net/vmnet-host.c
@@ -9,16 +9,114 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/uuid.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+QemuUUID uuid;
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+if (options->has_net_uuid &&
+qemu_uuid_parse(options->net_uuid, ) < 0) {
+error_setg(errp, "Invalid UUID provided in 'net-uuid'");
+return false;
+}
+#else
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-host.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+
+if (options->has_net_uuid) {
+error_setg(errp,
+   "vmnet-host.net-uuid feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+
+if ((options->has_start_address ||
+ options->has_end_address ||
+ options->has_subnet_mask) &&
+!(options->has_start_address &&
+  options->has_end_address &&
+  options->has_subnet_mask)) {
+error_setg(errp,
+   "'start-address', 'end-address', 'subnet-mask' "
+   "should be provided together");
+return false;
+}
+
+return true;
+}
+
+static xpc_object_t build_if_desc(const Netdev *netdev,
+  NetClientState *nc)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_HOST_MODE);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+
+QemuUUID network_uuid;
+if (options->has_net_uuid) {
+qemu_uuid_parse(options->net_uuid, _uuid);
+xpc_dictionary_set_uuid(if_desc,
+vmnet_network_identifier_key,
+network_uuid.data);
+}
+#endif
+
+if (options->has_start_address) {
+xpc_dictionary_set_string(if_desc,
+  vmnet_start_address_key,
+  options->start_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_end_address_key,
+  options->end_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_subnet_mask_key,
+  options->subnet_mask);
+}
+
+return if_desc;
+}
+
+static NetClientInfo net_vmnet_host_info = {
+.type = NET_CLIENT_DRIVER_VMNET_HOST,
+.size = sizeof(VmnetState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
 int net_init_vmnet_host(const Netdev *netdev, const char *name,
-NetClientState *peer, Error **errp) {
-  error_setg(errp, "vmnet-host is not implemented yet");
-  return -1;
+NetClientState *peer, Error **errp)
+{
+NetClientState *nc = qemu_new_net_client(_vmnet_host_info,
+ peer, "vmnet-host", name);
+if (!validate_options(netdev, errp)) {
+return -1;
+}
+return vmnet_if_create(nc, build_if_desc(netdev, nc), errp);
 }
-- 
2.34.1.vfs.0.0




[PATCH v18 3/7] net/vmnet: implement shared mode (vmnet-shared)

2022-03-15 Thread Vladislav Yaroshchuk
Interaction with vmnet.framework in different modes
differs only on configuration stage, so we can create
common `send`, `receive`, etc. procedures and reuse them.

Signed-off-by: Phillip Tennen 
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-common.m | 368 +
 net/vmnet-shared.c |  90 ++-
 net/vmnet_int.h|  40 -
 3 files changed, 493 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-common.m b/net/vmnet-common.m
index 06326efb1c..b9dac7b241 100644
--- a/net/vmnet-common.m
+++ b/net/vmnet-common.m
@@ -10,6 +10,8 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "qemu/log.h"
 #include "qapi/qapi-types-net.h"
 #include "vmnet_int.h"
 #include "clients.h"
@@ -17,4 +19,370 @@
 #include "qapi/error.h"
 
 #include 
+#include 
 
+
+static void vmnet_send_completed(NetClientState *nc, ssize_t len);
+
+
+const char *vmnet_status_map_str(vmnet_return_t status)
+{
+switch (status) {
+case VMNET_SUCCESS:
+return "success";
+case VMNET_FAILURE:
+return "general failure (possibly not enough privileges)";
+case VMNET_MEM_FAILURE:
+return "memory allocation failure";
+case VMNET_INVALID_ARGUMENT:
+return "invalid argument specified";
+case VMNET_SETUP_INCOMPLETE:
+return "interface setup is not complete";
+case VMNET_INVALID_ACCESS:
+return "invalid access, permission denied";
+case VMNET_PACKET_TOO_BIG:
+return "packet size is larger than MTU";
+case VMNET_BUFFER_EXHAUSTED:
+return "buffers exhausted in kernel";
+case VMNET_TOO_MANY_PACKETS:
+return "packet count exceeds limit";
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+case VMNET_SHARING_SERVICE_BUSY:
+return "conflict, sharing service is in use";
+#endif
+default:
+return "unknown vmnet error";
+}
+}
+
+
+/**
+ * Write packets from QEMU to vmnet interface.
+ *
+ * vmnet.framework supports iov, but writing more than
+ * one iov into vmnet interface fails with
+ * 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
+ * one and passing it to vmnet works fine. That's the
+ * reason why receive_iov() left unimplemented. But it still
+ * works with good performance having .receive() only.
+ */
+ssize_t vmnet_receive_common(NetClientState *nc,
+ const uint8_t *buf,
+ size_t size)
+{
+VmnetState *s = DO_UPCAST(VmnetState, nc, nc);
+struct vmpktdesc packet;
+struct iovec iov;
+int pkt_cnt;
+vmnet_return_t if_status;
+
+if (size > s->max_packet_size) {
+warn_report("vmnet: packet is too big, %zu > %" PRIu64,
+packet.vm_pkt_size,
+s->max_packet_size);
+return -1;
+}
+
+iov.iov_base = (char *) buf;
+iov.iov_len = size;
+
+packet.vm_pkt_iovcnt = 1;
+packet.vm_flags = 0;
+packet.vm_pkt_size = size;
+packet.vm_pkt_iov = 
+pkt_cnt = 1;
+
+if_status = vmnet_write(s->vmnet_if, , _cnt);
+if (if_status != VMNET_SUCCESS) {
+error_report("vmnet: write error: %s\n",
+ vmnet_status_map_str(if_status));
+return -1;
+}
+
+if (pkt_cnt) {
+return size;
+}
+return 0;
+}
+
+
+/**
+ * Read packets from vmnet interface and write them
+ * to temporary buffers in VmnetState.
+ *
+ * Returns read packets number (may be 0) on success,
+ * -1 on error
+ */
+static int vmnet_read_packets(VmnetState *s)
+{
+assert(s->packets_send_current_pos == s->packets_send_end_pos);
+
+struct vmpktdesc *packets = s->packets_buf;
+vmnet_return_t status;
+int pkt_cnt;
+int i;
+
+/* Read as many packets as present */
+pkt_cnt = VMNET_PACKETS_LIMIT;
+for (i = 0; i < pkt_cnt; ++i) {
+packets[i].vm_pkt_size = s->max_packet_size;
+packets[i].vm_pkt_iovcnt = 1;
+packets[i].vm_flags = 0;
+}
+
+status = vmnet_read(s->vmnet_if, packets, _cnt);
+if (status != VMNET_SUCCESS) {
+error_printf("vmnet: read failed: %s\n",
+ vmnet_status_map_str(status));
+s->packets_send_current_pos = -1;
+s->packets_send_end_pos = -1;
+return -1;
+}
+
+/*
+ * Adjust pointers: packets to be sent
+ * lay in (packets_send_current_pos..packets_send_end_pos]
+ * - excluding current_pos, including end_pos.
+ */
+s->packets_send_current_pos = -1;
+s->packets_send_end_pos = pkt_cnt - 1;
+
+return pkt_cnt;
+}
+
+
+/**
+ * Write packets from temporary buffers in VmnetState
+ * to QEMU.
+ */
+static void vmnet_write_packets_to_qemu(VmnetState *

[PATCH v18 7/7] net/vmnet: update hmp-commands.hx

2022-03-15 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 hmp-commands.hx | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 8476277aa9..8f3d78f177 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1265,7 +1265,11 @@ ERST
 {
 .name   = "netdev_add",
 .args_type  = "netdev:O",
-.params = 
"[user|tap|socket|vde|bridge|hubport|netmap|vhost-user],id=str[,prop=value][,...]",
+.params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user"
+#ifdef CONFIG_VMNET
+  "|vmnet-host|vmnet-shared|vmnet-bridged"
+#endif
+  "],id=str[,prop=value][,...]",
 .help   = "add host network device",
 .cmd= hmp_netdev_add,
 .command_completion = netdev_add_completion,
-- 
2.34.1.vfs.0.0




[PATCH v18 2/7] net/vmnet: add vmnet backends to qapi/net

2022-03-15 Thread Vladislav Yaroshchuk
Create separate netdevs for each vmnet operating mode:
- vmnet-host
- vmnet-shared
- vmnet-bridged

Signed-off-by: Vladislav Yaroshchuk 
---
 net/clients.h   |  11 
 net/meson.build |   7 +++
 net/net.c   |  10 
 net/vmnet-bridged.m |  25 +
 net/vmnet-common.m  |  20 +++
 net/vmnet-host.c|  24 
 net/vmnet-shared.c  |  25 +
 net/vmnet_int.h |  25 +
 qapi/net.json   | 133 +++-
 9 files changed, 278 insertions(+), 2 deletions(-)
 create mode 100644 net/vmnet-bridged.m
 create mode 100644 net/vmnet-common.m
 create mode 100644 net/vmnet-host.c
 create mode 100644 net/vmnet-shared.c
 create mode 100644 net/vmnet_int.h

diff --git a/net/clients.h b/net/clients.h
index 92f9b59aed..c9157789f2 100644
--- a/net/clients.h
+++ b/net/clients.h
@@ -63,4 +63,15 @@ int net_init_vhost_user(const Netdev *netdev, const char 
*name,
 
 int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
 NetClientState *peer, Error **errp);
+#ifdef CONFIG_VMNET
+int net_init_vmnet_host(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_shared(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+#endif /* CONFIG_VMNET */
+
 #endif /* QEMU_NET_CLIENTS_H */
diff --git a/net/meson.build b/net/meson.build
index 847bc2ac85..00a88c4951 100644
--- a/net/meson.build
+++ b/net/meson.build
@@ -42,4 +42,11 @@ softmmu_ss.add(when: 'CONFIG_POSIX', if_true: 
files(tap_posix))
 softmmu_ss.add(when: 'CONFIG_WIN32', if_true: files('tap-win32.c'))
 softmmu_ss.add(when: 'CONFIG_VHOST_NET_VDPA', if_true: files('vhost-vdpa.c'))
 
+vmnet_files = files(
+  'vmnet-common.m',
+  'vmnet-bridged.m',
+  'vmnet-host.c',
+  'vmnet-shared.c'
+)
+softmmu_ss.add(when: vmnet, if_true: vmnet_files)
 subdir('can')
diff --git a/net/net.c b/net/net.c
index f0d14dbfc1..1dbb64b935 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1021,6 +1021,11 @@ static int (* const 
net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
 #ifdef CONFIG_L2TPV3
 [NET_CLIENT_DRIVER_L2TPV3]= net_init_l2tpv3,
 #endif
+#ifdef CONFIG_VMNET
+[NET_CLIENT_DRIVER_VMNET_HOST] = net_init_vmnet_host,
+[NET_CLIENT_DRIVER_VMNET_SHARED] = net_init_vmnet_shared,
+[NET_CLIENT_DRIVER_VMNET_BRIDGED] = net_init_vmnet_bridged,
+#endif /* CONFIG_VMNET */
 };
 
 
@@ -1106,6 +,11 @@ void show_netdevs(void)
 #endif
 #ifdef CONFIG_VHOST_VDPA
 "vhost-vdpa",
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host",
+"vmnet-shared",
+"vmnet-bridged",
 #endif
 };
 
diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
new file mode 100644
index 00..91c1a2f2c7
--- /dev/null
+++ b/net/vmnet-bridged.m
@@ -0,0 +1,25 @@
+/*
+ * vmnet-bridged.m
+ *
+ * Copyright(c) 2022 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+   NetClientState *peer, Error **errp)
+{
+  error_setg(errp, "vmnet-bridged is not implemented yet");
+  return -1;
+}
diff --git a/net/vmnet-common.m b/net/vmnet-common.m
new file mode 100644
index 00..06326efb1c
--- /dev/null
+++ b/net/vmnet-common.m
@@ -0,0 +1,20 @@
+/*
+ * vmnet-common.m - network client wrapper for Apple vmnet.framework
+ *
+ * Copyright(c) 2022 Vladislav Yaroshchuk 
+ * Copyright(c) 2021 Phillip Tennen 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
diff --git a/net/vmnet-host.c b/net/vmnet-host.c
new file mode 100644
index 00..a461d507c5
--- /dev/null
+++ b/net/vmnet-host.c
@@ -0,0 +1,24 @@
+/*
+ * vmnet-host.c
+ *
+ * Copyright(c) 2022 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qa

[PATCH v18 6/7] net/vmnet: update qemu-options.hx

2022-03-15 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 qemu-options.hx | 25 +
 1 file changed, 25 insertions(+)

diff --git a/qemu-options.hx b/qemu-options.hx
index 5ce0ada75e..ea00d0eeb6 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2743,6 +2743,25 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
 #ifdef __linux__
 "-netdev vhost-vdpa,id=str,vhostdev=/path/to/dev\n"
 "configure a vhost-vdpa network,Establish a vhost-vdpa 
netdev\n"
+#endif
+#ifdef CONFIG_VMNET
+"-netdev vmnet-host,id=str[,isolated=on|off][,net-uuid=uuid]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in host mode with ID 
'str',\n"
+"isolate this interface from others with 'isolated',\n"
+"configure the address range and choose a subnet mask,\n"
+"specify network UUID 'uuid' to disable DHCP and interact 
with\n"
+"vmnet-host interfaces within this isolated network\n"
+"-netdev vmnet-shared,id=str[,isolated=on|off][,nat66-prefix=addr]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in shared mode with ID 
'str',\n"
+"configure the address range and choose a subnet mask,\n"
+"set IPv6 ULA prefix (of length 64) to use for internal 
network,\n"
+"isolate this interface from others with 'isolated'\n"
+"-netdev vmnet-bridged,id=str,ifname=name[,isolated=on|off]\n"
+"configure a vmnet network backend in bridged mode with ID 
'str',\n"
+"use 'ifname=name' to select a physical network interface 
to be bridged,\n"
+"isolate this interface from others with 'isolated'\n"
 #endif
 "-netdev hubport,id=str,hubid=n[,netdev=nd]\n"
 "configure a hub port on the hub with ID 'n'\n", 
QEMU_ARCH_ALL)
@@ -2762,6 +2781,9 @@ DEF("nic", HAS_ARG, QEMU_OPTION_nic,
 #endif
 #ifdef CONFIG_POSIX
 "vhost-user|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,...][mac=macaddr]\n"
 "initialize an on-board / default host NIC (using MAC 
address\n"
@@ -2784,6 +2806,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
 #endif
 #ifdef CONFIG_NETMAP
 "netmap|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,option][,...]\n"
 "old way to initialize a host network interface\n"
-- 
2.34.1.vfs.0.0




[PATCH v18 1/7] net/vmnet: add vmnet dependency and customizable option

2022-03-15 Thread Vladislav Yaroshchuk
vmnet.framework dependency is added with 'vmnet' option
to enable or disable it. Default value is 'auto'.

used vmnet features are available since macOS 11.0,
but new backend can be built and work properly with
subset of them on 10.15 too.

Signed-off-by: Vladislav Yaroshchuk 
---
 meson.build   | 16 +++-
 meson_options.txt |  2 ++
 scripts/meson-buildoptions.sh |  1 +
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index 2d6601467f..806f3869f9 100644
--- a/meson.build
+++ b/meson.build
@@ -522,6 +522,18 @@ if cocoa.found() and get_option('gtk').enabled()
   error('Cocoa and GTK+ cannot be enabled at the same time')
 endif
 
+vmnet = dependency('appleframeworks', modules: 'vmnet', required: 
get_option('vmnet'))
+if vmnet.found() and not cc.has_header_symbol('vmnet/vmnet.h',
+  'VMNET_BRIDGED_MODE',
+  dependencies: vmnet)
+  vmnet = not_found
+  if get_option('vmnet').enabled()
+error('vmnet.framework API is outdated')
+  else
+warning('vmnet.framework API is outdated, disabling')
+  endif
+endif
+
 seccomp = not_found
 if not get_option('seccomp').auto() or have_system or have_tools
   seccomp = dependency('libseccomp', version: '>=2.3.0',
@@ -1550,6 +1562,7 @@ config_host_data.set('CONFIG_SNAPPY', snappy.found())
 config_host_data.set('CONFIG_TPM', have_tpm)
 config_host_data.set('CONFIG_USB_LIBUSB', libusb.found())
 config_host_data.set('CONFIG_VDE', vde.found())
+config_host_data.set('CONFIG_VMNET', vmnet.found())
 config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', 
have_vhost_user_blk_server)
 config_host_data.set('CONFIG_VNC', vnc.found())
 config_host_data.set('CONFIG_VNC_JPEG', jpeg.found())
@@ -3588,7 +3601,8 @@ summary(summary_info, bool_yn: true, section: 'Crypto')
 # Libraries
 summary_info = {}
 if targetos == 'darwin'
-  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'vmnet.framework support': vmnet}
 endif
 summary_info += {'SDL support':   sdl}
 summary_info += {'SDL image support': sdl_image}
diff --git a/meson_options.txt b/meson_options.txt
index 52b11cead4..d2c0b6b412 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -175,6 +175,8 @@ option('netmap', type : 'feature', value : 'auto',
description: 'netmap network backend support')
 option('vde', type : 'feature', value : 'auto',
description: 'vde network backend support')
+option('vmnet', type : 'feature', value : 'auto',
+   description: 'vmnet.framework network backend support')
 option('virglrenderer', type : 'feature', value : 'auto',
description: 'virgl rendering support')
 option('vnc', type : 'feature', value : 'auto',
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 9ee684ef03..30946f3798 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -116,6 +116,7 @@ meson_options_help() {
   printf "%s\n" '  usb-redir   libusbredir support'
   printf "%s\n" '  vde vde network backend support'
   printf "%s\n" '  vdi vdi image format support'
+  printf "%s\n" '  vmnet   vmnet.framework network backend support'
   printf "%s\n" '  vhost-user-blk-server'
   printf "%s\n" '  build vhost-user-blk server'
   printf "%s\n" '  virglrenderer   virgl rendering support'
-- 
2.34.1.vfs.0.0




[PATCH v18 0/7] Add vmnet.framework based network backend

2022-03-15 Thread Vladislav Yaroshchuk
r proper printing
 - NOTE: This version of patch series may be one the last
   I submit - JetBrains has suspended operations in
   Russia indefinitely due to all the awful things happened
   the last weeks. I may leave this company and loose the
   ability to work on vmnet support :(
   It will be perfect if someone can handle my unfinished work,
   if something required to fix/improve is found.
   Because of this, MAINTAINERS list update is dropped
v16 -> v17
 - host: move network_uuid to local variable
 - common: refactor, add documentation
 - common/send (vmnet->qemu): read new packets after QEMU
   send_cb invoked
 - common/receive (qemu->vmnet): drop redundant vmnet
   status checks
 - restore dropped commit messaged from the previous series
v17 -> v18
 - use VmnetState struct for all three operation modes
 - drop send_enabled flag
 - do not unregister vmnet event callback on cleanup,
   let vmnet.framework do everything itself while interface
   description

Vladislav Yaroshchuk (7):
  net/vmnet: add vmnet dependency and customizable option
  net/vmnet: add vmnet backends to qapi/net
  net/vmnet: implement shared mode (vmnet-shared)
  net/vmnet: implement host mode (vmnet-host)
  net/vmnet: implement bridged mode (vmnet-bridged)
  net/vmnet: update qemu-options.hx
  net/vmnet: update hmp-commands.hx

 hmp-commands.hx   |   6 +-
 meson.build   |  16 +-
 meson_options.txt |   2 +
 net/clients.h |  11 +
 net/meson.build   |   7 +
 net/net.c |  10 +
 net/vmnet-bridged.m   | 143 +
 net/vmnet-common.m| 388 ++
 net/vmnet-host.c  | 122 +++
 net/vmnet-shared.c| 107 ++
 net/vmnet_int.h   |  63 ++
 qapi/net.json | 133 +++-
 qemu-options.hx   |  25 +++
 scripts/meson-buildoptions.sh |   1 +
 14 files changed, 1030 insertions(+), 4 deletions(-)
 create mode 100644 net/vmnet-bridged.m
 create mode 100644 net/vmnet-common.m
 create mode 100644 net/vmnet-host.c
 create mode 100644 net/vmnet-shared.c
 create mode 100644 net/vmnet_int.h

-- 
2.34.1.vfs.0.0




Re: [PATCH v17 3/7] net/vmnet: implement shared mode (vmnet-shared)

2022-03-15 Thread Vladislav Yaroshchuk
On Tue, Mar 15, 2022 at 8:54 PM Akihiko Odaki 
wrote:

> On 2022/03/16 2:45, Vladislav Yaroshchuk wrote:
> >
> >
> > On Tue, Mar 15, 2022 at 1:18 PM Akihiko Odaki  > <mailto:akihiko.od...@gmail.com>> wrote:
> >
> > On 2022/03/15 19:02, Vladislav Yaroshchuk wrote:
> >  > Interaction with vmnet.framework in different modes
> >  > differs only on configuration stage, so we can create
> >  > common `send`, `receive`, etc. procedures and reuse them.
> >  >
> >  > Signed-off-by: Phillip Tennen  > <mailto:phil...@axleos.com>>
> >  > Signed-off-by: Vladislav Yaroshchuk
> >  > <mailto:vladislav.yaroshc...@jetbrains.com>>
> >  > ---
> >  >   net/vmnet-common.m | 359
> > +
> >  >   net/vmnet-shared.c |  94 +++-
> >  >   net/vmnet_int.h|  41 +-
> >  >   3 files changed, 489 insertions(+), 5 deletions(-)
> >  >
> >  > diff --git a/net/vmnet-common.m b/net/vmnet-common.m
> >  > index 56612c72ce..6af042406b 100644
> >  > --- a/net/vmnet-common.m
> >  > +++ b/net/vmnet-common.m
> >  > @@ -10,6 +10,8 @@
> >  >*/
> >  >
> >  >   #include "qemu/osdep.h"
> >  > +#include "qemu/main-loop.h"
> >  > +#include "qemu/log.h"
> >  >   #include "qapi/qapi-types-net.h"
> >  >   #include "vmnet_int.h"
> >  >   #include "clients.h"
> >  > @@ -17,4 +19,361 @@
> >  >   #include "qapi/error.h"
> >  >
> >  >   #include 
> >  > +#include 
> >  >
> >  > +
> >  > +static void vmnet_send_completed(NetClientState *nc, ssize_t
> len);
> >  > +
> >  > +
> >  > +const char *vmnet_status_map_str(vmnet_return_t status)
> >  > +{
> >  > +switch (status) {
> >  > +case VMNET_SUCCESS:
> >  > +return "success";
> >  > +case VMNET_FAILURE:
> >  > +return "general failure (possibly not enough
> privileges)";
> >  > +case VMNET_MEM_FAILURE:
> >  > +return "memory allocation failure";
> >  > +case VMNET_INVALID_ARGUMENT:
> >  > +return "invalid argument specified";
> >  > +case VMNET_SETUP_INCOMPLETE:
> >  > +return "interface setup is not complete";
> >  > +case VMNET_INVALID_ACCESS:
> >  > +return "invalid access, permission denied";
> >  > +case VMNET_PACKET_TOO_BIG:
> >  > +return "packet size is larger than MTU";
> >  > +case VMNET_BUFFER_EXHAUSTED:
> >  > +return "buffers exhausted in kernel";
> >  > +case VMNET_TOO_MANY_PACKETS:
> >  > +return "packet count exceeds limit";
> >  > +#if defined(MAC_OS_VERSION_11_0) && \
> >  > +MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
> >  > +case VMNET_SHARING_SERVICE_BUSY:
> >  > +return "conflict, sharing service is in use";
> >  > +#endif
> >  > +default:
> >  > +return "unknown vmnet error";
> >  > +}
> >  > +}
> >  > +
> >  > +/**
> >  > + * Write packets from QEMU to vmnet interface.
> >  > + *
> >  > + * vmnet.framework supports iov, but writing more than
> >  > + * one iov into vmnet interface fails with
> >  > + * 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
> >  > + * one and passing it to vmnet works fine. That's the
> >  > + * reason why receive_iov() left unimplemented. But it still
> >  > + * works with good performance having .receive() only.
> >  > + */
> >  > +ssize_t vmnet_receive_common(NetClientState *nc,
> >  > + const uint8_t *buf,
> >  > + size_t size)
> >  > +{
> >  > +VmnetCommonState *s = DO_UPCAST(VmnetCommonState, nc, nc);
> >  > +struct vmpktdesc packet;
> >  > +struct iovec iov;
> >  > +int pkt_cnt;

Re: [PATCH v17 3/7] net/vmnet: implement shared mode (vmnet-shared)

2022-03-15 Thread Vladislav Yaroshchuk
On Tue, Mar 15, 2022 at 1:18 PM Akihiko Odaki 
wrote:

> On 2022/03/15 19:02, Vladislav Yaroshchuk wrote:
> > Interaction with vmnet.framework in different modes
> > differs only on configuration stage, so we can create
> > common `send`, `receive`, etc. procedures and reuse them.
> >
> > Signed-off-by: Phillip Tennen 
> > Signed-off-by: Vladislav Yaroshchuk 
> > ---
> >   net/vmnet-common.m | 359 +
> >   net/vmnet-shared.c |  94 +++-
> >   net/vmnet_int.h|  41 +-
> >   3 files changed, 489 insertions(+), 5 deletions(-)
> >
> > diff --git a/net/vmnet-common.m b/net/vmnet-common.m
> > index 56612c72ce..6af042406b 100644
> > --- a/net/vmnet-common.m
> > +++ b/net/vmnet-common.m
> > @@ -10,6 +10,8 @@
> >*/
> >
> >   #include "qemu/osdep.h"
> > +#include "qemu/main-loop.h"
> > +#include "qemu/log.h"
> >   #include "qapi/qapi-types-net.h"
> >   #include "vmnet_int.h"
> >   #include "clients.h"
> > @@ -17,4 +19,361 @@
> >   #include "qapi/error.h"
> >
> >   #include 
> > +#include 
> >
> > +
> > +static void vmnet_send_completed(NetClientState *nc, ssize_t len);
> > +
> > +
> > +const char *vmnet_status_map_str(vmnet_return_t status)
> > +{
> > +switch (status) {
> > +case VMNET_SUCCESS:
> > +return "success";
> > +case VMNET_FAILURE:
> > +return "general failure (possibly not enough privileges)";
> > +case VMNET_MEM_FAILURE:
> > +return "memory allocation failure";
> > +case VMNET_INVALID_ARGUMENT:
> > +return "invalid argument specified";
> > +case VMNET_SETUP_INCOMPLETE:
> > +return "interface setup is not complete";
> > +case VMNET_INVALID_ACCESS:
> > +return "invalid access, permission denied";
> > +case VMNET_PACKET_TOO_BIG:
> > +return "packet size is larger than MTU";
> > +case VMNET_BUFFER_EXHAUSTED:
> > +return "buffers exhausted in kernel";
> > +case VMNET_TOO_MANY_PACKETS:
> > +return "packet count exceeds limit";
> > +#if defined(MAC_OS_VERSION_11_0) && \
> > +MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
> > +case VMNET_SHARING_SERVICE_BUSY:
> > +return "conflict, sharing service is in use";
> > +#endif
> > +default:
> > +return "unknown vmnet error";
> > +}
> > +}
> > +
> > +/**
> > + * Write packets from QEMU to vmnet interface.
> > + *
> > + * vmnet.framework supports iov, but writing more than
> > + * one iov into vmnet interface fails with
> > + * 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
> > + * one and passing it to vmnet works fine. That's the
> > + * reason why receive_iov() left unimplemented. But it still
> > + * works with good performance having .receive() only.
> > + */
> > +ssize_t vmnet_receive_common(NetClientState *nc,
> > + const uint8_t *buf,
> > + size_t size)
> > +{
> > +VmnetCommonState *s = DO_UPCAST(VmnetCommonState, nc, nc);
> > +struct vmpktdesc packet;
> > +struct iovec iov;
> > +int pkt_cnt;
> > +vmnet_return_t if_status;
> > +
> > +if (size > s->max_packet_size) {
> > +warn_report("vmnet: packet is too big, %zu > %" PRIu64,
> > +packet.vm_pkt_size,
> > +s->max_packet_size);
> > +return -1;
> > +}
> > +
> > +iov.iov_base = (char *) buf;
> > +iov.iov_len = size;
> > +
> > +packet.vm_pkt_iovcnt = 1;
> > +packet.vm_flags = 0;
> > +packet.vm_pkt_size = size;
> > +packet.vm_pkt_iov = 
> > +pkt_cnt = 1;
> > +
> > +if_status = vmnet_write(s->vmnet_if, , _cnt);
> > +if (if_status != VMNET_SUCCESS) {
> > +error_report("vmnet: write error: %s\n",
> > + vmnet_status_map_str(if_status));
> > +return -1;
> > +}
> > +
> > +if (pkt_cnt) {
> > +return size;
> > +}
> > +return 0;
> > +}
> > +
> > +/**
> > + * Read packets from vmnet interface and write them
> > + * to temporary buffers in VmnetCommonState.
> > + 

[PATCH v17 6/7] net/vmnet: update qemu-options.hx

2022-03-15 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 qemu-options.hx | 25 +
 1 file changed, 25 insertions(+)

diff --git a/qemu-options.hx b/qemu-options.hx
index 5ce0ada75e..ea00d0eeb6 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2743,6 +2743,25 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
 #ifdef __linux__
 "-netdev vhost-vdpa,id=str,vhostdev=/path/to/dev\n"
 "configure a vhost-vdpa network,Establish a vhost-vdpa 
netdev\n"
+#endif
+#ifdef CONFIG_VMNET
+"-netdev vmnet-host,id=str[,isolated=on|off][,net-uuid=uuid]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in host mode with ID 
'str',\n"
+"isolate this interface from others with 'isolated',\n"
+"configure the address range and choose a subnet mask,\n"
+"specify network UUID 'uuid' to disable DHCP and interact 
with\n"
+"vmnet-host interfaces within this isolated network\n"
+"-netdev vmnet-shared,id=str[,isolated=on|off][,nat66-prefix=addr]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in shared mode with ID 
'str',\n"
+"configure the address range and choose a subnet mask,\n"
+"set IPv6 ULA prefix (of length 64) to use for internal 
network,\n"
+"isolate this interface from others with 'isolated'\n"
+"-netdev vmnet-bridged,id=str,ifname=name[,isolated=on|off]\n"
+"configure a vmnet network backend in bridged mode with ID 
'str',\n"
+"use 'ifname=name' to select a physical network interface 
to be bridged,\n"
+"isolate this interface from others with 'isolated'\n"
 #endif
 "-netdev hubport,id=str,hubid=n[,netdev=nd]\n"
 "configure a hub port on the hub with ID 'n'\n", 
QEMU_ARCH_ALL)
@@ -2762,6 +2781,9 @@ DEF("nic", HAS_ARG, QEMU_OPTION_nic,
 #endif
 #ifdef CONFIG_POSIX
 "vhost-user|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,...][mac=macaddr]\n"
 "initialize an on-board / default host NIC (using MAC 
address\n"
@@ -2784,6 +2806,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
 #endif
 #ifdef CONFIG_NETMAP
 "netmap|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,option][,...]\n"
 "old way to initialize a host network interface\n"
-- 
2.34.1.vfs.0.0




[PATCH v17 3/7] net/vmnet: implement shared mode (vmnet-shared)

2022-03-15 Thread Vladislav Yaroshchuk
Interaction with vmnet.framework in different modes
differs only on configuration stage, so we can create
common `send`, `receive`, etc. procedures and reuse them.

Signed-off-by: Phillip Tennen 
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-common.m | 359 +
 net/vmnet-shared.c |  94 +++-
 net/vmnet_int.h|  41 +-
 3 files changed, 489 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-common.m b/net/vmnet-common.m
index 56612c72ce..6af042406b 100644
--- a/net/vmnet-common.m
+++ b/net/vmnet-common.m
@@ -10,6 +10,8 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "qemu/log.h"
 #include "qapi/qapi-types-net.h"
 #include "vmnet_int.h"
 #include "clients.h"
@@ -17,4 +19,361 @@
 #include "qapi/error.h"
 
 #include 
+#include 
 
+
+static void vmnet_send_completed(NetClientState *nc, ssize_t len);
+
+
+const char *vmnet_status_map_str(vmnet_return_t status)
+{
+switch (status) {
+case VMNET_SUCCESS:
+return "success";
+case VMNET_FAILURE:
+return "general failure (possibly not enough privileges)";
+case VMNET_MEM_FAILURE:
+return "memory allocation failure";
+case VMNET_INVALID_ARGUMENT:
+return "invalid argument specified";
+case VMNET_SETUP_INCOMPLETE:
+return "interface setup is not complete";
+case VMNET_INVALID_ACCESS:
+return "invalid access, permission denied";
+case VMNET_PACKET_TOO_BIG:
+return "packet size is larger than MTU";
+case VMNET_BUFFER_EXHAUSTED:
+return "buffers exhausted in kernel";
+case VMNET_TOO_MANY_PACKETS:
+return "packet count exceeds limit";
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+case VMNET_SHARING_SERVICE_BUSY:
+return "conflict, sharing service is in use";
+#endif
+default:
+return "unknown vmnet error";
+}
+}
+
+/**
+ * Write packets from QEMU to vmnet interface.
+ *
+ * vmnet.framework supports iov, but writing more than
+ * one iov into vmnet interface fails with
+ * 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
+ * one and passing it to vmnet works fine. That's the
+ * reason why receive_iov() left unimplemented. But it still
+ * works with good performance having .receive() only.
+ */
+ssize_t vmnet_receive_common(NetClientState *nc,
+ const uint8_t *buf,
+ size_t size)
+{
+VmnetCommonState *s = DO_UPCAST(VmnetCommonState, nc, nc);
+struct vmpktdesc packet;
+struct iovec iov;
+int pkt_cnt;
+vmnet_return_t if_status;
+
+if (size > s->max_packet_size) {
+warn_report("vmnet: packet is too big, %zu > %" PRIu64,
+packet.vm_pkt_size,
+s->max_packet_size);
+return -1;
+}
+
+iov.iov_base = (char *) buf;
+iov.iov_len = size;
+
+packet.vm_pkt_iovcnt = 1;
+packet.vm_flags = 0;
+packet.vm_pkt_size = size;
+packet.vm_pkt_iov = 
+pkt_cnt = 1;
+
+if_status = vmnet_write(s->vmnet_if, , _cnt);
+if (if_status != VMNET_SUCCESS) {
+error_report("vmnet: write error: %s\n",
+ vmnet_status_map_str(if_status));
+return -1;
+}
+
+if (pkt_cnt) {
+return size;
+}
+return 0;
+}
+
+/**
+ * Read packets from vmnet interface and write them
+ * to temporary buffers in VmnetCommonState.
+ *
+ * Returns read packets number (may be 0) if read
+ * is successful, -1 on error
+ */
+static int vmnet_read_packets(VmnetCommonState *s) {
+assert(s->packets_send_current_pos == s->packets_send_end_pos);
+
+struct vmpktdesc *packets = s->packets_buf;
+vmnet_return_t status;
+int i;
+
+/* Read as many packets as present */
+s->packets_send_current_pos = 0;
+s->packets_send_end_pos = VMNET_PACKETS_LIMIT;
+for (i = 0; i < s->packets_send_end_pos; ++i) {
+packets[i].vm_pkt_size = s->max_packet_size;
+packets[i].vm_pkt_iovcnt = 1;
+packets[i].vm_flags = 0;
+}
+
+status = vmnet_read(s->vmnet_if, packets, >packets_send_end_pos);
+if (status != VMNET_SUCCESS) {
+error_printf("vmnet: read failed: %s\n",
+ vmnet_status_map_str(status));
+s->packets_send_current_pos = 0;
+s->packets_send_end_pos = 0;
+return -1;
+}
+
+return s->packets_send_end_pos;
+}
+
+/**
+ * Write packets from temporary buffers in VmnetCommonState
+ * to QEMU.
+ */
+static void vmnet_write_packets_to_qemu(VmnetCommonState *s) {
+ssize_t size;
+
+/*
+ * Packets to send lay in [current_pos..end_pos)
+ * (including current_po

[PATCH v17 7/7] net/vmnet: update hmp-commands.hx

2022-03-15 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 hmp-commands.hx | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 8476277aa9..8f3d78f177 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1265,7 +1265,11 @@ ERST
 {
 .name   = "netdev_add",
 .args_type  = "netdev:O",
-.params = 
"[user|tap|socket|vde|bridge|hubport|netmap|vhost-user],id=str[,prop=value][,...]",
+.params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user"
+#ifdef CONFIG_VMNET
+  "|vmnet-host|vmnet-shared|vmnet-bridged"
+#endif
+  "],id=str[,prop=value][,...]",
 .help   = "add host network device",
 .cmd= hmp_netdev_add,
 .command_completion = netdev_add_completion,
-- 
2.34.1.vfs.0.0




[PATCH v17 0/7] Add vmnet.framework based network backend

2022-03-15 Thread Vladislav Yaroshchuk
r proper printing
 - NOTE: This version of patch series may be one the last
   I submit - JetBrains has suspended operations in
   Russia indefinitely due to all the awful things happened
   the last weeks. I may leave this company and loose the
   ability to work on vmnet support :(
   It will be perfect if someone can handle my unfinished work,
   if something required to fix/improve is found.
   Because of this, MAINTAINERS list update is dropped
v16 -> v17
 - host: move network_uuid to local variable
 - common: refactor, add documentation
 - common/send (vmnet->qemu): read new packets after QEMU
   send_cb invoked
 - common/receive (qemu->vmnet): drop redundant vmnet
   status checks
 - restore dropped commit messaged from the previous series


Vladislav Yaroshchuk (7):
  net/vmnet: add vmnet dependency and customizable option
  net/vmnet: add vmnet backends to qapi/net
  net/vmnet: implement shared mode (vmnet-shared)
  net/vmnet: implement host mode (vmnet-host)
  net/vmnet: implement bridged mode (vmnet-bridged)
  net/vmnet: update qemu-options.hx
  net/vmnet: update hmp-commands.hx

 hmp-commands.hx   |   6 +-
 meson.build   |  16 +-
 meson_options.txt |   2 +
 net/clients.h |  11 +
 net/meson.build   |   7 +
 net/net.c |  10 +
 net/vmnet-bridged.m   | 148 +
 net/vmnet-common.m| 379 ++
 net/vmnet-host.c  | 125 +++
 net/vmnet-shared.c| 111 ++
 net/vmnet_int.h   |  64 ++
 qapi/net.json | 133 +++-
 qemu-options.hx   |  25 +++
 scripts/meson-buildoptions.sh |   1 +
 14 files changed, 1034 insertions(+), 4 deletions(-)
 create mode 100644 net/vmnet-bridged.m
 create mode 100644 net/vmnet-common.m
 create mode 100644 net/vmnet-host.c
 create mode 100644 net/vmnet-shared.c
 create mode 100644 net/vmnet_int.h

-- 
2.34.1.vfs.0.0




[PATCH v17 5/7] net/vmnet: implement bridged mode (vmnet-bridged)

2022-03-15 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-bridged.m | 133 ++--
 1 file changed, 128 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
index c735901666..4e29546bf2 100644
--- a/net/vmnet-bridged.m
+++ b/net/vmnet-bridged.m
@@ -10,16 +10,139 @@
 
 #include "qemu/osdep.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+
+typedef struct VmnetBridgedState {
+VmnetCommonState cs;
+} VmnetBridgedState;
+
+
+static bool validate_ifname(const char *ifname)
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+bool match = false;
+if (!xpc_array_get_count(shared_if_list)) {
+goto done;
+}
+
+match = !xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+return strcmp(xpc_string_get_string_ptr(value), ifname) != 0;
+});
+
+done:
+xpc_release(shared_if_list);
+return match;
+}
+
+
+static bool get_valid_ifnames(char *output_buf)
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+__block const char *ifname = NULL;
+__block int str_offset = 0;
+bool interfaces_available = true;
+
+if (!xpc_array_get_count(shared_if_list)) {
+interfaces_available = false;
+goto done;
+}
+
+xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+/* build list of strings like "en0 en1 en2 " */
+ifname = xpc_string_get_string_ptr(value);
+strcpy(output_buf + str_offset, ifname);
+strcpy(output_buf + str_offset + strlen(ifname), " ");
+str_offset += strlen(ifname) + 1;
+return true;
+});
+
+done:
+xpc_release(shared_if_list);
+return interfaces_available;
+}
+
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+char ifnames[1024];
+
+if (!validate_ifname(options->ifname)) {
+if (get_valid_ifnames(ifnames)) {
+error_setg(errp,
+   "unsupported ifname '%s', expected one of [ %s]",
+   options->ifname,
+   ifnames);
+return false;
+}
+error_setg(errp,
+   "unsupported ifname '%s', no supported "
+   "interfaces available",
+   options->ifname);
+return false;
+}
+
+#if !defined(MAC_OS_VERSION_11_0) || \
+MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_11_0
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-bridged.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+return true;
+}
+
+
+static xpc_object_t build_if_desc(const Netdev *netdev)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_BRIDGED_MODE
+);
+
+xpc_dictionary_set_string(if_desc,
+  vmnet_shared_interface_name_key,
+  options->ifname);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+#endif
+return if_desc;
+}
+
+
+static NetClientInfo net_vmnet_bridged_info = {
+.type = NET_CLIENT_DRIVER_VMNET_BRIDGED,
+.size = sizeof(VmnetBridgedState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
+
 int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
NetClientState *peer, Error **errp)
 {
-  error_setg(errp, "vmnet-bridged is not implemented yet");
-  return -1;
+NetClientState *nc = qemu_new_net_client(_vmnet_bridged_info,
+ peer, "vmnet-bridged", name);
+if (!validate_options(netdev, errp)) {
+return -1;
+}
+return vmnet_if_create(nc, build_if_desc(netdev), errp);
 }
-- 
2.34.1.vfs.0.0




[PATCH v17 4/7] net/vmnet: implement host mode (vmnet-host)

2022-03-15 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-host.c | 113 ---
 1 file changed, 107 insertions(+), 6 deletions(-)

diff --git a/net/vmnet-host.c b/net/vmnet-host.c
index 32dc437037..0395458d8d 100644
--- a/net/vmnet-host.c
+++ b/net/vmnet-host.c
@@ -9,16 +9,117 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/uuid.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+typedef struct VmnetHostState {
+VmnetCommonState cs;
+} VmnetHostState;
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+QemuUUID uuid;
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+if (options->has_net_uuid &&
+qemu_uuid_parse(options->net_uuid, ) < 0) {
+error_setg(errp, "Invalid UUID provided in 'net-uuid'");
+return false;
+}
+#else
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-host.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+
+if (options->has_net_uuid) {
+error_setg(errp,
+   "vmnet-host.net-uuid feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+
+if ((options->has_start_address ||
+ options->has_end_address ||
+ options->has_subnet_mask) &&
+!(options->has_start_address &&
+  options->has_end_address &&
+  options->has_subnet_mask)) {
+error_setg(errp,
+   "'start-address', 'end-address', 'subnet-mask' "
+   "should be provided together");
+return false;
+}
+
+return true;
+}
+
+static xpc_object_t build_if_desc(const Netdev *netdev,
+  NetClientState *nc)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_HOST_MODE);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+
+QemuUUID network_uuid;
+if (options->has_net_uuid) {
+qemu_uuid_parse(options->net_uuid, _uuid);
+xpc_dictionary_set_uuid(if_desc,
+vmnet_network_identifier_key,
+network_uuid.data);
+}
+#endif
+
+if (options->has_start_address) {
+xpc_dictionary_set_string(if_desc,
+  vmnet_start_address_key,
+  options->start_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_end_address_key,
+  options->end_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_subnet_mask_key,
+  options->subnet_mask);
+}
+
+return if_desc;
+}
+
+static NetClientInfo net_vmnet_host_info = {
+.type = NET_CLIENT_DRIVER_VMNET_HOST,
+.size = sizeof(VmnetHostState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
 int net_init_vmnet_host(const Netdev *netdev, const char *name,
-NetClientState *peer, Error **errp) {
-  error_setg(errp, "vmnet-host is not implemented yet");
-  return -1;
+NetClientState *peer, Error **errp)
+{
+NetClientState *nc = qemu_new_net_client(_vmnet_host_info,
+ peer, "vmnet-host", name);
+if (!validate_options(netdev, errp)) {
+return -1;
+}
+return vmnet_if_create(nc, build_if_desc(netdev, nc), errp);
 }
-- 
2.34.1.vfs.0.0




[PATCH v17 2/7] net/vmnet: add vmnet backends to qapi/net

2022-03-15 Thread Vladislav Yaroshchuk
Create separate netdevs for each vmnet operating mode:
- vmnet-host
- vmnet-shared
- vmnet-bridged

Signed-off-by: Vladislav Yaroshchuk 
---
 net/clients.h   |  11 
 net/meson.build |   7 +++
 net/net.c   |  10 
 net/vmnet-bridged.m |  25 +
 net/vmnet-common.m  |  20 +++
 net/vmnet-host.c|  24 
 net/vmnet-shared.c  |  25 +
 net/vmnet_int.h |  25 +
 qapi/net.json   | 133 +++-
 9 files changed, 278 insertions(+), 2 deletions(-)
 create mode 100644 net/vmnet-bridged.m
 create mode 100644 net/vmnet-common.m
 create mode 100644 net/vmnet-host.c
 create mode 100644 net/vmnet-shared.c
 create mode 100644 net/vmnet_int.h

diff --git a/net/clients.h b/net/clients.h
index 92f9b59aed..c9157789f2 100644
--- a/net/clients.h
+++ b/net/clients.h
@@ -63,4 +63,15 @@ int net_init_vhost_user(const Netdev *netdev, const char 
*name,
 
 int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
 NetClientState *peer, Error **errp);
+#ifdef CONFIG_VMNET
+int net_init_vmnet_host(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_shared(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+#endif /* CONFIG_VMNET */
+
 #endif /* QEMU_NET_CLIENTS_H */
diff --git a/net/meson.build b/net/meson.build
index 847bc2ac85..00a88c4951 100644
--- a/net/meson.build
+++ b/net/meson.build
@@ -42,4 +42,11 @@ softmmu_ss.add(when: 'CONFIG_POSIX', if_true: 
files(tap_posix))
 softmmu_ss.add(when: 'CONFIG_WIN32', if_true: files('tap-win32.c'))
 softmmu_ss.add(when: 'CONFIG_VHOST_NET_VDPA', if_true: files('vhost-vdpa.c'))
 
+vmnet_files = files(
+  'vmnet-common.m',
+  'vmnet-bridged.m',
+  'vmnet-host.c',
+  'vmnet-shared.c'
+)
+softmmu_ss.add(when: vmnet, if_true: vmnet_files)
 subdir('can')
diff --git a/net/net.c b/net/net.c
index f0d14dbfc1..1dbb64b935 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1021,6 +1021,11 @@ static int (* const 
net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
 #ifdef CONFIG_L2TPV3
 [NET_CLIENT_DRIVER_L2TPV3]= net_init_l2tpv3,
 #endif
+#ifdef CONFIG_VMNET
+[NET_CLIENT_DRIVER_VMNET_HOST] = net_init_vmnet_host,
+[NET_CLIENT_DRIVER_VMNET_SHARED] = net_init_vmnet_shared,
+[NET_CLIENT_DRIVER_VMNET_BRIDGED] = net_init_vmnet_bridged,
+#endif /* CONFIG_VMNET */
 };
 
 
@@ -1106,6 +,11 @@ void show_netdevs(void)
 #endif
 #ifdef CONFIG_VHOST_VDPA
 "vhost-vdpa",
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host",
+"vmnet-shared",
+"vmnet-bridged",
 #endif
 };
 
diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
new file mode 100644
index 00..c735901666
--- /dev/null
+++ b/net/vmnet-bridged.m
@@ -0,0 +1,25 @@
+/*
+ * vmnet-bridged.m
+ *
+ * Copyright(c) 2021 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+   NetClientState *peer, Error **errp)
+{
+  error_setg(errp, "vmnet-bridged is not implemented yet");
+  return -1;
+}
diff --git a/net/vmnet-common.m b/net/vmnet-common.m
new file mode 100644
index 00..56612c72ce
--- /dev/null
+++ b/net/vmnet-common.m
@@ -0,0 +1,20 @@
+/*
+ * vmnet-common.m - network client wrapper for Apple vmnet.framework
+ *
+ * Copyright(c) 2021 Vladislav Yaroshchuk 
+ * Copyright(c) 2021 Phillip Tennen 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
diff --git a/net/vmnet-host.c b/net/vmnet-host.c
new file mode 100644
index 00..32dc437037
--- /dev/null
+++ b/net/vmnet-host.c
@@ -0,0 +1,24 @@
+/*
+ * vmnet-host.c
+ *
+ * Copyright(c) 2021 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qa

[PATCH v17 1/7] net/vmnet: add vmnet dependency and customizable option

2022-03-15 Thread Vladislav Yaroshchuk
vmnet.framework dependency is added with 'vmnet' option
to enable or disable it. Default value is 'auto'.

vmnet features to be used are available since macOS 11.0,
corresponding probe is created into meson.build.

Signed-off-by: Vladislav Yaroshchuk 
---
 meson.build   | 16 +++-
 meson_options.txt |  2 ++
 scripts/meson-buildoptions.sh |  1 +
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index 2d6601467f..806f3869f9 100644
--- a/meson.build
+++ b/meson.build
@@ -522,6 +522,18 @@ if cocoa.found() and get_option('gtk').enabled()
   error('Cocoa and GTK+ cannot be enabled at the same time')
 endif
 
+vmnet = dependency('appleframeworks', modules: 'vmnet', required: 
get_option('vmnet'))
+if vmnet.found() and not cc.has_header_symbol('vmnet/vmnet.h',
+  'VMNET_BRIDGED_MODE',
+  dependencies: vmnet)
+  vmnet = not_found
+  if get_option('vmnet').enabled()
+error('vmnet.framework API is outdated')
+  else
+warning('vmnet.framework API is outdated, disabling')
+  endif
+endif
+
 seccomp = not_found
 if not get_option('seccomp').auto() or have_system or have_tools
   seccomp = dependency('libseccomp', version: '>=2.3.0',
@@ -1550,6 +1562,7 @@ config_host_data.set('CONFIG_SNAPPY', snappy.found())
 config_host_data.set('CONFIG_TPM', have_tpm)
 config_host_data.set('CONFIG_USB_LIBUSB', libusb.found())
 config_host_data.set('CONFIG_VDE', vde.found())
+config_host_data.set('CONFIG_VMNET', vmnet.found())
 config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', 
have_vhost_user_blk_server)
 config_host_data.set('CONFIG_VNC', vnc.found())
 config_host_data.set('CONFIG_VNC_JPEG', jpeg.found())
@@ -3588,7 +3601,8 @@ summary(summary_info, bool_yn: true, section: 'Crypto')
 # Libraries
 summary_info = {}
 if targetos == 'darwin'
-  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'vmnet.framework support': vmnet}
 endif
 summary_info += {'SDL support':   sdl}
 summary_info += {'SDL image support': sdl_image}
diff --git a/meson_options.txt b/meson_options.txt
index 52b11cead4..d2c0b6b412 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -175,6 +175,8 @@ option('netmap', type : 'feature', value : 'auto',
description: 'netmap network backend support')
 option('vde', type : 'feature', value : 'auto',
description: 'vde network backend support')
+option('vmnet', type : 'feature', value : 'auto',
+   description: 'vmnet.framework network backend support')
 option('virglrenderer', type : 'feature', value : 'auto',
description: 'virgl rendering support')
 option('vnc', type : 'feature', value : 'auto',
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 9ee684ef03..30946f3798 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -116,6 +116,7 @@ meson_options_help() {
   printf "%s\n" '  usb-redir   libusbredir support'
   printf "%s\n" '  vde vde network backend support'
   printf "%s\n" '  vdi vdi image format support'
+  printf "%s\n" '  vmnet   vmnet.framework network backend support'
   printf "%s\n" '  vhost-user-blk-server'
   printf "%s\n" '  build vhost-user-blk server'
   printf "%s\n" '  virglrenderer   virgl rendering support'
-- 
2.34.1.vfs.0.0




Re: [PATCH v16 3/7] net/vmnet: implement shared mode (vmnet-shared)

2022-03-14 Thread Vladislav Yaroshchuk
вт, 15 мар. 2022 г., 2:06 AM Akihiko Odaki :

> On 2022/03/15 8:02, Vladislav Yaroshchuk wrote:
> >
> >
> > вт, 15 мар. 2022 г., 1:34 AM Akihiko Odaki  > <mailto:akihiko.od...@gmail.com>>:
> >
> > On 2022/03/15 6:50, Vladislav Yaroshchuk wrote:
> >  > Thank you, Akihiko
> >  >
> >  > On Mon, Mar 14, 2022 at 10:46 PM Akihiko Odaki
> > mailto:akihiko.od...@gmail.com>
> >  > <mailto:akihiko.od...@gmail.com
> >     <mailto:akihiko.od...@gmail.com>>> wrote:
> >  >
> >  > On 2022/03/15 4:15, Vladislav Yaroshchuk wrote:
> >  >  > vmnet.framework supports iov, but writing more than
> >  >  > one iov into vmnet interface fails with
> >  >  > 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
> >  >  > one and passing it to vmnet works fine. That's the
> >  >  > reason why receive_iov() left unimplemented. But it still
> >  >  > works with good enough performance having .receive()
> >  >  > implemented only.
> >  >  >
> >  >  > Signed-off-by: Phillip Tennen  > <mailto:phil...@axleos.com>
> >  > <mailto:phil...@axleos.com <mailto:phil...@axleos.com>>>
> >  >  > Signed-off-by: Vladislav Yaroshchuk
> >  >  > <mailto:vladislav.yaroshc...@jetbrains.com>
> >  > <mailto:vladislav.yaroshc...@jetbrains.com
> > <mailto:vladislav.yaroshc...@jetbrains.com>>>
> >  >  > ---
> >  >  >   net/vmnet-common.m | 298
> >  > +
> >  >  >   net/vmnet-shared.c |  95 ++-
> >  >  >   net/vmnet_int.h|  41 ++-
> >  >  >   3 files changed, 429 insertions(+), 5 deletions(-)
> >  >  >
> >  >  > diff --git a/net/vmnet-common.m b/net/vmnet-common.m
> >  >  > index 56612c72ce..20a33d2591 100644
> >  >  > --- a/net/vmnet-common.m
> >  >  > +++ b/net/vmnet-common.m
> >  >  > @@ -10,6 +10,8 @@
> >  >  >*/
> >  >  >
> >  >  >   #include "qemu/osdep.h"
> >  >  > +#include "qemu/main-loop.h"
> >  >  > +#include "qemu/log.h"
> >  >  >   #include "qapi/qapi-types-net.h"
> >  >  >   #include "vmnet_int.h"
> >  >  >   #include "clients.h"
> >  >  > @@ -17,4 +19,300 @@
> >  >  >   #include "qapi/error.h"
> >  >  >
> >  >  >   #include 
> >  >  > +#include 
> >  >  >
> >  >  > +static bool vmnet_qemu_send_wrapper(VmnetCommonState *s);
> >  >
> >  > The names of vmnet_qemu_send_wrapper and vmnet_send_bh does
> > not tell
> >  > them apart well. Since only vmnet_send_bh does reading, its
> > name may
> >  > include "read" to clarify that. "wrapper" in
> > vmnet_qemu_send_wrapper
> >  > may
> >  > be also misleading as it does more than just calling the
> > underlying
> >  > QEMU
> >  > facility, but it also updates VmnetCommonState.
> >  >
> >  >
> >  > Ok, I'll think about how to name them better.
> >  >
> >  >  > +
> >  >  > +
> >  >  > +static void vmnet_send_completed(NetClientState *nc,
> > ssize_t len)
> >  >  > +{
> >  >  > +VmnetCommonState *s = DO_UPCAST(VmnetCommonState, nc,
> > nc);
> >  >  > +/* Complete sending packets left in VmnetCommonState
> > buffers */
> >  >  > +s->send_enabled = vmnet_qemu_send_wrapper(s);
> >  >
> >  > It must qemu_bh_schedule(s->send_bh) after
> > vmnet_qemu_send_wrapper.
> >  >
> >  >
> >  > Agree with you, thanks.
> >  >
> >  > Also, send_enabled flag can be removed as explained in:
> >  > https://www.mail-archive.com/qemu-devel@nongnu.org/msg873923.html
> > <https://www.mail-archive.com/qemu-devel@nongnu.org/msg873923.h

Re: [PATCH v16 3/7] net/vmnet: implement shared mode (vmnet-shared)

2022-03-14 Thread Vladislav Yaroshchuk
вт, 15 мар. 2022 г., 1:34 AM Akihiko Odaki :

> On 2022/03/15 6:50, Vladislav Yaroshchuk wrote:
> > Thank you, Akihiko
> >
> > On Mon, Mar 14, 2022 at 10:46 PM Akihiko Odaki  > <mailto:akihiko.od...@gmail.com>> wrote:
> >
> > On 2022/03/15 4:15, Vladislav Yaroshchuk wrote:
> >  > vmnet.framework supports iov, but writing more than
> >  > one iov into vmnet interface fails with
> >  > 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
> >  > one and passing it to vmnet works fine. That's the
> >  > reason why receive_iov() left unimplemented. But it still
> >  > works with good enough performance having .receive()
> >  > implemented only.
> >  >
> >  > Signed-off-by: Phillip Tennen  > <mailto:phil...@axleos.com>>
> >  > Signed-off-by: Vladislav Yaroshchuk
> >  > <mailto:vladislav.yaroshc...@jetbrains.com>>
> >  > ---
> >  >   net/vmnet-common.m | 298
> > +
> >  >   net/vmnet-shared.c |  95 ++-
> >  >   net/vmnet_int.h|  41 ++-
> >  >   3 files changed, 429 insertions(+), 5 deletions(-)
> >  >
> >  > diff --git a/net/vmnet-common.m b/net/vmnet-common.m
> >  > index 56612c72ce..20a33d2591 100644
> >  > --- a/net/vmnet-common.m
> >  > +++ b/net/vmnet-common.m
> >  > @@ -10,6 +10,8 @@
> >  >*/
> >  >
> >  >   #include "qemu/osdep.h"
> >  > +#include "qemu/main-loop.h"
> >  > +#include "qemu/log.h"
> >  >   #include "qapi/qapi-types-net.h"
> >  >   #include "vmnet_int.h"
> >  >   #include "clients.h"
> >  > @@ -17,4 +19,300 @@
> >  >   #include "qapi/error.h"
> >  >
> >  >   #include 
> >  > +#include 
> >  >
> >  > +static bool vmnet_qemu_send_wrapper(VmnetCommonState *s);
> >
> > The names of vmnet_qemu_send_wrapper and vmnet_send_bh does not tell
> > them apart well. Since only vmnet_send_bh does reading, its name may
> > include "read" to clarify that. "wrapper" in vmnet_qemu_send_wrapper
> > may
> > be also misleading as it does more than just calling the underlying
> > QEMU
> > facility, but it also updates VmnetCommonState.
> >
> >
> > Ok, I'll think about how to name them better.
> >
> >  > +
> >  > +
> >  > +static void vmnet_send_completed(NetClientState *nc, ssize_t len)
> >  > +{
> >  > +VmnetCommonState *s = DO_UPCAST(VmnetCommonState, nc, nc);
> >  > +/* Complete sending packets left in VmnetCommonState buffers
> */
> >  > +s->send_enabled = vmnet_qemu_send_wrapper(s);
> >
> > It must qemu_bh_schedule(s->send_bh) after vmnet_qemu_send_wrapper.
> >
> >
> > Agree with you, thanks.
> >
> > Also, send_enabled flag can be removed as explained in:
> > https://www.mail-archive.com/qemu-devel@nongnu.org/msg873923.html
> > <https://www.mail-archive.com/qemu-devel@nongnu.org/msg873923.html>
> >
> >
> > Not sure about this. Values of packets_send_current_pos
> > and packets_send_end_pos may be equal, but QEMU may be
> > not ready to receive new packets - the explanation:
> > 1. We are sending packets to QEMU with qemu_send_packet_async:
> >  packets_send_current_pos = 0
> >  packets_send_end_pos = 5
> > 2. All five packets (0, 1, 2, 3, 4) have been successfully sent to QEMU,
> >  but qemu_send_packet_async returned 0 "no more packets" after
> >  the last invocation
> > 3. In spite of this, all five packets are sent and
> >  packets_send_current_pos == packets_send_end_pos == 5
> > 4. It seems that "pointers are equal ->  QEMU is ready", but actually
> >  it is not.
> >
> > Also, hiding QEMU "ready"/"not ready" state behind pointers is a
> > bad choice I think. Having a concrete flag makes this more clear.
> > It provides understandability, not complexity (imho).
>
> packets_send_current_pos must not be incremented if
> qemu_send_packet_async returned 0. It must tell the position of the
> packet currently being sent.
>
>
>
> must be incremented
It cannot.

If qemu_send_packet_async returns 0,
it

Re: [PATCH v16 3/7] net/vmnet: implement shared mode (vmnet-shared)

2022-03-14 Thread Vladislav Yaroshchuk
Thank you, Akihiko

On Mon, Mar 14, 2022 at 10:46 PM Akihiko Odaki 
wrote:

> On 2022/03/15 4:15, Vladislav Yaroshchuk wrote:
> > vmnet.framework supports iov, but writing more than
> > one iov into vmnet interface fails with
> > 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
> > one and passing it to vmnet works fine. That's the
> > reason why receive_iov() left unimplemented. But it still
> > works with good enough performance having .receive()
> > implemented only.
> >
> > Signed-off-by: Phillip Tennen 
> > Signed-off-by: Vladislav Yaroshchuk 
> > ---
> >   net/vmnet-common.m | 298 +
> >   net/vmnet-shared.c |  95 ++-
> >   net/vmnet_int.h|  41 ++-
> >   3 files changed, 429 insertions(+), 5 deletions(-)
> >
> > diff --git a/net/vmnet-common.m b/net/vmnet-common.m
> > index 56612c72ce..20a33d2591 100644
> > --- a/net/vmnet-common.m
> > +++ b/net/vmnet-common.m
> > @@ -10,6 +10,8 @@
> >*/
> >
> >   #include "qemu/osdep.h"
> > +#include "qemu/main-loop.h"
> > +#include "qemu/log.h"
> >   #include "qapi/qapi-types-net.h"
> >   #include "vmnet_int.h"
> >   #include "clients.h"
> > @@ -17,4 +19,300 @@
> >   #include "qapi/error.h"
> >
> >   #include 
> > +#include 
> >
> > +static bool vmnet_qemu_send_wrapper(VmnetCommonState *s);
>
> The names of vmnet_qemu_send_wrapper and vmnet_send_bh does not tell
> them apart well. Since only vmnet_send_bh does reading, its name may
> include "read" to clarify that. "wrapper" in vmnet_qemu_send_wrapper may
> be also misleading as it does more than just calling the underlying QEMU
> facility, but it also updates VmnetCommonState.
>
>
Ok, I'll think about how to name them better.


> > +
> > +
> > +static void vmnet_send_completed(NetClientState *nc, ssize_t len)
> > +{
> > +VmnetCommonState *s = DO_UPCAST(VmnetCommonState, nc, nc);
> > +/* Complete sending packets left in VmnetCommonState buffers */
> > +s->send_enabled = vmnet_qemu_send_wrapper(s);
>
> It must qemu_bh_schedule(s->send_bh) after vmnet_qemu_send_wrapper.
>
>
Agree with you, thanks.


> Also, send_enabled flag can be removed as explained in:
> https://www.mail-archive.com/qemu-devel@nongnu.org/msg873923.html
>
>
Not sure about this. Values of packets_send_current_pos
and packets_send_end_pos may be equal, but QEMU may be
not ready to receive new packets - the explanation:
1. We are sending packets to QEMU with qemu_send_packet_async:
packets_send_current_pos = 0
packets_send_end_pos = 5
2. All five packets (0, 1, 2, 3, 4) have been successfully sent to QEMU,
but qemu_send_packet_async returned 0 "no more packets" after
the last invocation
3. In spite of this, all five packets are sent and
packets_send_current_pos == packets_send_end_pos == 5
4. It seems that "pointers are equal ->  QEMU is ready", but actually
it is not.

Also, hiding QEMU "ready"/"not ready" state behind pointers is a
bad choice I think. Having a concrete flag makes this more clear.
It provides understandability, not complexity (imho).


>  > send_enabled can be eliminated. When it is enabled, packets_send_pos
>  > and packets_batch_size must be equal. They must not be equal
>  > otherwise. packets_send_pos must represent the position of the packet
>  > which is not sent yet, possibly in the process of sending.
>  > vmnet_send_completed must call qemu_send_wrapper before scheduling
>  > send_bh. bh_send should do nothing if s->packets_send_pos <
>  > s->packets_batch_size.
>
> > +}
> > +
> > +
> > +static bool vmnet_qemu_send_wrapper(VmnetCommonState *s) {
> > +ssize_t size;
> > +
> > +/*
> > + * Packets to send lay in [current_pos..end_pos)
> > + * (including current_pos, excluding end_pos)
> > + */
> > +while (s->packets_send_current_pos < s->packets_send_end_pos) {
> > +size = qemu_send_packet_async(>nc,
> > +
> s->iov_buf[s->packets_send_current_pos].iov_base,
> > +
> s->packets_buf[s->packets_send_current_pos].vm_pkt_size,
> > +  vmnet_send_completed);
> > +++s->packets_send_current_pos;
> > +if (size == 0) {
> > +/* QEMU is not ready - wait for completion callback call */
> > +return false;
> > +}
> > +}
> > +return true;
&

[PATCH v16 7/7] net/vmnet: update hmp-commands.hx

2022-03-14 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 hmp-commands.hx | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 8476277aa9..8f3d78f177 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1265,7 +1265,11 @@ ERST
 {
 .name   = "netdev_add",
 .args_type  = "netdev:O",
-.params = 
"[user|tap|socket|vde|bridge|hubport|netmap|vhost-user],id=str[,prop=value][,...]",
+.params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user"
+#ifdef CONFIG_VMNET
+  "|vmnet-host|vmnet-shared|vmnet-bridged"
+#endif
+  "],id=str[,prop=value][,...]",
 .help   = "add host network device",
 .cmd= hmp_netdev_add,
 .command_completion = netdev_add_completion,
-- 
2.34.1.vfs.0.0




[PATCH v16 2/7] net/vmnet: add vmnet backends to qapi/net

2022-03-14 Thread Vladislav Yaroshchuk
Create separate netdevs for each vmnet operating mode:
- vmnet-host
- vmnet-shared
- vmnet-bridged

Signed-off-by: Vladislav Yaroshchuk 
---
 net/clients.h   |  11 
 net/meson.build |   7 +++
 net/net.c   |  10 
 net/vmnet-bridged.m |  25 +
 net/vmnet-common.m  |  20 +++
 net/vmnet-host.c|  24 
 net/vmnet-shared.c  |  25 +
 net/vmnet_int.h |  25 +
 qapi/net.json   | 133 +++-
 9 files changed, 278 insertions(+), 2 deletions(-)
 create mode 100644 net/vmnet-bridged.m
 create mode 100644 net/vmnet-common.m
 create mode 100644 net/vmnet-host.c
 create mode 100644 net/vmnet-shared.c
 create mode 100644 net/vmnet_int.h

diff --git a/net/clients.h b/net/clients.h
index 92f9b59aed..c9157789f2 100644
--- a/net/clients.h
+++ b/net/clients.h
@@ -63,4 +63,15 @@ int net_init_vhost_user(const Netdev *netdev, const char 
*name,
 
 int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
 NetClientState *peer, Error **errp);
+#ifdef CONFIG_VMNET
+int net_init_vmnet_host(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_shared(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+#endif /* CONFIG_VMNET */
+
 #endif /* QEMU_NET_CLIENTS_H */
diff --git a/net/meson.build b/net/meson.build
index 847bc2ac85..00a88c4951 100644
--- a/net/meson.build
+++ b/net/meson.build
@@ -42,4 +42,11 @@ softmmu_ss.add(when: 'CONFIG_POSIX', if_true: 
files(tap_posix))
 softmmu_ss.add(when: 'CONFIG_WIN32', if_true: files('tap-win32.c'))
 softmmu_ss.add(when: 'CONFIG_VHOST_NET_VDPA', if_true: files('vhost-vdpa.c'))
 
+vmnet_files = files(
+  'vmnet-common.m',
+  'vmnet-bridged.m',
+  'vmnet-host.c',
+  'vmnet-shared.c'
+)
+softmmu_ss.add(when: vmnet, if_true: vmnet_files)
 subdir('can')
diff --git a/net/net.c b/net/net.c
index f0d14dbfc1..1dbb64b935 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1021,6 +1021,11 @@ static int (* const 
net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
 #ifdef CONFIG_L2TPV3
 [NET_CLIENT_DRIVER_L2TPV3]= net_init_l2tpv3,
 #endif
+#ifdef CONFIG_VMNET
+[NET_CLIENT_DRIVER_VMNET_HOST] = net_init_vmnet_host,
+[NET_CLIENT_DRIVER_VMNET_SHARED] = net_init_vmnet_shared,
+[NET_CLIENT_DRIVER_VMNET_BRIDGED] = net_init_vmnet_bridged,
+#endif /* CONFIG_VMNET */
 };
 
 
@@ -1106,6 +,11 @@ void show_netdevs(void)
 #endif
 #ifdef CONFIG_VHOST_VDPA
 "vhost-vdpa",
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host",
+"vmnet-shared",
+"vmnet-bridged",
 #endif
 };
 
diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
new file mode 100644
index 00..c735901666
--- /dev/null
+++ b/net/vmnet-bridged.m
@@ -0,0 +1,25 @@
+/*
+ * vmnet-bridged.m
+ *
+ * Copyright(c) 2021 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+   NetClientState *peer, Error **errp)
+{
+  error_setg(errp, "vmnet-bridged is not implemented yet");
+  return -1;
+}
diff --git a/net/vmnet-common.m b/net/vmnet-common.m
new file mode 100644
index 00..56612c72ce
--- /dev/null
+++ b/net/vmnet-common.m
@@ -0,0 +1,20 @@
+/*
+ * vmnet-common.m - network client wrapper for Apple vmnet.framework
+ *
+ * Copyright(c) 2021 Vladislav Yaroshchuk 
+ * Copyright(c) 2021 Phillip Tennen 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
diff --git a/net/vmnet-host.c b/net/vmnet-host.c
new file mode 100644
index 00..32dc437037
--- /dev/null
+++ b/net/vmnet-host.c
@@ -0,0 +1,24 @@
+/*
+ * vmnet-host.c
+ *
+ * Copyright(c) 2021 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qa

[PATCH v16 6/7] net/vmnet: update qemu-options.hx

2022-03-14 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 qemu-options.hx | 25 +
 1 file changed, 25 insertions(+)

diff --git a/qemu-options.hx b/qemu-options.hx
index 5ce0ada75e..ea00d0eeb6 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2743,6 +2743,25 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
 #ifdef __linux__
 "-netdev vhost-vdpa,id=str,vhostdev=/path/to/dev\n"
 "configure a vhost-vdpa network,Establish a vhost-vdpa 
netdev\n"
+#endif
+#ifdef CONFIG_VMNET
+"-netdev vmnet-host,id=str[,isolated=on|off][,net-uuid=uuid]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in host mode with ID 
'str',\n"
+"isolate this interface from others with 'isolated',\n"
+"configure the address range and choose a subnet mask,\n"
+"specify network UUID 'uuid' to disable DHCP and interact 
with\n"
+"vmnet-host interfaces within this isolated network\n"
+"-netdev vmnet-shared,id=str[,isolated=on|off][,nat66-prefix=addr]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in shared mode with ID 
'str',\n"
+"configure the address range and choose a subnet mask,\n"
+"set IPv6 ULA prefix (of length 64) to use for internal 
network,\n"
+"isolate this interface from others with 'isolated'\n"
+"-netdev vmnet-bridged,id=str,ifname=name[,isolated=on|off]\n"
+"configure a vmnet network backend in bridged mode with ID 
'str',\n"
+"use 'ifname=name' to select a physical network interface 
to be bridged,\n"
+"isolate this interface from others with 'isolated'\n"
 #endif
 "-netdev hubport,id=str,hubid=n[,netdev=nd]\n"
 "configure a hub port on the hub with ID 'n'\n", 
QEMU_ARCH_ALL)
@@ -2762,6 +2781,9 @@ DEF("nic", HAS_ARG, QEMU_OPTION_nic,
 #endif
 #ifdef CONFIG_POSIX
 "vhost-user|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,...][mac=macaddr]\n"
 "initialize an on-board / default host NIC (using MAC 
address\n"
@@ -2784,6 +2806,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
 #endif
 #ifdef CONFIG_NETMAP
 "netmap|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,option][,...]\n"
 "old way to initialize a host network interface\n"
-- 
2.34.1.vfs.0.0




[PATCH v16 4/7] net/vmnet: implement host mode (vmnet-host)

2022-03-14 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-host.c | 116 ---
 1 file changed, 110 insertions(+), 6 deletions(-)

diff --git a/net/vmnet-host.c b/net/vmnet-host.c
index 32dc437037..15a832701a 100644
--- a/net/vmnet-host.c
+++ b/net/vmnet-host.c
@@ -9,16 +9,120 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/uuid.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+typedef struct VmnetHostState {
+VmnetCommonState cs;
+QemuUUID network_uuid;
+} VmnetHostState;
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+QemuUUID uuid;
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+if (options->has_net_uuid &&
+qemu_uuid_parse(options->net_uuid, ) < 0) {
+error_setg(errp, "Invalid UUID provided in 'net-uuid'");
+return false;
+}
+#else
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-host.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+
+if (options->has_net_uuid) {
+error_setg(errp,
+   "vmnet-host.net-uuid feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+
+if ((options->has_start_address ||
+ options->has_end_address ||
+ options->has_subnet_mask) &&
+!(options->has_start_address &&
+  options->has_end_address &&
+  options->has_subnet_mask)) {
+error_setg(errp,
+   "'start-address', 'end-address', 'subnet-mask' "
+   "should be provided together");
+return false;
+}
+
+return true;
+}
+
+static xpc_object_t build_if_desc(const Netdev *netdev,
+  NetClientState *nc)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+VmnetCommonState *cs = DO_UPCAST(VmnetCommonState, nc, nc);
+VmnetHostState *hs = DO_UPCAST(VmnetHostState, cs, cs);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_HOST_MODE);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+
+if (options->has_net_uuid) {
+qemu_uuid_parse(options->net_uuid, >network_uuid);
+xpc_dictionary_set_uuid(if_desc,
+vmnet_network_identifier_key,
+hs->network_uuid.data);
+}
+#endif
+
+if (options->has_start_address) {
+xpc_dictionary_set_string(if_desc,
+  vmnet_start_address_key,
+  options->start_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_end_address_key,
+  options->end_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_subnet_mask_key,
+  options->subnet_mask);
+}
+
+return if_desc;
+}
+
+static NetClientInfo net_vmnet_host_info = {
+.type = NET_CLIENT_DRIVER_VMNET_HOST,
+.size = sizeof(VmnetHostState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
 int net_init_vmnet_host(const Netdev *netdev, const char *name,
-NetClientState *peer, Error **errp) {
-  error_setg(errp, "vmnet-host is not implemented yet");
-  return -1;
+NetClientState *peer, Error **errp)
+{
+NetClientState *nc = qemu_new_net_client(_vmnet_host_info,
+ peer, "vmnet-host", name);
+if (!validate_options(netdev, errp)) {
+g_assert_not_reached();
+return -1;
+}
+return vmnet_if_create(nc, build_if_desc(netdev, nc), errp);
 }
-- 
2.34.1.vfs.0.0




[PATCH v16 5/7] net/vmnet: implement bridged mode (vmnet-bridged)

2022-03-14 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-bridged.m | 134 ++--
 1 file changed, 129 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
index c735901666..a23e03c40d 100644
--- a/net/vmnet-bridged.m
+++ b/net/vmnet-bridged.m
@@ -10,16 +10,140 @@
 
 #include "qemu/osdep.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+
+typedef struct VmnetBridgedState {
+VmnetCommonState cs;
+} VmnetBridgedState;
+
+
+static bool validate_ifname(const char *ifname)
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+bool match = false;
+if (!xpc_array_get_count(shared_if_list)) {
+goto done;
+}
+
+match = !xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+return strcmp(xpc_string_get_string_ptr(value), ifname) != 0;
+});
+
+done:
+xpc_release(shared_if_list);
+return match;
+}
+
+
+static bool get_valid_ifnames(char *output_buf)
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+__block const char *ifname = NULL;
+__block int str_offset = 0;
+bool interfaces_available = true;
+
+if (!xpc_array_get_count(shared_if_list)) {
+interfaces_available = false;
+goto done;
+}
+
+xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+/* build list of strings like "en0 en1 en2 " */
+ifname = xpc_string_get_string_ptr(value);
+strcpy(output_buf + str_offset, ifname);
+strcpy(output_buf + str_offset + strlen(ifname), " ");
+str_offset += strlen(ifname) + 1;
+return true;
+});
+
+done:
+xpc_release(shared_if_list);
+return interfaces_available;
+}
+
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+char ifnames[1024];
+
+if (!validate_ifname(options->ifname)) {
+if (get_valid_ifnames(ifnames)) {
+error_setg(errp,
+   "unsupported ifname '%s', expected one of [ %s]",
+   options->ifname,
+   ifnames);
+return false;
+}
+error_setg(errp,
+   "unsupported ifname '%s', no supported "
+   "interfaces available",
+   options->ifname);
+return false;
+}
+
+#if !defined(MAC_OS_VERSION_11_0) || \
+MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_11_0
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-bridged.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+return true;
+}
+
+
+static xpc_object_t build_if_desc(const Netdev *netdev)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_BRIDGED_MODE
+);
+
+xpc_dictionary_set_string(if_desc,
+  vmnet_shared_interface_name_key,
+  options->ifname);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+#endif
+return if_desc;
+}
+
+
+static NetClientInfo net_vmnet_bridged_info = {
+.type = NET_CLIENT_DRIVER_VMNET_BRIDGED,
+.size = sizeof(VmnetBridgedState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
+
 int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
NetClientState *peer, Error **errp)
 {
-  error_setg(errp, "vmnet-bridged is not implemented yet");
-  return -1;
+NetClientState *nc = qemu_new_net_client(_vmnet_bridged_info,
+ peer, "vmnet-bridged", name);
+if (!validate_options(netdev, errp)) {
+g_assert_not_reached();
+return -1;
+}
+return vmnet_if_create(nc, build_if_desc(netdev), errp);
 }
-- 
2.34.1.vfs.0.0




[PATCH v16 1/7] net/vmnet: add vmnet dependency and customizable option

2022-03-14 Thread Vladislav Yaroshchuk
vmnet.framework dependency is added with 'vmnet' option
to enable or disable it. Default value is 'auto'.

vmnet features to be used are available since macOS 11.0,
corresponding probe is created into meson.build.

Signed-off-by: Vladislav Yaroshchuk 
---
 meson.build   | 16 +++-
 meson_options.txt |  2 ++
 scripts/meson-buildoptions.sh |  1 +
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index 2d6601467f..806f3869f9 100644
--- a/meson.build
+++ b/meson.build
@@ -522,6 +522,18 @@ if cocoa.found() and get_option('gtk').enabled()
   error('Cocoa and GTK+ cannot be enabled at the same time')
 endif
 
+vmnet = dependency('appleframeworks', modules: 'vmnet', required: 
get_option('vmnet'))
+if vmnet.found() and not cc.has_header_symbol('vmnet/vmnet.h',
+  'VMNET_BRIDGED_MODE',
+  dependencies: vmnet)
+  vmnet = not_found
+  if get_option('vmnet').enabled()
+error('vmnet.framework API is outdated')
+  else
+warning('vmnet.framework API is outdated, disabling')
+  endif
+endif
+
 seccomp = not_found
 if not get_option('seccomp').auto() or have_system or have_tools
   seccomp = dependency('libseccomp', version: '>=2.3.0',
@@ -1550,6 +1562,7 @@ config_host_data.set('CONFIG_SNAPPY', snappy.found())
 config_host_data.set('CONFIG_TPM', have_tpm)
 config_host_data.set('CONFIG_USB_LIBUSB', libusb.found())
 config_host_data.set('CONFIG_VDE', vde.found())
+config_host_data.set('CONFIG_VMNET', vmnet.found())
 config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', 
have_vhost_user_blk_server)
 config_host_data.set('CONFIG_VNC', vnc.found())
 config_host_data.set('CONFIG_VNC_JPEG', jpeg.found())
@@ -3588,7 +3601,8 @@ summary(summary_info, bool_yn: true, section: 'Crypto')
 # Libraries
 summary_info = {}
 if targetos == 'darwin'
-  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'vmnet.framework support': vmnet}
 endif
 summary_info += {'SDL support':   sdl}
 summary_info += {'SDL image support': sdl_image}
diff --git a/meson_options.txt b/meson_options.txt
index 52b11cead4..d2c0b6b412 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -175,6 +175,8 @@ option('netmap', type : 'feature', value : 'auto',
description: 'netmap network backend support')
 option('vde', type : 'feature', value : 'auto',
description: 'vde network backend support')
+option('vmnet', type : 'feature', value : 'auto',
+   description: 'vmnet.framework network backend support')
 option('virglrenderer', type : 'feature', value : 'auto',
description: 'virgl rendering support')
 option('vnc', type : 'feature', value : 'auto',
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 9ee684ef03..30946f3798 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -116,6 +116,7 @@ meson_options_help() {
   printf "%s\n" '  usb-redir   libusbredir support'
   printf "%s\n" '  vde vde network backend support'
   printf "%s\n" '  vdi vdi image format support'
+  printf "%s\n" '  vmnet   vmnet.framework network backend support'
   printf "%s\n" '  vhost-user-blk-server'
   printf "%s\n" '  build vhost-user-blk server'
   printf "%s\n" '  virglrenderer   virgl rendering support'
-- 
2.34.1.vfs.0.0




[PATCH v16 0/7] Add vmnet.framework based network backend

2022-03-14 Thread Vladislav Yaroshchuk
r proper printing
 - NOTE: This version of patch series may be one the last
   I submit - JetBrains has suspended operations in
   Russia indefinitely due to all the awful things happened
   the last weeks. I may leave this company and loose the
   ability to work on vmnet support :(
   It will be perfect if someone can handle my unfinished work,
   if something required to fix/improve is found.
   Because of this, MAINTAINERS list update is dropped


Vladislav Yaroshchuk (7):
  net/vmnet: add vmnet dependency and customizable option
  net/vmnet: add vmnet backends to qapi/net
  net/vmnet: implement shared mode (vmnet-shared)
  net/vmnet: implement host mode (vmnet-host)
  net/vmnet: implement bridged mode (vmnet-bridged)
  net/vmnet: update qemu-options.hx
  net/vmnet: update hmp-commands.hx

 hmp-commands.hx   |   6 +-
 meson.build   |  16 +-
 meson_options.txt |   2 +
 net/clients.h |  11 ++
 net/meson.build   |   7 +
 net/net.c |  10 ++
 net/vmnet-bridged.m   | 149 
 net/vmnet-common.m| 318 ++
 net/vmnet-host.c  | 128 ++
 net/vmnet-shared.c| 112 
 net/vmnet_int.h   |  64 +++
 qapi/net.json | 133 +-
 qemu-options.hx   |  25 +++
 scripts/meson-buildoptions.sh |   1 +
 14 files changed, 978 insertions(+), 4 deletions(-)
 create mode 100644 net/vmnet-bridged.m
 create mode 100644 net/vmnet-common.m
 create mode 100644 net/vmnet-host.c
 create mode 100644 net/vmnet-shared.c
 create mode 100644 net/vmnet_int.h

-- 
2.34.1.vfs.0.0




[PATCH v16 3/7] net/vmnet: implement shared mode (vmnet-shared)

2022-03-14 Thread Vladislav Yaroshchuk
vmnet.framework supports iov, but writing more than
one iov into vmnet interface fails with
'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
one and passing it to vmnet works fine. That's the
reason why receive_iov() left unimplemented. But it still
works with good enough performance having .receive()
implemented only.

Signed-off-by: Phillip Tennen 
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-common.m | 298 +
 net/vmnet-shared.c |  95 ++-
 net/vmnet_int.h|  41 ++-
 3 files changed, 429 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-common.m b/net/vmnet-common.m
index 56612c72ce..20a33d2591 100644
--- a/net/vmnet-common.m
+++ b/net/vmnet-common.m
@@ -10,6 +10,8 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "qemu/log.h"
 #include "qapi/qapi-types-net.h"
 #include "vmnet_int.h"
 #include "clients.h"
@@ -17,4 +19,300 @@
 #include "qapi/error.h"
 
 #include 
+#include 
 
+static bool vmnet_qemu_send_wrapper(VmnetCommonState *s);
+
+
+static void vmnet_send_completed(NetClientState *nc, ssize_t len)
+{
+VmnetCommonState *s = DO_UPCAST(VmnetCommonState, nc, nc);
+/* Complete sending packets left in VmnetCommonState buffers */
+s->send_enabled = vmnet_qemu_send_wrapper(s);
+}
+
+
+static bool vmnet_qemu_send_wrapper(VmnetCommonState *s) {
+ssize_t size;
+
+/*
+ * Packets to send lay in [current_pos..end_pos)
+ * (including current_pos, excluding end_pos)
+ */
+while (s->packets_send_current_pos < s->packets_send_end_pos) {
+size = qemu_send_packet_async(>nc,
+  
s->iov_buf[s->packets_send_current_pos].iov_base,
+  
s->packets_buf[s->packets_send_current_pos].vm_pkt_size,
+  vmnet_send_completed);
+++s->packets_send_current_pos;
+if (size == 0) {
+/* QEMU is not ready - wait for completion callback call */
+return false;
+}
+}
+return true;
+}
+
+
+static void vmnet_send_bh(void *opaque)
+{
+NetClientState *nc = (NetClientState *) opaque;
+VmnetCommonState *s = DO_UPCAST(VmnetCommonState, nc, nc);
+struct vmpktdesc *packets = s->packets_buf;
+vmnet_return_t status;
+int i;
+
+/*
+ * Do nothing if QEMU is not ready - wait
+ * for completion callback invocation
+ */
+if (!s->send_enabled) {
+return;
+}
+
+/* Read as many packets as present */
+s->packets_send_current_pos = 0;
+s->packets_send_end_pos = VMNET_PACKETS_LIMIT;
+for (i = 0; i < s->packets_send_end_pos; ++i) {
+packets[i].vm_pkt_size = s->max_packet_size;
+packets[i].vm_pkt_iovcnt = 1;
+packets[i].vm_flags = 0;
+}
+
+status = vmnet_read(s->vmnet_if, packets, >packets_send_end_pos);
+if (status != VMNET_SUCCESS) {
+error_printf("vmnet: read failed: %s\n",
+ vmnet_status_map_str(status));
+s->packets_send_current_pos = 0;
+s->packets_send_end_pos = 0;
+return;
+}
+
+/* Send packets to QEMU */
+s->send_enabled = vmnet_qemu_send_wrapper(s);
+}
+
+
+static void vmnet_bufs_init(VmnetCommonState *s)
+{
+struct vmpktdesc *packets = s->packets_buf;
+struct iovec *iov = s->iov_buf;
+int i;
+
+for (i = 0; i < VMNET_PACKETS_LIMIT; ++i) {
+iov[i].iov_len = s->max_packet_size;
+iov[i].iov_base = g_malloc0(iov[i].iov_len);
+packets[i].vm_pkt_iov = iov + i;
+}
+}
+
+
+const char *vmnet_status_map_str(vmnet_return_t status)
+{
+switch (status) {
+case VMNET_SUCCESS:
+return "success";
+case VMNET_FAILURE:
+return "general failure (possibly not enough privileges)";
+case VMNET_MEM_FAILURE:
+return "memory allocation failure";
+case VMNET_INVALID_ARGUMENT:
+return "invalid argument specified";
+case VMNET_SETUP_INCOMPLETE:
+return "interface setup is not complete";
+case VMNET_INVALID_ACCESS:
+return "invalid access, permission denied";
+case VMNET_PACKET_TOO_BIG:
+return "packet size is larger than MTU";
+case VMNET_BUFFER_EXHAUSTED:
+return "buffers exhausted in kernel";
+case VMNET_TOO_MANY_PACKETS:
+return "packet count exceeds limit";
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+case VMNET_SHARING_SERVICE_BUSY:
+return "conflict, sharing service is in use";
+#endif
+default:
+return "unknown vmnet error";
+}
+}
+
+
+int vmnet_if_create(NetClientState *nc,
+   

Re: [PATCH v15 3/8] net/vmnet: implement shared mode (vmnet-shared)

2022-03-03 Thread Vladislav Yaroshchuk
On Tue, Mar 1, 2022 at 11:21 AM Akihiko Odaki 
wrote:

> On 2022/03/01 17:09, Vladislav Yaroshchuk wrote:
> >  > Not sure that only one field is enough, cause
> >  > we may have two states on bh execution start:
> >  > 1. There are packets in vmnet buffer s->packets_buf
> >  >  that were rejected by qemu_send_async and waiting
> >  >  to be sent. If this happens, we should complete sending
> >  >  these waiting packets with qemu_send_async firstly,
> >  >  and after that we should call vmnet_read to get
> >  >  new ones and send them to QEMU;
> >  > 2. There are no packets in s->packets_buf to be sent to
> >  >  qemu, we only need to get new packets from vmnet
> >  >  with vmnet_read and send them to QEMU
> >
> > In case 1, you should just keep calling qemu_send_packet_async.
> > Actually
> > qemu_send_packet_async adds the packet to its internal queue and
> calls
> > the callback when it is consumed.
> >
> >
> > I'm not sure we can keep calling qemu_send_packet_async,
> > because as docs from net/queue.c says:
> >
> > /* [...]
> >   * If a sent callback is provided to send(), the caller must handle a
> >   * zero return from the delivery handler by not sending any more packets
> >   * until we have invoked the callback. Only in that case will we queue
> >   * the packet.
> >   *
> >   * If a sent callback isn't provided, we just drop the packet to avoid
> >   * unbounded queueing.
> >   */
> >
> > So after we did vmnet_read and read N packets
> > into temporary s->packets_buf, we begin calling
> > qemu_send_packet_async. If it returns 0 - it says
> > "no more packets until sent_cb called please".
> > At this moment we have N packets in s->packets_buf
> > and already queued K < N of them. But, packets K..N
> > are not queued and keep waiting for sent_cb to be sent
> > with qemu_send_packet_async.
> > Thus when sent_cb called, we should finish
> > our transfer of packets K..N from s->packets_buf
> > to qemu calling qemu_send_packet_async.
> > I meant this.
>
> I missed the comment. The description is contradicting with the actual
> code; qemu_net_queue_send_iov appends the packet to the queue whenever
> it cannot send one immediately.
>
>
Yes, it appends, but (net/queue.c):
*  qemu_net_queue_send tries to deliver the packet
immediately. If the packet cannot be delivered, the
qemu_net_queue_append is called and 0 is returned
to say the caller "the receiver is not ready, hold on";
*  qemu_net_queue_append does a probe before adding
the packet to the queue:
if (queue->nq_count >= queue->nq_maxlen && !sent_cb) {
return; /* drop if queue full and no callback */
}

The queue is not infinite, so we have three cases:
1. The queue is not full -> append the packet, no
problems here
2. The queue is full, no callback -> we cannot notify
a caller when we're ready, so just drop the packet
if we can't append it.
3. The queue is full, callback present -> we can notify
a caller when we are ready, so "let's queue this packet,
but expect no more (!) packets is sent until I call
sent_cb when the queue is ready"

Therefore if we provide a callback and keep sending
packets if 0 is returned, this may cause unlimited(!)
queue growth. To prevent this, we should stop sending
packets and wait for notification callback to continue.

I don't see any contradiction with that comment.

Jason Wang, I saw you are in the MAINTAINERS for net/. Can you tell if
> calling qemu_send_packet_async is allowed after it returns 0?
>
>
It may be wrong, but I think it's not allowed to send
packets after qemu_send_packet_async returns 0.

Jason Wang, can you confirm please?

Best Regards,

Vladislav Yaroshchuk


> Regards,
> Akihiko Odaki
>


Re: [PATCH v15 3/8] net/vmnet: implement shared mode (vmnet-shared)

2022-03-01 Thread Vladislav Yaroshchuk
On Tue, Mar 1, 2022 at 8:52 AM Akihiko Odaki 
wrote:

> On 2022/02/28 20:59, Vladislav Yaroshchuk wrote:
> >
> >
> > On Sat, Feb 26, 2022 at 3:27 PM Akihiko Odaki  > <mailto:akihiko.od...@gmail.com>> wrote:
> >
> >     On Sat, Feb 26, 2022 at 8:33 PM Vladislav Yaroshchuk
> >  > <mailto:vladislav.yaroshc...@jetbrains.com>> wrote:
> >  >
> >  >
> >  >
> >  > On Sat, Feb 26, 2022 at 12:16 PM Akihiko Odaki
> > mailto:akihiko.od...@gmail.com>> wrote:
> >  >>
> >  >> On 2022/02/26 17:37, Vladislav Yaroshchuk wrote:
> >  >> >
> >  >> > Hi Akihiko,
> >  >> >
> >  >> > On Fri, Feb 25, 2022 at 8:46 PM Akihiko Odaki
> > mailto:akihiko.od...@gmail.com>
> >  >> > <mailto:akihiko.od...@gmail.com
> > <mailto:akihiko.od...@gmail.com>>> wrote:
> >  >> >
> >  >> > On 2022/02/26 2:13, Vladislav Yaroshchuk wrote:
> >  >> >  > Interaction with vmnet.framework in different modes
> >  >> >  > differs only on configuration stage, so we can create
> >  >> >  > common `send`, `receive`, etc. procedures and reuse
> them.
> >  >> >  >
> >  >> >  > vmnet.framework supports iov, but writing more than
> >  >> >  > one iov into vmnet interface fails with
> >  >> >  > 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
> >  >> >  > one and passing it to vmnet works fine. That's the
> >  >> >  > reason why receive_iov() left unimplemented. But it
> still
> >  >> >  > works with good enough performance having .receive()
> >  >> >  > net/vmnet: implement shared mode (vmnet-shared)
> >  >> >  >
> >  >> >  > Interaction with vmnet.framework in different modes
> >  >> >  > differs only on configuration stage, so we can create
> >  >> >  > common `send`, `receive`, etc. procedures and reuse
> them.
> >  >> >  >
> >  >> >  > vmnet.framework supports iov, but writing more than
> >  >> >  > one iov into vmnet interface fails with
> >  >> >  > 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
> >  >> >  > one and passing it to vmnet works fine. That's the
> >  >> >  > reason why receive_iov() left unimplemented. But it
> still
> >  >> >  > works with good enough performance having .receive()
> >  >> >  > implemented only.
> >  >> >  >
> >  >> >  > Also, there is no way to unsubscribe from vmnet packages
> >  >> >  > receiving except registering and unregistering event
> >  >> >  > callback or simply drop packages just ignoring and
> >  >> >  > not processing them when related flag is set. Here we do
> >  >> >  > using the second way.
> >  >> >  >
> >  >> >  > Signed-off-by: Phillip Tennen  > <mailto:phil...@axleos.com>
> >  >> > <mailto:phil...@axleos.com <mailto:phil...@axleos.com>>>
> >  >> >  > Signed-off-by: Vladislav Yaroshchuk
> >  >> >  > <mailto:vladislav.yaroshc...@jetbrains.com>
> >  >> > <mailto:vladislav.yaroshc...@jetbrains.com
> > <mailto:vladislav.yaroshc...@jetbrains.com>>>
> >  >> >
> >  >> > Thank you for persistently working on this.
> >  >> >
> >  >> >  > ---
> >  >> >  >   net/vmnet-common.m | 302
> >  >> > +
> >  >> >  >   net/vmnet-shared.c |  94 +-
> >  >> >  >   net/vmnet_int.h|  39 +-
> >  >> >  >   3 files changed, 430 insertions(+), 5 deletions(-)
> >  >> >  >
> >  >> >  > diff --git a/net/vmnet-common.m b/net/vmnet-common.m
> >  >> >  > index 56612c72ce..2f70921cae 100644
> >  >> >  > --- a/net/vmnet-comm

Re: [PATCH v15 3/8] net/vmnet: implement shared mode (vmnet-shared)

2022-02-28 Thread Vladislav Yaroshchuk
On Sat, Feb 26, 2022 at 3:27 PM Akihiko Odaki 
wrote:

> On Sat, Feb 26, 2022 at 8:33 PM Vladislav Yaroshchuk
>  wrote:
> >
> >
> >
> > On Sat, Feb 26, 2022 at 12:16 PM Akihiko Odaki 
> wrote:
> >>
> >> On 2022/02/26 17:37, Vladislav Yaroshchuk wrote:
> >> >
> >> > Hi Akihiko,
> >> >
> >> > On Fri, Feb 25, 2022 at 8:46 PM Akihiko Odaki <
> akihiko.od...@gmail.com
> >> > <mailto:akihiko.od...@gmail.com>> wrote:
> >> >
> >> > On 2022/02/26 2:13, Vladislav Yaroshchuk wrote:
> >> >  > Interaction with vmnet.framework in different modes
> >> >  > differs only on configuration stage, so we can create
> >> >  > common `send`, `receive`, etc. procedures and reuse them.
> >> >  >
> >> >  > vmnet.framework supports iov, but writing more than
> >> >  > one iov into vmnet interface fails with
> >> >  > 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
> >> >  > one and passing it to vmnet works fine. That's the
> >> >  > reason why receive_iov() left unimplemented. But it still
> >> >  > works with good enough performance having .receive()
> >> >  > net/vmnet: implement shared mode (vmnet-shared)
> >> >  >
> >> >  > Interaction with vmnet.framework in different modes
> >> >  > differs only on configuration stage, so we can create
> >> >  > common `send`, `receive`, etc. procedures and reuse them.
> >> >  >
> >> >  > vmnet.framework supports iov, but writing more than
> >> >  > one iov into vmnet interface fails with
> >> >  > 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
> >> >  > one and passing it to vmnet works fine. That's the
> >> >  > reason why receive_iov() left unimplemented. But it still
> >> >  > works with good enough performance having .receive()
> >> >  > implemented only.
> >> >  >
> >> >  > Also, there is no way to unsubscribe from vmnet packages
> >> >  > receiving except registering and unregistering event
> >> >  > callback or simply drop packages just ignoring and
> >> >  > not processing them when related flag is set. Here we do
> >> >  > using the second way.
> >> >  >
> >> >  > Signed-off-by: Phillip Tennen  >> > <mailto:phil...@axleos.com>>
> >> >  > Signed-off-by: Vladislav Yaroshchuk
> >> >  >> > <mailto:vladislav.yaroshc...@jetbrains.com>>
> >> >
> >> > Thank you for persistently working on this.
> >> >
> >> >  > ---
> >> >  >   net/vmnet-common.m | 302
> >> > +
> >> >  >   net/vmnet-shared.c |  94 +-
> >> >  >   net/vmnet_int.h|  39 +-
> >> >  >   3 files changed, 430 insertions(+), 5 deletions(-)
> >> >  >
> >> >  > diff --git a/net/vmnet-common.m b/net/vmnet-common.m
> >> >  > index 56612c72ce..2f70921cae 100644
> >> >  > --- a/net/vmnet-common.m
> >> >  > +++ b/net/vmnet-common.m
> >> >  > @@ -10,6 +10,8 @@
> >> >  >*/
> >> >  >
> >> >  >   #include "qemu/osdep.h"
> >> >  > +#include "qemu/main-loop.h"
> >> >  > +#include "qemu/log.h"
> >> >  >   #include "qapi/qapi-types-net.h"
> >> >  >   #include "vmnet_int.h"
> >> >  >   #include "clients.h"
> >> >  > @@ -17,4 +19,304 @@
> >> >  >   #include "qapi/error.h"
> >> >  >
> >> >  >   #include 
> >> >  > +#include 
> >> >  >
> >> >  > +
> >> >  > +static inline void
> vmnet_set_send_bh_scheduled(VmnetCommonState *s,
> >> >  > +   bool enable)
> >> >  > +{
> >> >  > +qatomic_set(>send_scheduled, enable);
> >> >  > +}
> >> &g

Re: [PATCH v15 2/8] net/vmnet: add vmnet backends to qapi/net

2022-02-28 Thread Vladislav Yaroshchuk
On Mon, Feb 28, 2022 at 1:07 PM Markus Armbruster  wrote:

> Vladislav Yaroshchuk  writes:
>
> > Create separate netdevs for each vmnet operating mode:
> > - vmnet-host
> > - vmnet-shared
> > - vmnet-bridged
> >
> > Signed-off-by: Vladislav Yaroshchuk 
>
> I acked v8 and v13 of the QAPI schema part.  You should add Acked-by and
> Reviewed-by you receive in later revisions, unless you make changes that
> invalidate them.  When in doubt, drop them.  However, this patch is
> identical to v13.  You dropping my Acked-by made me look at it again,
> wasting my time.  Please don't.
>
>
I missed the qapi discussion thread while working on other parts,
sincerely apologize. Don't want to waste your time, sorry.


> > diff --git a/qapi/net.json b/qapi/net.json
> > index 7fab2e7cd8..b922e2e34f 100644
> > --- a/qapi/net.json
> > +++ b/qapi/net.json
> > @@ -452,6 +452,120 @@
> >  '*vhostdev': 'str',
> >  '*queues':   'int' } }
> >
> > +##
> > +# @NetdevVmnetHostOptions:
> > +#
> > +# vmnet (host mode) network backend.
> > +#
> > +# Allows the vmnet interface to communicate with other vmnet
> > +# interfaces that are in host mode and also with the host.
> > +#
> > +# @start-address: The starting IPv4 address to use for the interface.
> > +# Must be in the private IP range (RFC 1918). Must be
> > +# specified along with @end-address and @subnet-mask.
> > +# This address is used as the gateway address. The
> > +# subsequent address up to and including end-address are
> > +# placed in the DHCP pool.
> > +#
> > +# @end-address: The DHCP IPv4 range end address to use for the
> > +#   interface. Must be in the private IP range (RFC 1918).
> > +#   Must be specified along with @start-address and
> > +#   @subnet-mask.
> > +#
> > +# @subnet-mask: The IPv4 subnet mask to use on the interface. Must
> > +#   be specified along with @start-address and @subnet-mask.
> > +#
> > +# @isolated: Enable isolation for this interface. Interface isolation
> > +#ensures that vmnet interface is not able to communicate
> > +#with any other vmnet interfaces. Only communication with
> > +#host is allowed. Available since macOS Big Sur 11.0.
>
> In review of v13, I suggested to replace "Available since macOS Big Sur
> 11.0" by "Requires at least macOS Big Sur 11.0" here and below, and you
> agreed.  Looks like you forgot to actually change them.
>
> With these changes, QAPI schema
> Acked-by: Markus Armbruster 
>
>
Fixed locally, will submit within the next version. Thank you!

[...]
>
>
Best Regards,

Vladislav Yaroshchuk


Re: [PATCH v15 3/8] net/vmnet: implement shared mode (vmnet-shared)

2022-02-26 Thread Vladislav Yaroshchuk
On Sat, Feb 26, 2022 at 12:16 PM Akihiko Odaki 
wrote:

> On 2022/02/26 17:37, Vladislav Yaroshchuk wrote:
> >
> > Hi Akihiko,
> >
> > On Fri, Feb 25, 2022 at 8:46 PM Akihiko Odaki  > <mailto:akihiko.od...@gmail.com>> wrote:
> >
> > On 2022/02/26 2:13, Vladislav Yaroshchuk wrote:
> >  > Interaction with vmnet.framework in different modes
> >  > differs only on configuration stage, so we can create
> >  > common `send`, `receive`, etc. procedures and reuse them.
> >  >
> >  > vmnet.framework supports iov, but writing more than
> >  > one iov into vmnet interface fails with
> >  > 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
> >  > one and passing it to vmnet works fine. That's the
> >  > reason why receive_iov() left unimplemented. But it still
> >  > works with good enough performance having .receive()
> >  > net/vmnet: implement shared mode (vmnet-shared)
> >  >
> >  > Interaction with vmnet.framework in different modes
> >  > differs only on configuration stage, so we can create
> >  > common `send`, `receive`, etc. procedures and reuse them.
> >  >
> >  > vmnet.framework supports iov, but writing more than
> >  > one iov into vmnet interface fails with
> >  > 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
> >  > one and passing it to vmnet works fine. That's the
> >  > reason why receive_iov() left unimplemented. But it still
> >  > works with good enough performance having .receive()
> >  > implemented only.
> >  >
> >  > Also, there is no way to unsubscribe from vmnet packages
> >  > receiving except registering and unregistering event
> >      > callback or simply drop packages just ignoring and
> >  > not processing them when related flag is set. Here we do
> >  > using the second way.
> >  >
> >  > Signed-off-by: Phillip Tennen  > <mailto:phil...@axleos.com>>
> >  > Signed-off-by: Vladislav Yaroshchuk
> >  > <mailto:vladislav.yaroshc...@jetbrains.com>>
> >
> > Thank you for persistently working on this.
> >
> >  > ---
> >  >   net/vmnet-common.m | 302
> > +
> >  >   net/vmnet-shared.c |  94 +-
> >  >   net/vmnet_int.h|  39 +-
> >  >   3 files changed, 430 insertions(+), 5 deletions(-)
> >  >
> >  > diff --git a/net/vmnet-common.m b/net/vmnet-common.m
> >  > index 56612c72ce..2f70921cae 100644
> >  > --- a/net/vmnet-common.m
> >  > +++ b/net/vmnet-common.m
> >  > @@ -10,6 +10,8 @@
> >  >*/
> >  >
> >  >   #include "qemu/osdep.h"
> >  > +#include "qemu/main-loop.h"
> >  > +#include "qemu/log.h"
> >  >   #include "qapi/qapi-types-net.h"
> >  >   #include "vmnet_int.h"
> >  >   #include "clients.h"
> >  > @@ -17,4 +19,304 @@
> >  >   #include "qapi/error.h"
> >  >
> >  >   #include 
> >  > +#include 
> >  >
> >  > +
> >  > +static inline void vmnet_set_send_bh_scheduled(VmnetCommonState
> *s,
> >  > +   bool enable)
> >  > +{
> >  > +qatomic_set(>send_scheduled, enable);
> >  > +}
> >  > +
> >  > +
> >  > +static inline bool vmnet_is_send_bh_scheduled(VmnetCommonState
> *s)
> >  > +{
> >  > +return qatomic_load_acquire(>send_scheduled);
> >  > +}
> >  > +
> >  > +
> >  > +static inline void vmnet_set_send_enabled(VmnetCommonState *s,
> >  > +  bool enable)
> >  > +{
> >  > +if (enable) {
> >  > +vmnet_interface_set_event_callback(
> >  > +s->vmnet_if,
> >  > +VMNET_INTERFACE_PACKETS_AVAILABLE,
> >  > +s->if_queue,
> >  > +^(interface_event_t event_id, xpc_object_t event) {
> >  > +assert(event_id ==
> > VMNET_INTERFACE_PACKETS_AVAILABLE);
> >  > +/*
> >  

Re: [PATCH v15 3/8] net/vmnet: implement shared mode (vmnet-shared)

2022-02-26 Thread Vladislav Yaroshchuk
Hi Akihiko,

On Fri, Feb 25, 2022 at 8:46 PM Akihiko Odaki 
wrote:

> On 2022/02/26 2:13, Vladislav Yaroshchuk wrote:
> > Interaction with vmnet.framework in different modes
> > differs only on configuration stage, so we can create
> > common `send`, `receive`, etc. procedures and reuse them.
> >
> > vmnet.framework supports iov, but writing more than
> > one iov into vmnet interface fails with
> > 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
> > one and passing it to vmnet works fine. That's the
> > reason why receive_iov() left unimplemented. But it still
> > works with good enough performance having .receive()
> > net/vmnet: implement shared mode (vmnet-shared)
> >
> > Interaction with vmnet.framework in different modes
> > differs only on configuration stage, so we can create
> > common `send`, `receive`, etc. procedures and reuse them.
> >
> > vmnet.framework supports iov, but writing more than
> > one iov into vmnet interface fails with
> > 'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
> > one and passing it to vmnet works fine. That's the
> > reason why receive_iov() left unimplemented. But it still
> > works with good enough performance having .receive()
> > implemented only.
> >
> > Also, there is no way to unsubscribe from vmnet packages
> > receiving except registering and unregistering event
> > callback or simply drop packages just ignoring and
> > not processing them when related flag is set. Here we do
> > using the second way.
> >
> > Signed-off-by: Phillip Tennen 
> > Signed-off-by: Vladislav Yaroshchuk 
>
> Thank you for persistently working on this.
>
> > ---
> >   net/vmnet-common.m | 302 +
> >   net/vmnet-shared.c |  94 +-
> >   net/vmnet_int.h|  39 +-
> >   3 files changed, 430 insertions(+), 5 deletions(-)
> >
> > diff --git a/net/vmnet-common.m b/net/vmnet-common.m
> > index 56612c72ce..2f70921cae 100644
> > --- a/net/vmnet-common.m
> > +++ b/net/vmnet-common.m
> > @@ -10,6 +10,8 @@
> >*/
> >
> >   #include "qemu/osdep.h"
> > +#include "qemu/main-loop.h"
> > +#include "qemu/log.h"
> >   #include "qapi/qapi-types-net.h"
> >   #include "vmnet_int.h"
> >   #include "clients.h"
> > @@ -17,4 +19,304 @@
> >   #include "qapi/error.h"
> >
> >   #include 
> > +#include 
> >
> > +
> > +static inline void vmnet_set_send_bh_scheduled(VmnetCommonState *s,
> > +   bool enable)
> > +{
> > +qatomic_set(>send_scheduled, enable);
> > +}
> > +
> > +
> > +static inline bool vmnet_is_send_bh_scheduled(VmnetCommonState *s)
> > +{
> > +return qatomic_load_acquire(>send_scheduled);
> > +}
> > +
> > +
> > +static inline void vmnet_set_send_enabled(VmnetCommonState *s,
> > +  bool enable)
> > +{
> > +if (enable) {
> > +vmnet_interface_set_event_callback(
> > +s->vmnet_if,
> > +VMNET_INTERFACE_PACKETS_AVAILABLE,
> > +s->if_queue,
> > +^(interface_event_t event_id, xpc_object_t event) {
> > +assert(event_id == VMNET_INTERFACE_PACKETS_AVAILABLE);
> > +/*
> > + * This function is being called from a non qemu
> thread, so
> > + * we only schedule a BH, and do the rest of the io
> completion
> > + * handling from vmnet_send_bh() which runs in a qemu
> context.
> > + *
> > + * Avoid scheduling multiple bottom halves
> > + */
> > +if (!vmnet_is_send_bh_scheduled(s)) {
> > +vmnet_set_send_bh_scheduled(s, true);
>
> It can be interrupted between vmnet_is_send_bh_scheduled and
> vmnet_set_send_bh_scheduled, which leads to data race.
>
>
Sorry, I did not clearly understand what you meant. Since this
callback (block) is submitted on DISPATCH_QUEUE_SERIAL,
only one instance of the callback will be executed at any
moment of time.
https://developer.apple.com/documentation/dispatch/dispatch_queue_serial

Also this is the only place where we schedule a bottom half.

After we set the 'send_scheduled' flag, all the other
callback  blocks will do nothing (skip the if block) until
the bottom half is executed and reset 'send_scheduled'.
I don't see any races here :(

Correct me if I

[PATCH v15 4/8] net/vmnet: implement host mode (vmnet-host)

2022-02-25 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-host.c | 115 ---
 1 file changed, 109 insertions(+), 6 deletions(-)

diff --git a/net/vmnet-host.c b/net/vmnet-host.c
index 32dc437037..2a711400e7 100644
--- a/net/vmnet-host.c
+++ b/net/vmnet-host.c
@@ -9,16 +9,119 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/uuid.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+typedef struct VmnetHostState {
+VmnetCommonState cs;
+QemuUUID network_uuid;
+} VmnetHostState;
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+QemuUUID uuid;
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+if (options->has_net_uuid &&
+qemu_uuid_parse(options->net_uuid, ) < 0) {
+error_setg(errp, "Invalid UUID provided in 'net-uuid'");
+return false;
+}
+#else
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-host.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+
+if (options->has_net_uuid) {
+error_setg(errp,
+   "vmnet-host.net-uuid feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+
+if ((options->has_start_address ||
+ options->has_end_address ||
+ options->has_subnet_mask) &&
+!(options->has_start_address &&
+  options->has_end_address &&
+  options->has_subnet_mask)) {
+error_setg(errp,
+   "'start-address', 'end-address', 'subnet-mask' "
+   "should be provided together");
+return false;
+}
+
+return true;
+}
+
+static xpc_object_t build_if_desc(const Netdev *netdev,
+  NetClientState *nc)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+VmnetCommonState *cs = DO_UPCAST(VmnetCommonState, nc, nc);
+VmnetHostState *hs = DO_UPCAST(VmnetHostState, cs, cs);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_HOST_MODE);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+
+if (options->has_net_uuid) {
+qemu_uuid_parse(options->net_uuid, >network_uuid);
+xpc_dictionary_set_uuid(if_desc,
+vmnet_network_identifier_key,
+hs->network_uuid.data);
+}
+#endif
+
+if (options->has_start_address) {
+xpc_dictionary_set_string(if_desc,
+  vmnet_start_address_key,
+  options->start_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_end_address_key,
+  options->end_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_subnet_mask_key,
+  options->subnet_mask);
+}
+
+return if_desc;
+}
+
+static NetClientInfo net_vmnet_host_info = {
+.type = NET_CLIENT_DRIVER_VMNET_HOST,
+.size = sizeof(VmnetHostState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
 int net_init_vmnet_host(const Netdev *netdev, const char *name,
-NetClientState *peer, Error **errp) {
-  error_setg(errp, "vmnet-host is not implemented yet");
-  return -1;
+NetClientState *peer, Error **errp)
+{
+NetClientState *nc = qemu_new_net_client(_vmnet_host_info,
+ peer, "vmnet-host", name);
+if (!validate_options(netdev, errp)) {
+g_assert_not_reached();
+}
+return vmnet_if_create(nc, build_if_desc(netdev, nc), errp);
 }
-- 
2.34.1.vfs.0.0




[PATCH v15 1/8] net/vmnet: add vmnet dependency and customizable option

2022-02-25 Thread Vladislav Yaroshchuk
vmnet.framework dependency is added with 'vmnet' option
to enable or disable it. Default value is 'auto'.

vmnet features to be used are available since macOS 11.0,
corresponding probe is created into meson.build.

Signed-off-by: Vladislav Yaroshchuk 
---
 meson.build   | 16 +++-
 meson_options.txt |  2 ++
 scripts/meson-buildoptions.sh |  1 +
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/meson.build b/meson.build
index 8df40bfac4..d3a791e6c4 100644
--- a/meson.build
+++ b/meson.build
@@ -522,6 +522,18 @@ if cocoa.found() and get_option('gtk').enabled()
   error('Cocoa and GTK+ cannot be enabled at the same time')
 endif
 
+vmnet = dependency('appleframeworks', modules: 'vmnet', required: 
get_option('vmnet'))
+if vmnet.found() and not cc.has_header_symbol('vmnet/vmnet.h',
+  'VMNET_BRIDGED_MODE',
+  dependencies: vmnet)
+  vmnet = not_found
+  if get_option('vmnet').enabled()
+error('vmnet.framework API is outdated')
+  else
+warning('vmnet.framework API is outdated, disabling')
+  endif
+endif
+
 seccomp = not_found
 if not get_option('seccomp').auto() or have_system or have_tools
   seccomp = dependency('libseccomp', version: '>=2.3.0',
@@ -1536,6 +1548,7 @@ config_host_data.set('CONFIG_SNAPPY', snappy.found())
 config_host_data.set('CONFIG_TPM', have_tpm)
 config_host_data.set('CONFIG_USB_LIBUSB', libusb.found())
 config_host_data.set('CONFIG_VDE', vde.found())
+config_host_data.set('CONFIG_VMNET', vmnet.found())
 config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', 
have_vhost_user_blk_server)
 config_host_data.set('CONFIG_VNC', vnc.found())
 config_host_data.set('CONFIG_VNC_JPEG', jpeg.found())
@@ -3564,7 +3577,8 @@ summary(summary_info, bool_yn: true, section: 'Crypto')
 # Libraries
 summary_info = {}
 if targetos == 'darwin'
-  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'vmnet.framework support': vmnet}
 endif
 summary_info += {'SDL support':   sdl}
 summary_info += {'SDL image support': sdl_image}
diff --git a/meson_options.txt b/meson_options.txt
index 52b11cead4..d2c0b6b412 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -175,6 +175,8 @@ option('netmap', type : 'feature', value : 'auto',
description: 'netmap network backend support')
 option('vde', type : 'feature', value : 'auto',
description: 'vde network backend support')
+option('vmnet', type : 'feature', value : 'auto',
+   description: 'vmnet.framework network backend support')
 option('virglrenderer', type : 'feature', value : 'auto',
description: 'virgl rendering support')
 option('vnc', type : 'feature', value : 'auto',
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 9ee684ef03..30946f3798 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -116,6 +116,7 @@ meson_options_help() {
   printf "%s\n" '  usb-redir   libusbredir support'
   printf "%s\n" '  vde vde network backend support'
   printf "%s\n" '  vdi vdi image format support'
+  printf "%s\n" '  vmnet   vmnet.framework network backend support'
   printf "%s\n" '  vhost-user-blk-server'
   printf "%s\n" '  build vhost-user-blk server'
   printf "%s\n" '  virglrenderer   virgl rendering support'
-- 
2.34.1.vfs.0.0




[PATCH v14 7/8] net/vmnet: update hmp-commands.hx

2022-02-25 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 hmp-commands.hx | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 70a9136ac2..406ac4bba8 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1265,7 +1265,11 @@ ERST
 {
 .name   = "netdev_add",
 .args_type  = "netdev:O",
-.params = 
"[user|tap|socket|vde|bridge|hubport|netmap|vhost-user],id=str[,prop=value][,...]",
+.params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user"
+#ifdef CONFIG_VMNET
+  "|vmnet-host|vmnet-shared|vmnet-bridged"
+#endif
+  "],id=str[,prop=value][,...]",
 .help   = "add host network device",
 .cmd= hmp_netdev_add,
 .command_completion = netdev_add_completion,
-- 
2.34.1.vfs.0.0




[PATCH v15 8/8] net/vmnet: update MAINTAINERS list

2022-02-25 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 MAINTAINERS | 5 +
 1 file changed, 5 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index fa8adc2618..8e0fa7a2bf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2730,6 +2730,11 @@ W: http://info.iet.unipi.it/~luigi/netmap/
 S: Maintained
 F: net/netmap.c
 
+Apple vmnet network backends
+M: Vladislav Yaroshchuk 
+S: Maintained
+F: net/vmnet*
+
 Host Memory Backends
 M: David Hildenbrand 
 M: Igor Mammedov 
-- 
2.34.1.vfs.0.0




[PATCH v15 7/8] net/vmnet: update hmp-commands.hx

2022-02-25 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 hmp-commands.hx | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 70a9136ac2..406ac4bba8 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1265,7 +1265,11 @@ ERST
 {
 .name   = "netdev_add",
 .args_type  = "netdev:O",
-.params = 
"[user|tap|socket|vde|bridge|hubport|netmap|vhost-user],id=str[,prop=value][,...]",
+.params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user"
+#ifdef CONFIG_VMNET
+  "|vmnet-host|vmnet-shared|vmnet-bridged"
+#endif
+  "],id=str[,prop=value][,...]",
 .help   = "add host network device",
 .cmd= hmp_netdev_add,
 .command_completion = netdev_add_completion,
-- 
2.34.1.vfs.0.0




[PATCH v15 0/8] Add vmnet.framework based network backend

2022-02-25 Thread Vladislav Yaroshchuk
macOS provides networking API for VMs called 'vmnet.framework':
https://developer.apple.com/documentation/vmnet

We can provide its support as the new QEMU network backends which
represent three different vmnet.framework interface usage modes:

  * `vmnet-shared`:
allows the guest to communicate with other guests in shared mode and
also with external network (Internet) via NAT. Has (macOS-provided)
DHCP server; subnet mask and IP range can be configured;

  * `vmnet-host`:
allows the guest to communicate with other guests in host mode.
By default has enabled DHCP as `vmnet-shared`, but providing
network unique id (uuid) can make `vmnet-host` interfaces isolated
from each other and also disables DHCP.

  * `vmnet-bridged`:
bridges the guest with a physical network interface.

This backends cannot work on macOS Catalina 10.15 cause we use
vmnet.framework API provided only with macOS 11 and newer. Seems
that it is not a problem, because QEMU guarantees to work on two most
recent versions of macOS which now are Big Sur (11) and Monterey (12).

Also, we have one inconvenient restriction: vmnet.framework interfaces
can create only privileged user:
`$ sudo qemu-system-x86_64 -nic vmnet-shared`

Attempt of `vmnet-*` netdev creation being unprivileged user fails with
vmnet's 'general failure'.

This happens because vmnet.framework requires `com.apple.vm.networking`
entitlement which is: "restricted to developers of virtualization software.
To request this entitlement, contact your Apple representative." as Apple
documentation says:
https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_vm_networking

One more note: we still have quite useful but not supported
'vmnet.framework' features as creating port forwarding rules, IPv6
NAT prefix specifying and so on.

Nevertheless, new backends work fine and tested within `qemu-system-x86-64`
on macOS Bir Sur 11.5.2 host with such nic models:
  * e1000-82545em
  * virtio-net-pci
  * vmxnet3

The guests were:
  * macOS 10.15.7
  * Ubuntu Bionic (server cloudimg)


This series partially reuses patches by Phillip Tennen:
https://patchew.org/QEMU/20210218134947.1860-1-phillip.en...@gmail.com/
So I included them signed-off line into one of the commit messages and
also here.

v1 -> v2:
 Since v1 minor typos were fixed, patches rebased onto latest master,
 redundant changes removed (small commits squashed)
v2 -> v3:
 - QAPI style fixes
 - Typos fixes in comments
 - `#include`'s updated to be in sync with recent master
v3 -> v4:
 - Support vmnet interfaces isolation feature
 - Support vmnet-host network uuid setting feature
 - Refactored sources a bit
v4 -> v5:
 - Missed 6.2 boat, now 7.0 candidate
 - Fix qapi netdev descriptions and styles
   (@subnetmask -> @subnet-mask)
 - Support vmnet-shared IPv6 prefix setting feature
v5 -> v6
 - provide detailed commit messages for commits of
   many changes
 - rename properties @dhcpstart and @dhcpend to
   @start-address and @end-address
 - improve qapi documentation about isolation
   features (@isolated, @net-uuid)
v6 -> v7:
 - update MAINTAINERS list
v7 -> v8
 - QAPI code style fixes
v8 -> v9
 - Fix building on Linux: add missing qapi
   `'if': 'CONFIG_VMNET'` statement to Netdev union
v9 -> v10
 - Disable vmnet feature for macOS < 11.0: add
   vmnet.framework API probe into meson.build.
   This fixes QEMU building on macOS < 11.0:
   https://patchew.org/QEMU/20220110034000.20221-1-jasow...@redhat.com/
v10 -> v11
 - Enable vmnet for macOS 10.15 with subset of available
   features. Disable vmnet for macOS < 10.15.
 - Fix typos
v11 -> v12
 - use more general macOS version check with
   MAC_OS_VERSION_11_0 instead of manual
   definition creating.
v12 -> v13
 - fix incorrect macOS version bound while
   'feature available since 11.0' check.
   Use MAC_OS_X_VERSION_MIN_REQUIRED instead of
   MAC_OS_X_VERSION_MAX_ALLOWED.
v13 -> v14
 - fix memory leaks
 - get rid of direct global mutex taking while resending
   packets from vmnet to QEMU, schedule a bottom half
   instead (it can be a thing to discuss, maybe exists a
   better way to perform the packets transfer)
 - update hmp commands
 - a bit refactor everything
 - change the email from which patches are being
   submitted, same to email in MAINTAINERS list
 - P.S. sorry for so late reply
v14 -> v15
 - restore --enable-vdi and --disable-vdi
   mistakenly dropped in previous series

Vladislav Yaroshchuk (8):
  net/vmnet: add vmnet dependency and customizable option
  net/vmnet: add vmnet backends to qapi/net
  net/vmnet: implement shared mode (vmnet-shared)
  net/vmnet: implement host mode (vmnet-host)
  net/vmnet: implement bridged mode (vmnet-bridged)
  net/vmnet: update qemu-options.hx
  net/vmnet: update hmp-commands.hx
  net/vmnet: update MAINTAINERS list

 MAINTAINERS   |   5 +
 hmp-commands.hx   |   6 +-
 meson.build 

[PATCH v15 5/8] net/vmnet: implement bridged mode (vmnet-bridged)

2022-02-25 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-bridged.m | 129 ++--
 1 file changed, 124 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
index c735901666..a19b10909e 100644
--- a/net/vmnet-bridged.m
+++ b/net/vmnet-bridged.m
@@ -10,16 +10,135 @@
 
 #include "qemu/osdep.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+typedef struct VmnetBridgedState {
+VmnetCommonState cs;
+} VmnetBridgedState;
+
+
+static bool validate_ifname(const char *ifname)
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+bool match = false;
+if (!xpc_array_get_count(shared_if_list)) {
+goto done;
+}
+
+match = !xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+return strcmp(xpc_string_get_string_ptr(value), ifname) != 0;
+});
+
+done:
+xpc_release(shared_if_list);
+return match;
+}
+
+
+static bool get_valid_ifnames(char *output_buf)
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+__block const char *ifname = NULL;
+__block int str_offset = 0;
+bool interfaces_available = true;
+
+if (!xpc_array_get_count(shared_if_list)) {
+interfaces_available = false;
+goto done;
+}
+
+xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+/* build list of strings like "en0 en1 en2 " */
+ifname = xpc_string_get_string_ptr(value);
+strcpy(output_buf + str_offset, ifname);
+strcpy(output_buf + str_offset + strlen(ifname), " ");
+str_offset += strlen(ifname) + 1;
+return true;
+});
+
+done:
+xpc_release(shared_if_list);
+return interfaces_available;
+}
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+char ifnames[256];
+
+if (!validate_ifname(options->ifname)) {
+if (get_valid_ifnames(ifnames)) {
+error_setg(errp,
+   "unsupported ifname '%s', expected one of [ %s]",
+   options->ifname,
+   ifnames);
+return false;
+}
+error_setg(errp,
+   "unsupported ifname '%s', no supported "
+   "interfaces available",
+   options->ifname);
+return false;
+}
+
+#if !defined(MAC_OS_VERSION_11_0) || \
+MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_11_0
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-bridged.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+return true;
+}
+
+static xpc_object_t build_if_desc(const Netdev *netdev)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_BRIDGED_MODE
+);
+
+xpc_dictionary_set_string(if_desc,
+  vmnet_shared_interface_name_key,
+  options->ifname);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+#endif
+return if_desc;
+}
+
+static NetClientInfo net_vmnet_bridged_info = {
+.type = NET_CLIENT_DRIVER_VMNET_BRIDGED,
+.size = sizeof(VmnetBridgedState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
+
 int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
NetClientState *peer, Error **errp)
 {
-  error_setg(errp, "vmnet-bridged is not implemented yet");
-  return -1;
+NetClientState *nc = qemu_new_net_client(_vmnet_bridged_info,
+ peer, "vmnet-bridged", name);
+if (!validate_options(netdev, errp)) {
+g_assert_not_reached();
+}
+return vmnet_if_create(nc, build_if_desc(netdev), errp);
 }
-- 
2.34.1.vfs.0.0




[PATCH v15 6/8] net/vmnet: update qemu-options.hx

2022-02-25 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 qemu-options.hx | 25 +
 1 file changed, 25 insertions(+)

diff --git a/qemu-options.hx b/qemu-options.hx
index 094a6c1d7c..d2deab95d0 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2742,6 +2742,25 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
 #ifdef __linux__
 "-netdev vhost-vdpa,id=str,vhostdev=/path/to/dev\n"
 "configure a vhost-vdpa network,Establish a vhost-vdpa 
netdev\n"
+#endif
+#ifdef CONFIG_VMNET
+"-netdev vmnet-host,id=str[,isolated=on|off][,net-uuid=uuid]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in host mode with ID 
'str',\n"
+"isolate this interface from others with 'isolated',\n"
+"configure the address range and choose a subnet mask,\n"
+"specify network UUID 'uuid' to disable DHCP and interact 
with\n"
+"vmnet-host interfaces within this isolated network\n"
+"-netdev vmnet-shared,id=str[,isolated=on|off][,nat66-prefix=addr]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in shared mode with ID 
'str',\n"
+"configure the address range and choose a subnet mask,\n"
+"set IPv6 ULA prefix (of length 64) to use for internal 
network,\n"
+"isolate this interface from others with 'isolated'\n"
+"-netdev vmnet-bridged,id=str,ifname=name[,isolated=on|off]\n"
+"configure a vmnet network backend in bridged mode with ID 
'str',\n"
+"use 'ifname=name' to select a physical network interface 
to be bridged,\n"
+"isolate this interface from others with 'isolated'\n"
 #endif
 "-netdev hubport,id=str,hubid=n[,netdev=nd]\n"
 "configure a hub port on the hub with ID 'n'\n", 
QEMU_ARCH_ALL)
@@ -2761,6 +2780,9 @@ DEF("nic", HAS_ARG, QEMU_OPTION_nic,
 #endif
 #ifdef CONFIG_POSIX
 "vhost-user|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,...][mac=macaddr]\n"
 "initialize an on-board / default host NIC (using MAC 
address\n"
@@ -2783,6 +2805,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
 #endif
 #ifdef CONFIG_NETMAP
 "netmap|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,option][,...]\n"
 "old way to initialize a host network interface\n"
-- 
2.34.1.vfs.0.0




[PATCH v14 6/8] net/vmnet: update qemu-options.hx

2022-02-25 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 qemu-options.hx | 25 +
 1 file changed, 25 insertions(+)

diff --git a/qemu-options.hx b/qemu-options.hx
index 094a6c1d7c..d2deab95d0 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2742,6 +2742,25 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
 #ifdef __linux__
 "-netdev vhost-vdpa,id=str,vhostdev=/path/to/dev\n"
 "configure a vhost-vdpa network,Establish a vhost-vdpa 
netdev\n"
+#endif
+#ifdef CONFIG_VMNET
+"-netdev vmnet-host,id=str[,isolated=on|off][,net-uuid=uuid]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in host mode with ID 
'str',\n"
+"isolate this interface from others with 'isolated',\n"
+"configure the address range and choose a subnet mask,\n"
+"specify network UUID 'uuid' to disable DHCP and interact 
with\n"
+"vmnet-host interfaces within this isolated network\n"
+"-netdev vmnet-shared,id=str[,isolated=on|off][,nat66-prefix=addr]\n"
+" [,start-address=addr,end-address=addr,subnet-mask=mask]\n"
+"configure a vmnet network backend in shared mode with ID 
'str',\n"
+"configure the address range and choose a subnet mask,\n"
+"set IPv6 ULA prefix (of length 64) to use for internal 
network,\n"
+"isolate this interface from others with 'isolated'\n"
+"-netdev vmnet-bridged,id=str,ifname=name[,isolated=on|off]\n"
+"configure a vmnet network backend in bridged mode with ID 
'str',\n"
+"use 'ifname=name' to select a physical network interface 
to be bridged,\n"
+"isolate this interface from others with 'isolated'\n"
 #endif
 "-netdev hubport,id=str,hubid=n[,netdev=nd]\n"
 "configure a hub port on the hub with ID 'n'\n", 
QEMU_ARCH_ALL)
@@ -2761,6 +2780,9 @@ DEF("nic", HAS_ARG, QEMU_OPTION_nic,
 #endif
 #ifdef CONFIG_POSIX
 "vhost-user|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,...][mac=macaddr]\n"
 "initialize an on-board / default host NIC (using MAC 
address\n"
@@ -2783,6 +2805,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
 #endif
 #ifdef CONFIG_NETMAP
 "netmap|"
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host|vmnet-shared|vmnet-bridged|"
 #endif
 "socket][,option][,option][,...]\n"
 "old way to initialize a host network interface\n"
-- 
2.34.1.vfs.0.0




[PATCH v15 3/8] net/vmnet: implement shared mode (vmnet-shared)

2022-02-25 Thread Vladislav Yaroshchuk
Interaction with vmnet.framework in different modes
differs only on configuration stage, so we can create
common `send`, `receive`, etc. procedures and reuse them.

vmnet.framework supports iov, but writing more than
one iov into vmnet interface fails with
'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
one and passing it to vmnet works fine. That's the
reason why receive_iov() left unimplemented. But it still
works with good enough performance having .receive()
net/vmnet: implement shared mode (vmnet-shared)

Interaction with vmnet.framework in different modes
differs only on configuration stage, so we can create
common `send`, `receive`, etc. procedures and reuse them.

vmnet.framework supports iov, but writing more than
one iov into vmnet interface fails with
'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
one and passing it to vmnet works fine. That's the
reason why receive_iov() left unimplemented. But it still
works with good enough performance having .receive()
implemented only.

Also, there is no way to unsubscribe from vmnet packages
receiving except registering and unregistering event
callback or simply drop packages just ignoring and
not processing them when related flag is set. Here we do
using the second way.

Signed-off-by: Phillip Tennen 
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-common.m | 302 +
 net/vmnet-shared.c |  94 +-
 net/vmnet_int.h|  39 +-
 3 files changed, 430 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-common.m b/net/vmnet-common.m
index 56612c72ce..2f70921cae 100644
--- a/net/vmnet-common.m
+++ b/net/vmnet-common.m
@@ -10,6 +10,8 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "qemu/log.h"
 #include "qapi/qapi-types-net.h"
 #include "vmnet_int.h"
 #include "clients.h"
@@ -17,4 +19,304 @@
 #include "qapi/error.h"
 
 #include 
+#include 
 
+
+static inline void vmnet_set_send_bh_scheduled(VmnetCommonState *s,
+   bool enable)
+{
+qatomic_set(>send_scheduled, enable);
+}
+
+
+static inline bool vmnet_is_send_bh_scheduled(VmnetCommonState *s)
+{
+return qatomic_load_acquire(>send_scheduled);
+}
+
+
+static inline void vmnet_set_send_enabled(VmnetCommonState *s,
+  bool enable)
+{
+if (enable) {
+vmnet_interface_set_event_callback(
+s->vmnet_if,
+VMNET_INTERFACE_PACKETS_AVAILABLE,
+s->if_queue,
+^(interface_event_t event_id, xpc_object_t event) {
+assert(event_id == VMNET_INTERFACE_PACKETS_AVAILABLE);
+/*
+ * This function is being called from a non qemu thread, so
+ * we only schedule a BH, and do the rest of the io completion
+ * handling from vmnet_send_bh() which runs in a qemu context.
+ *
+ * Avoid scheduling multiple bottom halves
+ */
+if (!vmnet_is_send_bh_scheduled(s)) {
+vmnet_set_send_bh_scheduled(s, true);
+qemu_bh_schedule(s->send_bh);
+}
+});
+} else {
+vmnet_interface_set_event_callback(
+s->vmnet_if,
+VMNET_INTERFACE_PACKETS_AVAILABLE,
+NULL,
+NULL);
+}
+}
+
+
+static void vmnet_send_completed(NetClientState *nc, ssize_t len)
+{
+VmnetCommonState *s = DO_UPCAST(VmnetCommonState, nc, nc);
+vmnet_set_send_enabled(s, true);
+}
+
+
+static void vmnet_send_bh(void *opaque)
+{
+NetClientState *nc = (NetClientState *) opaque;
+VmnetCommonState *s = DO_UPCAST(VmnetCommonState, nc, nc);
+
+struct iovec *iov = s->iov_buf;
+struct vmpktdesc *packets = s->packets_buf;
+int pkt_cnt;
+int i;
+
+vmnet_return_t status;
+ssize_t size;
+
+/* read as many packets as present */
+pkt_cnt = VMNET_PACKETS_LIMIT;
+for (i = 0; i < pkt_cnt; ++i) {
+packets[i].vm_pkt_size = s->max_packet_size;
+packets[i].vm_pkt_iovcnt = 1;
+packets[i].vm_flags = 0;
+}
+
+status = vmnet_read(s->vmnet_if, packets, _cnt);
+if (status != VMNET_SUCCESS) {
+error_printf("vmnet: read failed: %s\n",
+ vmnet_status_map_str(status));
+goto done;
+}
+
+for (i = 0; i < pkt_cnt; ++i) {
+size = qemu_send_packet_async(nc,
+  iov[i].iov_base,
+  packets[i].vm_pkt_size,
+  vmnet_send_completed);
+if (size == 0) {
+vmnet_set_send_enabled(s, false);
+goto done;
+} else if (size < 0) {
+break;
+}
+}
+
+done:
+vmnet_set_send_bh_scheduled(s, false);
+}
+
+

[PATCH v14 8/8] net/vmnet: update MAINTAINERS list

2022-02-25 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 MAINTAINERS | 5 +
 1 file changed, 5 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index fa8adc2618..8e0fa7a2bf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2730,6 +2730,11 @@ W: http://info.iet.unipi.it/~luigi/netmap/
 S: Maintained
 F: net/netmap.c
 
+Apple vmnet network backends
+M: Vladislav Yaroshchuk 
+S: Maintained
+F: net/vmnet*
+
 Host Memory Backends
 M: David Hildenbrand 
 M: Igor Mammedov 
-- 
2.34.1.vfs.0.0




[PATCH v15 2/8] net/vmnet: add vmnet backends to qapi/net

2022-02-25 Thread Vladislav Yaroshchuk
Create separate netdevs for each vmnet operating mode:
- vmnet-host
- vmnet-shared
- vmnet-bridged

Signed-off-by: Vladislav Yaroshchuk 
---
 net/clients.h   |  11 
 net/meson.build |   7 +++
 net/net.c   |  10 
 net/vmnet-bridged.m |  25 +
 net/vmnet-common.m  |  20 +++
 net/vmnet-host.c|  24 
 net/vmnet-shared.c  |  25 +
 net/vmnet_int.h |  25 +
 qapi/net.json   | 133 +++-
 9 files changed, 278 insertions(+), 2 deletions(-)
 create mode 100644 net/vmnet-bridged.m
 create mode 100644 net/vmnet-common.m
 create mode 100644 net/vmnet-host.c
 create mode 100644 net/vmnet-shared.c
 create mode 100644 net/vmnet_int.h

diff --git a/net/clients.h b/net/clients.h
index 92f9b59aed..c9157789f2 100644
--- a/net/clients.h
+++ b/net/clients.h
@@ -63,4 +63,15 @@ int net_init_vhost_user(const Netdev *netdev, const char 
*name,
 
 int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
 NetClientState *peer, Error **errp);
+#ifdef CONFIG_VMNET
+int net_init_vmnet_host(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_shared(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+#endif /* CONFIG_VMNET */
+
 #endif /* QEMU_NET_CLIENTS_H */
diff --git a/net/meson.build b/net/meson.build
index 847bc2ac85..00a88c4951 100644
--- a/net/meson.build
+++ b/net/meson.build
@@ -42,4 +42,11 @@ softmmu_ss.add(when: 'CONFIG_POSIX', if_true: 
files(tap_posix))
 softmmu_ss.add(when: 'CONFIG_WIN32', if_true: files('tap-win32.c'))
 softmmu_ss.add(when: 'CONFIG_VHOST_NET_VDPA', if_true: files('vhost-vdpa.c'))
 
+vmnet_files = files(
+  'vmnet-common.m',
+  'vmnet-bridged.m',
+  'vmnet-host.c',
+  'vmnet-shared.c'
+)
+softmmu_ss.add(when: vmnet, if_true: vmnet_files)
 subdir('can')
diff --git a/net/net.c b/net/net.c
index f0d14dbfc1..1dbb64b935 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1021,6 +1021,11 @@ static int (* const 
net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
 #ifdef CONFIG_L2TPV3
 [NET_CLIENT_DRIVER_L2TPV3]= net_init_l2tpv3,
 #endif
+#ifdef CONFIG_VMNET
+[NET_CLIENT_DRIVER_VMNET_HOST] = net_init_vmnet_host,
+[NET_CLIENT_DRIVER_VMNET_SHARED] = net_init_vmnet_shared,
+[NET_CLIENT_DRIVER_VMNET_BRIDGED] = net_init_vmnet_bridged,
+#endif /* CONFIG_VMNET */
 };
 
 
@@ -1106,6 +,11 @@ void show_netdevs(void)
 #endif
 #ifdef CONFIG_VHOST_VDPA
 "vhost-vdpa",
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host",
+"vmnet-shared",
+"vmnet-bridged",
 #endif
 };
 
diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
new file mode 100644
index 00..c735901666
--- /dev/null
+++ b/net/vmnet-bridged.m
@@ -0,0 +1,25 @@
+/*
+ * vmnet-bridged.m
+ *
+ * Copyright(c) 2021 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+   NetClientState *peer, Error **errp)
+{
+  error_setg(errp, "vmnet-bridged is not implemented yet");
+  return -1;
+}
diff --git a/net/vmnet-common.m b/net/vmnet-common.m
new file mode 100644
index 00..56612c72ce
--- /dev/null
+++ b/net/vmnet-common.m
@@ -0,0 +1,20 @@
+/*
+ * vmnet-common.m - network client wrapper for Apple vmnet.framework
+ *
+ * Copyright(c) 2021 Vladislav Yaroshchuk 
+ * Copyright(c) 2021 Phillip Tennen 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
diff --git a/net/vmnet-host.c b/net/vmnet-host.c
new file mode 100644
index 00..32dc437037
--- /dev/null
+++ b/net/vmnet-host.c
@@ -0,0 +1,24 @@
+/*
+ * vmnet-host.c
+ *
+ * Copyright(c) 2021 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qa

[PATCH v14 5/8] net/vmnet: implement bridged mode (vmnet-bridged)

2022-02-25 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-bridged.m | 129 ++--
 1 file changed, 124 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
index c735901666..a19b10909e 100644
--- a/net/vmnet-bridged.m
+++ b/net/vmnet-bridged.m
@@ -10,16 +10,135 @@
 
 #include "qemu/osdep.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+typedef struct VmnetBridgedState {
+VmnetCommonState cs;
+} VmnetBridgedState;
+
+
+static bool validate_ifname(const char *ifname)
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+bool match = false;
+if (!xpc_array_get_count(shared_if_list)) {
+goto done;
+}
+
+match = !xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+return strcmp(xpc_string_get_string_ptr(value), ifname) != 0;
+});
+
+done:
+xpc_release(shared_if_list);
+return match;
+}
+
+
+static bool get_valid_ifnames(char *output_buf)
+{
+xpc_object_t shared_if_list = vmnet_copy_shared_interface_list();
+__block const char *ifname = NULL;
+__block int str_offset = 0;
+bool interfaces_available = true;
+
+if (!xpc_array_get_count(shared_if_list)) {
+interfaces_available = false;
+goto done;
+}
+
+xpc_array_apply(
+shared_if_list,
+^bool(size_t index, xpc_object_t value) {
+/* build list of strings like "en0 en1 en2 " */
+ifname = xpc_string_get_string_ptr(value);
+strcpy(output_buf + str_offset, ifname);
+strcpy(output_buf + str_offset + strlen(ifname), " ");
+str_offset += strlen(ifname) + 1;
+return true;
+});
+
+done:
+xpc_release(shared_if_list);
+return interfaces_available;
+}
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+char ifnames[256];
+
+if (!validate_ifname(options->ifname)) {
+if (get_valid_ifnames(ifnames)) {
+error_setg(errp,
+   "unsupported ifname '%s', expected one of [ %s]",
+   options->ifname,
+   ifnames);
+return false;
+}
+error_setg(errp,
+   "unsupported ifname '%s', no supported "
+   "interfaces available",
+   options->ifname);
+return false;
+}
+
+#if !defined(MAC_OS_VERSION_11_0) || \
+MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_11_0
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-bridged.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+return true;
+}
+
+static xpc_object_t build_if_desc(const Netdev *netdev)
+{
+const NetdevVmnetBridgedOptions *options = &(netdev->u.vmnet_bridged);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_BRIDGED_MODE
+);
+
+xpc_dictionary_set_string(if_desc,
+  vmnet_shared_interface_name_key,
+  options->ifname);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+#endif
+return if_desc;
+}
+
+static NetClientInfo net_vmnet_bridged_info = {
+.type = NET_CLIENT_DRIVER_VMNET_BRIDGED,
+.size = sizeof(VmnetBridgedState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
+
 int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
NetClientState *peer, Error **errp)
 {
-  error_setg(errp, "vmnet-bridged is not implemented yet");
-  return -1;
+NetClientState *nc = qemu_new_net_client(_vmnet_bridged_info,
+ peer, "vmnet-bridged", name);
+if (!validate_options(netdev, errp)) {
+g_assert_not_reached();
+}
+return vmnet_if_create(nc, build_if_desc(netdev), errp);
 }
-- 
2.34.1.vfs.0.0




[PATCH v14 0/8] Add vmnet.framework based network backend

2022-02-25 Thread Vladislav Yaroshchuk
macOS provides networking API for VMs called 'vmnet.framework':
https://developer.apple.com/documentation/vmnet

We can provide its support as the new QEMU network backends which
represent three different vmnet.framework interface usage modes:

  * `vmnet-shared`:
allows the guest to communicate with other guests in shared mode and
also with external network (Internet) via NAT. Has (macOS-provided)
DHCP server; subnet mask and IP range can be configured;

  * `vmnet-host`:
allows the guest to communicate with other guests in host mode.
By default has enabled DHCP as `vmnet-shared`, but providing
network unique id (uuid) can make `vmnet-host` interfaces isolated
from each other and also disables DHCP.

  * `vmnet-bridged`:
bridges the guest with a physical network interface.

This backends cannot work on macOS Catalina 10.15 cause we use
vmnet.framework API provided only with macOS 11 and newer. Seems
that it is not a problem, because QEMU guarantees to work on two most
recent versions of macOS which now are Big Sur (11) and Monterey (12).

Also, we have one inconvenient restriction: vmnet.framework interfaces
can create only privileged user:
`$ sudo qemu-system-x86_64 -nic vmnet-shared`

Attempt of `vmnet-*` netdev creation being unprivileged user fails with
vmnet's 'general failure'.

This happens because vmnet.framework requires `com.apple.vm.networking`
entitlement which is: "restricted to developers of virtualization software.
To request this entitlement, contact your Apple representative." as Apple
documentation says:
https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_vm_networking

One more note: we still have quite useful but not supported
'vmnet.framework' features as creating port forwarding rules, IPv6
NAT prefix specifying and so on.

Nevertheless, new backends work fine and tested within `qemu-system-x86-64`
on macOS Bir Sur 11.5.2 host with such nic models:
  * e1000-82545em
  * virtio-net-pci
  * vmxnet3

The guests were:
  * macOS 10.15.7
  * Ubuntu Bionic (server cloudimg)


This series partially reuses patches by Phillip Tennen:
https://patchew.org/QEMU/20210218134947.1860-1-phillip.en...@gmail.com/
So I included them signed-off line into one of the commit messages and
also here.

v1 -> v2:
 Since v1 minor typos were fixed, patches rebased onto latest master,
 redundant changes removed (small commits squashed)
v2 -> v3:
 - QAPI style fixes
 - Typos fixes in comments
 - `#include`'s updated to be in sync with recent master
v3 -> v4:
 - Support vmnet interfaces isolation feature
 - Support vmnet-host network uuid setting feature
 - Refactored sources a bit
v4 -> v5:
 - Missed 6.2 boat, now 7.0 candidate
 - Fix qapi netdev descriptions and styles
   (@subnetmask -> @subnet-mask)
 - Support vmnet-shared IPv6 prefix setting feature
v5 -> v6
 - provide detailed commit messages for commits of
   many changes
 - rename properties @dhcpstart and @dhcpend to
   @start-address and @end-address
 - improve qapi documentation about isolation
   features (@isolated, @net-uuid)
v6 -> v7:
 - update MAINTAINERS list
v7 -> v8
 - QAPI code style fixes
v8 -> v9
 - Fix building on Linux: add missing qapi
   `'if': 'CONFIG_VMNET'` statement to Netdev union
v9 -> v10
 - Disable vmnet feature for macOS < 11.0: add
   vmnet.framework API probe into meson.build.
   This fixes QEMU building on macOS < 11.0:
   https://patchew.org/QEMU/20220110034000.20221-1-jasow...@redhat.com/
v10 -> v11
 - Enable vmnet for macOS 10.15 with subset of available
   features. Disable vmnet for macOS < 10.15.
 - Fix typos
v11 -> v12
 - use more general macOS version check with
   MAC_OS_VERSION_11_0 instead of manual
   definition creating.
v12 -> v13
 - fix incorrect macOS version bound while
   'feature available since 11.0' check.
   Use MAC_OS_X_VERSION_MIN_REQUIRED instead of
   MAC_OS_X_VERSION_MAX_ALLOWED.
v13 -> v14
 - fix memory leaks
 - get rid of direct global mutex taking while resending
   packets from vmnet to QEMU, schedule a bottom half
   instead (it can be a thing to discuss, maybe exists a
   better way to perform the packets transfer)
 - update hmp commands
 - a bit refactor everything
 - change the email from which patches are being
   submitted, same to email in MAINTAINERS list
 - P.S. sorry for so late reply

Vladislav Yaroshchuk (8):
  net/vmnet: add vmnet dependency and customizable option
  net/vmnet: add vmnet backends to qapi/net
  net/vmnet: implement shared mode (vmnet-shared)
  net/vmnet: implement host mode (vmnet-host)
  net/vmnet: implement bridged mode (vmnet-bridged)
  net/vmnet: update qemu-options.hx
  net/vmnet: update hmp-commands.hx
  net/vmnet: update MAINTAINERS list

 MAINTAINERS   |   5 +
 hmp-commands.hx   |   6 +-
 meson.build   |  16 +-
 meson_options.txt |   2 +
 net/clients.h  

[PATCH v14 4/8] net/vmnet: implement host mode (vmnet-host)

2022-02-25 Thread Vladislav Yaroshchuk
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-host.c | 115 ---
 1 file changed, 109 insertions(+), 6 deletions(-)

diff --git a/net/vmnet-host.c b/net/vmnet-host.c
index 32dc437037..2a711400e7 100644
--- a/net/vmnet-host.c
+++ b/net/vmnet-host.c
@@ -9,16 +9,119 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/uuid.h"
 #include "qapi/qapi-types-net.h"
-#include "vmnet_int.h"
-#include "clients.h"
-#include "qemu/error-report.h"
 #include "qapi/error.h"
+#include "clients.h"
+#include "vmnet_int.h"
 
 #include 
 
+typedef struct VmnetHostState {
+VmnetCommonState cs;
+QemuUUID network_uuid;
+} VmnetHostState;
+
+static bool validate_options(const Netdev *netdev, Error **errp)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+QemuUUID uuid;
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+if (options->has_net_uuid &&
+qemu_uuid_parse(options->net_uuid, ) < 0) {
+error_setg(errp, "Invalid UUID provided in 'net-uuid'");
+return false;
+}
+#else
+if (options->has_isolated) {
+error_setg(errp,
+   "vmnet-host.isolated feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+
+if (options->has_net_uuid) {
+error_setg(errp,
+   "vmnet-host.net-uuid feature is "
+   "unavailable: outdated vmnet.framework API");
+return false;
+}
+#endif
+
+if ((options->has_start_address ||
+ options->has_end_address ||
+ options->has_subnet_mask) &&
+!(options->has_start_address &&
+  options->has_end_address &&
+  options->has_subnet_mask)) {
+error_setg(errp,
+   "'start-address', 'end-address', 'subnet-mask' "
+   "should be provided together");
+return false;
+}
+
+return true;
+}
+
+static xpc_object_t build_if_desc(const Netdev *netdev,
+  NetClientState *nc)
+{
+const NetdevVmnetHostOptions *options = &(netdev->u.vmnet_host);
+VmnetCommonState *cs = DO_UPCAST(VmnetCommonState, nc, nc);
+VmnetHostState *hs = DO_UPCAST(VmnetHostState, cs, cs);
+xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
+
+xpc_dictionary_set_uint64(if_desc,
+  vmnet_operation_mode_key,
+  VMNET_HOST_MODE);
+
+#if defined(MAC_OS_VERSION_11_0) && \
+MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0
+
+xpc_dictionary_set_bool(if_desc,
+vmnet_enable_isolation_key,
+options->isolated);
+
+if (options->has_net_uuid) {
+qemu_uuid_parse(options->net_uuid, >network_uuid);
+xpc_dictionary_set_uuid(if_desc,
+vmnet_network_identifier_key,
+hs->network_uuid.data);
+}
+#endif
+
+if (options->has_start_address) {
+xpc_dictionary_set_string(if_desc,
+  vmnet_start_address_key,
+  options->start_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_end_address_key,
+  options->end_address);
+xpc_dictionary_set_string(if_desc,
+  vmnet_subnet_mask_key,
+  options->subnet_mask);
+}
+
+return if_desc;
+}
+
+static NetClientInfo net_vmnet_host_info = {
+.type = NET_CLIENT_DRIVER_VMNET_HOST,
+.size = sizeof(VmnetHostState),
+.receive = vmnet_receive_common,
+.cleanup = vmnet_cleanup_common,
+};
+
 int net_init_vmnet_host(const Netdev *netdev, const char *name,
-NetClientState *peer, Error **errp) {
-  error_setg(errp, "vmnet-host is not implemented yet");
-  return -1;
+NetClientState *peer, Error **errp)
+{
+NetClientState *nc = qemu_new_net_client(_vmnet_host_info,
+ peer, "vmnet-host", name);
+if (!validate_options(netdev, errp)) {
+g_assert_not_reached();
+}
+return vmnet_if_create(nc, build_if_desc(netdev, nc), errp);
 }
-- 
2.34.1.vfs.0.0




[PATCH v14 1/8] net/vmnet: add vmnet dependency and customizable option

2022-02-25 Thread Vladislav Yaroshchuk
vmnet.framework dependency is added with 'vmnet' option
to enable or disable it. Default value is 'auto'.

vmnet features to be used are available since macOS 11.0,
corresponding probe is created into meson.build.

Signed-off-by: Vladislav Yaroshchuk 
---
 meson.build   | 16 +++-
 meson_options.txt |  2 ++
 scripts/meson-buildoptions.sh |  3 +--
 3 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/meson.build b/meson.build
index 8df40bfac4..d3a791e6c4 100644
--- a/meson.build
+++ b/meson.build
@@ -522,6 +522,18 @@ if cocoa.found() and get_option('gtk').enabled()
   error('Cocoa and GTK+ cannot be enabled at the same time')
 endif
 
+vmnet = dependency('appleframeworks', modules: 'vmnet', required: 
get_option('vmnet'))
+if vmnet.found() and not cc.has_header_symbol('vmnet/vmnet.h',
+  'VMNET_BRIDGED_MODE',
+  dependencies: vmnet)
+  vmnet = not_found
+  if get_option('vmnet').enabled()
+error('vmnet.framework API is outdated')
+  else
+warning('vmnet.framework API is outdated, disabling')
+  endif
+endif
+
 seccomp = not_found
 if not get_option('seccomp').auto() or have_system or have_tools
   seccomp = dependency('libseccomp', version: '>=2.3.0',
@@ -1536,6 +1548,7 @@ config_host_data.set('CONFIG_SNAPPY', snappy.found())
 config_host_data.set('CONFIG_TPM', have_tpm)
 config_host_data.set('CONFIG_USB_LIBUSB', libusb.found())
 config_host_data.set('CONFIG_VDE', vde.found())
+config_host_data.set('CONFIG_VMNET', vmnet.found())
 config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER', 
have_vhost_user_blk_server)
 config_host_data.set('CONFIG_VNC', vnc.found())
 config_host_data.set('CONFIG_VNC_JPEG', jpeg.found())
@@ -3564,7 +3577,8 @@ summary(summary_info, bool_yn: true, section: 'Crypto')
 # Libraries
 summary_info = {}
 if targetos == 'darwin'
-  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'Cocoa support':   cocoa}
+  summary_info += {'vmnet.framework support': vmnet}
 endif
 summary_info += {'SDL support':   sdl}
 summary_info += {'SDL image support': sdl_image}
diff --git a/meson_options.txt b/meson_options.txt
index 52b11cead4..d2c0b6b412 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -175,6 +175,8 @@ option('netmap', type : 'feature', value : 'auto',
description: 'netmap network backend support')
 option('vde', type : 'feature', value : 'auto',
description: 'vde network backend support')
+option('vmnet', type : 'feature', value : 'auto',
+   description: 'vmnet.framework network backend support')
 option('virglrenderer', type : 'feature', value : 'auto',
description: 'virgl rendering support')
 option('vnc', type : 'feature', value : 'auto',
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 9ee684ef03..7c37f13384 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -116,6 +116,7 @@ meson_options_help() {
   printf "%s\n" '  usb-redir   libusbredir support'
   printf "%s\n" '  vde vde network backend support'
   printf "%s\n" '  vdi vdi image format support'
+  printf "%s\n" '  vmnet   vmnet.framework network backend support'
   printf "%s\n" '  vhost-user-blk-server'
   printf "%s\n" '  build vhost-user-blk server'
   printf "%s\n" '  virglrenderer   virgl rendering support'
@@ -333,8 +334,6 @@ _meson_option_parse() {
 --disable-usb-redir) printf "%s" -Dusb_redir=disabled ;;
 --enable-vde) printf "%s" -Dvde=enabled ;;
 --disable-vde) printf "%s" -Dvde=disabled ;;
---enable-vdi) printf "%s" -Dvdi=enabled ;;
---disable-vdi) printf "%s" -Dvdi=disabled ;;
 --enable-vhost-user-blk-server) printf "%s" 
-Dvhost_user_blk_server=enabled ;;
 --disable-vhost-user-blk-server) printf "%s" 
-Dvhost_user_blk_server=disabled ;;
 --enable-virglrenderer) printf "%s" -Dvirglrenderer=enabled ;;
-- 
2.34.1.vfs.0.0




[PATCH v14 3/8] net/vmnet: implement shared mode (vmnet-shared)

2022-02-25 Thread Vladislav Yaroshchuk
Interaction with vmnet.framework in different modes
differs only on configuration stage, so we can create
common `send`, `receive`, etc. procedures and reuse them.

vmnet.framework supports iov, but writing more than
one iov into vmnet interface fails with
'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
one and passing it to vmnet works fine. That's the
reason why receive_iov() left unimplemented. But it still
works with good enough performance having .receive()
net/vmnet: implement shared mode (vmnet-shared)

Interaction with vmnet.framework in different modes
differs only on configuration stage, so we can create
common `send`, `receive`, etc. procedures and reuse them.

vmnet.framework supports iov, but writing more than
one iov into vmnet interface fails with
'VMNET_INVALID_ARGUMENT'. Collecting provided iovs into
one and passing it to vmnet works fine. That's the
reason why receive_iov() left unimplemented. But it still
works with good enough performance having .receive()
implemented only.

Also, there is no way to unsubscribe from vmnet packages
receiving except registering and unregistering event
callback or simply drop packages just ignoring and
not processing them when related flag is set. Here we do
using the second way.

Signed-off-by: Phillip Tennen 
Signed-off-by: Vladislav Yaroshchuk 
---
 net/vmnet-common.m | 302 +
 net/vmnet-shared.c |  94 +-
 net/vmnet_int.h|  39 +-
 3 files changed, 430 insertions(+), 5 deletions(-)

diff --git a/net/vmnet-common.m b/net/vmnet-common.m
index 56612c72ce..2f70921cae 100644
--- a/net/vmnet-common.m
+++ b/net/vmnet-common.m
@@ -10,6 +10,8 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "qemu/log.h"
 #include "qapi/qapi-types-net.h"
 #include "vmnet_int.h"
 #include "clients.h"
@@ -17,4 +19,304 @@
 #include "qapi/error.h"
 
 #include 
+#include 
 
+
+static inline void vmnet_set_send_bh_scheduled(VmnetCommonState *s,
+   bool enable)
+{
+qatomic_set(>send_scheduled, enable);
+}
+
+
+static inline bool vmnet_is_send_bh_scheduled(VmnetCommonState *s)
+{
+return qatomic_load_acquire(>send_scheduled);
+}
+
+
+static inline void vmnet_set_send_enabled(VmnetCommonState *s,
+  bool enable)
+{
+if (enable) {
+vmnet_interface_set_event_callback(
+s->vmnet_if,
+VMNET_INTERFACE_PACKETS_AVAILABLE,
+s->if_queue,
+^(interface_event_t event_id, xpc_object_t event) {
+assert(event_id == VMNET_INTERFACE_PACKETS_AVAILABLE);
+/*
+ * This function is being called from a non qemu thread, so
+ * we only schedule a BH, and do the rest of the io completion
+ * handling from vmnet_send_bh() which runs in a qemu context.
+ *
+ * Avoid scheduling multiple bottom halves
+ */
+if (!vmnet_is_send_bh_scheduled(s)) {
+vmnet_set_send_bh_scheduled(s, true);
+qemu_bh_schedule(s->send_bh);
+}
+});
+} else {
+vmnet_interface_set_event_callback(
+s->vmnet_if,
+VMNET_INTERFACE_PACKETS_AVAILABLE,
+NULL,
+NULL);
+}
+}
+
+
+static void vmnet_send_completed(NetClientState *nc, ssize_t len)
+{
+VmnetCommonState *s = DO_UPCAST(VmnetCommonState, nc, nc);
+vmnet_set_send_enabled(s, true);
+}
+
+
+static void vmnet_send_bh(void *opaque)
+{
+NetClientState *nc = (NetClientState *) opaque;
+VmnetCommonState *s = DO_UPCAST(VmnetCommonState, nc, nc);
+
+struct iovec *iov = s->iov_buf;
+struct vmpktdesc *packets = s->packets_buf;
+int pkt_cnt;
+int i;
+
+vmnet_return_t status;
+ssize_t size;
+
+/* read as many packets as present */
+pkt_cnt = VMNET_PACKETS_LIMIT;
+for (i = 0; i < pkt_cnt; ++i) {
+packets[i].vm_pkt_size = s->max_packet_size;
+packets[i].vm_pkt_iovcnt = 1;
+packets[i].vm_flags = 0;
+}
+
+status = vmnet_read(s->vmnet_if, packets, _cnt);
+if (status != VMNET_SUCCESS) {
+error_printf("vmnet: read failed: %s\n",
+ vmnet_status_map_str(status));
+goto done;
+}
+
+for (i = 0; i < pkt_cnt; ++i) {
+size = qemu_send_packet_async(nc,
+  iov[i].iov_base,
+  packets[i].vm_pkt_size,
+  vmnet_send_completed);
+if (size == 0) {
+vmnet_set_send_enabled(s, false);
+goto done;
+} else if (size < 0) {
+break;
+}
+}
+
+done:
+vmnet_set_send_bh_scheduled(s, false);
+}
+
+

[PATCH v14 2/8] net/vmnet: add vmnet backends to qapi/net

2022-02-25 Thread Vladislav Yaroshchuk
Create separate netdevs for each vmnet operating mode:
- vmnet-host
- vmnet-shared
- vmnet-bridged

Signed-off-by: Vladislav Yaroshchuk 
---
 net/clients.h   |  11 
 net/meson.build |   7 +++
 net/net.c   |  10 
 net/vmnet-bridged.m |  25 +
 net/vmnet-common.m  |  20 +++
 net/vmnet-host.c|  24 
 net/vmnet-shared.c  |  25 +
 net/vmnet_int.h |  25 +
 qapi/net.json   | 133 +++-
 9 files changed, 278 insertions(+), 2 deletions(-)
 create mode 100644 net/vmnet-bridged.m
 create mode 100644 net/vmnet-common.m
 create mode 100644 net/vmnet-host.c
 create mode 100644 net/vmnet-shared.c
 create mode 100644 net/vmnet_int.h

diff --git a/net/clients.h b/net/clients.h
index 92f9b59aed..c9157789f2 100644
--- a/net/clients.h
+++ b/net/clients.h
@@ -63,4 +63,15 @@ int net_init_vhost_user(const Netdev *netdev, const char 
*name,
 
 int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
 NetClientState *peer, Error **errp);
+#ifdef CONFIG_VMNET
+int net_init_vmnet_host(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_shared(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+  NetClientState *peer, Error **errp);
+#endif /* CONFIG_VMNET */
+
 #endif /* QEMU_NET_CLIENTS_H */
diff --git a/net/meson.build b/net/meson.build
index 847bc2ac85..00a88c4951 100644
--- a/net/meson.build
+++ b/net/meson.build
@@ -42,4 +42,11 @@ softmmu_ss.add(when: 'CONFIG_POSIX', if_true: 
files(tap_posix))
 softmmu_ss.add(when: 'CONFIG_WIN32', if_true: files('tap-win32.c'))
 softmmu_ss.add(when: 'CONFIG_VHOST_NET_VDPA', if_true: files('vhost-vdpa.c'))
 
+vmnet_files = files(
+  'vmnet-common.m',
+  'vmnet-bridged.m',
+  'vmnet-host.c',
+  'vmnet-shared.c'
+)
+softmmu_ss.add(when: vmnet, if_true: vmnet_files)
 subdir('can')
diff --git a/net/net.c b/net/net.c
index f0d14dbfc1..1dbb64b935 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1021,6 +1021,11 @@ static int (* const 
net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
 #ifdef CONFIG_L2TPV3
 [NET_CLIENT_DRIVER_L2TPV3]= net_init_l2tpv3,
 #endif
+#ifdef CONFIG_VMNET
+[NET_CLIENT_DRIVER_VMNET_HOST] = net_init_vmnet_host,
+[NET_CLIENT_DRIVER_VMNET_SHARED] = net_init_vmnet_shared,
+[NET_CLIENT_DRIVER_VMNET_BRIDGED] = net_init_vmnet_bridged,
+#endif /* CONFIG_VMNET */
 };
 
 
@@ -1106,6 +,11 @@ void show_netdevs(void)
 #endif
 #ifdef CONFIG_VHOST_VDPA
 "vhost-vdpa",
+#endif
+#ifdef CONFIG_VMNET
+"vmnet-host",
+"vmnet-shared",
+"vmnet-bridged",
 #endif
 };
 
diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
new file mode 100644
index 00..c735901666
--- /dev/null
+++ b/net/vmnet-bridged.m
@@ -0,0 +1,25 @@
+/*
+ * vmnet-bridged.m
+ *
+ * Copyright(c) 2021 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
+int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
+   NetClientState *peer, Error **errp)
+{
+  error_setg(errp, "vmnet-bridged is not implemented yet");
+  return -1;
+}
diff --git a/net/vmnet-common.m b/net/vmnet-common.m
new file mode 100644
index 00..56612c72ce
--- /dev/null
+++ b/net/vmnet-common.m
@@ -0,0 +1,20 @@
+/*
+ * vmnet-common.m - network client wrapper for Apple vmnet.framework
+ *
+ * Copyright(c) 2021 Vladislav Yaroshchuk 
+ * Copyright(c) 2021 Phillip Tennen 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+
+#include 
+
diff --git a/net/vmnet-host.c b/net/vmnet-host.c
new file mode 100644
index 00..32dc437037
--- /dev/null
+++ b/net/vmnet-host.c
@@ -0,0 +1,24 @@
+/*
+ * vmnet-host.c
+ *
+ * Copyright(c) 2021 Vladislav Yaroshchuk 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/qapi-types-net.h"
+#include "vmnet_int.h"
+#include "clients.h"
+#include "qemu/error-report.h"
+#include "qa

Re: [PATCH v8] isa-applesmc: provide OSK forwarding on Apple hosts

2022-02-16 Thread Vladislav Yaroshchuk
ping
https://patchew.org/QEMU/20220113152836.60398-1-yaroshchuk2...@gmail.com/

чт, 13 янв. 2022 г. в 18:28, Vladislav Yaroshchuk :

> On Apple hosts we can read AppleSMC OSK key directly from host's
> SMC and forward this value to QEMU Guest.
>
> New 'hostosk' property is added:
> * `-device isa-applesmc,hostosk=on`
> The property is set to 'on' by default for machine version > 6.2
>
> Apple licence allows use and run up to two additional copies
> or instances of macOS operating system within virtual operating system
> environments on each Apple-branded computer that is already running
> the Apple Software, for purposes of:
>  * software development
>  * testing during software development
>  * using macOS Server
>  * personal, non-commercial use
>
> Guest macOS requires AppleSMC with correct OSK. The most legal
> way to pass it to the Guest is to forward the key from host SMC
> without any value exposion.
>
> Based on
> https://web.archive.org/web/20200103161737/osxbook.com/book/bonus/chapter7/tpmdrmmyth/
>
> Signed-off-by: Vladislav Yaroshchuk 
> ---
>  hw/core/machine.c  |   4 +-
>  hw/misc/applesmc.c | 125 +++--
>  2 files changed, 125 insertions(+), 4 deletions(-)
>
> diff --git a/hw/core/machine.c b/hw/core/machine.c
> index debcdc0e70..ea70be0270 100644
> --- a/hw/core/machine.c
> +++ b/hw/core/machine.c
> @@ -37,7 +37,9 @@
>  #include "hw/virtio/virtio.h"
>  #include "hw/virtio/virtio-pci.h"
>
> -GlobalProperty hw_compat_6_2[] = {};
> +GlobalProperty hw_compat_6_2[] = {
> +{ "isa-applesmc", "hostosk", "off" }
> +};
>  const size_t hw_compat_6_2_len = G_N_ELEMENTS(hw_compat_6_2);
>
>  GlobalProperty hw_compat_6_1[] = {
> diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c
> index 1b9acaf1d3..99bcc937f9 100644
> --- a/hw/misc/applesmc.c
> +++ b/hw/misc/applesmc.c
> @@ -37,6 +37,11 @@
>  #include "qemu/module.h"
>  #include "qemu/timer.h"
>  #include "qom/object.h"
> +#include "qapi/error.h"
> +
> +#if defined(__APPLE__) && defined(__MACH__)
> +#include 
> +#endif
>
>  /* #define DEBUG_SMC */
>
> @@ -80,7 +85,7 @@ enum {
>  #define smc_debug(...) do { } while (0)
>  #endif
>
> -static char default_osk[64] = "This is a dummy key. Enter the real key "
> +static char default_osk[65] = "This is a dummy key. Enter the real key "
>"using the -osk parameter";
>
>  struct AppleSMCData {
> @@ -109,6 +114,7 @@ struct AppleSMCState {
>  uint8_t data_pos;
>  uint8_t data[255];
>  char *osk;
> +bool hostosk;
>  QLIST_HEAD(, AppleSMCData) data_def;
>  };
>
> @@ -312,6 +318,101 @@ static const MemoryRegionOps applesmc_err_io_ops = {
>  },
>  };
>
> +#if defined(__APPLE__) && defined(__MACH__)
> +/*
> + * Based on
> + *
> https://web.archive.org/web/20200103161737/osxbook.com/book/bonus/chapter7/tpmdrmmyth/
> + */
> +enum {
> +SMC_HANDLE_EVENT = 2,
> +SMC_READ_KEY = 5
> +};
> +
> +struct AppleSMCParam {
> +uint32_t key;
> +uint8_t pad0[22];
> +IOByteCount data_size;
> +uint8_t pad1[10];
> +uint8_t command;
> +uint32_t pad2;
> +uint8_t bytes[32];
> +};
> +
> +static bool applesmc_read_host_osk(char *host_osk, Error **errp)
> +{
> +assert(host_osk != NULL);
> +
> +io_service_t hostsmc_service = IO_OBJECT_NULL;
> +io_connect_t hostsmc_connect = IO_OBJECT_NULL;
> +size_t smc_param_size = sizeof(struct AppleSMCParam);
> +IOReturn status = kIOReturnError;
> +int i;
> +
> +struct AppleSMCParam smc_param[2] = {
> + {
> + .key = ('OSK0'),
> + .data_size = sizeof(smc_param[0].bytes),
> + .command = SMC_READ_KEY,
> + }, {
> + .key = ('OSK1'),
> + .data_size = sizeof(smc_param[0].bytes),
> + .command = SMC_READ_KEY,
> + },
> +};
> +
> +hostsmc_service = IOServiceGetMatchingService(
> +kIOMasterPortDefault,
> +IOServiceMatching("AppleSMC"));
> +if (hostsmc_service == IO_OBJECT_NULL) {
> +error_setg(errp, "Unable to get host-AppleSMC service");
> +goto error;
> +}
> +
> +status = IOServiceOpen(hostsmc_service,
> +   mach_task_self(),
> +   0,
> +   _connect);
> +if (status != kIOReturnSuccess || hostsmc_connect == IO_OBJECT_NULL) {
> +

Re: [PATCH v8 5/7] net/vmnet: implement bridged mode (vmnet-bridged)

2022-01-28 Thread Vladislav Yaroshchuk
вс, 23 янв. 2022 г. в 07:51, 李士林 :

> Hi:
> I develop a custom os use qemu and use macos as host, I use the net
> argument '-net nic,model=pcnet -net
> tap,ifname=tap0,script=no,downscript=no’ when run the qemu-system-i386,then
> I can get the network device in my custom os:
>
>
Please notice that `-net` is a legacy option
https://wiki.qemu.org/Documentation/Networking#The_legacy_-net_option


> pci_device_dump: vendor id:  0x1022
> pci_device_dump: device id:  0x2000
> pci_device_dump: class code: 0x2
> pci_device_dump: revision id:0x10
> pci_device_dump: multi function: 0
> pci_device_dump: card bus CIS pointer: 0
> pci_device_dump: subsystem vendor id: 0
> pci_device_dump: subsystem device id: 0
> pci_device_dump: expansion ROM base address: feb8
> pci_device_dump: capability list pointer:  0
> pci_device_dump: irq line: 11
> pci_device_dump: irq pin:  1
> pci_device_dump: min Gnt: 6
> pci_device_dump: max Lat:  255
> pci_device_dump: bar 0:
> pci_device_bar_dump: type: io base address
> pci_device_bar_dump: base address: c000
> pci_device_bar_dump: len: 20
> pci_device_dump: bar 1:
> pci_device_bar_dump: type: mem base address
> pci_device_bar_dump: base address: febd1000
> pci_device_bar_dump: len: 20
>
> I can send a message to the host from my custom os in qemu, but can’t
> receive a message from the host.
>
>
This is known issue:
https://gitlab.com/qemu-project/qemu/-/issues/335


> so I rebuild the qemu use this patch, then I use the argument '-netdev
> vmnet-bridged,id=vmnet,ifname=en0’ run the qemu-system-i386 again, this
> time, I can’t get the network device either, I don’t know why, how to use
> vmnet-bridged to send message to host from my custom os and receive a
> message from the host, what should I do? thanks a lot!


It's normal behavior since you've specified a
network backend only. See the corresponding
QEMU documentation section:
https://wiki.qemu.org/Documentation/Networking#Network_Backends

Currently you have:
`-netdev vmnet-bridged,id=vmnet,ifname=en0`
You need add a device:
 `-netdev vmnet-bridged,id=vmnet,ifname=en0 -device pcnet,netdev=vmnet`

Supported devices can be listed with -device help:
`qemu-system-xxx -device help`

--
Best Regards,

Vladislav Yaroshchuk


Re: [PATCH v13 2/7] net/vmnet: add vmnet backends to qapi/net

2022-01-28 Thread Vladislav Yaroshchuk
пт, 21 янв. 2022 г. в 16:03, Akihiko Odaki :

> On Fri, Jan 21, 2022 at 9:19 PM Vladislav Yaroshchuk
>  wrote:
> >
> >
> > чт, 20 янв. 2022 г. в 11:32, Roman Bolshakov :
> >>
> >> On Thu, Jan 13, 2022 at 08:22:14PM +0300, Vladislav Yaroshchuk wrote:
> >> > Create separate netdevs for each vmnet operating mode:
> >> > - vmnet-host
> >> > - vmnet-shared
> >> > - vmnet-bridged
> >> >
> >>
> >> Sure I'm late to the party but what if we add only one backend - vmnet
> >> with default mode set to shared and all parameters are added there?
> >>
> >> The CLI would look more reasonable for the most typical use case:
> >>  -netdev vmnet,id=if1 -device virtio-net,netdev=if1
> >>
> >> That would remove duplication of options in QAPI schema (e.g. isolated
> >> is available in all backends now, altough I'm not sure if it makes sense
> >> for bridged mode):
> >>
> >>  -netdev vmnet,id=if1,isolated=yes
> >>
> >> start-address, end-address and subnet-mask are also used by both shared
> >> and host modes.
> >>
> >> Bridged netdev would lool like:
> >>
> >>  -netdev vmnet,id=if1,mode=bridged,ifname=en1
> >>
> >> Checksum offloading also seems to be available for all backends from
> >> Monterey.
> >>
> >> The approach might simplify integration of the changes to libvirt and
> >> discovery of upcoming vmnet features via qapi.
> >>
> >
> > I can rewrite this if it sounds more suitable to use
> > single `vmnet` netdev instead of three different ones.
> > We can discuss this with Markus as a QAPI reviewer.
> > Markus, what is your opinion about single netdev?
> >
> > P.S. Seems we have enough time for discussion:
> > I started fixing memory leaks found by Akihiko and
> > met a strange deadlock on QEMU shutdown on
> > `qemu_mutex_lock_iothread()` during careful
> > interface destruction with added semaphore.
> > Need to go deeper to understand what's the
> > problem, it will take some time.
> >
> > Mentioned part of Akihiko's review:
> >
> https://patchew.org/QEMU/20220113172219.66372-1-yaroshchuk2...@gmail.com/20220113172219.66372-4-yaroshchuk2...@gmail.com/
>
>
> Actually I thought it would be tricky to implement.

You mean single netdev type?

Actually I thought it would be tricky to implement. A deadlock will
> occur in a simple implementation if vmnet_send is already queued but
> not executed yet when destructing:
> - vmnet_send tries to lock the iothread and waits for the destructor to
> unlock.
> - vmnet_stop_interface waits for vmnet_send finishing.
>
>
Sounds like that's what happens actually.
With added semaphore:
--- a/net/vmnet-common.m
+++ b/net/vmnet-common.m
@@ -320,13 +320,14 @@ void vmnet_cleanup_common(NetClientState *nc)
 "org.qemu.vmnet.destroy",
 DISPATCH_QUEUE_SERIAL
 );
-
+dispatch_semaphore_t if_destroy_sem = dispatch_semaphore_create(0);
 vmnet_stop_interface(
 s->vmnet_if,
 if_destroy_q,
 ^(vmnet_return_t status) {
+dispatch_semaphore_signal(if_destroy_sem);
 });
-
+dispatch_semaphore_wait(if_destroy_sem, DISPATCH_TIME_FOREVER);
 for (int i = 0; i < VMNET_PACKETS_LIMIT; ++i) {
 g_free(s->iov_buf[i].iov_base);
 }
-- 

I see this thread dump on deadlock:

(lldb) bt all
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  * frame #0: 0x7fff2037ebb2 libsystem_kernel.dylib`__semwait_signal +
10
frame #1: 0x7fff202fec1a libsystem_c.dylib`nanosleep + 196
frame #2: 0x7fff212c4bb8 Foundation`+[NSThread
sleepForTimeInterval:] + 170
frame #3: 0x000101ebce3a
qemu-system-x86_64`-[QemuCocoaAppController
applicationWillTerminate:](self=0x7fa9f91a1de0,
_cmd="applicationWillTerminate:",
aNotification=@"NSApplicationWillTerminateNotification") at cocoa.m:1202:5
frame #4: 0x7fff204a00cd
CoreFoundation`__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
frame #5: 0x7fff2053bb1c
CoreFoundation`___CFXRegistrationPost_block_invoke + 49
frame #6: 0x7fff2053ba9a CoreFoundation`_CFXRegistrationPost + 454
frame #7: 0x7fff2047134e CoreFoundation`_CFXNotificationPost + 736
frame #8: 0x7fff211e1bb8 Foundation`-[NSNotificationCenter
postNotificationName:object:userInfo:] + 59
frame #9: 0x7fff22f585b3 AppKit`-[NSApplication terminate:] + 1377
frame #10: 0x000101ebcf1f
qemu-system-x86_64`-[QemuCocoaAppController
windowShouldClose:](self=0x7fa9f91a1de0, _cmd="windowShouldClose:",
sender=0x7fa9f91a7810) at c

Re: [PATCH v13 2/7] net/vmnet: add vmnet backends to qapi/net

2022-01-21 Thread Vladislav Yaroshchuk
чт, 20 янв. 2022 г. в 11:32, Roman Bolshakov :

> On Thu, Jan 13, 2022 at 08:22:14PM +0300, Vladislav Yaroshchuk wrote:
> > Create separate netdevs for each vmnet operating mode:
> > - vmnet-host
> > - vmnet-shared
> > - vmnet-bridged
> >
>
> Sure I'm late to the party but what if we add only one backend - vmnet
> with default mode set to shared and all parameters are added there?
>
> The CLI would look more reasonable for the most typical use case:
>  -netdev vmnet,id=if1 -device virtio-net,netdev=if1
>
> That would remove duplication of options in QAPI schema (e.g. isolated
> is available in all backends now, altough I'm not sure if it makes sense
> for bridged mode):
>
>  -netdev vmnet,id=if1,isolated=yes
>
> start-address, end-address and subnet-mask are also used by both shared
> and host modes.
>
> Bridged netdev would lool like:
>
>  -netdev vmnet,id=if1,mode=bridged,ifname=en1
>
> Checksum offloading also seems to be available for all backends from
> Monterey.
>
> The approach might simplify integration of the changes to libvirt and
> discovery of upcoming vmnet features via qapi.
>
>
I can rewrite this if it sounds more suitable to use
single `vmnet` netdev instead of three different ones.
We can discuss this with Markus as a QAPI reviewer.
Markus, what is your opinion about single netdev?

P.S. Seems we have enough time for discussion:
I started fixing memory leaks found by Akihiko and
met a strange deadlock on QEMU shutdown on
`qemu_mutex_lock_iothread()` during careful
interface destruction with added semaphore.
Need to go deeper to understand what's the
problem, it will take some time.

Mentioned part of Akihiko's review:
https://patchew.org/QEMU/20220113172219.66372-1-yaroshchuk2...@gmail.com/20220113172219.66372-4-yaroshchuk2...@gmail.com/


Thanks,
> Roman
>
> > Signed-off-by: Vladislav Yaroshchuk 
> > ---
> >  net/clients.h   |  11 
> >  net/meson.build |   7 +++
> >  net/net.c   |  10 
> >  net/vmnet-bridged.m |  25 +
> >  net/vmnet-common.m  |  20 +++
> >  net/vmnet-host.c|  24 
> >  net/vmnet-shared.c  |  25 +
> >  net/vmnet_int.h |  25 +
> >  qapi/net.json   | 133 +++-
> >  9 files changed, 278 insertions(+), 2 deletions(-)
> >  create mode 100644 net/vmnet-bridged.m
> >  create mode 100644 net/vmnet-common.m
> >  create mode 100644 net/vmnet-host.c
> >  create mode 100644 net/vmnet-shared.c
> >  create mode 100644 net/vmnet_int.h
> >
> > diff --git a/net/net.c b/net/net.c
> > index f0d14dbfc1..1dbb64b935 100644
> > --- a/net/net.c
> > +++ b/net/net.c
> > @@ -1021,6 +1021,11 @@ static int (* const
> net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
> >  #ifdef CONFIG_L2TPV3
> >  [NET_CLIENT_DRIVER_L2TPV3]= net_init_l2tpv3,
> >  #endif
> > +#ifdef CONFIG_VMNET
> > +[NET_CLIENT_DRIVER_VMNET_HOST] = net_init_vmnet_host,
> > +[NET_CLIENT_DRIVER_VMNET_SHARED] = net_init_vmnet_shared,
> > +[NET_CLIENT_DRIVER_VMNET_BRIDGED] = net_init_vmnet_bridged,
> > +#endif /* CONFIG_VMNET */
> >  };
> >
> >
> > @@ -1106,6 +,11 @@ void show_netdevs(void)
> >  #endif
> >  #ifdef CONFIG_VHOST_VDPA
> >  "vhost-vdpa",
> > +#endif
> > +#ifdef CONFIG_VMNET
> > +    "vmnet-host",
> > +"vmnet-shared",
> > +"vmnet-bridged",
> >  #endif
> >  };
> >
> > diff --git a/net/vmnet-bridged.m b/net/vmnet-bridged.m
> > new file mode 100644
> > index 00..4e42a90391
> > --- /dev/null
> > +++ b/net/vmnet-bridged.m
> > @@ -0,0 +1,25 @@
> > +/*
> > + * vmnet-bridged.m
> > + *
> > + * Copyright(c) 2021 Vladislav Yaroshchuk 
> > + *
> > + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> > + * See the COPYING file in the top-level directory.
> > + *
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qapi/qapi-types-net.h"
> > +#include "vmnet_int.h"
> > +#include "clients.h"
> > +#include "qemu/error-report.h"
> > +#include "qapi/error.h"
> > +
> > +#include 
> > +
> > +int net_init_vmnet_bridged(const Netdev *netdev, const char *name,
> > +   NetClientState *peer, Error **errp)
> > +{
> > +  error_setg(errp, "vmnet-bridged is not implemented yet");
> > +  return -1;
> > +}
> > diff --git 

Re: [PATCH v13 1/7] net/vmnet: add vmnet dependency and customizable option

2022-01-21 Thread Vladislav Yaroshchuk
Hi Roman,

чт, 20 янв. 2022 г. в 10:14, Roman Bolshakov :

> On Thu, Jan 13, 2022 at 08:22:13PM +0300, Vladislav Yaroshchuk wrote:
> > vmnet.framework dependency is added with 'vmnet' option
> > to enable or disable it. Default value is 'auto'.
> >
> > vmnet features to be used are available since macOS 11.0,
>
> Hi Vladislav,
>
> I'm not sure if the comment belongs here. Perhaps you mean that bridged
> mode is available from 10.15:
>
> VMNET_BRIDGED_MODE API_AVAILABLE(macos(10.15))  = 1002
>
>
Yes, I forgot to update this part of the cover letter, thank you.


> This means vmnet.framework is supported on all macbooks starting from 2012.
>
> With this fixed,
> Tested-by: Roman Bolshakov 
> Reviewed-by: Roman Bolshakov 
>
> The other two modes - shared and host are supported on earlier versions
> of macOS (from 10.10). But port forwarding is only available from macOS
> 10.15.
>
> Theoretically it should possible to support the framework on the earlier
> models from 2010 or 2007 on Yosemite up to High Sierra with less
> features using MacPorts but I don't think it'd be reasonable to ask
> that.
>
>
I'm not sure it's necessary to support such old models. Compatibility with
10.15 on 2012+ macs is enough I think.

Thanks,
> Roman
>
> > corresponding probe is created into meson.build.
> >
> > Signed-off-by: Vladislav Yaroshchuk 
> > ---
> >  meson.build   | 16 +++-
> >  meson_options.txt |  2 ++
> >  scripts/meson-buildoptions.sh |  3 +++
> >  3 files changed, 20 insertions(+), 1 deletion(-)
> >
> > diff --git a/meson.build b/meson.build
> > index c1b1db1e28..285fb7bc41 100644
> > --- a/meson.build
> > +++ b/meson.build
> > @@ -496,6 +496,18 @@ if cocoa.found() and get_option('gtk').enabled()
> >error('Cocoa and GTK+ cannot be enabled at the same time')
> >  endif
> >
> > +vmnet = dependency('appleframeworks', modules: 'vmnet', required:
> get_option('vmnet'))
> > +if vmnet.found() and not cc.has_header_symbol('vmnet/vmnet.h',
> > +  'VMNET_BRIDGED_MODE',
> > +  dependencies: vmnet)
> > +  vmnet = not_found
> > +  if get_option('vmnet').enabled()
> > +error('vmnet.framework API is outdated')
> > +  else
> > +warning('vmnet.framework API is outdated, disabling')
> > +  endif
> > +endif
> > +
> >  seccomp = not_found
> >  if not get_option('seccomp').auto() or have_system or have_tools
> >seccomp = dependency('libseccomp', version: '>=2.3.0',
> > @@ -1492,6 +1504,7 @@ config_host_data.set('CONFIG_SECCOMP',
> seccomp.found())
> >  config_host_data.set('CONFIG_SNAPPY', snappy.found())
> >  config_host_data.set('CONFIG_USB_LIBUSB', libusb.found())
> >  config_host_data.set('CONFIG_VDE', vde.found())
> > +config_host_data.set('CONFIG_VMNET', vmnet.found())
> >  config_host_data.set('CONFIG_VHOST_USER_BLK_SERVER',
> have_vhost_user_blk_server)
> >  config_host_data.set('CONFIG_VNC', vnc.found())
> >  config_host_data.set('CONFIG_VNC_JPEG', jpeg.found())
> > @@ -3406,7 +3419,8 @@ summary(summary_info, bool_yn: true, section:
> 'Crypto')
> >  # Libraries
> >  summary_info = {}
> >  if targetos == 'darwin'
> > -  summary_info += {'Cocoa support':   cocoa}
> > +  summary_info += {'Cocoa support':   cocoa}
> > +  summary_info += {'vmnet.framework support': vmnet}
> >  endif
> >  summary_info += {'SDL support':   sdl}
> >  summary_info += {'SDL image support': sdl_image}
> > diff --git a/meson_options.txt b/meson_options.txt
> > index 921967eddb..701e1381f9 100644
> > --- a/meson_options.txt
> > +++ b/meson_options.txt
> > @@ -151,6 +151,8 @@ option('netmap', type : 'feature', value : 'auto',
> > description: 'netmap network backend support')
> >  option('vde', type : 'feature', value : 'auto',
> > description: 'vde network backend support')
> > +option('vmnet', type : 'feature', value : 'auto',
> > +   description: 'vmnet.framework network backend support')
> >  option('virglrenderer', type : 'feature', value : 'auto',
> > description: 'virgl rendering support')
> >  option('vnc', type : 'feature', value : 'auto',
> > diff --git a/scripts/meson-buildoptions.sh
> b/scripts/meson-buildoptions.sh
> > index 50bd7bed4d..cdcece4b05 100644
> > --- a/scripts/meson-buildoptions.sh
> > +++ b/scripts/meson-buildoptions.sh
> > @@ -84,6 +84,7 @@ meson_options_help() {
> >printf "%s\n" '  u2f   

Re: [PATCH v13 2/7] net/vmnet: add vmnet backends to qapi/net

2022-01-18 Thread Vladislav Yaroshchuk
вт, 18 янв. 2022 г. в 19:35, Markus Armbruster :

> Vladislav Yaroshchuk  writes:
>
> > вт, 18 янв. 2022 г. в 18:01, Markus Armbruster :
> >
> >> Vladislav Yaroshchuk  writes:
> >>
> >> > Create separate netdevs for each vmnet operating mode:
> >> > - vmnet-host
> >> > - vmnet-shared
> >> > - vmnet-bridged
> >> >
> >> > Signed-off-by: Vladislav Yaroshchuk 
> >>
> >> I acked v8 of the QAPI schema part.  You should add Acked-by and
> >> Reviewed-by you receive in later revisions, unless you make changes that
> >> invalidate them.  When in doubt, drop them.
> >>
> >>
> > Oh ok, I'll do that next time.
>
> Thanks :)
>
> >> > diff --git a/qapi/net.json b/qapi/net.json
> >> > index 7fab2e7cd8..b922e2e34f 100644
> >> > --- a/qapi/net.json
> >> > +++ b/qapi/net.json
> >> > @@ -452,6 +452,120 @@
> >> >  '*vhostdev': 'str',
> >> >  '*queues':   'int' } }
> >> >
> >> > +##
> >> > +# @NetdevVmnetHostOptions:
> >> > +#
> >> > +# vmnet (host mode) network backend.
> >> > +#
> >> > +# Allows the vmnet interface to communicate with other vmnet
> >> > +# interfaces that are in host mode and also with the host.
> >> > +#
> >> > +# @start-address: The starting IPv4 address to use for the interface.
> >> > +# Must be in the private IP range (RFC 1918). Must be
> >> > +# specified along with @end-address and @subnet-mask.
> >> > +# This address is used as the gateway address. The
> >> > +# subsequent address up to and including end-address
> are
> >> > +# placed in the DHCP pool.
> >> > +#
> >> > +# @end-address: The DHCP IPv4 range end address to use for the
> >> > +#   interface. Must be in the private IP range (RFC
> 1918).
> >> > +#   Must be specified along with @start-address and
> >> > +#   @subnet-mask.
> >> > +#
> >> > +# @subnet-mask: The IPv4 subnet mask to use on the interface. Must
> >> > +#   be specified along with @start-address and
> @subnet-mask.
> >> > +#
> >> > +# @isolated: Enable isolation for this interface. Interface isolation
> >> > +#ensures that vmnet interface is not able to communicate
> >> > +#with any other vmnet interfaces. Only communication with
> >> > +#host is allowed. Available since macOS Big Sur 11.0.
> >>
> >> What happens when the host is too old?
> >>
> >>
> > In this case netdev creation will fail with
> > corresponding message (error_setg() used).
>
> "Available" feels slightly misleading.  It's always available, it just
> doesn't work unless the host OS is new enough.  Suggest something like
> "Requires at least macOS Big Sur 11.0."
>
>
Yep, "Requires" sounds much more suitable. Will update
the description in the next version along with other fixes.

Thank you!

Same for the others.
>
> QAPI schema
> Acked-by: Markus Armbruster 
>
> [...]
>
>

-- 
Best Regards,

Vladislav Yaroshchuk


  1   2   3   >