cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

vhost-vdpa.c (5815B)


      1/*
      2 * vhost-vdpa.c
      3 *
      4 * Copyright(c) 2017-2018 Intel Corporation.
      5 * Copyright(c) 2020 Red Hat, Inc.
      6 *
      7 * This work is licensed under the terms of the GNU GPL, version 2 or later.
      8 * See the COPYING file in the top-level directory.
      9 *
     10 */
     11
     12#include "qemu/osdep.h"
     13#include "clients.h"
     14#include "net/vhost_net.h"
     15#include "net/vhost-vdpa.h"
     16#include "hw/virtio/vhost-vdpa.h"
     17#include "qemu/config-file.h"
     18#include "qemu/error-report.h"
     19#include "qemu/option.h"
     20#include "qapi/error.h"
     21#include <sys/ioctl.h>
     22#include <err.h>
     23#include "standard-headers/linux/virtio_net.h"
     24#include "monitor/monitor.h"
     25#include "hw/virtio/vhost.h"
     26
     27/* Todo:need to add the multiqueue support here */
     28typedef struct VhostVDPAState {
     29    NetClientState nc;
     30    struct vhost_vdpa vhost_vdpa;
     31    VHostNetState *vhost_net;
     32    bool started;
     33} VhostVDPAState;
     34
     35const int vdpa_feature_bits[] = {
     36    VIRTIO_F_NOTIFY_ON_EMPTY,
     37    VIRTIO_RING_F_INDIRECT_DESC,
     38    VIRTIO_RING_F_EVENT_IDX,
     39    VIRTIO_F_ANY_LAYOUT,
     40    VIRTIO_F_VERSION_1,
     41    VIRTIO_NET_F_CSUM,
     42    VIRTIO_NET_F_GUEST_CSUM,
     43    VIRTIO_NET_F_GSO,
     44    VIRTIO_NET_F_GUEST_TSO4,
     45    VIRTIO_NET_F_GUEST_TSO6,
     46    VIRTIO_NET_F_GUEST_ECN,
     47    VIRTIO_NET_F_GUEST_UFO,
     48    VIRTIO_NET_F_HOST_TSO4,
     49    VIRTIO_NET_F_HOST_TSO6,
     50    VIRTIO_NET_F_HOST_ECN,
     51    VIRTIO_NET_F_HOST_UFO,
     52    VIRTIO_NET_F_MRG_RXBUF,
     53    VIRTIO_NET_F_MTU,
     54    VIRTIO_F_IOMMU_PLATFORM,
     55    VIRTIO_F_RING_PACKED,
     56    VIRTIO_NET_F_RSS,
     57    VIRTIO_NET_F_HASH_REPORT,
     58    VIRTIO_NET_F_GUEST_ANNOUNCE,
     59    VIRTIO_NET_F_STATUS,
     60    VHOST_INVALID_FEATURE_BIT
     61};
     62
     63VHostNetState *vhost_vdpa_get_vhost_net(NetClientState *nc)
     64{
     65    VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc);
     66    assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
     67    return s->vhost_net;
     68}
     69
     70static int vhost_vdpa_net_check_device_id(struct vhost_net *net)
     71{
     72    uint32_t device_id;
     73    int ret;
     74    struct vhost_dev *hdev;
     75
     76    hdev = (struct vhost_dev *)&net->dev;
     77    ret = hdev->vhost_ops->vhost_get_device_id(hdev, &device_id);
     78    if (device_id != VIRTIO_ID_NET) {
     79        return -ENOTSUP;
     80    }
     81    return ret;
     82}
     83
     84static int vhost_vdpa_add(NetClientState *ncs, void *be)
     85{
     86    VhostNetOptions options;
     87    struct vhost_net *net = NULL;
     88    VhostVDPAState *s;
     89    int ret;
     90
     91    options.backend_type = VHOST_BACKEND_TYPE_VDPA;
     92    assert(ncs->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
     93    s = DO_UPCAST(VhostVDPAState, nc, ncs);
     94    options.net_backend = ncs;
     95    options.opaque      = be;
     96    options.busyloop_timeout = 0;
     97    options.nvqs = 2;
     98
     99    net = vhost_net_init(&options);
    100    if (!net) {
    101        error_report("failed to init vhost_net for queue");
    102        goto err_init;
    103    }
    104    s->vhost_net = net;
    105    ret = vhost_vdpa_net_check_device_id(net);
    106    if (ret) {
    107        goto err_check;
    108    }
    109    return 0;
    110err_check:
    111    vhost_net_cleanup(net);
    112    g_free(net);
    113err_init:
    114    return -1;
    115}
    116
    117static void vhost_vdpa_cleanup(NetClientState *nc)
    118{
    119    VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc);
    120
    121    if (s->vhost_net) {
    122        vhost_net_cleanup(s->vhost_net);
    123        g_free(s->vhost_net);
    124        s->vhost_net = NULL;
    125    }
    126     if (s->vhost_vdpa.device_fd >= 0) {
    127        qemu_close(s->vhost_vdpa.device_fd);
    128        s->vhost_vdpa.device_fd = -1;
    129    }
    130}
    131
    132static bool vhost_vdpa_has_vnet_hdr(NetClientState *nc)
    133{
    134    assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
    135
    136    return true;
    137}
    138
    139static bool vhost_vdpa_has_ufo(NetClientState *nc)
    140{
    141    assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA);
    142    VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc);
    143    uint64_t features = 0;
    144    features |= (1ULL << VIRTIO_NET_F_HOST_UFO);
    145    features = vhost_net_get_features(s->vhost_net, features);
    146    return !!(features & (1ULL << VIRTIO_NET_F_HOST_UFO));
    147
    148}
    149
    150static NetClientInfo net_vhost_vdpa_info = {
    151        .type = NET_CLIENT_DRIVER_VHOST_VDPA,
    152        .size = sizeof(VhostVDPAState),
    153        .cleanup = vhost_vdpa_cleanup,
    154        .has_vnet_hdr = vhost_vdpa_has_vnet_hdr,
    155        .has_ufo = vhost_vdpa_has_ufo,
    156};
    157
    158static int net_vhost_vdpa_init(NetClientState *peer, const char *device,
    159                               const char *name, const char *vhostdev)
    160{
    161    NetClientState *nc = NULL;
    162    VhostVDPAState *s;
    163    int vdpa_device_fd = -1;
    164    int ret = 0;
    165    assert(name);
    166    nc = qemu_new_net_client(&net_vhost_vdpa_info, peer, device, name);
    167    snprintf(nc->info_str, sizeof(nc->info_str), TYPE_VHOST_VDPA);
    168    s = DO_UPCAST(VhostVDPAState, nc, nc);
    169    vdpa_device_fd = qemu_open_old(vhostdev, O_RDWR);
    170    if (vdpa_device_fd == -1) {
    171        return -errno;
    172    }
    173    s->vhost_vdpa.device_fd = vdpa_device_fd;
    174    ret = vhost_vdpa_add(nc, (void *)&s->vhost_vdpa);
    175    if (ret) {
    176        qemu_close(vdpa_device_fd);
    177        qemu_del_net_client(nc);
    178    }
    179    return ret;
    180}
    181
    182static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp)
    183{
    184    const char *name = opaque;
    185    const char *driver, *netdev;
    186
    187    driver = qemu_opt_get(opts, "driver");
    188    netdev = qemu_opt_get(opts, "netdev");
    189    if (!driver || !netdev) {
    190        return 0;
    191    }
    192    if (strcmp(netdev, name) == 0 &&
    193        !g_str_has_prefix(driver, "virtio-net-")) {
    194        error_setg(errp, "vhost-vdpa requires frontend driver virtio-net-*");
    195        return -1;
    196    }
    197    return 0;
    198}
    199
    200int net_init_vhost_vdpa(const Netdev *netdev, const char *name,
    201                        NetClientState *peer, Error **errp)
    202{
    203    const NetdevVhostVDPAOptions *opts;
    204
    205    assert(netdev->type == NET_CLIENT_DRIVER_VHOST_VDPA);
    206    opts = &netdev->u.vhost_vdpa;
    207    /* verify net frontend */
    208    if (qemu_opts_foreach(qemu_find_opts("device"), net_vhost_check_net,
    209                          (char *)name, errp)) {
    210        return -1;
    211    }
    212    return net_vhost_vdpa_init(peer, TYPE_VHOST_VDPA, name, opts->vhostdev);
    213}