Commit 5da73dab authored by Gonglei's avatar Gonglei Committed by Michael S. Tsirkin
Browse files

cryptodev: add vhost support



Impliment the vhost-crypto's funtions, such as startup,
stop and notification etc. Introduce an enum
QCryptoCryptoDevBackendOptionsType in order to
identify the cryptodev vhost backend is vhost-user
or vhost-kernel-module (If exist).

At this point, the cryptdoev-vhost-user works.

Signed-off-by: default avatarGonglei <arei.gonglei@huawei.com>
Signed-off-by: default avatarLongpeng(Mike) <longpeng2@huawei.com>
Signed-off-by: default avatarJay Zhou <jianjay.zhou@huawei.com>
Reviewed-by: default avatarMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
parent 042cea27
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ static void cryptodev_builtin_init(
              "cryptodev-builtin", NULL);
    cc->info_str = g_strdup_printf("cryptodev-builtin0");
    cc->queue_index = 0;
    cc->type = CRYPTODEV_BACKEND_TYPE_BUILTIN;
    backend->conf.peers.ccs[0] = cc;

    backend->conf.crypto_services =
+16 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include "standard-headers/linux/virtio_crypto.h"
#include "sysemu/cryptodev-vhost.h"
#include "chardev/char-fe.h"
#include "sysemu/cryptodev-vhost-user.h"


/**
@@ -58,6 +59,20 @@ cryptodev_vhost_user_running(
    return crypto ? 1 : 0;
}

CryptoDevBackendVhost *
cryptodev_vhost_user_get_vhost(
                         CryptoDevBackendClient *cc,
                         CryptoDevBackend *b,
                         uint16_t queue)
{
    CryptoDevBackendVhostUser *s =
                      CRYPTODEV_BACKEND_VHOST_USER(b);
    assert(cc->type == CRYPTODEV_BACKEND_TYPE_VHOST_USER);
    assert(queue < MAX_CRYPTO_QUEUE_NUM);

    return s->vhost_crypto[queue];
}

static void cryptodev_vhost_user_stop(int queues,
                          CryptoDevBackendVhostUser *s)
{
@@ -188,6 +203,7 @@ static void cryptodev_vhost_user_init(
        cc->info_str = g_strdup_printf("cryptodev-vhost-user%zu to %s ",
                                       i, chr->label);
        cc->queue_index = i;
        cc->type = CRYPTODEV_BACKEND_TYPE_VHOST_USER;

        backend->conf.peers.ccs[i] = cc;

+258 −0
Original line number Diff line number Diff line
@@ -23,9 +23,16 @@
 */

#include "qemu/osdep.h"
#include "hw/virtio/virtio-bus.h"
#include "sysemu/cryptodev-vhost.h"

#ifdef CONFIG_VHOST_CRYPTO
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
#include "qemu/error-report.h"
#include "hw/virtio/virtio-crypto.h"
#include "sysemu/cryptodev-vhost-user.h"

uint64_t
cryptodev_vhost_get_max_queues(
                        CryptoDevBackendVhost *crypto)
@@ -70,6 +77,228 @@ fail:
    return NULL;
}

static int
cryptodev_vhost_start_one(CryptoDevBackendVhost *crypto,
                                  VirtIODevice *dev)
{
    int r;

    crypto->dev.nvqs = 1;
    crypto->dev.vqs = crypto->vqs;

    r = vhost_dev_enable_notifiers(&crypto->dev, dev);
    if (r < 0) {
        goto fail_notifiers;
    }

    r = vhost_dev_start(&crypto->dev, dev);
    if (r < 0) {
        goto fail_start;
    }

    return 0;

fail_start:
    vhost_dev_disable_notifiers(&crypto->dev, dev);
fail_notifiers:
    return r;
}

static void
cryptodev_vhost_stop_one(CryptoDevBackendVhost *crypto,
                                 VirtIODevice *dev)
{
    vhost_dev_stop(&crypto->dev, dev);
    vhost_dev_disable_notifiers(&crypto->dev, dev);
}

CryptoDevBackendVhost *
cryptodev_get_vhost(CryptoDevBackendClient *cc,
                            CryptoDevBackend *b,
                            uint16_t queue)
{
    CryptoDevBackendVhost *vhost_crypto = NULL;

    if (!cc) {
        return NULL;
    }

    switch (cc->type) {
#if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
    case CRYPTODEV_BACKEND_TYPE_VHOST_USER:
        vhost_crypto = cryptodev_vhost_user_get_vhost(cc, b, queue);
        break;
#endif
    default:
        break;
    }

    return vhost_crypto;
}

static void
cryptodev_vhost_set_vq_index(CryptoDevBackendVhost *crypto,
                                     int vq_index)
{
    crypto->dev.vq_index = vq_index;
}

static int
vhost_set_vring_enable(CryptoDevBackendClient *cc,
                            CryptoDevBackend *b,
                            uint16_t queue, int enable)
{
    CryptoDevBackendVhost *crypto =
                       cryptodev_get_vhost(cc, b, queue);
    const VhostOps *vhost_ops;

    cc->vring_enable = enable;

    if (!crypto) {
        return 0;
    }

    vhost_ops = crypto->dev.vhost_ops;
    if (vhost_ops->vhost_set_vring_enable) {
        return vhost_ops->vhost_set_vring_enable(&crypto->dev, enable);
    }

    return 0;
}

int cryptodev_vhost_start(VirtIODevice *dev, int total_queues)
{
    VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(dev);
    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
    VirtioBusState *vbus = VIRTIO_BUS(qbus);
    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
    int r, e;
    int i;
    CryptoDevBackend *b = vcrypto->cryptodev;
    CryptoDevBackendVhost *vhost_crypto;
    CryptoDevBackendClient *cc;

    if (!k->set_guest_notifiers) {
        error_report("binding does not support guest notifiers");
        return -ENOSYS;
    }

    for (i = 0; i < total_queues; i++) {
        cc = b->conf.peers.ccs[i];

        vhost_crypto = cryptodev_get_vhost(cc, b, i);
        cryptodev_vhost_set_vq_index(vhost_crypto, i);

        /* Suppress the masking guest notifiers on vhost user
         * because vhost user doesn't interrupt masking/unmasking
         * properly.
         */
        if (cc->type == CRYPTODEV_BACKEND_TYPE_VHOST_USER) {
            dev->use_guest_notifier_mask = false;
        }
     }

    r = k->set_guest_notifiers(qbus->parent, total_queues, true);
    if (r < 0) {
        error_report("error binding guest notifier: %d", -r);
        goto err;
    }

    for (i = 0; i < total_queues; i++) {
        cc = b->conf.peers.ccs[i];

        vhost_crypto = cryptodev_get_vhost(cc, b, i);
        r = cryptodev_vhost_start_one(vhost_crypto, dev);

        if (r < 0) {
            goto err_start;
        }

        if (cc->vring_enable) {
            /* restore vring enable state */
            r = vhost_set_vring_enable(cc, b, i, cc->vring_enable);

            if (r < 0) {
                goto err_start;
            }
        }
    }

    return 0;

err_start:
    while (--i >= 0) {
        cc = b->conf.peers.ccs[i];
        vhost_crypto = cryptodev_get_vhost(cc, b, i);
        cryptodev_vhost_stop_one(vhost_crypto, dev);
    }
    e = k->set_guest_notifiers(qbus->parent, total_queues, false);
    if (e < 0) {
        error_report("vhost guest notifier cleanup failed: %d", e);
    }
err:
    return r;
}

void cryptodev_vhost_stop(VirtIODevice *dev, int total_queues)
{
    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
    VirtioBusState *vbus = VIRTIO_BUS(qbus);
    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
    VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(dev);
    CryptoDevBackend *b = vcrypto->cryptodev;
    CryptoDevBackendVhost *vhost_crypto;
    CryptoDevBackendClient *cc;
    size_t i;
    int r;

    for (i = 0; i < total_queues; i++) {
        cc = b->conf.peers.ccs[i];

        vhost_crypto = cryptodev_get_vhost(cc, b, i);
        cryptodev_vhost_stop_one(vhost_crypto, dev);
    }

    r = k->set_guest_notifiers(qbus->parent, total_queues, false);
    if (r < 0) {
        error_report("vhost guest notifier cleanup failed: %d", r);
    }
    assert(r >= 0);
}

void cryptodev_vhost_virtqueue_mask(VirtIODevice *dev,
                                           int queue,
                                           int idx, bool mask)
{
    VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(dev);
    CryptoDevBackend *b = vcrypto->cryptodev;
    CryptoDevBackendVhost *vhost_crypto;
    CryptoDevBackendClient *cc;

    assert(queue < MAX_CRYPTO_QUEUE_NUM);

    cc = b->conf.peers.ccs[queue];
    vhost_crypto = cryptodev_get_vhost(cc, b, queue);

    vhost_virtqueue_mask(&vhost_crypto->dev, dev, idx, mask);
}

bool cryptodev_vhost_virtqueue_pending(VirtIODevice *dev,
                                              int queue, int idx)
{
    VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(dev);
    CryptoDevBackend *b = vcrypto->cryptodev;
    CryptoDevBackendVhost *vhost_crypto;
    CryptoDevBackendClient *cc;

    assert(queue < MAX_CRYPTO_QUEUE_NUM);

    cc = b->conf.peers.ccs[queue];
    vhost_crypto = cryptodev_get_vhost(cc, b, queue);

    return vhost_virtqueue_pending(&vhost_crypto->dev, idx);
}

#else
uint64_t
cryptodev_vhost_get_max_queues(CryptoDevBackendVhost *crypto)
@@ -86,4 +315,33 @@ cryptodev_vhost_init(CryptoDevBackendVhostOptions *options)
{
    return NULL;
}

CryptoDevBackendVhost *
cryptodev_get_vhost(CryptoDevBackendClient *cc,
                    CryptoDevBackend *b,
                    uint16_t queue)
{
    return NULL;
}

int cryptodev_vhost_start(VirtIODevice *dev, int total_queues)
{
    return -1;
}

void cryptodev_vhost_stop(VirtIODevice *dev, int total_queues)
{
}

void cryptodev_vhost_virtqueue_mask(VirtIODevice *dev,
                                    int queue,
                                    int idx, bool mask)
{
}

bool cryptodev_vhost_virtqueue_pending(VirtIODevice *dev,
                                       int queue, int idx)
{
    return false;
}
#endif
+70 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include "hw/virtio/virtio-crypto.h"
#include "hw/virtio/virtio-access.h"
#include "standard-headers/linux/virtio_ids.h"
#include "sysemu/cryptodev-vhost.h"

#define VIRTIO_CRYPTO_VM_VERSION 1

@@ -880,6 +881,72 @@ static void virtio_crypto_get_config(VirtIODevice *vdev, uint8_t *config)
    memcpy(config, &crypto_cfg, c->config_size);
}

static bool virtio_crypto_started(VirtIOCrypto *c, uint8_t status)
{
    VirtIODevice *vdev = VIRTIO_DEVICE(c);
    return (status & VIRTIO_CONFIG_S_DRIVER_OK) &&
        (c->status & VIRTIO_CRYPTO_S_HW_READY) && vdev->vm_running;
}

static void virtio_crypto_vhost_status(VirtIOCrypto *c, uint8_t status)
{
    VirtIODevice *vdev = VIRTIO_DEVICE(c);
    int queues = c->multiqueue ? c->max_queues : 1;
    CryptoDevBackend *b = c->cryptodev;
    CryptoDevBackendClient *cc = b->conf.peers.ccs[0];

    if (!cryptodev_get_vhost(cc, b, 0)) {
        return;
    }

    if ((virtio_crypto_started(c, status)) == !!c->vhost_started) {
        return;
    }

    if (!c->vhost_started) {
        int r;

        c->vhost_started = 1;
        r = cryptodev_vhost_start(vdev, queues);
        if (r < 0) {
            error_report("unable to start vhost crypto: %d: "
                         "falling back on userspace virtio", -r);
            c->vhost_started = 0;
        }
    } else {
        cryptodev_vhost_stop(vdev, queues);
        c->vhost_started = 0;
    }
}

static void virtio_crypto_set_status(VirtIODevice *vdev, uint8_t status)
{
    VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev);

    virtio_crypto_vhost_status(vcrypto, status);
}

static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx,
                                           bool mask)
{
    VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev);
    int queue = virtio_crypto_vq2q(idx);

    assert(vcrypto->vhost_started);

    cryptodev_vhost_virtqueue_mask(vdev, queue, idx, mask);
}

static bool virtio_crypto_guest_notifier_pending(VirtIODevice *vdev, int idx)
{
    VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev);
    int queue = virtio_crypto_vq2q(idx);

    assert(vcrypto->vhost_started);

    return cryptodev_vhost_virtqueue_pending(vdev, queue, idx);
}

static void virtio_crypto_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
@@ -893,6 +960,9 @@ static void virtio_crypto_class_init(ObjectClass *klass, void *data)
    vdc->get_config = virtio_crypto_get_config;
    vdc->get_features = virtio_crypto_get_features;
    vdc->reset = virtio_crypto_reset;
    vdc->set_status = virtio_crypto_set_status;
    vdc->guest_notifier_mask = virtio_crypto_guest_notifier_mask;
    vdc->guest_notifier_pending = virtio_crypto_guest_notifier_pending;
}

static void virtio_crypto_instance_init(Object *obj)
+1 −0
Original line number Diff line number Diff line
@@ -96,6 +96,7 @@ typedef struct VirtIOCrypto {
    int multiqueue;
    uint32_t curr_queues;
    size_t config_size;
    uint8_t vhost_started;
} VirtIOCrypto;

#endif /* _QEMU_VIRTIO_CRYPTO_H */
Loading