diff mbox

[v1,4/4] vhost-user: Add new option to specify vhost-user backend features

Message ID 1432874550-10921-5-git-send-email-mukawa@igel.co.jp
State Superseded
Headers show

Commit Message

Tetsuya Mukawa May 29, 2015, 4:42 a.m. UTC
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(-)

Comments

Stefan Hajnoczi June 15, 2015, 1:58 p.m. UTC | #1
On Fri, May 29, 2015 at 01:42:30PM +0900, Tetsuya Mukawa wrote:
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index 3af6faf..7fbb306 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -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;

QEMU coding style always uses {} even for single statement if bodies:

if (!peer_has_vnet_hdr(n)) {
    return 0;
}

> diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
> index 4d7e3ba..d847ea5 100644
> --- a/hw/virtio/vhost-user.c
> +++ b/hw/virtio/vhost-user.c
> @@ -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",

Please use PRIx64 for msg.u64 to avoid compiler errors on 32-bit hosts.

> +                                 dev->backend_features, msg.u64);
> +                    goto close;

QEMU uses 4-space indentation.
Tetsuya Mukawa June 16, 2015, 5:08 a.m. UTC | #2
On 2015/06/15 22:58, Stefan Hajnoczi wrote:
> On Fri, May 29, 2015 at 01:42:30PM +0900, Tetsuya Mukawa wrote:
>> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
>> index 3af6faf..7fbb306 100644
>> --- a/hw/net/virtio-net.c
>> +++ b/hw/net/virtio-net.c
>> @@ -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;
> QEMU coding style always uses {} even for single statement if bodies:
>
> if (!peer_has_vnet_hdr(n)) {
>     return 0;
> }
>
>> diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
>> index 4d7e3ba..d847ea5 100644
>> --- a/hw/virtio/vhost-user.c
>> +++ b/hw/virtio/vhost-user.c
>> @@ -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",
> Please use PRIx64 for msg.u64 to avoid compiler errors on 32-bit hosts.
>> +                                 dev->backend_features, msg.u64);
>> +                    goto close;
> QEMU uses 4-space indentation.

I will fix above 3 issues in next patches.

Regards,
Tetsuya
Eric Blake June 16, 2015, 12:27 p.m. UTC | #3
On 05/28/2015 10:42 PM, Tetsuya Mukawa wrote:
> This patch adds below '-net' options to let QEMU know which features
> vhost-user backend will support.

[meta-comment: when posting a new revision of a series, do it as a new
top-level thread rather than buried in-reply-to an earlier version]

> 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)
> 

> 
> When connection between QEMU and the backend is established, QEMU checkes feature

s/checkes/checks/

> 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>
> ---

> +++ b/qapi-schema.json
> @@ -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)
> +#

s/backend_features/backend-features/

(we document that qapi should prefer - over _ unless there is a
consistency issue with _ already used in the struct)


> @@ -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)

Again, s/_/-/ throughout this struct.

> +#
> +# @backend_mq: #optional feature backend supports (default: false).
> +#              (Since 2.4)

A lot of identical descriptions. Might be worth more specific text to
each option; for example,
 @backend_mq: #optional: True if backend supports multiqueue feature
(default: false). (Since 2.4)


> +++ b/qemu-options.hx
> @@ -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"

Bikeshedding: Rather than having a lot of booleans, I wonder if it would
be better to have an array of flag names.  That is, in QMP form, this
would select three features (and leave the others off)

'backend-features':[ 'csum', 'guest-csum', gso' ]

although I'm not sure on how that would best translate to the command line.
Tetsuya Mukawa June 17, 2015, 9:29 a.m. UTC | #4
On 2015/06/16 21:27, Eric Blake wrote:
> On 05/28/2015 10:42 PM, Tetsuya Mukawa wrote:
>> This patch adds below '-net' options to let QEMU know which features
>> vhost-user backend will support.
> [meta-comment: when posting a new revision of a series, do it as a new
> top-level thread rather than buried in-reply-to an earlier version]

Hi Eric,

Thanks for comments.
Yes, I will follow like above in next patches.

>> 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)
>>
>> When connection between QEMU and the backend is established, QEMU checkes feature
> s/checkes/checks/
>
>> 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>
>> ---
>> +++ b/qapi-schema.json
>> @@ -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)
>> +#
> s/backend_features/backend-features/
>
> (we document that qapi should prefer - over _ unless there is a
> consistency issue with _ already used in the struct)
>
>
>> @@ -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)
> Again, s/_/-/ throughout this struct.

I will use '-' instead of '_'. Also will fix typo.

>> +#
>> +# @backend_mq: #optional feature backend supports (default: false).
>> +#              (Since 2.4)
> A lot of identical descriptions. Might be worth more specific text to
> each option; for example,
>  @backend_mq: #optional: True if backend supports multiqueue feature
> (default: false). (Since 2.4)
>

Sure I will add short descriptions, if we use this kind of command options.

>> +++ b/qemu-options.hx
>> @@ -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"
> Bikeshedding: Rather than having a lot of booleans, I wonder if it would
> be better to have an array of flag names.  That is, in QMP form, this
> would select three features (and leave the others off)
>
> 'backend-features':[ 'csum', 'guest-csum', gso' ]
>
> although I'm not sure on how that would best translate to the command line.
>

One more suggestion is here.
https://lists.gnu.org/archive/html/qemu-devel/2015-06/msg03807.html

I am also not sure what is best. But I guess above explanation is
reasonable at this time.
When we find a case that user needs to describe or change
backend-features frequently by hand, expand backend-features and add
these human readable options.

Regards,
Tetsuya
diff mbox

Patch

diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index 47f8b89..8799c75 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -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;
     }
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 3af6faf..7fbb306 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -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);
diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
index 335f442..25fae56 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, true);
+                         VHOST_BACKEND_TYPE_KERNEL, true, 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 4d7e3ba..d847ea5 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -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:
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 54851b7..0663aed 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -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) {
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index 8f04888..b75ed70 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -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);
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index e0dbb41..3edd175 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 e66ca03..16b855e 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -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);
diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h
index b1c18a3..ca6c5ab 100644
--- a/include/net/vhost_net.h
+++ b/include/net/vhost_net.h
@@ -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);
diff --git a/net/net.c b/net/net.c
index db6be12..7415eb2 100644
--- a/net/net.c
+++ b/net/net.c
@@ -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();
diff --git a/net/tap.c b/net/tap.c
index d1ca314..f2ba94d 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -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);
diff --git a/net/vhost-user.c b/net/vhost-user.c
index f823d78..6474a31 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -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);
 }
diff --git a/qapi-schema.json b/qapi-schema.json
index f97ffa1..1e868a9 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -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
diff --git a/qemu-options.hx b/qemu-options.hx
index 88d7661..133dc99 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -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"