diff mbox

[v1,02/14] crypto: introduce crypto queue handler

Message ID 1473306156-176628-3-git-send-email-arei.gonglei@huawei.com (mailing list archive)
State New, archived
Headers show

Commit Message

Gonglei (Arei) Sept. 8, 2016, 3:42 a.m. UTC
crypto queue is a gallery used for executing crypto
operation, which supports both synchronization and
asynchronization. The thoughts stolen from net/queue.c

Signed-off-by: Gonglei <arei.gonglei@huawei.com>
---
 crypto/Makefile.objs          |   1 +
 crypto/crypto-queue.c         | 205 ++++++++++++++++++++++++++++++++++++++++++
 crypto/crypto.c               |  28 ++++++
 include/crypto/crypto-queue.h |  69 ++++++++++++++
 include/crypto/crypto.h       |  12 +++
 5 files changed, 315 insertions(+)
 create mode 100644 crypto/crypto-queue.c
 create mode 100644 include/crypto/crypto-queue.h
diff mbox

Patch

diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs
index 2a63cb8..652b429 100644
--- a/crypto/Makefile.objs
+++ b/crypto/Makefile.objs
@@ -27,6 +27,7 @@  crypto-obj-y += block.o
 crypto-obj-y += block-qcow.o
 crypto-obj-y += block-luks.o
 crypto-obj-y += crypto.o
+crypto-obj-y += crypto-queue.o
 
 # Let the userspace emulators avoid linking gnutls/etc
 crypto-aes-obj-y = aes.o
diff --git a/crypto/crypto-queue.c b/crypto/crypto-queue.c
new file mode 100644
index 0000000..0d5be02
--- /dev/null
+++ b/crypto/crypto-queue.c
@@ -0,0 +1,205 @@ 
+/*
+ * Queue management for crypto device (based on net/qeueu.c)
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * Authors:
+ *    Gonglei <arei.gonglei@huawei.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "crypto/crypto-queue.h"
+#include "crypto/crypto.h"
+#include "qemu/queue.h"
+
+
+/* The delivery handler may only return zero if it will call
+ * qemu_crypto_queue_flush() when it determines that it is once again able
+ * to deliver packets. It must also call qemu_crypto_queue_purge() in its
+ * cleanup path.
+ *
+ * If a sent callback is provided to send(), the caller must handle a
+ * zero return from the delivery handler by not sending any more packets
+ * until we have invoked the callback. Only in that case will we queue
+ * the packet.
+ *
+ * If a sent callback isn't provided, we just drop the packet to avoid
+ * unbounded queueing.
+ */
+
+struct CryptoPacket {
+    QTAILQ_ENTRY(CryptoPacket) entry;
+    CryptoClientState *sender;
+    unsigned flags; /* algorithms' type etc. */
+    CryptoPacketSent *sent_cb; /* callback after packet sent */
+    void *opaque; /* header struct pointer of operation */
+    uint8_t data[0];
+};
+
+struct CryptoQueue {
+    void *opaque;
+    uint32_t nq_maxlen;
+    uint32_t nq_count;
+    CryptoQueueDeliverFunc *deliver;
+
+    QTAILQ_HEAD(packets, CryptoPacket) packets;
+
+    unsigned delivering:1;
+};
+
+CryptoQueue *
+qemu_new_crypto_queue(CryptoQueueDeliverFunc *deliver, void *opaque)
+{
+    CryptoQueue *queue;
+
+    queue = g_new0(CryptoQueue, 1);
+
+    queue->opaque = opaque;
+    queue->nq_maxlen = 10000;
+    queue->nq_count = 0;
+    queue->deliver = deliver;
+
+    QTAILQ_INIT(&queue->packets);
+
+    queue->delivering = 0;
+
+    return queue;
+}
+
+void qemu_del_crypto_queue(CryptoQueue *queue)
+{
+    CryptoPacket *packet, *next;
+
+    QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) {
+        QTAILQ_REMOVE(&queue->packets, packet, entry);
+        g_free(packet);
+    }
+
+    g_free(queue);
+}
+
+void qemu_crypto_queue_cache(CryptoQueue *queue,
+                               unsigned flags,
+                               CryptoClientState *sender,
+                               void *opaque,
+                               CryptoPacketSent *sent_cb)
+{
+    CryptoPacket *packet;
+
+    if (queue->nq_count >= queue->nq_maxlen && !sent_cb) {
+        return; /* drop if queue full and no callback */
+    }
+
+    packet = g_malloc(sizeof(CryptoPacket));
+    packet->sender = sender;
+    packet->sent_cb = sent_cb;
+    packet->flags = flags,
+    packet->opaque = opaque;
+
+    queue->nq_count++;
+    QTAILQ_INSERT_TAIL(&queue->packets, packet, entry);
+}
+
+static ssize_t qemu_crypto_queue_deliver(CryptoQueue *queue,
+                                         unsigned flags,
+                                         CryptoClientState *sender,
+                                         void *opaque)
+{
+    ssize_t ret = -1;
+
+    queue->delivering = 1;
+    ret = queue->deliver(sender, flags, opaque, queue->opaque);
+    queue->delivering = 0;
+
+    return ret;
+}
+
+int qemu_crypto_queue_send(CryptoQueue *queue,
+                            unsigned flags,
+                            CryptoClientState *sender,
+                            void *opaque,
+                            CryptoPacketSent *sent_cb)
+{
+    int ret;
+
+    if (queue->delivering) {
+        qemu_crypto_queue_cache(queue, flags, sender,
+                                opaque, sent_cb);
+        return 0;
+    }
+
+    ret = qemu_crypto_queue_deliver(queue, flags, sender, opaque);
+    if (ret == 0) {
+        qemu_crypto_queue_cache(queue, flags, sender,
+                                opaque, sent_cb);
+        return 0;
+    }
+
+    qemu_crypto_queue_flush(queue);
+
+    return ret;
+}
+
+void qemu_crypto_queue_purge(CryptoQueue *queue, CryptoClientState *from)
+{
+    CryptoPacket *packet, *next;
+
+    QTAILQ_FOREACH_SAFE(packet, &queue->packets, entry, next) {
+        if (packet->sender == from) {
+            QTAILQ_REMOVE(&queue->packets, packet, entry);
+            queue->nq_count--;
+            if (packet->sent_cb) {
+                packet->sent_cb(packet->sender, 0);
+            }
+            g_free(packet->opaque);
+            g_free(packet);
+        }
+    }
+}
+
+bool qemu_crypto_queue_flush(CryptoQueue *queue)
+{
+    while (!QTAILQ_EMPTY(&queue->packets)) {
+        CryptoPacket *packet;
+        int ret;
+
+        packet = QTAILQ_FIRST(&queue->packets);
+        QTAILQ_REMOVE(&queue->packets, packet, entry);
+        queue->nq_count--;
+
+        ret = qemu_crypto_queue_deliver(queue, packet->flags,
+                                        packet->sender, packet->opaque);
+        if (ret == 0) {
+            queue->nq_count++;
+            QTAILQ_INSERT_HEAD(&queue->packets, packet, entry);
+            return false;
+        }
+
+        if (packet->sent_cb) {
+            packet->sent_cb(packet->sender, ret);
+        }
+
+        g_free(packet->opaque);
+        g_free(packet);
+    }
+    return true;
+}
diff --git a/crypto/crypto.c b/crypto/crypto.c
index fbc6497..a0e4a34 100644
--- a/crypto/crypto.c
+++ b/crypto/crypto.c
@@ -151,6 +151,8 @@  static void crypto_client_setup(CryptoClientState *cc,
     }
     QTAILQ_INSERT_TAIL(&crypto_clients, cc, next);
     cc->destructor = destructor;
+    cc->incoming_queue =
+                qemu_new_crypto_queue(qemu_deliver_crypto_packet, cc);
 }
 
 CryptoClientState *new_crypto_client(CryptoClientInfo *info,
@@ -169,3 +171,29 @@  CryptoClientState *new_crypto_client(CryptoClientInfo *info,
 
     return cc;
 }
+
+int qemu_deliver_crypto_packet(CryptoClientState *sender,
+                              unsigned flags,
+                              void *header_opqaue,
+                              void *opaque)
+{
+    return 0;
+}
+
+int qemu_send_crypto_packet_async(CryptoClientState *sender,
+                                unsigned flags,
+                                void *opaque,
+                                CryptoPacketSent *sent_cb)
+{
+    CryptoQueue *queue;
+
+    if (!sender->ready) {
+        /* we assume that all packets are sent */
+        return 1;
+    }
+
+    queue = sender->peer->incoming_queue;
+
+    return qemu_crypto_queue_send(queue, flags, sender,
+                                  opaque, sent_cb);
+}
diff --git a/include/crypto/crypto-queue.h b/include/crypto/crypto-queue.h
new file mode 100644
index 0000000..6fba64d
--- /dev/null
+++ b/include/crypto/crypto-queue.h
@@ -0,0 +1,69 @@ 
+/*
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * Authors:
+ *    Gonglei <arei.gonglei@huawei.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_CRYPTO_QUEUE_H
+#define QEMU_CRYPTO_QUEUE_H
+
+#include "qemu-common.h"
+
+typedef struct CryptoPacket CryptoPacket;
+typedef struct CryptoQueue CryptoQueue;
+typedef struct CryptoPacketBuf CryptoPacketBuf;
+
+typedef void (CryptoPacketSent) (CryptoClientState *, int);
+
+
+/* Returns:
+ *   >0 - success
+ *    0 - queue packet for future redelivery
+ *   <0 - failure (discard packet)
+ */
+typedef int (CryptoQueueDeliverFunc)(CryptoClientState *sender,
+                                     unsigned flags,
+                                     void *header_opaque,
+                                     void *opaque);
+
+CryptoQueue *
+qemu_new_crypto_queue(CryptoQueueDeliverFunc *deliver, void *opaque);
+
+void qemu_crypto_queue_cache(CryptoQueue *queue,
+                               unsigned flags,
+                               CryptoClientState *sender,
+                               void *opaque,
+                               CryptoPacketSent *sent_cb);
+
+void qemu_del_crypto_queue(CryptoQueue *queue);
+
+int qemu_crypto_queue_send(CryptoQueue *queue,
+                                unsigned flags,
+                                CryptoClientState *sender,
+                                void *opaque,
+                                CryptoPacketSent *sent_cb);
+
+void qemu_crypto_queue_purge(CryptoQueue *queue, CryptoClientState *from);
+bool qemu_crypto_queue_flush(CryptoQueue *queue);
+
+#endif /* QEMU_CRYPTO_QUEUE_H */
diff --git a/include/crypto/crypto.h b/include/crypto/crypto.h
index 3734ee8..94cfc9f 100644
--- a/include/crypto/crypto.h
+++ b/include/crypto/crypto.h
@@ -30,6 +30,8 @@ 
 
 #include "qemu/queue.h"
 #include "qapi-types.h"
+#include "crypto/crypto-queue.h"
+
 
 typedef void (CryptoPoll)(CryptoClientState *, bool);
 typedef void (CryptoCleanup) (CryptoClientState *);
@@ -53,6 +55,8 @@  struct CryptoClientState {
     char *model;
     char *name;
     char info_str[256];
+    CryptoQueue *incoming_queue;
+    unsigned int queue_index;
     CryptoClientDestructor *destructor;
 };
 
@@ -63,5 +67,13 @@  CryptoClientState *new_crypto_client(CryptoClientInfo *info,
                                     CryptoClientState *peer,
                                     const char *model,
                                     const char *name);
+int qemu_deliver_crypto_packet(CryptoClientState *sender,
+                              unsigned flags,
+                              void *header_opqaue,
+                              void *opaque);
+int qemu_send_crypto_packet_async(CryptoClientState *sender,
+                                unsigned flags,
+                                void *opaque,
+                                CryptoPacketSent *sent_cb);
 
 #endif /* QCRYPTO_CRYPTO_H__ */