DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH] pmd/snow3g: add new SNOW 3G SW PMD
@ 2016-01-29 14:15 Pablo de Lara
  2016-03-07 14:07 ` [dpdk-dev] [PATCH v2] " Pablo de Lara
  0 siblings, 1 reply; 9+ messages in thread
From: Pablo de Lara @ 2016-01-29 14:15 UTC (permalink / raw)
  To: dev

Added new SW PMD which makes use of the libsso SW library,
which provides wireless algorithms SNOW 3G UEA2 and UIA2
in software.

This PMD supports cipher-only, hash-only and chained operations
("cipher then hash" and "hash then cipher") of the following
algorithms:
- RTE_CRYPTO_SYM_CIPHER_SNOW3G_UEA2
- RTE_CRYPTO_SYM_HASH_SNOW3G_UIA2

The SNOW 3G hash and cipher algorithms, which are enabled
by this crypto PMD are implemented by Intel's libsso software
library. For library download and build instructions,
see the documentation included (doc/guides/cryptodevs/snow3g.rst)

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
 MAINTAINERS                                      |   4 +
 config/common_linuxapp                           |  10 +-
 doc/guides/cryptodevs/index.rst                  |   1 +
 doc/guides/cryptodevs/snow3g.rst                 |  69 +++
 doc/guides/rel_notes/release_2_3.rst             |   4 +
 drivers/crypto/Makefile                          |   3 +-
 drivers/crypto/snow3g/Makefile                   |  64 +++
 drivers/crypto/snow3g/rte_pmd_snow3g_version.map |   3 +
 drivers/crypto/snow3g/rte_snow3g_pmd.c           | 508 +++++++++++++++++++++++
 drivers/crypto/snow3g/rte_snow3g_pmd_ops.c       | 291 +++++++++++++
 drivers/crypto/snow3g/rte_snow3g_pmd_private.h   | 107 +++++
 lib/librte_cryptodev/rte_crypto.h                |   4 +
 lib/librte_cryptodev/rte_cryptodev.h             |   5 +-
 mk/rte.app.mk                                    |   6 +-
 14 files changed, 1075 insertions(+), 4 deletions(-)
 create mode 100644 doc/guides/cryptodevs/snow3g.rst
 create mode 100644 drivers/crypto/snow3g/Makefile
 create mode 100644 drivers/crypto/snow3g/rte_pmd_snow3g_version.map
 create mode 100644 drivers/crypto/snow3g/rte_snow3g_pmd.c
 create mode 100644 drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
 create mode 100644 drivers/crypto/snow3g/rte_snow3g_pmd_private.h

diff --git a/MAINTAINERS b/MAINTAINERS
index b90aeea..69d27a9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -355,6 +355,10 @@ F: drivers/crypto/aesni_mb/
 Intel QuickAssist
 F: drivers/crypto/qat/
 
+SNOW 3G PMD
+M: Pablo de Lara <pablo.de.lara.guarch@intel.com>
+F: drivers/crypto/snow3g
+
 
 Packet processing
 -----------------
diff --git a/config/common_linuxapp b/config/common_linuxapp
index 74bc515..49aa274 100644
--- a/config/common_linuxapp
+++ b/config/common_linuxapp
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -356,6 +356,14 @@ CONFIG_RTE_AESNI_MB_PMD_MAX_NB_QUEUE_PAIRS=8
 CONFIG_RTE_AESNI_MB_PMD_MAX_NB_SESSIONS=2048
 
 #
+# Compile PMD for SNOW 3G device
+#
+CONFIG_RTE_LIBRTE_PMD_SNOW3G=n
+CONFIG_RTE_LIBRTE_PMD_SNOW3G_DEBUG=n
+CONFIG_RTE_SNOW3G_PMD_MAX_NB_QUEUE_PAIRS=8
+CONFIG_RTE_SNOW3G_PMD_MAX_NB_SESSIONS=2048
+
+#
 # Compile librte_ring
 #
 CONFIG_RTE_LIBRTE_RING=y
diff --git a/doc/guides/cryptodevs/index.rst b/doc/guides/cryptodevs/index.rst
index 16a5f4a..071e7d2 100644
--- a/doc/guides/cryptodevs/index.rst
+++ b/doc/guides/cryptodevs/index.rst
@@ -36,4 +36,5 @@ Crypto Device Drivers
     :numbered:
 
     aesni_mb
+    snow3g
     qat
diff --git a/doc/guides/cryptodevs/snow3g.rst b/doc/guides/cryptodevs/snow3g.rst
new file mode 100644
index 0000000..9e81eeb
--- /dev/null
+++ b/doc/guides/cryptodevs/snow3g.rst
@@ -0,0 +1,69 @@
+..  BSD LICENSE
+    Copyright(c) 2016 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.
+
+SNOW 3G Crypto Poll Mode Driver
+==============================
+
+The SNOW 3G PMD (**librte_pmd_snow3g**) provides poll mode crypto driver
+support for utilizing Intel Libsso library, which implements F8 and F9 functions
+for SNOW 3G UEA2 cipher and UIA2 hash algorithms.
+
+Features
+--------
+
+SNOW 3G PMD has support for:
+
+Cipher algorithm:
+
+* RTE_CRYPTO_SYM_CIPHER_SNOW3G_UEA2
+
+Hash algorithm:
+
+* RTE_CRYPTO_SYM_HASH_SNOW3G_UIA2
+
+Limitations
+-----------
+
+* Chained mbufs are not supported.
+
+Installation
+------------
+
+To build DPDK with the SNOW3G_PMD the user is required to get
+the export controlled libsso library, sending a request to
+`DPDKUser_software_access@intel.com`, and compile it
+on their user system before building DPDK:
+
+.. code-block:: console
+
+	make -f Makefile_snow3g
+
+The environmental variable LIBSSO_PATH must be exported with the path
+where you extracted and built the libsso library and finally set
+CONFIG_RTE_LIBRTE_SNOW3G=y in config/common_linuxapp.
diff --git a/doc/guides/rel_notes/release_2_3.rst b/doc/guides/rel_notes/release_2_3.rst
index 99de186..dcd8274 100644
--- a/doc/guides/rel_notes/release_2_3.rst
+++ b/doc/guides/rel_notes/release_2_3.rst
@@ -3,6 +3,10 @@ DPDK Release 2.3
 
 New Features
 ------------
+* **Added SNOW 3G SW PMD**
+
+  A new Crypto PMD has been added, which provides SNOW 3G UEA2 ciphering
+  and SNOW 3G UIA2 hashing.
 
 
 Resolved Issues
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index d07ee96..0636960 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -33,6 +33,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_AESNI_MB) += aesni_mb
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_QAT) += qat
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += snow3g
 
 include $(RTE_SDK)/mk/rte.sharelib.mk
 include $(RTE_SDK)/mk/rte.subdir.mk
\ No newline at end of file
diff --git a/drivers/crypto/snow3g/Makefile b/drivers/crypto/snow3g/Makefile
new file mode 100644
index 0000000..ee58270
--- /dev/null
+++ b/drivers/crypto/snow3g/Makefile
@@ -0,0 +1,64 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 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 ($(LIBSSO_PATH),)
+$(error "Please define LIBSSO_PATH environment variable")
+endif
+
+# library name
+LIB = librte_pmd_snow3g.a
+
+# build flags
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+# library version
+LIBABIVER := 1
+
+# versioning export map
+EXPORT_MAP := rte_pmd_snow3g_version.map
+
+# external library include paths
+CFLAGS += -I$(LIBSSO_PATH)
+CFLAGS += -I$(LIBSSO_PATH)/include
+CFLAGS += -I$(LIBSSO_PATH)/build
+
+# library source files
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += rte_snow3g_pmd.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += rte_snow3g_pmd_ops.c
+
+# library dependencies
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += lib/librte_cryptodev
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/crypto/snow3g/rte_pmd_snow3g_version.map b/drivers/crypto/snow3g/rte_pmd_snow3g_version.map
new file mode 100644
index 0000000..3871202
--- /dev/null
+++ b/drivers/crypto/snow3g/rte_pmd_snow3g_version.map
@@ -0,0 +1,3 @@
+DPDK_2.3 {
+	local: *;
+};
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd.c b/drivers/crypto/snow3g/rte_snow3g_pmd.c
new file mode 100644
index 0000000..0579614
--- /dev/null
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd.c
@@ -0,0 +1,508 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_snow3g_pmd_private.h"
+
+#define SNOW3G_MAX_BURST 16
+
+/**
+ * Global static parameter used to create a unique name for each SNOW 3G
+ * 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_SNOW3G_PMD,
+			unique_name_id++);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+/** Get xform chain order. */
+static enum snow3g_operation
+snow3g_get_mode(const struct rte_crypto_xform *xform)
+{
+	if (xform == NULL)
+		return SNOW3G_OP_NOT_SUPPORTED;
+
+	if (xform->next)
+		if (xform->next->next != NULL)
+			return SNOW3G_OP_NOT_SUPPORTED;
+
+	if (xform->type == RTE_CRYPTO_XFORM_AUTH) {
+		if (xform->next == NULL)
+			return SNOW3G_OP_ONLY_AUTH;
+		else if (xform->next->type == RTE_CRYPTO_XFORM_CIPHER)
+			return SNOW3G_OP_AUTH_CIPHER;
+		else
+			return SNOW3G_OP_NOT_SUPPORTED;
+	}
+
+	if (xform->type == RTE_CRYPTO_XFORM_CIPHER) {
+		if (xform->next == NULL)
+			return SNOW3G_OP_ONLY_CIPHER;
+		else if (xform->next->type == RTE_CRYPTO_XFORM_AUTH)
+			return SNOW3G_OP_CIPHER_AUTH;
+		else
+			return SNOW3G_OP_NOT_SUPPORTED;
+	}
+
+	return SNOW3G_OP_NOT_SUPPORTED;
+}
+
+
+/** Parse crypto xform chain and set private session parameters. */
+int
+snow3g_set_session_parameters(struct snow3g_session *sess,
+		const struct rte_crypto_xform *xform)
+{
+	const struct rte_crypto_xform *auth_xform = NULL;
+	const struct rte_crypto_xform *cipher_xform = NULL;
+	int mode;
+
+	/* Select Crypto operation - hash then cipher / cipher then hash */
+	mode = snow3g_get_mode(xform);
+
+	switch (mode) {
+	case SNOW3G_OP_CIPHER_AUTH:
+		auth_xform = xform->next;
+
+		/* Fall-through */
+	case SNOW3G_OP_ONLY_CIPHER:
+		cipher_xform = xform;
+		break;
+	case SNOW3G_OP_AUTH_CIPHER:
+		cipher_xform = xform->next;
+		/* Fall-through */
+	case SNOW3G_OP_ONLY_AUTH:
+		auth_xform = xform;
+	}
+
+	if (mode == SNOW3G_OP_NOT_SUPPORTED) {
+		SNOW3G_LOG_ERR("Unsupported operation chain order parameter");
+		return -EINVAL;
+	}
+
+	if (cipher_xform) {
+		/* Only SNOW 3G UEA2 supported */
+		if (cipher_xform->cipher.algo != RTE_CRYPTO_CIPHER_SNOW3G_UEA2)
+			return -EINVAL;
+		/* Initialize key */
+		sso_snow3g_init_key_sched(xform->cipher.key.data,
+				&sess->pKeySched_cipher);
+	}
+
+	if (auth_xform) {
+		/* Only SNOW 3G UIA2 supported */
+		if (auth_xform->auth.algo != RTE_CRYPTO_AUTH_SNOW3G_UIA2)
+			return -EINVAL;
+		sess->auth_op = auth_xform->auth.op;
+		/* Initialize key */
+		sso_snow3g_init_key_sched(xform->auth.key.data,
+				&sess->pKeySched_hash);
+	}
+
+
+	sess->op = mode;
+
+	return 0;
+}
+
+/** Get SNOW 3G session. */
+static struct snow3g_session *
+snow3g_get_session(struct snow3g_qp *qp, struct rte_crypto_op *crypto_op)
+{
+	struct snow3g_session *sess;
+
+	if (crypto_op->type == RTE_CRYPTO_OP_WITH_SESSION) {
+		if (unlikely(crypto_op->session->type !=
+				RTE_CRYPTODEV_SNOW3G_PMD))
+			return NULL;
+
+		sess = (struct snow3g_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 snow3g_session *)c_sess->_private;
+
+		if (unlikely(snow3g_set_session_parameters(sess,
+				crypto_op->xform) != 0))
+			return NULL;
+	}
+
+	return sess;
+}
+
+/** Encrypt/decrypt mbufs with same cipher key. */
+static void
+process_snow3g_cipher_op(struct rte_mbuf **mbufs,
+		struct rte_crypto_op **c_op, struct snow3g_session *session,
+		uint8_t num_mbufs)
+{
+	unsigned i;
+	uint8_t *src[SNOW3G_MAX_BURST], *dst[SNOW3G_MAX_BURST];
+	uint8_t *IV[SNOW3G_MAX_BURST];
+	uint32_t num_bytes[SNOW3G_MAX_BURST];
+
+	for (i = 0; i < num_mbufs; i++) {
+		src[i] = rte_pktmbuf_mtod(mbufs[i], uint8_t *) +
+				c_op[i]->data.to_cipher.offset;
+		dst[i] = c_op[i]->dst.m ?
+				rte_pktmbuf_mtod(c_op[i]->dst.m, uint8_t *) +
+				c_op[i]->dst.offset :
+				rte_pktmbuf_mtod(mbufs[i], uint8_t *) +
+				c_op[i]->data.to_cipher.offset;
+		IV[i] = c_op[i]->iv.data;
+		num_bytes[i] = c_op[i]->data.to_cipher.length;
+	}
+
+	sso_snow3g_f8_n_buffer(&session->pKeySched_cipher, IV, src, dst,
+			num_bytes, num_mbufs);
+}
+
+/** Generate/verify hash from mbufs with same hash key. */
+static void
+process_snow3g_hash_op(struct rte_mbuf **mbufs,
+		struct rte_crypto_op **c_op, struct snow3g_session *session,
+		uint8_t num_mbufs)
+{
+	unsigned i;
+	uint8_t *src, *dst;
+	uint32_t length_in_bits;
+
+	for (i = 0; i < num_mbufs; i++) {
+		length_in_bits = c_op[i]->data.to_hash.length * 8;
+
+		src = rte_pktmbuf_mtod(mbufs[i], uint8_t *) +
+				c_op[i]->data.to_hash.offset;
+
+		if (session->auth_op == RTE_CRYPTO_AUTH_OP_VERIFY) {
+			dst = (uint8_t *)rte_pktmbuf_append(mbufs[i],
+					c_op[i]->digest.length);
+
+			sso_snow3g_f9_1_buffer(&session->pKeySched_hash,
+					c_op[i]->iv.data, src, length_in_bits,
+					dst);
+			/* Verify digest. */
+			if (memcmp(dst, c_op[i]->digest.data,
+					c_op[i]->digest.length) != 0)
+				c_op[i]->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
+
+			/* Trim area used for digest from mbuf. */
+			rte_pktmbuf_trim(mbufs[i], c_op[i]->digest.length);
+		} else  {
+			dst = c_op[i]->digest.data;
+
+			sso_snow3g_f9_1_buffer(&session->pKeySched_hash,
+					c_op[i]->additional_auth.data, src,
+					length_in_bits, dst);
+		}
+	}
+}
+
+/** Process a batch of mbufs which shares the same session. */
+static int
+process_bufs(struct rte_mbuf **mbufs,
+		struct rte_crypto_op **c_op, struct snow3g_session *session,
+		struct snow3g_qp *qp, uint8_t num_mbufs)
+{
+	unsigned i;
+	unsigned processed_mbufs = num_mbufs;
+
+	switch (session->op) {
+	case SNOW3G_OP_ONLY_CIPHER:
+		process_snow3g_cipher_op(mbufs, c_op,
+				session, num_mbufs);
+		break;
+	case SNOW3G_OP_ONLY_AUTH:
+		process_snow3g_hash_op(mbufs, c_op, session,
+				num_mbufs);
+		break;
+	case SNOW3G_OP_CIPHER_AUTH:
+		process_snow3g_cipher_op(mbufs, c_op, session,
+				num_mbufs);
+		process_snow3g_hash_op(mbufs, c_op, session,
+				num_mbufs);
+		break;
+	case SNOW3G_OP_AUTH_CIPHER:
+		process_snow3g_hash_op(mbufs, c_op, session,
+				num_mbufs);
+		process_snow3g_cipher_op(mbufs, c_op, session,
+				num_mbufs);
+		break;
+	default:
+		/* Operation not supported. */
+		processed_mbufs = 0;
+	}
+
+	for (i = 0; i < num_mbufs; i++) {
+		/* Free session if a session-less crypto op. */
+		if (c_op[i]->type == RTE_CRYPTO_OP_SESSIONLESS) {
+			rte_mempool_put(qp->sess_mp, c_op[i]->session);
+			c_op[i]->session = NULL;
+		}
+	}
+
+	return processed_mbufs;
+}
+
+static uint16_t
+snow3g_pmd_enqueue_burst(void *queue_pair, struct rte_mbuf **bufs,
+		uint16_t nb_bufs)
+{
+	struct rte_crypto_op *c_op[SNOW3G_MAX_BURST];
+	struct rte_mbuf_offload *curr_ol;
+	struct rte_crypto_op *curr_c_op;
+
+	struct snow3g_session *prev_sess = NULL, *curr_sess = NULL;
+	struct snow3g_qp *qp = queue_pair;
+	unsigned i, n;
+	unsigned buf_burst_index = 0;
+	unsigned burst_size = 0;
+	uint16_t enqueued_pkts = 0;
+
+	for (i = 0; i < nb_bufs; i++) {
+		curr_ol = rte_pktmbuf_offload_get(bufs[i],
+				RTE_PKTMBUF_OL_CRYPTO);
+		if (unlikely(curr_ol == NULL)) {
+			qp->qp_stats.enqueue_err_count++;
+			return enqueued_pkts;
+		}
+
+		curr_c_op = &curr_ol->op.crypto;
+
+		/* Set status as successful by default. */
+		curr_c_op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
+
+		/* Sanity checks. */
+		if (curr_c_op->iv.length != 16 && curr_c_op->iv.length != 0) {
+			curr_c_op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+			SNOW3G_LOG_ERR("iv");
+			return enqueued_pkts;
+		}
+
+		if (curr_c_op->additional_auth.length != 16 &&
+				curr_c_op->additional_auth.length != 0) {
+			curr_c_op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+			SNOW3G_LOG_ERR("iv");
+			return enqueued_pkts;
+		}
+
+		if (curr_c_op->digest.length != 4 &&
+			curr_c_op->digest.length != 0) {
+			curr_c_op->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+			SNOW3G_LOG_ERR("digest");
+			return enqueued_pkts;
+		}
+
+		curr_sess = snow3g_get_session(qp, curr_c_op);
+		if (unlikely(curr_sess == NULL ||
+				curr_sess->op == SNOW3G_OP_NOT_SUPPORTED)) {
+			curr_c_op->status =
+					RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
+			qp->qp_stats.enqueue_err_count++;
+			return enqueued_pkts;
+		}
+
+		/* Batch mbufs that share the same session. */
+		if (prev_sess == NULL) {
+			prev_sess = curr_sess;
+			c_op[burst_size++] = curr_c_op;
+		} else if (curr_sess == prev_sess) {
+			c_op[burst_size++] = curr_c_op;
+			/*
+			 * When there are enough mbufs to process in a batch,
+			 * process them, and start a new batch.
+			 */
+			if (burst_size == SNOW3G_MAX_BURST) {
+				if (process_bufs(&bufs[buf_burst_index], c_op,
+						prev_sess, qp, burst_size) == 0)
+					return enqueued_pkts;
+				n = rte_ring_enqueue_burst(qp->processed_pkts,
+						(void **)&bufs[buf_burst_index],
+						burst_size);
+				qp->qp_stats.enqueued_count += n;
+				enqueued_pkts += n;
+				if (n < burst_size)
+					return enqueued_pkts;
+				burst_size = 0;
+				buf_burst_index = i + 1;
+
+				prev_sess = NULL;
+			}
+		} else {
+			/*
+			 * Different session, process the mbufs
+			 * of the previous session.
+			 */
+			if (process_bufs(&bufs[buf_burst_index], c_op,
+					prev_sess, qp, burst_size) == 0)
+				return enqueued_pkts;
+			n = rte_ring_enqueue_burst(qp->processed_pkts,
+					(void **)&bufs[i], burst_size);
+			qp->qp_stats.enqueued_count += n;
+			enqueued_pkts += n;
+			if (n < burst_size)
+				return enqueued_pkts;
+			burst_size = 0;
+
+			prev_sess = curr_sess;
+			buf_burst_index = i + 1;
+			c_op[burst_size++] = curr_c_op;
+		}
+	}
+
+	if (burst_size != 0) {
+		/* Process the mbufs of the last session. */
+		if (process_bufs(&bufs[buf_burst_index], c_op, prev_sess, qp,
+				burst_size) == 0)
+			return enqueued_pkts;
+		n = rte_ring_enqueue_burst(qp->processed_pkts,
+				(void **)&bufs[buf_burst_index], burst_size);
+
+		qp->qp_stats.enqueued_count += n;
+		enqueued_pkts += n;
+	}
+
+	return enqueued_pkts;
+}
+
+static uint16_t
+snow3g_pmd_dequeue_burst(void *queue_pair,
+		struct rte_mbuf **bufs,	uint16_t nb_bufs)
+{
+	struct snow3g_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_snow3g_uninit(const char *name);
+
+static int
+cryptodev_snow3g_create(const char *name, unsigned socket_id)
+{
+	struct rte_cryptodev *dev;
+	char crypto_dev_name[RTE_CRYPTODEV_NAME_MAX_LEN];
+	struct snow3g_private *internals;
+
+	/* Create a unique device name. */
+	if (create_unique_device_name(crypto_dev_name,
+			RTE_CRYPTODEV_NAME_MAX_LEN) != 0) {
+		SNOW3G_LOG_ERR("failed to create unique cryptodev name");
+		return -EINVAL;
+	}
+
+	dev = rte_cryptodev_pmd_virtual_dev_init(crypto_dev_name,
+			sizeof(struct snow3g_private), socket_id);
+	if (dev == NULL) {
+		SNOW3G_LOG_ERR("failed to create cryptodev vdev");
+		goto init_error;
+	}
+
+	dev->dev_type = RTE_CRYPTODEV_SNOW3G_PMD;
+	dev->dev_ops = rte_snow3g_pmd_ops;
+
+	/* Register RX/TX burst functions for data path. */
+	dev->dequeue_burst = snow3g_pmd_dequeue_burst;
+	dev->enqueue_burst = snow3g_pmd_enqueue_burst;
+
+	internals = dev->data->dev_private;
+
+	internals->max_nb_queue_pairs = RTE_SNOW3G_PMD_MAX_NB_QUEUE_PAIRS;
+	internals->max_nb_sessions = RTE_SNOW3G_PMD_MAX_NB_SESSIONS;
+
+	return dev->data->dev_id;
+init_error:
+	SNOW3G_LOG_ERR("driver %s: cryptodev_snow3g_create failed", name);
+
+	cryptodev_snow3g_uninit(crypto_dev_name);
+	return -EFAULT;
+}
+
+
+static int
+cryptodev_snow3g_init(const char *name,
+		const char *params __rte_unused)
+{
+	RTE_LOG(INFO, PMD, "Initialising %s\n", name);
+
+	return cryptodev_snow3g_create(name, rte_socket_id());
+}
+
+static int
+cryptodev_snow3g_uninit(const char *name)
+{
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Closing SNOW3G crypto device %s"
+			" on numa socket %u\n",
+			name, rte_socket_id());
+
+	return 0;
+}
+
+static struct rte_driver cryptodev_snow3g_pmd_drv = {
+	.name = CRYPTODEV_NAME_SNOW3G_PMD,
+	.type = PMD_VDEV,
+	.init = cryptodev_snow3g_init,
+	.uninit = cryptodev_snow3g_uninit
+};
+
+PMD_REGISTER_DRIVER(cryptodev_snow3g_pmd_drv);
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
new file mode 100644
index 0000000..b902018
--- /dev/null
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
@@ -0,0 +1,291 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_snow3g_pmd_private.h"
+
+/** Configure device */
+static int
+snow3g_pmd_config(__rte_unused struct rte_cryptodev *dev)
+{
+	return 0;
+}
+
+/** Start device */
+static int
+snow3g_pmd_start(__rte_unused struct rte_cryptodev *dev)
+{
+	return 0;
+}
+
+/** Stop device */
+static void
+snow3g_pmd_stop(__rte_unused struct rte_cryptodev *dev)
+{
+}
+
+/** Close device */
+static int
+snow3g_pmd_close(__rte_unused struct rte_cryptodev *dev)
+{
+	return 0;
+}
+
+
+/** Get device statistics */
+static void
+snow3g_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 snow3g_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
+snow3g_pmd_stats_reset(struct rte_cryptodev *dev)
+{
+	int qp_id;
+
+	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {
+		struct snow3g_qp *qp = dev->data->queue_pairs[qp_id];
+
+		memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
+	}
+}
+
+
+/** Get device info */
+static void
+snow3g_pmd_info_get(struct rte_cryptodev *dev,
+		struct rte_cryptodev_info *dev_info)
+{
+	struct snow3g_private *internals = dev->data->dev_private;
+
+	if (dev_info != NULL) {
+		dev_info->dev_type = dev->dev_type;
+		dev_info->max_nb_queue_pairs = internals->max_nb_queue_pairs;
+		dev_info->max_nb_sessions = internals->max_nb_sessions;
+	}
+}
+
+/** Release queue pair */
+static int
+snow3g_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 its name, dev_id and qp_id */
+static int
+snow3g_pmd_qp_set_unique_name(struct rte_cryptodev *dev,
+		struct snow3g_qp *qp)
+{
+	unsigned n = snprintf(qp->name, sizeof(qp->name),
+			"snow3g_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 *
+snow3g_pmd_qp_create_processed_pkts_ring(struct snow3g_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) {
+			SNOW3G_LOG_INFO("Reusing existing ring %s"
+					" for processed packets",
+					 qp->name);
+			return r;
+		}
+
+		SNOW3G_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
+snow3g_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
+		const struct rte_cryptodev_qp_conf *qp_conf,
+		 int socket_id)
+{
+	struct snow3g_qp *qp = NULL;
+
+	/* Free memory prior to re-allocation if needed. */
+	if (dev->data->queue_pairs[qp_id] != NULL)
+		snow3g_pmd_qp_release(dev, qp_id);
+
+	/* Allocate the queue pair data structure. */
+	qp = rte_zmalloc_socket("SNOW3G 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 (snow3g_pmd_qp_set_unique_name(dev, qp))
+		goto qp_setup_cleanup;
+
+	qp->processed_pkts = snow3g_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));
+
+	return 0;
+
+qp_setup_cleanup:
+	if (qp)
+		rte_free(qp);
+
+	return -1;
+}
+
+/** Start queue pair */
+static int
+snow3g_pmd_qp_start(__rte_unused struct rte_cryptodev *dev,
+		__rte_unused uint16_t queue_pair_id)
+{
+	return -ENOTSUP;
+}
+
+/** Stop queue pair */
+static int
+snow3g_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
+snow3g_pmd_qp_count(struct rte_cryptodev *dev)
+{
+	return dev->data->nb_queue_pairs;
+}
+
+/** Returns the size of the SNOW 3G session structure */
+static unsigned
+snow3g_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
+{
+	return sizeof(struct snow3g_session);
+}
+
+/** Configure a SNOW 3G session from a crypto xform chain */
+static void *
+snow3g_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
+		struct rte_crypto_xform *xform,	void *sess)
+{
+	if (unlikely(sess == NULL)) {
+		SNOW3G_LOG_ERR("invalid session struct");
+		return NULL;
+	}
+
+	if (snow3g_set_session_parameters(sess, xform) != 0) {
+		SNOW3G_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
+snow3g_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 snow3g_session));
+}
+
+struct rte_cryptodev_ops snow3g_pmd_ops = {
+		.dev_configure      = snow3g_pmd_config,
+		.dev_start          = snow3g_pmd_start,
+		.dev_stop           = snow3g_pmd_stop,
+		.dev_close          = snow3g_pmd_close,
+
+		.stats_get          = snow3g_pmd_stats_get,
+		.stats_reset        = snow3g_pmd_stats_reset,
+
+		.dev_infos_get      = snow3g_pmd_info_get,
+
+		.queue_pair_setup   = snow3g_pmd_qp_setup,
+		.queue_pair_release = snow3g_pmd_qp_release,
+		.queue_pair_start   = snow3g_pmd_qp_start,
+		.queue_pair_stop    = snow3g_pmd_qp_stop,
+		.queue_pair_count   = snow3g_pmd_qp_count,
+
+		.session_get_size   = snow3g_pmd_session_get_size,
+		.session_configure  = snow3g_pmd_session_configure,
+		.session_clear      = snow3g_pmd_session_clear
+};
+
+struct rte_cryptodev_ops *rte_snow3g_pmd_ops = &snow3g_pmd_ops;
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd_private.h b/drivers/crypto/snow3g/rte_snow3g_pmd_private.h
new file mode 100644
index 0000000..d09ed9d
--- /dev/null
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd_private.h
@@ -0,0 +1,107 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_SNOW3G_PMD_PRIVATE_H_
+#define _RTE_SNOW3G_PMD_PRIVATE_H_
+
+#include <sso_snow3g.h>
+
+#define SNOW3G_LOG_ERR(fmt, args...) \
+	RTE_LOG(ERR, CRYPTODEV, "[%s] %s() line %u: " fmt "\n",  \
+			CRYPTODEV_NAME_SNOW3G_PMD, \
+			__func__, __LINE__, ## args)
+
+#ifdef RTE_LIBRTE_SNOW3G_DEBUG
+#define SNOW3G_LOG_INFO(fmt, args...) \
+	RTE_LOG(INFO, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+			CRYPTODEV_NAME_SNOW3G_PMD, \
+			__func__, __LINE__, ## args)
+
+#define SNOW3G_LOG_DBG(fmt, args...) \
+	RTE_LOG(DEBUG, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+			CRYPTODEV_NAME_SNOW3G_PMD, \
+			__func__, __LINE__, ## args)
+#else
+#define SNOW3G_LOG_INFO(fmt, args...)
+#define SNOW3G_LOG_DBG(fmt, args...)
+#endif
+
+/** private data structure for each virtual SNOW 3G device */
+struct snow3g_private {
+	unsigned max_nb_queue_pairs;
+	/**< Max number of queue pairs supported by device */
+	unsigned max_nb_sessions;
+	/**< Max number of sessions supported by device */
+};
+
+/** SNOW 3G buffer queue pair */
+struct snow3g_qp {
+	uint16_t id;
+	/**< Queue Pair Identifier */
+	char name[RTE_CRYPTODEV_NAME_LEN];
+	/**< Unique Queue Pair Name */
+	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;
+
+enum snow3g_operation {
+	SNOW3G_OP_ONLY_CIPHER,
+	SNOW3G_OP_ONLY_AUTH,
+	SNOW3G_OP_CIPHER_AUTH,
+	SNOW3G_OP_AUTH_CIPHER,
+	SNOW3G_OP_NOT_SUPPORTED
+};
+
+/** SNOW 3G private session structure */
+struct snow3g_session {
+	enum snow3g_operation op;
+	enum rte_crypto_auth_operation auth_op;
+	sso_snow3g_key_schedule_t pKeySched_cipher;
+	sso_snow3g_key_schedule_t pKeySched_hash;
+} __rte_cache_aligned;
+
+
+extern int
+snow3g_set_session_parameters(struct snow3g_session *sess,
+		const struct rte_crypto_xform *xform);
+
+
+/** device specific operations function pointer structure */
+extern struct rte_cryptodev_ops *rte_snow3g_pmd_ops;
+
+
+
+#endif /* _RTE_SNOW3G_PMD_PRIVATE_H_ */
diff --git a/lib/librte_cryptodev/rte_crypto.h b/lib/librte_cryptodev/rte_crypto.h
index 42343a8..1c93e78 100644
--- a/lib/librte_cryptodev/rte_crypto.h
+++ b/lib/librte_cryptodev/rte_crypto.h
@@ -353,6 +353,10 @@ enum rte_crypto_op_status {
 	/**< Operation is enqueued on device */
 	RTE_CRYPTO_OP_STATUS_AUTH_FAILED,
 	/**< Authentication verification failed */
+	RTE_CRYPTO_OP_STATUS_INVALID_SESSION,
+	/**< Operation failed due to invalid session args or
+	 * if in session-less mode failed to created session
+	 */
 	RTE_CRYPTO_OP_STATUS_INVALID_ARGS,
 	/**< Operation failed due to invalid arguments in request */
 	RTE_CRYPTO_OP_STATUS_ERROR,
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index 892375d..36e3245 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -1,6 +1,6 @@
 /*-
  *
- *   Copyright(c) 2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2015-2016 Intel Corporation. All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
  *   modification, are permitted provided that the following conditions
@@ -57,6 +57,8 @@ extern "C" {
 /**< Null crypto PMD device name */
 #define CRYPTODEV_NAME_AESNI_MB_PMD	("cryptodev_aesni_mb_pmd")
 /**< AES-NI Multi buffer PMD device name */
+#define CRYPTODEV_NAME_SNOW3G_PMD	("cryptodev_snow3g_pmd")
+/**< SNOW 3G PMD device name */
 #define CRYPTODEV_NAME_QAT_PMD		("cryptodev_qat_pmd")
 /**< Intel QAT PMD device name */
 
@@ -64,6 +66,7 @@ extern "C" {
 enum rte_cryptodev_type {
 	RTE_CRYPTODEV_NULL_PMD = 1,	/**< Null crypto PMD */
 	RTE_CRYPTODEV_AESNI_MB_PMD,	/**< AES-NI multi buffer PMD */
+	RTE_CRYPTODEV_SNOW3G_PMD,	/**< SNOW 3G PMD */
 	RTE_CRYPTODEV_QAT_PMD,		/**< QAT PMD */
 };
 
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index 8ecab41..da1d01e 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   Copyright(c) 2014-2015 6WIND S.A.
 #   All rights reserved.
 #
@@ -159,6 +159,10 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_QAT)        += -lrte_pmd_qat
 _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
 
+# SNOW3G PMD is dependent on the LIBSSO library
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G)     += -lrte_pmd_snow3g
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G)     += -L$(LIBSSO_PATH)/build -lsso
+
 endif # ! $(CONFIG_RTE_BUILD_SHARED_LIB)
 
 endif # ! CONFIG_RTE_BUILD_COMBINE_LIBS
-- 
2.5.0

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [dpdk-dev] [PATCH v2] pmd/snow3g: add new SNOW 3G SW PMD
  2016-01-29 14:15 [dpdk-dev] [PATCH] pmd/snow3g: add new SNOW 3G SW PMD Pablo de Lara
@ 2016-03-07 14:07 ` Pablo de Lara
  2016-03-07 19:48   ` [dpdk-dev] [PATCH v3] " Pablo de Lara
  2016-03-07 19:48   ` [dpdk-dev] [PATCH v2] " De Lara Guarch, Pablo
  0 siblings, 2 replies; 9+ messages in thread
From: Pablo de Lara @ 2016-03-07 14:07 UTC (permalink / raw)
  To: dev

Added new SW PMD which makes use of the libsso SW library,
which provides wireless algorithms SNOW 3G UEA2 and UIA2
in software.

This PMD supports cipher-only, hash-only and chained operations
("cipher then hash" and "hash then cipher") of the following
algorithms:
- RTE_CRYPTO_SYM_CIPHER_SNOW3G_UEA2
- RTE_CRYPTO_SYM_HASH_SNOW3G_UIA2

The SNOW 3G hash and cipher algorithms, which are enabled
by this crypto PMD are implemented by Intel's libsso software
library. For library download and build instructions,
see the documentation included (doc/guides/cryptodevs/snow3g.rst)

The patch also contains the related unit tests function to test the PMD
supported operations.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---
Changes in v2:

- Rebased against crypto API changes
- Removed static config options and allow user to provide them
  as virtual device parameters.
- Added unit tests
- Changed DPDK version references from 2.3 to 16.04
- Fixed crypto operation status handling
- Fixed copyright dates
- Fixed enqueue error stats

This patch depends on "Cryptodev API changes" patchset
(http://dpdk.org/ml/archives/dev/2016-March/034822.html)


 MAINTAINERS                                      |   4 +
 app/test/test_cryptodev.c                        |  78 ++++
 config/common_base                               |   6 +
 doc/guides/cryptodevs/index.rst                  |   1 +
 doc/guides/cryptodevs/snow3g.rst                 |  69 +++
 doc/guides/rel_notes/release_16_04.rst           |   4 +
 drivers/crypto/Makefile                          |   3 +-
 drivers/crypto/snow3g/Makefile                   |  64 +++
 drivers/crypto/snow3g/rte_pmd_snow3g_version.map |   3 +
 drivers/crypto/snow3g/rte_snow3g_pmd.c           | 531 +++++++++++++++++++++++
 drivers/crypto/snow3g/rte_snow3g_pmd_ops.c       | 291 +++++++++++++
 drivers/crypto/snow3g/rte_snow3g_pmd_private.h   | 107 +++++
 lib/librte_cryptodev/Makefile                    |   3 +-
 lib/librte_cryptodev/rte_cryptodev.h             | 120 ++++-
 mk/rte.app.mk                                    |   6 +-
 15 files changed, 1286 insertions(+), 4 deletions(-)
 create mode 100644 doc/guides/cryptodevs/snow3g.rst
 create mode 100644 drivers/crypto/snow3g/Makefile
 create mode 100644 drivers/crypto/snow3g/rte_pmd_snow3g_version.map
 create mode 100644 drivers/crypto/snow3g/rte_snow3g_pmd.c
 create mode 100644 drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
 create mode 100644 drivers/crypto/snow3g/rte_snow3g_pmd_private.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 8d84dda..c028e67 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -355,6 +355,10 @@ F: drivers/crypto/aesni_mb/
 Intel QuickAssist
 F: drivers/crypto/qat/
 
+SNOW 3G PMD
+M: Pablo de Lara <pablo.de.lara.guarch@intel.com>
+F: drivers/crypto/snow3g
+
 
 Packet processing
 -----------------
diff --git a/app/test/test_cryptodev.c b/app/test/test_cryptodev.c
index a37018c..1f822f0 100644
--- a/app/test/test_cryptodev.c
+++ b/app/test/test_cryptodev.c
@@ -195,6 +195,20 @@ testsuite_setup(void)
 		}
 	}
 
+	/* Create 2 Snow3G devices if required */
+	if (gbl_cryptodev_type == RTE_CRYPTODEV_SNOW3G_PMD) {
+		nb_devs = rte_cryptodev_count_devtype(RTE_CRYPTODEV_SNOW3G_PMD);
+		if (nb_devs < 2) {
+			for (i = nb_devs; i < 2; i++) {
+				TEST_ASSERT_SUCCESS(rte_eal_vdev_init(
+					CRYPTODEV_NAME_SNOW3G_PMD, NULL),
+					"Failed to create instance %u of"
+					" pmd : %s",
+					i, CRYPTODEV_NAME_SNOW3G_PMD);
+			}
+		}
+	}
+
 	nb_devs = rte_cryptodev_count();
 	if (nb_devs < 1) {
 		RTE_LOG(ERR, USER1, "No crypto devices found?");
@@ -3074,6 +3088,56 @@ static struct unit_test_suite cryptodev_aesni_mb_testsuite  = {
 	}
 };
 
+static struct unit_test_suite cryptodev_sw_snow3g_testsuite  = {
+	.suite_name = "Crypto Device SW Snow3G Unit Test Suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		/** Snow3G encrypt only (UEA2) */
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encryption_test_case_1),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encryption_test_case_2),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encryption_test_case_3),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encryption_test_case_4),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encryption_test_case_5),
+
+
+		/** Snow3G decrypt only (UEA2) */
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_decryption_test_case_1),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_decryption_test_case_2),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_decryption_test_case_3),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_decryption_test_case_4),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_decryption_test_case_5),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_generate_test_case_1),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_generate_test_case_2),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_generate_test_case_3),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_verify_test_case_1),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_verify_test_case_2),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_verify_test_case_3),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_authenticated_encryption_test_case_1),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encrypted_authentication_test_case_1),
+
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
 static int
 test_cryptodev_qat(void /*argv __rte_unused, int argc __rte_unused*/)
 {
@@ -3098,5 +3162,19 @@ static struct test_command cryptodev_aesni_mb_cmd = {
 	.callback = test_cryptodev_aesni_mb,
 };
 
+static int
+test_cryptodev_sw_snow3g(void /*argv __rte_unused, int argc __rte_unused*/)
+{
+	gbl_cryptodev_type = RTE_CRYPTODEV_SNOW3G_PMD;
+
+	return unit_test_suite_runner(&cryptodev_sw_snow3g_testsuite);
+}
+
+static struct test_command cryptodev_sw_snow3g_cmd = {
+	.command = "cryptodev_sw_snow3g_autotest",
+	.callback = test_cryptodev_sw_snow3g,
+};
+
 REGISTER_TEST_COMMAND(cryptodev_qat_cmd);
 REGISTER_TEST_COMMAND(cryptodev_aesni_mb_cmd);
+REGISTER_TEST_COMMAND(cryptodev_sw_snow3g_cmd);
diff --git a/config/common_base b/config/common_base
index 3066e9a..4202a89 100644
--- a/config/common_base
+++ b/config/common_base
@@ -337,6 +337,12 @@ CONFIG_RTE_AESNI_MB_PMD_MAX_NB_QUEUE_PAIRS=8
 CONFIG_RTE_AESNI_MB_PMD_MAX_NB_SESSIONS=2048
 
 #
+# Compile PMD for SNOW 3G device
+#
+CONFIG_RTE_LIBRTE_PMD_SNOW3G=n
+CONFIG_RTE_LIBRTE_PMD_SNOW3G_DEBUG=n
+
+#
 # Compile librte_ring
 #
 CONFIG_RTE_LIBRTE_RING=y
diff --git a/doc/guides/cryptodevs/index.rst b/doc/guides/cryptodevs/index.rst
index 16a5f4a..071e7d2 100644
--- a/doc/guides/cryptodevs/index.rst
+++ b/doc/guides/cryptodevs/index.rst
@@ -36,4 +36,5 @@ Crypto Device Drivers
     :numbered:
 
     aesni_mb
+    snow3g
     qat
diff --git a/doc/guides/cryptodevs/snow3g.rst b/doc/guides/cryptodevs/snow3g.rst
new file mode 100644
index 0000000..9e81eeb
--- /dev/null
+++ b/doc/guides/cryptodevs/snow3g.rst
@@ -0,0 +1,69 @@
+..  BSD LICENSE
+    Copyright(c) 2016 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.
+
+SNOW 3G Crypto Poll Mode Driver
+==============================
+
+The SNOW 3G PMD (**librte_pmd_snow3g**) provides poll mode crypto driver
+support for utilizing Intel Libsso library, which implements F8 and F9 functions
+for SNOW 3G UEA2 cipher and UIA2 hash algorithms.
+
+Features
+--------
+
+SNOW 3G PMD has support for:
+
+Cipher algorithm:
+
+* RTE_CRYPTO_SYM_CIPHER_SNOW3G_UEA2
+
+Hash algorithm:
+
+* RTE_CRYPTO_SYM_HASH_SNOW3G_UIA2
+
+Limitations
+-----------
+
+* Chained mbufs are not supported.
+
+Installation
+------------
+
+To build DPDK with the SNOW3G_PMD the user is required to get
+the export controlled libsso library, sending a request to
+`DPDKUser_software_access@intel.com`, and compile it
+on their user system before building DPDK:
+
+.. code-block:: console
+
+	make -f Makefile_snow3g
+
+The environmental variable LIBSSO_PATH must be exported with the path
+where you extracted and built the libsso library and finally set
+CONFIG_RTE_LIBRTE_SNOW3G=y in config/common_linuxapp.
diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst
index ab446ff..d7a264a 100644
--- a/doc/guides/rel_notes/release_16_04.rst
+++ b/doc/guides/rel_notes/release_16_04.rst
@@ -63,6 +63,10 @@ This section should contain new features added in this release. Sample format:
 
 * **Added vhost-user live migration support.**
 
+* **Added SNOW3G SW PMD**
+
+  A new Crypto PMD has been added, which provides SNOW 3G UEA2 ciphering
+  and SNOW3G UIA2 hashing.
 
 Resolved Issues
 ---------------
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index d0258da..bf586d9 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -33,5 +33,6 @@ include $(RTE_SDK)/mk/rte.vars.mk
 
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_AESNI_MB) += aesni_mb
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_QAT) += qat
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += snow3g
 
 include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/drivers/crypto/snow3g/Makefile b/drivers/crypto/snow3g/Makefile
new file mode 100644
index 0000000..ee58270
--- /dev/null
+++ b/drivers/crypto/snow3g/Makefile
@@ -0,0 +1,64 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 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 ($(LIBSSO_PATH),)
+$(error "Please define LIBSSO_PATH environment variable")
+endif
+
+# library name
+LIB = librte_pmd_snow3g.a
+
+# build flags
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+# library version
+LIBABIVER := 1
+
+# versioning export map
+EXPORT_MAP := rte_pmd_snow3g_version.map
+
+# external library include paths
+CFLAGS += -I$(LIBSSO_PATH)
+CFLAGS += -I$(LIBSSO_PATH)/include
+CFLAGS += -I$(LIBSSO_PATH)/build
+
+# library source files
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += rte_snow3g_pmd.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += rte_snow3g_pmd_ops.c
+
+# library dependencies
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += lib/librte_cryptodev
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/crypto/snow3g/rte_pmd_snow3g_version.map b/drivers/crypto/snow3g/rte_pmd_snow3g_version.map
new file mode 100644
index 0000000..dc4d417
--- /dev/null
+++ b/drivers/crypto/snow3g/rte_pmd_snow3g_version.map
@@ -0,0 +1,3 @@
+DPDK_16.04 {
+	local: *;
+};
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd.c b/drivers/crypto/snow3g/rte_snow3g_pmd.c
new file mode 100644
index 0000000..c35e66e
--- /dev/null
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd.c
@@ -0,0 +1,531 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_kvargs.h>
+
+#include "rte_snow3g_pmd_private.h"
+
+#define SNOW3G_MAX_BURST 8
+
+/**
+ * Global static parameter used to create a unique name for each SNOW 3G
+ * 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_SNOW3G_PMD,
+			unique_name_id++);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+/** Get xform chain order. */
+static enum snow3g_operation
+snow3g_get_mode(const struct rte_crypto_sym_xform *xform)
+{
+	if (xform == NULL)
+		return SNOW3G_OP_NOT_SUPPORTED;
+
+	if (xform->next)
+		if (xform->next->next != NULL)
+			return SNOW3G_OP_NOT_SUPPORTED;
+
+	if (xform->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
+		if (xform->next == NULL)
+			return SNOW3G_OP_ONLY_AUTH;
+		else if (xform->next->type == RTE_CRYPTO_SYM_XFORM_CIPHER)
+			return SNOW3G_OP_AUTH_CIPHER;
+		else
+			return SNOW3G_OP_NOT_SUPPORTED;
+	}
+
+	if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		if (xform->next == NULL)
+			return SNOW3G_OP_ONLY_CIPHER;
+		else if (xform->next->type == RTE_CRYPTO_SYM_XFORM_AUTH)
+			return SNOW3G_OP_CIPHER_AUTH;
+		else
+			return SNOW3G_OP_NOT_SUPPORTED;
+	}
+
+	return SNOW3G_OP_NOT_SUPPORTED;
+}
+
+
+/** Parse crypto xform chain and set private session parameters. */
+int
+snow3g_set_session_parameters(struct snow3g_session *sess,
+		const struct rte_crypto_sym_xform *xform)
+{
+	const struct rte_crypto_sym_xform *auth_xform = NULL;
+	const struct rte_crypto_sym_xform *cipher_xform = NULL;
+	int mode;
+
+	/* Select Crypto operation - hash then cipher / cipher then hash */
+	mode = snow3g_get_mode(xform);
+
+	switch (mode) {
+	case SNOW3G_OP_CIPHER_AUTH:
+		auth_xform = xform->next;
+
+		/* Fall-through */
+	case SNOW3G_OP_ONLY_CIPHER:
+		cipher_xform = xform;
+		break;
+	case SNOW3G_OP_AUTH_CIPHER:
+		cipher_xform = xform->next;
+		/* Fall-through */
+	case SNOW3G_OP_ONLY_AUTH:
+		auth_xform = xform;
+	}
+
+	if (mode == SNOW3G_OP_NOT_SUPPORTED) {
+		SNOW3G_LOG_ERR("Unsupported operation chain order parameter");
+		return -EINVAL;
+	}
+
+	if (cipher_xform) {
+		/* Only SNOW 3G UEA2 supported */
+		if (cipher_xform->cipher.algo != RTE_CRYPTO_CIPHER_SNOW3G_UEA2)
+			return -EINVAL;
+		/* Initialize key */
+		sso_snow3g_init_key_sched(xform->cipher.key.data,
+				&sess->pKeySched_cipher);
+	}
+
+	if (auth_xform) {
+		/* Only SNOW 3G UIA2 supported */
+		if (auth_xform->auth.algo != RTE_CRYPTO_AUTH_SNOW3G_UIA2)
+			return -EINVAL;
+		sess->auth_op = auth_xform->auth.op;
+		/* Initialize key */
+		sso_snow3g_init_key_sched(xform->auth.key.data,
+				&sess->pKeySched_hash);
+	}
+
+
+	sess->op = mode;
+
+	return 0;
+}
+
+/** Get SNOW 3G session. */
+static struct snow3g_session *
+snow3g_get_session(struct snow3g_qp *qp, struct rte_crypto_op *op)
+{
+	struct snow3g_session *sess;
+
+	if (op->sym->type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
+		if (unlikely(op->sym->session->type !=
+				RTE_CRYPTODEV_SNOW3G_PMD))
+			return NULL;
+
+		sess = (struct snow3g_session *)op->sym->session->_private;
+	} else  {
+		struct rte_cryptodev_session *c_sess = NULL;
+
+		if (rte_mempool_get(qp->sess_mp, (void **)&c_sess))
+			return NULL;
+
+		sess = (struct snow3g_session *)c_sess->_private;
+
+		if (unlikely(snow3g_set_session_parameters(sess,
+				op->sym->xform) != 0))
+			return NULL;
+	}
+
+	return sess;
+}
+
+/** Encrypt/decrypt mbufs with same cipher key. */
+static uint8_t
+process_snow3g_cipher_op(struct rte_crypto_op **ops,
+		struct snow3g_session *session,
+		uint8_t num_ops)
+{
+	unsigned i;
+	uint8_t processed_ops = 0;
+	uint8_t *src[SNOW3G_MAX_BURST], *dst[SNOW3G_MAX_BURST];
+	uint8_t *IV[SNOW3G_MAX_BURST];
+	uint32_t num_bytes[SNOW3G_MAX_BURST];
+
+	for (i = 0; i < num_ops; i++) {
+		/* Sanity checks. */
+		if (ops[i]->sym->cipher.iv.length != 16) {
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+			SNOW3G_LOG_ERR("iv");
+			break;
+		}
+
+		src[i] = rte_pktmbuf_mtod(ops[i]->sym->m_src, uint8_t *) +
+				ops[i]->sym->cipher.data.offset;
+		dst[i] = ops[i]->sym->m_dst ?
+				rte_pktmbuf_mtod(ops[i]->sym->m_dst, uint8_t *) +
+					ops[i]->sym->cipher.data.offset :
+				rte_pktmbuf_mtod(ops[i]->sym->m_src, uint8_t *) +
+					ops[i]->sym->cipher.data.offset;
+		IV[i] = ops[i]->sym->cipher.iv.data;
+		num_bytes[i] = ops[i]->sym->cipher.data.length;
+
+		processed_ops++;
+	}
+
+	sso_snow3g_f8_n_buffer(&session->pKeySched_cipher, IV, src, dst,
+			num_bytes, processed_ops);
+
+	return processed_ops;
+}
+
+/** Generate/verify hash from mbufs with same hash key. */
+static int
+process_snow3g_hash_op(struct rte_crypto_op **ops,
+		struct snow3g_session *session,
+		uint8_t num_ops)
+{
+	unsigned i;
+	uint8_t processed_ops = 0;
+	uint8_t *src, *dst;
+	uint32_t length_in_bits;
+
+	for (i = 0; i < num_ops; i++) {
+		if (ops[i]->sym->auth.aad.length != 16) {
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+			SNOW3G_LOG_ERR("aad");
+			break;
+		}
+
+		if (ops[i]->sym->auth.digest.length != 4) {
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+			SNOW3G_LOG_ERR("digest");
+			break;
+		}
+
+		length_in_bits = ops[i]->sym->auth.data.length * 8;
+
+		src = rte_pktmbuf_mtod(ops[i]->sym->m_src, uint8_t *) +
+				ops[i]->sym->auth.data.offset;
+
+		if (session->auth_op == RTE_CRYPTO_AUTH_OP_VERIFY) {
+			dst = (uint8_t *)rte_pktmbuf_append(ops[i]->sym->m_src,
+					ops[i]->sym->auth.digest.length);
+
+			sso_snow3g_f9_1_buffer(&session->pKeySched_hash,
+					ops[i]->sym->auth.aad.data, src,
+					length_in_bits,	dst);
+			/* Verify digest. */
+			if (memcmp(dst, ops[i]->sym->auth.digest.data,
+					ops[i]->sym->auth.digest.length) != 0)
+				ops[i]->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
+
+			/* Trim area used for digest from mbuf. */
+			rte_pktmbuf_trim(ops[i]->sym->m_src,
+					ops[i]->sym->auth.digest.length);
+		} else  {
+			dst = ops[i]->sym->auth.digest.data;
+
+			sso_snow3g_f9_1_buffer(&session->pKeySched_hash,
+					ops[i]->sym->auth.aad.data, src,
+					length_in_bits, dst);
+		}
+		processed_ops++;
+	}
+
+	return processed_ops;
+}
+
+/** Process a batch of crypto ops which shares the same session. */
+static int
+process_ops(struct rte_crypto_op **ops, struct snow3g_session *session,
+		struct snow3g_qp *qp, uint8_t num_ops)
+{
+	unsigned i;
+	unsigned processed_ops;
+
+	switch (session->op) {
+	case SNOW3G_OP_ONLY_CIPHER:
+		processed_ops = process_snow3g_cipher_op(ops,
+				session, num_ops);
+		break;
+	case SNOW3G_OP_ONLY_AUTH:
+		processed_ops = process_snow3g_hash_op(ops, session,
+				num_ops);
+		break;
+	case SNOW3G_OP_CIPHER_AUTH:
+		processed_ops = process_snow3g_cipher_op(ops, session,
+				num_ops);
+		process_snow3g_hash_op(ops, session, processed_ops);
+		break;
+	case SNOW3G_OP_AUTH_CIPHER:
+		processed_ops = process_snow3g_hash_op(ops, session,
+				num_ops);
+		process_snow3g_cipher_op(ops, session, processed_ops);
+		break;
+	default:
+		/* Operation not supported. */
+		processed_ops = 0;
+	}
+
+	for (i = 0; i < num_ops; i++) {
+		/*
+		 * If there was no error/authentication failure,
+		 * change status to successful.
+		 */
+		if (ops[i]->status == RTE_CRYPTO_OP_STATUS_NOT_PROCESSED)
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
+		/* Free session if a session-less crypto op. */
+		if (ops[i]->sym->type == RTE_CRYPTO_SYM_OP_SESSIONLESS) {
+			rte_mempool_put(qp->sess_mp, ops[i]->sym->session);
+			ops[i]->sym->session = NULL;
+		}
+	}
+
+	return processed_ops;
+}
+
+static uint16_t
+snow3g_pmd_enqueue_burst(void *queue_pair, struct rte_crypto_op **ops,
+		uint16_t nb_ops)
+{
+	struct rte_crypto_op *c_ops[SNOW3G_MAX_BURST];
+	struct rte_crypto_op *curr_c_op;
+
+	struct snow3g_session *prev_sess = NULL, *curr_sess = NULL;
+	struct snow3g_qp *qp = queue_pair;
+	unsigned i, n;
+	uint8_t burst_size = 0;
+	uint16_t enqueued_ops = 0;
+	uint8_t processed_ops;
+
+	for (i = 0; i < nb_ops; i++) {
+		curr_c_op = ops[i];
+
+		/* Set status as enqueued (not processed yet) by default. */
+		curr_c_op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
+
+		curr_sess = snow3g_get_session(qp, curr_c_op);
+		if (unlikely(curr_sess == NULL ||
+				curr_sess->op == SNOW3G_OP_NOT_SUPPORTED)) {
+			curr_c_op->status =
+					RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
+			qp->qp_stats.enqueue_err_count += nb_ops - enqueued_ops;
+			return enqueued_ops;
+		}
+
+		/* Batch ops that share the same session. */
+		if (prev_sess == NULL) {
+			prev_sess = curr_sess;
+			c_ops[burst_size++] = curr_c_op;
+		} else if (curr_sess == prev_sess) {
+			c_ops[burst_size++] = curr_c_op;
+			/*
+			 * When there are enough ops to process in a batch,
+			 * process them, and start a new batch.
+			 */
+			if (burst_size == SNOW3G_MAX_BURST) {
+				processed_ops = process_ops(c_ops,
+						prev_sess, qp, burst_size);
+				n = rte_ring_enqueue_burst(qp->processed_ops,
+						(void **)c_ops,
+						processed_ops);
+				qp->qp_stats.enqueued_count += n;
+				enqueued_ops += n;
+				if (n < burst_size) {
+					qp->qp_stats.enqueue_err_count +=
+							nb_ops - enqueued_ops;
+					return enqueued_ops;
+				}
+				burst_size = 0;
+
+				prev_sess = NULL;
+			}
+		} else {
+			/*
+			 * Different session, process the ops
+			 * of the previous session.
+			 */
+			processed_ops = process_ops(c_ops,
+					prev_sess, qp, burst_size);
+			n = rte_ring_enqueue_burst(qp->processed_ops,
+					(void **)c_ops,
+					processed_ops);
+			qp->qp_stats.enqueued_count += n;
+			enqueued_ops += n;
+			if (n < burst_size) {
+				qp->qp_stats.enqueue_err_count +=
+						nb_ops - enqueued_ops;
+				return enqueued_ops;
+			}
+			burst_size = 0;
+
+			prev_sess = curr_sess;
+			c_ops[burst_size++] = curr_c_op;
+		}
+	}
+
+	if (burst_size != 0) {
+		/* Process the crypto ops of the last session. */
+		processed_ops = process_ops(c_ops,
+				prev_sess, qp, burst_size);
+		n = rte_ring_enqueue_burst(qp->processed_ops,
+				(void **)c_ops,
+				processed_ops);
+		qp->qp_stats.enqueued_count += n;
+		enqueued_ops += n;
+		if (n < burst_size) {
+			qp->qp_stats.enqueue_err_count +=
+					nb_ops - enqueued_ops;
+			return enqueued_ops;
+		}
+	}
+
+	return enqueued_ops;
+}
+
+static uint16_t
+snow3g_pmd_dequeue_burst(void *queue_pair,
+		struct rte_crypto_op **c_ops, uint16_t nb_ops)
+{
+	struct snow3g_qp *qp = queue_pair;
+
+	unsigned nb_dequeued;
+
+	nb_dequeued = rte_ring_dequeue_burst(qp->processed_ops,
+			(void **)c_ops, nb_ops);
+	qp->qp_stats.dequeued_count += nb_dequeued;
+
+	return nb_dequeued;
+}
+
+static int cryptodev_snow3g_uninit(const char *name);
+
+static int
+cryptodev_snow3g_create(const char *name,
+		struct rte_crypto_vdev_init_params *init_params)
+{
+	struct rte_cryptodev *dev;
+	char crypto_dev_name[RTE_CRYPTODEV_NAME_MAX_LEN];
+	struct snow3g_private *internals;
+
+	/* Create a unique device name. */
+	if (create_unique_device_name(crypto_dev_name,
+			RTE_CRYPTODEV_NAME_MAX_LEN) != 0) {
+		SNOW3G_LOG_ERR("failed to create unique cryptodev name");
+		return -EINVAL;
+	}
+
+	dev = rte_cryptodev_pmd_virtual_dev_init(crypto_dev_name,
+			sizeof(struct snow3g_private), init_params->socket_id);
+	if (dev == NULL) {
+		SNOW3G_LOG_ERR("failed to create cryptodev vdev");
+		goto init_error;
+	}
+
+	dev->dev_type = RTE_CRYPTODEV_SNOW3G_PMD;
+	dev->dev_ops = rte_snow3g_pmd_ops;
+
+	/* Register RX/TX burst functions for data path. */
+	dev->dequeue_burst = snow3g_pmd_dequeue_burst;
+	dev->enqueue_burst = snow3g_pmd_enqueue_burst;
+
+	internals = dev->data->dev_private;
+
+	internals->max_nb_queue_pairs = init_params->max_nb_queue_pairs;
+	internals->max_nb_sessions = init_params->max_nb_sessions;
+
+	return 0;
+init_error:
+	SNOW3G_LOG_ERR("driver %s: cryptodev_snow3g_create failed", name);
+
+	cryptodev_snow3g_uninit(crypto_dev_name);
+	return -EFAULT;
+}
+
+static int
+cryptodev_snow3g_init(const char *name,
+		const char *input_args)
+{
+	struct rte_crypto_vdev_init_params init_params = {
+		RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_QUEUE_PAIRS,
+		RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_SESSIONS,
+		rte_socket_id()
+	};
+
+	rte_cryptodev_parse_vdev_init_params(&init_params, input_args);
+
+	RTE_LOG(INFO, PMD, "Initialising %s on NUMA node %d\n", name,
+			init_params.socket_id);
+	RTE_LOG(INFO, PMD, "  Max number of queue pairs = %d\n",
+			init_params.max_nb_queue_pairs);
+	RTE_LOG(INFO, PMD, "  Max number of sessions = %d\n",
+			init_params.max_nb_sessions);
+
+	return cryptodev_snow3g_create(name, &init_params);
+}
+
+static int
+cryptodev_snow3g_uninit(const char *name)
+{
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Closing SNOW3G crypto device %s"
+			" on numa socket %u\n",
+			name, rte_socket_id());
+
+	return 0;
+}
+
+static struct rte_driver cryptodev_snow3g_pmd_drv = {
+	.name = CRYPTODEV_NAME_SNOW3G_PMD,
+	.type = PMD_VDEV,
+	.init = cryptodev_snow3g_init,
+	.uninit = cryptodev_snow3g_uninit
+};
+
+PMD_REGISTER_DRIVER(cryptodev_snow3g_pmd_drv);
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
new file mode 100644
index 0000000..5643323
--- /dev/null
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
@@ -0,0 +1,291 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_snow3g_pmd_private.h"
+
+/** Configure device */
+static int
+snow3g_pmd_config(__rte_unused struct rte_cryptodev *dev)
+{
+	return 0;
+}
+
+/** Start device */
+static int
+snow3g_pmd_start(__rte_unused struct rte_cryptodev *dev)
+{
+	return 0;
+}
+
+/** Stop device */
+static void
+snow3g_pmd_stop(__rte_unused struct rte_cryptodev *dev)
+{
+}
+
+/** Close device */
+static int
+snow3g_pmd_close(__rte_unused struct rte_cryptodev *dev)
+{
+	return 0;
+}
+
+
+/** Get device statistics */
+static void
+snow3g_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 snow3g_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
+snow3g_pmd_stats_reset(struct rte_cryptodev *dev)
+{
+	int qp_id;
+
+	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {
+		struct snow3g_qp *qp = dev->data->queue_pairs[qp_id];
+
+		memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
+	}
+}
+
+
+/** Get device info */
+static void
+snow3g_pmd_info_get(struct rte_cryptodev *dev,
+		struct rte_cryptodev_info *dev_info)
+{
+	struct snow3g_private *internals = dev->data->dev_private;
+
+	if (dev_info != NULL) {
+		dev_info->dev_type = dev->dev_type;
+		dev_info->max_nb_queue_pairs = internals->max_nb_queue_pairs;
+		dev_info->sym.max_nb_sessions = internals->max_nb_sessions;
+	}
+}
+
+/** Release queue pair */
+static int
+snow3g_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 its name, dev_id and qp_id */
+static int
+snow3g_pmd_qp_set_unique_name(struct rte_cryptodev *dev,
+		struct snow3g_qp *qp)
+{
+	unsigned n = snprintf(qp->name, sizeof(qp->name),
+			"snow3g_pmd_%u_qp_%u",
+			dev->data->dev_id, qp->id);
+
+	if (n > sizeof(qp->name))
+		return -1;
+
+	return 0;
+}
+
+/** Create a ring to place processed ops on */
+static struct rte_ring *
+snow3g_pmd_qp_create_processed_ops_ring(struct snow3g_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) {
+			SNOW3G_LOG_INFO("Reusing existing ring %s"
+					" for processed packets",
+					 qp->name);
+			return r;
+		}
+
+		SNOW3G_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
+snow3g_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
+		const struct rte_cryptodev_qp_conf *qp_conf,
+		 int socket_id)
+{
+	struct snow3g_qp *qp = NULL;
+
+	/* Free memory prior to re-allocation if needed. */
+	if (dev->data->queue_pairs[qp_id] != NULL)
+		snow3g_pmd_qp_release(dev, qp_id);
+
+	/* Allocate the queue pair data structure. */
+	qp = rte_zmalloc_socket("SNOW3G 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 (snow3g_pmd_qp_set_unique_name(dev, qp))
+		goto qp_setup_cleanup;
+
+	qp->processed_ops = snow3g_pmd_qp_create_processed_ops_ring(qp,
+			qp_conf->nb_descriptors, socket_id);
+	if (qp->processed_ops == NULL)
+		goto qp_setup_cleanup;
+
+	qp->sess_mp = dev->data->session_pool;
+
+	memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
+
+	return 0;
+
+qp_setup_cleanup:
+	if (qp)
+		rte_free(qp);
+
+	return -1;
+}
+
+/** Start queue pair */
+static int
+snow3g_pmd_qp_start(__rte_unused struct rte_cryptodev *dev,
+		__rte_unused uint16_t queue_pair_id)
+{
+	return -ENOTSUP;
+}
+
+/** Stop queue pair */
+static int
+snow3g_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
+snow3g_pmd_qp_count(struct rte_cryptodev *dev)
+{
+	return dev->data->nb_queue_pairs;
+}
+
+/** Returns the size of the SNOW 3G session structure */
+static unsigned
+snow3g_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
+{
+	return sizeof(struct snow3g_session);
+}
+
+/** Configure a SNOW 3G session from a crypto xform chain */
+static void *
+snow3g_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
+		struct rte_crypto_sym_xform *xform,	void *sess)
+{
+	if (unlikely(sess == NULL)) {
+		SNOW3G_LOG_ERR("invalid session struct");
+		return NULL;
+	}
+
+	if (snow3g_set_session_parameters(sess, xform) != 0) {
+		SNOW3G_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
+snow3g_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 snow3g_session));
+}
+
+struct rte_cryptodev_ops snow3g_pmd_ops = {
+		.dev_configure      = snow3g_pmd_config,
+		.dev_start          = snow3g_pmd_start,
+		.dev_stop           = snow3g_pmd_stop,
+		.dev_close          = snow3g_pmd_close,
+
+		.stats_get          = snow3g_pmd_stats_get,
+		.stats_reset        = snow3g_pmd_stats_reset,
+
+		.dev_infos_get      = snow3g_pmd_info_get,
+
+		.queue_pair_setup   = snow3g_pmd_qp_setup,
+		.queue_pair_release = snow3g_pmd_qp_release,
+		.queue_pair_start   = snow3g_pmd_qp_start,
+		.queue_pair_stop    = snow3g_pmd_qp_stop,
+		.queue_pair_count   = snow3g_pmd_qp_count,
+
+		.session_get_size   = snow3g_pmd_session_get_size,
+		.session_configure  = snow3g_pmd_session_configure,
+		.session_clear      = snow3g_pmd_session_clear
+};
+
+struct rte_cryptodev_ops *rte_snow3g_pmd_ops = &snow3g_pmd_ops;
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd_private.h b/drivers/crypto/snow3g/rte_snow3g_pmd_private.h
new file mode 100644
index 0000000..b383cbc
--- /dev/null
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd_private.h
@@ -0,0 +1,107 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_SNOW3G_PMD_PRIVATE_H_
+#define _RTE_SNOW3G_PMD_PRIVATE_H_
+
+#include <sso_snow3g.h>
+
+#define SNOW3G_LOG_ERR(fmt, args...) \
+	RTE_LOG(ERR, CRYPTODEV, "[%s] %s() line %u: " fmt "\n",  \
+			CRYPTODEV_NAME_SNOW3G_PMD, \
+			__func__, __LINE__, ## args)
+
+#ifdef RTE_LIBRTE_SNOW3G_DEBUG
+#define SNOW3G_LOG_INFO(fmt, args...) \
+	RTE_LOG(INFO, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+			CRYPTODEV_NAME_SNOW3G_PMD, \
+			__func__, __LINE__, ## args)
+
+#define SNOW3G_LOG_DBG(fmt, args...) \
+	RTE_LOG(DEBUG, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+			CRYPTODEV_NAME_SNOW3G_PMD, \
+			__func__, __LINE__, ## args)
+#else
+#define SNOW3G_LOG_INFO(fmt, args...)
+#define SNOW3G_LOG_DBG(fmt, args...)
+#endif
+
+/** private data structure for each virtual SNOW 3G device */
+struct snow3g_private {
+	unsigned max_nb_queue_pairs;
+	/**< Max number of queue pairs supported by device */
+	unsigned max_nb_sessions;
+	/**< Max number of sessions supported by device */
+};
+
+/** SNOW 3G buffer queue pair */
+struct snow3g_qp {
+	uint16_t id;
+	/**< Queue Pair Identifier */
+	char name[RTE_CRYPTODEV_NAME_LEN];
+	/**< Unique Queue Pair Name */
+	struct rte_ring *processed_ops;
+	/**< Ring for placing processed ops */
+	struct rte_mempool *sess_mp;
+	/**< Session Mempool */
+	struct rte_cryptodev_stats qp_stats;
+	/**< Queue pair statistics */
+} __rte_cache_aligned;
+
+enum snow3g_operation {
+	SNOW3G_OP_ONLY_CIPHER,
+	SNOW3G_OP_ONLY_AUTH,
+	SNOW3G_OP_CIPHER_AUTH,
+	SNOW3G_OP_AUTH_CIPHER,
+	SNOW3G_OP_NOT_SUPPORTED
+};
+
+/** SNOW 3G private session structure */
+struct snow3g_session {
+	enum snow3g_operation op;
+	enum rte_crypto_auth_operation auth_op;
+	sso_snow3g_key_schedule_t pKeySched_cipher;
+	sso_snow3g_key_schedule_t pKeySched_hash;
+} __rte_cache_aligned;
+
+
+extern int
+snow3g_set_session_parameters(struct snow3g_session *sess,
+		const struct rte_crypto_sym_xform *xform);
+
+
+/** device specific operations function pointer structure */
+extern struct rte_cryptodev_ops *rte_snow3g_pmd_ops;
+
+
+
+#endif /* _RTE_SNOW3G_PMD_PRIVATE_H_ */
diff --git a/lib/librte_cryptodev/Makefile b/lib/librte_cryptodev/Makefile
index 0d59229..314a046 100644
--- a/lib/librte_cryptodev/Makefile
+++ b/lib/librte_cryptodev/Makefile
@@ -57,5 +57,6 @@ DEPDIRS-y += lib/librte_eal
 DEPDIRS-y += lib/librte_mempool
 DEPDIRS-y += lib/librte_ring
 DEPDIRS-y += lib/librte_mbuf
+DEPDIRS-y += lib/librte_kvargs
 
-include $(RTE_SDK)/mk/rte.lib.mk
\ No newline at end of file
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index aab8cff..f279c92 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -48,6 +48,7 @@
 extern "C" {
 #endif
 
+#include "rte_kvargs.h"
 #include "rte_crypto.h"
 #include "rte_dev.h"
 
@@ -57,15 +58,17 @@ extern "C" {
 /**< AES-NI Multi buffer PMD device name */
 #define CRYPTODEV_NAME_QAT_SYM_PMD	("cryptodev_qat_sym_pmd")
 /**< Intel QAT Symmetric Crypto PMD device name */
+#define CRYPTODEV_NAME_SNOW3G_PMD	("cryptodev_snow3g_pmd")
+/**< SNOW 3G PMD device name */
 
 /** Crypto device type */
 enum rte_cryptodev_type {
 	RTE_CRYPTODEV_NULL_PMD = 1,	/**< Null crypto PMD */
 	RTE_CRYPTODEV_AESNI_MB_PMD,	/**< AES-NI multi buffer PMD */
 	RTE_CRYPTODEV_QAT_SYM_PMD,	/**< QAT PMD Symmetric Crypto */
+	RTE_CRYPTODEV_SNOW3G_PMD,	/**< SNOW 3G PMD */
 };
 
-
 extern const char **rte_cyptodev_names;
 
 /* Logging Macros */
@@ -148,6 +151,121 @@ struct rte_cryptodev_stats {
 	/**< Total error count on operations dequeued */
 };
 
+#define RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_QUEUE_PAIRS	8
+#define RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_SESSIONS	2048
+
+/**
+ * @internal
+ * Initialisation parameters for virtual crypto devices
+ */
+struct rte_crypto_vdev_init_params {
+	unsigned max_nb_queue_pairs;
+	unsigned max_nb_sessions;
+	uint8_t socket_id;
+};
+
+#define RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG		("max_nb_queue_pairs")
+#define RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG		("max_nb_sessions")
+#define RTE_CRYPTODEV_VDEV_SOCKET_ID			("socket_id")
+
+static const char *cryptodev_vdev_valid_params[] = {
+	RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
+	RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG,
+	RTE_CRYPTODEV_VDEV_SOCKET_ID
+};
+
+static inline uint8_t
+number_of_sockets(void)
+{
+	int sockets = 0;
+	int i;
+	const struct rte_memseg *ms = rte_eal_get_physmem_layout();
+
+	for (i = 0; ((i < RTE_MAX_MEMSEG) && (ms[i].addr != NULL)); i++) {
+		if (sockets < ms[i].socket_id)
+			sockets = ms[i].socket_id;
+	}
+
+	/* Number of sockets = maximum socket_id + 1 */
+	return ++sockets;
+}
+
+/** Parse integer from integer argument */
+static inline int
+__rte_cryptodev_parse_integer_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	int *i = extra_args;
+
+	*i = atoi(value);
+	if (*i < 0) {
+		CDEV_LOG_ERR("Argument has to be positive.");
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse virtual device initialisation parameters input arguments
+ * @internal
+ *
+ * @params	params		Initialisation parameters with defaults set.
+ * @params	input_args	Command line arguments
+ *
+ * @return
+ * 0 on successful parse
+ * <0 on failure to parse
+ */
+static inline int
+rte_cryptodev_parse_vdev_init_params(struct rte_crypto_vdev_init_params *params,
+		const char *input_args)
+{
+	struct rte_kvargs *kvlist;
+	int ret;
+
+	if (params == NULL)
+		return -EINVAL;
+
+	if (input_args) {
+		kvlist = rte_kvargs_parse(input_args,
+				cryptodev_vdev_valid_params);
+		if (kvlist == NULL)
+			return -1;
+
+		ret = rte_kvargs_process(kvlist,
+					RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
+					&__rte_cryptodev_parse_integer_arg,
+					&params->max_nb_queue_pairs);
+		if (ret < 0)
+			goto free_kvlist;
+
+		ret = rte_kvargs_process(kvlist,
+					RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG,
+					&__rte_cryptodev_parse_integer_arg,
+					&params->max_nb_sessions);
+		if (ret < 0)
+			goto free_kvlist;
+
+		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_SOCKET_ID,
+					&__rte_cryptodev_parse_integer_arg,
+					&params->socket_id);
+		if (ret < 0)
+			goto free_kvlist;
+
+		if (params->socket_id >= number_of_sockets()) {
+			CDEV_LOG_ERR("Invalid socket id specified to create "
+				"the virtual crypto device on");
+			goto free_kvlist;
+		}
+	}
+
+	return 0;
+
+free_kvlist:
+	rte_kvargs_free(kvlist);
+	return ret;
+}
 
 /**
  * Create a virtual crypto device
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index daac09f..7e46370 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   Copyright(c) 2014-2015 6WIND S.A.
 #   All rights reserved.
 #
@@ -150,6 +150,10 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_QAT)        += -lrte_pmd_qat
 _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
 
+# SNOW3G PMD is dependent on the LIBSSO library
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G)     += -lrte_pmd_snow3g
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G)     += -L$(LIBSSO_PATH)/build -lsso
+
 endif # ! $(CONFIG_RTE_BUILD_SHARED_LIB)
 
 _LDLIBS-y += $(EXECENV_LDLIBS)
-- 
2.5.0

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [dpdk-dev] [PATCH v3] pmd/snow3g: add new SNOW 3G SW PMD
  2016-03-07 14:07 ` [dpdk-dev] [PATCH v2] " Pablo de Lara
@ 2016-03-07 19:48   ` Pablo de Lara
  2016-03-08 14:10     ` Jain, Deepak K
  2016-03-10 16:33     ` [dpdk-dev] [PATCH v4] " Pablo de Lara
  2016-03-07 19:48   ` [dpdk-dev] [PATCH v2] " De Lara Guarch, Pablo
  1 sibling, 2 replies; 9+ messages in thread
From: Pablo de Lara @ 2016-03-07 19:48 UTC (permalink / raw)
  To: dev

Added new SW PMD which makes use of the libsso SW library,
which provides wireless algorithms SNOW 3G UEA2 and UIA2
in software.

This PMD supports cipher-only, hash-only and chained operations
("cipher then hash" and "hash then cipher") of the following
algorithms:
- RTE_CRYPTO_SYM_CIPHER_SNOW3G_UEA2
- RTE_CRYPTO_SYM_HASH_SNOW3G_UIA2

The SNOW 3G hash and cipher algorithms, which are enabled
by this crypto PMD are implemented by Intel's libsso software
library. For library download and build instructions,
see the documentation included (doc/guides/cryptodevs/snow3g.rst)

The patch also contains the related unit tests function to test the PMD
supported operations.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---

This patch depends on "Snow3G support for Intel Quick Assist Devices" patchset
(http://dpdk.org/ml/archives/dev/2016-March/034503.html).

Changes in v3:

- Corrected patch dependency

Changes in v2:

- Rebased against crypto API changes
- Removed static config options and allow user to provide them
  as virtual device parameters.
- Added unit tests
- Changed DPDK version references from 2.3 to 16.04
- Fixed crypto operation status handling
- Fixed copyright dates
- Fixed enqueue error stats


 MAINTAINERS                                      |   4 +
 app/test/test_cryptodev.c                        |  78 ++++
 config/common_base                               |   6 +
 doc/guides/cryptodevs/index.rst                  |   1 +
 doc/guides/cryptodevs/snow3g.rst                 |  69 +++
 doc/guides/rel_notes/release_16_04.rst           |   4 +
 drivers/crypto/Makefile                          |   3 +-
 drivers/crypto/snow3g/Makefile                   |  64 +++
 drivers/crypto/snow3g/rte_pmd_snow3g_version.map |   3 +
 drivers/crypto/snow3g/rte_snow3g_pmd.c           | 531 +++++++++++++++++++++++
 drivers/crypto/snow3g/rte_snow3g_pmd_ops.c       | 291 +++++++++++++
 drivers/crypto/snow3g/rte_snow3g_pmd_private.h   | 107 +++++
 lib/librte_cryptodev/Makefile                    |   3 +-
 lib/librte_cryptodev/rte_cryptodev.h             | 120 ++++-
 mk/rte.app.mk                                    |   6 +-
 15 files changed, 1286 insertions(+), 4 deletions(-)
 create mode 100644 doc/guides/cryptodevs/snow3g.rst
 create mode 100644 drivers/crypto/snow3g/Makefile
 create mode 100644 drivers/crypto/snow3g/rte_pmd_snow3g_version.map
 create mode 100644 drivers/crypto/snow3g/rte_snow3g_pmd.c
 create mode 100644 drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
 create mode 100644 drivers/crypto/snow3g/rte_snow3g_pmd_private.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 8d84dda..c028e67 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -355,6 +355,10 @@ F: drivers/crypto/aesni_mb/
 Intel QuickAssist
 F: drivers/crypto/qat/
 
+SNOW 3G PMD
+M: Pablo de Lara <pablo.de.lara.guarch@intel.com>
+F: drivers/crypto/snow3g
+
 
 Packet processing
 -----------------
diff --git a/app/test/test_cryptodev.c b/app/test/test_cryptodev.c
index a37018c..1f822f0 100644
--- a/app/test/test_cryptodev.c
+++ b/app/test/test_cryptodev.c
@@ -195,6 +195,20 @@ testsuite_setup(void)
 		}
 	}
 
+	/* Create 2 Snow3G devices if required */
+	if (gbl_cryptodev_type == RTE_CRYPTODEV_SNOW3G_PMD) {
+		nb_devs = rte_cryptodev_count_devtype(RTE_CRYPTODEV_SNOW3G_PMD);
+		if (nb_devs < 2) {
+			for (i = nb_devs; i < 2; i++) {
+				TEST_ASSERT_SUCCESS(rte_eal_vdev_init(
+					CRYPTODEV_NAME_SNOW3G_PMD, NULL),
+					"Failed to create instance %u of"
+					" pmd : %s",
+					i, CRYPTODEV_NAME_SNOW3G_PMD);
+			}
+		}
+	}
+
 	nb_devs = rte_cryptodev_count();
 	if (nb_devs < 1) {
 		RTE_LOG(ERR, USER1, "No crypto devices found?");
@@ -3074,6 +3088,56 @@ static struct unit_test_suite cryptodev_aesni_mb_testsuite  = {
 	}
 };
 
+static struct unit_test_suite cryptodev_sw_snow3g_testsuite  = {
+	.suite_name = "Crypto Device SW Snow3G Unit Test Suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		/** Snow3G encrypt only (UEA2) */
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encryption_test_case_1),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encryption_test_case_2),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encryption_test_case_3),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encryption_test_case_4),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encryption_test_case_5),
+
+
+		/** Snow3G decrypt only (UEA2) */
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_decryption_test_case_1),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_decryption_test_case_2),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_decryption_test_case_3),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_decryption_test_case_4),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_decryption_test_case_5),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_generate_test_case_1),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_generate_test_case_2),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_generate_test_case_3),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_verify_test_case_1),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_verify_test_case_2),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_verify_test_case_3),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_authenticated_encryption_test_case_1),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encrypted_authentication_test_case_1),
+
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
 static int
 test_cryptodev_qat(void /*argv __rte_unused, int argc __rte_unused*/)
 {
@@ -3098,5 +3162,19 @@ static struct test_command cryptodev_aesni_mb_cmd = {
 	.callback = test_cryptodev_aesni_mb,
 };
 
+static int
+test_cryptodev_sw_snow3g(void /*argv __rte_unused, int argc __rte_unused*/)
+{
+	gbl_cryptodev_type = RTE_CRYPTODEV_SNOW3G_PMD;
+
+	return unit_test_suite_runner(&cryptodev_sw_snow3g_testsuite);
+}
+
+static struct test_command cryptodev_sw_snow3g_cmd = {
+	.command = "cryptodev_sw_snow3g_autotest",
+	.callback = test_cryptodev_sw_snow3g,
+};
+
 REGISTER_TEST_COMMAND(cryptodev_qat_cmd);
 REGISTER_TEST_COMMAND(cryptodev_aesni_mb_cmd);
+REGISTER_TEST_COMMAND(cryptodev_sw_snow3g_cmd);
diff --git a/config/common_base b/config/common_base
index 3066e9a..4202a89 100644
--- a/config/common_base
+++ b/config/common_base
@@ -337,6 +337,12 @@ CONFIG_RTE_AESNI_MB_PMD_MAX_NB_QUEUE_PAIRS=8
 CONFIG_RTE_AESNI_MB_PMD_MAX_NB_SESSIONS=2048
 
 #
+# Compile PMD for SNOW 3G device
+#
+CONFIG_RTE_LIBRTE_PMD_SNOW3G=n
+CONFIG_RTE_LIBRTE_PMD_SNOW3G_DEBUG=n
+
+#
 # Compile librte_ring
 #
 CONFIG_RTE_LIBRTE_RING=y
diff --git a/doc/guides/cryptodevs/index.rst b/doc/guides/cryptodevs/index.rst
index 16a5f4a..071e7d2 100644
--- a/doc/guides/cryptodevs/index.rst
+++ b/doc/guides/cryptodevs/index.rst
@@ -36,4 +36,5 @@ Crypto Device Drivers
     :numbered:
 
     aesni_mb
+    snow3g
     qat
diff --git a/doc/guides/cryptodevs/snow3g.rst b/doc/guides/cryptodevs/snow3g.rst
new file mode 100644
index 0000000..9e81eeb
--- /dev/null
+++ b/doc/guides/cryptodevs/snow3g.rst
@@ -0,0 +1,69 @@
+..  BSD LICENSE
+    Copyright(c) 2016 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.
+
+SNOW 3G Crypto Poll Mode Driver
+==============================
+
+The SNOW 3G PMD (**librte_pmd_snow3g**) provides poll mode crypto driver
+support for utilizing Intel Libsso library, which implements F8 and F9 functions
+for SNOW 3G UEA2 cipher and UIA2 hash algorithms.
+
+Features
+--------
+
+SNOW 3G PMD has support for:
+
+Cipher algorithm:
+
+* RTE_CRYPTO_SYM_CIPHER_SNOW3G_UEA2
+
+Hash algorithm:
+
+* RTE_CRYPTO_SYM_HASH_SNOW3G_UIA2
+
+Limitations
+-----------
+
+* Chained mbufs are not supported.
+
+Installation
+------------
+
+To build DPDK with the SNOW3G_PMD the user is required to get
+the export controlled libsso library, sending a request to
+`DPDKUser_software_access@intel.com`, and compile it
+on their user system before building DPDK:
+
+.. code-block:: console
+
+	make -f Makefile_snow3g
+
+The environmental variable LIBSSO_PATH must be exported with the path
+where you extracted and built the libsso library and finally set
+CONFIG_RTE_LIBRTE_SNOW3G=y in config/common_linuxapp.
diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst
index ab446ff..d7a264a 100644
--- a/doc/guides/rel_notes/release_16_04.rst
+++ b/doc/guides/rel_notes/release_16_04.rst
@@ -63,6 +63,10 @@ This section should contain new features added in this release. Sample format:
 
 * **Added vhost-user live migration support.**
 
+* **Added SNOW3G SW PMD**
+
+  A new Crypto PMD has been added, which provides SNOW 3G UEA2 ciphering
+  and SNOW3G UIA2 hashing.
 
 Resolved Issues
 ---------------
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index d0258da..bf586d9 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -33,5 +33,6 @@ include $(RTE_SDK)/mk/rte.vars.mk
 
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_AESNI_MB) += aesni_mb
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_QAT) += qat
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += snow3g
 
 include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/drivers/crypto/snow3g/Makefile b/drivers/crypto/snow3g/Makefile
new file mode 100644
index 0000000..ee58270
--- /dev/null
+++ b/drivers/crypto/snow3g/Makefile
@@ -0,0 +1,64 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 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 ($(LIBSSO_PATH),)
+$(error "Please define LIBSSO_PATH environment variable")
+endif
+
+# library name
+LIB = librte_pmd_snow3g.a
+
+# build flags
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+# library version
+LIBABIVER := 1
+
+# versioning export map
+EXPORT_MAP := rte_pmd_snow3g_version.map
+
+# external library include paths
+CFLAGS += -I$(LIBSSO_PATH)
+CFLAGS += -I$(LIBSSO_PATH)/include
+CFLAGS += -I$(LIBSSO_PATH)/build
+
+# library source files
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += rte_snow3g_pmd.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += rte_snow3g_pmd_ops.c
+
+# library dependencies
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += lib/librte_cryptodev
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/crypto/snow3g/rte_pmd_snow3g_version.map b/drivers/crypto/snow3g/rte_pmd_snow3g_version.map
new file mode 100644
index 0000000..dc4d417
--- /dev/null
+++ b/drivers/crypto/snow3g/rte_pmd_snow3g_version.map
@@ -0,0 +1,3 @@
+DPDK_16.04 {
+	local: *;
+};
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd.c b/drivers/crypto/snow3g/rte_snow3g_pmd.c
new file mode 100644
index 0000000..c35e66e
--- /dev/null
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd.c
@@ -0,0 +1,531 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_kvargs.h>
+
+#include "rte_snow3g_pmd_private.h"
+
+#define SNOW3G_MAX_BURST 8
+
+/**
+ * Global static parameter used to create a unique name for each SNOW 3G
+ * 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_SNOW3G_PMD,
+			unique_name_id++);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+/** Get xform chain order. */
+static enum snow3g_operation
+snow3g_get_mode(const struct rte_crypto_sym_xform *xform)
+{
+	if (xform == NULL)
+		return SNOW3G_OP_NOT_SUPPORTED;
+
+	if (xform->next)
+		if (xform->next->next != NULL)
+			return SNOW3G_OP_NOT_SUPPORTED;
+
+	if (xform->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
+		if (xform->next == NULL)
+			return SNOW3G_OP_ONLY_AUTH;
+		else if (xform->next->type == RTE_CRYPTO_SYM_XFORM_CIPHER)
+			return SNOW3G_OP_AUTH_CIPHER;
+		else
+			return SNOW3G_OP_NOT_SUPPORTED;
+	}
+
+	if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		if (xform->next == NULL)
+			return SNOW3G_OP_ONLY_CIPHER;
+		else if (xform->next->type == RTE_CRYPTO_SYM_XFORM_AUTH)
+			return SNOW3G_OP_CIPHER_AUTH;
+		else
+			return SNOW3G_OP_NOT_SUPPORTED;
+	}
+
+	return SNOW3G_OP_NOT_SUPPORTED;
+}
+
+
+/** Parse crypto xform chain and set private session parameters. */
+int
+snow3g_set_session_parameters(struct snow3g_session *sess,
+		const struct rte_crypto_sym_xform *xform)
+{
+	const struct rte_crypto_sym_xform *auth_xform = NULL;
+	const struct rte_crypto_sym_xform *cipher_xform = NULL;
+	int mode;
+
+	/* Select Crypto operation - hash then cipher / cipher then hash */
+	mode = snow3g_get_mode(xform);
+
+	switch (mode) {
+	case SNOW3G_OP_CIPHER_AUTH:
+		auth_xform = xform->next;
+
+		/* Fall-through */
+	case SNOW3G_OP_ONLY_CIPHER:
+		cipher_xform = xform;
+		break;
+	case SNOW3G_OP_AUTH_CIPHER:
+		cipher_xform = xform->next;
+		/* Fall-through */
+	case SNOW3G_OP_ONLY_AUTH:
+		auth_xform = xform;
+	}
+
+	if (mode == SNOW3G_OP_NOT_SUPPORTED) {
+		SNOW3G_LOG_ERR("Unsupported operation chain order parameter");
+		return -EINVAL;
+	}
+
+	if (cipher_xform) {
+		/* Only SNOW 3G UEA2 supported */
+		if (cipher_xform->cipher.algo != RTE_CRYPTO_CIPHER_SNOW3G_UEA2)
+			return -EINVAL;
+		/* Initialize key */
+		sso_snow3g_init_key_sched(xform->cipher.key.data,
+				&sess->pKeySched_cipher);
+	}
+
+	if (auth_xform) {
+		/* Only SNOW 3G UIA2 supported */
+		if (auth_xform->auth.algo != RTE_CRYPTO_AUTH_SNOW3G_UIA2)
+			return -EINVAL;
+		sess->auth_op = auth_xform->auth.op;
+		/* Initialize key */
+		sso_snow3g_init_key_sched(xform->auth.key.data,
+				&sess->pKeySched_hash);
+	}
+
+
+	sess->op = mode;
+
+	return 0;
+}
+
+/** Get SNOW 3G session. */
+static struct snow3g_session *
+snow3g_get_session(struct snow3g_qp *qp, struct rte_crypto_op *op)
+{
+	struct snow3g_session *sess;
+
+	if (op->sym->type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
+		if (unlikely(op->sym->session->type !=
+				RTE_CRYPTODEV_SNOW3G_PMD))
+			return NULL;
+
+		sess = (struct snow3g_session *)op->sym->session->_private;
+	} else  {
+		struct rte_cryptodev_session *c_sess = NULL;
+
+		if (rte_mempool_get(qp->sess_mp, (void **)&c_sess))
+			return NULL;
+
+		sess = (struct snow3g_session *)c_sess->_private;
+
+		if (unlikely(snow3g_set_session_parameters(sess,
+				op->sym->xform) != 0))
+			return NULL;
+	}
+
+	return sess;
+}
+
+/** Encrypt/decrypt mbufs with same cipher key. */
+static uint8_t
+process_snow3g_cipher_op(struct rte_crypto_op **ops,
+		struct snow3g_session *session,
+		uint8_t num_ops)
+{
+	unsigned i;
+	uint8_t processed_ops = 0;
+	uint8_t *src[SNOW3G_MAX_BURST], *dst[SNOW3G_MAX_BURST];
+	uint8_t *IV[SNOW3G_MAX_BURST];
+	uint32_t num_bytes[SNOW3G_MAX_BURST];
+
+	for (i = 0; i < num_ops; i++) {
+		/* Sanity checks. */
+		if (ops[i]->sym->cipher.iv.length != 16) {
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+			SNOW3G_LOG_ERR("iv");
+			break;
+		}
+
+		src[i] = rte_pktmbuf_mtod(ops[i]->sym->m_src, uint8_t *) +
+				ops[i]->sym->cipher.data.offset;
+		dst[i] = ops[i]->sym->m_dst ?
+				rte_pktmbuf_mtod(ops[i]->sym->m_dst, uint8_t *) +
+					ops[i]->sym->cipher.data.offset :
+				rte_pktmbuf_mtod(ops[i]->sym->m_src, uint8_t *) +
+					ops[i]->sym->cipher.data.offset;
+		IV[i] = ops[i]->sym->cipher.iv.data;
+		num_bytes[i] = ops[i]->sym->cipher.data.length;
+
+		processed_ops++;
+	}
+
+	sso_snow3g_f8_n_buffer(&session->pKeySched_cipher, IV, src, dst,
+			num_bytes, processed_ops);
+
+	return processed_ops;
+}
+
+/** Generate/verify hash from mbufs with same hash key. */
+static int
+process_snow3g_hash_op(struct rte_crypto_op **ops,
+		struct snow3g_session *session,
+		uint8_t num_ops)
+{
+	unsigned i;
+	uint8_t processed_ops = 0;
+	uint8_t *src, *dst;
+	uint32_t length_in_bits;
+
+	for (i = 0; i < num_ops; i++) {
+		if (ops[i]->sym->auth.aad.length != 16) {
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+			SNOW3G_LOG_ERR("aad");
+			break;
+		}
+
+		if (ops[i]->sym->auth.digest.length != 4) {
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+			SNOW3G_LOG_ERR("digest");
+			break;
+		}
+
+		length_in_bits = ops[i]->sym->auth.data.length * 8;
+
+		src = rte_pktmbuf_mtod(ops[i]->sym->m_src, uint8_t *) +
+				ops[i]->sym->auth.data.offset;
+
+		if (session->auth_op == RTE_CRYPTO_AUTH_OP_VERIFY) {
+			dst = (uint8_t *)rte_pktmbuf_append(ops[i]->sym->m_src,
+					ops[i]->sym->auth.digest.length);
+
+			sso_snow3g_f9_1_buffer(&session->pKeySched_hash,
+					ops[i]->sym->auth.aad.data, src,
+					length_in_bits,	dst);
+			/* Verify digest. */
+			if (memcmp(dst, ops[i]->sym->auth.digest.data,
+					ops[i]->sym->auth.digest.length) != 0)
+				ops[i]->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
+
+			/* Trim area used for digest from mbuf. */
+			rte_pktmbuf_trim(ops[i]->sym->m_src,
+					ops[i]->sym->auth.digest.length);
+		} else  {
+			dst = ops[i]->sym->auth.digest.data;
+
+			sso_snow3g_f9_1_buffer(&session->pKeySched_hash,
+					ops[i]->sym->auth.aad.data, src,
+					length_in_bits, dst);
+		}
+		processed_ops++;
+	}
+
+	return processed_ops;
+}
+
+/** Process a batch of crypto ops which shares the same session. */
+static int
+process_ops(struct rte_crypto_op **ops, struct snow3g_session *session,
+		struct snow3g_qp *qp, uint8_t num_ops)
+{
+	unsigned i;
+	unsigned processed_ops;
+
+	switch (session->op) {
+	case SNOW3G_OP_ONLY_CIPHER:
+		processed_ops = process_snow3g_cipher_op(ops,
+				session, num_ops);
+		break;
+	case SNOW3G_OP_ONLY_AUTH:
+		processed_ops = process_snow3g_hash_op(ops, session,
+				num_ops);
+		break;
+	case SNOW3G_OP_CIPHER_AUTH:
+		processed_ops = process_snow3g_cipher_op(ops, session,
+				num_ops);
+		process_snow3g_hash_op(ops, session, processed_ops);
+		break;
+	case SNOW3G_OP_AUTH_CIPHER:
+		processed_ops = process_snow3g_hash_op(ops, session,
+				num_ops);
+		process_snow3g_cipher_op(ops, session, processed_ops);
+		break;
+	default:
+		/* Operation not supported. */
+		processed_ops = 0;
+	}
+
+	for (i = 0; i < num_ops; i++) {
+		/*
+		 * If there was no error/authentication failure,
+		 * change status to successful.
+		 */
+		if (ops[i]->status == RTE_CRYPTO_OP_STATUS_NOT_PROCESSED)
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
+		/* Free session if a session-less crypto op. */
+		if (ops[i]->sym->type == RTE_CRYPTO_SYM_OP_SESSIONLESS) {
+			rte_mempool_put(qp->sess_mp, ops[i]->sym->session);
+			ops[i]->sym->session = NULL;
+		}
+	}
+
+	return processed_ops;
+}
+
+static uint16_t
+snow3g_pmd_enqueue_burst(void *queue_pair, struct rte_crypto_op **ops,
+		uint16_t nb_ops)
+{
+	struct rte_crypto_op *c_ops[SNOW3G_MAX_BURST];
+	struct rte_crypto_op *curr_c_op;
+
+	struct snow3g_session *prev_sess = NULL, *curr_sess = NULL;
+	struct snow3g_qp *qp = queue_pair;
+	unsigned i, n;
+	uint8_t burst_size = 0;
+	uint16_t enqueued_ops = 0;
+	uint8_t processed_ops;
+
+	for (i = 0; i < nb_ops; i++) {
+		curr_c_op = ops[i];
+
+		/* Set status as enqueued (not processed yet) by default. */
+		curr_c_op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
+
+		curr_sess = snow3g_get_session(qp, curr_c_op);
+		if (unlikely(curr_sess == NULL ||
+				curr_sess->op == SNOW3G_OP_NOT_SUPPORTED)) {
+			curr_c_op->status =
+					RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
+			qp->qp_stats.enqueue_err_count += nb_ops - enqueued_ops;
+			return enqueued_ops;
+		}
+
+		/* Batch ops that share the same session. */
+		if (prev_sess == NULL) {
+			prev_sess = curr_sess;
+			c_ops[burst_size++] = curr_c_op;
+		} else if (curr_sess == prev_sess) {
+			c_ops[burst_size++] = curr_c_op;
+			/*
+			 * When there are enough ops to process in a batch,
+			 * process them, and start a new batch.
+			 */
+			if (burst_size == SNOW3G_MAX_BURST) {
+				processed_ops = process_ops(c_ops,
+						prev_sess, qp, burst_size);
+				n = rte_ring_enqueue_burst(qp->processed_ops,
+						(void **)c_ops,
+						processed_ops);
+				qp->qp_stats.enqueued_count += n;
+				enqueued_ops += n;
+				if (n < burst_size) {
+					qp->qp_stats.enqueue_err_count +=
+							nb_ops - enqueued_ops;
+					return enqueued_ops;
+				}
+				burst_size = 0;
+
+				prev_sess = NULL;
+			}
+		} else {
+			/*
+			 * Different session, process the ops
+			 * of the previous session.
+			 */
+			processed_ops = process_ops(c_ops,
+					prev_sess, qp, burst_size);
+			n = rte_ring_enqueue_burst(qp->processed_ops,
+					(void **)c_ops,
+					processed_ops);
+			qp->qp_stats.enqueued_count += n;
+			enqueued_ops += n;
+			if (n < burst_size) {
+				qp->qp_stats.enqueue_err_count +=
+						nb_ops - enqueued_ops;
+				return enqueued_ops;
+			}
+			burst_size = 0;
+
+			prev_sess = curr_sess;
+			c_ops[burst_size++] = curr_c_op;
+		}
+	}
+
+	if (burst_size != 0) {
+		/* Process the crypto ops of the last session. */
+		processed_ops = process_ops(c_ops,
+				prev_sess, qp, burst_size);
+		n = rte_ring_enqueue_burst(qp->processed_ops,
+				(void **)c_ops,
+				processed_ops);
+		qp->qp_stats.enqueued_count += n;
+		enqueued_ops += n;
+		if (n < burst_size) {
+			qp->qp_stats.enqueue_err_count +=
+					nb_ops - enqueued_ops;
+			return enqueued_ops;
+		}
+	}
+
+	return enqueued_ops;
+}
+
+static uint16_t
+snow3g_pmd_dequeue_burst(void *queue_pair,
+		struct rte_crypto_op **c_ops, uint16_t nb_ops)
+{
+	struct snow3g_qp *qp = queue_pair;
+
+	unsigned nb_dequeued;
+
+	nb_dequeued = rte_ring_dequeue_burst(qp->processed_ops,
+			(void **)c_ops, nb_ops);
+	qp->qp_stats.dequeued_count += nb_dequeued;
+
+	return nb_dequeued;
+}
+
+static int cryptodev_snow3g_uninit(const char *name);
+
+static int
+cryptodev_snow3g_create(const char *name,
+		struct rte_crypto_vdev_init_params *init_params)
+{
+	struct rte_cryptodev *dev;
+	char crypto_dev_name[RTE_CRYPTODEV_NAME_MAX_LEN];
+	struct snow3g_private *internals;
+
+	/* Create a unique device name. */
+	if (create_unique_device_name(crypto_dev_name,
+			RTE_CRYPTODEV_NAME_MAX_LEN) != 0) {
+		SNOW3G_LOG_ERR("failed to create unique cryptodev name");
+		return -EINVAL;
+	}
+
+	dev = rte_cryptodev_pmd_virtual_dev_init(crypto_dev_name,
+			sizeof(struct snow3g_private), init_params->socket_id);
+	if (dev == NULL) {
+		SNOW3G_LOG_ERR("failed to create cryptodev vdev");
+		goto init_error;
+	}
+
+	dev->dev_type = RTE_CRYPTODEV_SNOW3G_PMD;
+	dev->dev_ops = rte_snow3g_pmd_ops;
+
+	/* Register RX/TX burst functions for data path. */
+	dev->dequeue_burst = snow3g_pmd_dequeue_burst;
+	dev->enqueue_burst = snow3g_pmd_enqueue_burst;
+
+	internals = dev->data->dev_private;
+
+	internals->max_nb_queue_pairs = init_params->max_nb_queue_pairs;
+	internals->max_nb_sessions = init_params->max_nb_sessions;
+
+	return 0;
+init_error:
+	SNOW3G_LOG_ERR("driver %s: cryptodev_snow3g_create failed", name);
+
+	cryptodev_snow3g_uninit(crypto_dev_name);
+	return -EFAULT;
+}
+
+static int
+cryptodev_snow3g_init(const char *name,
+		const char *input_args)
+{
+	struct rte_crypto_vdev_init_params init_params = {
+		RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_QUEUE_PAIRS,
+		RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_SESSIONS,
+		rte_socket_id()
+	};
+
+	rte_cryptodev_parse_vdev_init_params(&init_params, input_args);
+
+	RTE_LOG(INFO, PMD, "Initialising %s on NUMA node %d\n", name,
+			init_params.socket_id);
+	RTE_LOG(INFO, PMD, "  Max number of queue pairs = %d\n",
+			init_params.max_nb_queue_pairs);
+	RTE_LOG(INFO, PMD, "  Max number of sessions = %d\n",
+			init_params.max_nb_sessions);
+
+	return cryptodev_snow3g_create(name, &init_params);
+}
+
+static int
+cryptodev_snow3g_uninit(const char *name)
+{
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Closing SNOW3G crypto device %s"
+			" on numa socket %u\n",
+			name, rte_socket_id());
+
+	return 0;
+}
+
+static struct rte_driver cryptodev_snow3g_pmd_drv = {
+	.name = CRYPTODEV_NAME_SNOW3G_PMD,
+	.type = PMD_VDEV,
+	.init = cryptodev_snow3g_init,
+	.uninit = cryptodev_snow3g_uninit
+};
+
+PMD_REGISTER_DRIVER(cryptodev_snow3g_pmd_drv);
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
new file mode 100644
index 0000000..5643323
--- /dev/null
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
@@ -0,0 +1,291 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_snow3g_pmd_private.h"
+
+/** Configure device */
+static int
+snow3g_pmd_config(__rte_unused struct rte_cryptodev *dev)
+{
+	return 0;
+}
+
+/** Start device */
+static int
+snow3g_pmd_start(__rte_unused struct rte_cryptodev *dev)
+{
+	return 0;
+}
+
+/** Stop device */
+static void
+snow3g_pmd_stop(__rte_unused struct rte_cryptodev *dev)
+{
+}
+
+/** Close device */
+static int
+snow3g_pmd_close(__rte_unused struct rte_cryptodev *dev)
+{
+	return 0;
+}
+
+
+/** Get device statistics */
+static void
+snow3g_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 snow3g_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
+snow3g_pmd_stats_reset(struct rte_cryptodev *dev)
+{
+	int qp_id;
+
+	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {
+		struct snow3g_qp *qp = dev->data->queue_pairs[qp_id];
+
+		memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
+	}
+}
+
+
+/** Get device info */
+static void
+snow3g_pmd_info_get(struct rte_cryptodev *dev,
+		struct rte_cryptodev_info *dev_info)
+{
+	struct snow3g_private *internals = dev->data->dev_private;
+
+	if (dev_info != NULL) {
+		dev_info->dev_type = dev->dev_type;
+		dev_info->max_nb_queue_pairs = internals->max_nb_queue_pairs;
+		dev_info->sym.max_nb_sessions = internals->max_nb_sessions;
+	}
+}
+
+/** Release queue pair */
+static int
+snow3g_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 its name, dev_id and qp_id */
+static int
+snow3g_pmd_qp_set_unique_name(struct rte_cryptodev *dev,
+		struct snow3g_qp *qp)
+{
+	unsigned n = snprintf(qp->name, sizeof(qp->name),
+			"snow3g_pmd_%u_qp_%u",
+			dev->data->dev_id, qp->id);
+
+	if (n > sizeof(qp->name))
+		return -1;
+
+	return 0;
+}
+
+/** Create a ring to place processed ops on */
+static struct rte_ring *
+snow3g_pmd_qp_create_processed_ops_ring(struct snow3g_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) {
+			SNOW3G_LOG_INFO("Reusing existing ring %s"
+					" for processed packets",
+					 qp->name);
+			return r;
+		}
+
+		SNOW3G_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
+snow3g_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
+		const struct rte_cryptodev_qp_conf *qp_conf,
+		 int socket_id)
+{
+	struct snow3g_qp *qp = NULL;
+
+	/* Free memory prior to re-allocation if needed. */
+	if (dev->data->queue_pairs[qp_id] != NULL)
+		snow3g_pmd_qp_release(dev, qp_id);
+
+	/* Allocate the queue pair data structure. */
+	qp = rte_zmalloc_socket("SNOW3G 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 (snow3g_pmd_qp_set_unique_name(dev, qp))
+		goto qp_setup_cleanup;
+
+	qp->processed_ops = snow3g_pmd_qp_create_processed_ops_ring(qp,
+			qp_conf->nb_descriptors, socket_id);
+	if (qp->processed_ops == NULL)
+		goto qp_setup_cleanup;
+
+	qp->sess_mp = dev->data->session_pool;
+
+	memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
+
+	return 0;
+
+qp_setup_cleanup:
+	if (qp)
+		rte_free(qp);
+
+	return -1;
+}
+
+/** Start queue pair */
+static int
+snow3g_pmd_qp_start(__rte_unused struct rte_cryptodev *dev,
+		__rte_unused uint16_t queue_pair_id)
+{
+	return -ENOTSUP;
+}
+
+/** Stop queue pair */
+static int
+snow3g_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
+snow3g_pmd_qp_count(struct rte_cryptodev *dev)
+{
+	return dev->data->nb_queue_pairs;
+}
+
+/** Returns the size of the SNOW 3G session structure */
+static unsigned
+snow3g_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
+{
+	return sizeof(struct snow3g_session);
+}
+
+/** Configure a SNOW 3G session from a crypto xform chain */
+static void *
+snow3g_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
+		struct rte_crypto_sym_xform *xform,	void *sess)
+{
+	if (unlikely(sess == NULL)) {
+		SNOW3G_LOG_ERR("invalid session struct");
+		return NULL;
+	}
+
+	if (snow3g_set_session_parameters(sess, xform) != 0) {
+		SNOW3G_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
+snow3g_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 snow3g_session));
+}
+
+struct rte_cryptodev_ops snow3g_pmd_ops = {
+		.dev_configure      = snow3g_pmd_config,
+		.dev_start          = snow3g_pmd_start,
+		.dev_stop           = snow3g_pmd_stop,
+		.dev_close          = snow3g_pmd_close,
+
+		.stats_get          = snow3g_pmd_stats_get,
+		.stats_reset        = snow3g_pmd_stats_reset,
+
+		.dev_infos_get      = snow3g_pmd_info_get,
+
+		.queue_pair_setup   = snow3g_pmd_qp_setup,
+		.queue_pair_release = snow3g_pmd_qp_release,
+		.queue_pair_start   = snow3g_pmd_qp_start,
+		.queue_pair_stop    = snow3g_pmd_qp_stop,
+		.queue_pair_count   = snow3g_pmd_qp_count,
+
+		.session_get_size   = snow3g_pmd_session_get_size,
+		.session_configure  = snow3g_pmd_session_configure,
+		.session_clear      = snow3g_pmd_session_clear
+};
+
+struct rte_cryptodev_ops *rte_snow3g_pmd_ops = &snow3g_pmd_ops;
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd_private.h b/drivers/crypto/snow3g/rte_snow3g_pmd_private.h
new file mode 100644
index 0000000..b383cbc
--- /dev/null
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd_private.h
@@ -0,0 +1,107 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_SNOW3G_PMD_PRIVATE_H_
+#define _RTE_SNOW3G_PMD_PRIVATE_H_
+
+#include <sso_snow3g.h>
+
+#define SNOW3G_LOG_ERR(fmt, args...) \
+	RTE_LOG(ERR, CRYPTODEV, "[%s] %s() line %u: " fmt "\n",  \
+			CRYPTODEV_NAME_SNOW3G_PMD, \
+			__func__, __LINE__, ## args)
+
+#ifdef RTE_LIBRTE_SNOW3G_DEBUG
+#define SNOW3G_LOG_INFO(fmt, args...) \
+	RTE_LOG(INFO, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+			CRYPTODEV_NAME_SNOW3G_PMD, \
+			__func__, __LINE__, ## args)
+
+#define SNOW3G_LOG_DBG(fmt, args...) \
+	RTE_LOG(DEBUG, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+			CRYPTODEV_NAME_SNOW3G_PMD, \
+			__func__, __LINE__, ## args)
+#else
+#define SNOW3G_LOG_INFO(fmt, args...)
+#define SNOW3G_LOG_DBG(fmt, args...)
+#endif
+
+/** private data structure for each virtual SNOW 3G device */
+struct snow3g_private {
+	unsigned max_nb_queue_pairs;
+	/**< Max number of queue pairs supported by device */
+	unsigned max_nb_sessions;
+	/**< Max number of sessions supported by device */
+};
+
+/** SNOW 3G buffer queue pair */
+struct snow3g_qp {
+	uint16_t id;
+	/**< Queue Pair Identifier */
+	char name[RTE_CRYPTODEV_NAME_LEN];
+	/**< Unique Queue Pair Name */
+	struct rte_ring *processed_ops;
+	/**< Ring for placing processed ops */
+	struct rte_mempool *sess_mp;
+	/**< Session Mempool */
+	struct rte_cryptodev_stats qp_stats;
+	/**< Queue pair statistics */
+} __rte_cache_aligned;
+
+enum snow3g_operation {
+	SNOW3G_OP_ONLY_CIPHER,
+	SNOW3G_OP_ONLY_AUTH,
+	SNOW3G_OP_CIPHER_AUTH,
+	SNOW3G_OP_AUTH_CIPHER,
+	SNOW3G_OP_NOT_SUPPORTED
+};
+
+/** SNOW 3G private session structure */
+struct snow3g_session {
+	enum snow3g_operation op;
+	enum rte_crypto_auth_operation auth_op;
+	sso_snow3g_key_schedule_t pKeySched_cipher;
+	sso_snow3g_key_schedule_t pKeySched_hash;
+} __rte_cache_aligned;
+
+
+extern int
+snow3g_set_session_parameters(struct snow3g_session *sess,
+		const struct rte_crypto_sym_xform *xform);
+
+
+/** device specific operations function pointer structure */
+extern struct rte_cryptodev_ops *rte_snow3g_pmd_ops;
+
+
+
+#endif /* _RTE_SNOW3G_PMD_PRIVATE_H_ */
diff --git a/lib/librte_cryptodev/Makefile b/lib/librte_cryptodev/Makefile
index 0d59229..314a046 100644
--- a/lib/librte_cryptodev/Makefile
+++ b/lib/librte_cryptodev/Makefile
@@ -57,5 +57,6 @@ DEPDIRS-y += lib/librte_eal
 DEPDIRS-y += lib/librte_mempool
 DEPDIRS-y += lib/librte_ring
 DEPDIRS-y += lib/librte_mbuf
+DEPDIRS-y += lib/librte_kvargs
 
-include $(RTE_SDK)/mk/rte.lib.mk
\ No newline at end of file
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index aab8cff..f279c92 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -48,6 +48,7 @@
 extern "C" {
 #endif
 
+#include "rte_kvargs.h"
 #include "rte_crypto.h"
 #include "rte_dev.h"
 
@@ -57,15 +58,17 @@ extern "C" {
 /**< AES-NI Multi buffer PMD device name */
 #define CRYPTODEV_NAME_QAT_SYM_PMD	("cryptodev_qat_sym_pmd")
 /**< Intel QAT Symmetric Crypto PMD device name */
+#define CRYPTODEV_NAME_SNOW3G_PMD	("cryptodev_snow3g_pmd")
+/**< SNOW 3G PMD device name */
 
 /** Crypto device type */
 enum rte_cryptodev_type {
 	RTE_CRYPTODEV_NULL_PMD = 1,	/**< Null crypto PMD */
 	RTE_CRYPTODEV_AESNI_MB_PMD,	/**< AES-NI multi buffer PMD */
 	RTE_CRYPTODEV_QAT_SYM_PMD,	/**< QAT PMD Symmetric Crypto */
+	RTE_CRYPTODEV_SNOW3G_PMD,	/**< SNOW 3G PMD */
 };
 
-
 extern const char **rte_cyptodev_names;
 
 /* Logging Macros */
@@ -148,6 +151,121 @@ struct rte_cryptodev_stats {
 	/**< Total error count on operations dequeued */
 };
 
+#define RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_QUEUE_PAIRS	8
+#define RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_SESSIONS	2048
+
+/**
+ * @internal
+ * Initialisation parameters for virtual crypto devices
+ */
+struct rte_crypto_vdev_init_params {
+	unsigned max_nb_queue_pairs;
+	unsigned max_nb_sessions;
+	uint8_t socket_id;
+};
+
+#define RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG		("max_nb_queue_pairs")
+#define RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG		("max_nb_sessions")
+#define RTE_CRYPTODEV_VDEV_SOCKET_ID			("socket_id")
+
+static const char *cryptodev_vdev_valid_params[] = {
+	RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
+	RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG,
+	RTE_CRYPTODEV_VDEV_SOCKET_ID
+};
+
+static inline uint8_t
+number_of_sockets(void)
+{
+	int sockets = 0;
+	int i;
+	const struct rte_memseg *ms = rte_eal_get_physmem_layout();
+
+	for (i = 0; ((i < RTE_MAX_MEMSEG) && (ms[i].addr != NULL)); i++) {
+		if (sockets < ms[i].socket_id)
+			sockets = ms[i].socket_id;
+	}
+
+	/* Number of sockets = maximum socket_id + 1 */
+	return ++sockets;
+}
+
+/** Parse integer from integer argument */
+static inline int
+__rte_cryptodev_parse_integer_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	int *i = extra_args;
+
+	*i = atoi(value);
+	if (*i < 0) {
+		CDEV_LOG_ERR("Argument has to be positive.");
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse virtual device initialisation parameters input arguments
+ * @internal
+ *
+ * @params	params		Initialisation parameters with defaults set.
+ * @params	input_args	Command line arguments
+ *
+ * @return
+ * 0 on successful parse
+ * <0 on failure to parse
+ */
+static inline int
+rte_cryptodev_parse_vdev_init_params(struct rte_crypto_vdev_init_params *params,
+		const char *input_args)
+{
+	struct rte_kvargs *kvlist;
+	int ret;
+
+	if (params == NULL)
+		return -EINVAL;
+
+	if (input_args) {
+		kvlist = rte_kvargs_parse(input_args,
+				cryptodev_vdev_valid_params);
+		if (kvlist == NULL)
+			return -1;
+
+		ret = rte_kvargs_process(kvlist,
+					RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
+					&__rte_cryptodev_parse_integer_arg,
+					&params->max_nb_queue_pairs);
+		if (ret < 0)
+			goto free_kvlist;
+
+		ret = rte_kvargs_process(kvlist,
+					RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG,
+					&__rte_cryptodev_parse_integer_arg,
+					&params->max_nb_sessions);
+		if (ret < 0)
+			goto free_kvlist;
+
+		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_SOCKET_ID,
+					&__rte_cryptodev_parse_integer_arg,
+					&params->socket_id);
+		if (ret < 0)
+			goto free_kvlist;
+
+		if (params->socket_id >= number_of_sockets()) {
+			CDEV_LOG_ERR("Invalid socket id specified to create "
+				"the virtual crypto device on");
+			goto free_kvlist;
+		}
+	}
+
+	return 0;
+
+free_kvlist:
+	rte_kvargs_free(kvlist);
+	return ret;
+}
 
 /**
  * Create a virtual crypto device
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index daac09f..7e46370 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   Copyright(c) 2014-2015 6WIND S.A.
 #   All rights reserved.
 #
@@ -150,6 +150,10 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_QAT)        += -lrte_pmd_qat
 _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
 
+# SNOW3G PMD is dependent on the LIBSSO library
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G)     += -lrte_pmd_snow3g
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G)     += -L$(LIBSSO_PATH)/build -lsso
+
 endif # ! $(CONFIG_RTE_BUILD_SHARED_LIB)
 
 _LDLIBS-y += $(EXECENV_LDLIBS)
-- 
2.5.0

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [dpdk-dev] [PATCH v2] pmd/snow3g: add new SNOW 3G SW PMD
  2016-03-07 14:07 ` [dpdk-dev] [PATCH v2] " Pablo de Lara
  2016-03-07 19:48   ` [dpdk-dev] [PATCH v3] " Pablo de Lara
@ 2016-03-07 19:48   ` De Lara Guarch, Pablo
  1 sibling, 0 replies; 9+ messages in thread
From: De Lara Guarch, Pablo @ 2016-03-07 19:48 UTC (permalink / raw)
  To: dev



> -----Original Message-----
> From: De Lara Guarch, Pablo
> Sent: Monday, March 07, 2016 2:07 PM
> To: dev@dpdk.org
> Cc: Doherty, Declan; De Lara Guarch, Pablo
> Subject: [PATCH v2] pmd/snow3g: add new SNOW 3G SW PMD
> 
> Added new SW PMD which makes use of the libsso SW library,
> which provides wireless algorithms SNOW 3G UEA2 and UIA2
> in software.
> 
> This PMD supports cipher-only, hash-only and chained operations
> ("cipher then hash" and "hash then cipher") of the following
> algorithms:
> - RTE_CRYPTO_SYM_CIPHER_SNOW3G_UEA2
> - RTE_CRYPTO_SYM_HASH_SNOW3G_UIA2
> 
> The SNOW 3G hash and cipher algorithms, which are enabled
> by this crypto PMD are implemented by Intel's libsso software
> library. For library download and build instructions,
> see the documentation included (doc/guides/cryptodevs/snow3g.rst)
> 
> The patch also contains the related unit tests function to test the PMD
> supported operations.
> 
> Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>

Nack, because of wrong dependency.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [dpdk-dev] [PATCH v3] pmd/snow3g: add new SNOW 3G SW PMD
  2016-03-07 19:48   ` [dpdk-dev] [PATCH v3] " Pablo de Lara
@ 2016-03-08 14:10     ` Jain, Deepak K
  2016-03-10 16:33     ` [dpdk-dev] [PATCH v4] " Pablo de Lara
  1 sibling, 0 replies; 9+ messages in thread
From: Jain, Deepak K @ 2016-03-08 14:10 UTC (permalink / raw)
  To: De Lara Guarch, Pablo, dev



-----Original Message-----
From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Pablo de Lara
Sent: Monday, March 7, 2016 7:48 PM
To: dev@dpdk.org
Subject: [dpdk-dev] [PATCH v3] pmd/snow3g: add new SNOW 3G SW PMD

Added new SW PMD which makes use of the libsso SW library, which provides wireless algorithms SNOW 3G UEA2 and UIA2 in software.

This PMD supports cipher-only, hash-only and chained operations ("cipher then hash" and "hash then cipher") of the following
algorithms:
- RTE_CRYPTO_SYM_CIPHER_SNOW3G_UEA2
- RTE_CRYPTO_SYM_HASH_SNOW3G_UIA2

The SNOW 3G hash and cipher algorithms, which are enabled by this crypto PMD are implemented by Intel's libsso software library. For library download and build instructions, see the documentation included (doc/guides/cryptodevs/snow3g.rst)

The patch also contains the related unit tests function to test the PMD supported operations.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---

This patch depends on "Snow3G support for Intel Quick Assist Devices" patchset (http://dpdk.org/ml/archives/dev/2016-March/034503.html).

Changes in v3:

- Corrected patch dependency

Changes in v2:

- Rebased against crypto API changes
- Removed static config options and allow user to provide them
  as virtual device parameters.
- Added unit tests
- Changed DPDK version references from 2.3 to 16.04
- Fixed crypto operation status handling
- Fixed copyright dates
- Fixed enqueue error stats


 MAINTAINERS                                      |   4 +
 app/test/test_cryptodev.c                        |  78 ++++
 config/common_base                               |   6 +
 doc/guides/cryptodevs/index.rst                  |   1 +
 doc/guides/cryptodevs/snow3g.rst                 |  69 +++
 doc/guides/rel_notes/release_16_04.rst           |   4 +
 drivers/crypto/Makefile                          |   3 +-
 drivers/crypto/snow3g/Makefile                   |  64 +++
 drivers/crypto/snow3g/rte_pmd_snow3g_version.map |   3 +
 drivers/crypto/snow3g/rte_snow3g_pmd.c           | 531 +++++++++++++++++++++++
 drivers/crypto/snow3g/rte_snow3g_pmd_ops.c       | 291 +++++++++++++
 drivers/crypto/snow3g/rte_snow3g_pmd_private.h   | 107 +++++
 lib/librte_cryptodev/Makefile                    |   3 +-
 lib/librte_cryptodev/rte_cryptodev.h             | 120 ++++-
 mk/rte.app.mk                                    |   6 +-
 15 files changed, 1286 insertions(+), 4 deletions(-)  create mode 100644 doc/guides/cryptodevs/snow3g.rst  create mode 100644 drivers/crypto/snow3g/Makefile  create mode 100644 drivers/crypto/snow3g/rte_pmd_snow3g_version.map
 create mode 100644 drivers/crypto/snow3g/rte_snow3g_pmd.c
 create mode 100644 drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
 create mode 100644 drivers/crypto/snow3g/rte_snow3g_pmd_private.h
-- 
2.5.0

Acked-by: Deepak Kumar JAIN <deepak.k.jain@intel.com>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [dpdk-dev] [PATCH v4] pmd/snow3g: add new SNOW 3G SW PMD
  2016-03-07 19:48   ` [dpdk-dev] [PATCH v3] " Pablo de Lara
  2016-03-08 14:10     ` Jain, Deepak K
@ 2016-03-10 16:33     ` Pablo de Lara
  2016-03-10 16:54       ` Jain, Deepak K
  2016-03-10 22:56       ` Thomas Monjalon
  1 sibling, 2 replies; 9+ messages in thread
From: Pablo de Lara @ 2016-03-10 16:33 UTC (permalink / raw)
  To: dev

Added new SW PMD which makes use of the libsso SW library,
which provides wireless algorithms SNOW 3G UEA2 and UIA2
in software.

This PMD supports cipher-only, hash-only and chained operations
("cipher then hash" and "hash then cipher") of the following
algorithms:
- RTE_CRYPTO_SYM_CIPHER_SNOW3G_UEA2
- RTE_CRYPTO_SYM_AUTH_SNOW3G_UIA2

The SNOW 3G hash and cipher algorithms, which are enabled
by this crypto PMD are implemented by Intel's libsso software
library. For library download and build instructions,
see the documentation included (doc/guides/cryptodevs/snow3g.rst)

The patch also contains the related unit tests function to test the PMD
supported operations.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---

This patch depends on "Snow3G support for Intel Quick Assist Devices" patchset
(http://dpdk.org/ml/archives/dev/2016-March/03548.html).

Changes in v4:

- Added missing fix casting that was breaking C++ compilation.
- Fixed documentation
- Rebased against latest DPDK code

Changes in v3:

- Corrected patch dependency

Changes in v2:

- Rebased against crypto API changes
- Removed static config options and allow user to provide them
  as virtual device parameters.
- Added unit tests
- Changed DPDK version references from 2.3 to 16.04
- Fixed crypto operation status handling
- Fixed copyright dates
- Fixed enqueue error stats


 MAINTAINERS                                      |   4 +
 app/test/test_cryptodev.c                        |  78 ++++
 config/common_base                               |   6 +
 doc/guides/cryptodevs/index.rst                  |   1 +
 doc/guides/cryptodevs/snow3g.rst                 |  69 +++
 doc/guides/rel_notes/release_16_04.rst           |   4 +
 drivers/crypto/Makefile                          |   3 +-
 drivers/crypto/snow3g/Makefile                   |  64 +++
 drivers/crypto/snow3g/rte_pmd_snow3g_version.map |   3 +
 drivers/crypto/snow3g/rte_snow3g_pmd.c           | 531 +++++++++++++++++++++++
 drivers/crypto/snow3g/rte_snow3g_pmd_ops.c       | 291 +++++++++++++
 drivers/crypto/snow3g/rte_snow3g_pmd_private.h   | 107 +++++
 lib/librte_cryptodev/Makefile                    |   3 +-
 lib/librte_cryptodev/rte_cryptodev.h             | 120 ++++-
 mk/rte.app.mk                                    |   6 +-
 15 files changed, 1286 insertions(+), 4 deletions(-)
 create mode 100644 doc/guides/cryptodevs/snow3g.rst
 create mode 100644 drivers/crypto/snow3g/Makefile
 create mode 100644 drivers/crypto/snow3g/rte_pmd_snow3g_version.map
 create mode 100644 drivers/crypto/snow3g/rte_snow3g_pmd.c
 create mode 100644 drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
 create mode 100644 drivers/crypto/snow3g/rte_snow3g_pmd_private.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 421c317..52198b7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -356,6 +356,10 @@ F: drivers/crypto/aesni_mb/
 Intel QuickAssist
 F: drivers/crypto/qat/
 
+SNOW 3G PMD
+M: Pablo de Lara <pablo.de.lara.guarch@intel.com>
+F: drivers/crypto/snow3g
+
 
 Packet processing
 -----------------
diff --git a/app/test/test_cryptodev.c b/app/test/test_cryptodev.c
index 0fe47b9..595b9f9 100644
--- a/app/test/test_cryptodev.c
+++ b/app/test/test_cryptodev.c
@@ -195,6 +195,20 @@ testsuite_setup(void)
 		}
 	}
 
+	/* Create 2 Snow3G devices if required */
+	if (gbl_cryptodev_type == RTE_CRYPTODEV_SNOW3G_PMD) {
+		nb_devs = rte_cryptodev_count_devtype(RTE_CRYPTODEV_SNOW3G_PMD);
+		if (nb_devs < 2) {
+			for (i = nb_devs; i < 2; i++) {
+				TEST_ASSERT_SUCCESS(rte_eal_vdev_init(
+					CRYPTODEV_NAME_SNOW3G_PMD, NULL),
+					"Failed to create instance %u of"
+					" pmd : %s",
+					i, CRYPTODEV_NAME_SNOW3G_PMD);
+			}
+		}
+	}
+
 	nb_devs = rte_cryptodev_count();
 	if (nb_devs < 1) {
 		RTE_LOG(ERR, USER1, "No crypto devices found?");
@@ -3061,6 +3075,56 @@ static struct unit_test_suite cryptodev_aesni_mb_testsuite  = {
 	}
 };
 
+static struct unit_test_suite cryptodev_sw_snow3g_testsuite  = {
+	.suite_name = "Crypto Device SW Snow3G Unit Test Suite",
+	.setup = testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		/** Snow3G encrypt only (UEA2) */
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encryption_test_case_1),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encryption_test_case_2),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encryption_test_case_3),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encryption_test_case_4),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encryption_test_case_5),
+
+
+		/** Snow3G decrypt only (UEA2) */
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_decryption_test_case_1),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_decryption_test_case_2),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_decryption_test_case_3),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_decryption_test_case_4),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_decryption_test_case_5),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_generate_test_case_1),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_generate_test_case_2),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_generate_test_case_3),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_verify_test_case_1),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_verify_test_case_2),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_hash_verify_test_case_3),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_authenticated_encryption_test_case_1),
+		TEST_CASE_ST(ut_setup, ut_teardown,
+			test_snow3g_encrypted_authentication_test_case_1),
+
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
 static int
 test_cryptodev_qat(void /*argv __rte_unused, int argc __rte_unused*/)
 {
@@ -3085,5 +3149,19 @@ static struct test_command cryptodev_aesni_mb_cmd = {
 	.callback = test_cryptodev_aesni_mb,
 };
 
+static int
+test_cryptodev_sw_snow3g(void /*argv __rte_unused, int argc __rte_unused*/)
+{
+	gbl_cryptodev_type = RTE_CRYPTODEV_SNOW3G_PMD;
+
+	return unit_test_suite_runner(&cryptodev_sw_snow3g_testsuite);
+}
+
+static struct test_command cryptodev_sw_snow3g_cmd = {
+	.command = "cryptodev_sw_snow3g_autotest",
+	.callback = test_cryptodev_sw_snow3g,
+};
+
 REGISTER_TEST_COMMAND(cryptodev_qat_cmd);
 REGISTER_TEST_COMMAND(cryptodev_aesni_mb_cmd);
+REGISTER_TEST_COMMAND(cryptodev_sw_snow3g_cmd);
diff --git a/config/common_base b/config/common_base
index 0a02924..99f2d31 100644
--- a/config/common_base
+++ b/config/common_base
@@ -338,6 +338,12 @@ CONFIG_RTE_AESNI_MB_PMD_MAX_NB_QUEUE_PAIRS=8
 CONFIG_RTE_AESNI_MB_PMD_MAX_NB_SESSIONS=2048
 
 #
+# Compile PMD for SNOW 3G device
+#
+CONFIG_RTE_LIBRTE_PMD_SNOW3G=n
+CONFIG_RTE_LIBRTE_PMD_SNOW3G_DEBUG=n
+
+#
 # Compile librte_ring
 #
 CONFIG_RTE_LIBRTE_RING=y
diff --git a/doc/guides/cryptodevs/index.rst b/doc/guides/cryptodevs/index.rst
index 16a5f4a..071e7d2 100644
--- a/doc/guides/cryptodevs/index.rst
+++ b/doc/guides/cryptodevs/index.rst
@@ -36,4 +36,5 @@ Crypto Device Drivers
     :numbered:
 
     aesni_mb
+    snow3g
     qat
diff --git a/doc/guides/cryptodevs/snow3g.rst b/doc/guides/cryptodevs/snow3g.rst
new file mode 100644
index 0000000..f04fbaf
--- /dev/null
+++ b/doc/guides/cryptodevs/snow3g.rst
@@ -0,0 +1,69 @@
+..  BSD LICENSE
+    Copyright(c) 2016 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.
+
+SNOW 3G Crypto Poll Mode Driver
+===============================
+
+The SNOW 3G PMD (**librte_pmd_snow3g**) provides poll mode crypto driver
+support for utilizing Intel Libsso library, which implements F8 and F9 functions
+for SNOW 3G UEA2 cipher and UIA2 hash algorithms.
+
+Features
+--------
+
+SNOW 3G PMD has support for:
+
+Cipher algorithm:
+
+* RTE_CRYPTO_SYM_CIPHER_SNOW3G_UEA2
+
+Authentication algorithm:
+
+* RTE_CRYPTO_SYM_AUTH_SNOW3G_UIA2
+
+Limitations
+-----------
+
+* Chained mbufs are not supported.
+
+Installation
+------------
+
+To build DPDK with the SNOW3G_PMD the user is required to get
+the export controlled libsso library, sending a request to
+`DPDKUser_software_access@intel.com`, and compile it
+on their user system before building DPDK:
+
+.. code-block:: console
+
+	make -f Makefile_snow3g
+
+The environmental variable LIBSSO_PATH must be exported with the path
+where you extracted and built the libsso library and finally set
+CONFIG_RTE_LIBRTE_SNOW3G=y in config/common_base.
diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst
index 4f41e63..4fb0738 100644
--- a/doc/guides/rel_notes/release_16_04.rst
+++ b/doc/guides/rel_notes/release_16_04.rst
@@ -80,6 +80,10 @@ This section should contain new features added in this release. Sample format:
 
   The next_hop field is extended from 8 bits to 24 bits for IPv4.
 
+* **Added SNOW3G SW PMD**
+
+  A new Crypto PMD has been added, which provides SNOW 3G UEA2 ciphering
+  and SNOW3G UIA2 hashing.
 
 Resolved Issues
 ---------------
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index d0258da..bf586d9 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   All rights reserved.
 #
 #   Redistribution and use in source and binary forms, with or without
@@ -33,5 +33,6 @@ include $(RTE_SDK)/mk/rte.vars.mk
 
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_AESNI_MB) += aesni_mb
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_QAT) += qat
+DIRS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += snow3g
 
 include $(RTE_SDK)/mk/rte.subdir.mk
diff --git a/drivers/crypto/snow3g/Makefile b/drivers/crypto/snow3g/Makefile
new file mode 100644
index 0000000..ee58270
--- /dev/null
+++ b/drivers/crypto/snow3g/Makefile
@@ -0,0 +1,64 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2016 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 ($(LIBSSO_PATH),)
+$(error "Please define LIBSSO_PATH environment variable")
+endif
+
+# library name
+LIB = librte_pmd_snow3g.a
+
+# build flags
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+# library version
+LIBABIVER := 1
+
+# versioning export map
+EXPORT_MAP := rte_pmd_snow3g_version.map
+
+# external library include paths
+CFLAGS += -I$(LIBSSO_PATH)
+CFLAGS += -I$(LIBSSO_PATH)/include
+CFLAGS += -I$(LIBSSO_PATH)/build
+
+# library source files
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += rte_snow3g_pmd.c
+SRCS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += rte_snow3g_pmd_ops.c
+
+# library dependencies
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += lib/librte_eal
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G) += lib/librte_cryptodev
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/drivers/crypto/snow3g/rte_pmd_snow3g_version.map b/drivers/crypto/snow3g/rte_pmd_snow3g_version.map
new file mode 100644
index 0000000..dc4d417
--- /dev/null
+++ b/drivers/crypto/snow3g/rte_pmd_snow3g_version.map
@@ -0,0 +1,3 @@
+DPDK_16.04 {
+	local: *;
+};
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd.c b/drivers/crypto/snow3g/rte_snow3g_pmd.c
new file mode 100644
index 0000000..c35e66e
--- /dev/null
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd.c
@@ -0,0 +1,531 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_kvargs.h>
+
+#include "rte_snow3g_pmd_private.h"
+
+#define SNOW3G_MAX_BURST 8
+
+/**
+ * Global static parameter used to create a unique name for each SNOW 3G
+ * 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_SNOW3G_PMD,
+			unique_name_id++);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+/** Get xform chain order. */
+static enum snow3g_operation
+snow3g_get_mode(const struct rte_crypto_sym_xform *xform)
+{
+	if (xform == NULL)
+		return SNOW3G_OP_NOT_SUPPORTED;
+
+	if (xform->next)
+		if (xform->next->next != NULL)
+			return SNOW3G_OP_NOT_SUPPORTED;
+
+	if (xform->type == RTE_CRYPTO_SYM_XFORM_AUTH) {
+		if (xform->next == NULL)
+			return SNOW3G_OP_ONLY_AUTH;
+		else if (xform->next->type == RTE_CRYPTO_SYM_XFORM_CIPHER)
+			return SNOW3G_OP_AUTH_CIPHER;
+		else
+			return SNOW3G_OP_NOT_SUPPORTED;
+	}
+
+	if (xform->type == RTE_CRYPTO_SYM_XFORM_CIPHER) {
+		if (xform->next == NULL)
+			return SNOW3G_OP_ONLY_CIPHER;
+		else if (xform->next->type == RTE_CRYPTO_SYM_XFORM_AUTH)
+			return SNOW3G_OP_CIPHER_AUTH;
+		else
+			return SNOW3G_OP_NOT_SUPPORTED;
+	}
+
+	return SNOW3G_OP_NOT_SUPPORTED;
+}
+
+
+/** Parse crypto xform chain and set private session parameters. */
+int
+snow3g_set_session_parameters(struct snow3g_session *sess,
+		const struct rte_crypto_sym_xform *xform)
+{
+	const struct rte_crypto_sym_xform *auth_xform = NULL;
+	const struct rte_crypto_sym_xform *cipher_xform = NULL;
+	int mode;
+
+	/* Select Crypto operation - hash then cipher / cipher then hash */
+	mode = snow3g_get_mode(xform);
+
+	switch (mode) {
+	case SNOW3G_OP_CIPHER_AUTH:
+		auth_xform = xform->next;
+
+		/* Fall-through */
+	case SNOW3G_OP_ONLY_CIPHER:
+		cipher_xform = xform;
+		break;
+	case SNOW3G_OP_AUTH_CIPHER:
+		cipher_xform = xform->next;
+		/* Fall-through */
+	case SNOW3G_OP_ONLY_AUTH:
+		auth_xform = xform;
+	}
+
+	if (mode == SNOW3G_OP_NOT_SUPPORTED) {
+		SNOW3G_LOG_ERR("Unsupported operation chain order parameter");
+		return -EINVAL;
+	}
+
+	if (cipher_xform) {
+		/* Only SNOW 3G UEA2 supported */
+		if (cipher_xform->cipher.algo != RTE_CRYPTO_CIPHER_SNOW3G_UEA2)
+			return -EINVAL;
+		/* Initialize key */
+		sso_snow3g_init_key_sched(xform->cipher.key.data,
+				&sess->pKeySched_cipher);
+	}
+
+	if (auth_xform) {
+		/* Only SNOW 3G UIA2 supported */
+		if (auth_xform->auth.algo != RTE_CRYPTO_AUTH_SNOW3G_UIA2)
+			return -EINVAL;
+		sess->auth_op = auth_xform->auth.op;
+		/* Initialize key */
+		sso_snow3g_init_key_sched(xform->auth.key.data,
+				&sess->pKeySched_hash);
+	}
+
+
+	sess->op = mode;
+
+	return 0;
+}
+
+/** Get SNOW 3G session. */
+static struct snow3g_session *
+snow3g_get_session(struct snow3g_qp *qp, struct rte_crypto_op *op)
+{
+	struct snow3g_session *sess;
+
+	if (op->sym->type == RTE_CRYPTO_SYM_OP_WITH_SESSION) {
+		if (unlikely(op->sym->session->type !=
+				RTE_CRYPTODEV_SNOW3G_PMD))
+			return NULL;
+
+		sess = (struct snow3g_session *)op->sym->session->_private;
+	} else  {
+		struct rte_cryptodev_session *c_sess = NULL;
+
+		if (rte_mempool_get(qp->sess_mp, (void **)&c_sess))
+			return NULL;
+
+		sess = (struct snow3g_session *)c_sess->_private;
+
+		if (unlikely(snow3g_set_session_parameters(sess,
+				op->sym->xform) != 0))
+			return NULL;
+	}
+
+	return sess;
+}
+
+/** Encrypt/decrypt mbufs with same cipher key. */
+static uint8_t
+process_snow3g_cipher_op(struct rte_crypto_op **ops,
+		struct snow3g_session *session,
+		uint8_t num_ops)
+{
+	unsigned i;
+	uint8_t processed_ops = 0;
+	uint8_t *src[SNOW3G_MAX_BURST], *dst[SNOW3G_MAX_BURST];
+	uint8_t *IV[SNOW3G_MAX_BURST];
+	uint32_t num_bytes[SNOW3G_MAX_BURST];
+
+	for (i = 0; i < num_ops; i++) {
+		/* Sanity checks. */
+		if (ops[i]->sym->cipher.iv.length != 16) {
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+			SNOW3G_LOG_ERR("iv");
+			break;
+		}
+
+		src[i] = rte_pktmbuf_mtod(ops[i]->sym->m_src, uint8_t *) +
+				ops[i]->sym->cipher.data.offset;
+		dst[i] = ops[i]->sym->m_dst ?
+				rte_pktmbuf_mtod(ops[i]->sym->m_dst, uint8_t *) +
+					ops[i]->sym->cipher.data.offset :
+				rte_pktmbuf_mtod(ops[i]->sym->m_src, uint8_t *) +
+					ops[i]->sym->cipher.data.offset;
+		IV[i] = ops[i]->sym->cipher.iv.data;
+		num_bytes[i] = ops[i]->sym->cipher.data.length;
+
+		processed_ops++;
+	}
+
+	sso_snow3g_f8_n_buffer(&session->pKeySched_cipher, IV, src, dst,
+			num_bytes, processed_ops);
+
+	return processed_ops;
+}
+
+/** Generate/verify hash from mbufs with same hash key. */
+static int
+process_snow3g_hash_op(struct rte_crypto_op **ops,
+		struct snow3g_session *session,
+		uint8_t num_ops)
+{
+	unsigned i;
+	uint8_t processed_ops = 0;
+	uint8_t *src, *dst;
+	uint32_t length_in_bits;
+
+	for (i = 0; i < num_ops; i++) {
+		if (ops[i]->sym->auth.aad.length != 16) {
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+			SNOW3G_LOG_ERR("aad");
+			break;
+		}
+
+		if (ops[i]->sym->auth.digest.length != 4) {
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_INVALID_ARGS;
+			SNOW3G_LOG_ERR("digest");
+			break;
+		}
+
+		length_in_bits = ops[i]->sym->auth.data.length * 8;
+
+		src = rte_pktmbuf_mtod(ops[i]->sym->m_src, uint8_t *) +
+				ops[i]->sym->auth.data.offset;
+
+		if (session->auth_op == RTE_CRYPTO_AUTH_OP_VERIFY) {
+			dst = (uint8_t *)rte_pktmbuf_append(ops[i]->sym->m_src,
+					ops[i]->sym->auth.digest.length);
+
+			sso_snow3g_f9_1_buffer(&session->pKeySched_hash,
+					ops[i]->sym->auth.aad.data, src,
+					length_in_bits,	dst);
+			/* Verify digest. */
+			if (memcmp(dst, ops[i]->sym->auth.digest.data,
+					ops[i]->sym->auth.digest.length) != 0)
+				ops[i]->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
+
+			/* Trim area used for digest from mbuf. */
+			rte_pktmbuf_trim(ops[i]->sym->m_src,
+					ops[i]->sym->auth.digest.length);
+		} else  {
+			dst = ops[i]->sym->auth.digest.data;
+
+			sso_snow3g_f9_1_buffer(&session->pKeySched_hash,
+					ops[i]->sym->auth.aad.data, src,
+					length_in_bits, dst);
+		}
+		processed_ops++;
+	}
+
+	return processed_ops;
+}
+
+/** Process a batch of crypto ops which shares the same session. */
+static int
+process_ops(struct rte_crypto_op **ops, struct snow3g_session *session,
+		struct snow3g_qp *qp, uint8_t num_ops)
+{
+	unsigned i;
+	unsigned processed_ops;
+
+	switch (session->op) {
+	case SNOW3G_OP_ONLY_CIPHER:
+		processed_ops = process_snow3g_cipher_op(ops,
+				session, num_ops);
+		break;
+	case SNOW3G_OP_ONLY_AUTH:
+		processed_ops = process_snow3g_hash_op(ops, session,
+				num_ops);
+		break;
+	case SNOW3G_OP_CIPHER_AUTH:
+		processed_ops = process_snow3g_cipher_op(ops, session,
+				num_ops);
+		process_snow3g_hash_op(ops, session, processed_ops);
+		break;
+	case SNOW3G_OP_AUTH_CIPHER:
+		processed_ops = process_snow3g_hash_op(ops, session,
+				num_ops);
+		process_snow3g_cipher_op(ops, session, processed_ops);
+		break;
+	default:
+		/* Operation not supported. */
+		processed_ops = 0;
+	}
+
+	for (i = 0; i < num_ops; i++) {
+		/*
+		 * If there was no error/authentication failure,
+		 * change status to successful.
+		 */
+		if (ops[i]->status == RTE_CRYPTO_OP_STATUS_NOT_PROCESSED)
+			ops[i]->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
+		/* Free session if a session-less crypto op. */
+		if (ops[i]->sym->type == RTE_CRYPTO_SYM_OP_SESSIONLESS) {
+			rte_mempool_put(qp->sess_mp, ops[i]->sym->session);
+			ops[i]->sym->session = NULL;
+		}
+	}
+
+	return processed_ops;
+}
+
+static uint16_t
+snow3g_pmd_enqueue_burst(void *queue_pair, struct rte_crypto_op **ops,
+		uint16_t nb_ops)
+{
+	struct rte_crypto_op *c_ops[SNOW3G_MAX_BURST];
+	struct rte_crypto_op *curr_c_op;
+
+	struct snow3g_session *prev_sess = NULL, *curr_sess = NULL;
+	struct snow3g_qp *qp = queue_pair;
+	unsigned i, n;
+	uint8_t burst_size = 0;
+	uint16_t enqueued_ops = 0;
+	uint8_t processed_ops;
+
+	for (i = 0; i < nb_ops; i++) {
+		curr_c_op = ops[i];
+
+		/* Set status as enqueued (not processed yet) by default. */
+		curr_c_op->status = RTE_CRYPTO_OP_STATUS_NOT_PROCESSED;
+
+		curr_sess = snow3g_get_session(qp, curr_c_op);
+		if (unlikely(curr_sess == NULL ||
+				curr_sess->op == SNOW3G_OP_NOT_SUPPORTED)) {
+			curr_c_op->status =
+					RTE_CRYPTO_OP_STATUS_INVALID_SESSION;
+			qp->qp_stats.enqueue_err_count += nb_ops - enqueued_ops;
+			return enqueued_ops;
+		}
+
+		/* Batch ops that share the same session. */
+		if (prev_sess == NULL) {
+			prev_sess = curr_sess;
+			c_ops[burst_size++] = curr_c_op;
+		} else if (curr_sess == prev_sess) {
+			c_ops[burst_size++] = curr_c_op;
+			/*
+			 * When there are enough ops to process in a batch,
+			 * process them, and start a new batch.
+			 */
+			if (burst_size == SNOW3G_MAX_BURST) {
+				processed_ops = process_ops(c_ops,
+						prev_sess, qp, burst_size);
+				n = rte_ring_enqueue_burst(qp->processed_ops,
+						(void **)c_ops,
+						processed_ops);
+				qp->qp_stats.enqueued_count += n;
+				enqueued_ops += n;
+				if (n < burst_size) {
+					qp->qp_stats.enqueue_err_count +=
+							nb_ops - enqueued_ops;
+					return enqueued_ops;
+				}
+				burst_size = 0;
+
+				prev_sess = NULL;
+			}
+		} else {
+			/*
+			 * Different session, process the ops
+			 * of the previous session.
+			 */
+			processed_ops = process_ops(c_ops,
+					prev_sess, qp, burst_size);
+			n = rte_ring_enqueue_burst(qp->processed_ops,
+					(void **)c_ops,
+					processed_ops);
+			qp->qp_stats.enqueued_count += n;
+			enqueued_ops += n;
+			if (n < burst_size) {
+				qp->qp_stats.enqueue_err_count +=
+						nb_ops - enqueued_ops;
+				return enqueued_ops;
+			}
+			burst_size = 0;
+
+			prev_sess = curr_sess;
+			c_ops[burst_size++] = curr_c_op;
+		}
+	}
+
+	if (burst_size != 0) {
+		/* Process the crypto ops of the last session. */
+		processed_ops = process_ops(c_ops,
+				prev_sess, qp, burst_size);
+		n = rte_ring_enqueue_burst(qp->processed_ops,
+				(void **)c_ops,
+				processed_ops);
+		qp->qp_stats.enqueued_count += n;
+		enqueued_ops += n;
+		if (n < burst_size) {
+			qp->qp_stats.enqueue_err_count +=
+					nb_ops - enqueued_ops;
+			return enqueued_ops;
+		}
+	}
+
+	return enqueued_ops;
+}
+
+static uint16_t
+snow3g_pmd_dequeue_burst(void *queue_pair,
+		struct rte_crypto_op **c_ops, uint16_t nb_ops)
+{
+	struct snow3g_qp *qp = queue_pair;
+
+	unsigned nb_dequeued;
+
+	nb_dequeued = rte_ring_dequeue_burst(qp->processed_ops,
+			(void **)c_ops, nb_ops);
+	qp->qp_stats.dequeued_count += nb_dequeued;
+
+	return nb_dequeued;
+}
+
+static int cryptodev_snow3g_uninit(const char *name);
+
+static int
+cryptodev_snow3g_create(const char *name,
+		struct rte_crypto_vdev_init_params *init_params)
+{
+	struct rte_cryptodev *dev;
+	char crypto_dev_name[RTE_CRYPTODEV_NAME_MAX_LEN];
+	struct snow3g_private *internals;
+
+	/* Create a unique device name. */
+	if (create_unique_device_name(crypto_dev_name,
+			RTE_CRYPTODEV_NAME_MAX_LEN) != 0) {
+		SNOW3G_LOG_ERR("failed to create unique cryptodev name");
+		return -EINVAL;
+	}
+
+	dev = rte_cryptodev_pmd_virtual_dev_init(crypto_dev_name,
+			sizeof(struct snow3g_private), init_params->socket_id);
+	if (dev == NULL) {
+		SNOW3G_LOG_ERR("failed to create cryptodev vdev");
+		goto init_error;
+	}
+
+	dev->dev_type = RTE_CRYPTODEV_SNOW3G_PMD;
+	dev->dev_ops = rte_snow3g_pmd_ops;
+
+	/* Register RX/TX burst functions for data path. */
+	dev->dequeue_burst = snow3g_pmd_dequeue_burst;
+	dev->enqueue_burst = snow3g_pmd_enqueue_burst;
+
+	internals = dev->data->dev_private;
+
+	internals->max_nb_queue_pairs = init_params->max_nb_queue_pairs;
+	internals->max_nb_sessions = init_params->max_nb_sessions;
+
+	return 0;
+init_error:
+	SNOW3G_LOG_ERR("driver %s: cryptodev_snow3g_create failed", name);
+
+	cryptodev_snow3g_uninit(crypto_dev_name);
+	return -EFAULT;
+}
+
+static int
+cryptodev_snow3g_init(const char *name,
+		const char *input_args)
+{
+	struct rte_crypto_vdev_init_params init_params = {
+		RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_QUEUE_PAIRS,
+		RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_SESSIONS,
+		rte_socket_id()
+	};
+
+	rte_cryptodev_parse_vdev_init_params(&init_params, input_args);
+
+	RTE_LOG(INFO, PMD, "Initialising %s on NUMA node %d\n", name,
+			init_params.socket_id);
+	RTE_LOG(INFO, PMD, "  Max number of queue pairs = %d\n",
+			init_params.max_nb_queue_pairs);
+	RTE_LOG(INFO, PMD, "  Max number of sessions = %d\n",
+			init_params.max_nb_sessions);
+
+	return cryptodev_snow3g_create(name, &init_params);
+}
+
+static int
+cryptodev_snow3g_uninit(const char *name)
+{
+	if (name == NULL)
+		return -EINVAL;
+
+	RTE_LOG(INFO, PMD, "Closing SNOW3G crypto device %s"
+			" on numa socket %u\n",
+			name, rte_socket_id());
+
+	return 0;
+}
+
+static struct rte_driver cryptodev_snow3g_pmd_drv = {
+	.name = CRYPTODEV_NAME_SNOW3G_PMD,
+	.type = PMD_VDEV,
+	.init = cryptodev_snow3g_init,
+	.uninit = cryptodev_snow3g_uninit
+};
+
+PMD_REGISTER_DRIVER(cryptodev_snow3g_pmd_drv);
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
new file mode 100644
index 0000000..5643323
--- /dev/null
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd_ops.c
@@ -0,0 +1,291 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_snow3g_pmd_private.h"
+
+/** Configure device */
+static int
+snow3g_pmd_config(__rte_unused struct rte_cryptodev *dev)
+{
+	return 0;
+}
+
+/** Start device */
+static int
+snow3g_pmd_start(__rte_unused struct rte_cryptodev *dev)
+{
+	return 0;
+}
+
+/** Stop device */
+static void
+snow3g_pmd_stop(__rte_unused struct rte_cryptodev *dev)
+{
+}
+
+/** Close device */
+static int
+snow3g_pmd_close(__rte_unused struct rte_cryptodev *dev)
+{
+	return 0;
+}
+
+
+/** Get device statistics */
+static void
+snow3g_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 snow3g_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
+snow3g_pmd_stats_reset(struct rte_cryptodev *dev)
+{
+	int qp_id;
+
+	for (qp_id = 0; qp_id < dev->data->nb_queue_pairs; qp_id++) {
+		struct snow3g_qp *qp = dev->data->queue_pairs[qp_id];
+
+		memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
+	}
+}
+
+
+/** Get device info */
+static void
+snow3g_pmd_info_get(struct rte_cryptodev *dev,
+		struct rte_cryptodev_info *dev_info)
+{
+	struct snow3g_private *internals = dev->data->dev_private;
+
+	if (dev_info != NULL) {
+		dev_info->dev_type = dev->dev_type;
+		dev_info->max_nb_queue_pairs = internals->max_nb_queue_pairs;
+		dev_info->sym.max_nb_sessions = internals->max_nb_sessions;
+	}
+}
+
+/** Release queue pair */
+static int
+snow3g_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 its name, dev_id and qp_id */
+static int
+snow3g_pmd_qp_set_unique_name(struct rte_cryptodev *dev,
+		struct snow3g_qp *qp)
+{
+	unsigned n = snprintf(qp->name, sizeof(qp->name),
+			"snow3g_pmd_%u_qp_%u",
+			dev->data->dev_id, qp->id);
+
+	if (n > sizeof(qp->name))
+		return -1;
+
+	return 0;
+}
+
+/** Create a ring to place processed ops on */
+static struct rte_ring *
+snow3g_pmd_qp_create_processed_ops_ring(struct snow3g_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) {
+			SNOW3G_LOG_INFO("Reusing existing ring %s"
+					" for processed packets",
+					 qp->name);
+			return r;
+		}
+
+		SNOW3G_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
+snow3g_pmd_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
+		const struct rte_cryptodev_qp_conf *qp_conf,
+		 int socket_id)
+{
+	struct snow3g_qp *qp = NULL;
+
+	/* Free memory prior to re-allocation if needed. */
+	if (dev->data->queue_pairs[qp_id] != NULL)
+		snow3g_pmd_qp_release(dev, qp_id);
+
+	/* Allocate the queue pair data structure. */
+	qp = rte_zmalloc_socket("SNOW3G 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 (snow3g_pmd_qp_set_unique_name(dev, qp))
+		goto qp_setup_cleanup;
+
+	qp->processed_ops = snow3g_pmd_qp_create_processed_ops_ring(qp,
+			qp_conf->nb_descriptors, socket_id);
+	if (qp->processed_ops == NULL)
+		goto qp_setup_cleanup;
+
+	qp->sess_mp = dev->data->session_pool;
+
+	memset(&qp->qp_stats, 0, sizeof(qp->qp_stats));
+
+	return 0;
+
+qp_setup_cleanup:
+	if (qp)
+		rte_free(qp);
+
+	return -1;
+}
+
+/** Start queue pair */
+static int
+snow3g_pmd_qp_start(__rte_unused struct rte_cryptodev *dev,
+		__rte_unused uint16_t queue_pair_id)
+{
+	return -ENOTSUP;
+}
+
+/** Stop queue pair */
+static int
+snow3g_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
+snow3g_pmd_qp_count(struct rte_cryptodev *dev)
+{
+	return dev->data->nb_queue_pairs;
+}
+
+/** Returns the size of the SNOW 3G session structure */
+static unsigned
+snow3g_pmd_session_get_size(struct rte_cryptodev *dev __rte_unused)
+{
+	return sizeof(struct snow3g_session);
+}
+
+/** Configure a SNOW 3G session from a crypto xform chain */
+static void *
+snow3g_pmd_session_configure(struct rte_cryptodev *dev __rte_unused,
+		struct rte_crypto_sym_xform *xform,	void *sess)
+{
+	if (unlikely(sess == NULL)) {
+		SNOW3G_LOG_ERR("invalid session struct");
+		return NULL;
+	}
+
+	if (snow3g_set_session_parameters(sess, xform) != 0) {
+		SNOW3G_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
+snow3g_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 snow3g_session));
+}
+
+struct rte_cryptodev_ops snow3g_pmd_ops = {
+		.dev_configure      = snow3g_pmd_config,
+		.dev_start          = snow3g_pmd_start,
+		.dev_stop           = snow3g_pmd_stop,
+		.dev_close          = snow3g_pmd_close,
+
+		.stats_get          = snow3g_pmd_stats_get,
+		.stats_reset        = snow3g_pmd_stats_reset,
+
+		.dev_infos_get      = snow3g_pmd_info_get,
+
+		.queue_pair_setup   = snow3g_pmd_qp_setup,
+		.queue_pair_release = snow3g_pmd_qp_release,
+		.queue_pair_start   = snow3g_pmd_qp_start,
+		.queue_pair_stop    = snow3g_pmd_qp_stop,
+		.queue_pair_count   = snow3g_pmd_qp_count,
+
+		.session_get_size   = snow3g_pmd_session_get_size,
+		.session_configure  = snow3g_pmd_session_configure,
+		.session_clear      = snow3g_pmd_session_clear
+};
+
+struct rte_cryptodev_ops *rte_snow3g_pmd_ops = &snow3g_pmd_ops;
diff --git a/drivers/crypto/snow3g/rte_snow3g_pmd_private.h b/drivers/crypto/snow3g/rte_snow3g_pmd_private.h
new file mode 100644
index 0000000..b383cbc
--- /dev/null
+++ b/drivers/crypto/snow3g/rte_snow3g_pmd_private.h
@@ -0,0 +1,107 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2016 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_SNOW3G_PMD_PRIVATE_H_
+#define _RTE_SNOW3G_PMD_PRIVATE_H_
+
+#include <sso_snow3g.h>
+
+#define SNOW3G_LOG_ERR(fmt, args...) \
+	RTE_LOG(ERR, CRYPTODEV, "[%s] %s() line %u: " fmt "\n",  \
+			CRYPTODEV_NAME_SNOW3G_PMD, \
+			__func__, __LINE__, ## args)
+
+#ifdef RTE_LIBRTE_SNOW3G_DEBUG
+#define SNOW3G_LOG_INFO(fmt, args...) \
+	RTE_LOG(INFO, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+			CRYPTODEV_NAME_SNOW3G_PMD, \
+			__func__, __LINE__, ## args)
+
+#define SNOW3G_LOG_DBG(fmt, args...) \
+	RTE_LOG(DEBUG, CRYPTODEV, "[%s] %s() line %u: " fmt "\n", \
+			CRYPTODEV_NAME_SNOW3G_PMD, \
+			__func__, __LINE__, ## args)
+#else
+#define SNOW3G_LOG_INFO(fmt, args...)
+#define SNOW3G_LOG_DBG(fmt, args...)
+#endif
+
+/** private data structure for each virtual SNOW 3G device */
+struct snow3g_private {
+	unsigned max_nb_queue_pairs;
+	/**< Max number of queue pairs supported by device */
+	unsigned max_nb_sessions;
+	/**< Max number of sessions supported by device */
+};
+
+/** SNOW 3G buffer queue pair */
+struct snow3g_qp {
+	uint16_t id;
+	/**< Queue Pair Identifier */
+	char name[RTE_CRYPTODEV_NAME_LEN];
+	/**< Unique Queue Pair Name */
+	struct rte_ring *processed_ops;
+	/**< Ring for placing processed ops */
+	struct rte_mempool *sess_mp;
+	/**< Session Mempool */
+	struct rte_cryptodev_stats qp_stats;
+	/**< Queue pair statistics */
+} __rte_cache_aligned;
+
+enum snow3g_operation {
+	SNOW3G_OP_ONLY_CIPHER,
+	SNOW3G_OP_ONLY_AUTH,
+	SNOW3G_OP_CIPHER_AUTH,
+	SNOW3G_OP_AUTH_CIPHER,
+	SNOW3G_OP_NOT_SUPPORTED
+};
+
+/** SNOW 3G private session structure */
+struct snow3g_session {
+	enum snow3g_operation op;
+	enum rte_crypto_auth_operation auth_op;
+	sso_snow3g_key_schedule_t pKeySched_cipher;
+	sso_snow3g_key_schedule_t pKeySched_hash;
+} __rte_cache_aligned;
+
+
+extern int
+snow3g_set_session_parameters(struct snow3g_session *sess,
+		const struct rte_crypto_sym_xform *xform);
+
+
+/** device specific operations function pointer structure */
+extern struct rte_cryptodev_ops *rte_snow3g_pmd_ops;
+
+
+
+#endif /* _RTE_SNOW3G_PMD_PRIVATE_H_ */
diff --git a/lib/librte_cryptodev/Makefile b/lib/librte_cryptodev/Makefile
index 0d59229..314a046 100644
--- a/lib/librte_cryptodev/Makefile
+++ b/lib/librte_cryptodev/Makefile
@@ -57,5 +57,6 @@ DEPDIRS-y += lib/librte_eal
 DEPDIRS-y += lib/librte_mempool
 DEPDIRS-y += lib/librte_ring
 DEPDIRS-y += lib/librte_mbuf
+DEPDIRS-y += lib/librte_kvargs
 
-include $(RTE_SDK)/mk/rte.lib.mk
\ No newline at end of file
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_cryptodev/rte_cryptodev.h b/lib/librte_cryptodev/rte_cryptodev.h
index aab8cff..53cca22 100644
--- a/lib/librte_cryptodev/rte_cryptodev.h
+++ b/lib/librte_cryptodev/rte_cryptodev.h
@@ -48,6 +48,7 @@
 extern "C" {
 #endif
 
+#include "rte_kvargs.h"
 #include "rte_crypto.h"
 #include "rte_dev.h"
 
@@ -57,15 +58,17 @@ extern "C" {
 /**< AES-NI Multi buffer PMD device name */
 #define CRYPTODEV_NAME_QAT_SYM_PMD	("cryptodev_qat_sym_pmd")
 /**< Intel QAT Symmetric Crypto PMD device name */
+#define CRYPTODEV_NAME_SNOW3G_PMD	("cryptodev_snow3g_pmd")
+/**< SNOW 3G PMD device name */
 
 /** Crypto device type */
 enum rte_cryptodev_type {
 	RTE_CRYPTODEV_NULL_PMD = 1,	/**< Null crypto PMD */
 	RTE_CRYPTODEV_AESNI_MB_PMD,	/**< AES-NI multi buffer PMD */
 	RTE_CRYPTODEV_QAT_SYM_PMD,	/**< QAT PMD Symmetric Crypto */
+	RTE_CRYPTODEV_SNOW3G_PMD,	/**< SNOW 3G PMD */
 };
 
-
 extern const char **rte_cyptodev_names;
 
 /* Logging Macros */
@@ -148,6 +151,121 @@ struct rte_cryptodev_stats {
 	/**< Total error count on operations dequeued */
 };
 
+#define RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_QUEUE_PAIRS	8
+#define RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_SESSIONS	2048
+
+/**
+ * @internal
+ * Initialisation parameters for virtual crypto devices
+ */
+struct rte_crypto_vdev_init_params {
+	unsigned max_nb_queue_pairs;
+	unsigned max_nb_sessions;
+	uint8_t socket_id;
+};
+
+#define RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG		("max_nb_queue_pairs")
+#define RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG		("max_nb_sessions")
+#define RTE_CRYPTODEV_VDEV_SOCKET_ID			("socket_id")
+
+static const char *cryptodev_vdev_valid_params[] = {
+	RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
+	RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG,
+	RTE_CRYPTODEV_VDEV_SOCKET_ID
+};
+
+static inline uint8_t
+number_of_sockets(void)
+{
+	int sockets = 0;
+	int i;
+	const struct rte_memseg *ms = rte_eal_get_physmem_layout();
+
+	for (i = 0; ((i < RTE_MAX_MEMSEG) && (ms[i].addr != NULL)); i++) {
+		if (sockets < ms[i].socket_id)
+			sockets = ms[i].socket_id;
+	}
+
+	/* Number of sockets = maximum socket_id + 1 */
+	return ++sockets;
+}
+
+/** Parse integer from integer argument */
+static inline int
+__rte_cryptodev_parse_integer_arg(const char *key __rte_unused,
+		const char *value, void *extra_args)
+{
+	int *i = (int *) extra_args;
+
+	*i = atoi(value);
+	if (*i < 0) {
+		CDEV_LOG_ERR("Argument has to be positive.");
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * Parse virtual device initialisation parameters input arguments
+ * @internal
+ *
+ * @params	params		Initialisation parameters with defaults set.
+ * @params	input_args	Command line arguments
+ *
+ * @return
+ * 0 on successful parse
+ * <0 on failure to parse
+ */
+static inline int
+rte_cryptodev_parse_vdev_init_params(struct rte_crypto_vdev_init_params *params,
+		const char *input_args)
+{
+	struct rte_kvargs *kvlist;
+	int ret;
+
+	if (params == NULL)
+		return -EINVAL;
+
+	if (input_args) {
+		kvlist = rte_kvargs_parse(input_args,
+				cryptodev_vdev_valid_params);
+		if (kvlist == NULL)
+			return -1;
+
+		ret = rte_kvargs_process(kvlist,
+					RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
+					&__rte_cryptodev_parse_integer_arg,
+					&params->max_nb_queue_pairs);
+		if (ret < 0)
+			goto free_kvlist;
+
+		ret = rte_kvargs_process(kvlist,
+					RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG,
+					&__rte_cryptodev_parse_integer_arg,
+					&params->max_nb_sessions);
+		if (ret < 0)
+			goto free_kvlist;
+
+		ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_SOCKET_ID,
+					&__rte_cryptodev_parse_integer_arg,
+					&params->socket_id);
+		if (ret < 0)
+			goto free_kvlist;
+
+		if (params->socket_id >= number_of_sockets()) {
+			CDEV_LOG_ERR("Invalid socket id specified to create "
+				"the virtual crypto device on");
+			goto free_kvlist;
+		}
+	}
+
+	return 0;
+
+free_kvlist:
+	rte_kvargs_free(kvlist);
+	return ret;
+}
 
 /**
  * Create a virtual crypto device
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index daac09f..7e46370 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -1,6 +1,6 @@
 #   BSD LICENSE
 #
-#   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+#   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
 #   Copyright(c) 2014-2015 6WIND S.A.
 #   All rights reserved.
 #
@@ -150,6 +150,10 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_QAT)        += -lrte_pmd_qat
 _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
 
+# SNOW3G PMD is dependent on the LIBSSO library
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G)     += -lrte_pmd_snow3g
+_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G)     += -L$(LIBSSO_PATH)/build -lsso
+
 endif # ! $(CONFIG_RTE_BUILD_SHARED_LIB)
 
 _LDLIBS-y += $(EXECENV_LDLIBS)
-- 
2.5.0

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [dpdk-dev] [PATCH v4] pmd/snow3g: add new SNOW 3G SW PMD
  2016-03-10 16:33     ` [dpdk-dev] [PATCH v4] " Pablo de Lara
@ 2016-03-10 16:54       ` Jain, Deepak K
  2016-03-10 23:00         ` Thomas Monjalon
  2016-03-10 22:56       ` Thomas Monjalon
  1 sibling, 1 reply; 9+ messages in thread
From: Jain, Deepak K @ 2016-03-10 16:54 UTC (permalink / raw)
  To: De Lara Guarch, Pablo, dev



-----Original Message-----
From: De Lara Guarch, Pablo 
Sent: Thursday, March 10, 2016 4:33 PM
To: dev@dpdk.org
Cc: Doherty, Declan <declan.doherty@intel.com>; Jain, Deepak K <deepak.k.jain@intel.com>; De Lara Guarch, Pablo <pablo.de.lara.guarch@intel.com>
Subject: [PATCH v4] pmd/snow3g: add new SNOW 3G SW PMD

Added new SW PMD which makes use of the libsso SW library, which provides wireless algorithms SNOW 3G UEA2 and UIA2 in software.

This PMD supports cipher-only, hash-only and chained operations ("cipher then hash" and "hash then cipher") of the following
algorithms:
- RTE_CRYPTO_SYM_CIPHER_SNOW3G_UEA2
- RTE_CRYPTO_SYM_AUTH_SNOW3G_UIA2

The SNOW 3G hash and cipher algorithms, which are enabled by this crypto PMD are implemented by Intel's libsso software library. For library download and build instructions, see the documentation included (doc/guides/cryptodevs/snow3g.rst)

The patch also contains the related unit tests function to test the PMD supported operations.

Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
---

This patch depends on "Snow3G support for Intel Quick Assist Devices" patchset (http://dpdk.org/ml/archives/dev/2016-March/03548.html).

Changes in v4:

- Added missing fix casting that was breaking C++ compilation.
- Fixed documentation
- Rebased against latest DPDK code

Changes in v3:

- Corrected patch dependency

Changes in v2:

- Rebased against crypto API changes
- Removed static config options and allow user to provide them
  as virtual device parameters.
- Added unit tests
- Changed DPDK version references from 2.3 to 16.04
- Fixed crypto operation status handling
- Fixed copyright dates
- Fixed enqueue error stats

-- 
2.5.0

Acked-by: Deepak Kumar JAIN <deepak.k.jain@intel.com>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [dpdk-dev] [PATCH v4] pmd/snow3g: add new SNOW 3G SW PMD
  2016-03-10 16:33     ` [dpdk-dev] [PATCH v4] " Pablo de Lara
  2016-03-10 16:54       ` Jain, Deepak K
@ 2016-03-10 22:56       ` Thomas Monjalon
  1 sibling, 0 replies; 9+ messages in thread
From: Thomas Monjalon @ 2016-03-10 22:56 UTC (permalink / raw)
  To: Pablo de Lara; +Cc: dev

2016-03-10 16:33, Pablo de Lara:
> +SNOW 3G PMD
> +M: Pablo de Lara <pablo.de.lara.guarch@intel.com>
> +F: drivers/crypto/snow3g

Missing doc reference:
F: doc/guides/cryptodevs/snow3g.rst

> +To build DPDK with the SNOW3G_PMD the user is required to get
> +the export controlled libsso library, sending a request to
> +`DPDKUser_software_access@intel.com`, and compile it
> +on their user system before building DPDK:

I'm a bit concerned that this library is not freely available.
It makes testing difficult.

> +The environmental variable LIBSSO_PATH must be exported with the path
> +where you extracted and built the libsso library and finally set
> +CONFIG_RTE_LIBRTE_SNOW3G=y in config/common_base.

It is CONFIG_RTE_LIBRTE_PMD_SNOW3G.

> +# SNOW3G PMD is dependent on the LIBSSO library
> +_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G)     += -lrte_pmd_snow3g
> +_LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_SNOW3G)     += -L$(LIBSSO_PATH)/build -lsso
> +
>  endif # ! $(CONFIG_RTE_BUILD_SHARED_LIB)

This is for the static library case.
The PMD should be linked to libsso also in the shared library case.
There is the same problem with -lIPSec_MB (aesni_mb driver).

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [dpdk-dev] [PATCH v4] pmd/snow3g: add new SNOW 3G SW PMD
  2016-03-10 16:54       ` Jain, Deepak K
@ 2016-03-10 23:00         ` Thomas Monjalon
  0 siblings, 0 replies; 9+ messages in thread
From: Thomas Monjalon @ 2016-03-10 23:00 UTC (permalink / raw)
  To: De Lara Guarch, Pablo; +Cc: dev

> Added new SW PMD which makes use of the libsso SW library, which provides wireless algorithms SNOW 3G UEA2 and UIA2 in software.
> 
> This PMD supports cipher-only, hash-only and chained operations ("cipher then hash" and "hash then cipher") of the following
> algorithms:
> - RTE_CRYPTO_SYM_CIPHER_SNOW3G_UEA2
> - RTE_CRYPTO_SYM_AUTH_SNOW3G_UIA2
> 
> The SNOW 3G hash and cipher algorithms, which are enabled by this crypto PMD are implemented by Intel's libsso software library. For library download and build instructions, see the documentation included (doc/guides/cryptodevs/snow3g.rst)
> 
> The patch also contains the related unit tests function to test the PMD supported operations.
> 
> Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
> Acked-by: Deepak Kumar JAIN <deepak.k.jain@intel.com>

Applied with some trivial fixes.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2016-03-10 23:02 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-29 14:15 [dpdk-dev] [PATCH] pmd/snow3g: add new SNOW 3G SW PMD Pablo de Lara
2016-03-07 14:07 ` [dpdk-dev] [PATCH v2] " Pablo de Lara
2016-03-07 19:48   ` [dpdk-dev] [PATCH v3] " Pablo de Lara
2016-03-08 14:10     ` Jain, Deepak K
2016-03-10 16:33     ` [dpdk-dev] [PATCH v4] " Pablo de Lara
2016-03-10 16:54       ` Jain, Deepak K
2016-03-10 23:00         ` Thomas Monjalon
2016-03-10 22:56       ` Thomas Monjalon
2016-03-07 19:48   ` [dpdk-dev] [PATCH v2] " De Lara Guarch, Pablo

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).