diff mbox

[v4,04/13] cryptodev: introduce a new cryptodev backend

Message ID 1475051152-400276-5-git-send-email-arei.gonglei@huawei.com
State New
Headers show

Commit Message

Gonglei (Arei) Sept. 28, 2016, 8:25 a.m. UTC
The new cryptodev backend named cryptodev-builtin,
which realized by QEMU cipher APIS. These APIs can
be backed by either nettle or gcrypt.

Signed-off-by: Gonglei <arei.gonglei@huawei.com>
---
 backends/Makefile.objs       |   1 +
 backends/cryptodev-builtin.c | 345 +++++++++++++++++++++++++++++++++++++++++++
 qemu-options.hx              |  18 +++
 3 files changed, 364 insertions(+)
 create mode 100644 backends/cryptodev-builtin.c

Comments

Stefan Hajnoczi Oct. 3, 2016, 4:31 p.m. UTC | #1
On Wed, Sep 28, 2016 at 04:25:43PM +0800, Gonglei wrote:
> +/* Max number of symetrical sessions */

s/symetrical/symmetric/

But why does the comment say "symetrical" when the constant name
MAX_NUM_SESSIONS seems to be a global limit for *all* sessions (not just
symmetric)?

> +#define MAX_NUM_SESSIONS 256

The guest can only have 256 sessions open?

What are the limits of real crypto libraries and accelerators?

> +
> +
> +struct QCryptoCryptoDevBackendBuiltin {
> +    QCryptoCryptoDevBackend parent_obj;
> +
> +    QCryptoCryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS];
> +};
> +
> +static void qcrypto_cryptodev_backend_builtin_init(
> +             QCryptoCryptoDevBackend *backend, Error **errp)
> +{
> +    /* Only support one queue */
> +    int queues = MAX(backend->conf.peers.queues, 1);
> +    size_t i;
> +    QCryptoCryptoDevBackendClientState *cc;
> +
> +    for (i = 0; i < queues; i++) {
> +        cc = qcrypto_cryptodev_backend_new_client(
> +                  "cryptodev-builtin", NULL);
> +        snprintf(cc->info_str, sizeof(cc->info_str),
> +                 "cryptodev-builtin%lu", i);
> +        cc->queue_index = i;
> +
> +        backend->conf.peers.ccs[i] = cc;
> +    }
> +
> +    backend->conf.crypto_services =
> +                         1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
> +                         1u << VIRTIO_CRYPTO_SERVICE_HASH |
> +                         1u << VIRTIO_CRYPTO_SERVICE_MAC;
> +    backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
> +    backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
> +}
> +
> +static int
> +qcrypto_cryptodev_backend_builtin_get_unused_session_index(
> +      QCryptoCryptoDevBackendBuiltin *builtin)
> +{
> +    size_t i;
> +
> +    for (i = 0; i < MAX_NUM_SESSIONS; i++) {
> +        if (builtin->sessions[i] == NULL) {
> +            return i;
> +        }
> +    }
> +
> +    return -1;
> +}
> +
> +static int
> +qcrypto_cryptodev_backend_builtin_get_algo(uint32_t key_len,
> +                                           Error **errp)
> +{
> +    int algo;
> +
> +    if (key_len == 128 / 8) {
> +        algo = QCRYPTO_CIPHER_ALG_AES_128;
> +    } else if (key_len == 192 / 8) {
> +        algo = QCRYPTO_CIPHER_ALG_AES_192;
> +    } else if (key_len == 256 / 8) {
> +        algo = QCRYPTO_CIPHER_ALG_AES_256;
> +    } else {
> +        error_setg(errp, "unsupported key length :%u", key_len);
> +        return -1;
> +    }
> +
> +    return algo;
> +}
> +
> +static int qcrypto_cryptodev_backend_builtin_create_cipher_session(
> +                    QCryptoCryptoDevBackendBuiltin *builtin,
> +                    QCryptoCryptoDevBackendSymSessionInfo *sess_info,
> +                    Error **errp)
> +{
> +    int algo;
> +    int mode;
> +    QCryptoCipher *cipher;
> +    int index;
> +    QCryptoCryptoDevBackendBuiltinSession *sess;
> +
> +    if (sess_info->op_type != VIRTIO_CRYPTO_SYM_OP_CIPHER) {
> +        error_setg(errp, "unsupported optype :%u", sess_info->op_type);
> +        return -1;
> +    }
> +
> +    index = qcrypto_cryptodev_backend_builtin_get_unused_session_index(builtin);

Feel free to omit the function name prefix for static functions.  These
names are very long.

> +    if (index < 0) {
> +        error_setg(errp, "the total number of created session exceed %u",

"Total number of sessions created exceeds %u"

> +                  MAX_NUM_SESSIONS);
> +        return -1;
> +    }
> +
> +    switch (sess_info->cipher_alg) {
> +    case VIRTIO_CRYPTO_CIPHER_AES_ECB:
> +        algo = qcrypto_cryptodev_backend_builtin_get_algo(sess_info->key_len,
> +                                                          errp);
> +        if (algo < 0)  {
> +            return -1;
> +        }
> +        mode = QCRYPTO_CIPHER_MODE_ECB;
> +        break;
> +    case VIRTIO_CRYPTO_CIPHER_AES_CBC:
> +        algo = qcrypto_cryptodev_backend_builtin_get_algo(sess_info->key_len,
> +                                                          errp);
> +        if (algo < 0)  {
> +            return -1;
> +        }
> +        mode = QCRYPTO_CIPHER_MODE_CBC;
> +        break;
> +    case VIRTIO_CRYPTO_CIPHER_AES_CTR:
> +        algo = qcrypto_cryptodev_backend_builtin_get_algo(sess_info->key_len,
> +                                                          errp);
> +        if (algo < 0)  {
> +            return -1;
> +        }
> +        mode = QCRYPTO_CIPHER_MODE_CTR;
> +        break;
> +    default:
> +        error_setg(errp, "unsupported cipher alg :%u",
> +                   sess_info->cipher_alg);
> +        return -1;
> +    }

Code duplication can be eliminated:

switch (sess_info->cipher_alg) {
case VIRTIO_CRYPTO_CIPHER_AES_ECB:
    mode = QCRYPTO_CIPHER_MODE_ECB;
    break;
...
}

algo = qcrypto_cryptodev_backend_builtin_get_algo(sess_info->key_len,
                                                  errp);
if (algo < 0) {
    return -1;
}

> +static void qcrypto_cryptodev_backend_builtin_cleanup(
> +             QCryptoCryptoDevBackend *backend,
> +             Error **errp)
> +{
> +    QCryptoCryptoDevBackendBuiltin *builtin =
> +                      QCRYPTO_CRYPTODEV_BACKEND_BUILTIN(backend);
> +    size_t i;
> +    int queues = backend->conf.peers.queues;
> +    QCryptoCryptoDevBackendClientState *cc;
> +
> +    for (i = 0; i < MAX_NUM_SESSIONS; i++) {
> +        if (builtin->sessions[i] != NULL) {
> +            qcrypto_cryptodev_backend_builtin_sym_close_session(
> +                    backend, i, 0, errp);
> +        }
> +    }
> +
> +    for (i = 0; i < queues; i++) {

This device doesn't seem to support queues because queue_index is
ignored by all functions that take it.

Perhaps there should be an error if the device is realized with more
than 1 queue?
Gonglei (Arei) Oct. 5, 2016, 3:19 a.m. UTC | #2
> -----Original Message-----
> From: Stefan Hajnoczi [mailto:stefanha@redhat.com]
> Sent: Tuesday, October 04, 2016 12:32 AM
> Subject: Re: [PATCH v4 04/13] cryptodev: introduce a new cryptodev backend
> 
> On Wed, Sep 28, 2016 at 04:25:43PM +0800, Gonglei wrote:
> > +/* Max number of symetrical sessions */
> 
> s/symetrical/symmetric/
> 
> But why does the comment say "symetrical" when the constant name
> MAX_NUM_SESSIONS seems to be a global limit for *all* sessions (not just
> symmetric)?
> 
> > +#define MAX_NUM_SESSIONS 256
> 
> The guest can only have 256 sessions open?
> 
For cipher API backend, it's a experimental cryptodev backend, which
can't be applied in production environment because of the poor performance. 
The limit is just for simplifying code logic, of course we can increase the number
as well, but it doesn't necessary IMO.

> What are the limits of real crypto libraries and accelerators?
> 
The hardware accelerators maybe have a limit, for example the
Intel QAT pmd driver in DPDK limit the maximum num of session is 2048.

> > +
> > +
> > +struct QCryptoCryptoDevBackendBuiltin {
> > +    QCryptoCryptoDevBackend parent_obj;
> > +
> > +    QCryptoCryptoDevBackendBuiltinSession
> *sessions[MAX_NUM_SESSIONS];
> > +};
> > +
> > +static void qcrypto_cryptodev_backend_builtin_init(
> > +             QCryptoCryptoDevBackend *backend, Error **errp)
> > +{
> > +    /* Only support one queue */
> > +    int queues = MAX(backend->conf.peers.queues, 1);
> > +    size_t i;
> > +    QCryptoCryptoDevBackendClientState *cc;
> > +
> > +    for (i = 0; i < queues; i++) {
> > +        cc = qcrypto_cryptodev_backend_new_client(
> > +                  "cryptodev-builtin", NULL);
> > +        snprintf(cc->info_str, sizeof(cc->info_str),
> > +                 "cryptodev-builtin%lu", i);
> > +        cc->queue_index = i;
> > +
> > +        backend->conf.peers.ccs[i] = cc;
> > +    }
> > +
> > +    backend->conf.crypto_services =
> > +                         1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
> > +                         1u << VIRTIO_CRYPTO_SERVICE_HASH |
> > +                         1u << VIRTIO_CRYPTO_SERVICE_MAC;
> > +    backend->conf.cipher_algo_l = 1u <<
> VIRTIO_CRYPTO_CIPHER_AES_CBC;
> > +    backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
> > +}
> > +
> > +static int
> > +qcrypto_cryptodev_backend_builtin_get_unused_session_index(
> > +      QCryptoCryptoDevBackendBuiltin *builtin)
> > +{
> > +    size_t i;
> > +
> > +    for (i = 0; i < MAX_NUM_SESSIONS; i++) {
> > +        if (builtin->sessions[i] == NULL) {
> > +            return i;
> > +        }
> > +    }
> > +
> > +    return -1;
> > +}
> > +
> > +static int
> > +qcrypto_cryptodev_backend_builtin_get_algo(uint32_t key_len,
> > +                                           Error **errp)
> > +{
> > +    int algo;
> > +
> > +    if (key_len == 128 / 8) {
> > +        algo = QCRYPTO_CIPHER_ALG_AES_128;
> > +    } else if (key_len == 192 / 8) {
> > +        algo = QCRYPTO_CIPHER_ALG_AES_192;
> > +    } else if (key_len == 256 / 8) {
> > +        algo = QCRYPTO_CIPHER_ALG_AES_256;
> > +    } else {
> > +        error_setg(errp, "unsupported key length :%u", key_len);
> > +        return -1;
> > +    }
> > +
> > +    return algo;
> > +}
> > +
> > +static int qcrypto_cryptodev_backend_builtin_create_cipher_session(
> > +                    QCryptoCryptoDevBackendBuiltin *builtin,
> > +                    QCryptoCryptoDevBackendSymSessionInfo
> *sess_info,
> > +                    Error **errp)
> > +{
> > +    int algo;
> > +    int mode;
> > +    QCryptoCipher *cipher;
> > +    int index;
> > +    QCryptoCryptoDevBackendBuiltinSession *sess;
> > +
> > +    if (sess_info->op_type != VIRTIO_CRYPTO_SYM_OP_CIPHER) {
> > +        error_setg(errp, "unsupported optype :%u", sess_info->op_type);
> > +        return -1;
> > +    }
> > +
> > +    index =
> qcrypto_cryptodev_backend_builtin_get_unused_session_index(builtin);
> 
> Feel free to omit the function name prefix for static functions.  These
> names are very long.
> 
> > +    if (index < 0) {
> > +        error_setg(errp, "the total number of created session
> exceed %u",
> 
> "Total number of sessions created exceeds %u"
> 
> > +                  MAX_NUM_SESSIONS);
> > +        return -1;
> > +    }
> > +
> > +    switch (sess_info->cipher_alg) {
> > +    case VIRTIO_CRYPTO_CIPHER_AES_ECB:
> > +        algo =
> qcrypto_cryptodev_backend_builtin_get_algo(sess_info->key_len,
> > +
> errp);
> > +        if (algo < 0)  {
> > +            return -1;
> > +        }
> > +        mode = QCRYPTO_CIPHER_MODE_ECB;
> > +        break;
> > +    case VIRTIO_CRYPTO_CIPHER_AES_CBC:
> > +        algo =
> qcrypto_cryptodev_backend_builtin_get_algo(sess_info->key_len,
> > +
> errp);
> > +        if (algo < 0)  {
> > +            return -1;
> > +        }
> > +        mode = QCRYPTO_CIPHER_MODE_CBC;
> > +        break;
> > +    case VIRTIO_CRYPTO_CIPHER_AES_CTR:
> > +        algo =
> qcrypto_cryptodev_backend_builtin_get_algo(sess_info->key_len,
> > +
> errp);
> > +        if (algo < 0)  {
> > +            return -1;
> > +        }
> > +        mode = QCRYPTO_CIPHER_MODE_CTR;
> > +        break;
> > +    default:
> > +        error_setg(errp, "unsupported cipher alg :%u",
> > +                   sess_info->cipher_alg);
> > +        return -1;
> > +    }
> 
> Code duplication can be eliminated:
> 
> switch (sess_info->cipher_alg) {
> case VIRTIO_CRYPTO_CIPHER_AES_ECB:
>     mode = QCRYPTO_CIPHER_MODE_ECB;
>     break;
> ...
> }
> 
> algo = qcrypto_cryptodev_backend_builtin_get_algo(sess_info->key_len,
>                                                   errp);
> if (algo < 0) {
>     return -1;
> }
> 
Make sense. :)

> > +static void qcrypto_cryptodev_backend_builtin_cleanup(
> > +             QCryptoCryptoDevBackend *backend,
> > +             Error **errp)
> > +{
> > +    QCryptoCryptoDevBackendBuiltin *builtin =
> > +
> QCRYPTO_CRYPTODEV_BACKEND_BUILTIN(backend);
> > +    size_t i;
> > +    int queues = backend->conf.peers.queues;
> > +    QCryptoCryptoDevBackendClientState *cc;
> > +
> > +    for (i = 0; i < MAX_NUM_SESSIONS; i++) {
> > +        if (builtin->sessions[i] != NULL) {
> > +            qcrypto_cryptodev_backend_builtin_sym_close_session(
> > +                    backend, i, 0, errp);
> > +        }
> > +    }
> > +
> > +    for (i = 0; i < queues; i++) {
> 
> This device doesn't seem to support queues because queue_index is
> ignored by all functions that take it.
> 
> Perhaps there should be an error if the device is realized with more
> than 1 queue?

Yes, we can add the check for cryptodev-builtin backend.


Regards,
-Gonglei
Stefan Hajnoczi Oct. 5, 2016, 12:53 p.m. UTC | #3
On Wed, Oct 05, 2016 at 03:19:44AM +0000, Gonglei (Arei) wrote:
> > -----Original Message-----
> > From: Stefan Hajnoczi [mailto:stefanha@redhat.com]
> > Sent: Tuesday, October 04, 2016 12:32 AM
> > Subject: Re: [PATCH v4 04/13] cryptodev: introduce a new cryptodev backend
> > 
> > On Wed, Sep 28, 2016 at 04:25:43PM +0800, Gonglei wrote:
> > > +/* Max number of symetrical sessions */
> > 
> > s/symetrical/symmetric/
> > 
> > But why does the comment say "symetrical" when the constant name
> > MAX_NUM_SESSIONS seems to be a global limit for *all* sessions (not just
> > symmetric)?
> > 
> > > +#define MAX_NUM_SESSIONS 256
> > 
> > The guest can only have 256 sessions open?
> > 
> For cipher API backend, it's a experimental cryptodev backend, which
> can't be applied in production environment because of the poor performance. 
> The limit is just for simplifying code logic, of course we can increase the number
> as well, but it doesn't necessary IMO.
> 
> > What are the limits of real crypto libraries and accelerators?
> > 
> The hardware accelerators maybe have a limit, for example the
> Intel QAT pmd driver in DPDK limit the maximum num of session is 2048.

How do we prevent competing guests from creating idle sessions ahead of
time in order to "reserve" them?

Greedy guests could prevent other guests from creating sessions if the
hardware limit is 2048.

Perhaps the max sessions limit should be a user parameter so the host
administrator use it to guarantee session availability.
diff mbox

Patch

diff --git a/backends/Makefile.objs b/backends/Makefile.objs
index 55bd43d..1846998 100644
--- a/backends/Makefile.objs
+++ b/backends/Makefile.objs
@@ -11,3 +11,4 @@  common-obj-y += hostmem.o hostmem-ram.o
 common-obj-$(CONFIG_LINUX) += hostmem-file.o
 
 common-obj-y += cryptodev.o
+common-obj-y += cryptodev-builtin.o
diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c
new file mode 100644
index 0000000..22fbe84
--- /dev/null
+++ b/backends/cryptodev-builtin.c
@@ -0,0 +1,345 @@ 
+/*
+ * QEMU Cryptodev backend for QEMU cipher APIs
+ *
+ * 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/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "sysemu/cryptodev.h"
+#include "hw/boards.h"
+#include "qapi/error.h"
+#include "standard-headers/linux/virtio_crypto.h"
+#include "crypto/cipher.h"
+
+
+/**
+ * @TYPE_QCRYPTO_CRYPTODEV_BACKEND_BUILTIN:
+ * name of backend that uses QEMU cipher API
+ */
+#define TYPE_QCRYPTO_CRYPTODEV_BACKEND_BUILTIN "cryptodev-backend-builtin"
+
+#define QCRYPTO_CRYPTODEV_BACKEND_BUILTIN(obj) \
+    OBJECT_CHECK(QCryptoCryptoDevBackendBuiltin, \
+                 (obj), TYPE_QCRYPTO_CRYPTODEV_BACKEND_BUILTIN)
+
+typedef struct QCryptoCryptoDevBackendBuiltin
+                         QCryptoCryptoDevBackendBuiltin;
+
+typedef struct QCryptoCryptoDevBackendBuiltinSession {
+    QCryptoCipher *cipher;
+    uint8_t direction; /* encryption or decryption */
+    uint8_t type; /* cipher? hash? aead? */
+    QTAILQ_ENTRY(QCryptoCryptoDevBackendBuiltinSession) next;
+} QCryptoCryptoDevBackendBuiltinSession;
+
+/* Max number of symetrical sessions */
+#define MAX_NUM_SESSIONS 256
+
+
+struct QCryptoCryptoDevBackendBuiltin {
+    QCryptoCryptoDevBackend parent_obj;
+
+    QCryptoCryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS];
+};
+
+static void qcrypto_cryptodev_backend_builtin_init(
+             QCryptoCryptoDevBackend *backend, Error **errp)
+{
+    /* Only support one queue */
+    int queues = MAX(backend->conf.peers.queues, 1);
+    size_t i;
+    QCryptoCryptoDevBackendClientState *cc;
+
+    for (i = 0; i < queues; i++) {
+        cc = qcrypto_cryptodev_backend_new_client(
+                  "cryptodev-builtin", NULL);
+        snprintf(cc->info_str, sizeof(cc->info_str),
+                 "cryptodev-builtin%lu", i);
+        cc->queue_index = i;
+
+        backend->conf.peers.ccs[i] = cc;
+    }
+
+    backend->conf.crypto_services =
+                         1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
+                         1u << VIRTIO_CRYPTO_SERVICE_HASH |
+                         1u << VIRTIO_CRYPTO_SERVICE_MAC;
+    backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
+    backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
+}
+
+static int
+qcrypto_cryptodev_backend_builtin_get_unused_session_index(
+      QCryptoCryptoDevBackendBuiltin *builtin)
+{
+    size_t i;
+
+    for (i = 0; i < MAX_NUM_SESSIONS; i++) {
+        if (builtin->sessions[i] == NULL) {
+            return i;
+        }
+    }
+
+    return -1;
+}
+
+static int
+qcrypto_cryptodev_backend_builtin_get_algo(uint32_t key_len,
+                                           Error **errp)
+{
+    int algo;
+
+    if (key_len == 128 / 8) {
+        algo = QCRYPTO_CIPHER_ALG_AES_128;
+    } else if (key_len == 192 / 8) {
+        algo = QCRYPTO_CIPHER_ALG_AES_192;
+    } else if (key_len == 256 / 8) {
+        algo = QCRYPTO_CIPHER_ALG_AES_256;
+    } else {
+        error_setg(errp, "unsupported key length :%u", key_len);
+        return -1;
+    }
+
+    return algo;
+}
+
+static int qcrypto_cryptodev_backend_builtin_create_cipher_session(
+                    QCryptoCryptoDevBackendBuiltin *builtin,
+                    QCryptoCryptoDevBackendSymSessionInfo *sess_info,
+                    Error **errp)
+{
+    int algo;
+    int mode;
+    QCryptoCipher *cipher;
+    int index;
+    QCryptoCryptoDevBackendBuiltinSession *sess;
+
+    if (sess_info->op_type != VIRTIO_CRYPTO_SYM_OP_CIPHER) {
+        error_setg(errp, "unsupported optype :%u", sess_info->op_type);
+        return -1;
+    }
+
+    index = qcrypto_cryptodev_backend_builtin_get_unused_session_index(builtin);
+    if (index < 0) {
+        error_setg(errp, "the total number of created session exceed %u",
+                  MAX_NUM_SESSIONS);
+        return -1;
+    }
+
+    switch (sess_info->cipher_alg) {
+    case VIRTIO_CRYPTO_CIPHER_AES_ECB:
+        algo = qcrypto_cryptodev_backend_builtin_get_algo(sess_info->key_len,
+                                                          errp);
+        if (algo < 0)  {
+            return -1;
+        }
+        mode = QCRYPTO_CIPHER_MODE_ECB;
+        break;
+    case VIRTIO_CRYPTO_CIPHER_AES_CBC:
+        algo = qcrypto_cryptodev_backend_builtin_get_algo(sess_info->key_len,
+                                                          errp);
+        if (algo < 0)  {
+            return -1;
+        }
+        mode = QCRYPTO_CIPHER_MODE_CBC;
+        break;
+    case VIRTIO_CRYPTO_CIPHER_AES_CTR:
+        algo = qcrypto_cryptodev_backend_builtin_get_algo(sess_info->key_len,
+                                                          errp);
+        if (algo < 0)  {
+            return -1;
+        }
+        mode = QCRYPTO_CIPHER_MODE_CTR;
+        break;
+    default:
+        error_setg(errp, "unsupported cipher alg :%u",
+                   sess_info->cipher_alg);
+        return -1;
+    }
+
+    cipher = qcrypto_cipher_new(algo, mode,
+                               sess_info->cipher_key,
+                               sess_info->key_len,
+                               errp);
+    if (!cipher) {
+        return -1;
+    }
+
+    sess = g_new0(QCryptoCryptoDevBackendBuiltinSession, 1);
+    sess->cipher = cipher;
+    sess->direction = sess_info->direction;
+    sess->type = sess_info->op_type;
+
+    builtin->sessions[index] = sess;
+
+    return index;
+}
+
+static int64_t qcrypto_cryptodev_backend_builtin_sym_create_session(
+           QCryptoCryptoDevBackend *backend,
+           QCryptoCryptoDevBackendSymSessionInfo *sess_info,
+           uint32_t queue_index, Error **errp)
+{
+    QCryptoCryptoDevBackendBuiltin *builtin =
+                      QCRYPTO_CRYPTODEV_BACKEND_BUILTIN(backend);
+    int64_t session_id = -1;
+    int ret;
+
+    switch (sess_info->op_code) {
+    case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
+        ret = qcrypto_cryptodev_backend_builtin_create_cipher_session(
+                           builtin, sess_info, errp);
+        if (ret < 0) {
+            return ret;
+        } else {
+            session_id = ret;
+        }
+        break;
+    case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
+    case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
+    default:
+        error_setg(errp, "unsupported opcode :%" PRIu32 "",
+                   sess_info->op_code);
+        return -1;
+    }
+
+    return session_id;
+}
+
+static int qcrypto_cryptodev_backend_builtin_sym_close_session(
+           QCryptoCryptoDevBackend *backend,
+           uint64_t session_id,
+           uint32_t queue_index, Error **errp)
+{
+    QCryptoCryptoDevBackendBuiltin *builtin =
+                      QCRYPTO_CRYPTODEV_BACKEND_BUILTIN(backend);
+
+    if (session_id >= MAX_NUM_SESSIONS ||
+              builtin->sessions[session_id] == NULL) {
+        error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
+                      session_id);
+        return -1;
+    }
+
+    qcrypto_cipher_free(builtin->sessions[session_id]->cipher);
+    g_free(builtin->sessions[session_id]);
+    builtin->sessions[session_id] = NULL;
+    return 0;
+}
+
+static int qcrypto_cryptodev_backend_builtin_sym_operation(
+                 QCryptoCryptoDevBackend *backend,
+                 QCryptoCryptoDevBackendSymOpInfo *op_info,
+                 uint32_t queue_index, Error **errp)
+{
+    QCryptoCryptoDevBackendBuiltin *builtin =
+                      QCRYPTO_CRYPTODEV_BACKEND_BUILTIN(backend);
+    QCryptoCryptoDevBackendBuiltinSession *sess;
+    int ret;
+
+    if (op_info->session_id >= MAX_NUM_SESSIONS ||
+              builtin->sessions[op_info->session_id] == NULL) {
+        error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
+                   op_info->session_id);
+        return -VIRTIO_CRYPTO_INVSESS;
+    }
+
+    sess = builtin->sessions[op_info->session_id];
+
+    ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv,
+                               op_info->iv_len, errp);
+    if (ret < 0) {
+        return -VIRTIO_CRYPTO_ERR;
+    }
+
+    if (sess->direction == VIRTIO_CRYPTO_OP_ENCRYPT) {
+        ret = qcrypto_cipher_encrypt(sess->cipher, op_info->src,
+                                     op_info->dst, op_info->src_len, errp);
+        if (ret < 0) {
+            return -VIRTIO_CRYPTO_ERR;
+        }
+    } else {
+        ret = qcrypto_cipher_decrypt(sess->cipher, op_info->src,
+                                     op_info->dst, op_info->src_len, errp);
+        if (ret < 0) {
+            return -VIRTIO_CRYPTO_ERR;
+        }
+    }
+    return 0;
+}
+
+static void qcrypto_cryptodev_backend_builtin_cleanup(
+             QCryptoCryptoDevBackend *backend,
+             Error **errp)
+{
+    QCryptoCryptoDevBackendBuiltin *builtin =
+                      QCRYPTO_CRYPTODEV_BACKEND_BUILTIN(backend);
+    size_t i;
+    int queues = backend->conf.peers.queues;
+    QCryptoCryptoDevBackendClientState *cc;
+
+    for (i = 0; i < MAX_NUM_SESSIONS; i++) {
+        if (builtin->sessions[i] != NULL) {
+            qcrypto_cryptodev_backend_builtin_sym_close_session(
+                    backend, i, 0, errp);
+        }
+    }
+
+    for (i = 0; i < queues; i++) {
+        cc = backend->conf.peers.ccs[i];
+        if (cc) {
+            qcrypto_cryptodev_backend_free_client(cc);
+            backend->conf.peers.ccs[i] = NULL;
+        }
+    }
+}
+
+static void qcrypto_cryptodev_backend_builtin_finalize(Object *obj)
+{
+
+}
+
+static void
+qcrypto_cryptodev_backend_builtin_class_init(ObjectClass *oc, void *data)
+{
+    QCryptoCryptoDevBackendClass *bc = QCRYPTO_CRYPTODEV_BACKEND_CLASS(oc);
+
+    bc->init = qcrypto_cryptodev_backend_builtin_init;
+    bc->cleanup = qcrypto_cryptodev_backend_builtin_cleanup;
+    bc->create_session = qcrypto_cryptodev_backend_builtin_sym_create_session;
+    bc->close_session = qcrypto_cryptodev_backend_builtin_sym_close_session;
+    bc->do_sym_op = qcrypto_cryptodev_backend_builtin_sym_operation;
+}
+
+static const TypeInfo qcrypto_cryptodev_backend_builtin_info = {
+    .name = TYPE_QCRYPTO_CRYPTODEV_BACKEND_BUILTIN,
+    .parent = TYPE_QCRYPTO_CRYPTODEV_BACKEND,
+    .class_init = qcrypto_cryptodev_backend_builtin_class_init,
+    .instance_finalize = qcrypto_cryptodev_backend_builtin_finalize,
+    .instance_size = sizeof(QCryptoCryptoDevBackendBuiltin),
+};
+
+static void
+qcrypto_cryptodev_backend_builtin_register_types(void)
+{
+    type_register_static(&qcrypto_cryptodev_backend_builtin_info);
+}
+
+type_init(qcrypto_cryptodev_backend_builtin_register_types);
diff --git a/qemu-options.hx b/qemu-options.hx
index 01f01df..616cd30 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3948,6 +3948,24 @@  secondary:
 If you want to know the detail of above command line, you can read
 the colo-compare git log.
 
+@item -object cryptodev-backend-builtin,id=@var{id}[,queues=@var{queues}]
+
+Creates a cryptodev backend which executes crypto opreation from
+the QEMU cipher APIS. The @var{id} parameter is
+a unique ID that will be used to reference this cryptodev backend from
+the @option{virtio-crypto} device. The @var{queues} parameter is optional,
+which specify the queue number of cryptodev backend, the default of
+@var{queues} is 1.
+
+@example
+
+ # qemu-system-x86_64 \
+   [...] \
+       -object cryptodev-backend-builtin,id=cryptodev0 \
+       -device virtio-crypto-pci,id=crypto0,cryptodev=cryptodev0 \
+   [...]
+@end example
+
 @item -object secret,id=@var{id},data=@var{string},format=@var{raw|base64}[,keyid=@var{secretid},iv=@var{string}]
 @item -object secret,id=@var{id},file=@var{filename},format=@var{raw|base64}[,keyid=@var{secretid},iv=@var{string}]