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