From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga11.intel.com (mga11.intel.com [192.55.52.93]) by dpdk.org (Postfix) with ESMTP id 71A9E3230 for ; Mon, 27 Nov 2017 21:03:02 +0100 (CET) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 27 Nov 2017 12:03:02 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.44,465,1505804400"; d="scan'208";a="6889851" Received: from silpixa00398673.ir.intel.com (HELO silpixa00398673.ger.corp.intel.com) ([10.237.223.54]) by orsmga003.jf.intel.com with ESMTP; 27 Nov 2017 12:02:59 -0800 From: Fan Zhang To: dev@dpdk.org Cc: roy.fan.zhang@intel.com, yliu@fridaylinux.org, maxime.coquelin@redhat.com, tiwei.bie@intel.com Date: Mon, 27 Nov 2017 20:01:07 +0000 Message-Id: <20171127200115.31049-5-roy.fan.zhang@intel.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20171127200115.31049-1-roy.fan.zhang@intel.com> References: <20171127200115.31049-1-roy.fan.zhang@intel.com> Subject: [dpdk-dev] [PATCH 04/12] lib/librte_vhost: add session messsage handler X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 27 Nov 2017 20:03:03 -0000 This patch adds session message handler to vhost crypto Signed-off-by: Fan Zhang --- lib/librte_vhost/vhost_crypto.c | 447 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 447 insertions(+) create mode 100644 lib/librte_vhost/vhost_crypto.c diff --git a/lib/librte_vhost/vhost_crypto.c b/lib/librte_vhost/vhost_crypto.c new file mode 100644 index 0000000..271083a --- /dev/null +++ b/lib/librte_vhost/vhost_crypto.c @@ -0,0 +1,447 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#ifdef RTE_LIBRTE_VHOST_DEBUG +#include +#endif +#include "vhost.h" +#include "vhost_user.h" +#include "rte_vhost_crypto.h" + +#define NB_MEMPOOL_OBJS (1024) +#define NB_CRYPTO_DESCRIPTORS (1024) +#define NB_CACHE_OBJS (128) + +#define SESSION_MAP_ENTRIES (1024) /**< Max nb sessions per vdev */ +#define MAX_KEY_SIZE (32) +#define VHOST_CRYPTO_MAX_IV_LEN (16) +#define MAX_COUNT_DOWN_TIMES (100) + +#define VHOST_USER_MSG_CREATE_SESS (23) +#define VHOST_USER_MSG_CLOSE_SESS (24) + +#define INHDR_LEN (sizeof(struct virtio_crypto_inhdr)) +#define IV_OFFSET (sizeof(struct rte_crypto_op) + \ + sizeof(struct rte_crypto_sym_op)) + +#ifdef RTE_LIBRTE_VHOST_DEBUG +#define VC_LOG_ERR(fmt, args...) \ + RTE_LOG(ERR, USER1, "[%s] %s() line %u: " fmt "\n", \ + "Vhost-Crypto", __func__, __LINE__, ## args) +#define VC_LOG_INFO(fmt, args...) \ + RTE_LOG(INFO, USER1, "[%s] %s() line %u: " fmt "\n", \ + "Vhost-Crypto", __func__, __LINE__, ## args) + +#define VC_LOG_DBG(fmt, args...) \ + RTE_LOG(DEBUG, USER1, "[%s] %s() line %u: " fmt "\n", \ + "Vhost-Crypto", __func__, __LINE__, ## args) +#else +#define VC_LOG_ERR(fmt, args...) \ + RTE_LOG(ERR, USER1, "[VHOST-Crypto]: " fmt "\n", ## args) +#define VC_LOG_INFO(fmt, args...) \ + RTE_LOG(INFO, USER1, "[VHOST-Crypto]: " fmt "\n", ## args) +#define VC_LOG_DBG(fmt, args...) +#endif + +#define VIRTIO_CRYPTO_FEATURES ((1 << VIRTIO_F_NOTIFY_ON_EMPTY) | \ + (1 << VIRTIO_RING_F_INDIRECT_DESC) | \ + (1 << VIRTIO_RING_F_EVENT_IDX) | \ + (1 << VIRTIO_CRYPTO_SERVICE_CIPHER) | \ + (1 << VIRTIO_CRYPTO_SERVICE_HASH) | \ + (1 << VIRTIO_CRYPTO_SERVICE_MAC) | \ + (1 << VIRTIO_CRYPTO_SERVICE_AEAD) | \ + (1 << VIRTIO_NET_F_CTRL_VQ)) + + +#define GPA_TO_VVA(t, m, a) \ + (t)(uintptr_t)rte_vhost_gpa_to_vva(m, a) + +/* Macro to get the buffer at the end of rte_crypto_op */ +#define REQ_OP_OFFSET (IV_OFFSET + VHOST_CRYPTO_MAX_IV_LEN) + +/** + * 1-to-1 mapping between RTE_CRYPTO_*ALGO* and VIRTIO_CRYPTO_*ALGO*, for + * algorithms not supported by RTE_CRYPTODEV, the -VIRTIO_CRYPTO_NOTSUPP is + * returned. + */ +static int cipher_algo_transform[] = { + RTE_CRYPTO_CIPHER_NULL, + RTE_CRYPTO_CIPHER_ARC4, + RTE_CRYPTO_CIPHER_AES_ECB, + RTE_CRYPTO_CIPHER_AES_CBC, + RTE_CRYPTO_CIPHER_AES_CTR, + -VIRTIO_CRYPTO_NOTSUPP, /* VIRTIO_CRYPTO_CIPHER_DES_ECB */ + RTE_CRYPTO_CIPHER_DES_CBC, + RTE_CRYPTO_CIPHER_3DES_ECB, + RTE_CRYPTO_CIPHER_3DES_CBC, + RTE_CRYPTO_CIPHER_3DES_CTR, + RTE_CRYPTO_CIPHER_KASUMI_F8, + RTE_CRYPTO_CIPHER_SNOW3G_UEA2, + RTE_CRYPTO_CIPHER_AES_F8, + RTE_CRYPTO_CIPHER_AES_XTS, + RTE_CRYPTO_CIPHER_ZUC_EEA3 +}; + +/** + * VIRTIO_CRYTPO_AUTH_* indexes are not sequential, the gaps are filled with + * -VIRTIO_CRYPTO_BADMSG errors. + */ +static int auth_algo_transform[] = { + RTE_CRYPTO_AUTH_NULL, + RTE_CRYPTO_AUTH_MD5_HMAC, + RTE_CRYPTO_AUTH_SHA1_HMAC, + RTE_CRYPTO_AUTH_SHA224_HMAC, + RTE_CRYPTO_AUTH_SHA256_HMAC, + RTE_CRYPTO_AUTH_SHA384_HMAC, + RTE_CRYPTO_AUTH_SHA512_HMAC, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_NOTSUPP, /* VIRTIO_CRYPTO_MAC_CMAC_3DES */ + RTE_CRYPTO_AUTH_AES_CMAC, + RTE_CRYPTO_AUTH_KASUMI_F9, + RTE_CRYPTO_AUTH_SNOW3G_UIA2, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + -VIRTIO_CRYPTO_BADMSG, + RTE_CRYPTO_AUTH_AES_GMAC, + -VIRTIO_CRYPTO_NOTSUPP, /* VIRTIO_CRYPTO_MAC_GMAC_TWOFISH */ + RTE_CRYPTO_AUTH_AES_CBC_MAC, + -VIRTIO_CRYPTO_NOTSUPP, /* VIRTIO_CRYPTO_MAC_CBCMAC_KASUMI_F9 */ + RTE_CRYPTO_AUTH_AES_XCBC_MAC +}; + +static int cipher_op_transform[] = { + -VIRTIO_CRYPTO_BADMSG, /* meaningless */ + RTE_CRYPTO_CIPHER_OP_ENCRYPT, + RTE_CRYPTO_CIPHER_OP_DECRYPT +}; + +static int chain_cipher_op_transform[] = { + -VIRTIO_CRYPTO_BADMSG, /* meaningless */ + RTE_CRYPTO_CIPHER_OP_DECRYPT, /* HASH THEN CIPHER */ + RTE_CRYPTO_CIPHER_OP_ENCRYPT /* CPIHER THEN HASH */ +}; + +static int chain_auth_op_transform[] = { + -VIRTIO_CRYPTO_BADMSG, /* meaningless */ + RTE_CRYPTO_AUTH_OP_VERIFY, + RTE_CRYPTO_AUTH_OP_GENERATE +}; + +static int iv_lens[] = { + -1, /* Invalid input */ + 0, /* RTE_CRYPTO_CIPHER_NULL */ + 8, /* RTE_CRYPTO_CIPHER_3DES_CBC */ + 8, /* RTE_CRYPTO_CIPHER_3DES_CTR */ + 8, /* RTE_CRYPTO_CIPHER_3DES_ECB */ + 16, /* RTE_CRYPTO_CIPHER_AES_CBC */ + /* TODO: add common algos */ +}; + +/** + * vhost_crypto struct is used to maintain a number of virtio_cryptos and + * one DPDK crypto device that deals with all crypto workloads. It is declared + * here and defined in vhost_crypto.c + */ +struct vhost_crypto { + /** Used to lookup DPDK Cryptodev Session based on VIRTIO crypto + * session ID. + */ + struct rte_hash *session_map; + + /** DPDK cryptodev ID */ + uint8_t cid; + struct rte_mempool *sess_pool; + uint16_t nb_qps; + + uint64_t last_session_id; + + uint64_t cache_session_id; + struct rte_cryptodev_sym_session *cache_session; + /** socket id for the device */ + int socket_id; +}; + +static int +transform_cipher_param(struct rte_crypto_sym_xform *xform, + VhostUserCryptoSessionParam *param) { + int ret; + + ret = cipher_algo_transform[param->cipher_algo]; + if (unlikely(ret < 0)) + return ret; + + xform->type = RTE_CRYPTO_SYM_XFORM_CIPHER; + xform->cipher.algo = ret; + xform->cipher.key.length = param->cipher_key_len; + if (xform->cipher.key.length > 0) + xform->cipher.key.data = param->cipher_key_buf; + ret = cipher_op_transform[param->dir]; + if (unlikely(ret < 0)) { + VC_LOG_DBG("Bad operation type"); + return ret; + } + xform->cipher.op = ret; + ret = iv_lens[xform->cipher.algo]; + if (unlikely(ret < 0)) + return ret; + xform->cipher.iv.length = ret; + xform->cipher.iv.offset = IV_OFFSET; + return 0; +} + +static int +transform_chain_param(struct rte_crypto_sym_xform *xforms, + VhostUserCryptoSessionParam *param) +{ + struct rte_crypto_sym_xform *xform_cipher, *xform_auth; + int ret; + + if (param->dir == VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER) { + xform_auth = xforms; + xform_cipher = xforms->next; + } else { + xform_cipher = xforms; + xform_auth = xforms->next; + } + + /* cipher */ + ret = cipher_algo_transform[param->cipher_algo]; + if (unlikely(ret < 0)) + return ret; + xform_cipher->type = RTE_CRYPTO_SYM_XFORM_CIPHER; + xform_cipher->cipher.algo = ret; + xform_cipher->cipher.key.length = param->cipher_key_len; + if (xform_cipher->cipher.key.length > 0) + xform_cipher->cipher.key.data = param->cipher_key_buf; + ret = chain_cipher_op_transform[param->dir]; + if (unlikely(ret < 0)) + return ret; + xform_cipher->cipher.op = ret; + ret = iv_lens[xform_cipher->cipher.algo]; + if (unlikely(ret < 0)) + return ret; + xform_cipher->cipher.iv.length = ret; + xform_cipher->cipher.iv.offset = IV_OFFSET; + + /* auth */ + xform_auth->type = RTE_CRYPTO_SYM_XFORM_AUTH; + ret = auth_algo_transform[param->hash_algo]; + if (unlikely(ret < 0)) + return ret; + xform_auth->auth.algo = ret; + ret = chain_auth_op_transform[param->dir]; + if (unlikely(ret)) + return ret; + xform_auth->auth.op = ret; + xform_auth->auth.digest_length = param->digest_len; + xform_auth->auth.key.length = param->auth_key_len; + if (xform_auth->auth.key.length) + xform_auth->auth.key.data = param->auth_key_buf; + + return 0; +} + +static void +vhost_crypto_create_sess(struct vhost_crypto *vcrypto, + VhostUserCryptoSessionParam *sess_param) +{ + struct rte_crypto_sym_xform xform1 = {0}, xform2 = {0}; + struct rte_cryptodev_sym_session *session; + int ret; + + switch(sess_param->op_type) { + case VIRTIO_CRYPTO_SYM_OP_NONE: + case VIRTIO_CRYPTO_SYM_OP_CIPHER: + ret = transform_cipher_param(&xform1, sess_param); + if (unlikely(ret)) { + VC_LOG_ERR("Error transform session msg (%i)", ret); + sess_param->session_id = ret; + return; + } + break; + case VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING: + if (unlikely(sess_param->hash_mode != + VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH)) { + sess_param->session_id = -VIRTIO_CRYPTO_NOTSUPP; + VC_LOG_ERR("Error transform session message (%i)", + -VIRTIO_CRYPTO_NOTSUPP); + return; + } + + xform1.next = &xform2; + + ret = transform_chain_param(&xform1, sess_param); + if (unlikely(ret)) { + VC_LOG_ERR("Error transform session message (%i)", ret); + sess_param->session_id = ret; + return; + } + + break; + default: + VC_LOG_ERR("Algorithm not yet supported"); + sess_param->session_id = -VIRTIO_CRYPTO_NOTSUPP; + return; + } + + session = rte_cryptodev_sym_session_create(vcrypto->sess_pool); + if (!session) { + VC_LOG_ERR("Failed to create session"); + sess_param->session_id = -VIRTIO_CRYPTO_ERR; + return; + } + + if (rte_cryptodev_sym_session_init(vcrypto->cid, session, &xform1, + vcrypto->sess_pool) < 0) { + VC_LOG_ERR("Failed to initialize session"); + sess_param->session_id = -VIRTIO_CRYPTO_ERR; + return; + } + + /* insert hash to map */ + if (rte_hash_add_key_data(vcrypto->session_map, + &vcrypto->last_session_id, session) < 0) { + VC_LOG_ERR("Failed to insert session to hash table"); + + if (rte_cryptodev_sym_session_clear(vcrypto->cid, session) < 0) + VC_LOG_ERR("Failed to clear session"); + else { + if (rte_cryptodev_sym_session_free(session) < 0) + VC_LOG_ERR("Failed to free session"); + } + sess_param->session_id = -VIRTIO_CRYPTO_ERR; + return; + } + + VC_LOG_DBG("Session (key %lu, session %p) created.", + vcrypto->last_session_id, session); + + sess_param->session_id = vcrypto->last_session_id; + vcrypto->last_session_id++; +} + +static int +vhost_crypto_close_sess(struct vhost_crypto *vcrypto, uint64_t session_id) +{ + struct rte_cryptodev_sym_session *session; + uint64_t sess_id = session_id; + int ret; + + ret = rte_hash_lookup_data(vcrypto->session_map, &sess_id, + (void **)&session); + + if (unlikely(ret < 0)) { + VC_LOG_ERR("Failed to delete session (key %lu).", session_id); + return -VIRTIO_CRYPTO_INVSESS; + } + + if (rte_cryptodev_sym_session_clear(vcrypto->cid, session) < 0) { + VC_LOG_DBG("Failed to delete session"); + return -VIRTIO_CRYPTO_ERR; + } + + if (rte_cryptodev_sym_session_free(session) < 0) { + VC_LOG_DBG("Failed to delete session"); + return -VIRTIO_CRYPTO_ERR; + } + + if (rte_hash_del_key(vcrypto->session_map, &sess_id) < 0) { + VC_LOG_DBG("Failed to delete session from hash table."); + return -VIRTIO_CRYPTO_ERR; + } + + VC_LOG_DBG("Session (key %lu, session %p) deleted.", sess_id, + session); + + return 0; +} + +static int +vhost_crypto_msg_handler(struct virtio_net *dev, struct VhostUserMsg *msg, + int fd) +{ + struct vhost_user_dev_priv *priv; + struct vhost_crypto *vcrypto; + int ret = 0; + + priv = dev->private_data; + if (unlikely(priv == NULL)) { + VC_LOG_ERR("Cannot find required data, is it initialized?"); + return -ENOENT; + } + vcrypto = (struct vhost_crypto *)priv->data; + + if (msg->request.master == VHOST_USER_MSG_CREATE_SESS) { + vhost_crypto_create_sess(vcrypto, &msg->payload.crypto_session); + + msg->flags &= ~VHOST_USER_VERSION_MASK; + msg->flags &= ~VHOST_USER_NEED_REPLY; + msg->flags |= VHOST_USER_VERSION; + msg->flags |= VHOST_USER_REPLY_MASK; + + ret = send_fd_message(fd, (char *)msg, VHOST_USER_HDR_SIZE + + msg->size, NULL, 0); + } else if (msg->request.master == VHOST_USER_MSG_CLOSE_SESS) + ret = vhost_crypto_close_sess(vcrypto, msg->payload.u64); + else + ret = -EINVAL; + + return ret; +} -- 2.9.5