]> git.ipfire.org Git - thirdparty/qemu.git/commitdiff
cryptodev: add vhost support
authorGonglei <arei.gonglei@huawei.com>
Thu, 1 Mar 2018 13:46:29 +0000 (21:46 +0800)
committerMichael S. Tsirkin <mst@redhat.com>
Thu, 1 Mar 2018 16:26:17 +0000 (18:26 +0200)
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: Gonglei <arei.gonglei@huawei.com>
Signed-off-by: Longpeng(Mike) <longpeng2@huawei.com>
Signed-off-by: Jay Zhou <jianjay.zhou@huawei.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
backends/cryptodev-builtin.c
backends/cryptodev-vhost-user.c
backends/cryptodev-vhost.c
hw/virtio/virtio-crypto.c
include/hw/virtio/virtio-crypto.h
include/sysemu/cryptodev-vhost-user.h [new file with mode: 0644]
include/sysemu/cryptodev.h

index 657c0ba2f3e6a45a68036e2aafa114325554ab9c..9fb0bd57a6d7fb6553139ca442aa367a661a7e9a 100644 (file)
@@ -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 =
index 93c3f10a8f9a9b09bd99bf49b7ceceddb8646e03..151a0e6ca79fbbdfc6b7987d29dee074c16ad23a 100644 (file)
@@ -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;
 
index 27e1c4ad2591e0b6626ef87ac33954c469f0ed29..8337c9a495f0b28086d50fc303c67c929f31cfd9 100644 (file)
  */
 
 #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
index 19c82e0432528790e1eb27159e3f8a84b99b0501..9a9fa495d2d92bdbad9551da0838bd8dc7c5fad7 100644 (file)
@@ -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)
index a00a0bfabad8916e4c56b9b1f59e6e0d69605077..ca3a04938ee312a6c4e541fc1f1416cc7cb3f2be 100644 (file)
@@ -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 */
diff --git a/include/sysemu/cryptodev-vhost-user.h b/include/sysemu/cryptodev-vhost-user.h
new file mode 100644 (file)
index 0000000..937217b
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * QEMU Crypto Device Common Vhost User Implement
+ *
+ * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * Authors:
+ *    Gonglei <arei.gonglei@huawei.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef CRYPTODEV_VHOST_USER_H
+#define CRYPTODEV_VHOST_USER_H
+
+
+/**
+ * cryptodev_vhost_user_get_vhost:
+ * @cc: the client object for each queue
+ * @b: the cryptodev backend common vhost object
+ * @queue: the queue index
+ *
+ * Gets a new cryptodev backend common vhost object based on
+ * @b and @queue
+ *
+ * Returns: the cryptodev backend common vhost object
+ */
+CryptoDevBackendVhost *
+cryptodev_vhost_user_get_vhost(
+                         CryptoDevBackendClient *cc,
+                         CryptoDevBackend *b,
+                         uint16_t queue);
+
+#endif /* CRYPTODEV_VHOST_USER_H */
index a9d0d1ee25a25d1c4f90f9b6821d370178e21205..faeb6f891a471c6e1dcc78fedad87dc7060bdbc1 100644 (file)
@@ -163,12 +163,20 @@ typedef struct CryptoDevBackendClass {
                      uint32_t queue_index, Error **errp);
 } CryptoDevBackendClass;
 
+typedef enum CryptoDevBackendOptionsType {
+    CRYPTODEV_BACKEND_TYPE_NONE = 0,
+    CRYPTODEV_BACKEND_TYPE_BUILTIN = 1,
+    CRYPTODEV_BACKEND_TYPE_VHOST_USER = 2,
+    CRYPTODEV_BACKEND_TYPE__MAX,
+} CryptoDevBackendOptionsType;
 
 struct CryptoDevBackendClient {
+    CryptoDevBackendOptionsType type;
     char *model;
     char *name;
     char *info_str;
     unsigned int queue_index;
+    int vring_enable;
     QTAILQ_ENTRY(CryptoDevBackendClient) next;
 };