qemu/hw/net/vhost_net.c
<<
>>
Prefs
   1/*
   2 * vhost-net support
   3 *
   4 * Copyright Red Hat, Inc. 2010
   5 *
   6 * Authors:
   7 *  Michael S. Tsirkin <mst@redhat.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2.  See
  10 * the COPYING file in the top-level directory.
  11 *
  12 * Contributions after 2012-01-13 are licensed under the terms of the
  13 * GNU GPL, version 2 or (at your option) any later version.
  14 */
  15
  16#include "qemu/osdep.h"
  17#include "net/net.h"
  18#include "net/tap.h"
  19#include "net/vhost-user.h"
  20
  21#include "hw/virtio/virtio-net.h"
  22#include "net/vhost_net.h"
  23#include "qemu/error-report.h"
  24
  25
  26#ifdef CONFIG_VHOST_NET
  27#include <linux/vhost.h>
  28#include <sys/socket.h>
  29#include <linux/kvm.h>
  30#include <netpacket/packet.h>
  31#include <net/ethernet.h>
  32#include <net/if.h>
  33#include <netinet/in.h>
  34
  35
  36#include "standard-headers/linux/virtio_ring.h"
  37#include "hw/virtio/vhost.h"
  38#include "hw/virtio/virtio-bus.h"
  39
  40struct vhost_net {
  41    struct vhost_dev dev;
  42    struct vhost_virtqueue vqs[2];
  43    int backend;
  44    NetClientState *nc;
  45};
  46
  47/* Features supported by host kernel. */
  48static const int kernel_feature_bits[] = {
  49    VIRTIO_F_NOTIFY_ON_EMPTY,
  50    VIRTIO_RING_F_INDIRECT_DESC,
  51    VIRTIO_RING_F_EVENT_IDX,
  52    VIRTIO_NET_F_MRG_RXBUF,
  53    VIRTIO_F_VERSION_1,
  54    VHOST_INVALID_FEATURE_BIT
  55};
  56
  57/* Features supported by others. */
  58static const int user_feature_bits[] = {
  59    VIRTIO_F_NOTIFY_ON_EMPTY,
  60    VIRTIO_RING_F_INDIRECT_DESC,
  61    VIRTIO_RING_F_EVENT_IDX,
  62
  63    VIRTIO_F_ANY_LAYOUT,
  64    VIRTIO_F_VERSION_1,
  65    VIRTIO_NET_F_CSUM,
  66    VIRTIO_NET_F_GUEST_CSUM,
  67    VIRTIO_NET_F_GSO,
  68    VIRTIO_NET_F_GUEST_TSO4,
  69    VIRTIO_NET_F_GUEST_TSO6,
  70    VIRTIO_NET_F_GUEST_ECN,
  71    VIRTIO_NET_F_GUEST_UFO,
  72    VIRTIO_NET_F_HOST_TSO4,
  73    VIRTIO_NET_F_HOST_TSO6,
  74    VIRTIO_NET_F_HOST_ECN,
  75    VIRTIO_NET_F_HOST_UFO,
  76    VIRTIO_NET_F_MRG_RXBUF,
  77
  78    /* This bit implies RARP isn't sent by QEMU out of band */
  79    VIRTIO_NET_F_GUEST_ANNOUNCE,
  80
  81    VIRTIO_NET_F_MQ,
  82
  83    VHOST_INVALID_FEATURE_BIT
  84};
  85
  86static const int *vhost_net_get_feature_bits(struct vhost_net *net)
  87{
  88    const int *feature_bits = 0;
  89
  90    switch (net->nc->info->type) {
  91    case NET_CLIENT_OPTIONS_KIND_TAP:
  92        feature_bits = kernel_feature_bits;
  93        break;
  94    case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
  95        feature_bits = user_feature_bits;
  96        break;
  97    default:
  98        error_report("Feature bits not defined for this type: %d",
  99                net->nc->info->type);
 100        break;
 101    }
 102
 103    return feature_bits;
 104}
 105
 106uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features)
 107{
 108    return vhost_get_features(&net->dev, vhost_net_get_feature_bits(net),
 109            features);
 110}
 111
 112void vhost_net_ack_features(struct vhost_net *net, uint64_t features)
 113{
 114    net->dev.acked_features = net->dev.backend_features;
 115    vhost_ack_features(&net->dev, vhost_net_get_feature_bits(net), features);
 116}
 117
 118uint64_t vhost_net_get_max_queues(VHostNetState *net)
 119{
 120    return net->dev.max_queues;
 121}
 122
 123static int vhost_net_get_fd(NetClientState *backend)
 124{
 125    switch (backend->info->type) {
 126    case NET_CLIENT_OPTIONS_KIND_TAP:
 127        return tap_get_fd(backend);
 128    default:
 129        fprintf(stderr, "vhost-net requires tap backend\n");
 130        return -EBADFD;
 131    }
 132}
 133
 134struct vhost_net *vhost_net_init(VhostNetOptions *options)
 135{
 136    int r;
 137    bool backend_kernel = options->backend_type == VHOST_BACKEND_TYPE_KERNEL;
 138    struct vhost_net *net = g_malloc(sizeof *net);
 139
 140    if (!options->net_backend) {
 141        fprintf(stderr, "vhost-net requires net backend to be setup\n");
 142        goto fail;
 143    }
 144    net->nc = options->net_backend;
 145
 146    net->dev.max_queues = 1;
 147    net->dev.nvqs = 2;
 148    net->dev.vqs = net->vqs;
 149
 150    if (backend_kernel) {
 151        r = vhost_net_get_fd(options->net_backend);
 152        if (r < 0) {
 153            goto fail;
 154        }
 155        net->dev.backend_features = qemu_has_vnet_hdr(options->net_backend)
 156            ? 0 : (1ULL << VHOST_NET_F_VIRTIO_NET_HDR);
 157        net->backend = r;
 158        net->dev.protocol_features = 0;
 159    } else {
 160        net->dev.backend_features = 0;
 161        net->dev.protocol_features = 0;
 162        net->backend = -1;
 163
 164        /* vhost-user needs vq_index to initiate a specific queue pair */
 165        net->dev.vq_index = net->nc->queue_index * net->dev.nvqs;
 166    }
 167
 168    r = vhost_dev_init(&net->dev, options->opaque,
 169                       options->backend_type);
 170    if (r < 0) {
 171        goto fail;
 172    }
 173    if (backend_kernel) {
 174        if (!qemu_has_vnet_hdr_len(options->net_backend,
 175                               sizeof(struct virtio_net_hdr_mrg_rxbuf))) {
 176            net->dev.features &= ~(1ULL << VIRTIO_NET_F_MRG_RXBUF);
 177        }
 178        if (~net->dev.features & net->dev.backend_features) {
 179            fprintf(stderr, "vhost lacks feature mask %" PRIu64
 180                   " for backend\n",
 181                   (uint64_t)(~net->dev.features & net->dev.backend_features));
 182            vhost_dev_cleanup(&net->dev);
 183            goto fail;
 184        }
 185    }
 186    /* Set sane init value. Override when guest acks. */
 187    vhost_net_ack_features(net, 0);
 188    return net;
 189fail:
 190    g_free(net);
 191    return NULL;
 192}
 193
 194static void vhost_net_set_vq_index(struct vhost_net *net, int vq_index)
 195{
 196    net->dev.vq_index = vq_index;
 197}
 198
 199static int vhost_net_start_one(struct vhost_net *net,
 200                               VirtIODevice *dev)
 201{
 202    struct vhost_vring_file file = { };
 203    int r;
 204
 205    net->dev.nvqs = 2;
 206    net->dev.vqs = net->vqs;
 207
 208    r = vhost_dev_enable_notifiers(&net->dev, dev);
 209    if (r < 0) {
 210        goto fail_notifiers;
 211    }
 212
 213    r = vhost_dev_start(&net->dev, dev);
 214    if (r < 0) {
 215        goto fail_start;
 216    }
 217
 218    if (net->nc->info->poll) {
 219        net->nc->info->poll(net->nc, false);
 220    }
 221
 222    if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
 223        qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
 224        file.fd = net->backend;
 225        for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
 226            const VhostOps *vhost_ops = net->dev.vhost_ops;
 227            r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
 228            if (r < 0) {
 229                r = -errno;
 230                goto fail;
 231            }
 232        }
 233    }
 234    return 0;
 235fail:
 236    file.fd = -1;
 237    if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
 238        while (file.index-- > 0) {
 239            const VhostOps *vhost_ops = net->dev.vhost_ops;
 240            int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
 241            assert(r >= 0);
 242        }
 243    }
 244    if (net->nc->info->poll) {
 245        net->nc->info->poll(net->nc, true);
 246    }
 247    vhost_dev_stop(&net->dev, dev);
 248fail_start:
 249    vhost_dev_disable_notifiers(&net->dev, dev);
 250fail_notifiers:
 251    return r;
 252}
 253
 254static void vhost_net_stop_one(struct vhost_net *net,
 255                               VirtIODevice *dev)
 256{
 257    struct vhost_vring_file file = { .fd = -1 };
 258
 259    if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) {
 260        for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
 261            const VhostOps *vhost_ops = net->dev.vhost_ops;
 262            int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
 263            assert(r >= 0);
 264        }
 265    }
 266    if (net->nc->info->poll) {
 267        net->nc->info->poll(net->nc, true);
 268    }
 269    vhost_dev_stop(&net->dev, dev);
 270    vhost_dev_disable_notifiers(&net->dev, dev);
 271}
 272
 273int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
 274                    int total_queues)
 275{
 276    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
 277    VirtioBusState *vbus = VIRTIO_BUS(qbus);
 278    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
 279    int r, e, i;
 280
 281    if (!k->set_guest_notifiers) {
 282        error_report("binding does not support guest notifiers");
 283        return -ENOSYS;
 284    }
 285
 286    for (i = 0; i < total_queues; i++) {
 287        struct vhost_net *net;
 288
 289        net = get_vhost_net(ncs[i].peer);
 290        vhost_net_set_vq_index(net, i * 2);
 291
 292        /* Suppress the masking guest notifiers on vhost user
 293         * because vhost user doesn't interrupt masking/unmasking
 294         * properly.
 295         */
 296        if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
 297                dev->use_guest_notifier_mask = false;
 298        }
 299     }
 300
 301    r = k->set_guest_notifiers(qbus->parent, total_queues * 2, true);
 302    if (r < 0) {
 303        error_report("Error binding guest notifier: %d", -r);
 304        goto err;
 305    }
 306
 307    for (i = 0; i < total_queues; i++) {
 308        r = vhost_net_start_one(get_vhost_net(ncs[i].peer), dev);
 309
 310        if (r < 0) {
 311            goto err_start;
 312        }
 313    }
 314
 315    return 0;
 316
 317err_start:
 318    while (--i >= 0) {
 319        vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
 320    }
 321    e = k->set_guest_notifiers(qbus->parent, total_queues * 2, false);
 322    if (e < 0) {
 323        fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", e);
 324        fflush(stderr);
 325    }
 326err:
 327    return r;
 328}
 329
 330void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
 331                    int total_queues)
 332{
 333    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
 334    VirtioBusState *vbus = VIRTIO_BUS(qbus);
 335    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
 336    int i, r;
 337
 338    for (i = 0; i < total_queues; i++) {
 339        vhost_net_stop_one(get_vhost_net(ncs[i].peer), dev);
 340    }
 341
 342    r = k->set_guest_notifiers(qbus->parent, total_queues * 2, false);
 343    if (r < 0) {
 344        fprintf(stderr, "vhost guest notifier cleanup failed: %d\n", r);
 345        fflush(stderr);
 346    }
 347    assert(r >= 0);
 348}
 349
 350void vhost_net_cleanup(struct vhost_net *net)
 351{
 352    vhost_dev_cleanup(&net->dev);
 353    g_free(net);
 354}
 355
 356int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr)
 357{
 358    const VhostOps *vhost_ops = net->dev.vhost_ops;
 359    int r = -1;
 360
 361    if (vhost_ops->vhost_migration_done) {
 362        r = vhost_ops->vhost_migration_done(&net->dev, mac_addr);
 363    }
 364
 365    return r;
 366}
 367
 368bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
 369{
 370    return vhost_virtqueue_pending(&net->dev, idx);
 371}
 372
 373void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
 374                              int idx, bool mask)
 375{
 376    vhost_virtqueue_mask(&net->dev, dev, idx, mask);
 377}
 378
 379VHostNetState *get_vhost_net(NetClientState *nc)
 380{
 381    VHostNetState *vhost_net = 0;
 382
 383    if (!nc) {
 384        return 0;
 385    }
 386
 387    switch (nc->info->type) {
 388    case NET_CLIENT_OPTIONS_KIND_TAP:
 389        vhost_net = tap_get_vhost_net(nc);
 390        break;
 391    case NET_CLIENT_OPTIONS_KIND_VHOST_USER:
 392        vhost_net = vhost_user_get_vhost_net(nc);
 393        break;
 394    default:
 395        break;
 396    }
 397
 398    return vhost_net;
 399}
 400
 401int vhost_set_vring_enable(NetClientState *nc, int enable)
 402{
 403    VHostNetState *net = get_vhost_net(nc);
 404    const VhostOps *vhost_ops = net->dev.vhost_ops;
 405
 406    if (vhost_ops->vhost_set_vring_enable) {
 407        return vhost_ops->vhost_set_vring_enable(&net->dev, enable);
 408    }
 409
 410    return 0;
 411}
 412
 413#else
 414uint64_t vhost_net_get_max_queues(VHostNetState *net)
 415{
 416    return 1;
 417}
 418
 419struct vhost_net *vhost_net_init(VhostNetOptions *options)
 420{
 421    error_report("vhost-net support is not compiled in");
 422    return NULL;
 423}
 424
 425int vhost_net_start(VirtIODevice *dev,
 426                    NetClientState *ncs,
 427                    int total_queues)
 428{
 429    return -ENOSYS;
 430}
 431void vhost_net_stop(VirtIODevice *dev,
 432                    NetClientState *ncs,
 433                    int total_queues)
 434{
 435}
 436
 437void vhost_net_cleanup(struct vhost_net *net)
 438{
 439}
 440
 441uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features)
 442{
 443    return features;
 444}
 445void vhost_net_ack_features(struct vhost_net *net, uint64_t features)
 446{
 447}
 448
 449bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
 450{
 451    return false;
 452}
 453
 454void vhost_net_virtqueue_mask(VHostNetState *net, VirtIODevice *dev,
 455                              int idx, bool mask)
 456{
 457}
 458
 459int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr)
 460{
 461    return -1;
 462}
 463
 464VHostNetState *get_vhost_net(NetClientState *nc)
 465{
 466    return 0;
 467}
 468
 469int vhost_set_vring_enable(NetClientState *nc, int enable)
 470{
 471    return 0;
 472}
 473#endif
 474