From: Declan Doherty <declan.doherty@intel.com>
To: dev@dpdk.org
Subject: [dpdk-dev] [PATCH 3/4] aesni_mb_pmd: Initial implementation of multi buffer based crypto device
Date: Thu, 20 Aug 2015 15:07:22 +0100 [thread overview]
Message-ID: <1440079643-5437-4-git-send-email-declan.doherty@intel.com> (raw)
In-Reply-To: <1440079643-5437-1-git-send-email-declan.doherty@intel.com>
This patch provides the initial implementation of the AES-NI multi-buffer
based crypto poll mode driver using DPDK's new cryptodev framework.
This PMD is dependent on Intel's multibuffer library, see the white paper
"Fast Multi-buffer IPsec Implementations on Intel® Architecture
Processors", see ref 1 for details on the library's design and ref 2 to
download the library itself. This initial implementation is limited to
supporting the chained operations of "hash then cipher" or "cipher then
hash" for the following cipher and hash algorithms:
- RTE_CRYPTO_SYM_CIPHER_AES128_CBC
- RTE_CRYPTO_SYM_CIPHER_AES256_CBC
- RTE_CRYPTO_SYM_CIPHER_AES512_CBC
- RTE_CRYPTO_SYM_HASH_SHA1_HMAC
- RTE_CRYPTO_SYM_HASH_SHA256_HMAC
- RTE_CRYPTO_SYM_HASH_SHA512_HMAC
Important Note:
Due to the fact that the multi-buffer library is designed for
accelerating IPsec crypto oepration, the digest's generated for the HMAC
functions are truncated to lengths specified by IPsec RFC's, ie RFC2404
for using HMAC-SHA-1 with IPsec specifies that the digest is truncate
from 20 to 12 bytes.
Build instructions:
To build DPKD with the AESNI_MB_PMD the user is required to download
(ref 2) and compile the multi-buffer library on there user system before
building DPDK. The environmental variable AESNI_MULTI_BUFFER_LIB_PATH
must be exported with the path where you extracted and built the multi
buffer library and finally set CONFIG_RTE_LIBRTE_PMD_AESNI_MB=y in
config/common_linuxapp.
Current status: This is a work in progress, which has not been
performance tuned. The software has only been built and tested on
Fedora 20 64-bit using gcc. It's doesn't support crypto operation across
chained mbufs, or cipher only or hash only operations.
ref 1:
https://www-ssl.intel.com/content/www/us/en/intelligent-systems/intel-technology/fast-multi-buffer-ipsec-implementations-ia-processors-p
ref 2: https://downloadcenter.intel.com/download/22972
Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
config/common_bsdapp | 8 +
config/common_linuxapp | 7 +
doc/guides/cryptodevs/aesni_mb.rst | 76 +++
doc/guides/cryptodevs/index.rst | 1 +
drivers/crypto/Makefile | 2 +-
drivers/crypto/aesni_mb/Makefile | 67 +++
drivers/crypto/aesni_mb/aesni_mb_ops.h | 206 ++++++++
drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c | 550 +++++++++++++++++++++
drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c | 346 +++++++++++++
drivers/crypto/aesni_mb/rte_aesni_mb_pmd_private.h | 224 +++++++++
drivers/crypto/aesni_mb/rte_pmd_aesni_version.map | 5 +
mk/rte.app.mk | 4 +
12 files changed, 1495 insertions(+), 1 deletion(-)
create mode 100644 doc/guides/cryptodevs/aesni_mb.rst
create mode 100644 drivers/crypto/aesni_mb/Makefile
create mode 100644 drivers/crypto/aesni_mb/aesni_mb_ops.h
create mode 100644 drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
create mode 100644 drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
create mode 100644 drivers/crypto/aesni_mb/rte_aesni_mb_pmd_private.h
create mode 100644 drivers/crypto/aesni_mb/rte_pmd_aesni_version.map
diff --git a/config/common_bsdapp b/config/common_bsdapp
index 8fcc004..9c5e1e0 100644
--- a/config/common_bsdapp
+++ b/config/common_bsdapp
@@ -167,6 +167,14 @@ CONFIG_RTE_LIBRTE_QAT_DEBUG_DRIVER=y
#
CONFIG_RTE_MAX_QAT_SESSIONS=200
+
+#
+# Compile PMD for AESNI backed device
+#
+CONFIG_RTE_LIBRTE_PMD_AESNI_MB=y
+CONFIG_RTE_LIBRTE_AESNI_MB_DEBUG=n
+
+#
# Support NIC bypass logic
#
CONFIG_RTE_NIC_BYPASS=n
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 7199c95..8e9e8fd 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -165,6 +165,13 @@ CONFIG_RTE_LIBRTE_PMD_QAT_DEBUG_DRIVER=y
#
CONFIG_RTE_LIBRTE_PMD_QAT_MAX_SESSIONS=4096
+# Compile PMD for AESNI backed device
+#
+CONFIG_RTE_LIBRTE_PMD_AESNI_MB=y
+CONFIG_RTE_LIBRTE_PMD_AESNI_MB_DEBUG=n
+CONFIG_RTE_LIBRTE_PMD_AESNI_MB_MAX_SESSIONS=2048
+
+#
# Support NIC bypass logic
#
CONFIG_RTE_NIC_BYPASS=n
diff --git a/doc/guides/cryptodevs/aesni_mb.rst b/doc/guides/cryptodevs/aesni_mb.rst
new file mode 100644
index 0000000..4d15b6b
--- /dev/null
+++ b/doc/guides/cryptodevs/aesni_mb.rst
@@ -0,0 +1,76 @@
+.. BSD LICENSE
+ Copyright(c) 2015 Intel Corporation. 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.
+
+AESN-NI Multi Buffer Crytpo Poll Mode Driver
+============================================
+
+
+The AESNI MB PMD (**librte_pmd_aesni_mb**) provides poll mode crypto driver
+support for utilising Intel multi buffer library, see the white paper
+`Fast Multi-buffer IPsec Implementations on Intel® Architecture Processors
+<https://www-ssl.intel.com/content/www/us/en/intelligent-systems/intel-technology/fast-multi-buffer-ipsec-implementations-ia-processors-paper.html?wapkw=multi+buffer>`_.
+
+The AES-NI MB PMD has current only been tested on Fedora 21 64-bit with gcc.
+
+Features
+--------
+
+AESNI MB PMD has support for:
+
+Cipher algorithms:
+
+* RTE_CRYPTO_SYM_CIPHER_AES128_CBC
+* RTE_CRYPTO_SYM_CIPHER_AES256_CBC
+* RTE_CRYPTO_SYM_CIPHER_AES512_CBC
+
+Hash algorithms:
+
+* RTE_CRYPTO_SYM_HASH_SHA1_HMAC
+* RTE_CRYPTO_SYM_HASH_SHA256_HMAC
+* RTE_CRYPTO_SYM_HASH_SHA512_HMAC
+
+Limitations
+-----------
+
+* Chained mbufs are not supported.
+* Hash only is not supported.
+* Cipher only is not supported.
+* Only in-place is currently supported (destination address is the same as source address).
+* Only supports session-oriented API implementation (session-less APIs are not supported).
+* Not performance tuned.
+
+Installation
+------------
+
+To build DPKD with the AESNI_MB_PMD the user is required to download the library
+from `here <https://downloadcenter.intel.com/download/22972>`_ and compile it on
+their user system before building DPDK. The environmental variable
+AESNI_MULTI_BUFFER_LIB_PATH must be exported with the path where you extracted
+and built the multi buffer library and finally set
+CONFIG_RTE_LIBRTE_PMD_AESNI_MB=y in config/common_linuxapp.
\ No newline at end of file
diff --git a/doc/guides/cryptodevs/index.rst b/doc/guides/cryptodevs/index.rst
index 1c31697..8949fd0 100644
--- a/doc/guides/cryptodevs/index.rst
+++ b/doc/guides/cryptodevs/index.rst
@@ -39,4 +39,5 @@ Crypto Device Drivers
:maxdepth: 2
:numbered:
+ aesni_mb
qat
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index eeb998e..26325b0 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -31,7 +31,7 @@
include $(RTE_SDK)/mk/rte.vars.mk
-
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_AESNI_MB) += aesni_mb
DIRS-$(CONFIG_RTE_LIBRTE_PMD_QAT) += qat
include $(RTE_SDK)/mk/rte.sharelib.mk
diff --git a/drivers/crypto/aesni_mb/Makefile b/drivers/crypto/aesni_mb/Makefile
new file mode 100644
index 0000000..62f51ce
--- /dev/null
+++ b/drivers/crypto/aesni_mb/Makefile
@@ -0,0 +1,67 @@
+# BSD LICENSE
+#
+# Copyright(c) 2015 Intel Corporation. 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 $(RTE_SDK)/mk/rte.vars.mk
+
+ifeq ($(AESNI_MULTI_BUFFER_LIB_PATH),)
+$(error "Please define AESNI_MULTI_BUFFER_LIB_PATH environment variable")
+endif
+
+# library name
+LIB = librte_pmd_aesni_mb.a
+
+# build flags
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+# library version
+LIBABIVER := 1
+
+# versioning export map
+EXPORT_MAP := rte_pmd_aesni_version.map
+
+# external library include paths
+CFLAGS += -I$(AESNI_MULTI_BUFFER_LIB_PATH)
+CFLAGS += -I$(AESNI_MULTI_BUFFER_LIB_PATH)/include
+
+# library source files
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_AESNI_MB) += rte_aesni_mb_pmd.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_AESNI_MB) += rte_aesni_mb_pmd_ops.c
+
+# export include files
+SYMLINK-y-include +=
+
+
+# library dependencies
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_AESNI_MB) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_AESNI_MB) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_AESNI_MB) += lib/librte_cryptodev
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/crypto/aesni_mb/aesni_mb_ops.h b/drivers/crypto/aesni_mb/aesni_mb_ops.h
new file mode 100644
index 0000000..ab96990
--- /dev/null
+++ b/drivers/crypto/aesni_mb/aesni_mb_ops.h
@@ -0,0 +1,206 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Intel Corporation. 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.
+ */
+
+#ifndef _AESNI_MB_OPS_H_
+#define _AESNI_MB_OPS_H_
+
+#ifndef LINUX
+#define LINUX
+#endif
+
+#include <mb_mgr.h>
+#include <aux_funcs.h>
+#include <gcm_defines.h>
+
+enum aesni_mb_vector_mode {
+ RTE_AESNI_MB_NOT_SUPPORTED = 0,
+ RTE_AESNI_MB_SSE,
+ RTE_AESNI_MB_AVX,
+ RTE_AESNI_MB_AVX2
+};
+
+typedef void (*md5_one_block_t)(void *data, void *digest);
+typedef void (*sha1_one_block_t)(void *data, void *digest);
+typedef void (*sha224_one_block_t)(void *data, void *digest);
+typedef void (*sha256_one_block_t)(void *data, void *digest);
+typedef void (*sha384_one_block_t)(void *data, void *digest);
+typedef void (*sha512_one_block_t)(void *data, void *digest);
+
+typedef void (*aes_keyexp_128_t)(void *key, void *enc_exp_keys, void *dec_exp_keys);
+typedef void (*aes_keyexp_192_t)(void *key, void *enc_exp_keys, void *dec_exp_keys);
+typedef void (*aes_keyexp_256_t)(void *key, void *enc_exp_keys, void *dec_exp_keys);
+
+typedef void (*aes_xcbc_expand_key_t)(void *key, void *k1_exp, void *k2, void *k3);
+
+typedef void (*aesni_gcm_t)(gcm_data *my_ctx_data, u8 *out, const u8 *in,
+ u64 plaintext_len, u8 *iv, const u8 *aad, u64 aad_len,
+ u8 *auth_tag, u64 auth_tag_len);
+
+typedef void (*aesni_gcm_precomp_t)(gcm_data *my_ctx_data, u8 *hash_subkey);
+
+/** Multi-buffer library function pointer table */
+struct aesni_mb_ops {
+ struct {
+ init_mb_mgr_t init_mgr; /**< Initialise scheduler */
+ get_next_job_t get_next; /**< Get next free job structure */
+ submit_job_t submit; /**< Submit job to scheduler */
+ get_completed_job_t get_completed_job; /**< Get completed job */
+ flush_job_t flush_job; /**< flush jobs from manager */
+ } job; /**< multi buffer manager functions */
+ struct {
+ struct {
+ md5_one_block_t md5; /**< MD5 one block hash */
+ sha1_one_block_t sha1; /**< SHA1 one block hash */
+ sha224_one_block_t sha224; /**< SHA224 one block hash */
+ sha256_one_block_t sha256; /**< SHA256 one block hash */
+ sha384_one_block_t sha384; /**< SHA384 one block hash */
+ sha512_one_block_t sha512; /**< SHA512 one block hash */
+ } one_block; /**< one block hash functions */
+ struct {
+ aes_keyexp_128_t aes128; /**< AES128 key expansions */
+ aes_keyexp_192_t aes192; /**< AES192 key expansions */
+ aes_keyexp_256_t aes256; /**< AES256 key expansions */
+ aes_xcbc_expand_key_t aes_xcbc; /**< AES XCBC key expansions */
+ } keyexp; /**< Key expansion functions */
+ } aux; /**< Auxiliary functions */
+ struct {
+ aesni_gcm_t enc; /**< MD5 encode */
+ aesni_gcm_t dec; /**< GCM decode */
+ aesni_gcm_precomp_t precomp; /**< GCM pre-compute */
+ } gcm; /**< GCM functions */
+};
+
+
+static const struct aesni_mb_ops job_ops[] = {
+ [RTE_AESNI_MB_NOT_SUPPORTED] = {
+ .job = { NULL },
+ .aux = {
+ .one_block = { NULL },
+ .keyexp = { NULL }
+ },
+ .gcm = { NULL
+ }
+ },
+ [RTE_AESNI_MB_SSE] = {
+ .job = {
+ init_mb_mgr_sse,
+ get_next_job_sse,
+ submit_job_sse,
+ get_completed_job_sse,
+ flush_job_sse
+ },
+ .aux = {
+ .one_block = {
+ md5_one_block_sse,
+ sha1_one_block_sse,
+ sha224_one_block_sse,
+ sha256_one_block_sse,
+ sha384_one_block_sse,
+ sha512_one_block_sse
+ },
+ .keyexp = {
+ aes_keyexp_128_sse,
+ aes_keyexp_192_sse,
+ aes_keyexp_256_sse,
+ aes_xcbc_expand_key_sse
+ }
+ },
+ .gcm = {
+ aesni_gcm_enc_sse,
+ aesni_gcm_dec_sse,
+ aesni_gcm_precomp_sse
+ }
+ },
+ [RTE_AESNI_MB_AVX] = {
+ .job = {
+ init_mb_mgr_avx,
+ get_next_job_avx,
+ submit_job_avx,
+ get_completed_job_avx,
+ flush_job_avx
+ },
+ .aux = {
+ .one_block = {
+ md5_one_block_avx,
+ sha1_one_block_avx,
+ sha224_one_block_avx,
+ sha256_one_block_avx,
+ sha384_one_block_avx,
+ sha512_one_block_avx
+ },
+ .keyexp = {
+ aes_keyexp_128_avx,
+ aes_keyexp_192_avx,
+ aes_keyexp_256_avx,
+ aes_xcbc_expand_key_avx
+ }
+ },
+ .gcm = {
+ aesni_gcm_enc_avx_gen2,
+ aesni_gcm_dec_avx_gen2,
+ aesni_gcm_precomp_avx_gen2
+ }
+ },
+ [RTE_AESNI_MB_AVX2] = {
+ .job = {
+ init_mb_mgr_avx2,
+ get_next_job_avx2,
+ submit_job_avx2,
+ get_completed_job_avx2,
+ flush_job_avx2
+ },
+ .aux = {
+ .one_block = {
+ md5_one_block_avx2,
+ sha1_one_block_avx2,
+ sha224_one_block_avx2,
+ sha256_one_block_avx2,
+ sha384_one_block_avx2,
+ sha512_one_block_avx2
+ },
+ .keyexp = {
+ aes_keyexp_128_avx2,
+ aes_keyexp_192_avx2,
+ aes_keyexp_256_avx2,
+ aes_xcbc_expand_key_avx2
+ }
+ },
+ .gcm = {
+ aesni_gcm_enc_avx_gen4,
+ aesni_gcm_dec_avx_gen4,
+ aesni_gcm_precomp_avx_gen4
+ }
+ },
+};
+
+
+#endif /* _AESNI_MB_OPS_H_ */
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
new file mode 100644
index 0000000..65a3731
--- /dev/null
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd.c
@@ -0,0 +1,550 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Intel Corporation. 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 <rte_common.h>
+#include <rte_cryptodev.h>
+#include <rte_dev.h>
+#include <rte_malloc.h>
+#include <rte_cpuflags.h>
+
+#include "rte_aesni_mb_pmd_private.h"
+
+/**
+ * Global static parameter used to create a unique name for each AES-NI multi
+ * buffer crypto device.
+ */
+static unsigned unique_name_id = 0;
+
+static inline int
+create_unique_device_name(char *name, size_t size)
+{
+ int ret;
+
+ if (name == NULL)
+ return -EINVAL;
+
+ ret = snprintf(name, size, "%s_%u", CRYPTODEV_NAME_AESNI_MB_PMD,
+ unique_name_id++);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+typedef void (*hash_one_block_t)(void *data, void *digest);
+typedef void (*aes_keyexp_t)(void *key, void *enc_exp_keys, void *dec_exp_keys);
+
+/**
+ * Calculate the authentication pre-computes
+ *
+ * @param one_block_hash Function pointer to calculate digest on ipad/opad
+ * @param ipad Inner pad output byte array
+ * @param opad Outer pad output byte array
+ * @param hkey Authentication key
+ * @param hkey_len Authentication key length
+ * @param blocksize Block size of selected hash algo
+ */
+static void
+calculate_auth_precomputes(hash_one_block_t one_block_hash,
+ uint8_t *ipad, uint8_t *opad,
+ uint8_t *hkey, uint16_t hkey_len,
+ uint16_t blocksize)
+{
+ unsigned i, length;
+
+ uint8_t ipad_buf[blocksize] __rte_align(16);
+ uint8_t opad_buf[blocksize] __rte_align(16);
+
+ /* Setup inner and outer pads */
+ memset(ipad_buf, HMAC_IPAD_VALUE, blocksize);
+ memset(opad_buf, HMAC_OPAD_VALUE, blocksize);
+
+ /* XOR hash key with inner and outer pads */
+ length = hkey_len > blocksize ? blocksize : hkey_len;
+
+ for (i = 0; i < length; i++) {
+ ipad_buf[i] ^= hkey[i];
+ opad_buf[i] ^= hkey[i];
+ }
+
+ /* Compute partial hashes */
+ (*one_block_hash)(ipad_buf, ipad);
+ (*one_block_hash)(opad_buf, opad);
+
+ /* Clean up stack */
+ memset(ipad_buf, 0, blocksize);
+ memset(opad_buf, 0, blocksize);
+}
+
+int
+aesni_mb_set_session_parameters(const struct aesni_mb_ops *mb_ops,
+ struct aesni_mb_session *sess,
+ struct rte_crypto_cipher_params *cipher_params,
+ struct rte_crypto_hash_params *auth_params,
+ enum rte_crypto_operation_chain op_chain)
+{
+ aes_keyexp_t aes_keyexp_fn;
+ hash_one_block_t hash_oneblock_fn;
+
+ /* Select Crypto operation - hash then cipher / cipher then hash */
+ switch (op_chain) {
+ case RTE_CRYPTO_SYM_OPCHAIN_HASH_CIPHER:
+ sess->chain_order = HASH_CIPHER;
+ break;
+ case RTE_CRYPTO_SYM_OPCHAIN_CIPHER_HASH:
+ sess->chain_order = CIPHER_HASH;
+ break;
+ default:
+ printf("unsupported operation chain order parameter");
+ return -1;
+ }
+
+ /* Select cipher direction */
+ switch (cipher_params->op) {
+ case RTE_CRYPTO_SYM_CIPHER_OP_ENCRYPT:
+ sess->cipher.direction = ENCRYPT;
+ break;
+ case RTE_CRYPTO_SYM_CIPHER_OP_DECRYPT:
+ sess->cipher.direction = DECRYPT;
+ break;
+ default:
+ printf("unsupported cipher operation parameter");
+ return -1;
+ }
+
+ /* Select cipher mode */
+ switch (cipher_params->algo) {
+ case RTE_CRYPTO_SYM_CIPHER_AES_CBC:
+ sess->cipher.mode = CBC;
+ break;
+ default:
+ printf("unsupported cipher mode parameter");
+ return -1;
+ }
+
+ /* Check key length and choose key expansion function */
+ switch (cipher_params->key.length) {
+ case AES_128_BYTES:
+ sess->cipher.key_length_in_bytes = AES_128_BYTES;
+ aes_keyexp_fn = mb_ops->aux.keyexp.aes128;
+ break;
+ case AES_192_BYTES:
+ sess->cipher.key_length_in_bytes = AES_192_BYTES;
+ aes_keyexp_fn = mb_ops->aux.keyexp.aes192;
+ break;
+ case AES_256_BYTES:
+ sess->cipher.key_length_in_bytes = AES_256_BYTES;
+ aes_keyexp_fn = mb_ops->aux.keyexp.aes256;
+ break;
+ default:
+ printf("unsupported cipher key length");
+ return -1;
+ }
+
+ /* Expanded cipher keys */
+ (*aes_keyexp_fn)(cipher_params->key.data,
+ sess->cipher.expanded_aes_keys.encode,
+ sess->cipher.expanded_aes_keys.decode);
+
+ /* Set Authentication Parameters */
+ switch (auth_params->algo) {
+ case RTE_CRYPTO_SYM_HASH_MD5_HMAC:
+ sess->auth.algo = MD5;
+ hash_oneblock_fn = mb_ops->aux.one_block.md5;
+ break;
+ case RTE_CRYPTO_SYM_HASH_SHA1_HMAC:
+ sess->auth.algo = SHA1;
+ hash_oneblock_fn = mb_ops->aux.one_block.sha1;
+ break;
+ case RTE_CRYPTO_SYM_HASH_SHA224_HMAC:
+ sess->auth.algo = SHA_224;
+ hash_oneblock_fn = mb_ops->aux.one_block.sha224;
+ break;
+ case RTE_CRYPTO_SYM_HASH_SHA256_HMAC:
+ sess->auth.algo = SHA_256;
+ hash_oneblock_fn = mb_ops->aux.one_block.sha256;
+ break;
+ case RTE_CRYPTO_SYM_HASH_SHA384_HMAC:
+ sess->auth.algo = SHA_384;
+ hash_oneblock_fn = mb_ops->aux.one_block.sha384;
+ break;
+ case RTE_CRYPTO_SYM_HASH_SHA512_HMAC:
+ sess->auth.algo = SHA_512;
+ hash_oneblock_fn = mb_ops->aux.one_block.sha512;
+ break;
+ default:
+ printf("unsupported authentication algorithm selection");
+ return -1;
+ }
+
+ /* Calculate Authentication precomputes */
+ calculate_auth_precomputes(hash_oneblock_fn,
+ sess->auth.pads.inner, sess->auth.pads.outer,
+ auth_params->auth_key.data,
+ auth_params->auth_key.length,
+ get_auth_algo_blocksize(sess->auth.algo));
+
+ return 0;
+}
+
+/**
+ * Process a crypto operation and complete a JOB_AES_HMAC job structure for
+ * submission to the multi buffer library for processing.
+ *
+ * @param qp queue pair
+ * @param job JOB_AES_HMAC structure to fill
+ * @param m mbuf to process
+ *
+ * @return
+ * - Completed JOB_AES_HMAC structure pointer on success
+ * - NULL pointer if completion of JOB_AES_HMAC structure isn't possible
+ */
+static JOB_AES_HMAC *
+process_crypto_op(struct aesni_mb_qp *qp, JOB_AES_HMAC *job, struct rte_mbuf *m)
+{
+ struct rte_crypto_op_data *c_op = m->crypto_op;
+ struct aesni_mb_session *sess;
+
+ if (c_op->type == RTE_CRYPTO_OP_SESSIONLESS) {
+ sess = aesni_mb_get_session(qp->sess_mp);
+ if (unlikely(sess == NULL))
+ return NULL;
+
+ if (unlikely(aesni_mb_set_session_parameters(qp->mb_ops,
+ sess, &c_op->op_params.cipher,
+ &c_op->op_params.hash,
+ c_op->op_params.opchain) != 0))
+ return NULL;
+ } else {
+ sess = (struct aesni_mb_session *)c_op->session;
+ }
+
+ /* Set crypto operation */
+ job->chain_order = sess->chain_order;
+
+
+ /* Set cipher parameters */
+ job->cipher_direction = sess->cipher.direction;
+ job->cipher_mode = sess->cipher.mode;
+
+ job->aes_key_len_in_bytes = sess->cipher.key_length_in_bytes;
+ job->aes_enc_key_expanded = sess->cipher.expanded_aes_keys.encode;
+ job->aes_dec_key_expanded = sess->cipher.expanded_aes_keys.decode;
+
+
+ /* Set authentication parameters */
+ job->hash_alg = sess->auth.algo;
+ job->hashed_auth_key_xor_ipad = sess->auth.pads.inner;
+ job->hashed_auth_key_xor_opad = sess->auth.pads.outer;
+
+
+ /* Mutable crypto operation parameters */
+
+ /* Set digest output location */
+ if (job->cipher_direction == DECRYPT) {
+ job->auth_tag_output = (uint8_t *)rte_pktmbuf_append(m,
+ get_digest_byte_length(job->hash_alg));
+
+ if (job->auth_tag_output)
+ memset(job->auth_tag_output, 0,
+ sizeof(get_digest_byte_length(job->hash_alg)));
+ else
+ return NULL;
+ } else {
+ job->auth_tag_output = c_op->digest.data;
+ }
+
+ /* Set digest output length */
+#if 0
+ job->auth_tag_output_len_in_bytes = get_digest_byte_length(job->hash_alg);
+ job->auth_tag_output_len_in_bytes = job->auth_tag_output_len_in_bytes > c_op->digest.length ? c_op->digest.length : job->auth_tag_output_len_in_bytes;
+#else
+ job->auth_tag_output_len_in_bytes = get_truncated_digest_byte_length(job->hash_alg);
+#endif
+ /* Set IV parameters */
+ job->iv = c_op->iv.data;
+ job->iv_len_in_bytes = c_op->iv.length;
+
+ /* Data Parameter */
+ job->src = rte_pktmbuf_mtod(m, uint8_t *);
+ job->dst = c_op->dst ? rte_pktmbuf_mtod(c_op->dst, uint8_t *) :
+ rte_pktmbuf_mtod(m, uint8_t *) + c_op->data.to_cipher.offset;
+
+ job->cipher_start_src_offset_in_bytes = c_op->data.to_cipher.offset;
+ job->msg_len_to_cipher_in_bytes = c_op->data.to_cipher.length;
+
+ job->hash_start_src_offset_in_bytes = c_op->data.to_hash.offset;
+ job->msg_len_to_hash_in_bytes = c_op->data.to_hash.length;
+
+ /* Set user data to be crypto operation data struct */
+ job->user_data = m;
+
+ return job;
+}
+
+/**
+ * Process a completed job and return rte_mbuf which job processed
+ *
+ * @param job JOB_AES_HMAC job to process
+ *
+ * @return
+ * - Returns processed mbuf which is trimmed of output digest used in
+ * verification of supplied digest in the case of a HASH_CIPHER operation
+ * - Returns NULL on invalid job
+ */
+static struct rte_mbuf *
+post_process_job(JOB_AES_HMAC *job)
+{
+ struct rte_mbuf *m;
+
+ if (job == NULL || job->user_data == NULL)
+ return NULL;
+
+ /* handled retrieved job */
+ m = (struct rte_mbuf *)job->user_data;
+
+ /* Verify digest if required */
+ if (job->chain_order == HASH_CIPHER) {
+ if (memcmp(job->auth_tag_output, m->crypto_op->digest.data,
+ job->auth_tag_output_len_in_bytes) != 0)
+ m->ol_flags |= PKT_RX_CRYPTO_DIGEST_BAD;
+ else
+ m->ol_flags &= ~PKT_RX_CRYPTO_DIGEST_BAD;
+
+ /* trim area used for digest from mbuf */
+ rte_pktmbuf_trim(m, get_digest_byte_length(job->hash_alg));
+ }
+
+ return m;
+}
+
+/**
+ * Process a completed JOB_AES_HMAC job and keep processing jobs until
+ * get_completed_job return NULL
+ *
+ * @param qp Queue Pair to process
+ * @param job JOB_AES_HMAC job
+ *
+ * @return
+ * - Number of processed jobs
+ */
+static unsigned
+handle_completed_jobs(struct aesni_mb_qp *qp, JOB_AES_HMAC *job)
+{
+ struct rte_mbuf *m = NULL;
+ unsigned processed_jobs = 0;
+
+ while (job) {
+ processed_jobs++;
+ m = post_process_job(job);
+ if (m)
+ rte_ring_enqueue(qp->processed_pkts, (void *)m);
+ else
+ qp->qp_stats.dequeue_err_count++;
+
+ job = (*qp->mb_ops->job.get_completed_job)(&qp->mb_mgr);
+ }
+
+ return processed_jobs;
+}
+
+
+static uint16_t
+aesni_mb_pmd_enqueue_burst(void *queue_pair,
+ struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+ struct aesni_mb_qp *qp = queue_pair;
+ JOB_AES_HMAC *job = NULL;
+
+ int i, processed_jobs = 0;
+
+ for (i = 0; i < nb_bufs; i++) {
+
+ if (unlikely(!(bufs[i]->ol_flags & PKT_TX_CRYPTO_OP))) {
+ qp->qp_stats.enqueue_err_count++;
+ goto flush_jobs;
+ }
+
+ job = (*qp->mb_ops->job.get_next)(&qp->mb_mgr);
+ if (unlikely(job == NULL)) {
+ qp->qp_stats.enqueue_err_count++;
+ goto flush_jobs;
+ }
+
+ job = process_crypto_op(qp, job, bufs[i]);
+ if (unlikely(job == NULL)) {
+ qp->qp_stats.enqueue_err_count++;
+ goto flush_jobs;
+ }
+
+ /* Submit Job */
+ job = (*qp->mb_ops->job.submit)(&qp->mb_mgr);
+ qp->qp_stats.enqueued_count++;
+
+ /* If submit return a processed job then handle it, before
+ * submitting subsequent jobs */
+ if (job)
+ processed_jobs += handle_completed_jobs(qp, job);
+ }
+
+ if (processed_jobs == 0)
+ goto flush_jobs;
+ else
+ qp->qp_stats.dequeued_count += processed_jobs;
+ return i;
+
+flush_jobs:
+ /* if we haven't processed any jobs in submit loop, then flush jobs
+ * queue to stop the output stalling */
+ job = (*qp->mb_ops->job.flush_job)(&qp->mb_mgr);
+ if (job)
+ qp->qp_stats.dequeued_count += handle_completed_jobs(qp, job);
+
+ return i;
+}
+
+static uint16_t
+aesni_mb_pmd_dequeue_burst(void *queue_pair,
+ struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+ struct aesni_mb_qp *qp = queue_pair;
+ unsigned i, nb_dequeued;
+
+ nb_dequeued = rte_ring_dequeue_burst(qp->processed_pkts,
+ (void **)bufs, nb_bufs);
+
+ for (i = 0; i < nb_dequeued; i++) {
+ /* Free session if a session-less crypto op */
+ if (bufs[i]->crypto_op->type == RTE_CRYPTO_OP_SESSIONLESS) {
+ aesni_mb_free_session(qp->sess_mp,
+ (struct aesni_mb_session *)bufs[i]->crypto_op->session);
+ bufs[i]->crypto_op->session = NULL;
+ }
+ }
+
+ return nb_dequeued;
+}
+
+
+static int cryptodev_aesni_mb_uninit(const char *name);
+
+static int
+cryptodev_aesni_mb_create(const char *name, unsigned socket_id)
+{
+ struct rte_cryptodev *dev;
+ char crypto_dev_name[RTE_CRYPTODEV_NAME_MAX_LEN];
+ struct aesni_mb_private *internals;
+ enum aesni_mb_vector_mode vector_mode;
+
+ /* Check CPU for support for AES instruction set */
+ if (!rte_cpu_get_flag_enabled(RTE_CPUFLAG_AES)) {
+ MB_LOG_ERR("AES instructions not supported by CPU");
+ return -EFAULT;
+ }
+
+ /* Check CPU for supported vector instruction set */
+ if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2))
+ vector_mode = RTE_AESNI_MB_AVX2;
+ else if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX))
+ vector_mode = RTE_AESNI_MB_AVX;
+ else if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_SSE4_1))
+ vector_mode = RTE_AESNI_MB_SSE;
+ else {
+ MB_LOG_ERR("Vector instructions are not supported by CPU");
+ return -EFAULT;
+ }
+
+ /* create a unique device name */
+ if (create_unique_device_name(crypto_dev_name,
+ RTE_CRYPTODEV_NAME_MAX_LEN) != 0) {
+ MB_LOG_ERR("failed to create unique cryptodev name");
+ return -EINVAL;
+ }
+
+
+ dev = rte_cryptodev_pmd_virtual_dev_init(crypto_dev_name,
+ sizeof(struct aesni_mb_private), socket_id);
+ if (dev == NULL) {
+ MB_LOG_ERR("failed to create cryptodev vdev");
+ goto init_error;
+ }
+
+ dev->dev_type = RTE_CRYPTODEV_AESNI_MB_PMD;
+ dev->dev_ops = rte_aesni_mb_pmd_ops;
+
+ /* register rx/tx burst functions for data path */
+ dev->dequeue_burst = aesni_mb_pmd_dequeue_burst;
+ dev->enqueue_burst = aesni_mb_pmd_enqueue_burst;
+
+ /* Set vector instructions mode supported */
+ internals = dev->data->dev_private;
+
+ internals->vector_mode = vector_mode;
+ internals->max_nb_qpairs = AESNI_MB_MAX_NB_QUEUE_PAIRS;
+
+ return dev->data->dev_id;
+init_error:
+ MB_LOG_ERR("driver %s: cryptodev_aesni_create failed", name);
+
+ cryptodev_aesni_mb_uninit(crypto_dev_name);
+ return -EFAULT;
+}
+
+
+static int
+cryptodev_aesni_mb_init(const char *name,
+ const char *params __rte_unused)
+{
+ RTE_LOG(INFO, PMD, "Initialising %s\n", name);
+
+ return cryptodev_aesni_mb_create(name, rte_socket_id());
+}
+
+static int
+cryptodev_aesni_mb_uninit(const char *name)
+{
+ if (name == NULL)
+ return -EINVAL;
+
+ RTE_LOG(INFO, PMD, "Closing AESNI crypto device %s on numa socket %u\n",
+ name, rte_socket_id());
+
+ return 0;
+}
+
+static struct rte_driver cryptodev_aesni_mb_pmd_drv = {
+ .name = CRYPTODEV_NAME_AESNI_MB_PMD,
+ .type = PMD_VDEV,
+ .init = cryptodev_aesni_mb_init,
+ .uninit = cryptodev_aesni_mb_uninit
+};
+
+PMD_REGISTER_DRIVER(cryptodev_aesni_mb_pmd_drv);
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
new file mode 100644
index 0000000..fb57e7b
--- /dev/null
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_ops.c
@@ -0,0 +1,346 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Intel Corporation. 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 <rte_common.h>
+#include <rte_cryptodev.h>
+
+#include "rte_aesni_mb_pmd_private.h"
+
+/** Configure device */
+static int
+aesni_mb_pmd_config(__rte_unused struct rte_cryptodev *dev)
+{
+ return 0;
+}
+
+/** Start device */
+static int
+aesni_mb_pmd_start(__rte_unused struct rte_cryptodev *dev)
+{
+ return -ENOTSUP;
+}
+
+/** Stop device */
+static void
+aesni_mb_pmd_stop(__rte_unused struct rte_cryptodev *dev)
+{
+}
+
+/** Close device */
+static void
+aesni_mb_pmd_close(__rte_unused struct rte_cryptodev *dev)
+{
+}
+
+
+/** Get device statistics */
+static void
+aesni_mb_pmd_stats_get(struct rte_cryptodev *dev,
+ struct rte_cryptodev_stats *stats)
+{
+ int qp_id;
+
+ for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {
+ struct aesni_mb_qp *qp = dev->data->queue_pairs[qp_id];
+
+ stats->enqueued_count += qp->qp_stats.enqueued_count;
+ stats->dequeued_count += qp->qp_stats.dequeued_count;
+
+ stats->enqueue_err_count += qp->qp_stats.enqueue_err_count;
+ stats->dequeue_err_count += qp->qp_stats.dequeue_err_count;
+ }
+}
+
+/** Reset device statistics */
+static void
+aesni_mb_pmd_stats_reset(struct rte_cryptodev *dev)
+{
+ int qp_id;
+
+ for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {
+ struct aesni_mb_qp *qp = dev->data->queue_pairs[qp_id];
+
+ memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
+ }
+}
+
+
+/** Get device info */
+static void
+aesni_mb_pmd_info_get(struct rte_cryptodev *dev,
+ struct rte_cryptodev_info *dev_info)
+{
+ struct aesni_mb_private *internals = dev->data->dev_private;
+
+ if (dev_info != NULL) {
+ dev_info->dev_type = dev->dev_type;
+ dev_info->max_queue_pairs = internals->max_nb_qpairs;
+ }
+}
+
+/** Release queue pair */
+static void
+aesni_mb_pmd_qp_release(struct rte_cryptodev *dev, uint16_t qp_id)
+{
+ if (dev->data->queue_pairs[qp_id] != NULL) {
+ rte_free(dev->data->queue_pairs[qp_id]);
+ dev->data->queue_pairs[qp_id] = NULL;
+ }
+}
+
+/** set a unique name for the queue pair based on it's name, dev_id and qp_id */
+static int
+aesni_mb_pmd_qp_set_unique_name(struct rte_cryptodev *dev,
+ struct aesni_mb_qp *qp)
+{
+ unsigned n = snprintf(qp->name, sizeof(qp->name),
+ "aesni_mb_pmd_%u_qp_%u",
+ dev->data->dev_id, qp->id);
+
+ if (n > sizeof(qp->name))
+ return -1;
+
+ return 0;
+}
+
+/** Create a ring to place process packets on */
+static struct rte_ring *
+aesni_mb_pmd_qp_create_processed_pkts_ring(struct aesni_mb_qp *qp,
+ unsigned ring_size, int socket_id)
+{
+ struct rte_ring *r;
+
+ r = rte_ring_lookup(qp->name);
+ if (r) {
+ if (r->prod.size >= ring_size) {
+ MB_LOG_INFO("Reusing existing ring %s for processed packets", qp->name);
+ return r;
+ } else {
+ MB_LOG_ERR("Unable to reuse existing ring %s for processed packets", qp->name);
+ return NULL;
+ }
+ }
+
+ return rte_ring_create(qp->name, ring_size, socket_id,
+ RING_F_SP_ENQ | RING_F_SC_DEQ);
+}
+
+/** Setup a queue pair */
+static int
+aesni_mb_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
+ const struct rte_cryptodev_qp_conf *qp_conf,
+ int socket_id)
+{
+ struct aesni_mb_qp *qp = NULL;
+ struct aesni_mb_private *internals = dev->data->dev_private;
+
+ /* Free memory prior to re-allocation if needed. */
+ if (dev->data->queue_pairs[qp_id] != NULL)
+ aesni_mb_pmd_qp_release(dev, qp_id);
+
+ /* Allocate the queue pair data structure. */
+ qp = rte_zmalloc_socket("AES-NI PMD Queue Pair", sizeof(*qp),
+ RTE_CACHE_LINE_SIZE, socket_id);
+ if (qp == NULL)
+ return (-ENOMEM);
+
+ qp->id = qp_id;
+ dev->data->queue_pairs[qp_id] = qp;
+
+ if (aesni_mb_pmd_qp_set_unique_name(dev, qp))
+ goto qp_setup_cleanup;
+
+ qp->mb_ops = &job_ops[internals->vector_mode];
+
+ qp->processed_pkts = aesni_mb_pmd_qp_create_processed_pkts_ring(qp,
+ qp_conf->nb_descriptors, socket_id);
+
+ if (qp->processed_pkts == NULL)
+ goto qp_setup_cleanup;
+
+ qp->sess_mp = internals->sess_mp;
+
+ memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
+
+ /* Initialise multi-buffer manager */
+ (*qp->mb_ops->job.init_mgr)(&qp->mb_mgr);
+
+ return 0;
+
+qp_setup_cleanup:
+ if (qp)
+ rte_free(qp);
+
+ return -1;
+}
+
+/** Start queue pair */
+static int
+aesni_mb_pmd_qp_start(__rte_unused struct rte_cryptodev *dev,
+ __rte_unused uint16_t queue_pair_id)
+{
+ return -ENOTSUP;
+}
+
+/** Stop queue pair */
+static int
+aesni_mb_pmd_qp_stop(__rte_unused struct rte_cryptodev *dev,
+ __rte_unused uint16_t queue_pair_id)
+{
+ return -ENOTSUP;
+}
+
+/** Return the number of allocated queue pairs */
+static uint32_t
+aesni_mb_pmd_qp_count(struct rte_cryptodev *dev)
+{
+ return dev->data->nb_queue_pairs;
+}
+
+
+static void
+session_obj_init(__rte_unused struct rte_mempool *mp,
+ __rte_unused void *user_arg, __rte_unused void *element,
+ __rte_unused unsigned element_idx)
+{
+}
+
+static int
+aesni_mb_pmd_session_mempool_create(struct rte_cryptodev *dev,
+ unsigned nb_objs, unsigned obj_cache_size, int socket_id)
+{
+ struct aesni_mb_private *internals = dev->data->dev_private;
+
+ unsigned n = snprintf(internals->sess_mp_name,
+ sizeof(internals->sess_mp_name), "mb_cdev_%d_sess_mp",
+ dev->data->dev_id);
+
+ if (n > sizeof(internals->sess_mp_name)){
+ MB_LOG_ERR("Unable to create unique name for session mempool");
+ return -ENOMEM;
+ }
+ internals->sess_mp = rte_mempool_lookup(internals->sess_mp_name);
+ if (internals->sess_mp != NULL) {
+ if (internals->sess_mp->elt_size != sizeof(struct aesni_mb_session) ||
+ internals->sess_mp->cache_size < obj_cache_size ||
+ internals->sess_mp->size < nb_objs) {
+
+ MB_LOG_ERR("%s mempool already exists with different "
+ "initialisation parameters",
+ internals->sess_mp_name);
+ internals->sess_mp = NULL;
+ return -ENOMEM;
+ }
+ } else {
+ internals->sess_mp = rte_mempool_create(
+ internals->sess_mp_name, /* mempool name */
+ nb_objs, /* number of elements*/
+ sizeof(struct aesni_mb_session),/* element size*/
+ obj_cache_size, /* Cache size*/
+ 0, /* private data size */
+ NULL, /* obj initialisation constructor */
+ NULL, /* obj initialisation constructor argument */
+ session_obj_init, /* obj constructor */
+ NULL, /* obj constructor argument */
+ socket_id, /* socket id */
+ 0); /* flags */
+
+ if (internals->sess_mp == NULL) {
+ MB_LOG_ERR("%s mempool allocation failed",
+ internals->sess_mp_name);
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+static struct rte_cryptodev_session *
+aesni_mb_pmd_create_session(struct rte_cryptodev *dev,
+ struct rte_crypto_cipher_params *cipher_setup_data,
+ struct rte_crypto_hash_params *hash_setup_data,
+ enum rte_crypto_operation_chain op_chain)
+{
+ struct aesni_mb_private *internals = dev->data->dev_private;
+ struct aesni_mb_session *sess =
+ aesni_mb_get_session(internals->sess_mp);
+
+ if (unlikely(sess == NULL)) {
+ MB_LOG_ERR("failed to get session from mempool");
+ return NULL;
+ }
+
+ if (aesni_mb_set_session_parameters(
+ &job_ops[internals->vector_mode], sess,
+ cipher_setup_data, hash_setup_data, op_chain) != 0) {
+ aesni_mb_free_session(internals->sess_mp, sess);
+ }
+
+ return (struct rte_cryptodev_session *)sess;
+}
+
+static void
+aesni_mb_pmd_destroy_session(struct rte_cryptodev *dev,
+ struct rte_cryptodev_session *sess)
+{
+ struct aesni_mb_private *internals = dev->data->dev_private;
+
+ if (sess)
+ aesni_mb_free_session(internals->sess_mp,
+ (struct aesni_mb_session *)sess);
+}
+
+struct rte_cryptodev_ops aesni_mb_pmd_ops = {
+ .dev_configure = aesni_mb_pmd_config,
+ .dev_start = aesni_mb_pmd_start,
+ .dev_stop = aesni_mb_pmd_stop,
+ .dev_close = aesni_mb_pmd_close,
+
+ .stats_get = aesni_mb_pmd_stats_get,
+ .stats_reset = aesni_mb_pmd_stats_reset,
+
+ .dev_infos_get = aesni_mb_pmd_info_get,
+
+ .queue_pair_setup = aesni_mb_pmd_qp_setup,
+ .queue_pair_release = aesni_mb_pmd_qp_release,
+ .queue_pair_start = aesni_mb_pmd_qp_start,
+ .queue_pair_stop = aesni_mb_pmd_qp_stop,
+ .queue_pair_count = aesni_mb_pmd_qp_count,
+
+ .session_mp_create = aesni_mb_pmd_session_mempool_create,
+
+ .session_create = aesni_mb_pmd_create_session,
+ .session_destroy = aesni_mb_pmd_destroy_session
+};
+
+struct rte_cryptodev_ops *rte_aesni_mb_pmd_ops = &aesni_mb_pmd_ops;
+
diff --git a/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_private.h b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_private.h
new file mode 100644
index 0000000..c5c4a86
--- /dev/null
+++ b/drivers/crypto/aesni_mb/rte_aesni_mb_pmd_private.h
@@ -0,0 +1,224 @@
+/*-
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Intel Corporation. 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.
+ */
+
+#ifndef _RTE_AESNI_MB_PMD_PRIVATE_H_
+#define _RTE_AESNI_MB_PMD_PRIVATE_H_
+
+#include "aesni_mb_ops.h"
+
+#define MB_LOG_ERR(fmt, args...) do { \
+ RTE_LOG(ERR, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+ CRYPTODEV_NAME_AESNI_MB_PMD, \
+ __func__, __LINE__, ## args); \
+ } while (0)
+
+#ifdef RTE_LIBRTE_AESNI_MB_DEBUG
+#define MB_LOG_INFO(fmt, args...) do { \
+ RTE_LOG(INFO, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+ CRYPTODEV_NAME_AESNI_MB_PMD, \
+ __func__, __LINE__, ## args); \
+ } while (0)
+
+#define MB_LOG_DBG(fmt, args...) do { \
+ RTE_LOG(DEBUG, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+ CRYPTODEV_NAME_AESNI_MB_PMD, \
+ __func__, __LINE__, ## args); \
+ } while (0)
+#else
+#define MB_LOG_INFO(fmt, args...)
+#define MB_LOG_DBG(fmt, args...)
+#endif
+
+#define AESNI_MB_NAME_MAX_LENGTH (64)
+#define AESNI_MB_MAX_NB_QUEUE_PAIRS (4)
+
+#define HMAC_IPAD_VALUE (0x36)
+#define HMAC_OPAD_VALUE (0x5C)
+
+static const unsigned auth_blocksize[] = {
+ [MD5] = 64,
+ [SHA1] = 64,
+ [SHA_224] = 64,
+ [SHA_256] = 64,
+ [SHA_384] = 128,
+ [SHA_512] = 128,
+ [AES_XCBC] = 16,
+};
+
+/**
+ * Get the blocksize in bytes for a specified authentication algorithm
+ *
+ * @Note: this function will not return a valid value for a non-valid
+ * authentication algorithm
+ */
+static inline unsigned
+get_auth_algo_blocksize(JOB_HASH_ALG algo)
+{
+ return auth_blocksize[algo];
+}
+
+static const unsigned auth_truncated_digest_byte_lengths[] = {
+ [MD5] = 12,
+ [SHA1] = 12,
+ [SHA_224] = 14,
+ [SHA_256] = 16,
+ [SHA_384] = 24,
+ [SHA_512] = 32,
+ [AES_XCBC] = 12,
+};
+
+/**
+ * Get the IPsec specified truncated length in bytes of the HMAC digest for a
+ * specified authentication algorithm
+ *
+ * @Note: this function will not return a valid value for a non-valid
+ * authentication algorithm
+ */
+static inline unsigned
+get_truncated_digest_byte_length(JOB_HASH_ALG algo)
+{
+ return auth_truncated_digest_byte_lengths[algo];
+}
+
+static const unsigned auth_digest_byte_lengths[] = {
+ [MD5] = 16,
+ [SHA1] = 20,
+ [SHA_224] = 28,
+ [SHA_256] = 32,
+ [SHA_384] = 48,
+ [SHA_512] = 64,
+ [AES_XCBC] = 16,
+};
+
+/**
+ * Get the output digest size in bytes for a specified authentication algorithm
+ *
+ * @Note: this function will not return a valid value for a non-valid
+ * authentication algorithm
+ */
+static inline unsigned
+get_digest_byte_length(JOB_HASH_ALG algo)
+{
+ return auth_digest_byte_lengths[algo];
+}
+
+
+/** private data structure for each virtual AESNI device */
+struct aesni_mb_private {
+ enum aesni_mb_vector_mode vector_mode;
+
+ char sess_mp_name[AESNI_MB_NAME_MAX_LENGTH];
+ struct rte_mempool *sess_mp;
+
+ unsigned max_nb_qpairs;
+};
+
+struct aesni_mb_qp {
+ uint16_t id; /**< Queue Pair Identifier */
+ char name[AESNI_MB_NAME_MAX_LENGTH]; /**< Unique Queue Pair Name */
+ const struct aesni_mb_ops *mb_ops; /**<
+ * Architecture dependent function
+ * pointer table of the multi-buffer
+ * APIs */
+ MB_MGR mb_mgr; /**< Multi-buffer instance */
+ struct rte_ring *processed_pkts; /**< Ring for placing process packets */
+ struct rte_mempool *sess_mp; /**< Crypto Session mempool */
+
+ struct rte_cryptodev_stats qp_stats; /**< Queue pair statistics */
+} __rte_cache_aligned;
+
+
+/** AES-NI Multi buffer session */
+struct aesni_mb_session {
+ JOB_CHAIN_ORDER chain_order;
+
+ struct {
+ JOB_CIPHER_DIRECTION direction; /**< Cipher direction - encrypt / decrypt */
+ JOB_CIPHER_MODE mode; /**< Cipher mode - CBC / Counter */
+
+ uint64_t key_length_in_bytes;
+
+ struct {
+ uint32_t encode[256] __rte_align(16); /**< encode key */
+ uint32_t decode[256] __rte_align(16); /**< decode key */
+ } expanded_aes_keys;
+ /**< Expanded AES keys - Allocating space to contain the
+ * maximum expanded key size which is 240 bytes for 256 bit
+ * AES, calculate by: ((key size (bytes)) * ((number of rounds) + 1)) */
+ } cipher; /**< Cipher Parameters */
+
+ struct {
+ JOB_HASH_ALG algo; /** Authentication Algorithm */
+
+ struct {
+ uint8_t inner[128] __rte_align(16); /**< inner pad */
+ uint8_t outer[128] __rte_align(16); /**< outer pad */
+ } pads;
+ /** HMAC Authentication pads - allocating space for the maximum
+ * pad size supported which is 128 bytes for SHA512 */
+
+ uint8_t digest[64] __rte_align(16);
+ } auth; /**< Authentication Parameters */
+} __rte_cache_aligned;
+
+
+static inline struct aesni_mb_session *
+aesni_mb_get_session(struct rte_mempool *mempool)
+{
+ struct aesni_mb_session *sess;
+
+ if (rte_mempool_get(mempool, (void **)&sess)) {
+ return NULL;
+ }
+ return sess;
+}
+
+static inline void
+aesni_mb_free_session(struct rte_mempool *mempool,
+ struct aesni_mb_session *sess)
+{
+ rte_mempool_put(mempool, (void *)sess);
+}
+
+extern int
+aesni_mb_set_session_parameters(const struct aesni_mb_ops *mb_ops,
+ struct aesni_mb_session *sess,
+ struct rte_crypto_cipher_params *cparams,
+ struct rte_crypto_hash_params *aparams,
+ enum rte_crypto_operation_chain op_chain);
+
+extern struct rte_cryptodev_ops *rte_aesni_mb_pmd_ops;
+
+
+
+#endif /* _RTE_AESNI_MB_PMD_PRIVATE_H_ */
+
diff --git a/drivers/crypto/aesni_mb/rte_pmd_aesni_version.map b/drivers/crypto/aesni_mb/rte_pmd_aesni_version.map
new file mode 100644
index 0000000..39cc84f
--- /dev/null
+++ b/drivers/crypto/aesni_mb/rte_pmd_aesni_version.map
@@ -0,0 +1,5 @@
+DPDK_2.2 {
+ global:
+
+ local: *;
+};
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 5502cc4..496cbeb 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -148,6 +148,10 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += -lrte_pmd_null
# QAT PMD has a dependancy on libcrypto (from openssl) for calculating HMAC precomputes
_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_QAT) += -lrte_pmd_qat -lcrypto
+# AESNI MULTI BUFFER is dependent on the IPSec_MB library
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_AESNI_MB) += -lrte_pmd_aesni_mb
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_AESNI_MB) += -L$(AESNI_MULTI_BUFFER_LIB_PATH) -lIPSec_MB
+
endif # ! $(CONFIG_RTE_BUILD_SHARED_LIB)
endif # ! CONFIG_RTE_BUILD_COMBINE_LIBS
--
1.9.3
next prev parent reply other threads:[~2015-08-20 13:59 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-08-20 14:07 [dpdk-dev] [PATCH 0/4] A proposed DPDK Crypto API and device framework Declan Doherty
2015-08-20 14:07 ` [dpdk-dev] [PATCH 1/4] cryptodev: Initial DPDK Crypto APIs and device framework release Declan Doherty
2015-08-20 19:07 ` Neil Horman
2015-08-21 14:02 ` Declan Doherty
2015-09-15 16:36 ` [dpdk-dev] [PATCH] cryptodev: changes to crypto operation APIs to support non prescriptive chaining of crypto transforms in a crypto operation. app/test: updates to cryptodev unit tests to support new xform chaining APIs. aesni_mb_pmd: updates to device to support API changes Declan Doherty
2015-08-20 14:07 ` [dpdk-dev] [PATCH 2/4] qat_crypto_pmd: Addition of a new QAT DPDK PMD Declan Doherty
2015-08-20 14:07 ` Declan Doherty [this message]
2015-08-20 14:07 ` [dpdk-dev] [PATCH 4/4] app/test: add cryptodev unit and performance tests Declan Doherty
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1440079643-5437-4-git-send-email-declan.doherty@intel.com \
--to=declan.doherty@intel.com \
--cc=dev@dpdk.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).