@@ -168,6 +168,13 @@ CONFIG_RTE_LIBRTE_QAT_DEBUG_DRIVER=n
#
CONFIG_RTE_MAX_QAT_SESSIONS=200
+
+#
+# Compile PMD for AESNI backed device
+#
+CONFIG_RTE_LIBRTE_PMD_AESNI_MB=n
+CONFIG_RTE_LIBRTE_AESNI_MB_DEBUG=n
+
#
# Support NIC bypass logic
#
@@ -166,6 +166,12 @@ CONFIG_RTE_LIBRTE_PMD_QAT_DEBUG_DRIVER=n
#
CONFIG_RTE_LIBRTE_PMD_QAT_MAX_SESSIONS=2048
+# Compile PMD for AESNI backed device
+#
+CONFIG_RTE_LIBRTE_PMD_AESNI_MB=n
+CONFIG_RTE_LIBRTE_PMD_AESNI_MB_DEBUG=n
+CONFIG_RTE_LIBRTE_PMD_AESNI_MB_MAX_SESSIONS=2048
+
#
# Support NIC bypass logic
#
new file mode 100644
@@ -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.
@@ -39,4 +39,5 @@ Crypto Device Drivers
:maxdepth: 2
:numbered:
+ aesni_mb
qat
@@ -31,6 +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
new file mode 100644
@@ -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
new file mode 100644
@@ -0,0 +1,212 @@
+/*-
+ * 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_128_enc_t)(void *key, void *enc_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 *exp_k1, 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_128_enc_t aes128_enc;/**< AES128 enc key expansion */
+ 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_128_enc_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_128_enc_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_128_enc_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_ */
new file mode 100644
@@ -0,0 +1,790 @@
+/*-
+ * 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_config.h>
+#include <rte_hexdump.h>
+#include <rte_cryptodev.h>
+#include <rte_cryptodev_pmd.h>
+#include <rte_dev.h>
+#include <rte_malloc.h>
+#include <rte_cpuflags.h>
+#include <rte_mbuf_offload.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;
+
+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_aligned(16);
+ uint8_t opad_buf[blocksize] __rte_aligned(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);
+}
+
+/** Get xform chain order */
+static int
+aesni_mb_get_chain_order(const struct rte_crypto_xform *xform)
+{
+ /* multi-buffer only supports HASH_CIPHER or CIPHER_HASH chained
+ * operations, all other options are invalid, so we must have exactly
+ * 2 xform structs chained together */
+ if (xform->next == NULL || xform->next->next != NULL)
+ return -1;
+
+ if (xform->type == RTE_CRYPTO_XFORM_AUTH &&
+ xform->next->type == RTE_CRYPTO_XFORM_CIPHER)
+ return HASH_CIPHER;
+
+ if (xform->type == RTE_CRYPTO_XFORM_CIPHER &&
+ xform->next->type == RTE_CRYPTO_XFORM_AUTH)
+ return CIPHER_HASH;
+
+ return -1;
+}
+
+/** Set session authentication parameters */
+static int
+aesni_mb_set_session_auth_parameters(const struct aesni_mb_ops *mb_ops,
+ struct aesni_mb_session *sess,
+ const struct rte_crypto_xform *xform)
+{
+ hash_one_block_t hash_oneblock_fn;
+
+ if (xform->type != RTE_CRYPTO_XFORM_AUTH) {
+ MB_LOG_ERR("Crypto xform struct not of type auth");
+ return -1;
+ }
+
+ /* Set Authentication Parameters */
+ if (xform->auth.algo == RTE_CRYPTO_AUTH_AES_XCBC_MAC) {
+ sess->auth.algo = AES_XCBC;
+ (*mb_ops->aux.keyexp.aes_xcbc)(xform->auth.key.data,
+ sess->auth.xcbc.k1_expanded,
+ sess->auth.xcbc.k2, sess->auth.xcbc.k3);
+ return 0;
+ }
+
+ switch (xform->auth.algo) {
+ case RTE_CRYPTO_AUTH_MD5_HMAC:
+ sess->auth.algo = MD5;
+ hash_oneblock_fn = mb_ops->aux.one_block.md5;
+ break;
+ case RTE_CRYPTO_AUTH_SHA1_HMAC:
+ sess->auth.algo = SHA1;
+ hash_oneblock_fn = mb_ops->aux.one_block.sha1;
+ break;
+ case RTE_CRYPTO_AUTH_SHA224_HMAC:
+ sess->auth.algo = SHA_224;
+ hash_oneblock_fn = mb_ops->aux.one_block.sha224;
+ break;
+ case RTE_CRYPTO_AUTH_SHA256_HMAC:
+ sess->auth.algo = SHA_256;
+ hash_oneblock_fn = mb_ops->aux.one_block.sha256;
+ break;
+ case RTE_CRYPTO_AUTH_SHA384_HMAC:
+ sess->auth.algo = SHA_384;
+ hash_oneblock_fn = mb_ops->aux.one_block.sha384;
+ break;
+ case RTE_CRYPTO_AUTH_SHA512_HMAC:
+ sess->auth.algo = SHA_512;
+ hash_oneblock_fn = mb_ops->aux.one_block.sha512;
+ break;
+ default:
+ MB_LOG_ERR("Unsupported authentication algorithm selection");
+ return -1;
+ }
+
+ /* Calculate Authentication precomputes */
+ calculate_auth_precomputes(hash_oneblock_fn,
+ sess->auth.pads.inner, sess->auth.pads.outer,
+ xform->auth.key.data,
+ xform->auth.key.length,
+ get_auth_algo_blocksize(sess->auth.algo));
+
+ return 0;
+}
+
+/** Set session cipher parameters */
+static int
+aesni_mb_set_session_cipher_parameters(const struct aesni_mb_ops *mb_ops,
+ struct aesni_mb_session *sess,
+ const struct rte_crypto_xform *xform)
+{
+ aes_keyexp_t aes_keyexp_fn;
+
+ if (xform->type != RTE_CRYPTO_XFORM_CIPHER) {
+ MB_LOG_ERR("Crypto xform struct not of type cipher");
+ return -1;
+ }
+
+ /* Select cipher direction */
+ switch (xform->cipher.op) {
+ case RTE_CRYPTO_CIPHER_OP_ENCRYPT:
+ sess->cipher.direction = ENCRYPT;
+ break;
+ case RTE_CRYPTO_CIPHER_OP_DECRYPT:
+ sess->cipher.direction = DECRYPT;
+ break;
+ default:
+ MB_LOG_ERR("Unsupported cipher operation parameter");
+ return -1;
+ }
+
+
+ /* Select cipher mode */
+ switch (xform->cipher.algo) {
+ case RTE_CRYPTO_CIPHER_AES_CBC:
+ sess->cipher.mode = CBC;
+ break;
+ default:
+ MB_LOG_ERR("Unsupported cipher mode parameter");
+ return -1;
+ }
+
+ /* Check key length and choose key expansion function */
+ switch (xform->cipher.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:
+ MB_LOG_ERR("Unsupported cipher key length");
+ return -1;
+ }
+
+ /* Expanded cipher keys */
+ (*aes_keyexp_fn)(xform->cipher.key.data,
+ sess->cipher.expanded_aes_keys.encode,
+ sess->cipher.expanded_aes_keys.decode);
+
+ return 0;
+}
+
+/** Parse crypto xform chain and set private session parameters */
+int
+aesni_mb_set_session_parameters(const struct aesni_mb_ops *mb_ops,
+ struct aesni_mb_session *sess,
+ const struct rte_crypto_xform *xform)
+{
+ const struct rte_crypto_xform *auth_xform = NULL;
+ const struct rte_crypto_xform *cipher_xform = NULL;
+
+ /* Select Crypto operation - hash then cipher / cipher then hash */
+ switch (aesni_mb_get_chain_order(xform)) {
+ case HASH_CIPHER:
+ sess->chain_order = HASH_CIPHER;
+ auth_xform = xform;
+ cipher_xform = xform->next;
+ break;
+ case CIPHER_HASH:
+ sess->chain_order = CIPHER_HASH;
+ auth_xform = xform->next;
+ cipher_xform = xform;
+ break;
+ default:
+ MB_LOG_ERR("Unsupported operation chain order parameter");
+ return -1;
+ }
+
+ if (aesni_mb_set_session_auth_parameters(mb_ops, sess, auth_xform)) {
+ MB_LOG_ERR("Invalid/unsupported authentication parameters");
+ return -1;
+ }
+
+ if (aesni_mb_set_session_cipher_parameters(mb_ops, sess, cipher_xform)) {
+ MB_LOG_ERR("Invalid/unsupported cipher parameters");
+ return -1;
+ }
+ return 0;
+}
+
+/** Get multi buffer session */
+static struct aesni_mb_session *
+aesni_mb_get_session(struct aesni_mb_qp *qp, struct rte_crypto_op *crypto_op)
+{
+ struct aesni_mb_session *sess;
+
+ if (crypto_op->type == RTE_CRYPTO_OP_WITH_SESSION) {
+ if (unlikely(crypto_op->session->type !=
+ RTE_CRYPTODEV_AESNI_MB_PMD))
+ return NULL;
+
+ sess = (struct aesni_mb_session *)crypto_op->session->_private;
+ } else {
+ struct rte_cryptodev_session *c_sess = NULL;
+
+ if (rte_mempool_get(qp->sess_mp, (void **)&c_sess))
+ return NULL;
+
+ sess = (struct aesni_mb_session *)c_sess->_private;
+
+ if (unlikely(aesni_mb_set_session_parameters(qp->mb_ops,
+ sess, crypto_op->xform) != 0))
+ return NULL;
+ }
+
+ return sess;
+}
+
+/**
+ * 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_mb_crypto_op(struct aesni_mb_qp *qp, struct rte_mbuf *m,
+ struct rte_crypto_op *c_op, struct aesni_mb_session *session)
+{
+ JOB_AES_HMAC *job;
+
+ job = (*qp->mb_ops->job.get_next)(&qp->mb_mgr);
+ if (unlikely(job == NULL))
+ return job;
+
+ /* Set crypto operation */
+ job->chain_order = session->chain_order;
+
+ /* Set cipher parameters */
+ job->cipher_direction = session->cipher.direction;
+ job->cipher_mode = session->cipher.mode;
+
+ job->aes_key_len_in_bytes = session->cipher.key_length_in_bytes;
+ job->aes_enc_key_expanded = session->cipher.expanded_aes_keys.encode;
+ job->aes_dec_key_expanded = session->cipher.expanded_aes_keys.decode;
+
+
+ /* Set authentication parameters */
+ job->hash_alg = session->auth.algo;
+ if (job->hash_alg == AES_XCBC) {
+ job->_k1_expanded = session->auth.xcbc.k1_expanded;
+ job->_k2 = session->auth.xcbc.k2;
+ job->_k3 = session->auth.xcbc.k3;
+ } else {
+ job->hashed_auth_key_xor_ipad = session->auth.pads.inner;
+ job->hashed_auth_key_xor_opad = session->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;
+ }
+
+ /* Multiple buffer library current only support returning a truncated digest length
+ * as specified in the relevant IPsec RFCs */
+ job->auth_tag_output_len_in_bytes =
+ get_truncated_digest_byte_length(job->hash_alg);
+
+ /* 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.m ?
+ rte_pktmbuf_mtod(c_op->dst.m, uint8_t *) +
+ c_op->dst.offset :
+ 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;
+ job->user_data2 = c_op;
+
+ return job;
+}
+
+/**
+ * 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
+ *
+ */
+static int
+process_gcm_crypto_op(struct aesni_mb_qp *qp, struct rte_mbuf *m,
+ struct rte_crypto_op *c_op, struct aesni_mb_session *session)
+{
+ uint8_t *src, *dst;
+
+ src = rte_pktmbuf_mtod(m, uint8_t *) + c_op->data.to_cipher.offset;
+ dst = c_op->dst.m ?
+ rte_pktmbuf_mtod(c_op->dst.m, uint8_t *) +
+ c_op->dst.offset :
+ rte_pktmbuf_mtod(m, uint8_t *) +
+ c_op->data.to_cipher.offset;
+
+ if (session->cipher.direction == ENCRYPT) {
+
+ (*qp->mb_ops->gcm.enc)(&session->gdata, dst, src,
+ (uint64_t)c_op->data.to_cipher.length,
+ c_op->iv.data,
+ c_op->additional_auth.data,
+ (uint64_t)c_op->additional_auth.length,
+ c_op->digest.data,
+ (uint64_t)c_op->digest.length);
+ } else {
+ uint8_t *auth_tag = (uint8_t *)rte_pktmbuf_append(m,
+ c_op->digest.length);
+
+ if (!auth_tag)
+ return -1;
+
+ (*qp->mb_ops->gcm.dec)(&session->gdata, dst, src,
+ (uint64_t)c_op->data.to_cipher.length,
+ c_op->iv.data,
+ c_op->additional_auth.data,
+ (uint64_t)c_op->additional_auth.length,
+ auth_tag,
+ (uint64_t)c_op->digest.length);
+ }
+
+ return 0;
+}
+
+/**
+ * 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_mb_job(struct aesni_mb_qp *qp, JOB_AES_HMAC *job)
+{
+ struct rte_mbuf *m;
+ struct rte_crypto_op *c_op;
+
+ if (job->user_data == NULL)
+ return NULL;
+
+ /* handled retrieved job */
+ m = (struct rte_mbuf *)job->user_data;
+ c_op = (struct rte_crypto_op *)job->user_data2;
+
+ /* check if job has been processed */
+ if (unlikely(job->status != STS_COMPLETED)) {
+ c_op->status = RTE_CRYPTO_OP_STATUS_ERROR;
+ return m;
+ } else if (job->chain_order == HASH_CIPHER) {
+ /* Verify digest if required */
+ if (memcmp(job->auth_tag_output, c_op->digest.data,
+ job->auth_tag_output_len_in_bytes) != 0)
+ c_op->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
+ else
+ c_op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
+
+ /* trim area used for digest from mbuf */
+ rte_pktmbuf_trim(m, get_digest_byte_length(job->hash_alg));
+ } else {
+ c_op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
+ }
+
+ /* Free session if a session-less crypto op */
+ if (c_op->type == RTE_CRYPTO_OP_SESSIONLESS) {
+ rte_mempool_put(qp->sess_mp, c_op->session);
+ c_op->session = NULL;
+ }
+
+ 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_mb_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_mb_job(qp, 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;
+}
+
+/**
+ * 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_gcm_crypto_op(struct rte_mbuf *m, struct rte_crypto_op *c_op)
+{
+ struct aesni_mb_session *session =
+ (struct aesni_mb_session *)c_op->session->_private;
+
+ /* Verify digest if required */
+ if (session->cipher.direction == DECRYPT) {
+
+ uint8_t *auth_tag = rte_pktmbuf_mtod_offset(m, uint8_t *,
+ m->data_len - c_op->digest.length);
+
+ if (memcmp(auth_tag, c_op->digest.data,
+ c_op->digest.length) != 0)
+ c_op->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
+ else
+ c_op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
+
+ /* trim area used for digest from mbuf */
+ rte_pktmbuf_trim(m, c_op->digest.length);
+ } else {
+ c_op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
+ }
+
+ return m;
+}
+
+/**
+ * Process a completed GCM request
+ *
+ * @param qp Queue Pair to process
+ * @param job JOB_AES_HMAC job
+ *
+ * @return
+ * - Number of processed jobs
+ */
+static unsigned
+handle_completed_gcm_crypto_op(struct aesni_mb_qp *qp, struct rte_mbuf *m,
+ struct rte_crypto_op *c_op)
+{
+ m = post_process_gcm_crypto_op(m, c_op);
+
+ /* Free session if a session-less crypto op */
+ if (c_op->type == RTE_CRYPTO_OP_SESSIONLESS) {
+ rte_mempool_put(qp->sess_mp, c_op->session);
+ c_op->session = NULL;
+ }
+
+ rte_ring_enqueue(qp->processed_pkts, (void *)m);
+
+ return 0;
+}
+
+static uint16_t
+aesni_mb_pmd_enqueue_burst(void *queue_pair, struct rte_mbuf **bufs,
+ uint16_t nb_bufs)
+{
+ struct rte_mbuf_offload *ol;
+ struct rte_crypto_op *c_op;
+
+ struct aesni_mb_session *sess;
+ struct aesni_mb_qp *qp = queue_pair;
+ JOB_AES_HMAC *job = NULL;
+
+ int i, retval, processed_jobs = 0;
+
+ for (i = 0; i < nb_bufs; i++) {
+ ol = rte_pktmbuf_offload_get(bufs[i], RTE_PKTMBUF_OL_CRYPTO);
+ if (unlikely(ol == NULL)) {
+ qp->qp_stats.enqueue_err_count++;
+ goto flush_jobs;
+ }
+ c_op = &ol->op.crypto;
+
+ sess = aesni_mb_get_session(qp, c_op);
+ if (unlikely(sess == NULL)) {
+ qp->qp_stats.enqueue_err_count++;
+ goto flush_jobs;
+ }
+
+ if (sess->gcm_session) {
+ retval = process_gcm_crypto_op(qp, bufs[i], c_op, sess);
+ if (retval < 0) {
+ qp->qp_stats.enqueue_err_count++;
+ goto flush_jobs;
+ }
+
+ handle_completed_gcm_crypto_op(qp, bufs[i], c_op);
+ processed_jobs++;
+ } else {
+ job = process_mb_crypto_op(qp, bufs[i], c_op, sess);
+ if (unlikely(job == NULL)) {
+ qp->qp_stats.enqueue_err_count++;
+ goto flush_jobs;
+ }
+
+ /* Submit Job */
+ job = (*qp->mb_ops->job.submit)(&qp->mb_mgr);
+
+ /* If submit returns a processed job then handle it,
+ * before submitting subsequent jobs */
+ if (job)
+ processed_jobs +=
+ handle_completed_mb_jobs(qp, job);
+ }
+ }
+
+ if (processed_jobs == 0)
+ goto flush_jobs;
+ else
+ qp->qp_stats.enqueued_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.enqueued_count +=
+ handle_completed_mb_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 nb_dequeued;
+
+ nb_dequeued = rte_ring_dequeue_burst(qp->processed_pkts,
+ (void **)bufs, nb_bufs);
+ qp->qp_stats.dequeued_count += nb_dequeued;
+
+ 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);
new file mode 100644
@@ -0,0 +1,296 @@
+/*-
+ * 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 <string.h>
+
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_cryptodev_pmd.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 0;
+}
+
+/** Stop device */
+static void
+aesni_mb_pmd_stop(__rte_unused struct rte_cryptodev *dev)
+{
+}
+
+/** Close device */
+static int
+aesni_mb_pmd_close(__rte_unused struct rte_cryptodev *dev)
+{
+ return 0;
+}
+
+
+/** 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 int
+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;
+ }
+ return 0;
+}
+
+/** 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;
+ }
+
+ 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 = dev->data->session_pool;
+
+ 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;
+}
+
+/** Returns the size of the aesni multi-buffer session structure */
+static unsigned
+aesni_mb_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
+{
+ return sizeof(struct aesni_mb_session);
+}
+
+/** Configure a aesni multi-buffer session from a crypto xform chain */
+static void *
+aesni_mb_pmd_session_configure(struct rte_cryptodev *dev,
+ struct rte_crypto_xform *xform, void *sess)
+{
+ struct aesni_mb_private *internals = dev->data->dev_private;
+
+ if (unlikely(sess == NULL)) {
+ MB_LOG_ERR("invalid session struct");
+ return NULL;
+ }
+
+ if (aesni_mb_set_session_parameters(&job_ops[internals->vector_mode],
+ sess, xform) != 0) {
+ MB_LOG_ERR("failed configure session parameters");
+ return NULL;
+ }
+
+ return sess;
+}
+
+/** Clear the memory of session so it doesn't leave key material behind */
+static void
+aesni_mb_pmd_session_clear(struct rte_cryptodev *dev __rte_unused, void *sess)
+{
+ /* Current just resetting the whole data structure, need to investigate
+ * whether a more selective reset of key would be more performant */
+ if (sess)
+ memset(sess, 0, sizeof(struct aesni_mb_session));
+}
+
+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_get_size = aesni_mb_pmd_session_get_size,
+ .session_configure = aesni_mb_pmd_session_configure,
+ .session_clear = aesni_mb_pmd_session_clear
+};
+
+struct rte_cryptodev_ops *rte_aesni_mb_pmd_ops = &aesni_mb_pmd_ops;
+
new file mode 100644
@@ -0,0 +1,230 @@
+/*-
+ * 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...) \
+ RTE_LOG(ERR, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+ CRYPTODEV_NAME_AESNI_MB_PMD, \
+ __func__, __LINE__, ## args)
+
+#ifdef RTE_LIBRTE_AESNI_MB_DEBUG
+#define MB_LOG_INFO(fmt, args...) \
+ RTE_LOG(INFO, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+ CRYPTODEV_NAME_AESNI_MB_PMD, \
+ __func__, __LINE__, ## args)
+
+#define MB_LOG_DBG(fmt, args...) \
+ RTE_LOG(DEBUG, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+ CRYPTODEV_NAME_AESNI_MB_PMD, \
+ __func__, __LINE__, ## args)
+#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;
+
+ 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; /**< Session Mempool */
+ struct rte_cryptodev_stats qp_stats; /**< Queue pair statistics */
+} __rte_cache_aligned;
+
+
+/** AES-NI multi-buffer private session structure */
+struct aesni_mb_session {
+ JOB_CHAIN_ORDER chain_order;
+
+ unsigned gcm_session:1;
+
+ /** Cipher Parameters */
+ struct {
+ /** Cipher direction - encrypt / decrypt */
+ JOB_CIPHER_DIRECTION direction;
+ /** Cipher mode - CBC / Counter */
+ JOB_CIPHER_MODE mode;
+
+ uint64_t key_length_in_bytes;
+
+ struct {
+ uint32_t encode[60] __rte_aligned(16);
+ /**< encode key */
+ uint32_t decode[60] __rte_aligned(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;
+
+ union {
+ /** Authentication Parameters */
+ struct {
+ JOB_HASH_ALG algo; /**< Authentication Algorithm */
+ union {
+ struct {
+ uint8_t inner[128] __rte_aligned(16);
+ /**< inner pad */
+ uint8_t outer[128] __rte_aligned(16);
+ /**< outer pad */
+ } pads;
+ /**< HMAC Authentication pads -
+ * allocating space for the maximum pad
+ * size supported which is 128 bytes for
+ * SHA512 */
+
+ struct {
+ uint32_t k1_expanded[44] __rte_aligned(16);
+ /**< k1 (expanded key). */
+ uint8_t k2[16] __rte_aligned(16);
+ /**< k2. */
+ uint8_t k3[16] __rte_aligned(16);
+ /**< k3. */
+ } xcbc;
+ /**< Expanded XCBC authentication keys */
+ };
+ } auth;
+
+ /** GCM parameters */
+ struct gcm_data gdata;
+ };
+} __rte_cache_aligned;
+
+
+/**
+ *
+ */
+extern int
+aesni_mb_set_session_parameters(const struct aesni_mb_ops *mb_ops,
+ struct aesni_mb_session *sess,
+ const struct rte_crypto_xform *xform);
+
+
+/** device specific operations function pointer structure */
+extern struct rte_cryptodev_ops *rte_aesni_mb_pmd_ops;
+
+
+
+#endif /* _RTE_AESNI_MB_PMD_PRIVATE_H_ */
+
new file mode 100644
@@ -0,0 +1,3 @@
+DPDK_2.2 {
+ local: *;
+};
@@ -148,6 +148,10 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NULL) += -lrte_pmd_null
# QAT PMD has a dependency 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