mirror of https://github.com/xemu-project/xemu.git
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1 iQEcBAABAgAGBQJig2G8AAoJEO8Ells5jWIR7ocH/j+bduaZwE9HM+a9CbemkdOz 7iPPEq8eKPvLrcURa8DNmguwGul+NSXv1jonb1m1P/C5Lox/PagdC219irk43WGc DJBzkAo+wOetmvVeCCQl4ovJbYF4PBftYaxkBfm8KbavnoD1aSUPL70QHVvGmuKi kxmf9WMQgksw+LirSI4avZSJc1YIsjruEYDagbZmA5r/kTNbm4zobLe8/BV/2mgJ j5bHbrPeci8feBFhjuBVgZKkbUU7HrJj9kLAzbObdQ8a9VDtaWWfQiwmpeAaItl0 5OHSD+tFsGt3MSZn+/LXP9emJeKDnLt+LCxvT0yzGw06iF9N0WFJlSUdd4eYkjI= =5fRf -----END PGP SIGNATURE----- Merge tag 'net-pull-request' of https://github.com/jasowang/qemu into staging # -----BEGIN PGP SIGNATURE----- # Version: GnuPG v1 # # iQEcBAABAgAGBQJig2G8AAoJEO8Ells5jWIR7ocH/j+bduaZwE9HM+a9CbemkdOz # 7iPPEq8eKPvLrcURa8DNmguwGul+NSXv1jonb1m1P/C5Lox/PagdC219irk43WGc # DJBzkAo+wOetmvVeCCQl4ovJbYF4PBftYaxkBfm8KbavnoD1aSUPL70QHVvGmuKi # kxmf9WMQgksw+LirSI4avZSJc1YIsjruEYDagbZmA5r/kTNbm4zobLe8/BV/2mgJ # j5bHbrPeci8feBFhjuBVgZKkbUU7HrJj9kLAzbObdQ8a9VDtaWWfQiwmpeAaItl0 # 5OHSD+tFsGt3MSZn+/LXP9emJeKDnLt+LCxvT0yzGw06iF9N0WFJlSUdd4eYkjI= # =5fRf # -----END PGP SIGNATURE----- # gpg: Signature made Tue 17 May 2022 01:50:04 AM PDT # gpg: using RSA key EF04965B398D6211 # gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 215D 46F4 8246 689E C77F 3562 EF04 965B 398D 6211 * tag 'net-pull-request' of https://github.com/jasowang/qemu: tulip: Assign default MAC address if not specified net/vmnet: update hmp-commands.hx net/vmnet: update qemu-options.hx net/vmnet: implement bridged mode (vmnet-bridged) net/vmnet: implement host mode (vmnet-host) net/vmnet: implement shared mode (vmnet-shared) net/vmnet: add vmnet backends to qapi/net net/vmnet: add vmnet dependency and customizable option Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
bcf0a3a422
|
@ -1269,7 +1269,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,
|
||||
|
|
|
@ -967,6 +967,8 @@ static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp)
|
|||
pci_conf = s->dev.config;
|
||||
pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
|
||||
|
||||
qemu_macaddr_default_if_unset(&s->c.macaddr);
|
||||
|
||||
s->eeprom = eeprom93xx_new(&pci_dev->qdev, 64);
|
||||
tulip_fill_eeprom(s);
|
||||
|
||||
|
@ -981,8 +983,6 @@ static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp)
|
|||
|
||||
s->irq = pci_allocate_irq(&s->dev);
|
||||
|
||||
qemu_macaddr_default_if_unset(&s->c.macaddr);
|
||||
|
||||
s->nic = qemu_new_nic(&net_tulip_info, &s->c,
|
||||
object_get_typename(OBJECT(pci_dev)),
|
||||
pci_dev->qdev.id, s);
|
||||
|
|
16
meson.build
16
meson.build
|
@ -580,6 +580,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',
|
||||
|
@ -1741,6 +1753,7 @@ config_host_data.set('CONFIG_VHOST_KERNEL', have_vhost_kernel)
|
|||
config_host_data.set('CONFIG_VHOST_USER', have_vhost_user)
|
||||
config_host_data.set('CONFIG_VHOST_CRYPTO', have_vhost_user_crypto)
|
||||
config_host_data.set('CONFIG_VHOST_VDPA', have_vhost_vdpa)
|
||||
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_PNG', png.found())
|
||||
config_host_data.set('CONFIG_VNC', vnc.found())
|
||||
|
@ -3897,7 +3910,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}
|
||||
|
|
|
@ -197,6 +197,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('png', type : 'feature', value : 'auto',
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -44,4 +44,11 @@ if have_vhost_net_vdpa
|
|||
softmmu_ss.add(files('vhost-vdpa.c'))
|
||||
endif
|
||||
|
||||
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')
|
||||
|
|
10
net/net.c
10
net/net.c
|
@ -1020,6 +1020,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 */
|
||||
};
|
||||
|
||||
|
||||
|
@ -1105,6 +1110,11 @@ void show_netdevs(void)
|
|||
#endif
|
||||
#ifdef CONFIG_VHOST_VDPA
|
||||
"vhost-vdpa",
|
||||
#endif
|
||||
#ifdef CONFIG_VMNET
|
||||
"vmnet-host",
|
||||
"vmnet-shared",
|
||||
"vmnet-bridged",
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* vmnet-bridged.m
|
||||
*
|
||||
* Copyright(c) 2022 Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com>
|
||||
*
|
||||
* 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 "qapi/error.h"
|
||||
#include "clients.h"
|
||||
#include "vmnet_int.h"
|
||||
|
||||
#include <vmnet/vmnet.h>
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
NetClientState *nc = qemu_new_net_client(&net_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;
|
||||
}
|
|
@ -0,0 +1,378 @@
|
|||
/*
|
||||
* vmnet-common.m - network client wrapper for Apple vmnet.framework
|
||||
*
|
||||
* Copyright(c) 2022 Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com>
|
||||
* Copyright(c) 2021 Phillip Tennen <phillip@axleos.com>
|
||||
*
|
||||
* 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 "qemu/main-loop.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qapi/qapi-types-net.h"
|
||||
#include "vmnet_int.h"
|
||||
#include "clients.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#include <vmnet/vmnet.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
|
||||
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 = &iov;
|
||||
pkt_cnt = 1;
|
||||
|
||||
if_status = vmnet_write(s->vmnet_if, &packet, &pkt_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, &s->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(&s->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);
|
||||
|
||||
if (size == 0) {
|
||||
/* QEMU is not ready to consume more packets -
|
||||
* stop and wait for completion callback call */
|
||||
return;
|
||||
}
|
||||
++s->packets_send_current_pos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* including current_pos, excluding end_pos.
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int vmnet_if_create(NetClientState *nc,
|
||||
xpc_object_t if_desc,
|
||||
Error **errp)
|
||||
{
|
||||
VmnetState *s = DO_UPCAST(VmnetState, nc, nc);
|
||||
dispatch_semaphore_t if_created_sem = dispatch_semaphore_create(0);
|
||||
__block vmnet_return_t if_status;
|
||||
|
||||
s->if_queue = dispatch_queue_create(
|
||||
"org.qemu.vmnet.if_queue",
|
||||
DISPATCH_QUEUE_SERIAL
|
||||
);
|
||||
|
||||
xpc_dictionary_set_bool(
|
||||
if_desc,
|
||||
vmnet_allocate_mac_address_key,
|
||||
false
|
||||
);
|
||||
|
||||
#ifdef DEBUG
|
||||
qemu_log("vmnet.start.interface_desc:\n");
|
||||
xpc_dictionary_apply(if_desc,
|
||||
^bool(const char *k, xpc_object_t v) {
|
||||
char *desc = xpc_copy_description(v);
|
||||
qemu_log(" %s=%s\n", k, desc);
|
||||
free(desc);
|
||||
return true;
|
||||
});
|
||||
#endif /* DEBUG */
|
||||
|
||||
s->vmnet_if = vmnet_start_interface(
|
||||
if_desc,
|
||||
s->if_queue,
|
||||
^(vmnet_return_t status, xpc_object_t interface_param) {
|
||||
if_status = status;
|
||||
if (status != VMNET_SUCCESS || !interface_param) {
|
||||
dispatch_semaphore_signal(if_created_sem);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
qemu_log("vmnet.start.interface_param:\n");
|
||||
xpc_dictionary_apply(interface_param,
|
||||
^bool(const char *k, xpc_object_t v) {
|
||||
char *desc = xpc_copy_description(v);
|
||||
qemu_log(" %s=%s\n", k, desc);
|
||||
free(desc);
|
||||
return true;
|
||||
});
|
||||
#endif /* DEBUG */
|
||||
|
||||
s->mtu = xpc_dictionary_get_uint64(
|
||||
interface_param,
|
||||
vmnet_mtu_key);
|
||||
s->max_packet_size = xpc_dictionary_get_uint64(
|
||||
interface_param,
|
||||
vmnet_max_packet_size_key);
|
||||
|
||||
dispatch_semaphore_signal(if_created_sem);
|
||||
});
|
||||
|
||||
if (s->vmnet_if == NULL) {
|
||||
dispatch_release(s->if_queue);
|
||||
dispatch_release(if_created_sem);
|
||||
error_setg(errp,
|
||||
"unable to create interface with requested params");
|
||||
return -1;
|
||||
}
|
||||
|
||||
dispatch_semaphore_wait(if_created_sem, DISPATCH_TIME_FOREVER);
|
||||
dispatch_release(if_created_sem);
|
||||
|
||||
if (if_status != VMNET_SUCCESS) {
|
||||
dispatch_release(s->if_queue);
|
||||
error_setg(errp,
|
||||
"cannot create vmnet interface: %s",
|
||||
vmnet_status_map_str(if_status));
|
||||
return -1;
|
||||
}
|
||||
|
||||
s->send_bh = aio_bh_new(qemu_get_aio_context(), vmnet_send_bh, nc);
|
||||
vmnet_bufs_init(s);
|
||||
|
||||
s->packets_send_current_pos = 0;
|
||||
s->packets_send_end_pos = 0;
|
||||
|
||||
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.
|
||||
*/
|
||||
qemu_bh_schedule(s->send_bh);
|
||||
});
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void vmnet_cleanup_common(NetClientState *nc)
|
||||
{
|
||||
VmnetState *s = DO_UPCAST(VmnetState, nc, nc);
|
||||
dispatch_semaphore_t if_stopped_sem;
|
||||
|
||||
if (s->vmnet_if == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if_stopped_sem = dispatch_semaphore_create(0);
|
||||
vmnet_stop_interface(
|
||||
s->vmnet_if,
|
||||
s->if_queue,
|
||||
^(vmnet_return_t status) {
|
||||
assert(status == VMNET_SUCCESS);
|
||||
dispatch_semaphore_signal(if_stopped_sem);
|
||||
});
|
||||
dispatch_semaphore_wait(if_stopped_sem, DISPATCH_TIME_FOREVER);
|
||||
|
||||
qemu_purge_queued_packets(nc);
|
||||
|
||||
qemu_bh_delete(s->send_bh);
|
||||
dispatch_release(if_stopped_sem);
|
||||
dispatch_release(s->if_queue);
|
||||
|
||||
for (int i = 0; i < VMNET_PACKETS_LIMIT; ++i) {
|
||||
g_free(s->iov_buf[i].iov_base);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* vmnet-host.c
|
||||
*
|
||||
* Copyright(c) 2022 Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com>
|
||||
*
|
||||
* 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 "qemu/uuid.h"
|
||||
#include "qapi/qapi-types-net.h"
|
||||
#include "qapi/error.h"
|
||||
#include "clients.h"
|
||||
#include "vmnet_int.h"
|
||||
|
||||
#include <vmnet/vmnet.h>
|
||||
|
||||
|
||||
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, &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)
|
||||
{
|
||||
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, &net_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)
|
||||
{
|
||||
NetClientState *nc = qemu_new_net_client(&net_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;
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* vmnet-shared.c
|
||||
*
|
||||
* Copyright(c) 2022 Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com>
|
||||
*
|
||||
* 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 "qapi/error.h"
|
||||
#include "vmnet_int.h"
|
||||
#include "clients.h"
|
||||
|
||||
#include <vmnet/vmnet.h>
|
||||
|
||||
|
||||
static bool validate_options(const Netdev *netdev, Error **errp)
|
||||
{
|
||||
const NetdevVmnetSharedOptions *options = &(netdev->u.vmnet_shared);
|
||||
|
||||
#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-shared.isolated 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 NetdevVmnetSharedOptions *options = &(netdev->u.vmnet_shared);
|
||||
xpc_object_t if_desc = xpc_dictionary_create(NULL, NULL, 0);
|
||||
|
||||
xpc_dictionary_set_uint64(
|
||||
if_desc,
|
||||
vmnet_operation_mode_key,
|
||||
VMNET_SHARED_MODE
|
||||
);
|
||||
|
||||
if (options->has_nat66_prefix) {
|
||||
xpc_dictionary_set_string(if_desc,
|
||||
vmnet_nat66_prefix_key,
|
||||
options->nat66_prefix);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
#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_shared_info = {
|
||||
.type = NET_CLIENT_DRIVER_VMNET_SHARED,
|
||||
.size = sizeof(VmnetState),
|
||||
.receive = vmnet_receive_common,
|
||||
.cleanup = vmnet_cleanup_common,
|
||||
};
|
||||
|
||||
int net_init_vmnet_shared(const Netdev *netdev, const char *name,
|
||||
NetClientState *peer, Error **errp)
|
||||
{
|
||||
NetClientState *nc = qemu_new_net_client(&net_vmnet_shared_info,
|
||||
peer, "vmnet-shared", 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;
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* vmnet_int.h
|
||||
*
|
||||
* Copyright(c) 2022 Vladislav Yaroshchuk <vladislav.yaroshchuk@jetbrains.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
#ifndef VMNET_INT_H
|
||||
#define VMNET_INT_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "vmnet_int.h"
|
||||
#include "clients.h"
|
||||
|
||||
#include <vmnet/vmnet.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
/**
|
||||
* From vmnet.framework documentation
|
||||
*
|
||||
* Each read/write call allows up to 200 packets to be
|
||||
* read or written for a maximum of 256KB.
|
||||
*
|
||||
* Each packet written should be a complete
|
||||
* ethernet frame.
|
||||
*
|
||||
* https://developer.apple.com/documentation/vmnet
|
||||
*/
|
||||
#define VMNET_PACKETS_LIMIT 200
|
||||
|
||||
typedef struct VmnetState {
|
||||
NetClientState nc;
|
||||
interface_ref vmnet_if;
|
||||
|
||||
uint64_t mtu;
|
||||
uint64_t max_packet_size;
|
||||
|
||||
dispatch_queue_t if_queue;
|
||||
|
||||
QEMUBH *send_bh;
|
||||
|
||||
struct vmpktdesc packets_buf[VMNET_PACKETS_LIMIT];
|
||||
int packets_send_current_pos;
|
||||
int packets_send_end_pos;
|
||||
|
||||
struct iovec iov_buf[VMNET_PACKETS_LIMIT];
|
||||
} VmnetState;
|
||||
|
||||
const char *vmnet_status_map_str(vmnet_return_t status);
|
||||
|
||||
int vmnet_if_create(NetClientState *nc,
|
||||
xpc_object_t if_desc,
|
||||
Error **errp);
|
||||
|
||||
ssize_t vmnet_receive_common(NetClientState *nc,
|
||||
const uint8_t *buf,
|
||||
size_t size);
|
||||
|
||||
void vmnet_cleanup_common(NetClientState *nc);
|
||||
|
||||
#endif /* VMNET_INT_H */
|
133
qapi/net.json
133
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. Requires at least macOS Big Sur 11.0.
|
||||
#
|
||||
# @net-uuid: The identifier (UUID) to uniquely identify the isolated
|
||||
# network vmnet interface should be added to. If
|
||||
# set, no DHCP service is provided for this interface and
|
||||
# network communication is allowed only with other interfaces
|
||||
# added to this network identified by the UUID. Requires
|
||||
# at least macOS Big Sur 11.0.
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'struct': 'NetdevVmnetHostOptions',
|
||||
'data': {
|
||||
'*start-address': 'str',
|
||||
'*end-address': 'str',
|
||||
'*subnet-mask': 'str',
|
||||
'*isolated': 'bool',
|
||||
'*net-uuid': 'str' },
|
||||
'if': 'CONFIG_VMNET' }
|
||||
|
||||
##
|
||||
# @NetdevVmnetSharedOptions:
|
||||
#
|
||||
# vmnet (shared mode) network backend.
|
||||
#
|
||||
# Allows traffic originating from the vmnet interface to reach the
|
||||
# Internet through a network address translator (NAT).
|
||||
# The vmnet interface can communicate with the host and with
|
||||
# other shared mode interfaces on the same subnet. If no DHCP
|
||||
# settings, subnet mask and IPv6 prefix specified, the interface can
|
||||
# communicate with any of other interfaces in shared mode.
|
||||
#
|
||||
# @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. Requires at least macOS Big Sur 11.0.
|
||||
#
|
||||
# @nat66-prefix: The IPv6 prefix to use into guest network. Must be a
|
||||
# unique local address i.e. start with fd00::/8 and have
|
||||
# length of 64.
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'struct': 'NetdevVmnetSharedOptions',
|
||||
'data': {
|
||||
'*start-address': 'str',
|
||||
'*end-address': 'str',
|
||||
'*subnet-mask': 'str',
|
||||
'*isolated': 'bool',
|
||||
'*nat66-prefix': 'str' },
|
||||
'if': 'CONFIG_VMNET' }
|
||||
|
||||
##
|
||||
# @NetdevVmnetBridgedOptions:
|
||||
#
|
||||
# vmnet (bridged mode) network backend.
|
||||
#
|
||||
# Bridges the vmnet interface with a physical network interface.
|
||||
#
|
||||
# @ifname: The name of the physical interface to be bridged.
|
||||
#
|
||||
# @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. Requires at least macOS Big Sur 11.0.
|
||||
#
|
||||
# Since: 7.1
|
||||
##
|
||||
{ 'struct': 'NetdevVmnetBridgedOptions',
|
||||
'data': {
|
||||
'ifname': 'str',
|
||||
'*isolated': 'bool' },
|
||||
'if': 'CONFIG_VMNET' }
|
||||
|
||||
##
|
||||
# @NetClientDriver:
|
||||
#
|
||||
|
@ -460,10 +574,16 @@
|
|||
# Since: 2.7
|
||||
#
|
||||
# @vhost-vdpa since 5.1
|
||||
# @vmnet-host since 7.1
|
||||
# @vmnet-shared since 7.1
|
||||
# @vmnet-bridged since 7.1
|
||||
##
|
||||
{ 'enum': 'NetClientDriver',
|
||||
'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'vde',
|
||||
'bridge', 'hubport', 'netmap', 'vhost-user', 'vhost-vdpa' ] }
|
||||
'bridge', 'hubport', 'netmap', 'vhost-user', 'vhost-vdpa',
|
||||
{ 'name': 'vmnet-host', 'if': 'CONFIG_VMNET' },
|
||||
{ 'name': 'vmnet-shared', 'if': 'CONFIG_VMNET' },
|
||||
{ 'name': 'vmnet-bridged', 'if': 'CONFIG_VMNET' }] }
|
||||
|
||||
##
|
||||
# @Netdev:
|
||||
|
@ -477,6 +597,9 @@
|
|||
# Since: 1.2
|
||||
#
|
||||
# 'l2tpv3' - since 2.1
|
||||
# 'vmnet-host' - since 7.1
|
||||
# 'vmnet-shared' - since 7.1
|
||||
# 'vmnet-bridged' - since 7.1
|
||||
##
|
||||
{ 'union': 'Netdev',
|
||||
'base': { 'id': 'str', 'type': 'NetClientDriver' },
|
||||
|
@ -492,7 +615,13 @@
|
|||
'hubport': 'NetdevHubPortOptions',
|
||||
'netmap': 'NetdevNetmapOptions',
|
||||
'vhost-user': 'NetdevVhostUserOptions',
|
||||
'vhost-vdpa': 'NetdevVhostVDPAOptions' } }
|
||||
'vhost-vdpa': 'NetdevVhostVDPAOptions',
|
||||
'vmnet-host': { 'type': 'NetdevVmnetHostOptions',
|
||||
'if': 'CONFIG_VMNET' },
|
||||
'vmnet-shared': { 'type': 'NetdevVmnetSharedOptions',
|
||||
'if': 'CONFIG_VMNET' },
|
||||
'vmnet-bridged': { 'type': 'NetdevVmnetBridgedOptions',
|
||||
'if': 'CONFIG_VMNET' } } }
|
||||
|
||||
##
|
||||
# @RxState:
|
||||
|
|
|
@ -2795,6 +2795,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)
|
||||
|
@ -2814,6 +2833,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"
|
||||
|
@ -2836,6 +2858,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"
|
||||
|
|
|
@ -158,6 +158,7 @@ meson_options_help() {
|
|||
printf "%s\n" ' vhost-kernel vhost kernel backend support'
|
||||
printf "%s\n" ' vhost-net vhost-net kernel acceleration support'
|
||||
printf "%s\n" ' vhost-user vhost-user backend 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" ' vhost-vdpa vhost-vdpa kernel backend support'
|
||||
|
|
Loading…
Reference in New Issue