Add the vhost-user netdev backend to the command line
The supplied chardev id will be inspected for supported options. Only a socket backend, with a set path (i.e. a Unix socket) and optionally the server parameter set, will be allowed. Other options (nowait, telnet) will make the chardev unusable and the netdev will not be initialised. Additional checks for validity: - requires `-numa node,memdev=..` - requires `-device virtio-net-*` The `vhostforce` option is used to force vhost-net when we deal with non-MSIX guests. Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com> Signed-off-by: Nikolay Nikolaev <n.nikolaev@virtualopensystems.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Acked-by: Luiz Capitulino <lcapitulino@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
d314f586b3
commit
03ce574442
3
configure
vendored
3
configure
vendored
@ -4515,6 +4515,9 @@ fi
|
|||||||
if test "$vhost_scsi" = "yes" ; then
|
if test "$vhost_scsi" = "yes" ; then
|
||||||
echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
|
echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
if test "$vhost_net" = "yes" ; then
|
||||||
|
echo "CONFIG_VHOST_NET_USED=y" >> $config_host_mak
|
||||||
|
fi
|
||||||
if test "$blobs" = "yes" ; then
|
if test "$blobs" = "yes" ; then
|
||||||
echo "INSTALL_BLOBS=yes" >> $config_host_mak
|
echo "INSTALL_BLOBS=yes" >> $config_host_mak
|
||||||
fi
|
fi
|
||||||
|
@ -1211,7 +1211,7 @@ ETEXI
|
|||||||
{
|
{
|
||||||
.name = "host_net_add",
|
.name = "host_net_add",
|
||||||
.args_type = "device:s,opts:s?",
|
.args_type = "device:s,opts:s?",
|
||||||
.params = "tap|user|socket|vde|netmap|bridge|dump [options]",
|
.params = "tap|user|socket|vde|netmap|bridge|vhost-user|dump [options]",
|
||||||
.help = "add host VLAN client",
|
.help = "add host VLAN client",
|
||||||
.mhandler.cmd = net_host_device_add,
|
.mhandler.cmd = net_host_device_add,
|
||||||
.command_completion = host_net_add_completion,
|
.command_completion = host_net_add_completion,
|
||||||
@ -1241,7 +1241,7 @@ ETEXI
|
|||||||
{
|
{
|
||||||
.name = "netdev_add",
|
.name = "netdev_add",
|
||||||
.args_type = "netdev:O",
|
.args_type = "netdev:O",
|
||||||
.params = "[user|tap|socket|vde|bridge|hubport|netmap],id=str[,prop=value][,...]",
|
.params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user],id=str[,prop=value][,...]",
|
||||||
.help = "add host network device",
|
.help = "add host network device",
|
||||||
.mhandler.cmd = hmp_netdev_add,
|
.mhandler.cmd = hmp_netdev_add,
|
||||||
.command_completion = netdev_add_completion,
|
.command_completion = netdev_add_completion,
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "net/net.h"
|
#include "net/net.h"
|
||||||
#include "net/tap.h"
|
#include "net/tap.h"
|
||||||
|
#include "net/vhost-user.h"
|
||||||
|
|
||||||
#include "hw/virtio/virtio-net.h"
|
#include "hw/virtio/virtio-net.h"
|
||||||
#include "net/vhost_net.h"
|
#include "net/vhost_net.h"
|
||||||
@ -360,6 +361,9 @@ VHostNetState *get_vhost_net(NetClientState *nc)
|
|||||||
case NET_CLIENT_OPTIONS_KIND_TAP:
|
case NET_CLIENT_OPTIONS_KIND_TAP:
|
||||||
vhost_net = tap_get_vhost_net(nc);
|
vhost_net = tap_get_vhost_net(nc);
|
||||||
break;
|
break;
|
||||||
|
case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
|
||||||
|
vhost_net = vhost_user_get_vhost_net(nc);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -322,6 +322,7 @@ void net_hub_check_clients(void)
|
|||||||
case NET_CLIENT_OPTIONS_KIND_TAP:
|
case NET_CLIENT_OPTIONS_KIND_TAP:
|
||||||
case NET_CLIENT_OPTIONS_KIND_SOCKET:
|
case NET_CLIENT_OPTIONS_KIND_SOCKET:
|
||||||
case NET_CLIENT_OPTIONS_KIND_VDE:
|
case NET_CLIENT_OPTIONS_KIND_VDE:
|
||||||
|
case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
|
||||||
has_host_dev = 1;
|
has_host_dev = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -62,6 +62,7 @@ const char *host_net_devices[] = {
|
|||||||
#ifdef CONFIG_VDE
|
#ifdef CONFIG_VDE
|
||||||
"vde",
|
"vde",
|
||||||
#endif
|
#endif
|
||||||
|
"vhost-user",
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -802,6 +803,9 @@ static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND_MAX])(
|
|||||||
[NET_CLIENT_OPTIONS_KIND_BRIDGE] = net_init_bridge,
|
[NET_CLIENT_OPTIONS_KIND_BRIDGE] = net_init_bridge,
|
||||||
#endif
|
#endif
|
||||||
[NET_CLIENT_OPTIONS_KIND_HUBPORT] = net_init_hubport,
|
[NET_CLIENT_OPTIONS_KIND_HUBPORT] = net_init_hubport,
|
||||||
|
#ifdef CONFIG_VHOST_NET_USED
|
||||||
|
[NET_CLIENT_OPTIONS_KIND_VHOST_USER] = net_init_vhost_user,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -835,6 +839,9 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp)
|
|||||||
case NET_CLIENT_OPTIONS_KIND_BRIDGE:
|
case NET_CLIENT_OPTIONS_KIND_BRIDGE:
|
||||||
#endif
|
#endif
|
||||||
case NET_CLIENT_OPTIONS_KIND_HUBPORT:
|
case NET_CLIENT_OPTIONS_KIND_HUBPORT:
|
||||||
|
#ifdef CONFIG_VHOST_NET_USED
|
||||||
|
case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
107
net/vhost-user.c
107
net/vhost-user.c
@ -12,6 +12,7 @@
|
|||||||
#include "net/vhost_net.h"
|
#include "net/vhost_net.h"
|
||||||
#include "net/vhost-user.h"
|
#include "net/vhost-user.h"
|
||||||
#include "sysemu/char.h"
|
#include "sysemu/char.h"
|
||||||
|
#include "qemu/config-file.h"
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
|
|
||||||
typedef struct VhostUserState {
|
typedef struct VhostUserState {
|
||||||
@ -21,9 +22,16 @@ typedef struct VhostUserState {
|
|||||||
VHostNetState *vhost_net;
|
VHostNetState *vhost_net;
|
||||||
} VhostUserState;
|
} VhostUserState;
|
||||||
|
|
||||||
|
typedef struct VhostUserChardevProps {
|
||||||
|
bool is_socket;
|
||||||
|
bool is_unix;
|
||||||
|
bool is_server;
|
||||||
|
} VhostUserChardevProps;
|
||||||
|
|
||||||
VHostNetState *vhost_user_get_vhost_net(NetClientState *nc)
|
VHostNetState *vhost_user_get_vhost_net(NetClientState *nc)
|
||||||
{
|
{
|
||||||
VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc);
|
VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc);
|
||||||
|
assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
|
||||||
return s->vhost_net;
|
return s->vhost_net;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +90,7 @@ static bool vhost_user_has_ufo(NetClientState *nc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static NetClientInfo net_vhost_user_info = {
|
static NetClientInfo net_vhost_user_info = {
|
||||||
.type = 0,
|
.type = NET_CLIENT_OPTIONS_KIND_VHOST_USER,
|
||||||
.size = sizeof(VhostUserState),
|
.size = sizeof(VhostUserState),
|
||||||
.cleanup = vhost_user_cleanup,
|
.cleanup = vhost_user_cleanup,
|
||||||
.has_vnet_hdr = vhost_user_has_vnet_hdr,
|
.has_vnet_hdr = vhost_user_has_vnet_hdr,
|
||||||
@ -148,8 +156,103 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int net_vhost_chardev_opts(const char *name, const char *value,
|
||||||
|
void *opaque)
|
||||||
|
{
|
||||||
|
VhostUserChardevProps *props = opaque;
|
||||||
|
|
||||||
|
if (strcmp(name, "backend") == 0 && strcmp(value, "socket") == 0) {
|
||||||
|
props->is_socket = true;
|
||||||
|
} else if (strcmp(name, "path") == 0) {
|
||||||
|
props->is_unix = true;
|
||||||
|
} else if (strcmp(name, "server") == 0) {
|
||||||
|
props->is_server = true;
|
||||||
|
} else {
|
||||||
|
error_report("vhost-user does not support a chardev"
|
||||||
|
" with the following option:\n %s = %s",
|
||||||
|
name, value);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CharDriverState *net_vhost_parse_chardev(const NetdevVhostUserOptions *opts)
|
||||||
|
{
|
||||||
|
CharDriverState *chr = qemu_chr_find(opts->chardev);
|
||||||
|
VhostUserChardevProps props;
|
||||||
|
|
||||||
|
if (chr == NULL) {
|
||||||
|
error_report("chardev \"%s\" not found", opts->chardev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inspect chardev opts */
|
||||||
|
memset(&props, 0, sizeof(props));
|
||||||
|
if (qemu_opt_foreach(chr->opts, net_vhost_chardev_opts, &props, true) != 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!props.is_socket || !props.is_unix) {
|
||||||
|
error_report("chardev \"%s\" is not a unix socket",
|
||||||
|
opts->chardev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_chr_fe_claim_no_fail(chr);
|
||||||
|
|
||||||
|
return chr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int net_vhost_check_net(QemuOpts *opts, void *opaque)
|
||||||
|
{
|
||||||
|
const char *name = opaque;
|
||||||
|
const char *driver, *netdev;
|
||||||
|
const char virtio_name[] = "virtio-net-";
|
||||||
|
|
||||||
|
driver = qemu_opt_get(opts, "driver");
|
||||||
|
netdev = qemu_opt_get(opts, "netdev");
|
||||||
|
|
||||||
|
if (!driver || !netdev) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(netdev, name) == 0 &&
|
||||||
|
strncmp(driver, virtio_name, strlen(virtio_name)) != 0) {
|
||||||
|
error_report("vhost-user requires frontend driver virtio-net-*");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int net_init_vhost_user(const NetClientOptions *opts, const char *name,
|
int net_init_vhost_user(const NetClientOptions *opts, const char *name,
|
||||||
NetClientState *peer)
|
NetClientState *peer)
|
||||||
{
|
{
|
||||||
return net_vhost_user_init(peer, "vhost_user", 0, 0, 0);
|
const NetdevVhostUserOptions *vhost_user_opts;
|
||||||
|
CharDriverState *chr;
|
||||||
|
bool vhostforce;
|
||||||
|
|
||||||
|
assert(opts->kind == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
|
||||||
|
vhost_user_opts = opts->vhost_user;
|
||||||
|
|
||||||
|
chr = net_vhost_parse_chardev(vhost_user_opts);
|
||||||
|
if (!chr) {
|
||||||
|
error_report("No suitable chardev found");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* verify net frontend */
|
||||||
|
if (qemu_opts_foreach(qemu_find_opts("device"), net_vhost_check_net,
|
||||||
|
(char *)name, true) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vhostforce for non-MSIX */
|
||||||
|
if (vhost_user_opts->has_vhostforce) {
|
||||||
|
vhostforce = vhost_user_opts->vhostforce;
|
||||||
|
} else {
|
||||||
|
vhostforce = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return net_vhost_user_init(peer, "vhost_user", name, chr, vhostforce);
|
||||||
}
|
}
|
||||||
|
@ -2068,6 +2068,22 @@
|
|||||||
'ifname': 'str',
|
'ifname': 'str',
|
||||||
'*devname': 'str' } }
|
'*devname': 'str' } }
|
||||||
|
|
||||||
|
##
|
||||||
|
# @NetdevVhostUserOptions
|
||||||
|
#
|
||||||
|
# Vhost-user network backend
|
||||||
|
#
|
||||||
|
# @chardev: name of a unix socket chardev
|
||||||
|
#
|
||||||
|
# @vhostforce: #optional vhost on for non-MSIX virtio guests (default: false).
|
||||||
|
#
|
||||||
|
# Since 2.1
|
||||||
|
##
|
||||||
|
{ 'type': 'NetdevVhostUserOptions',
|
||||||
|
'data': {
|
||||||
|
'chardev': 'str',
|
||||||
|
'*vhostforce': 'bool' } }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @NetClientOptions
|
# @NetClientOptions
|
||||||
#
|
#
|
||||||
@ -2086,7 +2102,8 @@
|
|||||||
'dump': 'NetdevDumpOptions',
|
'dump': 'NetdevDumpOptions',
|
||||||
'bridge': 'NetdevBridgeOptions',
|
'bridge': 'NetdevBridgeOptions',
|
||||||
'hubport': 'NetdevHubPortOptions',
|
'hubport': 'NetdevHubPortOptions',
|
||||||
'netmap': 'NetdevNetmapOptions' } }
|
'netmap': 'NetdevNetmapOptions',
|
||||||
|
'vhost-user': 'NetdevVhostUserOptions' } }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @NetLegacy
|
# @NetLegacy
|
||||||
|
@ -1460,6 +1460,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
|
|||||||
#ifdef CONFIG_NETMAP
|
#ifdef CONFIG_NETMAP
|
||||||
"netmap|"
|
"netmap|"
|
||||||
#endif
|
#endif
|
||||||
|
"vhost-user|"
|
||||||
"socket|"
|
"socket|"
|
||||||
"hubport],id=str[,option][,option][,...]\n", QEMU_ARCH_ALL)
|
"hubport],id=str[,option][,option][,...]\n", QEMU_ARCH_ALL)
|
||||||
STEXI
|
STEXI
|
||||||
@ -1791,6 +1792,23 @@ The hubport netdev lets you connect a NIC to a QEMU "vlan" instead of a single
|
|||||||
netdev. @code{-net} and @code{-device} with parameter @option{vlan} create the
|
netdev. @code{-net} and @code{-device} with parameter @option{vlan} create the
|
||||||
required hub automatically.
|
required hub automatically.
|
||||||
|
|
||||||
|
@item -netdev vhost-user,chardev=@var{id}[,vhostforce=on|off]
|
||||||
|
|
||||||
|
Establish a vhost-user netdev, backed by a chardev @var{id}. The chardev should
|
||||||
|
be a unix domain socket backed one. The vhost-user uses a specifically defined
|
||||||
|
protocol to pass vhost ioctl replacement messages to an application on the other
|
||||||
|
end of the socket. On non-MSIX guests, the feature can be forced with
|
||||||
|
@var{vhostforce}.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
@example
|
||||||
|
qemu -m 512 -object memory-backend-file,id=mem,size=512M,mem-path=/hugetlbfs,share=on \
|
||||||
|
-numa node,memdev=mem \
|
||||||
|
-chardev socket,path=/path/to/socket \
|
||||||
|
-netdev type=vhost-user,id=net0,chardev=chr0 \
|
||||||
|
-device virtio-net-pci,netdev=net0
|
||||||
|
@end example
|
||||||
|
|
||||||
@item -net dump[,vlan=@var{n}][,file=@var{file}][,len=@var{len}]
|
@item -net dump[,vlan=@var{n}][,file=@var{file}][,len=@var{len}]
|
||||||
Dump network traffic on VLAN @var{n} to file @var{file} (@file{qemu-vlan0.pcap} by default).
|
Dump network traffic on VLAN @var{n} to file @var{file} (@file{qemu-vlan0.pcap} by default).
|
||||||
At most @var{len} bytes (64k by default) per packet are stored. The file format is
|
At most @var{len} bytes (64k by default) per packet are stored. The file format is
|
||||||
|
Loading…
Reference in New Issue
Block a user