From patchwork Mon Oct 10 08:43:38 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gonglei (Arei)" X-Patchwork-Id: 9369141 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 7D35A607FD for ; Mon, 10 Oct 2016 08:45:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6E46E28FDC for ; Mon, 10 Oct 2016 08:45:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 62A92293B8; Mon, 10 Oct 2016 08:45:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 5C20328FDC for ; Mon, 10 Oct 2016 08:45:29 +0000 (UTC) Received: from localhost ([::1]:48109 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1btWDA-0004xF-Co for patchwork-qemu-devel@patchwork.kernel.org; Mon, 10 Oct 2016 04:45:28 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45206) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1btWCd-0004vJ-6N for qemu-devel@nongnu.org; Mon, 10 Oct 2016 04:44:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1btWCa-0007vj-VH for qemu-devel@nongnu.org; Mon, 10 Oct 2016 04:44:54 -0400 Received: from szxga02-in.huawei.com ([119.145.14.65]:59079) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1btWCZ-0007sS-Mg for qemu-devel@nongnu.org; Mon, 10 Oct 2016 04:44:52 -0400 Received: from 172.24.1.36 (EHLO szxeml431-hub.china.huawei.com) ([172.24.1.36]) by szxrg02-dlp.huawei.com (MOS 4.3.7-GA FastPath queued) with ESMTP id DOJ71768; Mon, 10 Oct 2016 16:44:00 +0800 (CST) Received: from localhost (10.177.18.62) by szxeml431-hub.china.huawei.com (10.82.67.208) with Microsoft SMTP Server id 14.3.235.1; Mon, 10 Oct 2016 16:43:53 +0800 From: Gonglei To: , Date: Mon, 10 Oct 2016 16:43:38 +0800 Message-ID: <1476089024-68684-7-git-send-email-arei.gonglei@huawei.com> X-Mailer: git-send-email 2.6.3.windows.1 In-Reply-To: <1476089024-68684-1-git-send-email-arei.gonglei@huawei.com> References: <1476089024-68684-1-git-send-email-arei.gonglei@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.177.18.62] X-CFilter-Loop: Reflected X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4.x-2.6.x [generic] X-Received-From: 119.145.14.65 Subject: [Qemu-devel] [PATCH v6 06/12] virtio-crypto: add control queue handler X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: weidong.huang@huawei.com, claudio.fontana@huawei.com, mst@redhat.com, xin.zeng@intel.com, hanweidong@huawei.com, luonengjun@huawei.com, agraf@suse.de, nmorey@kalray.eu, mike.caraman@nxp.com, Gonglei , stefanha@redhat.com, jianjay.zhou@huawei.com, pbonzini@redhat.com, peter.huangpeng@huawei.com, vincent.jardin@6wind.com, wu.wubin@huawei.com, arei.gonglei@hotmail.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Realize the symmetric algorithm control queue handler, including plain cipher and chainning algorithms. Currently the control queue is used to create and close session for symmetric algorithm. Signed-off-by: Gonglei --- hw/virtio/virtio-crypto.c | 285 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 284 insertions(+), 1 deletion(-) diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index e2bc90e..98a7d60 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -23,6 +23,289 @@ #define VIRTIO_CRYPTO_VM_VERSION 1 +/* + * Transfer virtqueue index to crypto queue index. + * The control virtqueue is after the data virtqueues + * so the input value doesn't need to be adjusted + */ +static inline int virtio_crypto_vq2q(int queue_index) +{ + return queue_index; +} + +static int +virtio_crypto_cipher_session_helper(VirtIODevice *vdev, + CryptoDevBackendSymSessionInfo *info, + struct virtio_crypto_cipher_session_para *cipher_para, + struct iovec **iov, unsigned int *out_num) +{ + unsigned int num = *out_num; + + info->cipher_alg = virtio_ldl_p(vdev, &cipher_para->algo); + info->key_len = virtio_ldl_p(vdev, &cipher_para->keylen); + info->direction = virtio_ldl_p(vdev, &cipher_para->op); + DPRINTF("cipher_alg=%" PRIu32 ", info->direction=%" PRIu32 "\n", + info->cipher_alg, info->direction); + /* Get cipher key */ + if (info->key_len > 0) { + size_t s; + DPRINTF("keylen=%" PRIu32 "\n", info->key_len); + + info->cipher_key = g_malloc(info->key_len); + s = iov_to_buf(*iov, num, 0, info->cipher_key, info->key_len); + if (unlikely(s != info->key_len)) { + virtio_error(vdev, "virtio-crypto cipher key incorrect"); + return -EFAULT; + } + iov_discard_front(iov, &num, info->key_len); + *out_num = num; + } + + return 0; +} + +static int64_t +virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto, + struct virtio_crypto_sym_create_session_req *sess_req, + uint32_t queue_id, + uint32_t opcode, + struct iovec *iov, unsigned int out_num) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); + CryptoDevBackendSymSessionInfo info; + int64_t session_id; + int queue_index; + uint32_t op_type; + Error *local_err = NULL; + int ret; + + memset(&info, 0, sizeof(info)); + op_type = virtio_ldl_p(vdev, &sess_req->op_type); + info.op_type = op_type; + info.op_code = opcode; + + if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) { + ret = virtio_crypto_cipher_session_helper(vdev, &info, + &sess_req->u.cipher.para, + &iov, &out_num); + if (ret < 0) { + return -EFAULT; + } + } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { + size_t s; + /* cipher part */ + ret = virtio_crypto_cipher_session_helper(vdev, &info, + &sess_req->u.chain.para.cipher_param, + &iov, &out_num); + if (ret < 0) { + return -EFAULT; + } + /* hash part */ + info.alg_chain_order = virtio_ldl_p(vdev, + &sess_req->u.chain.para.alg_chain_order); + info.add_len = virtio_ldl_p(vdev, &sess_req->u.chain.para.aad_len); + info.hash_mode = virtio_ldl_p(vdev, &sess_req->u.chain.para.hash_mode); + if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) { + info.hash_alg = virtio_ldl_p(vdev, + &sess_req->u.chain.para.u.mac_param.algo); + info.auth_key_len = virtio_ldl_p(vdev, + &sess_req->u.chain.para.u.mac_param.auth_key_len); + info.hash_result_len = virtio_ldl_p(vdev, + &sess_req->u.chain.para.u.mac_param.hash_result_len); + /* get auth key */ + if (info.auth_key_len > 0) { + DPRINTF("auth_keylen=%" PRIu32 "\n", info.auth_key_len); + info.auth_key = g_malloc(info.auth_key_len); + s = iov_to_buf(iov, out_num, 0, info.auth_key, + info.auth_key_len); + if (unlikely(s != info.auth_key_len)) { + virtio_error(vdev, + "virtio-crypto authenticated key incorrect"); + ret = -EFAULT; + goto err; + } + iov_discard_front(&iov, &out_num, info.auth_key_len); + } + } else if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) { + info.hash_alg = virtio_ldl_p(vdev, + &sess_req->u.chain.para.u.hash_param.algo); + info.hash_result_len = virtio_ldl_p(vdev, + &sess_req->u.chain.para.u.hash_param.hash_result_len); + } else { + /* VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED */ + error_report("unsupported hash mode"); + ret = -VIRTIO_CRYPTO_NOTSUPP; + goto err; + } + } else { + /* VIRTIO_CRYPTO_SYM_OP_NONE */ + error_report("unsupported cipher op_type: VIRTIO_CRYPTO_SYM_OP_NONE"); + ret = -VIRTIO_CRYPTO_NOTSUPP; + goto err; + } + + queue_index = virtio_crypto_vq2q(queue_id); + session_id = cryptodev_backend_sym_create_session( + vcrypto->cryptodev, + &info, queue_index, &local_err); + if (session_id >= 0) { + DPRINTF("create session_id=%" PRIu64 " successfully\n", + session_id); + + ret = session_id; + } else { + if (local_err) { + error_report_err(local_err); + } + ret = -VIRTIO_CRYPTO_ERR; + } + +err: + g_free(info.cipher_key); + g_free(info.auth_key); + return ret; +} + +static uint32_t +virtio_crypto_handle_close_session(VirtIOCrypto *vcrypto, + struct virtio_crypto_destroy_session_req *close_sess_req, + uint32_t queue_id) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); + int ret; + uint64_t session_id; + uint32_t status; + Error *local_err = NULL; + + session_id = virtio_ldq_p(vdev, &close_sess_req->session_id); + DPRINTF("close session, id=%" PRIu64 "\n", session_id); + + ret = cryptodev_backend_sym_close_session( + vcrypto->cryptodev, session_id, queue_id, &local_err); + if (ret == 0) { + status = VIRTIO_CRYPTO_OK; + } else { + if (local_err) { + error_report_err(local_err); + } else { + error_report("destroy session failed"); + } + status = VIRTIO_CRYPTO_ERR; + } + + return status; +} + +static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); + struct virtio_crypto_op_ctrl_req ctrl; + VirtQueueElement *elem; + size_t in_len; + struct iovec *in_iov; + struct iovec *out_iov; + unsigned in_num; + unsigned out_num; + uint32_t queue_id; + uint32_t opcode; + struct virtio_crypto_session_input *input; + int64_t session_id; + uint32_t status; + size_t s; + + for (;;) { + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { + break; + } + if (elem->out_num < 1 || elem->in_num < 1) { + virtio_error(vdev, "virtio-crypto ctrl missing headers"); + virtqueue_detach_element(vq, elem, 0); + g_free(elem); + break; + } + + out_num = elem->out_num; + out_iov = elem->out_sg; + in_num = elem->in_num; + in_iov = elem->in_sg; + if (unlikely(iov_to_buf(out_iov, out_num, 0, &ctrl, sizeof(ctrl)) + != sizeof(ctrl))) { + virtio_error(vdev, "virtio-crypto request ctrl_hdr too short"); + virtqueue_detach_element(vq, elem, 0); + g_free(elem); + break; + } + iov_discard_front(&out_iov, &out_num, sizeof(ctrl)); + + opcode = virtio_ldl_p(vdev, &ctrl.header.opcode); + queue_id = virtio_ldl_p(vdev, &ctrl.header.queue_id); + + switch (opcode) { + case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: + in_len = iov_size(in_iov, in_num); + input = (void *)in_iov[in_num - 1].iov_base + + in_iov[in_num - 1].iov_len + - sizeof(*input); + iov_discard_back(in_iov, &in_num, sizeof(*input)); + + session_id = virtio_crypto_create_sym_session(vcrypto, + &ctrl.u.sym_create_session, + queue_id, opcode, + out_iov, out_num); + /* Serious errors, need to reset virtio crypto device */ + if (session_id == -EFAULT) { + virtqueue_detach_element(vq, elem, 0); + break; + } else if (session_id == -VIRTIO_CRYPTO_NOTSUPP) { + input->status = VIRTIO_CRYPTO_NOTSUPP; + } else if (session_id == -VIRTIO_CRYPTO_ERR) { + input->status = VIRTIO_CRYPTO_ERR; + } else { + input->session_id = session_id; + input->status = VIRTIO_CRYPTO_OK; + } + + virtqueue_push(vq, elem, in_len); + virtio_notify(vdev, vq); + break; + case VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION: + case VIRTIO_CRYPTO_HASH_DESTROY_SESSION: + case VIRTIO_CRYPTO_MAC_DESTROY_SESSION: + case VIRTIO_CRYPTO_AEAD_DESTROY_SESSION: + status = virtio_crypto_handle_close_session(vcrypto, + &ctrl.u.destroy_session, queue_id); + + s = iov_from_buf(in_iov, in_num, 0, &status, sizeof(status)); + if (unlikely(s != sizeof(status))) { + virtio_error(vdev, "virtio-crypto status incorrect"); + virtqueue_detach_element(vq, elem, 0); + break; + } + virtqueue_push(vq, elem, sizeof(status)); + virtio_notify(vdev, vq); + break; + case VIRTIO_CRYPTO_HASH_CREATE_SESSION: + case VIRTIO_CRYPTO_MAC_CREATE_SESSION: + case VIRTIO_CRYPTO_AEAD_CREATE_SESSION: + default: + in_len = iov_size(in_iov, in_num); + input = (void *)in_iov[in_num - 1].iov_base + + in_iov[in_num - 1].iov_len + - sizeof(*input); + error_report("virtio-crypto unsupported ctrl opcode: %d", opcode); + + input->status = VIRTIO_CRYPTO_NOTSUPP; + virtqueue_push(vq, elem, in_len); + virtio_notify(vdev, vq); + + break; + } /* end switch case */ + + g_free(elem); + } /* end for loop */ +} + static uint64_t virtio_crypto_get_features(VirtIODevice *vdev, uint64_t features, Error **errp) @@ -85,7 +368,7 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp) virtio_add_queue(vdev, 1024, NULL); } - vcrypto->ctrl_vq = virtio_add_queue(vdev, 64, NULL); + vcrypto->ctrl_vq = virtio_add_queue(vdev, 64, virtio_crypto_handle_ctrl); if (!vcrypto->cryptodev->ready) { vcrypto->status &= ~VIRTIO_CRYPTO_S_HW_READY; } else {