Skip to content

Commit

Permalink
Add the vhost-user netdev backend to the command line
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Nikolay Nikolaev <[email protected]>
Reviewed-by: Michael S. Tsirkin <[email protected]>
Signed-off-by: Michael S. Tsirkin <[email protected]>
Acked-by: Luiz Capitulino <[email protected]>
Reviewed-by: Eric Blake <[email protected]>
  • Loading branch information
Nikolay Nikolaev authored and mstsirkin committed Jun 19, 2014
1 parent d314f58 commit 03ce574
Show file tree
Hide file tree
Showing 8 changed files with 159 additions and 6 deletions.
3 changes: 3 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -4515,6 +4515,9 @@ fi
if test "$vhost_scsi" = "yes" ; then
echo "CONFIG_VHOST_SCSI=y" >> $config_host_mak
fi
if test "$vhost_net" = "yes" ; then
echo "CONFIG_VHOST_NET_USED=y" >> $config_host_mak
fi
if test "$blobs" = "yes" ; then
echo "INSTALL_BLOBS=yes" >> $config_host_mak
fi
Expand Down
4 changes: 2 additions & 2 deletions hmp-commands.hx
Original file line number Diff line number Diff line change
Expand Up @@ -1211,7 +1211,7 @@ ETEXI
{
.name = "host_net_add",
.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",
.mhandler.cmd = net_host_device_add,
.command_completion = host_net_add_completion,
Expand Down Expand Up @@ -1241,7 +1241,7 @@ ETEXI
{
.name = "netdev_add",
.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",
.mhandler.cmd = hmp_netdev_add,
.command_completion = netdev_add_completion,
Expand Down
4 changes: 4 additions & 0 deletions hw/net/vhost_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "net/net.h"
#include "net/tap.h"
#include "net/vhost-user.h"

#include "hw/virtio/virtio-net.h"
#include "net/vhost_net.h"
Expand Down Expand Up @@ -360,6 +361,9 @@ VHostNetState *get_vhost_net(NetClientState *nc)
case NET_CLIENT_OPTIONS_KIND_TAP:
vhost_net = tap_get_vhost_net(nc);
break;
case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
vhost_net = vhost_user_get_vhost_net(nc);
break;
default:
break;
}
Expand Down
1 change: 1 addition & 0 deletions net/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ void net_hub_check_clients(void)
case NET_CLIENT_OPTIONS_KIND_TAP:
case NET_CLIENT_OPTIONS_KIND_SOCKET:
case NET_CLIENT_OPTIONS_KIND_VDE:
case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
has_host_dev = 1;
break;
default:
Expand Down
7 changes: 7 additions & 0 deletions net/net.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const char *host_net_devices[] = {
#ifdef CONFIG_VDE
"vde",
#endif
"vhost-user",
NULL,
};

Expand Down Expand Up @@ -802,6 +803,9 @@ static int (* const net_client_init_fun[NET_CLIENT_OPTIONS_KIND_MAX])(
[NET_CLIENT_OPTIONS_KIND_BRIDGE] = net_init_bridge,
#endif
[NET_CLIENT_OPTIONS_KIND_HUBPORT] = net_init_hubport,
#ifdef CONFIG_VHOST_NET_USED
[NET_CLIENT_OPTIONS_KIND_VHOST_USER] = net_init_vhost_user,
#endif
};


Expand Down Expand Up @@ -835,6 +839,9 @@ static int net_client_init1(const void *object, int is_netdev, Error **errp)
case NET_CLIENT_OPTIONS_KIND_BRIDGE:
#endif
case NET_CLIENT_OPTIONS_KIND_HUBPORT:
#ifdef CONFIG_VHOST_NET_USED
case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
#endif
break;

default:
Expand Down
109 changes: 106 additions & 3 deletions net/vhost-user.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "net/vhost_net.h"
#include "net/vhost-user.h"
#include "sysemu/char.h"
#include "qemu/config-file.h"
#include "qemu/error-report.h"

typedef struct VhostUserState {
Expand All @@ -21,9 +22,16 @@ typedef struct VhostUserState {
VHostNetState *vhost_net;
} VhostUserState;

typedef struct VhostUserChardevProps {
bool is_socket;
bool is_unix;
bool is_server;
} VhostUserChardevProps;

VHostNetState *vhost_user_get_vhost_net(NetClientState *nc)
{
VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc);
assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
return s->vhost_net;
}

Expand Down Expand Up @@ -82,7 +90,7 @@ static bool vhost_user_has_ufo(NetClientState *nc)
}

static NetClientInfo net_vhost_user_info = {
.type = 0,
.type = NET_CLIENT_OPTIONS_KIND_VHOST_USER,
.size = sizeof(VhostUserState),
.cleanup = vhost_user_cleanup,
.has_vnet_hdr = vhost_user_has_vnet_hdr,
Expand Down Expand Up @@ -148,8 +156,103 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
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,
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);
}
19 changes: 18 additions & 1 deletion qapi-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2068,6 +2068,22 @@
'ifname': '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
#
Expand All @@ -2086,7 +2102,8 @@
'dump': 'NetdevDumpOptions',
'bridge': 'NetdevBridgeOptions',
'hubport': 'NetdevHubPortOptions',
'netmap': 'NetdevNetmapOptions' } }
'netmap': 'NetdevNetmapOptions',
'vhost-user': 'NetdevVhostUserOptions' } }

##
# @NetLegacy
Expand Down
18 changes: 18 additions & 0 deletions qemu-options.hx
Original file line number Diff line number Diff line change
Expand Up @@ -1460,6 +1460,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
#ifdef CONFIG_NETMAP
"netmap|"
#endif
"vhost-user|"
"socket|"
"hubport],id=str[,option][,option][,...]\n", QEMU_ARCH_ALL)
STEXI
Expand Down Expand Up @@ -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
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}]
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
Expand Down

0 comments on commit 03ce574

Please sign in to comment.