On Thu, Jan 9, 2014 at 5:14 PM, Michael S. Tsirkin <m...@redhat.com> wrote:

> On Thu, Jan 09, 2014 at 04:00:00PM +0100, Antonios Motakis wrote:
> > Add a new QEMU netdev backend that is intended to invoke vhost_net
> > with the vhost-user backend. Also decouple virtio-net from the tap
> > backend.
> >
> > Signed-off-by: Antonios Motakis <a.mota...@virtualopensystems.com>
> > Signed-off-by: Nikolay Nikolaev <n.nikol...@virtualopensystems.com>
> > ---
> >  hmp-commands.hx          |   4 +-
> >  hw/net/vhost_net.c       |  66 ++++++++++++++++++++++------
> >  hw/net/virtio-net.c      |  42 ++++++++----------
> >  hw/virtio/vhost.c        |   1 -
> >  include/net/vhost-user.h |  17 ++++++++
> >  include/net/vhost_net.h  |   1 +
> >  net/Makefile.objs        |   2 +-
> >  net/clients.h            |   3 ++
> >  net/hub.c                |   1 +
> >  net/net.c                |   2 +
> >  net/vhost-user.c         | 111
> +++++++++++++++++++++++++++++++++++++++++++++++
> >  qapi-schema.json         |  18 +++++++-
> >  qemu-options.hx          |   3 ++
> >  13 files changed, 227 insertions(+), 44 deletions(-)
> >  create mode 100644 include/net/vhost-user.h
> >  create mode 100644 net/vhost-user.c
> >
> > diff --git a/hmp-commands.hx b/hmp-commands.hx
> > index ebe8e78..d5a3774 100644
> > --- a/hmp-commands.hx
> > +++ b/hmp-commands.hx
> > @@ -1190,7 +1190,7 @@ ETEXI
> >      {
> >          .name       = "host_net_add",
> >          .args_type  = "device:s,opts:s?",
> > -        .params     = "tap|user|socket|vde|netmap|dump [options]",
> > +        .params     = "tap|user|socket|vde|netmap|vhost-user|dump
> [options]",
> >          .help       = "add host VLAN client",
> >          .mhandler.cmd = net_host_device_add,
> >      },
> > @@ -1218,7 +1218,7 @@ ETEXI
> >      {
> >          .name       = "netdev_add",
> >          .args_type  = "netdev:O",
> > -        .params     =
> "[user|tap|socket|hubport|netmap],id=str[,prop=value][,...]",
> > +        .params     =
> "[user|tap|socket|hubport|netmap|vhost-user],id=str[,prop=value][,...]",
> >          .help       = "add host network device",
> >          .mhandler.cmd = hmp_netdev_add,
> >      },
> > diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
> > index 3614e6c..e42f4d6 100644
> > --- a/hw/net/vhost_net.c
> > +++ b/hw/net/vhost_net.c
> > @@ -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"
> > @@ -174,15 +175,20 @@ static int vhost_net_start_one(struct vhost_net
> *net,
> >          goto fail_start;
> >      }
> >
> > -    net->nc->info->poll(net->nc, false);
> > -    qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
> > -    file.fd = net->backend;
> > -    for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
> > -        const VhostOps *vhost_ops = net->dev.vhost_ops;
> > -        r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND,
> &file);
> > -        if (r < 0) {
> > -            r = -errno;
> > -            goto fail;
> > +    if (net->nc->info->poll) {
> > +        net->nc->info->poll(net->nc, false);
> > +    }
> > +
> > +    if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
> > +        qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
> > +        file.fd = net->backend;
> > +        for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
> > +            const VhostOps *vhost_ops = net->dev.vhost_ops;
> > +            r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND,
> &file);
> > +            if (r < 0) {
> > +                r = -errno;
> > +                goto fail;
> > +            }
> >          }
> >      }
> >      return 0;
> > @@ -193,7 +199,9 @@ fail:
> >          int r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND,
> &file);
> >          assert(r >= 0);
> >      }
> > -    net->nc->info->poll(net->nc, true);
> > +    if (net->nc->info->poll) {
> > +        net->nc->info->poll(net->nc, true);
> > +    }
> >      vhost_dev_stop(&net->dev, dev);
> >  fail_start:
> >      vhost_dev_disable_notifiers(&net->dev, dev);
> > @@ -215,7 +223,9 @@ static void vhost_net_stop_one(struct vhost_net *net,
> >          int r = vhost_ops->vhost_call(&net->dev, VHOST_NET_SET_BACKEND,
> &file);
> >          assert(r >= 0);
> >      }
> > -    net->nc->info->poll(net->nc, true);
> > +    if (net->nc->info->poll) {
> > +        net->nc->info->poll(net->nc, true);
> > +    }
> >      vhost_dev_stop(&net->dev, dev);
> >      vhost_dev_disable_notifiers(&net->dev, dev);
> >  }
> > @@ -235,7 +245,7 @@ int vhost_net_start(VirtIODevice *dev,
> NetClientState *ncs,
> >      }
> >
> >      for (i = 0; i < total_queues; i++) {
> > -        r = vhost_net_start_one(tap_get_vhost_net(ncs[i].peer), dev, i
> * 2);
> > +        r = vhost_net_start_one(get_vhost_net(ncs[i].peer), dev, i * 2);
> >
> >          if (r < 0) {
> >              goto err;
> > @@ -252,7 +262,7 @@ int vhost_net_start(VirtIODevice *dev,
> NetClientState *ncs,
> >
> >  err:
> >      while (--i >= 0) {
> > -        vhost_net_stop_one(tap_get_vhost_net(ncs[i].peer), dev);
> > +        vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
> >      }
> >      return r;
> >  }
> > @@ -273,7 +283,7 @@ void vhost_net_stop(VirtIODevice *dev,
> NetClientState *ncs,
> >      assert(r >= 0);
> >
> >      for (i = 0; i < total_queues; i++) {
> > -        vhost_net_stop_one(tap_get_vhost_net(ncs[i].peer), dev);
> > +        vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
> >      }
> >  }
> >
> > @@ -293,6 +303,29 @@ void vhost_net_virtqueue_mask(VHostNetState *net,
> VirtIODevice *dev,
> >  {
> >      vhost_virtqueue_mask(&net->dev, dev, idx, mask);
> >  }
> > +
> > +VHostNetState *get_vhost_net(NetClientState *nc)
> > +{
> > +    VHostNetState *vhost_net = 0;
> > +
> > +    if (!nc) {
> > +        return 0;
> > +    }
> > +
> > +    switch (nc->info->type) {
> > +    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;
> > +    }
> > +
> > +    return vhost_net;
> > +}
> > +
> >  #else
> >  struct vhost_net *vhost_net_init(VhostNetOptions *options)
> >  {
> > @@ -338,4 +371,9 @@ void vhost_net_virtqueue_mask(VHostNetState *net,
> VirtIODevice *dev,
> >                                int idx, bool mask)
> >  {
> >  }
> > +
> > +VHostNetState *get_vhost_net(NetClientState *nc)
> > +{
> > +    return 0;
> > +}
> >  #endif
> > diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> > index 3626608..d49ee82 100644
> > --- a/hw/net/virtio-net.c
> > +++ b/hw/net/virtio-net.c
> > @@ -105,14 +105,7 @@ static void virtio_net_vhost_status(VirtIONet *n,
> uint8_t status)
> >      NetClientState *nc = qemu_get_queue(n->nic);
> >      int queues = n->multiqueue ? n->max_queues : 1;
> >
> > -    if (!nc->peer) {
> > -        return;
> > -    }
> > -    if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
> > -        return;
> > -    }
> > -
> > -    if (!tap_get_vhost_net(nc->peer)) {
> > +    if (!get_vhost_net(nc->peer)) {
> >          return;
> >      }
> >
> > @@ -122,7 +115,7 @@ static void virtio_net_vhost_status(VirtIONet *n,
> uint8_t status)
> >      }
> >      if (!n->vhost_started) {
> >          int r;
> > -        if (!vhost_net_query(tap_get_vhost_net(nc->peer), vdev)) {
> > +        if (!vhost_net_query(get_vhost_net(nc->peer), vdev)) {
> >              return;
> >          }
> >          n->vhost_started = 1;
> > @@ -325,11 +318,16 @@ static void peer_test_vnet_hdr(VirtIONet *n)
> >          return;
> >      }
> >
> > -    if (nc->peer->info->type != NET_CLIENT_OPTIONS_KIND_TAP) {
> > -        return;
> > +    switch (nc->peer->info->type) {
> > +    case NET_CLIENT_OPTIONS_KIND_TAP:
> > +        n->has_vnet_hdr = tap_has_vnet_hdr(nc->peer);
> > +        break;
> > +    case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
> > +        n->has_vnet_hdr = 0;
> > +        break;
> > +    default:
> > +        break;
> >      }
> > -
> > -    n->has_vnet_hdr = tap_has_vnet_hdr(nc->peer);
> >  }
> >
> >  static int peer_has_vnet_hdr(VirtIONet *n)
> > @@ -437,13 +435,10 @@ static uint32_t
> virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
> >          features &= ~(0x1 << VIRTIO_NET_F_HOST_UFO);
> >      }
> >
> > -    if (!nc->peer || nc->peer->info->type !=
> NET_CLIENT_OPTIONS_KIND_TAP) {
> > +    if (!get_vhost_net(nc->peer)) {
> >          return features;
> >      }
> > -    if (!tap_get_vhost_net(nc->peer)) {
> > -        return features;
> > -    }
> > -    return vhost_net_get_features(tap_get_vhost_net(nc->peer),
> features);
> > +    return vhost_net_get_features(get_vhost_net(nc->peer), features);
> >  }
> >
> >  static uint32_t virtio_net_bad_features(VirtIODevice *vdev)
> > @@ -507,13 +502,10 @@ static void virtio_net_set_features(VirtIODevice
> *vdev, uint32_t features)
> >      for (i = 0;  i < n->max_queues; i++) {
> >          NetClientState *nc = qemu_get_subqueue(n->nic, i);
> >
> > -        if (!nc->peer || nc->peer->info->type !=
> NET_CLIENT_OPTIONS_KIND_TAP) {
> > -            continue;
> > -        }
> > -        if (!tap_get_vhost_net(nc->peer)) {
> > +        if (!get_vhost_net(nc->peer)) {
> >              continue;
> >          }
> > -        vhost_net_ack_features(tap_get_vhost_net(nc->peer), features);
> > +        vhost_net_ack_features(get_vhost_net(nc->peer), features);
> >      }
> >  }
> >
> > @@ -1443,7 +1435,7 @@ static bool
> virtio_net_guest_notifier_pending(VirtIODevice *vdev, int idx)
> >      VirtIONet *n = VIRTIO_NET(vdev);
> >      NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx));
> >      assert(n->vhost_started);
> > -    return vhost_net_virtqueue_pending(tap_get_vhost_net(nc->peer),
> idx);
> > +    return vhost_net_virtqueue_pending(get_vhost_net(nc->peer), idx);
> >  }
> >
> >  static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx,
> > @@ -1452,7 +1444,7 @@ static void
> virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx,
> >      VirtIONet *n = VIRTIO_NET(vdev);
> >      NetClientState *nc = qemu_get_subqueue(n->nic, vq2q(idx));
> >      assert(n->vhost_started);
> > -    vhost_net_virtqueue_mask(tap_get_vhost_net(nc->peer),
> > +    vhost_net_virtqueue_mask(get_vhost_net(nc->peer),
> >                               vdev, idx, mask);
> >  }
> >
> > diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
> > index a1137e1..fe622fb 100644
> > --- a/hw/virtio/vhost.c
> > +++ b/hw/virtio/vhost.c
> > @@ -14,7 +14,6 @@
> >   */
> >
> >  #include "hw/virtio/vhost.h"
> > -#include "hw/virtio/vhost-backend.h"
> >  #include "hw/hw.h"
> >  #include "qemu/atomic.h"
> >  #include "qemu/range.h"
> > diff --git a/include/net/vhost-user.h b/include/net/vhost-user.h
> > new file mode 100644
> > index 0000000..85109f6
> > --- /dev/null
> > +++ b/include/net/vhost-user.h
> > @@ -0,0 +1,17 @@
> > +/*
> > + * vhost-user.h
> > + *
> > + * Copyright (c) 2013 Virtual Open Systems Sarl.
> > + *
> > + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> > + * See the COPYING file in the top-level directory.
> > + *
> > + */
> > +
> > +#ifndef VHOST_USER_H_
> > +#define VHOST_USER_H_
> > +
> > +struct vhost_net;
> > +struct vhost_net *vhost_user_get_vhost_net(NetClientState *nc);
> > +
> > +#endif /* VHOST_USER_H_ */
> > diff --git a/include/net/vhost_net.h b/include/net/vhost_net.h
> > index 1169562..abd3d0b 100644
> > --- a/include/net/vhost_net.h
> > +++ b/include/net/vhost_net.h
> > @@ -31,4 +31,5 @@ void vhost_net_ack_features(VHostNetState *net,
> unsigned features);
> >  bool vhost_net_virtqueue_pending(VHostNetState *net, int n);
> >  void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
> >                                int idx, bool mask);
> > +VHostNetState *get_vhost_net(NetClientState *nc);
> >  #endif
> > diff --git a/net/Makefile.objs b/net/Makefile.objs
> > index c25fe69..301f6b6 100644
> > --- a/net/Makefile.objs
> > +++ b/net/Makefile.objs
> > @@ -2,7 +2,7 @@ common-obj-y = net.o queue.o checksum.o util.o hub.o
> >  common-obj-y += socket.o
> >  common-obj-y += dump.o
> >  common-obj-y += eth.o
> > -common-obj-$(CONFIG_POSIX) += tap.o
> > +common-obj-$(CONFIG_POSIX) += tap.o vhost-user.o
> >  common-obj-$(CONFIG_LINUX) += tap-linux.o
> >  common-obj-$(CONFIG_WIN32) += tap-win32.o
> >  common-obj-$(CONFIG_BSD) += tap-bsd.o
> > diff --git a/net/clients.h b/net/clients.h
> > index 7322ff5..7f3d4ae 100644
> > --- a/net/clients.h
> > +++ b/net/clients.h
> > @@ -57,4 +57,7 @@ int net_init_netmap(const NetClientOptions *opts,
> const char *name,
> >                      NetClientState *peer);
> >  #endif
> >
> > +int net_init_vhost_user(const NetClientOptions *opts, const char *name,
> > +                        NetClientState *peer);
> > +
> >  #endif /* QEMU_NET_CLIENTS_H */
> > diff --git a/net/hub.c b/net/hub.c
> > index 33a99c9..7e0f2d6 100644
> > --- a/net/hub.c
> > +++ b/net/hub.c
> > @@ -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:
> > diff --git a/net/net.c b/net/net.c
> > index 9db88cc..0f057c5 100644
> > --- a/net/net.c
> > +++ b/net/net.c
> > @@ -734,6 +734,7 @@ 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,
> > +        [NET_CLIENT_OPTIONS_KIND_VHOST_USER] = net_init_vhost_user,
> >  };
> >
> >
> > @@ -767,6 +768,7 @@ 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:
> > +        case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
> >              break;
> >
> >          default:
> > diff --git a/net/vhost-user.c b/net/vhost-user.c
> > new file mode 100644
> > index 0000000..6fd5afc
> > --- /dev/null
> > +++ b/net/vhost-user.c
> > @@ -0,0 +1,111 @@
> > +/*
> > + * vhost-user.c
> > + *
> > + * Copyright (c) 2013 Virtual Open Systems Sarl.
> > + *
> > + * This work is licensed under the terms of the GNU GPL, version 2 or
> later.
> > + * See the COPYING file in the top-level directory.
> > + *
> > + */
> > +
> > +#include "clients.h"
> > +#include "net/vhost_net.h"
> > +#include "net/vhost-user.h"
> > +#include "qemu/error-report.h"
> > +
> > +typedef struct VhostUserState {
> > +    NetClientState nc;
> > +    VHostNetState *vhost_net;
> > +    char *devpath;
> > +} VhostUserState;
> > +
> > +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;
> > +}
> > +
> > +static int vhost_user_running(VhostUserState *s)
> > +{
> > +    return (s->vhost_net) ? 1 : 0;
> > +}
> > +
> > +static int vhost_user_start(VhostUserState *s)
> > +{
> > +    VhostNetOptions options;
> > +
> > +    if (vhost_user_running(s)) {
> > +        return 1;
> > +    }
> > +
> > +    options.backend_type = VHOST_BACKEND_TYPE_USER;
> > +    options.net_backend = &s->nc;
> > +    options.devpath = s->devpath;
> > +    options.devfd = -1;
> > +    options.force = 1;
> > +
> > +    s->vhost_net = vhost_net_init(&options);
> > +
> > +    return vhost_user_running(s) ? 0 : -1;
> > +}
> > +
> > +static void vhost_user_stop(VhostUserState *s)
> > +{
> > +    if (vhost_user_running(s)) {
> > +        vhost_net_cleanup(s->vhost_net);
> > +    }
> > +
> > +    s->vhost_net = 0;
> > +}
> > +
> > +static void vhost_user_cleanup(NetClientState *nc)
> > +{
> > +    VhostUserState *s = DO_UPCAST(VhostUserState, nc, nc);
> > +
> > +    vhost_user_stop(s);
> > +    qemu_purge_queued_packets(nc);
> > +}
> > +
> > +static NetClientInfo net_vhost_user_info = {
> > +        .type = NET_CLIENT_OPTIONS_KIND_VHOST_USER,
> > +        .size = sizeof(VhostUserState),
> > +        .cleanup = vhost_user_cleanup,
> > +};
> > +
> > +static int net_vhost_user_init(NetClientState *peer, const char *device,
> > +                          const char *name, const char *filename)
> > +{
> > +    NetClientState *nc;
> > +    VhostUserState *s;
> > +    int r;
> > +
> > +    nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name);
> > +
> > +    snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user to %s",
> filename);
> > +
> > +    s = DO_UPCAST(VhostUserState, nc, nc);
> > +
> > +    /* We don't provide a receive callback */
> > +    s->nc.receive_disabled = 1;
> > +
> > +    s->devpath = g_strdup(filename);
> > +
> > +    r = vhost_user_start(s);
> > +
> > +    return r;
> > +}
> > +
> > +int net_init_vhost_user(const NetClientOptions *opts, const char *name,
> > +                   NetClientState *peer)
> > +{
> > +    const char *file;
> > +    const NetdevVhostUserOptions *vhost_user;
> > +
> > +    assert(opts->kind == NET_CLIENT_OPTIONS_KIND_VHOST_USER);
> > +    vhost_user = opts->vhost_user;
> > +
> > +    file = vhost_user->file;
> > +
> > +    return net_vhost_user_init(peer, "vhost_user", name, file);
> > +}
> > diff --git a/qapi-schema.json b/qapi-schema.json
> > index c3c939c..3101287 100644
> > --- a/qapi-schema.json
> > +++ b/qapi-schema.json
> > @@ -3030,6 +3030,21 @@
> >      '*devname':    'str' } }
> >
> >  ##
> > +# @NetdevVhostUserOptions
> > +#
> > +# Vhost-user network backend
> > +#
> > +# @file: control socket path
> > +#
> > +# Since 2.0
> > +##
> > +{ 'type': 'NetdevVhostUserOptions',
> > +  'data': {
> > +    'file': 'str' } }
> > +
> > +##
> > +
> > +##
> >  # @NetClientOptions
> >  #
> >  # A discriminated record of network device traits.
> > @@ -3047,7 +3062,8 @@
> >      'dump':     'NetdevDumpOptions',
> >      'bridge':   'NetdevBridgeOptions',
> >      'hubport':  'NetdevHubPortOptions',
> > -    'netmap':   'NetdevNetmapOptions' } }
> > +    'netmap':   'NetdevNetmapOptions',
> > +    'vhost-user': 'NetdevVhostUserOptions' } }
> >
> >  ##
> >  # @NetLegacy
> > diff --git a/qemu-options.hx b/qemu-options.hx
> > index 0d35c9c..edf25d0 100644
> > --- a/qemu-options.hx
> > +++ b/qemu-options.hx
> > @@ -1419,6 +1419,8 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
> >      "                VALE port (created on the fly) called 'name'
> ('nmname' is name of the \n"
> >      "                netmap device, defaults to '/dev/netmap')\n"
> >  #endif
> > +    "-net vhost-user,file=name\n"
> > +    "                connect to a unix domain socket implementing
> vhost-user backend\n"
>
> I'm guessing this does not work, you really must use this with -netdev?
>

You are right, we will correct the message.


>
> >      "-net dump[,vlan=n][,file=f][,len=n]\n"
> >      "                dump traffic on vlan 'n' to file 'f' (max n bytes
> per packet)\n"
> >      "-net none       use it alone to have zero network devices. If no
> -net option\n"
> > @@ -1436,6 +1438,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
> > --
> > 1.8.3.2
> >
>

Reply via email to