@@ -158,8 +158,12 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
net->dev.nvqs = 2;
net->dev.vqs = net->vqs;
+ if (options->backend_features)
+ net->dev.backend_features = options->backend_features;
+
r = vhost_dev_init(&net->dev, options->opaque,
- options->backend_type, options->force);
+ options->backend_type, options->force,
+ options->backend_features);
if (r < 0) {
goto fail;
}
@@ -366,6 +366,17 @@ static int peer_has_ufo(VirtIONet *n)
return n->has_ufo;
}
+static uint64_t peer_backend_features(VirtIONet *n)
+{
+ if (!peer_has_vnet_hdr(n))
+ return 0;
+
+ n->backend_features =
+ qemu_backend_features(qemu_get_queue(n->nic)->peer);
+
+ return n->backend_features;
+}
+
static void virtio_net_set_mrg_rx_bufs(VirtIONet *n, int mergeable_rx_bufs)
{
int i;
@@ -463,6 +474,8 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
}
if (!get_vhost_net(nc->peer)) {
+ if (peer_backend_features(n))
+ features = peer_backend_features(n);
return features;
}
return vhost_net_get_features(get_vhost_net(nc->peer), features);
@@ -246,7 +246,7 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp)
s->dev.backend_features = 0;
ret = vhost_dev_init(&s->dev, (void *)(uintptr_t)vhostfd,
- VHOST_BACKEND_TYPE_KERNEL, true);
+ VHOST_BACKEND_TYPE_KERNEL, true, 0);
if (ret < 0) {
error_setg(errp, "vhost-scsi: vhost initialization failed: %s",
strerror(-ret));
@@ -307,6 +307,13 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
error_report("Received bad msg size.");
goto close;
}
+ if (dev->backend_features != (dev->backend_features & msg.u64)) {
+ error_report("Lack of backend features. "
+ "Expected 0x%llx, but receives 0x%lx",
+ dev->backend_features, msg.u64);
+ goto close;
+ }
+
*((__u64 *) arg) = msg.u64;
break;
case VHOST_USER_GET_VRING_BASE:
@@ -811,7 +811,8 @@ static void vhost_virtqueue_cleanup(struct vhost_virtqueue *vq)
}
int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
- VhostBackendType backend_type, bool force)
+ VhostBackendType backend_type, bool force,
+ unsigned long long backend_features)
{
uint64_t features;
int i, r;
@@ -833,7 +834,9 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
r = hdev->vhost_ops->vhost_call(hdev, VHOST_GET_FEATURES, &features);
if (r < 0) {
- goto fail;
+ if (backend_features == 0)
+ goto fail;
+ features = backend_features;
}
for (i = 0; i < hdev->nvqs; ++i) {
@@ -55,7 +55,8 @@ struct vhost_dev {
};
int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
- VhostBackendType backend_type, bool force);
+ VhostBackendType backend_type, bool force,
+ unsigned long long backend_features);
void vhost_dev_cleanup(struct vhost_dev *hdev);
bool vhost_dev_query(struct vhost_dev *hdev, VirtIODevice *vdev);
int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev);
@@ -70,6 +70,7 @@ typedef struct VirtIONet {
size_t guest_hdr_len;
uint32_t host_features;
uint8_t has_ufo;
+ uint64_t backend_features;
int mergeable_rx_bufs;
uint8_t promisc;
uint8_t allmulti;
@@ -55,6 +55,7 @@ typedef bool (HasVnetHdrLen)(NetClientState *, int);
typedef void (UsingVnetHdr)(NetClientState *, bool);
typedef void (SetOffload)(NetClientState *, int, int, int, int, int);
typedef void (SetVnetHdrLen)(NetClientState *, int);
+typedef unsigned long long (BackendFeatures)(NetClientState *);
typedef struct NetClientInfo {
NetClientOptionsKind type;
@@ -73,6 +74,7 @@ typedef struct NetClientInfo {
UsingVnetHdr *using_vnet_hdr;
SetOffload *set_offload;
SetVnetHdrLen *set_vnet_hdr_len;
+ BackendFeatures *backend_features;
} NetClientInfo;
struct NetClientState {
@@ -136,6 +138,7 @@ bool qemu_has_ufo(NetClientState *nc);
bool qemu_has_vnet_hdr(NetClientState *nc);
bool qemu_has_vnet_hdr_len(NetClientState *nc, int len);
void qemu_using_vnet_hdr(NetClientState *nc, bool enable);
+unsigned long long qemu_backend_features(NetClientState *nc);
void qemu_set_offload(NetClientState *nc, int csum, int tso4, int tso6,
int ecn, int ufo);
void qemu_set_vnet_hdr_len(NetClientState *nc, int len);
@@ -12,6 +12,7 @@ typedef struct VhostNetOptions {
NetClientState *net_backend;
void *opaque;
bool force;
+ unsigned long long backend_features;
} VhostNetOptions;
struct vhost_net *vhost_net_init(VhostNetOptions *options);
@@ -510,6 +510,15 @@ void qemu_set_vnet_hdr_len(NetClientState *nc, int len)
nc->info->set_vnet_hdr_len(nc, len);
}
+unsigned long long qemu_backend_features(NetClientState *nc)
+{
+ if (!nc || !nc->info->backend_features) {
+ return false;
+ }
+
+ return nc->info->backend_features(nc);
+}
+
int qemu_can_send_packet(NetClientState *sender)
{
int vm_running = runstate_is_running();
@@ -656,6 +656,7 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
options.backend_type = VHOST_BACKEND_TYPE_KERNEL;
options.net_backend = &s->nc;
options.force = tap->has_vhostforce && tap->vhostforce;
+ options.backend_features = tap->backend_features;
if (tap->has_vhostfd || tap->has_vhostfds) {
vhostfd = monitor_fd_param(cur_mon, vhostfdname, &err);
@@ -8,6 +8,8 @@
*
*/
+#include <linux/virtio_net.h>
+
#include "clients.h"
#include "net/vhost_net.h"
#include "net/vhost-user.h"
@@ -19,6 +21,7 @@ typedef struct VhostUserState {
NetClientState nc;
CharDriverState *chr;
VHostNetState *vhost_net;
+ unsigned long long backend_features;
int watch;
} VhostUserState;
@@ -54,6 +57,7 @@ static int vhost_user_start(VhostUserState *s)
options.net_backend = &s->nc;
options.opaque = s->chr;
options.force = true;
+ options.backend_features = s->backend_features;
s->vhost_net = vhost_net_init(&options);
@@ -91,12 +95,22 @@ static bool vhost_user_has_ufo(NetClientState *nc)
return true;
}
+static unsigned long long vhost_user_backend_features(NetClientState *nc)
+{
+ assert(nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
+
+ VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc);
+
+ return s->backend_features;
+}
+
static NetClientInfo net_vhost_user_info = {
.type = NET_CLIENT_OPTIONS_KIND_VHOST_USER,
.size = sizeof(VhostUserState),
.cleanup = vhost_user_cleanup,
.has_vnet_hdr = vhost_user_has_vnet_hdr,
.has_ufo = vhost_user_has_ufo,
+ .backend_features = vhost_user_backend_features,
};
static void net_vhost_link_down(VhostUserState *s, bool link_down)
@@ -148,7 +162,8 @@ static void net_vhost_user_event(void *opaque, int event)
}
static int net_vhost_user_init(NetClientState *peer, const char *device,
- const char *name, CharDriverState *chr)
+ const char *name, CharDriverState *chr,
+ unsigned long long backend_features)
{
NetClientState *nc;
VhostUserState *s;
@@ -163,6 +178,7 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
/* We don't provide a receive callback */
s->nc.receive_disabled = 1;
s->chr = chr;
+ s->backend_features = backend_features;
qemu_chr_add_handlers(s->chr, NULL, NULL, net_vhost_user_event, s);
@@ -242,12 +258,38 @@ static int net_vhost_check_net(QemuOpts *opts, void *opaque)
return 0;
}
+static inline unsigned long long
+net_get_vhost_backend_features(const NetdevVhostUserOptions *opts)
+{
+ return (opts->backend_csum ? 1 << VIRTIO_NET_F_CSUM : 0) |
+ (opts->backend_guest_csum ? 1 << VIRTIO_NET_F_GUEST_CSUM : 0) |
+ (opts->backend_gso ? 1 << VIRTIO_NET_F_GSO : 0) |
+ (opts->backend_guest_tso4 ? 1 << VIRTIO_NET_F_GUEST_TSO4 : 0) |
+ (opts->backend_guest_tso6 ? 1 << VIRTIO_NET_F_GUEST_TSO6 : 0) |
+ (opts->backend_guest_ecn ? 1 << VIRTIO_NET_F_GUEST_ECN : 0) |
+ (opts->backend_guest_ufo ? 1 << VIRTIO_NET_F_GUEST_UFO : 0) |
+ (opts->backend_guest_announce ? 1 << VIRTIO_NET_F_GUEST_ANNOUNCE : 0) |
+ (opts->backend_host_tso4 ? 1 << VIRTIO_NET_F_HOST_TSO4 : 0) |
+ (opts->backend_host_tso6 ? 1 << VIRTIO_NET_F_HOST_TSO6 : 0) |
+ (opts->backend_host_ecn ? 1 << VIRTIO_NET_F_HOST_ECN : 0) |
+ (opts->backend_host_ufo ? 1 << VIRTIO_NET_F_HOST_UFO : 0) |
+ (opts->backend_mrg_rxbuf ? 1 << VIRTIO_NET_F_MRG_RXBUF : 0) |
+ (opts->backend_status ? 1 << VIRTIO_NET_F_STATUS : 0) |
+ (opts->backend_ctrl_vq ? 1 << VIRTIO_NET_F_CTRL_VQ : 0) |
+ (opts->backend_ctrl_rx ? 1 << VIRTIO_NET_F_CTRL_RX : 0) |
+ (opts->backend_ctrl_vlan ? 1 << VIRTIO_NET_F_CTRL_VLAN : 0) |
+ (opts->backend_ctrl_rx_extra ? 1 << VIRTIO_NET_F_CTRL_RX_EXTRA : 0) |
+ (opts->backend_ctrl_mac_addr ? 1 << VIRTIO_NET_F_CTRL_MAC_ADDR : 0) |
+ (opts->backend_mq ? 1 << VIRTIO_NET_F_MQ : 0);
+}
+
int net_init_vhost_user(const NetClientOptions *opts, const char *name,
NetClientState *peer, Error **errp)
{
/* FIXME error_setg(errp, ...) on failure */
const NetdevVhostUserOptions *vhost_user_opts;
CharDriverState *chr;
+ unsigned long long backend_features;
assert(opts->kind == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
vhost_user_opts = opts->vhost_user;
@@ -264,6 +306,9 @@ int net_init_vhost_user(const NetClientOptions *opts, const char *name,
return -1;
}
+ /* backend features */
+ backend_features = net_get_vhost_backend_features(vhost_user_opts);
- return net_vhost_user_init(peer, "vhost_user", name, chr);
+ return net_vhost_user_init(peer, "vhost_user", name, chr,
+ backend_features);
}
@@ -2241,25 +2241,29 @@
#
# @vhostforce: #optional vhost on for non-MSIX virtio guests
#
+# @backend_features: #optional feature flag to support vhost user backend
+# (Since 2.4)
+#
# @queues: #optional number of queues to be created for multiqueue capable tap
#
# Since 1.2
##
{ 'struct': 'NetdevTapOptions',
'data': {
- '*ifname': 'str',
- '*fd': 'str',
- '*fds': 'str',
- '*script': 'str',
- '*downscript': 'str',
- '*helper': 'str',
- '*sndbuf': 'size',
- '*vnet_hdr': 'bool',
- '*vhost': 'bool',
- '*vhostfd': 'str',
- '*vhostfds': 'str',
- '*vhostforce': 'bool',
- '*queues': 'uint32'} }
+ '*ifname': 'str',
+ '*fd': 'str',
+ '*fds': 'str',
+ '*script': 'str',
+ '*downscript': 'str',
+ '*helper': 'str',
+ '*sndbuf': 'size',
+ '*vnet_hdr': 'bool',
+ '*vhost': 'bool',
+ '*vhostfd': 'str',
+ '*vhostfds': 'str',
+ '*vhostforce': 'bool',
+ '*backend_features': 'uint64',
+ '*queues': 'uint32'} }
##
# @NetdevSocketOptions
@@ -2444,12 +2448,92 @@
#
# @vhostforce: #optional vhost on for non-MSIX virtio guests (default: false).
#
+# @backend_csum: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_guest_csum: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_gso: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_guest_tso4: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_guest_tso6: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_guest_ecn: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_guest_ufo: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_guest_announce: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_host_tso4: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_host_tso6: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_host_ecn: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_host_ufo: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_mrg_rxbuf: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_status: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_ctrl_vq: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_ctrl_rx: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_ctrl_vlan: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_ctrl_rx_extra: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_ctrl_mac_addr: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
+# @backend_mq: #optional feature backend supports (default: false).
+# (Since 2.4)
+#
# Since 2.1
##
{ 'struct': 'NetdevVhostUserOptions',
'data': {
- 'chardev': 'str',
- '*vhostforce': 'bool' } }
+ 'chardev': 'str',
+ '*vhostforce': 'bool',
+ '*backend_csum': 'bool',
+ '*backend_guest_csum': 'bool',
+ '*backend_gso': 'bool',
+ '*backend_guest_tso4': 'bool',
+ '*backend_guest_tso6': 'bool',
+ '*backend_guest_ecn': 'bool',
+ '*backend_guest_ufo': 'bool',
+ '*backend_guest_announce': 'bool',
+ '*backend_host_tso4': 'bool',
+ '*backend_host_tso6': 'bool',
+ '*backend_host_ecn': 'bool',
+ '*backend_host_ufo': 'bool',
+ '*backend_mrg_rxbuf': 'bool',
+ '*backend_status': 'bool',
+ '*backend_ctrl_vq': 'bool',
+ '*backend_ctrl_rx': 'bool',
+ '*backend_ctrl_vlan': 'bool',
+ '*backend_ctrl_rx_extra': 'bool',
+ '*backend_ctrl_mac_addr': 'bool',
+ '*backend_mq': 'bool' } }
##
# @NetClientOptions
@@ -1467,6 +1467,15 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
"-netdev tap,id=str[,fd=h][,fds=x:y:...:z][,ifname=name][,script=file][,downscript=dfile]\n"
" [,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off]\n"
" [,vhostfd=h][,vhostfds=x:y:...:z][,vhostforce=on|off][,queues=n]\n"
+ " [,backend_csum=on|off][,backend_guest_csum=on|off][,backend_gso=on|off]\n"
+ " [,backend_guest_tso4=on|off][,backend_guest_tso6=on|off]\n"
+ " [,backend_guest_ecn=on|off][,backend_guest_ufo=on|off]\n"
+ " [,backend_guest_announce=on|off][,backend_host_tso4=on|off]\n"
+ " [,backend_host_tso6=on|off][,backend_host_ecn=on|off]\n"
+ " [,backend_host_ufo=on|off][,backend_mrg_rxbuf=on|off][,backend_status=on|off]\n"
+ " [,backend_ctrl_vq=on|off][,backend_ctrl_vx=on|off][,backend_ctrl_vlan=on|off]\n"
+ " [,backend_ctrl_rx_extra=on|off][,backend_ctrl_mac_addr=on|off]\n"
+ " [,backend_ctrl_guest_offloads=on|off][,backend_mq=on|off]\n"
" configure a host TAP network backend with ID 'str'\n"
" use network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n"
" to configure it and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n"
@@ -1486,6 +1495,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
" use 'vhostfd=h' to connect to an already opened vhost net device\n"
" use 'vhostfds=x:y:...:z to connect to multiple already opened vhost net devices\n"
" use 'queues=n' to specify the number of queues to be created for multiqueue TAP\n"
+ " use 'backend_*=on' to specify virtio-net feature that vhost-user backend supports\n"
"-netdev bridge,id=str[,br=bridge][,helper=helper]\n"
" configure a host TAP network backend with ID 'str' that is\n"
" connected to a bridge (default=" DEFAULT_BRIDGE_INTERFACE ")\n"
This patch adds below '-net' options to let QEMU know which features vhost-user backend will support. [,backend_csum=on|off] [,backend_guest_csum=on|off] [,backend_gso=on|off] [,backend_guest_tso4=on|off] [,backend_guest_tso6=on|off] [,backend_guest_ecn=on|off] [,backend_guest_ufo=on|off] [,backend_guest_announce=on|off] [,backend_host_tso4=on|off] [,backend_host_tso6=on|off] [,backend_host_ecn=on|off] [,backend_host_ufo=on|off] [,backend_mrg_rxbuf=on|off] [,backend_status=on|off] [,backend_ctrl_vq=on|off] [,backend_ctrl_vx=on|off] [,backend_ctrl_vlan=on|off] [,backend_ctrl_rx_extra=on|off] [,backend_ctrl_mac_addr=on|off] [,backend_ctrl_guest_offloads=on|off] [,backend_mq=on|off] If above features are specified, QEMU assumes vhost-user backend supports the features, then QEMU can start without vhost-user backend connection. (While no connection, link status of virtio-net device will be down) Here are examples. * QEMU is configured as vhost-user client. -chardev socket,id=chr0,path=/tmp/sock,reconnect=3 \ -netdev vhost-user,id=net0,chardev=chr0,vhostforce,backend_mrg_rxbuf \ -device virtio-net-pci,netdev=net0 \ * QEMU is configured as vhost-user server. -chardev socket,id=chr0,path=/tmp/sock,server,nowait \ -netdev vhost-user,id=net0,chardev=chr0,vhostforce,backend_mrg_rxbuf \ -device virtio-net-pci,netdev=net0 \ Above cases, QEMU assumes vhost-user backend will support VIRTIO_NET_F_MRG_RXBUF feature defined in linux/virtio_net.h When connection between QEMU and the backend is established, QEMU checkes feature values of the backend to make sure the expected features are provided. If it doesn't, the connection will be closed by QEMU. Signed-off-by: Tetsuya Mukawa <mukawa@igel.co.jp> --- hw/net/vhost_net.c | 6 ++- hw/net/virtio-net.c | 13 +++++ hw/scsi/vhost-scsi.c | 2 +- hw/virtio/vhost-user.c | 7 +++ hw/virtio/vhost.c | 7 ++- include/hw/virtio/vhost.h | 3 +- include/hw/virtio/virtio-net.h | 1 + include/net/net.h | 3 ++ include/net/vhost_net.h | 1 + net/net.c | 9 ++++ net/tap.c | 1 + net/vhost-user.c | 49 +++++++++++++++++- qapi-schema.json | 114 +++++++++++++++++++++++++++++++++++------ qemu-options.hx | 10 ++++ 14 files changed, 204 insertions(+), 22 deletions(-)