diff mbox series

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

Message ID 20220225171402.64861-6-Vladislav.Yaroshchuk@jetbrains.com
State New
Headers show
Series Add vmnet.framework based network backend | expand

Commit Message

Vladislav Yaroshchuk Feb. 25, 2022, 5:13 p.m. UTC
Signed-off-by: Vladislav Yaroshchuk <Vladislav.Yaroshchuk@jetbrains.com>
---
 net/vmnet-bridged.m | 129 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 124 insertions(+), 5 deletions(-)

Comments

Akihiko Odaki Feb. 25, 2022, 5:50 p.m. UTC | #1
On 2022/02/26 2:13, Vladislav Yaroshchuk wrote:
> Signed-off-by: Vladislav Yaroshchuk <Vladislav.Yaroshchuk@jetbrains.com>
> ---
>   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 <vmnet/vmnet.h>
>   
> +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];

I'm not sure if it always fits in 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(&net_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);
>   }
diff mbox series

Patch

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 <vmnet/vmnet.h>
 
+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(&net_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);
 }