This patch adds 'backend_features' option for vhost-user backends. If this option is specified, QEMU assumes vhost-user backends support the features specified by user, and QEMU can start without vhost-user backend.
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-features=0x68000 \ -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-features=0x68000 \ -device virtio-net-pci,netdev=net0 \ To know vhost-user backend features that the backend expects, please specify 0xffffffff as backend-features, then invoke QEMU and check error log like below. Lack of backend features. Expected 0xffffffff, but receives 0x68000 Above log indicates the backend features QEMU should be passed. Signed-off-by: Tetsuya Mukawa <muk...@igel.co.jp> --- hw/net/vhost_net.c | 6 +++++- hw/net/virtio-net.c | 15 +++++++++++++++ hw/scsi/vhost-scsi.c | 2 +- hw/virtio/vhost-user.c | 6 ++++++ hw/virtio/vhost.c | 3 ++- 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 | 19 +++++++++++++++++-- qapi-schema.json | 12 ++++++++++-- qemu-options.hx | 3 ++- 14 files changed, 75 insertions(+), 9 deletions(-) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 9bd360b..b9425ea 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -162,8 +162,12 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options) net->dev.vqs = net->vqs; net->dev.vq_index = net->nc->queue_index; + if (options->backend_features) { + net->dev.backend_features = options->backend_features; + } + r = vhost_dev_init(&net->dev, options->opaque, - options->backend_type); + options->backend_type, options->backend_features); if (r < 0) { goto fail; } diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index d728233..7138f4e 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -363,6 +363,18 @@ 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 version_1) { @@ -467,6 +479,9 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features) if (!get_vhost_net(nc->peer)) { virtio_add_feature(&features, VIRTIO_F_VERSION_1); + if (peer_backend_features(n)) { + features = peer_backend_features(n); + } return features; } return vhost_net_get_features(get_vhost_net(nc->peer), features); diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 1c389c4..1d7957c 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -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); + VHOST_BACKEND_TYPE_KERNEL, 0); if (ret < 0) { error_setg(errp, "vhost-scsi: vhost initialization failed: %s", strerror(-ret)); diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 2215c39..3caa1a0 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -315,6 +315,12 @@ 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%" PRIx64, + dev->backend_features, msg.u64); + goto close; + } *((__u64 *) arg) = msg.u64; break; case VHOST_USER_GET_VRING_BASE: diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index a6dcc79..bbfc336 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -901,7 +901,8 @@ static void vhost_virtqueue_cleanup(struct vhost_virtqueue *vq) } int vhost_dev_init(struct vhost_dev *hdev, void *opaque, - VhostBackendType backend_type) + VhostBackendType backend_type, + unsigned long long backend_features) { uint64_t features; int i, r; diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index dd51050..074b36b 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -60,7 +60,8 @@ struct vhost_dev { }; int vhost_dev_init(struct vhost_dev *hdev, void *opaque, - VhostBackendType backend_type); + VhostBackendType backend_type, + 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); diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index 280dacf..871dc3c 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -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; diff --git a/include/net/net.h b/include/net/net.h index 4306252..d4379d1 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -57,6 +57,7 @@ typedef void (SetOffload)(NetClientState *, int, int, int, int, int); typedef void (SetVnetHdrLen)(NetClientState *, int); typedef int (SetVnetLE)(NetClientState *, bool); typedef int (SetVnetBE)(NetClientState *, bool); +typedef unsigned long long (BackendFeatures)(NetClientState *); typedef struct NetClientInfo { NetClientOptionsKind type; @@ -77,6 +78,7 @@ typedef struct NetClientInfo { SetVnetHdrLen *set_vnet_hdr_len; SetVnetLE *set_vnet_le; SetVnetBE *set_vnet_be; + BackendFeatures *backend_features; } NetClientInfo; struct NetClientState { @@ -140,6 +142,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); diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h index 840d4b1..0b19b4a 100644 --- a/include/net/vhost_net.h +++ b/include/net/vhost_net.h @@ -11,6 +11,7 @@ typedef struct VhostNetOptions { VhostBackendType backend_type; NetClientState *net_backend; void *opaque; + unsigned long long backend_features; } VhostNetOptions; struct vhost_net *vhost_net_init(VhostNetOptions *options); diff --git a/net/net.c b/net/net.c index 6dbd61a..4ad7a69 100644 --- a/net/net.c +++ b/net/net.c @@ -528,6 +528,15 @@ int qemu_set_vnet_be(NetClientState *nc, bool is_be) return nc->info->set_vnet_be(nc, is_be); } +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(); diff --git a/net/tap.c b/net/tap.c index bd01590..743c168 100644 --- a/net/tap.c +++ b/net/tap.c @@ -662,6 +662,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.backend_features = tap->backend_features; if (tap->has_vhostfd || tap->has_vhostfds) { vhostfd = monitor_fd_param(cur_mon, vhostfdname, &err); diff --git a/net/vhost-user.c b/net/vhost-user.c index 58cd5dc..fd46e32 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -19,6 +19,7 @@ typedef struct VhostUserState { NetClientState nc; CharDriverState *chr; VHostNetState *vhost_net; + unsigned long long backend_features; int watch; } VhostUserState; @@ -53,6 +54,7 @@ static int vhost_user_start(VhostUserState *s) options.backend_type = VHOST_BACKEND_TYPE_USER; options.net_backend = &s->nc; options.opaque = s->chr; + options.backend_features = s->backend_features; s->vhost_net = vhost_net_init(&options); @@ -90,12 +92,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) @@ -152,7 +164,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, - uint32_t queues) + uint32_t queues, + unsigned long long backend_features) { NetClientState *nc; VhostUserState *s; @@ -170,6 +183,7 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, s->nc.receive_disabled = 1; s->chr = chr; s->nc.queue_index = i; + s->backend_features = backend_features; qemu_chr_add_handlers(s->chr, NULL, NULL, net_vhost_user_event, s); } @@ -279,5 +293,6 @@ int net_init_vhost_user(const NetClientOptions *opts, const char *name, queues = 1; } - return net_vhost_user_init(peer, "vhost_user", name, chr, queues); + return net_vhost_user_init(peer, "vhost_user", name, chr, queues, + vhost_user_opts->backend_features); } diff --git a/qapi-schema.json b/qapi-schema.json index 106008c..88760e5 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2262,6 +2262,9 @@ # # @queues: #optional number of queues to be created for multiqueue capable tap # +# @backend-features: #optional feature flag to support vhost user backend +# (since 2.4) +# # Since 1.2 ## { 'struct': 'NetdevTapOptions', @@ -2278,7 +2281,8 @@ '*vhostfd': 'str', '*vhostfds': 'str', '*vhostforce': 'bool', - '*queues': 'uint32'} } + '*queues': 'uint32', + '*backend-features':'uint64'} } ## # @NetdevSocketOptions @@ -2466,13 +2470,17 @@ # @queues: #optional number of queues to be created for multiqueue vhost-user # (default: 1) (Since 2.4) # +# @backend-features: #optional feature flag to support vhost user backend +# (default: 0) (since 2.4) +# # Since 2.1 ## { 'struct': 'NetdevVhostUserOptions', 'data': { 'chardev': 'str', '*vhostforce': 'bool', - '*queues': 'uint32' } } + '*queues': 'uint32', + '*backend-features': 'uint64' } } ## # @NetClientOptions diff --git a/qemu-options.hx b/qemu-options.hx index 7959dd0..69f13c2 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1473,7 +1473,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, #else "-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" + " [,vhostfd=h][,vhostfds=x:y:...:z][,vhostforce=on|off][,queues=n][,backend-features=n]\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" @@ -1493,6 +1493,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-features=n' to specify the features that vhost backend supported\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" -- 2.1.4